MediaCodec Buffer Underflow excel

时间:2014-01-30 15:08:42

标签: android mediacodec

我有一个h264流,想要使用Android 4.1.2

中的MediaCodec进行解码

使用ffmpeg可以解码流,但速度慢,所以我想使用MediaCodec。手机是三星Galaxy S3

点击按钮,将启动一项新活动。

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    test = new SurfaceView(getApplicationContext());
    test.getHolder().addCallback(this);
    setContentView(test);
}

在回调中

public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
    // TODO Auto-generated method stub
    //codedBuffer = new byte[1536000];
    if(wt == null){
        wt = new RenderThread(arg0.getSurface());
        wt.start();
    }

}

其中RenderThread是

public void run() {
formatIn = MediaFormat.createVideoFormat("video/avc", 480, 800);
coder = MediaCodec.createDecoderByType("video/avc");
if(formatIn != null)
    coder.configure(formatIn, mSurface, null, 0);
coder.start();
ByteBuffer[] inputBuffers = coder.getInputBuffers();
ByteBuffer[] outputBuffers = coder.getOutputBuffers();
mBufferInfo = new BufferInfo();
while(!Thread.interrupted()){

    while(waitForStream){
        Thread.yield();
}
if(!EOS ){

int inBufIndex = coder.dequeueInputBuffer(10000);
if(inBufIndex != -1){
ByteBuffer buffer = inputBuffers[inBufIndex]; 
buffer.put(receivebuffer,0,size);
coder.queueInputBuffer(inBufIndex, 0, size, 0,0);
}
int outBufIndex = coder.dequeueOutputBuffer(mBufferInfo, 10000);
switch (outBufIndex) {
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
Log.d("DecodeActivity", "INFO_OUTPUT_BUFFERS_CHANGED");
outputBuffers = coder.getOutputBuffers();
break;
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
Log.d("DecodeActivity", "New format " );
break;
case MediaCodec.INFO_TRY_AGAIN_LATER:
    Log.d("DecodeActivity", "dequeueOutputBuffer timed out!");
    break;
default:
//  ByteBuffer buffer = outputBuffers[outBufIndex];
//  buffer.get(decodedBuffer);
    coder.releaseOutputBuffer(outBufIndex, true);
}
}

decodedBuffer是一个字节[1536000]

更新的错误日志是

02-03 05:53:20.065: I/OMXClient(12333): Using client-side OMX mux.
02-03 05:53:20.145: D/DecodeActivity(12333): dequeueOutputBuffer timed out!
02-03 05:53:20.170: D/DecodeActivity(12333): dequeueOutputBuffer timed out!
02-03 05:53:20.195: D/DecodeActivity(12333): dequeueOutputBuffer timed out!
02-03 05:53:20.215: D/DecodeActivity(12333): dequeueOutputBuffer timed out!
02-03 05:53:20.270: D/DecodeActivity(12333): dequeueOutputBuffer timed out!
02-03 05:53:20.290: D/DecodeActivity(12333): dequeueOutputBuffer timed out!
02-03 05:53:20.295: E/SpannableStringBuilder(12333): SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
02-03 05:53:20.295: E/SpannableStringBuilder(12333): SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
02-03 05:53:20.310: D/DecodeActivity(12333): dequeueOutputBuffer timed out!
02-03 05:53:20.330: D/DecodeActivity(12333): dequeueOutputBuffer timed out!
02-03 05:53:20.355: D/DecodeActivity(12333): dequeueOutputBuffer timed out!
02-03 05:53:20.375: D/DecodeActivity(12333): dequeueOutputBuffer timed out!
02-03 05:53:20.395: D/DecodeActivity(12333): dequeueOutputBuffer timed out!
02-03 05:53:20.410: D/DecodeActivity(12333): dequeueOutputBuffer timed out!
02-03 05:53:20.420: D/DecodeActivity(12333): dequeueOutputBuffer timed out!
02-03 05:53:20.425: D/DecodeActivity(12333): New format 
02-03 05:53:20.485: D/DecodeActivity(12333): dequeueOutputBuffer timed out!
02-03 05:53:20.605: W/dalvikvm(12333): threadid=15: thread exiting with uncaught exception (group=0x40de32a0)
02-03 05:53:20.605: E/AndroidRuntime(12333): FATAL EXCEPTION: Thread-658
02-03 05:53:20.605: E/AndroidRuntime(12333): java.nio.BufferOverflowException
02-03 05:53:20.605: E/AndroidRuntime(12333):    at java.nio.Buffer.checkPutBounds(Buffer.java:189)
02-03 05:53:20.605: E/AndroidRuntime(12333):    at java.nio.ReadWriteDirectByteBuffer.put(ReadWriteDirectByteBuffer.java:100)
02-03 05:53:20.605: E/AndroidRuntime(12333):    at java.nio.ByteBuffer.put(ByteBuffer.java:712)

1 个答案:

答案 0 :(得分:3)

由于这是get()电话,我认为你在这里失败了:

ByteBuffer buffer = outputBuffers[outBufIndex];
buffer.get(decodedBuffer);

如果您查看与原始YUV数据一起使用的CTS EncodeDecodeTest,您会看到一个额外的位:

ByteBuffer outputFrame = decoderOutputBuffers[decoderStatus];
outputFrame.position(info.offset);
outputFrame.limit(info.offset + info.size);

MediaCodec代码无法读取或更新ByteBuffer状态,因此您必须明确地执行此操作。这也适用于输入端。

EncodeDecodeTest的缓冲区到缓冲区和缓冲区到表面的部分将与API 16一起使用,并且可用于检查。表面到表面测试需要API 18。

你会发现一件事是测试没有将缓冲区内容提取到固定大小的数组,因为帧的解码大小是静态不可知的。您需要知道输出的颜色格式,这将随设备的不同而不同。您还会发现checkFrame()完全放弃某些设备,因为它不了解帧格式。

如果您可以解码到Surface,您的代码可以像checkSurfaceFrame()那样工作,而您不关心缓冲区格式,因为OpenGL ES可以完成所有工作。另请参阅ExtractMpegFramesTest