Возможные местоположения для набора (ей) параметров последовательности / изображения для потока H.264
Я работаю над декодером H.264, и мне интересно, где найти SPS и PPS. Моя справочная литература говорит мне, что это NAL-единицы, закодированные в H.264-Stream, но когда я смотрю на файл-пример MP4 с IsoViewer, он говорит, что SPS и PPS находятся в блоке avcC.
Как именно это работает? Как это выглядит для файлов.mkv или других контейнеров H.264?
Заранее спасибо!
2 ответа
Во-первых, важно понимать, что не существует единого стандартного элементарного формата битового потока H.264. Документ спецификации содержит Приложение, в частности Приложение B, в котором описывается один возможный формат, но это не является фактическим требованием. Стандарт определяет, как видео кодируется в отдельные пакеты. Как эти пакеты хранятся и передаются, остается открытым для интегратора.
1. Приложение Б
Сетевые единицы уровня абстракции
Пакеты называются Единицами Уровня Абстракции Сети. Часто сокращенно NALU (или иногда просто NAL) каждый пакет может быть индивидуально проанализирован и обработан. Первый байт каждого NALU содержит тип NALU, в частности, биты с 3 по 7. (бит 0 всегда выключен, а биты 1-2 указывают, ссылается ли NALU на другой NALU).
Существует 19 различных типов NALU, разделенных на две категории: VCL и не VCL:
- Пакеты VCL или Video Coding Layer содержат фактическую визуальную информацию.
- Номера для VCL содержат метаданные, которые могут или не могут потребоваться для декодирования видео.
Один NALU или даже VCL NALU - это НЕ то же самое, что кадр. Кадр может быть "разрезан" на несколько блоков NALU. Также как вы можете нарезать пиццу. Один или несколько слайсов затем виртуально группируются в блоки доступа (AU), которые содержат один кадр. Нарезка имеет небольшую стоимость, поэтому ее не часто используют.
Ниже приведена таблица всех определенных NALU.
0 Unspecified non-VCL
1 Coded slice of a non-IDR picture VCL
2 Coded slice data partition A VCL
3 Coded slice data partition B VCL
4 Coded slice data partition C VCL
5 Coded slice of an IDR picture VCL
6 Supplemental enhancement information (SEI) non-VCL
7 Sequence parameter set non-VCL
8 Picture parameter set non-VCL
9 Access unit delimiter non-VCL
10 End of sequence non-VCL
11 End of stream non-VCL
12 Filler data non-VCL
13 Sequence parameter set extension non-VCL
14 Prefix NAL unit non-VCL
15 Subset sequence parameter set non-VCL
16 Depth parameter set non-VCL
17..18 Reserved non-VCL
19 Coded slice of an auxiliary coded picture without partitioning non-VCL
20 Coded slice extension non-VCL
21 Coded slice extension for depth view components non-VCL
22..23 Reserved non-VCL
24..31 Unspecified non-VCL
Есть пара типов NALU, где знание может быть полезно позже.
- Набор параметров последовательности (SPS). Это не VCL NALU содержит информацию, необходимую для настройки декодера, такую как профиль, уровень, разрешение, частота кадров.
- Набор параметров изображения (PPS). Подобно SPS, этот не-VCL содержит информацию о режиме энтропийного кодирования, группах слайсов, фильтрах предсказания движения и деблокирования.
- Мгновенное обновление декодера (IDR). Этот VCL NALU является автономным фрагментом изображения. Таким образом, IDR может быть декодирован и отображен без ссылки на любой другой NALU, кроме SPS и PPS.
- Разделитель доступа (AUD). AUD - это необязательный NALU, который можно использовать для разделения кадров в элементарном потоке. Это не требуется (если иное не указано контейнером / протоколом, таким как TS), и часто не включается для экономии места, но может быть полезно найти начало кадра без необходимости полного разбора каждого NALU.
Стартовые коды NALU
NALU не содержит его размер. Поэтому простая конкатенация NALU для создания потока не будет работать, потому что вы не будете знать, где останавливается один и начинается следующий.
Спецификация Приложения B решает эту проблему, требуя, чтобы "Начальные коды" предшествовали каждому NALU. Стартовый код 2 или 3 0x00
байты следуют с 0x01
байт. например 0x000001
или же 0x00000001
,
4-байтовое изменение полезно для передачи по последовательному соединению, поскольку тривиально выравнивание потока по байту выполняется путем поиска 31 нулевого бита, за которым следует один. Если следующий бит равен 0 (потому что каждый NALU начинается с 0 бита), это начало NALU. 4-байтовое изменение обычно используется только для сигнализации точек произвольного доступа в потоке, таких как SPS PPS AUD и IDR, где 3-байтовое изменение используется повсеместно для экономии места.
Байты предотвращения эмуляции
Начальные коды работают, потому что четыре байта последовательности 0x000000
, 0x000001
, 0x000002
а также 0x000003
являются незаконными в пределах NALU не RBSP. Поэтому при создании NALU необходимо избегать этих значений, которые в противном случае можно было бы спутать со стартовым кодом. Это достигается путем вставки байта "Предотвращение эмуляции" 0x03
, чтобы 0x000001
становится 0x00000301
,
При декодировании важно искать и игнорировать байты предотвращения эмуляции. Поскольку байты предотвращения эмуляции могут возникать практически в любом месте NALU, в документации часто удобнее предположить, что они уже удалены. Представление без байтов предотвращения эмуляции называется полезной нагрузкой последовательности необработанных байтов (RBSP).
пример
Давайте посмотрим на полный пример.
0x0000 | 00 00 00 01 67 64 00 0A AC 72 84 44 26 84 00 00
0x0010 | 03 00 04 00 00 03 00 CA 3C 48 96 11 80 00 00 00
0x0020 | 01 68 E8 43 8F 13 21 30 00 00 01 65 88 81 00 05
0x0030 | 4E 7F 87 DF 61 A5 8B 95 EE A4 E9 38 B7 6A 30 6A
0x0040 | 71 B9 55 60 0B 76 2E B5 0E E4 80 59 27 B8 67 A9
0x0050 | 63 37 5E 82 20 55 FB E4 6A E9 37 35 72 E2 22 91
0x0060 | 9E 4D FF 60 86 CE 7E 42 B7 95 CE 2A E1 26 BE 87
0x0070 | 73 84 26 BA 16 36 F4 E6 9F 17 DA D8 64 75 54 B1
0x0080 | F3 45 0C 0B 3C 74 B3 9D BC EB 53 73 87 C3 0E 62
0x0090 | 47 48 62 CA 59 EB 86 3F 3A FA 86 B5 BF A8 6D 06
0x00A0 | 16 50 82 C4 CE 62 9E 4E E6 4C C7 30 3E DE A1 0B
0x00B0 | D8 83 0B B6 B8 28 BC A9 EB 77 43 FC 7A 17 94 85
0x00C0 | 21 CA 37 6B 30 95 B5 46 77 30 60 B7 12 D6 8C C5
0x00D0 | 54 85 29 D8 69 A9 6F 12 4E 71 DF E3 E2 B1 6B 6B
0x00E0 | BF 9F FB 2E 57 30 A9 69 76 C4 46 A2 DF FA 91 D9
0x00F0 | 50 74 55 1D 49 04 5A 1C D6 86 68 7C B6 61 48 6C
0x0100 | 96 E6 12 4C 27 AD BA C7 51 99 8E D0 F0 ED 8E F6
0x0110 | 65 79 79 A6 12 A1 95 DB C8 AE E3 B6 35 E6 8D BC
0x0120 | 48 A3 7F AF 4A 28 8A 53 E2 7E 68 08 9F 67 77 98
0x0130 | 52 DB 50 84 D6 5E 25 E1 4A 99 58 34 C7 11 D6 43
0x0140 | FF C4 FD 9A 44 16 D1 B2 FB 02 DB A1 89 69 34 C2
0x0150 | 32 55 98 F9 9B B2 31 3F 49 59 0C 06 8C DB A5 B2
0x0160 | 9D 7E 12 2F D0 87 94 44 E4 0A 76 EF 99 2D 91 18
0x0170 | 39 50 3B 29 3B F5 2C 97 73 48 91 83 B0 A6 F3 4B
0x0180 | 70 2F 1C 8F 3B 78 23 C6 AA 86 46 43 1D D7 2A 23
0x0190 | 5E 2C D9 48 0A F5 F5 2C D1 FB 3F F0 4B 78 37 E9
0x01A0 | 45 DD 72 CF 80 35 C3 95 07 F3 D9 06 E5 4A 58 76
0x01B0 | 03 6C 81 20 62 45 65 44 73 BC FE C1 9F 31 E5 DB
0x01C0 | 89 5C 6B 79 D8 68 90 D7 26 A8 A1 88 86 81 DC 9A
0x01D0 | 4F 40 A5 23 C7 DE BE 6F 76 AB 79 16 51 21 67 83
0x01E0 | 2E F3 D6 27 1A 42 C2 94 D1 5D 6C DB 4A 7A E2 CB
0x01F0 | 0B B0 68 0B BE 19 59 00 50 FC C0 BD 9D F5 F5 F8
0x0200 | A8 17 19 D6 B3 E9 74 BA 50 E5 2C 45 7B F9 93 EA
0x0210 | 5A F9 A9 30 B1 6F 5B 36 24 1E 8D 55 57 F4 CC 67
0x0220 | B2 65 6A A9 36 26 D0 06 B8 E2 E3 73 8B D1 C0 1C
0x0230 | 52 15 CA B5 AC 60 3E 36 42 F1 2C BD 99 77 AB A8
0x0240 | A9 A4 8E 9C 8B 84 DE 73 F0 91 29 97 AE DB AF D6
0x0250 | F8 5E 9B 86 B3 B3 03 B3 AC 75 6F A6 11 69 2F 3D
0x0260 | 3A CE FA 53 86 60 95 6C BB C5 4E F3
Это полный AU, содержащий 3 NALU. Как видите, мы начинаем с кода запуска, за которым следует SPS (SPS начинается с 67). Внутри SPS вы увидите два байта предотвращения эмуляции. Без этих байтов недопустимая последовательность 0x000000
будет происходить на этих позициях. Далее вы увидите стартовый код, за которым следует PPS (PPS начинается с 68) и один финальный стартовый код, за которым следует фрагмент IDR. Это полный поток H.264. Если вы введете эти значения в шестнадцатеричный редактор и сохраните файл с .264
расширение, вы сможете преобразовать его в это изображение:
Приложение B обычно используется в живом и потоковом форматах, таких как транспортные потоки, эфирное вещание и DVD-диски. В этих форматах обычно периодически повторяют SPS и PPS, обычно перед каждым IDR, создавая точку произвольного доступа для декодера. Это дает возможность присоединиться к потоку, который уже выполняется.
2. AVCC
Другим распространенным методом хранения потока H.264 является формат AVCC. В этом формате каждому NALU предшествует его длина (в формате с прямым порядком байтов). Этот метод проще анализировать, но вы теряете функции выравнивания байтов в Приложении B. Просто, чтобы усложнить ситуацию, длина может быть закодирована с использованием 1, 2 или 4 байтов. Это значение хранится в объекте заголовка. Этот заголовок часто называют "экстраданными" или "заголовком последовательности". Его основной формат выглядит следующим образом:
bits
8 version ( always 0x01 )
8 avc profile ( sps[0][1] )
8 avc compatibility ( sps[0][2] )
8 avc level ( sps[0][3] )
6 reserved ( all bits on )
2 NALULengthSizeMinusOne
3 reserved ( all bits on )
5 number of SPS NALUs (usually 1)
repeated once per SPS:
16 SPS size
variable SPS NALU data
8 number of PPS NALUs (usually 1)
repeated once per PPS
16 PPS size
variable PPS NALU data
Используя тот же пример выше, дополнительные данные AVCC будут выглядеть так:
0x0000 | 01 64 00 0A FF E1 00 19 67 64 00 0A AC 72 84 44
0x0010 | 26 84 00 00 03 00 04 00 00 03 00 CA 3C 48 96 11
0x0020 | 80 01 00 07 68 E8 43 8F 13 21 30
Вы заметите, что SPS и PPS теперь хранятся вне диапазона. То есть отдельно от элементарных потоков данных. Хранение и передача этих данных является задачей файлового контейнера и выходит за рамки этого документа. Обратите внимание, что, хотя мы не используем стартовые коды, байты предотвращения эмуляции по-прежнему вставляются.
Кроме того, есть новая переменная под названием NALULengthSizeMinusOne
, Эта переменно-названная переменная сообщает нам, сколько байтов нужно использовать для хранения длины каждого NALU. Так что если NALULengthSizeMinusOne
устанавливается в 0, тогда каждому NALU предшествует один байт, указывающий его длину. При использовании одного байта для хранения размера максимальный размер NALU составляет 255 байтов. Это, очевидно, довольно мало. Слишком маленький для целого ключевого кадра. Использование 2 байтов дает нам 64 КБ за NALU. Это будет работать в нашем примере, но все еще довольно низкий предел. 3 байта были бы идеальными, но по некоторым причинам не универсально поддерживаются. Поэтому 4 байта на сегодняшний день являются наиболее распространенными, и это то, что мы использовали здесь:
0x0000 | 00 00 02 41 65 88 81 00 05 4E 7F 87 DF 61 A5 8B
0x0010 | 95 EE A4 E9 38 B7 6A 30 6A 71 B9 55 60 0B 76 2E
0x0020 | B5 0E E4 80 59 27 B8 67 A9 63 37 5E 82 20 55 FB
0x0030 | E4 6A E9 37 35 72 E2 22 91 9E 4D FF 60 86 CE 7E
0x0040 | 42 B7 95 CE 2A E1 26 BE 87 73 84 26 BA 16 36 F4
0x0050 | E6 9F 17 DA D8 64 75 54 B1 F3 45 0C 0B 3C 74 B3
0x0060 | 9D BC EB 53 73 87 C3 0E 62 47 48 62 CA 59 EB 86
0x0070 | 3F 3A FA 86 B5 BF A8 6D 06 16 50 82 C4 CE 62 9E
0x0080 | 4E E6 4C C7 30 3E DE A1 0B D8 83 0B B6 B8 28 BC
0x0090 | A9 EB 77 43 FC 7A 17 94 85 21 CA 37 6B 30 95 B5
0x00A0 | 46 77 30 60 B7 12 D6 8C C5 54 85 29 D8 69 A9 6F
0x00B0 | 12 4E 71 DF E3 E2 B1 6B 6B BF 9F FB 2E 57 30 A9
0x00C0 | 69 76 C4 46 A2 DF FA 91 D9 50 74 55 1D 49 04 5A
0x00D0 | 1C D6 86 68 7C B6 61 48 6C 96 E6 12 4C 27 AD BA
0x00E0 | C7 51 99 8E D0 F0 ED 8E F6 65 79 79 A6 12 A1 95
0x00F0 | DB C8 AE E3 B6 35 E6 8D BC 48 A3 7F AF 4A 28 8A
0x0100 | 53 E2 7E 68 08 9F 67 77 98 52 DB 50 84 D6 5E 25
0x0110 | E1 4A 99 58 34 C7 11 D6 43 FF C4 FD 9A 44 16 D1
0x0120 | B2 FB 02 DB A1 89 69 34 C2 32 55 98 F9 9B B2 31
0x0130 | 3F 49 59 0C 06 8C DB A5 B2 9D 7E 12 2F D0 87 94
0x0140 | 44 E4 0A 76 EF 99 2D 91 18 39 50 3B 29 3B F5 2C
0x0150 | 97 73 48 91 83 B0 A6 F3 4B 70 2F 1C 8F 3B 78 23
0x0160 | C6 AA 86 46 43 1D D7 2A 23 5E 2C D9 48 0A F5 F5
0x0170 | 2C D1 FB 3F F0 4B 78 37 E9 45 DD 72 CF 80 35 C3
0x0180 | 95 07 F3 D9 06 E5 4A 58 76 03 6C 81 20 62 45 65
0x0190 | 44 73 BC FE C1 9F 31 E5 DB 89 5C 6B 79 D8 68 90
0x01A0 | D7 26 A8 A1 88 86 81 DC 9A 4F 40 A5 23 C7 DE BE
0x01B0 | 6F 76 AB 79 16 51 21 67 83 2E F3 D6 27 1A 42 C2
0x01C0 | 94 D1 5D 6C DB 4A 7A E2 CB 0B B0 68 0B BE 19 59
0x01D0 | 00 50 FC C0 BD 9D F5 F5 F8 A8 17 19 D6 B3 E9 74
0x01E0 | BA 50 E5 2C 45 7B F9 93 EA 5A F9 A9 30 B1 6F 5B
0x01F0 | 36 24 1E 8D 55 57 F4 CC 67 B2 65 6A A9 36 26 D0
0x0200 | 06 B8 E2 E3 73 8B D1 C0 1C 52 15 CA B5 AC 60 3E
0x0210 | 36 42 F1 2C BD 99 77 AB A8 A9 A4 8E 9C 8B 84 DE
0x0220 | 73 F0 91 29 97 AE DB AF D6 F8 5E 9B 86 B3 B3 03
0x0230 | B3 AC 75 6F A6 11 69 2F 3D 3A CE FA 53 86 60 95
0x0240 | 6C BB C5 4E F3
Преимуществом этого формата является возможность настройки декодера в начале и перехода в середину потока. Это распространенный случай, когда носитель доступен на носителе с произвольным доступом, например на жестком диске, и поэтому используется в стандартных форматах контейнеров, таких как MP4 и MKV.
Я недавно работал над чем-то вроде этого.
Проверьте инспектора mp4. Как вы можете видеть на этом рисунке, у mp4 есть много блоков, которые нужно проанализировать, чтобы найти нужные вам данные.
Здесь я пометил части коробки avcc
Я только что написал много пост-блог о своей работе с h264. Я думаю, что слишком долго размещать здесь http://cagneymoreau.com/stream-video-android/