Как уменьшить задержку при декодировании видео/avc MediaCodec

Я выполнил простой хронометраж MoviePlayer.java в примере кода Grafika MediaCodec, работающего на Nexus 5. Я поместил оператор журнала в следующие места:

В строке 203 непосредственно перед

decoder.queueInputBuffer

В строке 244 после

decoder.dequeueOutputBuffer

Я сопоставил операторы журнала, используя presentationTimeUs.

Вот выдержка из logcat:

01-29 10:56:43.295: I/Grafika(21286): queueInputBuffer index/pts, 2,0
01-29 10:56:43.305: I/Grafika(21286): queueInputBuffer index/pts, 0,33100
01-29 10:56:43.315: I/Grafika(21286): queueInputBuffer index/pts, 3,66466
01-29 10:56:43.325: I/Grafika(21286): queueInputBuffer index/pts, 1,99833
01-29 10:56:43.325: I/Grafika(21286): queueInputBuffer index/pts, 2,133200
01-29 10:56:43.335: I/Grafika(21286): queueInputBuffer index/pts, 0,166566
01-29 10:56:43.345: I/ATSParser(21286): discontinuity on stream pid 0x1011
01-29 10:56:43.345: I/ATSParser(21286): discontinuity on stream pid 0x1100
01-29 10:56:43.345: I/Grafika(21286): queueInputBuffer index/pts, 3,199933
01-29 10:56:43.345: I/Grafika(21286): dequeueOutputBuffer index/pts, 7,0
01-29 10:56:43.345: I/Grafika(21286): queueInputBuffer index/pts, 1,300033
01-29 10:56:43.355: I/Grafika(21286): dequeueOutputBuffer index/pts, 6,33100
01-29 10:56:43.385: I/Grafika(21286): queueInputBuffer index/pts, 2,333400
01-29 10:56:43.385: I/Grafika(21286): dequeueOutputBuffer index/pts, 5,66466
01-29 10:56:43.415: I/Grafika(21286): queueInputBuffer index/pts, 0,366766
01-29 10:56:43.415: I/Grafika(21286): dequeueOutputBuffer index/pts, 4,99833
01-29 10:56:43.445: I/Grafika(21286): queueInputBuffer index/pts, 3,400133
01-29 10:56:43.445: I/Grafika(21286): dequeueOutputBuffer index/pts, 3,133200

Я обнаружил, что разница во времени между моментом постановки в очередь первого входного буфера и моментом исключения из очереди соответствующего выходного буфера составляет 50 миллисекунд. Кажется, что это слишком много времени для аппаратно-ускоренного декодирования.

Есть ли способ уменьшить эту задержку?


person Peter Tran    schedule 29.01.2014    source источник
comment
Я заметил, что @fadden упоминает, что Surface использует BufferQueue в этом ответе: stackoverflow.com/a/19260131/783051. Есть ли другая буферизация, которую я настраиваю?   -  person Peter Tran    schedule 29.01.2014


Ответы (1)


Я думаю, вы видите некоторые эффекты, уникальные для первого кадра. Я повторил ваш эксперимент с дальнейшим добавлением принудительного doRender = false вокруг строки 244, чтобы избежать вызовов сна, используемых для управления выходной частотой кадров. Я понимаю:

01-29 14:05:36.552  9115  9224 I Grafika : queueInputBuffer index/pts, 2,0
01-29 14:05:36.562  9115  9224 I Grafika : queueInputBuffer index/pts, 0,66655
01-29 14:05:36.572  9115  9224 I Grafika : queueInputBuffer index/pts, 3,133288
01-29 14:05:36.582  9115  9224 I Grafika : queueInputBuffer index/pts, 1,199955

01-29 14:05:36.602  9115  9224 I Grafika : dequeueOutputBuffer index/pts, 4,0
01-29 14:05:36.602  9115  9224 I Grafika : dequeueOutputBuffer index/pts, 3,66655
01-29 14:05:36.602  9115  9224 I Grafika : dequeueOutputBuffer index/pts, 2,133288
01-29 14:05:36.612  9115  9224 I Grafika : dequeueOutputBuffer index/pts, 4,199955

