Я пишу приложение, которое может кодировать видео с помощью входа камеры и обрабатывать видео с помощью шагов декодирования-редактирования-кодирования. Для камеры я использую класс Camera, а не Intent для настройки параметров камеры. Затем я передаю кадры камеры кодировщику (MediaCodec в API 16) и мультиплексору (я использую мультиплексор ffmpeg, так как хочу работать на устройствах 4.1).
Я измеряю временной код кадров камеры по системному нановремени и выбираю подмножество кадров, соответствующее желаемому FPS (в настоящее время 15). Есть небольшие "шумы" в значениях времени, например (в мс): 0, 60718, 135246, 201049, ... вместо 0, 66000, 133000, 200000, ... .
После некоторой попытки правильно настроить мультиплексор (как этот вопрос), я могу создать видео (с кодеком AVC), которое может воспроизводиться видеоплеером на устройствах. Скорость воспроизведения правильная, поэтому я думаю, что видео должно иметь правильную информацию о времени кадров.
Однако у меня возникла проблема, когда я пытаюсь декодировать видео для выполнения процесса редактирования видео. Я использую стандартные шаги извлечения/декодирования видео в виде этих примеров, например:
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);
extractor.advance();
}
}
else
{
Log.v(TAG, "Decoder dequeueInputBuffer timed out! Try again later");
}
Время расчета из getSampleTime() имеет правильное значение, когда я кодирую видео. (например, они ровно 0, 60718, 135246, 201049, ... в нас). Это также время представления на входе decoder.queueInputBuffer(). Когда декодер переходит к декодированию этого кадра, я получаю время кадра:
int decode_output_index = decoder.dequeueOutputBuffer(decode_buffer_info, TIMEOUT_USEC);
switch (decode_output_index)
{
....
(some negative-value flags in MediaCodec)
....
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);
....
}
}
Я ожидаю установить ту же временную последовательность, что и на входе декодера, но я получаю много нулей из BufferInfo на выходе декодера. Содержимое декодированного кадра кажется правильным, но большинство значений времени представления равны 0. Только последние несколько кадров имеют правильное время представления.
Я тестирую весь тот же процесс на устройстве с Android 4.3 (даже с тем же мультиплексором ffmpeg, а не MediaMuxer в API 18), и все выглядит нормально. На устройствах 4.1/4.2, если я захватываю видео с помощью встроенного приложения камеры на устройстве, а затем декодирую видео, время презентации также является правильным, хотя значения времени также имеют шумы из-за задержки камеры.
Что не так с видео или процессом декодирования, когда видео может воспроизводиться и декодироваться нормально, но с правильным временем выборки и плохим временем представления? Возможно, мне придется использовать обходной путь для измерения времени презентации по времени выборки (это легко сделать с помощью очереди), но я хочу выяснить, есть ли какая-то недостающая часть в моей работе.