Окружающая среда:
У меня есть 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]
Отсюда я могу определить:
Типы фрагментов, которые необходимы в моем случае, это:
Fragment Type 7 = SPS
Fragment Type 8 = PPS
Fragment Type 28 = Video Fragment
Байт NAL создается путем объединения битов блока NAL из байта 1 и 2.
Теперь в зависимости от типа фрагментации я делаю следующее:
СПС/ППС:
0x00 0x00 0x01
)а затем данные SPS или PPSФрагментация с помощью стартового бита
Фрагментация без стартового бита
Это означает, что мой необработанный файл выглядит примерно так:
[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 FPS.
Когда я вызываю ffmpeg с этими параметрами, я получаю файл.mp4, который я могу воспроизводить с помощью VLC и Windows MP, так что это действительно работает. Но теперь файл выглядит немного иначе, чем мой необработанный файл.
Это приводит меня к моему вопросу:
Что я на самом деле сделал?
Моя проблема не в том, что он не работает. Я просто хочу/нужно знать, что я на самом деле сделал с вызовом ffmpeg. У меня был необработанный файл H264, который я не мог воспроизвести. После использования FFmpeg я могу воспроизвести его.
Существуют следующие различия между исходным необработанным файлом (, который я написал ), и файлом, написанным FFmpeg:
В то время как новый видеокадр из необработанного файла начинался как [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? И почему он меняет некоторые байты в видеоданных?