Преобразование 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:

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

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

  1. Записать префикс NAL
  2. Записать единичный байт NAL
  3. Записать оставшиеся необработанные данные

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

  1. Записать необработанные данные

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

[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: Цитата из справочной страницы:

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 кадров в секунду.

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

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

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

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

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

  1. Заголовок: файл FFmpeg имеет примерно 0x30 байт заголовка.
  2. Нижний колонтитул: файл FFmpeg также имеет нижний колонтитул.
  3. Измененный префикс и 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? И почему он меняет некоторые байты в видеоданных?


person Toby    schedule 18.07.2012    source источник
comment
Удалось ли вам этого добиться? Если да, готовы ли вы поделиться решением? Спасибо!   -  person ioan ghip    schedule 07.03.2017
comment
Я тоже ищу подобное решение. Не могли бы вы решить это, не могли бы вы поделиться.   -  person Austin    schedule 03.04.2018
comment
Я знаю, что это очень старый вопрос, но, похоже, у вас неправильный порядок при анализе Byte 2 полезной нагрузки. Это должно быть [Start Bit | End Bit | Reserved Bit | 5 NAL Unit Bits] - Значит, вы переупорядочили зарезервированный бит с конечным битом.   -  person Adam Szmyd    schedule 11.07.2019


Ответы (3)


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

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

person micha137    schedule 28.08.2013

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

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

person mjacobs    schedule 26.07.2012

Вы можете узнать больше о своих изменениях в open спецификации h264. Глава Приложение B.

person Artem Markov    schedule 10.04.2014