带Surface输入的MediaCodec:生成分块输出

时间:2013-09-30 19:33:59

标签: android mediacodec

我正在尝试通过MediaCodec.createInputSurface()从CameraPreview数据生成短序列mp4文件。但是,重新创建MediaCodec及其关联的Surface需要停止相机以允许再次调用mCamera.setPreviewTexture(...)。此延迟会导致不可接受的丢帧量。

因此,我需要定期生成CODEC_CONFIGEND_OF_STREAM数据,而无需重新创建输入Surface,因此必须调用mCamera.setPreviewTexture(...)。这可能假设MediaFormat没有变化吗?

(我正在调整fadden的CameraToMpegTest示例。我的完整代码是here

尝试失败:

拨打MediaCodec.signalEndOfInputStream(),耗尽MediaCodec,然后在两个块之间调用MediaCodec.flush()会在第二次调用IllegalStateException时生成MediaCodec.signalEndOfInputStream()

调用MediaCodec.signalEndOfInputStream(),耗尽MediaCodec,然后在不再调用MediaCodec.stop(); MediaCodec.configure(...), MediaCodec.start()的情况下在块之间调用MediaCodec.createInputSurface()会产生以下错误:

    09-30 13:12:49.889  17638-17719/x.xx.xxxx E/Surface﹕ queueBuffer: error queuing buffer to SurfaceTexture, -19
09-30 13:12:49.889  17638-17719/x.xx.xxxx E/IMGSRV﹕ :0: UnlockPostBuffer: Failed to queue buffer 0x592e1e70
09-30 13:12:49.889  17638-17719/x.xx.xxxx E/CameraToMpegTest﹕ Encoding loop exception!
09-30 13:12:49.889  17638-17719/x.xx.xxxx W/System.err﹕ java.lang.RuntimeException: eglSwapBuffers: EGL error: 0x300b
09-30 13:12:49.896  17638-17719/x.xx.xxxx W/System.err﹕ at x.xx.xxxx.ChunkedHWRecorder$CodecInputSurface.checkEglError(ChunkedHWRecorder.java:731)
09-30 13:12:49.896  17638-17719/x.xx.xxxx W/System.err﹕ at x.xx.xxxx.ChunkedHWRecorder$CodecInputSurface.swapBuffers(ChunkedHWRecorder.java:713)
09-30 13:12:49.896  17638-17719/x.xx.xxxx W/System.err﹕ at x.xx.xxxx.ChunkedHWRecorder.startRecording(ChunkedHWRecorder.java:164)
09-30 13:12:49.896  17638-17719/x.xx.xxxx W/System.err﹕ at x.xx.xxxx.HWRecorderActivity$CameraToMpegWrapper.run(HWRecorderActivity.java:76)
09-30 13:12:49.896  17638-17719/x.xx.xxxx W/System.err﹕ at java.lang.Thread.run(Thread.java:841)

解决谢谢fadden。完整的解决方案来源是here

1 个答案:

答案 0 :(得分:9)

signalEndOfInputStream()调用更新MediaCodec堆栈中各个层的状态。您可以从MediaCodecTest中的测试上方的注释中了解哪些操作有效,但总体而言,MediaCodec的行为根本没有为“异常”用途定义。

所以你必须看一下代码。输入表面的生命周期与OMXNodeInstance的生命周期相关联;它由GraphicBufferSource表示。一旦发出EOS信号,GraphicBufferSource将忽略其他帧(参见line 426)。如果不拆除GraphicBufferSource,就无法重置EOS标志,但是当你这样做时,它会断开作为Surface底层的缓冲队列。

所以我认为您无法停止/重启MediaCodec并继续使用Surface。

然而......你不应该这样做。 CameraToMpegTest将相机预览路由到SurfaceTexture,然后使用GLES将纹理渲染到编码器的输入表面上。 SurfaceTexture与编码器分离,不需要更改。我认为需要改变的是CodecInputSurface,它使用MediaCodec中的Surface调用eglCreateWindowSurface()来告诉GLES在哪里绘制。如果你在那里添加一个新的“更新Surface”API(破坏旧的EGLSurface,创建新的EGLSurface,eglMakeCurrent),并在你启动一个新的MediaCodec时调用它,我认为它将全部正常工作。

更新以发表评论

您只需更改EGLSurface即可。 GLConsumer.cpp中的checkAndUpdateEglStateLocked()功能会检查以确保EGLDisplayEGLContext一旦设置就不会更改。您无法在CodecInputSurface中调用release() / eglSetup(),因为它会更改EGLContext。您只想销毁并重新创建EGLSurface