man*_*ock 22 android opengl-es mediacodec mediaextractor
我正在尝试使用以下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)
Run Code Online (Sandbox Code Playgroud)
通过在通话前添加以下内容我解决了这个问题:
format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 0);
Run Code Online (Sandbox Code Playgroud)
然而,我现在在4.1.1(Galaxy S2 GT-I9100)和4.1.2(三星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
Run Code Online (Sandbox Code Playgroud)
所以没有图像得到保存.但是相同的代码和视频适用于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());
Run Code Online (Sandbox Code Playgroud)
有了这个,surfaceTexture我的xml-layout中定义了一个SurfaceTexture:
mSurfaceTexture = textureView.getSurfaceTexture();
mSurfaceTexture.attachToGLContext(mTextureRender.getTextureId());
Run Code Online (Sandbox Code Playgroud)
但它getMessage()==null在第二行引发了一个奇怪的错误.我找不到任何其他方法来绘制某种视图.如何更改解码器以在Surface/SurfaceView/TextureView上显示帧而不是保存它们?
fad*_*den 14
这种方式SurfaceTexture使得这一点变得有点棘手.
该文件说,框架可用回调"呼吁任意线程".的SurfaceTexture类有一个比特的代码进行初始化(当将执行以下操作线318):
if (this thread has a looper) {
handle events on this thread
} else if (there's a "main" looper) {
handle events on the main UI thread
} else {
no events for you
}
Run Code Online (Sandbox Code Playgroud)
框架可用事件通过常规Looper/ Handler机制传递到您的应用程序.该机制只是一个消息队列,这意味着线程需要坐在Looper事件循环中等待它们到达.麻烦的是,如果你正在睡觉awaitNewImage(),你就不会看着Looper队列.事件到来了,但没有人看到它.最终awaitNewImage()超时,并且线程返回到观察事件队列,在那里它立即发现待处理的"新帧"消息.
因此,诀窍是确保框架可用事件到达与坐在其中的线程不同的线程awaitNewImage().在这个ExtractMpegFramesTest例子中,这是通过在新创建的线程(参见ExtractMpegFramesWrapper类)中运行测试来完成的,该线程没有Looper.(由于某种原因,执行CTS测试的线程有一个looper.)可用帧的事件到达主UI线程.
更新(对于"编辑3"):我有点难过忽略"大小"字段有帮助,但4.3之前很难预测设备的行为方式.
如果您只想显示帧,请将Surface您从SurfaceView或TextureView从MediaCodec解码器configure()调用中传递出来.然后你根本不必乱用SurfaceTexture- 在你解码它们时会显示帧.有关示例,请参阅Grafika中的两个"播放视频"活动.
如果你真的想要通过a SurfaceTexture,你需要更改CodecOutputSurface以渲染到窗口表面而不是pbuffer.(屏幕外渲染已完成,因此我们可以glReadPixels()在无头测试中使用.)
| 归档时间: |
|
| 查看次数: |
11503 次 |
| 最近记录: |