android mediacodec只在收到下一个后播放I-Frame(I帧之间的时差为2-3秒)

时间:2015-04-06 18:50:52

标签: android mediacodec

我正在尝试使用Android MediaCodec解码NAL设备。问题是视频播放的延迟时间为2-3秒,因为第一个I帧仅在接收到下一个I帧后播放(I帧之间的时差为2-3秒)。因此,如果我连续两次放置相同的I帧,那么它将毫无延迟地播放。但在这种情况下,我无法播放其余帧。

我不明白问题是什么。我试图自己解决它,但我不能。

public void play(MediaCodec decoder, PESPacket currentPES){
    byte[] data = currentPES.data.toByteArray();
    pts = currentPES.getPts();

    try {
        if (data[4] == 0x67) {
            Log.d(TAG, "found sps/pps!");
            int ibs = decoder.dequeueInputBuffer(0);
            if (ibs >= 0) {
                ByteBuffer buffer = decoder.getInputBuffers()[ibs];
                buffer.clear();
                buffer.put(data);
                decoder.queueInputBuffer(ibs, 0, data.length, pts, MediaCodec.BUFFER_FLAG_CODEC_CONFIG);
            }
        } else {
            if (data[4] == 0x41) {              // not I-frame
                int ibs = decoder.dequeueInputBuffer(0);
                if (ibs >= 0) {
                    System.out.println("queueInputBuffer little");
                    ByteBuffer buffer = decoder.getInputBuffers()[ibs];
                    buffer.clear();
                    buffer.put(data);
                    decoder.queueInputBuffer(ibs, 0, data.length, pts, 0);
                }
            }
            if (data[4] == 0x65) {              // I-frame
                int ibs = decoder.dequeueInputBuffer(0);
                if (ibs >= 0) {
                    System.out.println("queueInputBuffer");
                    ByteBuffer buffer = decoder.getInputBuffers()[ibs];
                    buffer.clear();
                    buffer.put(data);
                    decoder.queueInputBuffer(ibs, 0, data.length, pts, 0);
                }

            }
        }

        int outputBufferIndex = decoder.dequeueOutputBuffer(bufferInfo, 10000);
        if (outputBufferIndex >= 0) {
            System.out.println("releaseOutputBuffer " + outputBufferIndex);
            decoder.releaseOutputBuffer(outputBufferIndex, true);
        } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
            System.out.println("INFO_OUTPUT_BUFFERS_CHANGED ");
        } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            MediaFormat format = decoder.getOutputFormat();
            System.out.println("INFO_OUTPUT_FORMAT_CHANGED " + format);
        }
    } catch (Throwable t) {
        t.printStackTrace();
    }
}    

1 个答案:

答案 0 :(得分:0)

可能为时已晚,但想分享一些信息。

如果仅将IDR帧发送到视频解码器,则可以在配置解码器时尝试将MediaFormat中的“ android._num-input-buffers”和“ android._num-output-buffers”设置为1。这将尝试在视频解码器中分配单个缓冲区,从而立即输出缓冲区。但是,行为不能保证,将取决于解码器的实现。

我猜测Google的H264解码器软件“ omx.google.h264.decoder”应该支持此行为,但我尚未进行测试。

有关如何设置参数的信息,请参考以下Android源代码FrameDecoder.cpp。 FrameDecoder.cpp是Android API MetaDataExtractor.getFrameAt()的框架层实现。

http://androidxref.com/9.0.0_r3/xref/frameworks/av/media/libstagefright/FrameDecoder.cpp#411

451    // For the thumbnail extraction case, try to allocate single buffer in both
452    // input and output ports, if seeking to a sync frame. NOTE: This request may
453    // fail if component requires more than that for decoding.
454    bool isSeekingClosest = (mSeekMode == MediaSource::ReadOptions::SEEK_CLOSEST)
455            || (mSeekMode == MediaSource::ReadOptions::SEEK_FRAME_INDEX);
456    if (!isSeekingClosest) {
457        videoFormat->setInt32("android._num-input-buffers", 1);
458        videoFormat->setInt32("android._num-output-buffers", 1);
459    }