Dav*_*arl 14 android video-encoding mediacodec android-5.0-lollipop android-5.1.1-lollipop
我正在尝试解码文件中的视频,并使用API Level 21及更高版本(Android OS 5.0 Lollipop)支持MediaCodec
的新异步模式将其编码为不同的格式.
在Big Flake,Google的Grafika等网站上以同步模式执行此操作有很多示例,并且StackOverflow上有许多答案,但它们都不支持异步模式.
我不需要在此过程中显示视频.
我相信一般的程序是用一个读取文件MediaExtractor
作为MediaCodec
(解码器)的输入,允许解码器的输出渲染成一个Surface
也是共享输入到MediaCodec
(编码器),然后最后写入编码器输出文件通过MediaMuxer
.它Surface
是在编码器设置期间创建的,并与解码器共享.
我可以将视频解码为a TextureView
,但Surface
与编码器共享而不是屏幕也没有成功.
我MediaCodec.Callback()
为我的两个编解码器设置了s.我认为问题在于我不知道在Encoder的回调onInputBufferAvailable()
函数中该怎么做.我不知道(或知道如何)将数据从Surface
编码器复制到编码器中 - 这应该自动发生(就像在解码器输出上一样codec.releaseOutputBuffer(outputBufferId, true);
).然而,我认为onInputBufferAvailable
需要打电话codec.queueInputBuffer
才能运作.我只是不知道如何设置参数而不从像MediaExtractor
Decode端使用的那样获取数据.
如果您有一个打开视频文件MediaCodec
的示例,对其进行解码,使用异步回调将其编码为不同的分辨率或格式,然后将其保存为文件,请分享您的示例代码.
=== 编辑 ===
下面是我在异步模式下尝试做的同步模式的一个工作示例:ExtractDecodeEditEncodeMuxTest.java:https://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media /src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java这个例子在我的应用程序中工作
mst*_*sjo 14
我相信你不需要在编码器的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以获取参考对此.
就我看来,问题awaitNewImage
出在https://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media/src/android/media/cts/ OutputSurface.java#240.如果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);
Run Code Online (Sandbox Code Playgroud)
我希望这足以让您能够解决您的问题,如果您需要我编辑其中一个公共示例以在那里实现异步回调,请告诉我.
EDIT2:
此外,由于GL渲染可能是在onOutputBufferAvailable
回调中完成的,因此这可能与设置EGL上下文的线程不同.所以在这种情况下,需要在设置它的线程中释放EGL上下文,如下所示:
mEGL.eglMakeCurrent(mEGLDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
Run Code Online (Sandbox Code Playgroud)
并在渲染之前将其重新附加到另一个线程中:
mEGL.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext);
Run Code Online (Sandbox Code Playgroud)
EDIT3:
此外,如果在同一线程上接收到编码器和解码器回调,则onOutputBufferAvailable
执行渲染的解码器可以阻止编码器回调被传递.如果它们未被传递,则可以无限制地阻止渲染,因为编码器没有获得返回的输出缓冲区.这可以通过确保在不同的线程上接收视频解码器回调来解决,这避免了onFrameAvailable
回调的问题.
我尝试在这之上实现所有这些ExtractDecodeEditEncodeMuxTest
,并使其工作看起来很好,看看https://github.com/mstorsjo/android-decodeencodetest.我最初导入了未更改的测试,并转换为异步模式并分别修复了棘手的细节,以便于查看提交日志中的各个修复程序.
归档时间: |
|
查看次数: |
9914 次 |
最近记录: |