В RTP все H264 I-кадры (IDR) обычно фрагментированы.Когда вы получаете RTP, вы должны сначала пропустить заголовок (обычно первые 12 байтов), а затем перейти к блоку NAL (первый байт полезной нагрузки).Если значение NAL равно 28 (1C), это означает, что следующая полезная нагрузка представляет один фрагмент H2R IDR (I-кадр) и что вам необходимо собрать все из них для восстановления H264 IDR (I-Frame).
Фрагментацияпроисходит из-за ограниченного MTU и гораздо большего IDR.Один фрагмент может выглядеть так:
Фрагмент с начальным битом = 1:
First byte: [ 3 NAL UNIT BITS | 5 FRAGMENT TYPE BITS]
Second byte: [ START BIT | END BIT | RESERVED BIT | 5 NAL UNIT BITS]
Other bytes: [... IDR FRAGMENT DATA...]
Другие фрагменты:
First byte: [ 3 NAL UNIT BITS | 5 FRAGMENT TYPE BITS]
Other bytes: [... IDR FRAGMENT DATA...]
Чтобы восстановить IDR, вы должны собрать эту информацию:
int fragment_type = Data[0] & 0x1F;
int nal_type = Data[1] & 0x1F;
int start_bit = Data[1] & 0x80;
int end_bit = Data[1] & 0x40;
Если fragment_type == 28
, то полезная нагрузка, следующая за ним, представляет собой один фрагмент IDR.Следующая проверка start_bit
установлена, если это так, то этот фрагмент является первым в последовательности.Вы используете его для восстановления NAL-байта IDR, беря первые 3 бита из первого байта полезной нагрузки (3 NAL UNIT BITS)
и комбинируя их с последними 5 битами из второго байта полезной нагрузки (5 NAL UNIT BITS)
, чтобы вы получили такой байт, как этот [3 NAL UNIT BITS | 5 NAL UNIT BITS]
.Затем сначала запишите этот байт NAL в чистый буфер со всеми другими следующими байтами из этого фрагмента.Не забудьте пропустить первый байт в последовательности, поскольку он не является частью IDR, а только идентифицирует фрагмент.
Если start_bit
и end_bit
равны 0, тогда просто запишите полезную нагрузку (пропуская первый байт полезной нагрузки, которыйидентифицирует фрагмент) в буфер.
Если start_bit равен 0, а end_bit равен 1, это означает, что это последний фрагмент, и вы просто записываете его полезную нагрузку (пропуская первый байт, который идентифицирует фрагмент) вбуфер, и теперь ваш IDR восстановлен.
Если вам нужен код, просто спросите в комментарии, я опубликую его, но я думаю, что это довольно ясно, как это сделать ... =)
ОТНОСИТЕЛЬНО ДЕКОДИРОВАНИЯ
Сегодня мне пришло в голову, почему вы получаете ошибку при декодировании IDR (я предположил, что вы восстановили его хорошо).Как вы строите свою запись конфигурации декодера AVC?Есть ли автоматизированная библиотека, которую вы используете?Если нет, и вы не слышали об этом, продолжайте чтение ...
Указана AVCDCR, чтобы позволить декодерам быстро анализировать все данные, необходимые для декодирования видеопотока H264 (AVC).И данные следующие:
- ProfileIDC
- ProfileIOP
- LevelIDC
- SPS (наборы параметров последовательности)
- PPS (Наборы параметров изображения)
Все эти данные отправляются в сеансе RTSP в SDP под полями: profile-level-id
и sprop-parameter-sets
.
DECODING PROFILE-LEVEL-ID
Строка идентификатора уровня Prifile разделена на 3 подстроки, каждая длиной 2 символа:
[PROFILE IDC][PROFILE IOP][LEVEL IDC]
Каждая подстрока представляет один байт в base16 !Таким образом, если IDC профиля равен 28, это означает, что он действительно равен 40 в base10.Позже вы будете использовать значения base10 для создания записи конфигурации декодера AVC.
DECODING SPROP-PARAMETER-SETS
Спропы обычно представляют собой 2 строки (может быть больше), которые являются запятымиотделяется, а base64 кодируется !Вы можете декодировать их обоих, но в этом нет необходимости.Ваша задача здесь - просто преобразовать их из строки base64 в байтовый массив для дальнейшего использования.Теперь у вас есть 2-байтовые массивы, первый массив с использованием SPS, второй - PPS.
СОЗДАНИЕ AVCDCR
Теперь у вас есть все, что нужно для построения AVCDCR, выначните с создания нового чистого буфера, теперь запишите эти вещи в следующем порядке:
1 - байт, имеющий значение 1 и представляющий версию
2 - профильБайт IDC
3 - байт IOP Prifile
4 - байт IDC уровня
5 - байт со значением 0xFF (посмотрите в записи конфигурации декодера AVC, что это)
6 - байт со значением 0xE1
7 - шорт со значением длины массива SPS
8 - байтовый массив SPS
9 - байт с номероммассивов PPS (их может быть больше в наборе параметров sprop)
10 - Короткое с длиной следующего массива PPS
11 - Массив PPS
ДЕКОДИРОВАНИЕ ВИДЕОТОРА
Теперь у вас есть байтовый массив, которыйсообщает декодеру, как декодировать видеопоток H264.Я полагаю, что вам это нужно, если ваша библиотека не создает ее из SDP ...