我正在尝试解码文件中的视频,并使用Media Level 21C及更高版本支持的新异步模式中的MediaCodec将其编码为不同的格式(Android OS 5.0 Lollipop).
在诸如Big Flake,Google的Grafika等网站上的同步模式中有很多例子,以及StackOverflow上的几十个答案,但它们都不支持异步模式.
我不需要在此过程中显示视频.
我相信一般的过程是使用MediaExtractor作为MediaCodec(解码器)的输入来读取文件,允许Decoder的输出呈现为Surface,也是MediaCodec(编码器)的共享输入,然后最后通过Mediamuxer编写编码器输出文件. Surface是在编码器设置期间创建的,并与解码器共享.
我可以将视频解码为TextureVIEw,但是使用编码器而不是屏幕共享Surface并不成功.
我为我的两个编解码器设置了MediaCodec.Callback().我认为问题在于我不知道在Encoder的回调的oninputBufferAvailable()函数中该怎么做.我不知道(或知道如何)将数据从Surface复制到编码器中 – 这应该自动发生(就像使用codec.releaSEOutputBuffer(outputBufferID,true)在Decoder输出上完成的那样;).但是,我相信oninputBufferAvailable需要调用codec.queueinputBuffer才能运行.我只是不知道如何设置参数而不从像Decode端使用的MediaExtractor那样获取数据.
如果你有一个打开视频文件的示例,解码它,使用异步MediaCodec回调将其编码为不同的分辨率或格式,然后将其保存为文件,请分享您的示例代码.
===编辑===
这是我在异步模式下尝试做的同步模式的一个工作示例:ExtractDecodeEditEncodeMuxTest.java:https://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java此示例在我的应用程序中工作
解决方法:
我相信你不需要在编码器的oninputBufferAvailable()回调中做任何事情 – 你不应该调用encoder.queueinputBuffer().就像在同步模式下进行Surface输入编码时从不手动调用encoder.dequeueinputBuffer()和encoder.queueinputBuffer()一样,也不应该在异步模式下执行.
当你调用decoder.releaSEOutputBuffer(outputBufferID,true); (在同步和异步模式下),内部(使用您提供的Surface)将输入缓冲区从曲面中取出,将输出渲染到其中,然后将其排列回曲面(到编码器).同步模式和异步模式之间的唯一区别在于缓冲区事件在公共API中的暴露方式,但在使用Surface输入时,它使用不同的(内部)API来访问它,因此同步模式和异步模式应该不重要这一点.
所以据我所知(尽管我自己没有尝试过),你应该只为编码器留下oninputBufferAvailable()回调.
编辑:
所以,我自己尝试这样做,它(几乎)就像上面描述的一样简单.
如果编码器输入表面直接配置为解码器的输出(中间没有SurfaceTexture),那么事情就会起作用,同步解码编码循环转换为异步解码.
但是,如果使用SurfaceTexture,则可能会遇到小问题.如何等待帧到达SurfaceTexture与调用线程有关的问题,请参阅https://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media/src/android/media/cts/DecodeEditEncodeTest.java#106和https://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java#104以及https://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media/src/android/media/cts/OutputSurface.java#113以获取对此的引用.
就我所见,问题是在https://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media/src/android/media/cts/OutputSurface.java#240中的awaitNewImage中.如果应该在主线程上调用onFrameAvailable回调,如果awaitNewImage调用也在主线程上运行,则会出现问题.如果onOutputBufferAvailable回调也在主线程上被调用并且你从那里调用awaitNewImage,那么我们就会遇到一个问题,因为你最终会等待一个回调(使用wait()来阻止整个线程)运行直到当前方法返回.
因此,我们需要确保onFrameAvailable回调与调用awaitNewImage的线程不同.一个非常简单的方法是创建一个新的单独线程,除了服务onFrameAvailable回调之外什么都不做.为此,您可以执行以下 *** 作:这个:
private HandlerThread mHandlerThread = new HandlerThread("CallbackThread"); private Handler mHandler;... mHandlerThread.start(); mHandler = new Handler(mHandlerThread.getLooper());... mSurfaceTexture.setonFrameAvailableListener(this, mHandler);
我希望这足以让您能够解决您的问题,如果您需要我编辑其中一个公共示例以在那里实现异步回调,请告诉我.
EDIT2:
此外,由于GL渲染可能是在onOutputBufferAvailable回调中完成的,因此这可能与设置EGL上下文的线程不同.所以在这种情况下,需要在设置它的线程中释放EGL上下文,如下所示:
mEGL.eglMakeCurrent(mEGLdisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
并在渲染之前将其重新附加到另一个线程中:
mEGL.eglMakeCurrent(mEGLdisplay, mEGLSurface, mEGLSurface, mEGLContext);
EDIT3:
另外,如果在同一线程上接收到编码器和解码器回调,则执行渲染的解码器onOutputBufferAvailable可以阻止编码器回调被传递.如果它们未被传递,则可以无限制地阻止渲染,因为编码器没有获得返回的输出缓冲区.这可以通过确保在不同的线程上接收视频解码器回调来解决,这避免了onFrameAvailable回调的问题.
我尝试在ExtractDecodeEditEncodeMuxTest之上实现所有这些,并使其工作看起来很好,看看https://github.com/mstorsjo/android-decodeencodetest.我最初导入了未更改的测试,并进行了异步模式的转换并分别修复了棘手的细节,使其变得容易查看提交日志中的各个修复程序.
总结以上是内存溢出为你收集整理的Android MediaCodec在异步模式下编码和解码全部内容,希望文章能够帮你解决Android MediaCodec在异步模式下编码和解码所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)