使用媒体基础在 windows 上解码 android h264 编码流

decoding android h264 encoded stream on windows using media foundation

我正在尝试在 windows 电脑上解码从 android 设备流式传输的 h264 编码相机帧。 我正在使用 MediaFoundation H264 解码器解码从 android 设备发送的每一帧。但是我不断收到错误 'more input samples are required to process output error'.

MF H264解码器要求如下:

Media samples contain H.264 bitstream data with start codes and has interleaved SPS/PPS. Each sample contains one complete picture, either one field or one frame.

我想知道这是否与我从 android 设备发送的内容兼容。

我正在使用下面的代码将帧发送到 windows 设备:

    private static class AvcEncoder {

        private MediaCodec mediaCodec;
        final static int FRAME_RATE = 15;
        final static int MOTION_RANK = 2;

        public AvcEncoder(int width, int height) { 

            mediaCodec = MediaCodec.createEncoderByType("video/avc");
            MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height);
            mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, (int)(width*height*FRAME_RATE*MOTION_RANK*0.07));
            mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
            mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
            mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
            mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            mediaCodec.start();
        }

        public void close() {
            try {
                mediaCodec.stop();
                mediaCodec.release();
                outputStream.flush();
                outputStream.close();
            } catch (Exception e){ 
                e.printStackTrace();
            }
        }

        //frames are sent here
        public void offerEncoder(byte[] input) {
            try {
                ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
                ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
                int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
                if (inputBufferIndex >= 0) {
                    ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
                    inputBuffer.clear();
                    inputBuffer.put(input);
                    mediaCodec.queueInputBuffer(inputBufferIndex, 0, input.length, 0, 0);
                }

                MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
                int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);
                while (outputBufferIndex >= 0) {
                    ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
                    byte[] outData = new byte[bufferInfo.size];
                    outputBuffer.get(outData);
// write frame length
                    byte frameLength[] = ByteBuffer.allocate(4).putInt(outData.length).array();
                    outputStream.write(frameLength, 0, 4);
// write the actual frame
                    outputStream.write(outData, 0, outData.length);
                    Log.i("AvcEncoder", outData.length + " bytes written");
                    mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
                    outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
                }
            } catch (Throwable t) {
                t.printStackTrace();
            }

        }

如果需要,我也可以 post Windows 代码。

此外,当我将流式传输数据保存到文件时,我可以在 VLC 中播放它,因此 VLC 能够很好地理解和解码它。

好吧,修复非常简单。我不知道为什么,但 Media Foundation 要求您设置提供给解码器的每个样本的持续时间或时间戳。然而,输出似乎不受这两个参数的任何影响。

编辑: 请注意 IMFTransformInputProcess 方法应该 return MF_E_NO_SAMPLE_DURATIONMF_E_NO_SAMPLE_TIMESTAMP 如果在传递的 IMFSample 对象中未设置样本持续时间或时间戳InputProcess 方法。但是,在我的例子中,它没有 return 任何这样的值。