Android MediaCodec.INFO\u输出\u格式\u在某些设备中解码h.264时未调用更改
我正在使用以下代码准备硬件解码器。我希望outputBufferIndex为-1,然后是MediaCodec.INFO\u OUTPUT\u FORMAT\u CHANGED。在通知格式更改之前,不应>=0 我在25个不同的设备上测试了代码,其中7个设备从未返回信息、输出和格式。当我得到outputBufferIndex>=0时,mediaCodec.getOutputFormat()返回了IllegalStateException。我不知道所有不能工作的设备都是安卓4.2.2和OMX.qcom.video.decoder.avc解码器,这是否是巧合Android MediaCodec.INFO\u输出\u格式\u在某些设备中解码h.264时未调用更改,android,h.264,decoder,android-mediacodec,Android,H.264,Decoder,Android Mediacodec,我正在使用以下代码准备硬件解码器。我希望outputBufferIndex为-1,然后是MediaCodec.INFO\u OUTPUT\u FORMAT\u CHANGED。在通知格式更改之前,不应>=0 我在25个不同的设备上测试了代码,其中7个设备从未返回信息、输出和格式。当我得到outputBufferIndex>=0时,mediaCodec.getOutputFormat()返回了IllegalStateException。我不知道所有不能工作的设备都是安卓4.2.2和OMX.qcom
for (int i = 0; i < videoExtractor.getTrackCount(); i++) {
MediaFormat mediaFormat = videoExtractor.getTrackFormat(i);
String mime = mediaFormat.getString(MediaFormat.KEY_MIME);
if (mime.startsWith("video/")) {
videoExtractor.selectTrack(i);
videoCodec = MediaCodec.createDecoderByType(mediaFormat.getString(MediaFormat.KEY_MIME));
videoCodec.configure(mediaFormat, null, null, 0);
videoCodec.start();
}
}
ByteBuffer[] videoInputBuffers = videoCodec.getInputBuffers();
while (true) {
int sampleTrackIndex = videoExtractor.getSampleTrackIndex();
if (sampleTrackIndex == -1) {
break;
} else { // decode video
int inputBufferIndex = videoCodec.dequeueInputBuffer(0);
if (inputBufferIndex >= 0) {
int bytesRead = videoExtractor.readSampleData(videoInputBuffers[inputBufferIndex], 0);
if (bytesRead >= 0) {
videoCodec.queueInputBuffer(inputBufferIndex, 0, bytesRead,
videoExtractor.getSampleTime(), 0);
videoExtractor.advance();
}
}
MediaCodec.BufferInfo videoBufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = videoCodec.dequeueOutputBuffer(videoBufferInfo, 0);
if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat format = videoCodec.getOutputFormat();
Log.w("video format changed: " + videoCodec.getOutputFormat());
//do something...
break;
} else if (outputBufferIndex >= 0) {
//not supposed to happen!
}
}
}
for(int i=0;i=0){
int bytesRead=videoExtractor.readSampleData(videoInputBuffers[inputBufferIndex],0);
如果(字节读取>=0){
videoCodec.queueInputBuffer(inputBufferIndex,0,字节读取,
videoExtractor.getSampleTime(),0);
视频提取器;
}
}
MediaCodec.BufferInfo videoBufferInfo=新的MediaCodec.BufferInfo();
int outputBufferIndex=videoCodec.dequeueOutputBuffer(videoBufferInfo,0);
如果(outputBufferIndex==MediaCodec.INFO\u输出\u格式\u已更改){
MediaFormat=videoCodec.getOutputFormat();
w(“视频格式更改:+videoCodec.getOutputFormat());
//做点什么。。。
打破
}else if(outputBufferIndex>=0){
//不应该发生!
}
}
}
非常感谢您提供的线索和帮助 在Android 4.3中,CTS中添加了一组
MediaCodec
测试。如果查看DoEncodeDecodeDeviceOfromBuffer()
的工作方式,您可以看到它在任何数据之前都希望得到信息\u输出\u格式\u更改的结果。如果无法获取,则在尝试获取颜色格式时,对checkFrame()
的调用将失败。在Android 4.3之前,没有测试,任何行为都是可能的
话虽如此,我不记得在(基于高通公司的)Nexus 4上看到过这种行为
无论如何,我不确定这会给你带来多大的阻碍,除非你能够解码高通公司使用的专有缓冲区布局。您可以在同一个checkFrame()
函数中看到,当它看到OMX\u QCOM\u COLOR\u FormatYUV420PackedSemiPlanar64x32Tile2m8ka
时,它会弹出该函数。将输出发送到曲面可能是一个可行的替代方案,具体取决于您正在进行的操作
大部分的MediaCodec
代码都以API 18(安卓4.3)为目标,因为那时行为变得更加可预测。(surface input和MediaMuxer的可用性也具有巨大的价值。)是的,我确实花了大量精力将专有yuv格式(如QCOM_COLOR_FormatYUV420XXX和COLOR_TI_FormatYUV420XXX)转换为I420。当outputBufferIndex>=0时,不仅没有调用更改的信息输出格式,而且没有更新mediaFormat。更糟糕的是,当我释放OutputBuffer时,程序挂起。我尝试了谷歌的软件编解码器,当我在这些设备上执行MediaCodec.configure时,它会挂起,而在其他设备上则可以完美地工作。我检查了csd-0和csd-1,它们都是正确的。