Android MediaCodec.INFO\u输出\u格式\u在某些设备中解码h.264时未调用更改

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

我正在使用以下代码准备硬件解码器。我希望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解码器,这是否是巧合

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,它们都是正确的。