camera2的setVideoFramerate()没有任何效果。

3

我正在为我的LG G4开发相机应用程序,但我找不到以恒定帧率录制的方法。我参考了Google的示例Camera2 app来添加我的功能。

当我想录制UHD时:

mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);

mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
if (mNextVideoAbsolutePath == null || mNextVideoAbsolutePath.isEmpty()) {
    mNextVideoAbsolutePath = getVideoFilePath(getActivity());
}
mMediaRecorder.setOutputFile(mNextVideoAbsolutePath);

mMediaRecorder.setVideoEncodingBitRate(35 * 1000 * 1000);
mMediaRecorder.setVideoSize(3840, 2160);
mMediaRecorder.setVideoFrameRate(30);

mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);

三个不同输出视频的帧率分别为27.61,28.39和26.24等等。我无法获得一个稳定的29.97或30fps的帧率。我试过将比特率提高到50Mbps,降低到30Mbps,但没有任何改变。
最奇怪的是,我甚至不能以1080p超过30fps进行录制:
mMediaRecorder.setVideoSize(1920, 1080);
mMediaRecorder.setVideoFrameRate(60);

我曾经尝试过在29.69的情况下记录FHD画面,但录制结果和UHD画面一样随机。我做错了什么吗?

我查看了使用Camera2(在Android版本21上)API录制60fps视频,但它也无法解决问题。 我还找到了一些答案,但它们使用了已弃用的旧相机API(具有Camera.Parameters)。

还有其他参数吗?


文档 https://developer.android.com/reference/android/media/MediaRecorder.html#setVideoFrameRate(int) 表明 setVideoFrameRate 不能保证恒定的帧率。也许你可以尝试使用 Camera2 API 直接录制视频,但我对 camera2 不熟悉。 - nandsito
MediaRecorderCamera2 API 的一部分,对吧?我看到的所有使用 Camera2 API 的例子都在使用 MediaRecorder。据我所知,android.hardware.camera2 中没有记录方法。要实现恒定的 29.97 或 30 fps,使用 C/C++ 是否更好? - Raphaël
MediaRecorderCamera2是不同的API。前者是更高级别的API,用于录制音频和视频媒体,而后者提供接近硬件级别的相机功能,就像AudioRecorder一样提供音频功能。您说得对,Camera2不提供视频录制。我认为也没有原生的API来记录视频。 - nandsito
如果您确实需要确保恒定的帧率,可以配置相机(而不是媒体记录器)以恒定速率处理预览帧,以便从预览帧组装视频文件。这将是一项艰巨的工作,但应该可以做到。即便如此,某些设备也不能保证恒定的预览帧速率,所以请小心。我知道旧的“Camera”API可以做到这一点,因此我相信“Camera2”也可以。 - nandsito
1
“以恒定速率处理预览帧”是指“每秒拍摄30张照片并组装它们”吗?这会对处理器造成很大压力,而且我也不知道如何通过编程来组装图片制作视频。 - Raphaël
2个回答

1
对于仍然遇到这个问题的任何人,这是我的解决方案(请注意,FIXED_FRAME_RATE是您设备能力内可自定义值的私有常量):
private void startRecording() {
    if (cameraDevice == null || !previewView.isAvailable() || videoSize == null) {
        return;
    }

    try {
        closePreviewSession();
        setUpMediaRecorder();

        SurfaceTexture texture = previewView.getSurfaceTexture();
        texture.setDefaultBufferSize(videoSize.getWidth(), videoSize.getHeight());
        Surface previewSurface = new Surface(texture);

        List<Surface> surfaces = new ArrayList<>();
        surfaces.add(previewSurface);
        surfaces.add(mediaRecorder.getSurface());

        captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
        for (Surface surface : surfaces) {
            captureRequestBuilder.addTarget(surface);
        }

        // Set the frame rate in the CaptureRequest
        captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
        captureRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, new Range<>(FIXED_FRAME_RATE, FIXED_FRAME_RATE));

        cameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
            @Override
            public void onConfigured(@NonNull CameraCaptureSession session) {
                if (cameraDevice == null) {
                    return;
                }

                cameraCaptureSession = session;
                updatePreview();

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mediaRecorder.start();
                        isRecording = true;
                    }
                });
            }

            @Override
            public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                // You can Handle configuration failure if desired
            }
        }, null);

    } catch (CameraAccessException | IOException e) {
        e.printStackTrace();
    }
}

只需在按下按钮后调用startRecording(),一切都应该正常。
请注意,您还应该使用与原始问题中相同的FIXED_FRAME_RATE值设置mediaRecorder的视频帧率。使用setupMediaRecorder()方法。

-1

注意:在一些具有自动帧率的设备上,这将设置最大帧率,而不是恒定的帧率。实际帧率将根据光照条件而变化。

试试这个:

mediaRecorder.setCaptureRate(30);

这是作为答案发布的,但它并没有试图回答问题。它可能应该是一个评论或完全删除。 - Marcin Orlowski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接