【问题标题】:MediaCodec with Surface input: Producing chunked output带有 Surface 输入的 MediaCodec:产生分块输出
【发布时间】:2013-10-06 19:02:59
【问题描述】:

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

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

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

不成功的尝试:

调用MediaCodec.signalEndOfInputStream(),排空MediaCodec,然后在块之间调用MediaCodec.flush(),在第二次调用MediaCodec.signalEndOfInputStream()时产生IllegalStateException

调用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

【问题讨论】:

    标签: android android-mediacodec


    【解决方案1】:

    signalEndOfInputStream() 调用会更新 MediaCodec 堆栈中各个层的状态。您可以从MediaCodecTest 中的测试上方的 cmets 中了解哪些操作是有效的,但总的来说,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 时调用它,我认为它会正常工作。

    更新到地址 cmets

    只更改EGLSurface 很重要。 GLConsumer.cpp 中的 checkAndUpdateEglStateLocked() 函数检查以确保 EGLDisplayEGLContext 在设置后不会更改。您不能在 CodecInputSurface 中调用 release()/eglSetup(),因为它会更改 EGLContext。您只想销毁并重新创建EGLSurface

    【讨论】:

    • 非常感谢! CodecInputSurface.updateSurface(newSurface) 执行 release(); mSurface = newSurface; eglSetup();。然后我打电话给mMediaCodec.start(); mInputSurface.makeCurrent(); STextureRender.surfaceCreated();。我在下次致电SurfaceTexture.updateTexImage() 时收到E/GLConsumer﹕ checkAndUpdateEglState: invalid current EGLContext。有任何想法吗? nutshellFull code。我会坚持下去的。
    • 我需要给你买杯啤酒。在每次致电CodecInputSurface.updateSurface(newSurface) 后,我还必须删除我对STextureRender.surfaceCreated() 的电话。
    • 哦,对了,这会改变 SurfaceTexture 下的纹理 ID。
    猜你喜欢
    • 1970-01-01
    • 2013-10-15
    • 1970-01-01
    • 1970-01-01
    • 2021-11-15
    • 2013-08-06
    • 2014-04-19
    • 1970-01-01
    • 2019-03-07
    相关资源
    最近更新 更多