(Лишние линии удалены для ясности.) Это подтверждает ваши результаты. Обратите внимание, что несмотря на задержку в 50 мс между вводом и выводом для pts=0, последующие выходные кадры были доступны почти мгновенно. Я использовал видео «camera-test.mp4» (выход камеры 720p).

Чтобы понять, почему это происходит, взгляните на другие данные в журнале и на то, где они появляются. Начиная с первой queueInputBuffer строки журнала, подсчитайте количество журналов, которые появляются между этой и первой dequeueOutputBuffer строкой. Я насчитал около 60 строк вывода OMX-VDEC-1080P на моем. Теперь подсчитайте, сколько строк OMX-VDEC появится после того, как начнут появляться выходные буферы. Я не вижу ничего, пока видео не закончится.

Видеодекодер явно откладывает дорогостоящую инициализацию до тех пор, пока не будут доступны данные. Итак, следующий вопрос: сколько данных ему нужно? Я добавил 500 мс сна после отправки второго кадра (pts==66633). Результат: два отправленных кадра, пауза 500 мс, два отправленных кадра, большая куча логов OMX-VDEC. Таким образом, кажется, что декодер хочет несколько кадров, прежде чем он запустится.

Это говорит о том, что мы можем уменьшить задержку при запуске, быстро загружая первые несколько кадров. Чтобы проверить это, я изменил TIMEOUT_USEC на ноль, чтобы он реагировал быстро, но сжигал процессор. Новый вывод журнала (ваши журналы, без сна, без рендеринга):

01-29 14:29:04.542 10560 10599 I Grafika : queueInputBuffer index/pts, 0,0
01-29 14:29:04.542 10560 10599 I Grafika : queueInputBuffer index/pts, 2,66633
01-29 14:29:04.542 10560 10599 I Grafika : queueInputBuffer index/pts, 3,133288
...
01-29 14:29:04.572 10560 10599 I Grafika : dequeueOutputBuffer index/pts, 4,0
01-29 14:29:04.572 10560 10599 I Grafika : dequeueOutputBuffer index/pts, 3,66633
01-29 14:29:04.572 10560 10599 I Grafika : dequeueOutputBuffer index/pts, 2,133288

За счет быстрой подачи начальных кадров мы сократили начальную задержку с 50 мс до 30 мс.

(Обратите внимание, что все метки времени заканчиваются на «2»? Таймер, используемый для регистрации времени, кажется, округляется до ближайших 10 мс, поэтому фактическая дельта времени может немного отличаться.)

Причина, по которой мы загружаем начальные кадры медленно, заключается в том, что мы пытаемся слить вывод из декодера после отправки каждого входного буфера, ожидая 10 мс для вывода, который никогда не появляется. Моя первоначальная мысль заключалась в том, что мы хотим дождаться тайм-аута на либо dequeueInputBuffer() или dequeueOutputBuffer(), но не на обоих — возможно, использовать тайм-аут на вводе и быстрый опрос для сначала выводить, а затем переключаться на тайм-аут на выходе, когда у нас заканчивается ввод для подачи. (В этом отношении начальный тайм-аут для ввода может быть равен -1, поскольку мы знаем, что ничего не произойдет, пока первый входной буфер не будет поставлен в очередь.)

Я не знаю, есть ли способ еще больше уменьшить задержку.

person fadden    schedule 29.01.2014
comment
Что вы думаете о рендеринге на основе Choreographer.FrameCallback ? Проект Chromium заключает это в хороший класс с именем VSyncMonitor Таким образом, вместо того, чтобы вызывать удаление из очереди, а затем переходить в спящий режим для темпа вывода, я бы сначала принял решение, следует ли выполнить рендеринг, а затем удалить из очереди. Мысли? - person Peter Tran; 12.02.2014
comment
Вероятно, вам следует поместить это в новый вопрос. FWIW, приложение Grafika Record GL с активностью FBO управляется хореографом. - person fadden; 13.02.2014