视频录制和onPreviewFrame同时回调

Posted

技术标签:

【中文标题】视频录制和onPreviewFrame同时回调【英文标题】:Video recording and onPreviewFrame callback at the same time 【发布时间】:2019-02-18 06:06:40 【问题描述】:

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

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

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

我尝试了类似的方法,但它不起作用(录音有效,但从未调用过 onPreviewFrame

我还尝试在 MediaRecorder.start() 之后调用相机的 stopPreviewstartPreview 方法,但似乎我们不应该这样做,否则当我尝试停止录制 (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 和预览帧回调。如果是,那么如何正确地做到这一点?

【问题讨论】:

您找到解决方案了吗?我也面临同样的问题。 【参考方案1】:

(根据下面 Alex 的评论编辑)

是的,一般情况下是可以的。相机 API 可能很棘手,需要精度和持久性。

首先,从您知道有效的示例代码开始。比如官方的原始API抓视频教程是:https://developer.android.com/guide/topics/media/camera#capture-video。太好了,既然您的设备上有示例代码,那么您就已经完成了大部分工作。如果您无法让它在您的设备上运行,请至少尝试其他品牌的设备。

接下来,让您自己的应用代码与示例的线程和 API 调用相匹配。当您遇到错误或冻结时,请查看日志以了解发生了什么。这通常是一些微不足道的事情,比如清单中缺少权限。

最后,日志,日志,日志。在这个问题中,如果您在代码中发布了来自日志的错误,那么您可能已经找到了特定答案的特定问题。

祝你好运!

【讨论】:

你回答了一个不同的问题。显示预览和处理onPreveiwfFrame回调有很大区别【参考方案2】:

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

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

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

显然,MediaCodec 出现在 API 21 中,因此 these examples 主要与 LEGACY 设备相关。

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

【讨论】:

MediaRecorder + Camera2(或 Surface Video Source)有问题github.com/googlesamples/android-Camera2Video/issues/86 无论如何,是的,我也需要支持旧设备 @Alex 为什么“强烈建议切换到新的 camera2 API”? @leorleor 我试图澄清我的建议。 大家好,@AlexCohn 这对任何人都有效吗?我正在积极寻求同时处理预览帧和录制视频。期待您的来信。

以上是关于视频录制和onPreviewFrame同时回调的主要内容,如果未能解决你的问题,请参考以下文章

视频录制学习

Grafika 和 OpenGL 在 android 上以方形录制视频

同时录制视频和播放音频文件

如何用静态 YUV 帧覆盖 onPreviewFrame 数据?

同时录制摄像机视频和显示YouTube视频

如何同时录制视频和播放音频(快速教程)