[英]How to get frame timestamp when MediaCodec decoder is configured with SurfaceTexture output?
[英]Android MediaCodec decoder input/output frame count
我正在Android中進行視頻轉碼,並使用標准方法作為這些示例來提取/解碼視頻。 我在具有不同視頻設備的不同設備上測試了相同的過程,但發現解碼器輸入/輸出的幀數存在問題。
對於此問題中的一些時間碼問題,我使用一個隊列來記錄提取的視頻樣本,並在獲得解碼器幀輸出時檢查該隊列,例如以下代碼:(我省略了與編碼有關的代碼以使其更加清晰)
Queue<Long> sample_time_queue = new LinkedList<Long>();
....
// in transcoding loop
if (is_decode_input_done == false)
{
int decode_input_index = decoder.dequeueInputBuffer(TIMEOUT_USEC);
if (decode_input_index >= 0)
{
ByteBuffer decoder_input_buffer = decode_input_buffers[decode_input_index];
int sample_size = extractor.readSampleData(decoder_input_buffer, 0);
if (sample_size < 0)
{
decoder.queueInputBuffer(decode_input_index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
is_decode_input_done = true;
}
else
{
long sample_time = extractor.getSampleTime();
decoder.queueInputBuffer(decode_input_index, 0, sample_size, sample_time, 0);
sample_time_queue.offer(sample_time);
extractor.advance();
}
}
else
{
DumpLog(TAG, "Decoder dequeueInputBuffer timed out! Try again later");
}
}
....
if (is_decode_output_done == false)
{
int decode_output_index = decoder.dequeueOutputBuffer(decode_buffer_info, TIMEOUT_USEC);
switch (decode_output_index)
{
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
{
....
break;
}
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
{
....
break;
}
case MediaCodec.INFO_TRY_AGAIN_LATER:
{
DumpLog(TAG, "Decoder dequeueOutputBuffer timed out! Try again later");
break;
}
default:
{
ByteBuffer decode_output_buffer = decode_output_buffers[decode_output_index];
long ptime_us = decode_buffer_info.presentationTimeUs;
boolean is_decode_EOS = ((decode_buffer_info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0);
if (is_decode_EOS)
{
// Decoder gives an EOS output.
is_decode_output_done = true;
....
}
else
{
// The frame time may not be consistent for some videos.
// As a workaround, we use a frame time queue to guard this.
long sample_time = sample_time_queue.poll();
if (sample_time == ptime_us)
{
// Very good, the decoder input/output time is consistent.
}
else
{
// If the decoder input/output frame count is consistent, we can trust the sample time.
ptime_us = sample_time;
}
// process this frame
....
}
decoder.releaseOutputBuffer(decode_output_index, false);
}
}
}
在某些情況下,如果解碼器給出錯誤值(例如很多0),則隊列可以“校正” PTS。 但是,關於解碼器輸入/輸出的幀數仍然存在一些問題。
在HTC One 801e設備上,我使用編解碼器OMX.qcom.video.decoder.avc解碼視頻(MIME類型為video / avc)。 除最后一個幀外,采樣時間和PTS與這些幀匹配得很好。 例如,如果提取器將100幀然后EOS饋入解碼器,則前99個解碼后的幀具有完全相同的時間值,但是最后一個幀丟失了,我從解碼器得到了輸出EOS。 我測試了由內置攝像機,ffmpeg混合器或Windows上的視頻處理AP編碼的不同視頻。 他們所有的最后一幀都消失了。
在使用OMX.MTK.VIDEO.DECODER.AVC編解碼器的某些鍵盤上,情況變得更加混亂。 一些視頻具有來自解碼器的良好PTS,並且輸入/輸出幀計數正確(即,解碼完成后隊列為空)。 某些視頻的輸入/輸出幀數一致,而解碼器輸出中的PTS不好(我仍然可以通過隊列來糾正它們)。 對於某些視頻,解碼期間會丟失很多幀。 例如,提取器在7秒鍾的視頻中獲得210幀,但解碼器僅輸出最后180幀。 使用相同的解決方法無法恢復PTS。
有什么方法可以預期MediaCodec解碼器的輸入/輸出幀數嗎? 或更准確地說,是要知道解碼器丟棄了哪些幀,而提取器為它提供了具有正確采樣時間的視頻采樣?
與其他問題相同的基本故事。 在4.3之前的版本中,沒有測試可以確認輸入到編碼器或解碼器的每個幀都來自另一側。 我記得某些設備在某些測試中會可靠地丟棄最后一幀,直到編解碼器在4.3中得到修復。
當時我沒有尋找解決方法,所以我不知道是否存在。 如果EOS導致某些東西提前關閉,則延遲發送EOS可能會有所幫助。
我不相信我曾經見過設備掉落大量幀。 這似乎是一種不尋常的情況,因為即使沒有經過仔細測試,在以類似方式行使MediaCodec
任何應用程序中也會注意到這一點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.