我正在尝试使以下 MediaExtractor 示例正常工作:
http://bigflake.com/mediacodec/ - ExtractMpegFramesTest.java(需要 4.1,API 16)
我遇到的问题是 outputSurface.awaitNewImage(); 似乎总是抛出 RuntimeException("frame wait timed out"),只要mFrameSyncObject.wait(TIMEOUT_MS)
调用超时就会抛出。无论我设置什么TIMEOUT_MS
,onFrameAvailable()
总是在超时发生后立即被调用。我尝试了 50 毫秒和 30000 毫秒,结果是一样的。
似乎onFrameAvailable()
在线程忙时无法完成调用,一旦发生超时导致线程代码执行结束,它就可以解析onFrameAvailable()
调用。
有没有人设法让这个例子工作,或者知道 MediaExtractor 应该如何处理 GL 纹理?
编辑:在具有 API 4.4 和 4.1.1 的设备上进行了尝试,两者都发生了同样的情况。
编辑2:
感谢fadden,让它在4.4上工作。问题是ExtractMpegFramesWrapper.runTest()
调用的方法th.join();
阻塞了主线程并阻止了onFrameAvailable()
调用被处理。一旦我发表评论th.join();
,它就可以在 4.4 上运行。我想也许它ExtractMpegFramesWrapper.runTest()
本身应该在另一个线程上运行,所以主线程没有被阻塞。
在调用 4.1.2 时也有一个小问题codec.configure()
,它给出了错误:
A/ACodec(2566): frameworks/av/media/libstagefright/ACodec.cpp:1041 CHECK(def.nBufferSize >= size) failed.
A/libc(2566): Fatal signal 11 (SIGSEGV) at 0xdeadbaad (code=1), thread 2625 (CodecLooper)
我通过在通话前添加以下内容解决了这个问题:
format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 0);
然而,我现在在 4.1.1 (Galaxy S2 GT-I9100) 和 4.1.2 (Samsung Galaxy Tab GT-P3110) 上遇到的问题是它们总是将所有帧的 info.size 设置为 0。这是日志输出:
loop
input buffer not available
no output from decoder available
loop
input buffer not available
no output from decoder available
loop
input buffer not available
no output from decoder available
loop
input buffer not available
no output from decoder available
loop
submitted frame 0 to dec, size=20562
no output from decoder available
loop
submitted frame 1 to dec, size=7193
no output from decoder available
loop
[... skipped 18 lines ...]
submitted frame 8 to dec, size=6531
no output from decoder available
loop
submitted frame 9 to dec, size=5639
decoder output format changed: {height=240, what=1869968451, color-format=19, slice-height=240, crop-left=0, width=320, crop-bottom=239, crop-top=0, mime=video/raw, stride=320, crop-right=319}
loop
submitted frame 10 to dec, size=6272
surface decoder given buffer 0 (size=0)
loop
[... skipped 1211 lines ...]
submitted frame 409 to dec, size=456
surface decoder given buffer 1 (size=0)
loop
sent input EOS
surface decoder given buffer 0 (size=0)
loop
surface decoder given buffer 1 (size=0)
loop
surface decoder given buffer 0 (size=0)
loop
surface decoder given buffer 1 (size=0)
loop
[... skipped 27 lines all with size=0 ...]
surface decoder given buffer 1 (size=0)
loop
surface decoder given buffer 0 (size=0)
output EOS
Saving 0 frames took ? us per frame // edited to avoid division-by-zero error
所以没有图像被保存。然而,相同的代码和视频适用于 4.3。我使用的视频是带有“H264 - MPEG-4 AVC (avc1)”视频编解码器和“MPEG AAAC Audio (mp4a)”音频编解码器的 .mp4 文件。
我也尝试了其他视频格式,但它们似乎在 4.1.x 上死得更快,而两者都在 4.3 上工作。
编辑3:
我按照你的建议做了,它似乎正确保存了帧图像。谢谢你。
关于 KEY_MAX_INPUT_SIZE,我尝试不设置,或将其设置为 0、20、200、... 200000000,所有结果都与 info.size=0 相同。
我现在无法在我的布局上将渲染设置为 SurfaceView 或 TextureView。我尝试替换这一行:
mSurfaceTexture = new SurfaceTexture(mTextureRender.getTextureId());
有了这个,surfaceTexture
我的 xml 布局中定义的 SurfaceTexture 在哪里:
mSurfaceTexture = textureView.getSurfaceTexture();
mSurfaceTexture.attachToGLContext(mTextureRender.getTextureId());
但它getMessage()==null
在第二行引发了一个奇怪的错误。我找不到任何其他方法让它在某种视图上绘制。如何更改解码器以在 Surface/SurfaceView/TextureView 上显示帧而不是保存它们?