我有一个h264流,想要使用Android 4.1.2
使用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)
答案 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。