H.264 Annex-B, AVCC
서론
H.264 스트림은 NALU(Network Abstraction Layer Unit) 단위의 시퀀스라고 할 수 있다.
NALU에는 크기 정보가 포함되어 있지 않다. 그렇다면 어떻게 하나의 NALU가 끝나고 다음 NALU가 시작되는지 알 수 있을까?
이를 구분하기 위한 포맷에 대해 알아보자.
참고로 H.264 스트림에서 NALU를 구분하기 위한 단일 표준 포맷은 없다. (ITU-T H.264 문서를 봐도 Annex-B에 대한 언급만 있다.)
Annex-B
([start code] NALU) | ([start code] NALU) | ...
Annex-B는 각 NALU 앞에 start code를 추가하여 NALU를 구분하는 포맷이다. 즉, 새로운 start code가 나타나기 전까지 NALU 데이터를 읽으면 된다.
Start code는 3bytes(0x000001
) 혹은 4bytes(0x00000001
)로 표현된다.
Annex-B에서는 PPS(Picture Parameter Set), SPS(Sequence Parameter Set)도 일반적인 NALU와 같은 방식으로 처리된다.
Annex-B는 주기적으로 IDR 앞에 SPS, PPS를 반복하여 디코더가 진행 중인 스트림도 처리할 수 있게 한다.
Annex-B는 데이터 손실이 발생하더라도 start code를 통해 다음 NALU를 빠르게 찾을 수 있어 스트리밍 환경에서 사용하기에 적합한 포맷이다.
- Android MediaCodec은 Annex-B 포맷만 지원한다.
- Annex-B는 MPEG-2 Transport Stream Format, ElementaryStream Format으로도 불린다.
Emulation Prevention Bytes
0x000010 -> 0x00000301
Annex-B에서 데이터 내의 일부 값이 start code와 동일할 경우, NALU가 잘못 나누어질 수 있다.
이 문제를 해결하기 위해, start code를 추가하기 전에 데이터를 순회하며 start code와 같은 값을 갖는 부분에 emulation prevention byte(0x03
)를 추가한다.
디코딩 과정에서는 start code를 제거한 뒤, emulation prevention byte도 함께 제거한다. 이렇게 처리된 데이터를 RBSP(Raw Byte Sequence Payload)라고 부른다.
Annex-B Example
다음은 Annex-B 포맷을 사용하는 AU(Access Unit)의 예시이다.
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
3개의 NALU(SPS, PPS, IDR)로 구성되어 있으며 3개의 start code를 확인할 수 있다.
AVCC
([extradata]) | ([length] NALU) | ([length] NALU) | ...
AVCC는 각 NALU 앞에 길이 정보를 추가하여 NALU를 구분하는 포맷이다. 따라서 길이 정보만큼 NALU 데이터를 읽으면 된다.
길이 정보는 고정된 크기(1,2 혹은 4bytes)를 가지며, big-endian 형식으로 저장된다.
AVCC에서는 PPS, SPS를 특별한 데이터로 간주하여 extradata 섹션에 포함시킨다.
AVCC는 Annex-B에 비해 저장 효율성이 좋고 extradata를 이용한 빠른 random access가 가능하여 파일 저장에 적합한 포맷이다.
- Apple의 VideoToolBox는 AVCC 포맷만 지원한다.
- AVCC는 AVC1 Format, MPEG-4 Format, Byte-Stream Format으로도 불린다.
사실 avcC(AVC Configuration Box)는 NALU를 구분하는 포맷보다는 H.264 디코더 설정 정보를 의미한다. 그러나 H.264 스트림에서 NALU를 구분하는 명확한 표준 방식이 없어, 인터넷상에서 AVCC는 NALU를 구분하는 포맷으로도 혼용되어 사용되는 것으로 보인다.
extradata
앞서 소개한 extradata 섹션은 sequence header 혹은 AVCDecoderConfigurationRecord라고도 부르며 내부 정보는 다음과 같다.
bits description
---------------------------------------------
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
NALULengthSizeMinusOne
값에 1을 더하면 NALU 길이를 표현하는 바이트 수를 얻을 수 있다.
AVCC Example
다음은 AVCC 포맷을 사용하는 AU(Access Unit)의 예시이다.
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
extradata(SPS, PPS 포함)와 NALU(IDR)로 구성되어 있다.
참고로 AVCC는 start code가 없어도 NALU 해석을 명확하게 하기 위해 Annex-B와 동일하게 emulation prevention bytes를 추가한다.
Reference
- https://stackoverflow.com/questions/24884827/possible-locations-for-sequence-picture-parameter-sets-for-h-264-stream/24890903