带表面输入的MediaCodec:在后台录制

时间:2013-11-26 18:16:35

标签: android mediacodec

我正在开发一个视频编码应用程序,我想阻止托管活动进入后台时停止,或者屏幕循环开启。

我的编码器的架构源自优秀的CameraToMpegTest示例,并在GLSurfaceView中添加了显示相机帧(请参阅下面的Github链接)。我目前正在使用双态解决方案进行背景录制:

  • 当托管活动位于前台时,在每次调用GLSurfaceView.Renderer的{​​{1}}时编码一个视频帧。这允许我以突发方式访问GLSurfaceView的EGL状态,以便不阻止排队到渲染器线程的其他事件。

  • 当托管活动进入后台时,暂停onDrawFrame编码并在循环内的另一个后台线程上编码帧。此模式与CameraToMpegTest示例相同。

然而如果屏幕关机,GLSurfaceView的EGLContext将丢失,并且会发生对onDrawFrame的新调用。在这种情况下,我们必须重新创建连接到MediaCodec输入Surface的EGL窗口表面。不幸的是,第二次调用eglCreateWindowSurface会产生:

onSurfaceCreated

在致电之前,我release all EGL resources connected to the Android Surface

有没有办法交换连接到MediaCodec输入Surface的EGLSurface?

我的测试应用程序的完整源代码位于GithubMain Activity

更新我将此处学到的经验教训应用于video sdk for Android,基于MediaCodec& MediaMuxer类。希望它有所帮助!

1 个答案:

答案 0 :(得分:9)

背景首先......

当您致电eglCreateWindowSurface()时,Android EGL wrapper会在您传入的native_window_api_connect()上调用Surface。这最终会转变为BufferQueue生产者联系电话,这意味着此EGL表面现在是Surface的唯一图形缓冲源。

EGL表面与Surface保持连接,直到EGL表面被破坏。如果是,则surface destructor调用native_window_api_disconnect()以断开EGL曲面与BufferQueue的连接。 EGL表面是引用计数的,当表面传递给eglMakeCurrent()时,refcount递增,因此必须发生两件事:

  1. eglDestroySurface()必须被称为
  2. EGL表面在任何线程中都不能是“当前”
  3. 第二项需要在之前使用过曲面的任何线程上调用eglMakeCurrent()与另一个EGL曲面(或EGL_NO_SURFACE)或调用eglReleaseThread()。确认完成此操作的一种快速方法是在表面处于当前和非当前状态时调用eglMakeCurrent()之前添加日志记录,并通过使用adb logcat -v threadtime查看logcat输出来比较线程ID。使用像eglGetCurrentSurface(EGL_DRAW)这样的EGL查询来确认你在使表面最新的线程中进行非当前操作也可能很有用。

    如果EGL表面没有被破坏,它将不会与Surface断开连接,并且尝试连接新的生产者(通过使用新的EGL表面调用eglCreateWindowSurface)将被拒绝“已经连接”的消息。

    更新:我的实施现已在Grafika test project中提供。如果你安装它,选择“显示+捕捉相机”,开始录制,切换电源,然后停止录制,你应该有一个完整的电影,中间有一个长暂停。您可以退出,选择“播放视频”,然后选择“camera-test.mp4”进行查看。