Окружающая среда:
У меня есть 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
- Записать единичный байт NAL
- Записать оставшиеся необработанные данные
Фрагментация без стартового бита
- Записать необработанные данные
Это означает, что мой необработанный файл выглядит примерно так:
[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, есть следующие различия:
- Заголовок: файл 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? И почему он меняет некоторые байты в видеоданных?
Byte 2
полезной нагрузки. Это должно быть[Start Bit | End Bit | Reserved Bit | 5 NAL Unit Bits]
- Значит, вы переупорядочили зарезервированный бит с конечным битом. - person Adam Szmyd   schedule 11.07.2019