Подтвердить что ты не робот

Преобразование H.264 с FFmpeg (из потока RTP)

Окружающая среда:

У меня есть IP-камера, которая способна передавать данные по RTP в кодированном формате H.264. Этот необработанный поток записывается из сети Ethernet. С этими данными я должен работать.

Цель:

В конце концов, я хочу иметь файл *.mp4, который я могу играть с обычными медиаплеерами (например, VLC или Windows MP).

Что я сделал до сих пор:

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

1. Напишите исходный файл

Сначала я определяю тип каждого кадра, полученного по Ethernet. Для этого я разбираю первые два байта каждой полезной нагрузки RTP, поэтому я могу получить бит 8 NAL, бит типа фрагмента и стартовый, зарезервированный и конечный бит. В полезной нагрузке они расположены следующим образом:

Byte 1: [          3 NAL Unit Bits          | 5 Fragment Type Bits]
Byte 2: [Start Bit | Reserved Bit | End Bit | 5 NAL Unit Bits]

Из этого я могу определить:

  • Начало и конец Видеокадр → Начальный бит и конечный бит
  • Тип полезной нагрузки → 5 битов типа фрагмента
  • Байт блока NAL

Типы фрагментов, которые необходимы в моем случае:

Fragment Type  7 = SPS
Fragment Type  8 = PPS
Fragment Type 28 = Video Fragment

Байт NAL создается путем объединения бит блока NAL из байтов 1 и 2.

Теперь, в зависимости от типа фрагментации, я делаю следующее:

SPS/PPS:

  • Запишите префикс NAL (0x00 0x00 0x01), а затем данные SPS или PPS

Фрагментация с помощью стартового бита

  • Запись префикса NAL
  • Write NAL Unit Byte
  • Запись оставшихся необработанных данных

Фрагментация без стартового бита

  • Запись исходных данных

Это означает, что мой сырой файл выглядит примерно так:

[NAL Prefix][SPS][NAL Prefix][PPS][NAL Prefix][NAL Unit Byte][Raw Video Data][Raw Video Data]....[NAL Prefix][NAL Unit Byte][Raw Video Data]...

Для каждого PPS и SPS я нахожу в своих потоковых данных, я просто пишу префикс NAL (0x00 0x00 0x01), а затем сам SPS/PPS.

Теперь я не могу воспроизвести эти данные с помощью какого-либо медиаплеера, что приводит меня к:

2. Преобразовать файл

Так как я не хотел много работать с кодеками, я просто пошел использовать существующее приложение → FFmpeg. Это я вызываю с такими параметрами:

ffmpeg.exe -f h264 -i <RawInputFile> -vcodec copy -r 25 <OutPutFilename>.mp4

-f h264: Это должно сказать ffmpeg У меня есть кодированный поток h264

-vcodec copy: Цитата из manpage:

Force video codec to codec. Use the "copy" special value to tell that the raw codec data must be copied as is.

-r 25: устанавливает частоту кадров до 25 FPS.

Когда я вызываю ffmpeg с этими параметрами, я получаю файл .mp4, который я могу играть с VLC и Windows MP, поэтому он действительно работает. Но файл теперь немного отличается от моего сырого файла.

Это приводит меня к моему вопросу:

Что я на самом деле делал?

Моя проблема заключается не в том, что она не работает. Я просто хочу/должен знать, что я на самом деле сделал с вызовом ffmpeg. У меня был необработанный файл H264, в котором я не мог играть . После использования FFmpeg я может воспроизвести его.

Существуют следующие различия между исходным исходным файлом (который я написал) и тем, который был написан FFmpeg:

  • Заголовок: файл FFmpeg имеет около 0x30 байт заголовка
  • Нижний колонтитул: файл FFmpeg также имеет нижний колонтитул
  • Измененный префикс и 2 новых байта:

В то время как новый видеофрагмент из исходного файла начинался как [NAL Prefix][NAL Unit Byte][Raw Video Data] в новом файле выглядит так:

[0x00 0x00][2 "Random" Bytes][NAL Unit Byte][Raw Video Data].....[0x00 0x00[2 other "Random" Bytes][NAL Unit Byte][Raw Video Data]...

Я понимаю, что для видеопотока нужен формат контейнера (исправьте меня, если я ошибаюсь, но я полагаю, что за него отвечают новый верхний и нижний колонтитулы). Но почему это фактически меняет некоторые байты в необработанных данных? Это не может быть некоторое декодирование, поскольку сам поток должен быть декодирован игроком, а не ffmpeg.

Как вы можете видеть, мне больше не нужно новое решение для моей проблемы, поэтому я могу объяснить это самостоятельно. Что делает ffmpeg на самом деле? И почему это изменяет некоторые байты в видеоданных?

4b9b3361

Ответ 1

Помимо добавления контейнера MP4, ffmpeg преобразовал ваш байт-поток в H.264 приложения B (с префиксами NAL) в формат с префиксом длины.

Ваш [0x00 0x00] [2 "Случайные" байты] представляет собой 32-битное целое число, дающее длину следующего блока NAL в байтах.

Ответ 2

Похоже, поток был пакетирован. Многие форматы контейнеров разбивают поток битов на пакеты и добавляют немного информации, такой как отметки времени, длину пакета и т.д. Это дает перехват декодеру, чтобы пропустить файл без декодирования всего, пересинхронизация, когда пакет потерян, синхронизация аудио/видео, объединение нескольких потоков и т.д.

Посмотрите информацию о формате файла MP4 для получения дополнительной информации:
http://en.wikipedia.org/wiki/MPEG-4_Part_14

Ответ 3

Подробнее о ваших изменениях читайте в открытых спецификациях h264. Глава Приложение B.