H.264/H.265 에서의 NAL 유닛과 NAL 타입 찾기

이상문
4 min readMay 11, 2023

동영상 인코딩은 많은 기술 개념과 전문 용어가 포함된 복잡한 과정이다. 비디오 인코딩 작업 시 이해해야 할 가장 중요한 개념 중 하나는 NAL 유닛이다. NAL 유닛은 H.264 및 H.265 비디오 인코딩 전송의 핵심 구성 요소이며, 비디오 데이터로 작업하려면 그 작동 방식을 이해할 필요가 있다.

NAL 유닛

NAL 유닛은 H.264 및 H.265 비디오 인코딩 표준에 정의되어 있다. 비디오 데이터를 쉽게 압축하여 전송할 수 있는 독립된 작은 단위로 분할하는 데 사용된다. 각 NAL 단위에는 헤더와 페이로드가 포함된다.

NAL 유닛의 헤더에는 유형과 크기 등 유닛에 대한 정보가 포함된다. 페이로드에는 압축된 비디오 데이터가 포함된다. 슬라이스, SPS(시퀀스 파라미터 세트), PPS(픽처 파라미터 세트) 유닛 등 여러 유형의 NAL 유닛이 있다.

H.264 에서 NAL 유닛

H.264는 비디오 스트리밍 애플리케이션에서 널리 사용되는 비디오 인코딩 표준이다. H.264 비디오는 프레임으로 나뉘며, 각 프레임은 하나 이상의 슬라이스를 포함한다. 프레임은 I-프레임, P-프레임, B-프레임 등 여러 타입이 있다.

SPS 및 PPS 장치는 비디오 데이터를 디코딩하는 데 필요한 매개변수를 지정하는 데 사용된다. 여기에는 비디오 해상도, 비트 전송률 및 기타 매개변수에 대한 정보가 포함되어 있다.

NAL 유닛을 찾기 위해서는 시작 코드를 찾아야 하고, 이후 여러 가지 처리를 위해서 NAL 유닛의 타입 알아내야 하는 경우가 많다.

uint8_t *ptr = nal_buffer;
int nal_type = (ptr[0] & 0x1F);
if (nal_type == 7 || nal_type == 8) {
// This is an SPS or PPS unit
}
else if (nal_type == 5) {
// This is an I-frame
}
else {
// This is a non-I-frame
}
if (ptr[0] == 0x00 && ptr[1] == 0x00 && ptr[2] == 0x01) {
// This is a 3-byte start code
}
else if (ptr[0] == 0x00 && ptr[1] == 0x00 && ptr[2] == 0x00 && ptr[3] == 0x01) {
// This is a 4-byte start code
}

시작 코드는 “0x00 0x00 0x01” 혹은 “0x00 0x00 0x00 0x01” 이며, 바이트 정렬된 경우 전자를 사용한다.

시작 코드 다음 첫번째 바이트에 NAL 타입 정보가 들어 있다. 0x1f와 &연산을 취하는 것처럼 5비트만을 타입 정보를 위해 사용한다.

H.265 에서 NAL 유닛

고효율 비디오 코딩(HEVC)이라고도 하는 H.265는 비디오 코딩에 관한 공동 협력팀(JCT-VC)에서 개발한 최신 비디오 압축 표준이다. 비슷한 비디오 품질을 유지하면서 H.264에 비해 향상된 압축 효율을 제공하도록 설계되었다.

H.265와 H.264의 주요 차이점 중 하나는 비디오 스트림이 코딩 단위로 분할되는 방식이다. H.264에서는 스트림이 매크로 블록으로 분할되는 반면, H.265에서는 코딩 트리 단위(CTU)로 분할된다. CTU는 매크로 블록보다 유연하며 크기가 16x16에서 64x64픽셀까지 다양하다.

H.264와 마찬가지로 H.265도 NAL 단위를 사용하여 비디오 데이터를 패키징한다. H.265의 NAL 단위는 H.264의 단위와 구조가 유사하며, 1바이트 헤더에 NAL 단위 유형을 지정하고 그 뒤에 페이로드 데이터가 이어진다.

NAL 타입을 구하는 방법이 H.264와는 조금 다르다. NAL 페이로드의 첫번째 바이트에서 찾는 것은 동일하나 H.264에서는 비트0~비트4를 사용하는 것과는 달리, H.265에서는 비트1~비트6을 사용한다.

uint8_t *ptr = nal_buffer;
int nal_type = (ptr[0] >> 1) & 0x3F;
switch (nal_type) {
case 0:
printf("NAL unit type: Unspecified (0)\n");
break;
case 32:
printf("NAL unit type: VPS (32)\n");
break;
case 33:
printf("NAL unit type: SPS (33)\n");
break;
case 34:
printf("NAL unit type: PPS (34)\n");
break;
case 39:
printf("NAL unit type: Prefix SEI (39)\n");
break;
case 40:
printf("NAL unit type: Suffix SEI (40)\n");
break;
default:
printf("NAL unit type: Unknown (%d)\n", nal_type);
}

--

--

이상문

software developer working mainly in field of streaming, using C++, javascript