2016-07-05 2 views
1

Я вручную читаю поток RTP/H264 и передаю кадры H264 на Android MediaCodec. Я использую «markerBit» в качестве рамки для фреймов. MediaCodec привязан к текстуре OpenGL (SurfaceTexture). В целом все работает нормально. Но декодер выглядит как буферный кадр. Если я поместил фрейм в декодер, он сразу не отображается текстуре. После того, как я поместил в декодер 2-3 кадра больше, первый кадр отображается текстуре.Android MediaCodec появляется для хранения кадров H264

Я реализую Android 4.4.4.

private static final int INFINITE_TIMEOUT = -1; 
private static final int TIMEOUT_OUTPUT_BUFFER_MEDIA_CODEC = 1000; 
... 
int bufferIndex = codec.dequeueInputBuffer(INFINITE_TIMEOUT); 
if (bufferIndex < 0) { 
    throw new RuntimeException("Error"); 
} 

ByteBuffer inputBuffer = inputBuffers[bufferIndex]; 
inputBuffer.clear(); 

// Copy H264 data to inputBuffer 
h264Frame.fill(inputBuffer); 

codec.queueInputBuffer(bufferIndex, 0, inputBuffer.position(), 0, 0); 
drainOutputBuffers(); 
... 

и

private boolean drainOutputBuffers() { 
MediaCodec.BufferInfo buffInfo = new MediaCodec.BufferInfo(); 

int outputBufferIndex = codec.dequeueOutputBuffer(buffInfo, TIMEOUT_OUTPUT_BUFFER_MEDIA_CODEC); 

if (outputBufferIndex >= 0) { 
    codec.releaseOutputBuffer(outputBufferIndex, true); 
    return true; 
} 

switch (outputBufferIndex) { 
    case MediaCodec.INFO_TRY_AGAIN_LATER: 
    LOG.debug("Could not dequeue output buffer. Try again later"); 
    break; 
    case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED: 
    LOG.warn("The output format has changed."); 
    break; 
    case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED: 
    LOG.warn("The output buffers has changed."); 
    break; 
    default: 
    LOG.warn("The output buffer index was negative: {}", outputBufferIndex); 
} 
return false; 
} 

На стороне рендеринга я использую «onFrameAvailable» обратный вызов для проверки, если я должен обновить текстуру на OPENGL тему. Флаг, который я использую для проверки, защищен блокировкой (синхронизирован).

Я подозреваю, что временная метка презентации может повлиять на рендеринг. Но я установил его равным 0. Таким образом, я предполагаю, что кадр должен отображаться без задержки.

Я хотел бы, чтобы рамка была обработана текстурой без необходимости добавления дополнительных кадров.

+1

Я не думаю, что это характер декодера h264, это, скорее всего, недостаток в MediaCodec. Если я делаю это на ПК с помощью ffmpeg, задержки нет. – user3667089

ответ

1

От MediaCodec documentation

Исполнительное состояния имеет три подсостояния: раскрасневшиеся, бег и конца-Stream. Сразу после start() кодек находится в под-состоянии Flushed , где он содержит все буферы. Как только первый вход буфера отменяется, кодек переходит в подчиненное состояние, где он проводит большую часть своей жизни. Когда вы размещаете буфер ввода с маркером конца строки , кодек переходит в под-состояние . В этом состоянии кодек больше не принимает дополнительные входные буферы , но по-прежнему генерирует выходные буферы до тех пор, пока конечный поток не достигнет , достигнутого на выходе. Вы можете вернуться обратно в очищенное под-состояние в в любое время, находясь в состоянии Executing, используя flush().

Вам необходимо «поставить очередь буфера ввода с маркером end-of-stream». Сделайте это с первым кадром, который вы подаете на декодер (убедитесь, что это ключевой кадр).

Этот момент должен сказать декодеру не ожидать больше кадров и, следовательно, немедленно начать воспроизведение. В противном случае, как правило, нужно кормить 3 или 4 кадра, прежде чем что-либо увидеть. Это ожидание всех MPEG-декодеров и не связано с Android.

+0

Когда я отправляю флаг конца потока вместе с первым ключевым фреймом, mediacodec перестает работать. – Soccertrash

+1

В этом ** [link] (https://developer.android.com/reference/android/media/MediaCodec.html) ** Я отправил, прокрутите вниз до «Штатов» и внимательно прочитайте это. Рассмотрим также использование 'flush()' на декодере. Дело в том, что каждый кадр является частью ** G ** roup ** O ** f ** P ** ictures (например: ** I ** сопровождается ** P ** и ** B ** кадры). P & B всегда нуждается в ** I ** (ключевой кадр), поэтому он остается в стороне для справки, пока вы отправляете 3 или 4 (P или B) кадра, прежде чем что-либо увидите. Точка «конец потока» и «флеш» равна произношению «после моего ключевого кадра ничего нет, покажите его сейчас». –

+1

Я хотел прочитать ссылку и применить то, что говорит документация. Ваша проблема заключается в декодере MPEG, хранящем ключевой кадр (полное изображение) в стороне для ссылки некоторыми кадрами типа P и B (у них меньше информации о снимке, поэтому они получают недостающие части из ключевого кадра). Удалите поток, если это поможет. Решение состоит в том, чтобы как-то сообщить системе, что после того, как один кадр вы отправили для декодирования, поток теперь переполнен и поэтому отправляет данные через декодер (отображаемое изображение) ... –

-1

Mediacodec декодер буферирует 6-7 кадров перед выходом первого декодированного выходного кадра. Похоже, что он ошибается в медикакодеке. Это будет проблемой в потоковом приложении. Пока что моя отладка показывает декодирование H264 с mediacodec с задержкой 6-7 кадров во время запуска потока.

Смежные вопросы