关于我的关于orroids MediaCodec类的问题。我已成功设法解码原始h264内容并在两个TextureViews中显示结果。 h264流来自运行openGL场景的服务器。场景有一个摄像头,因此响应用户输入。为了进一步减少服务器上的输入和智能手机上的实际结果之间的延迟,我正在考虑使用MediaCodecs异步模式。 以下是我如何设置同步和异步两种变体:
异步:
//decoderCodec is "video/avc"
MediaFormat fmt = MediaFormat.createVideoFormat(decoderCodec, 1280,720);
codec.setCallback(new MediaCodec.Callback() {
@Override
public void onInputBufferAvailable(MediaCodec codec, int index) {
byte[] frameData;
try {
frameData = frameQueue.take(); //this call is blocking
} catch (InterruptedException e) {
return;
}
ByteBuffer inputData = codec.getInputBuffer(index);
inputData.clear();
inputData.put(frameData);
codec.queueInputBuffer(index, 0, frameData.length, 0, 0);
}
@Override
public void onOutputBufferAvailable(MediaCodec codec, int index, MediaCodec.BufferInfo info) {
codec.releaseOutputBuffer(index, true);
}
//The two other methods are left blank at the moment.
});
codec.configure(fmt, surface, null, 0);
codec.start();
同步:(除了codec.setCallback(...)
部分之外,设置为Async。两个变体所在的类都是Runnable。
public void run() {
while(!Thread.interrupted())
{
if(!IS_ASYNC) {
byte[] frameData;
try {
frameData = frameQueue.take(); //this call is blocking
} catch (InterruptedException e) {
break;
}
int inIndex = codec.dequeueInputBuffer(BUFFER_TIMEOUT);
if (inIndex >= 0) {
ByteBuffer input = codec.getInputBuffer(inIndex);
input.clear();
input.put(frameData);
codec.queueInputBuffer(inIndex, 0, frameData.length, 0, 0);
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outIndex = codec.dequeueOutputBuffer(bufferInfo, BUFFER_TIMEOUT);
if(outIndex >= 0)
codec.releaseOutputBuffer(outIndex, true);
}
else sleep(3000); //Just for testing, if we are in Async, this thread has nothing to do actually...
}
}
这两种方法都有效,但我观察到以同步模式播放的视频更加流畅,延迟也更低。
我提出了使用异步模式的想法,因为frameQueue
是LinkedBlockingDeque
我想,如果同步解码器等待新帧数据到达的时间太长,则解码输出可能已经可用但由于队列的阻塞性质而未显示。另一方面,我不想做像忙等待和轮询队列,inputBuffers和outputBuffers一样的事情。
所以我尝试使用Callbacks的AsyncMode,但是我得到的结果比同步模式更差。你们现在的问题是:为什么?我是否滥用异步模式或者其他什么?
感谢您的反馈!
Christoph
答案 0 :(得分:5)
如果onInputBufferAvailable
中的阻止呼叫是罪魁祸首,我不会感到惊讶。感觉很可能在同一个线程中调用了onInputBufferAvailable
和onOutputBufferAvailable
,如果你阻塞了一个,就会阻止另一个运行。
我建议更改它,以便你在onInputBufferAvailable
中将缓冲区索引推送到某个队列,并发出一个不同的线程,表示现在有另一个缓冲区,然后让第二个线程等待队列中的缓冲区,并在那里阻止获取输入数据。