Android - Декодирование сырого потока h264 вручную - PullRequest
2 голосов
/ 23 марта 2019

Итак, я пытаюсь декодировать поток необработанных данных h264 и рендерить их на поверхность на Android.Вот шаги:

  1. Получить пакет из потока h264
  2. Собрать его и попытаться извлечь единицы NAL (байтовые последовательности, начинающиеся с 00 00 00 01 (Заголовок NAL) и до следующего заголовка NAL.
  3. Для каждого извлеченного блока NAL, вызовите feedFrame (data), где data - это байт [], который начинается с заголовка NAL и содержит извлеченный блок.
  4. Смотрите видео, предоставленное на предоставленной мной поверхности.

В следующем коде используется AVC-декодер:

public StreamReceiver(DashCamActivity activity, Surface surface, int width, int height, byte[] sps, byte[] pps) {
    this.activity = activity;
    decoder = MediaCodec.createDecoderByType("video/avc");

    format.setByteBuffer("csd-0", ByteBuffer.wrap(sps));
    format.setByteBuffer("csd-1", ByteBuffer.wrap(pps));
    decoder.configure(format, surface, null, 0);
    decoder.start();

}

public void shutdown() 
{
    decoder.stop();
    decoder.release();
}

public void feedFrame(byte[] data) 
{
    BufferInfo info = new BufferInfo();
    int inputIndex = decoder.dequeueInputBuffer(1000);
    if(inputIndex == -1)
        return;
    ByteBuffer inputBuffer = decoder.getInputBuffers()[inputIndex];
    if (inputIndex >= 0) {
        inputBuffer.clear();
        inputBuffer.put(data, 0, data.length);
        inputBuffer.clear();
        decoder.queueInputBuffer(inputIndex, 0, data.length, 0, 0);
    }

    int outIndex = decoder.dequeueOutputBuffer(info, 1000);

    switch (outIndex) {
    case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
        break;

    case MediaCodec.INFO_TRY_AGAIN_LATER:
        break;

    case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
        break;

    default:
        decoder.releaseOutputBuffer(outIndex, true);
        break;
    }
}

Для меньших разрешений (1024x768, 1280x800) все работает отличноОднако при больших разрешениях (1920x1080, 1900x600), где длина предоставляемого мною байтового массива превышает 65535 (64 КБ), видео начинает иметь заикания и артефакты, а Logcat сообщает о странных ошибках декодера (например, IOCTL_MFC_DEC_EXE не удалось (ret: -2001)на Galaxy S3). Это также происходит на относительно новом устройстве, которое может воспроизводить 4k с удвоенной частотой кадров, которую я предоставляю.и я не знаю, есть ли в моей теории 64k какая-то истина, это всего лишь наблюдение.

Итак, резюмируем:

  • Я предоставляю отдельные блоки NAL декодеру,начиная с заголовка.
  • Поток h264 имеет базовый профиль, уровень 4.0.
  • Запись содержимого блоков NAL в файл в порядке их поступления приводит к созданию видеофайла, который полностьюВоспроизведение с помощью основных медиаплееров

Как заставить его играть в высоком разрешении?

...