Декодирование 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-файлы, поэтому реализация кодирования / декодирования там не так актуальна).