Декодирование H264 ByteStream на Android
Я хочу декодировать и отображать необработанный поток байтов видео h264 в Android, и поэтому в настоящее время я использую MediaCodec/Format
классы. Я получаю данные кадра через Udp с сервера.
Но, к сожалению, на данный момент ничего не отображается.
вот что у меня до сих пор.
Инициализация Класса MediaCodec:
codec = MediaCodec.createDecoderByType("video/avc");
MediaFormat format = new MediaFormat();
format.setString(MediaFormat.KEY_MIME, "video/avc");
format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 100000);
format.setInteger(MediaFormat.KEY_WIDTH, 800);
format.setInteger(MediaFormat.KEY_HEIGHT, 600);
format.setInteger("max-width", 800);
format.setInteger("max-height", 600);
format.setInteger("push-blank-buffers-on-shutdown", 1);
codec.configure(format, surface, null, 0);
использование декодера:
int inIndex = codec.dequeueInputBuffer(10000);
if(inIndex >= 0)
{
ByteBuffer inputBuffer = codecInputBuffers[inIndex];
inputBuffer.clear();
inputBuffer.put(frameData);
codec.queueInputBuffer(inIndex, 0, frameSize, 33, 0);
}
int outIndex = codec.dequeueOutputBuffer(null, 10000);
switch(outIndex)
{
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
codecOutputBuffers = codec.getOutputBuffers();
System.out.println("OB Changed");
break;
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
System.out.println("OF Changed");
break;
case MediaCodec.INFO_TRY_AGAIN_LATER:
System.out.println("l8r");
break;
default:
ByteBuffer buffer = codecOutputBuffers[outIndex];
codec.releaseOutputBuffer(outIndex, true);
}
устройство, на котором я тестирую этот код, - это Google Nexus 5. Когда я запускаю это,outIndex
равно MediaCodec.INFO_TRY_AGAIN_LATER
все время.
Я ранее написал клиент для ноутбуков, который отлично работает, поэтому я думаю, что поток h264 с сервера должен быть в порядке.
Спасибо за помощь
изменить: В случае, если кто-то сталкивается с той же проблемой, предлагаемая поправка (1) fadden решила проблему. Я исправил код выше. Теперь работает. Другой ошибкой моего показанного примера было то, что вы не можете передать null .dequeueOutputBuffers(...);. Вам нужно сделать что-то вроде
BufferInfo buffInfo = new MediaCodec.BufferInfo();
int outIndex = codec.dequeueOutputBuffer(buffInfo, 10000);
даже если вас это не интересует. ;)
1 ответов
Я вижу несколько проблем...
(1) вы пытаетесь заменить буфер во входном буферном массиве. MediaCodec
не работает так - платформа предоставляет буферы, и вы копируете данные в них. Идея заключается в том, что, позволяя структуре выполнять распределение, она потенциально может избежать копирования данных позже.
вам нужно получить массив входных буферов от decoder.getInputBuffers()
, и использовать их. Убедитесь, что clear()
на ByteBuffer
для того чтобы переустановить положение и ограничьте каждый раз.
(2) Вы пишете один пакет данных и ждет кадра данных. На практике может потребоваться предоставить несколько буферов данных до создания первого кадра. См.этот пост для примера. В некоторых профилях кодировщику разрешено переупорядочивать кадры, поэтому даже после того, как декодер начинает работать, вы не можете просто кормить кадр и ждать, пока декодированные данные выскочат с другой стороны.
(3) декодер AVC потребности Данные SPS / PPS, который вы можете предоставить через буфер с BUFFER_FLAG_CODEC_CONFIG
флаг установлен, или путем добавления данных с ключами" csd-0 " / "csd-1" к MediaFormat
используя MediaFormat#setByteBuffer()
. Примеры обоих подходов можно найти в EncodeDecodeTest.
существует ряд примеров декодирования AVC на bigflake, но источник данных MediaCodec
кодер, поэтому они обычно получают точку #3 бесплатно.
данное сообщение может быть полезно для вы.
для отображения кадров, вы можете увидеть различные подходы в графика (который обычно работает С. mp4-файлы, поэтому реализация кодирования / декодирования там не так актуальна).