[Android媒体编解码器仅在接收到下一帧后播放I帧(I帧之间的时间差为2-3秒)

问题描述 投票:0回答:1

我正在尝试使用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();
    }
}    
android mediacodec
1个回答
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    }
© www.soinside.com 2019 - 2024. All rights reserved.