10

我正在开发一个视频编码应用程序,我想防止在托管 Activity 进入后台或屏幕循环关闭/打开时停止。

我的编码器架构源自出色的CameraToMpegTest示例,并添加了将相机帧显示到 GLSurfaceView(请参阅下面的 Github 链接)。我目前正在使用两种状态的解决方案执行后台录制:

  • 当托管 Activity 位于前台时,在每次调用GLSurfaceView.Renderer's时编码一个视频帧onDrawFrame。这使我可以突发​​访问 GLSurfaceView 的 EGL 状态,以免阻塞排队到渲染器线程的其他事件。

  • 当宿主 Activity 进入后台时,onDrawFrame在循环内的另一个后台线程上停止编码和编码帧。此模式与 CameraToMpegTest 示例相同。

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

E/libEGL(18839): EGLNativeWindowType 0x7a931098 already connected to another API

在调用之前,我释放了所有连接到 Android Surface 的 EGL 资源

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

我的测试应用程序的完整源代码在Github上。主要活动

更新我将这里学到的经验应用到基于 MediaCodec 和 MediaMuxer 类的 Android 视频 sdk 中。希望能帮助到你!

4

1 回答 1

10

先说背景...

当您调用eglCreateWindowSurface()时,Android EGL 包装器会调用您传入native_window_api_connect()Surface。这最终会变成BufferQueue生产者连接调用,这意味着此 EGL 表面现在是Surface.

EGL 表面保持连接到EGL 表面,Surface直到 EGL 表面被破坏。如果是,则表面析构函数调用native_window_api_disconnect()以断开 EGL 表面与BufferQueue. EGL 表面是引用计数的,当表面被传递给时,引用计数会增加,eglMakeCurrent()所以要被销毁,必须发生两件事:

  1. eglDestroySurface()必须调用
  2. EGL 表面在任何线程中都不能是“当前”的

第二项需要调用eglMakeCurrent()另一个 EGL 表面(或EGL_NO_SURFACE),或调用eglReleaseThread()之前使用过该表面的任何线程。确认这已完成的一种快速方法是在调用之前添加日志记录,eglMakeCurrent()当表面变为当前和非当前时,并通过查看 logcat 输出来比较线程 ID adb logcat -v threadtime。使用 EGL 查询也可能很有用,例如eglGetCurrentSurface(EGL_DRAW)确认您正在使表面成为电流的线程中执行非电流。

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

更新:我的实现现在在Grafika 测试项目中可用。如果你安装这个,选择“显示+捕获相机”,开始录制,切换电源,然后停止录制,你应该有一个完整的电影,中间有很长的停顿。您可以退出,选择“播放视频”,然后选择“camera-test.mp4”进行查看。

于 2013-12-13T18:37:01.137 回答