H.264 over RTP - определение кадров SPS и PPS - PullRequest
11 голосов
/ 08 марта 2012

У меня есть необработанный поток H.264 с IP-камеры, упакованный в кадры RTP.Я хочу получить необработанные данные H.264 в файл, чтобы преобразовать их в ffmpeg.

. Поэтому, когда я хочу записать данные в необработанный файл H.264, я обнаружил, чтовот так:

00 00 01 [SPS] 
00 00 01 [PPS]
00 00 01 [NALByte]
[PAYLOAD RTP Frame 1]     // Payload always without the first 2 Bytes -> NAL
[PAYLOAD RTP Frame 2]
[... until PAYLOAD Frame with Mark Bit received]  // From here its a new Video Frame
00 00 01 [NAL BYTE]
[PAYLOAD RTP Frame 1]
....

Так что я получаю SPS и PPS из Session Description Protocol из моего предыдущего RTSP общения.Кроме того, камера отправляет SPS и PPS в двух отдельных сообщениях, прежде чем начинать с самого видеопотока.

Итак, я записываю сообщения в следующем порядке:

1. Preceding RTSP Communication here ( including SDP with SPS and PPS )
2. RTP Frame with Payload: 67 42 80 28 DA 01 40 16 C4    // This is the SPS 
3. RTP Frame with Payload: 68 CE 3C 80                   // This is the PPS
4. RTP Frame with Payload: ...  // Video Data

Затем идут несколько кадров с полезной нагрузкой и в какой-то момент кадр RTP с Marker Bit = 1.Это означает (если я правильно понял), что у меня есть полный видеокадр.После этого я снова записываю последовательность префикса (00 00 01) и NAL из полезной нагрузки и продолжаю в том же порядке.

Теперь моя камера отправляет мне после каждых 8 полных видеокадров SPSи снова PPS.(Снова в двух RTP-кадрах, как показано в примере выше).Я знаю, что особенно PPS может меняться между потоками, но это не проблема.

Мои вопросы сейчас:

1.Нужно ли писать SPS / PPS каждый 8-й видеокадр?

Если мои SPS и мои PPS не изменились, этого должно быть достаточно, чтобы они были записаны в самом началемой файл и ничего более?

2.Как различить SPS / PPS и обычные кадры RTP?

В моем коде C ++, который анализирует передаваемые данные, мне нужно провести различие между кадрами RTP с обычной полезной нагрузкой и теми, которые несут SPS/PPS,Как я могу их различить?Хорошо, кадры SPS/PPS обычно намного меньше, но это не вызов сохранения, на который можно положиться.Потому что, если я их игнорирую, мне нужно знать, какие данные я могу выбросить, или, если мне нужно записать их, мне нужно поставить префикс 00 00 01 перед ними.?Или это фиксированное правило, что они появляются в каждом восьмом видеокадре?

Ответы [ 2 ]

12 голосов
/ 01 сентября 2012
  1. Вы должны писать SPS и PPS в начале потока и только тогда, когда они изменяются в середине потока.

  2. SPS и PPS кадры упакованыв блоке STAP NAL (обычно STAP-A) с форматом STAL NAL типа 24 (STAP-A) или 25 (STAP-B) описано в RFC-3984, раздел 5.7.1

  3. Не полагайтесь на бит маркера, используйте начальный бит и конечный бит в заголовке NAL.

  4. Для фрагментированных видеокадров вы должны восстановить блок NAL, используя 3 блока NALбиты первого фрагмента (F, NRI) в сочетании с 5 битами первого байта типа NAL в полезной нагрузке (только для пакетов с начальным битом, установленным в 1), проверка RFC-3984, раздел 5.8 :

    Октет типа блока NAL фрагментированного блока NAL как таковой не включен в полезную нагрузку блока фрагментации, а информация о октете типа блока NAL фрагментированного блока NAL передается в полях F и NRI индикатора FUоктет блока фрагментации и в поле типа tЗаголовок FU.

РЕДАКТИРОВАТЬ: подробное описание конструкции блока NAL для блоков фрагментации:

это первые два байтаПолезная нагрузка FU-A (сразу после заголовка rtp):

|  FU indicator |   FU header   |
+---------------+---------------+
|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|F|NRI|  Type   |S|E|R|  Type   |
+---------------+---------------+

для построения блока NAL вы должны взять «Type» из «FU Header» и «F» и «NRI» из «FU индикатор»

здесь - простая реализация

11 голосов
/ 08 марта 2012
  1. Если SPS и PPS не меняются, вы можете пропустить их, кроме 1-го.
  2. Вам необходимо проанализировать поле nal_unit_type каждого NAL, для SPS, nal_unit_type == 7; для PPS nal_unit_type == 8.

Насколько я помню, nal_unit_type - это младшие 5 битов 1-го байта кадра.

nal_unit_type = frame[0] & 0x1f;
...