我正在尝试使用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();
}
}
答案 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 }