C 언어로 만드는 하드웨어 가속 TV 플레이어, 어디까지 왔을까?
HLS 스트리밍(HLS Streaming), MPEG-TS 디멀싱(MPEG-TS Demuxing), H.264 파싱(H.264 Parsing), Vulkan 비디오 디코딩(Vulkan Video Decoding)을 C 언어로 직접 구현하는 프로젝트 소개
FFmpeg, libav, GStreamer 등 기존 라이브러리 사용을 배제하고, picoM3U8, picoMpegTS, picoH264 등 자체 라이브러리 개발
H.264 비트스트림 파싱(H.264 Bitstream Parsing), POC 계산(Picture Order Count Calculation) 등 복잡한 기술적 난제와 해결 과정 제시
Vulkan Video 확장 기능(Vulkan Video Extensions)을 활용한 하드웨어 가속 디코딩 구현 및 성능 최적화 시도
HLS(HTTP Live Streaming) 프로토콜 이해
HLS(HTTP Live Streaming)는 적응형 비트레이트 스트리밍 프로토콜로, 라이브 및 VOD 콘텐츠 전송에 널리 사용된다. 마스터 플레이리스트(Master Playlists)는 다양한 비트레이트의 스트림을 참조하고, 미디어 플레이리스트(Media Playlists)는 실제 미디어 세그먼트의 URL을 포함한다. 개발자는 RFC 8216을 기반으로 picoM3U8 라이브러리를 구현하여 M3U8 파일을 파싱하고, 미디어 세그먼트 URL을 추출한다. 특히, 라이브 스트림의 경우, 미디어 시퀀스 번호(Media Sequence Number)를 통해 세그먼트의 순서를 관리한다.
MPEG-TS(MPEG Transport Stream) 디멀싱 심층 분석
MPEG-TS(MPEG Transport Stream)는 오디오, 비디오, 데이터를 전송하기 위한 컨테이너 형식으로, 오류에 강한 구조를 갖는다. 고정 크기(188-byte)의 전송 패킷(Transport Packets)으로 구성되며, 각 패킷은 PID(Packet Identifier)를 통해 특정 스트림을 식별한다. 개발자는 picoMpegTS 라이브러리를 사용하여 MPEG-TS 스트림을 파싱하고, PAT, PMT, PES 패킷을 처리한다. 특히, 스트림 유형 식별(Stream Type Identification)을 통해 H.264 비디오와 AAC 오디오를 구분하고, PES 패킷을 재조립한다.
H.264 비트스트림 파싱 및 POC(Picture Order Count) 계산
H.264 비트스트림은 복잡한 구조를 가지며, SPS(Sequence Parameter Sets), PPS(Picture Parameter Sets), 슬라이스 헤더(Slice Headers) 등의 정보를 포함한다. 개발자는 picoH264 라이브러리를 사용하여 H.264 비트스트림을 파싱하고, Vulkan Video 디코더에 필요한 메타데이터를 추출한다. 특히, POC(Picture Order Count) 계산은 B-프레임(B-frames)을 포함하는 비디오의 올바른 디스플레이 순서를 결정하는 데 중요하다. POC Type 0, 1, 2 등 다양한 계산 방식을 지원한다.
Vulkan Video를 활용한 하드웨어 가속 디코딩
Vulkan Video 확장은 Vulkan API에 비디오 인코딩 및 디코딩 기능을 통합하여, 하드웨어 가속을 제공한다. 개발자는 비디오 세션(Video Sessions)을 생성하고, SPS, PPS와 같은 코덱 관련 메타데이터(Codec-Specific Metadata)를 설정한다. 디코딩 작업(Decode Operations)은 커맨드 버퍼(Command Buffer)를 통해 제출되며, DPB(Decoded Picture Buffer)는 참조 프레임을 저장한다. Vulkan Video를 사용하면, 제로 카피(Zero-Copy) 전송, 통합 메모리 관리, 명시적 동기화, 교차 플랫폼 하드웨어 가속을 구현할 수 있다. 또한, 디버깅을 위해 AVD_VULKAN_VIDEO_DISABLE 매크로를 사용하여 비디오 기능을 비활성화할 수 있다.
오디오 디코딩 및 플랫폼 종속성
오디오 디코딩을 위해, picoAudio 라이브러리는 플랫폼 네이티브 API를 사용한다. Windows에서는 Media Foundation을, macOS에서는 AudioToolbox를 활용하여 고품질 오디오 디코딩을 수행한다. Linux 환경에서는 libfaad2를 고려했으나, 테스트 환경 부족으로 구현하지 못했다. picoAudio는 다양한 출력 형식(16-bit integer, 32-bit float)을 지원하며, HLS 플레이어에서는 MPEG-TS 디멀싱을 통해 얻은 AAC 데이터를 사용한다. PortAudio를 사용하여 오디오 I/O를 관리하고, 비디오와 오디오의 동기화를 제어한다.