首页 > 解决方案 > 视频录制和onPreviewFrame同时回调

问题描述

我正在尝试使用回调方法录制视频MediaRecorder并获取原始帧(字节数组)onPreviewFrame

似乎没那么容易,mb这甚至不可能,我不知道......

但是我找到了一些答案(对于类似的问题),人们说您应该Camera.reconnect()在调用MediaRecorder.start()并再次设置预览回调后重新连接相机实例()

我尝试过这样的事情,但它不起作用(录音有效,但从onPreviewFrame未被调用)

我也尝试在之后调用相机stopPreviewstartPreview方法,MediaRecorder.start()但似乎我们不应该这样做,否则当我尝试停止录制(MediaRecorder.stop())后,此类操作应用程序将停止响应(它变得冻结)

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.sample_main);
    mPreview = findViewById(R.id.surface_view);
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            testVideoRecording();
        }
    }, 1000);
}

@Override
public void onPreviewFrame(byte[] bytes, Camera camera) {
    Log.i(TAG, "onPreviewFrame");
}

private void testVideoRecording() {
    mCamera = Camera.open();

    Camera.Parameters parameters = mCamera.getParameters();
    List<Camera.Size> mSupportedPreviewSizes = parameters.getSupportedPreviewSizes();
    List<Camera.Size> mSupportedVideoSizes = parameters.getSupportedVideoSizes();
    Camera.Size optimalSize = CameraHelper.getOptimalVideoSize(mSupportedVideoSizes,
            mSupportedPreviewSizes, mPreview.getWidth(), mPreview.getHeight());

    CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
    profile.videoFrameWidth = optimalSize.width;
    profile.videoFrameHeight = optimalSize.height;

    parameters.setPreviewSize(profile.videoFrameWidth, profile.videoFrameHeight);
    mCamera.setParameters(parameters);
    try {
        mCamera.setPreviewTexture(mPreview.getSurfaceTexture());
    } catch (IOException e) {
        e.printStackTrace();
    }

    mCamera.setPreviewCallback(this);

    mMediaRecorder = new MediaRecorder();

    // Step 1: Unlock and set camera to MediaRecorder
    mCamera.unlock();
    mMediaRecorder.setCamera(mCamera);

    // Step 2: Set sources
    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

    // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
    mMediaRecorder.setProfile(profile);

    // Step 4: Set output file
    mOutputFile = new File(Environment.getExternalStorageDirectory()
            + File.separator + "test.mp4");
    if (mOutputFile.exists()) mOutputFile.delete();

    mMediaRecorder.setOutputFile(mOutputFile.getPath());

    // Step 5: Prepare configured MediaRecorder
    try {
        mMediaRecorder.prepare();
    } catch (IOException e) {
        e.printStackTrace();
    }
    mMediaRecorder.start();

    // Step 6: try to set preview frame callback

    //mCamera.stopPreview();

    try {
        mCamera.reconnect();
    } catch (IOException e) {
        e.printStackTrace();
    }

    /*try {
        mCamera.setPreviewTexture(mPreview.getSurfaceTexture());
    } catch (IOException e) {
        e.printStackTrace();
    }*/

    mCamera.setPreviewCallback(this);

    //mCamera.startPreview();
}

所以我想知道是否可以同时使用 MediaRecorder 和预览帧回调。如果是,那么如何正确地做到这一点?

标签: androidandroid-cameramediarecorderandroid-mediarecorderandroid-video-record

解决方案


首先,我强烈建议从已弃用的Camera API ( Camera.open(), ...) 切换到新的camera2 API,除非您的目标设备都低于 Android API 21。新的 API 更加强大和灵活。例如,它本机支持同一CaptureSession中的多个目标(限制取决于CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL)。是在同一会话中使用 MediaRecorder 和 ImageReader 的示例。

当 camera2 在设备上处于 LEGACY 级别时,直接使用旧 API 可能仍然更安全(这是此类相机的本地语言)。

如果您坚持使用旧 API,请考虑使用 MediaCodec 和 MediaMuxer 录制视频的示例之一。它比 MediaRecorder 更强大,但需要更多的工作。

显然,问题在于 MediaCodec 出现在 API 21 中,因此这些示例主要与 LEGACY 设备相关。

如果您真的必须使用旧设备,您别无选择,只能运行一些替代视频编码器,从onPreviewFrame()回调中收到的帧馈送。


推荐阅读