H.264 디코더에서 작업 중이며 SPS 및 PPS를 어디에서 찾을 수 있는지 궁금합니다. 내 참고 문헌에 따르면 H.264-Stream으로 인코딩 된 NAL 단위라고 나와 있지만 IsoViewer로 예제 MP4-File을 살펴보면 SPS와 PPS가 avcC 상자에 있다고 나와 있습니다.
정확히 어떻게 작동합니까? .mkv 파일 또는 기타 H.264 컨테이너를 어떻게 찾습니까?
미리 감사드립니다!
H.264 디코더에서 작업 중이며 SPS 및 PPS를 어디에서 찾을 수 있는지 궁금합니다. 내 참고 문헌에 따르면 H.264-Stream으로 인코딩 된 NAL 단위라고 나와 있지만 IsoViewer로 예제 MP4-File을 살펴보면 SPS와 PPS가 avcC 상자에 있다고 나와 있습니다.
정확히 어떻게 작동합니까? .mkv 파일 또는 기타 H.264 컨테이너를 어떻게 찾습니까?
미리 감사드립니다!
답변:
먼저, 단일 표준 H.264 기본 비트 스트림 형식이 없다는 것을 이해하는 것이 중요합니다. 사양 문서에는 한 가지 가능한 형식을 설명하는 부록, 특히 부록 B가 포함되어 있지만 실제 요구 사항은 아닙니다. 표준은 비디오가 개별 패킷으로 인코딩되는 방법을 지정합니다. 이러한 패킷이 저장되고 전송되는 방식은 통합 자에게 열려 있습니다.
패킷을 네트워크 추상화 계층 단위라고합니다. 종종 축약 된 NALU (또는 때로는 NAL) 각 패킷을 개별적으로 구문 분석하고 처리 할 수 있습니다. 각 NALU의 첫 번째 바이트에는 NALU 유형, 특히 비트 3 ~ 7이 포함됩니다 (비트 0은 항상 꺼져 있고 비트 1-2는 NALU가 다른 NALU에 의해 참조되는지 여부를 나타냄).
19 개의 서로 다른 NALU 유형이 VCL 및 비 VCL의 두 범주로 구분되어 정의됩니다.
단일 NALU 또는 VCL NALU는 프레임과 동일하지 않습니다. 프레임은 여러 NALU로 '분할'될 수 있습니다. 피자를자를 수있는 것처럼 요. 그런 다음 하나 이상의 슬라이스가 하나의 프레임을 포함하는 AU (Access Unit)로 가상으로 그룹화됩니다. 슬라이싱은 약간의 품질 비용이 들기 때문에 자주 사용되지 않습니다.
아래는 정의 된 모든 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 유형이 있습니다.
NALU에 포함되지 않은 것은 크기입니다. 따라서 NALU를 연결하여 스트림을 생성하는 것은 어디에서 멈추고 다음이 시작되는지 알 수 없기 때문에 작동하지 않습니다.
Annex B 사양은 각 NALU 앞에 '시작 코드'를 요구하여이를 해결합니다. 시작 코드는 2 0x00
바이트 또는 3 바이트 이고 그 뒤에 0x01
바이트가 있습니다. 예 : 0x000001
또는 0x00000001
.
4 바이트 변형은 직렬 연결을 통한 전송에 유용합니다. 31 개의 0 비트 다음에 1을 찾아 스트림을 바이트 정렬하는 것이 사소하기 때문입니다. 다음 비트가 0이면 (모든 NALU가 0 비트로 시작하기 때문에) NALU의 시작입니다. 4 바이트 변형은 일반적으로 SPS PPS AUD 및 IDR과 같은 스트림의 임의 액세스 포인트를 신호하는 데만 사용됩니다. 3 바이트 변형은 공간을 절약하기 위해 다른 모든 곳에서 사용됩니다.
시작 코드가 작동 네 개의 바이트 시퀀스 때문에 0x000000
, 0x000001
, 0x000002
및 0x000003
비 RBSP NALU 내에서 불법입니다. 따라서 NALU를 생성 할 때 시작 코드와 혼동 될 수있는 이러한 값을 이스케이프하도록주의해야합니다. 이것은 '에뮬레이션 방지'바이트를 삽입함으로써 달성된다 0x03
즉 있도록 0x000001
된다 0x00000301
.
디코딩 할 때 에뮬레이션 방지 바이트를 찾아 무시하는 것이 중요합니다. 에뮬레이션 방지 바이트는 NALU 내의 거의 모든 곳에서 발생할 수 있으므로 문서에서 이미 제거되었다고 가정하는 것이 더 편리합니다. 에뮬레이션 방지 바이트가없는 표현을 RBSP (Raw Byte Sequence Payload)라고합니다.
완전한 예를 살펴 보겠습니다.
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를 포함하는 완전한 AU입니다. 보시다시피 시작 코드와 SPS (SPS는 67로 시작)로 시작합니다. SPS 내에 두 개의 에뮬레이션 방지 바이트가 표시됩니다. 이러한 바이트가 없으면 이러한 0x000000
위치에서 잘못된 시퀀스 가 발생합니다. 다음으로 시작 코드와 PPS (PPS는 68로 시작), 마지막 시작 코드와 IDR 슬라이스가 차례로 표시됩니다. 이것은 완전한 H.264 스트림입니다. 이러한 값을 16 진 편집기에 입력하고 .264
확장자로 파일을 저장하면 다음 이미지로 변환 할 수 있습니다.
Annex B는 일반적으로 전송 스트림, 무선 방송 및 DVD와 같은 라이브 및 스트리밍 형식으로 사용됩니다. 이러한 형식에서는 SPS와 PPS를 정기적으로 반복하여 일반적으로 모든 IDR보다 먼저 반복하여 디코더에 대한 임의 액세스 포인트를 생성하는 것이 일반적입니다. 이를 통해 이미 진행중인 스트림에 참여할 수 있습니다.
H.264 스트림을 저장하는 또 다른 일반적인 방법은 AVCC 형식입니다. 이 형식에서 각 NALU는 길이 (빅 엔디안 형식)가 앞에옵니다. 이 방법은 파싱하기가 더 쉽지만 Annex 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 바이트를 사용하면 NALU 당 64k가됩니다. 이 예제에서는 작동하지만 여전히 매우 낮은 한계입니다. 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와 같은 일반적인 컨테이너 형식으로 사용됩니다.
0x00 0x07
대신의 0x07
.