You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Camera2 API实现稳定恒定的25fps视频录制

How to Achieve Stable 25fps Video Recording with Camera2 API & MediaRecorder

Hey there, let's break down your issue step by step and figure out how to get that steady 25fps recording working reliably, plus clear up why your devices show different support.

First: Why Do P30 Pro and Pixel 3 XL Have Different Frame Rate Support?

The root cause is hardware and driver implementation differences across Android devices, tied to Camera2 API capability levels:

  • P30 Pro likely falls into the FULL or LEVEL_3 Camera2 category. These devices support advanced control over capture parameters, including fixed frame rates like 25fps for specific resolutions.
  • Pixel 3 XL might only support LIMITED capabilities for your target resolution, or its camera sensor/ISP (Image Signal Processor) doesn't natively output 25fps. Some hardware is optimized for common rates like 30/60fps and doesn't include 25fps in its supported ranges.

To confirm this, you can check the device's supported frame rates programmatically (more on that later).

Fix 1: Validate Device Support for 25fps First

Before setting any parameters, confirm your target resolution actually supports a fixed 25fps range. Use this code snippet to check:

private boolean is25FpsSupported(String cameraId, Size videoSize) throws CameraAccessException {
    CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
    StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
    if (map == null) return false;

    // Check standard video frame rate ranges
    Range<Integer>[] fpsRanges = map.getOutputFpsRanges(videoSize);
    for (Range<Integer> range : fpsRanges) {
        if (range.getLower() == 25 && range.getUpper() == 25) {
            return true;
        }
    }

    // Check high-speed video ranges (if applicable)
    Range<Integer>[] highSpeedRanges = map.getHighSpeedVideoFpsRangesFor(videoSize);
    for (Range<Integer> range : highSpeedRanges) {
        if (range.getLower() == 25 && range.getUpper() == 25) {
            return true;
        }
    }
    return false;
}

If this returns false for a device (like Pixel 3 XL), hardware-level 25fps isn't possible—you'll either need to adjust your target rate or use software encoding (which impacts performance).

Fix 2: Correct MediaRecorder Parameter Configuration

Your current setup has a few gaps that might be causing frame rate drift:

  1. Parameter order matters: Ensure you set frame rate-related values in this sequence:

    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mMediaRecorder.setOutputFile(mNextVideoAbsolutePath);
    mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());
    mMediaRecorder.setVideoEncodingBitRate(10000000);
    mMediaRecorder.setVideoFrameRate(25); // Target encoder frame rate
    mMediaRecorder.setCaptureRate(25.0); // Critical: Matches camera capture rate to encoder
    mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
    mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
    mMediaRecorder.prepare();
    

    Use the double overload of setCaptureRate() for more precision than the integer version.

  2. Ensure resolution matches 25fps support: Some devices support 25fps at 1080p but not at 4K. Double-check that your mVideoSize is a resolution the device supports for 25fps.

Fix 3: Proper Camera2 CaptureRequest & Session Setup

Your existing Camera2 code is missing a key step: adding the MediaRecorder's surface to the capture session. Here's the corrected flow:

// After setting up MediaRecorder
Surface recorderSurface = mMediaRecorder.getSurface();
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
Surface previewSurface = new Surface(texture);

// Build capture request
mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
if (is25FpsSupported(mCameraId, mVideoSize)) {
    mPreviewBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, new Range<>(25, 25));
}
mPreviewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
mPreviewBuilder.addTarget(previewSurface);
mPreviewBuilder.addTarget(recorderSurface); // Critical: Send camera frames to MediaRecorder

// Create capture session
mCameraDevice.createCaptureSession(Arrays.asList(previewSurface, recorderSurface),
        new CameraCaptureSession.StateCallback() {
            @Override
            public void onConfigured(@NonNull CameraCaptureSession session) {
                mCaptureSession = session;
                try {
                    // Start repeating preview first
                    session.setRepeatingRequest(mPreviewBuilder.build(), null, mBackgroundHandler);
                    // Wait a moment for preview to stabilize, then start recording
                    mBackgroundHandler.postDelayed(() -> mMediaRecorder.start(), 500);
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                // Handle configuration failure
            }
        }, mBackgroundHandler);
  • Adding the MediaRecorder surface to the capture session ensures the camera sends frames directly to the recorder.
  • Adding a short delay before starting mMediaRecorder helps avoid initial frame rate fluctuations as the camera's AE/AF stabilizes.

Debugging Tips

  • Use CameraCaptureSession.CaptureCallback to log frame timestamps and calculate actual capture rate, to confirm if the issue is with the camera output or MediaRecorder encoding.
  • On debug builds, run this adb command to view all supported resolutions and frame rates:
    adb shell dumpsys camera | grep -A 15 "Stream configurations"
    

内容的提问来源于stack exchange,提问作者0stack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 06:37:59