AVPlayer로 m3u8 재생이 안 될 때 — HEVC 코덱 호환성 문제

내가 담당하고 있는 앱(차량 블랙박스 앱)의 기능 중 라이브 스트리밍 기능이 있는데, 기존에는 AVPlayer를 이용하여 영상을 재생하고 있었다. 그런데 새로운 블랙박스 연동 작업을 하던 중 스트리밍이 재생되지 않았다(까만 화면만 나옴). 분명 재생 관련 코드는 건드리지 않았는데도 말이다.

 

처음에는 내 작업으로 인한 사이드 이펙트라고 생각해 관련 코드를 확인해 봤지만, 변경된 부분은 없었다. 그래서 기존에 지원되던 단말로 스트리밍을 시도해 보니 정상적으로 재생되는 것을 확인했다. 또한 AVPlayer에서 AVPlayerItem의 프로퍼티들(status, error 등)을 KVO로 디버깅해 봤으나, 별다른 로그도 출력되지 않았다.

 

그래서 선임 개발자께 해당 이슈를 정리해서 문의했고, 이전 블랙박스와 신규 단말이 사용하는 코덱이 서로 다르니 그쪽을 확인해보라는 피드백을 받았다. 이를 계기로 m3u8이 무엇이고 어떤 점이 문제였는지 파악했던 과정을 정리해 보았다.

m3u8 파일 확인

m3u8은 HLS(http live streaming) 프로토콜에서 사용하는 플레이 리스트 파일의 확장자다. 

curl 명령어로 해당 url의 내용을 확인해 보면 아래와 같은 실제 영상 데이터의 목차가 담겨있는 media playlist가 나오거나 영상의 화질별, 음성별 media playlist가 목차로 담겨있는 파일인 master playlist를 확인 가능하다.

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:8
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:8.333333,
test_h265_0.ts
#EXTINF:8.333333,
test_h265_1.ts
#EXTINF:8.333333,
test_h265_2.ts
#EXTINF:5.100000,
test_h265_3.ts
#EXT-X-ENDLIST

이슈가 발생한 단말의 경우 위와 같이 바로 ts파일이 있는 media playlist를 url로 전달받았다. HLS의 버전은 3으로 ts파일을 사용하는 것도 확인 가능했다.

 

코덱의 경우 ts파일을 ffmpeg의 ffprobe를 사용하여 내부 내용을 확인했다. ffmpeg를 설치하고 ts파일의 내용을 확인하니 아래와 같이 나온다.

ffprobe test.ts
ffprobe version 8.1 Copyright (c) 2007-2026 the FFmpeg developers
       built with Apple clang version 21.0.0 (clang-2100.0.123.102)
       configuration: --prefix=/opt/homebrew/Cellar/ffmpeg/8.1_1 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags= --enable-ffplay
     --enable-gpl --enable-libsvtav1 --enable-libopus --enable-libx264 --enable-libmp3lame --enable-libdav1d --enable-libvmaf --enable-libvpx --enable-libx265 --enable-openssl
      --enable-videotoolbox --enable-audiotoolbox --enable-neon
       libavutil      60. 26.100 / 60. 26.100
       libavcodec     62. 28.100 / 62. 28.100
       libavformat    62. 12.100 / 62. 12.100
       libavdevice    62.  3.100 / 62.  3.100                                                                                                                                  
       libavfilter    11. 14.100 / 11. 14.100                                  
       libswscale      9.  5.100 /  9.  5.100                                                                                                                                  
       libswresample   6.  3.100 /  6.  3.100                                                                                                                                  
     Input #0, mpegts, from 'test.ts':
       Duration: 00:00:02.00, start: 26.933333, bitrate: 627 kb/s                                                                                                              
       Program 1  
         Metadata:
           service_name    : Service01
           service_provider: FFmpeg
       Stream #0:0[0x100]: Video: hevc (Main) (HEVC / 0x43564548), yuv420p(tv, bt709), 1280x720 [SAR 1:1 DAR 16:9], 15 fps, 15 tbr, 90k tbn, start 26.933333

 

가장 아래에 스트림 영상에 관한 정보가 나오는 것을 볼 수 있다. 해상도, 코덱, 프레임 등등.. 그리고 HEVC(h.265) 코덱을 이용한 것을 확인했다.

 

그리고 이번에는 AVPlayer로 재생이 되는 단말을 확인했을 때, HLS 버전과 m3u8도 동일한 형식인 것을 확인하였고, ts파일을 확인한 결과 avc1(h.264) 코덱을 사용한 것을 확인했다.

ffprobe version 8.1 Copyright (c) 2007-2026 the FFmpeg developers
       built with Apple clang version 21.0.0 (clang-2100.0.123.102)
       configuration: --prefix=/opt/homebrew/Cellar/ffmpeg/8.1_1 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags= --enable-ffplay
     --enable-gpl --enable-libsvtav1 --enable-libopus --enable-libx264 --enable-libmp3lame --enable-libdav1d --enable-libvmaf --enable-libvpx --enable-libx265 --enable-openssl
      --enable-videotoolbox --enable-audiotoolbox --enable-neon
       libavutil      60. 26.100 / 60. 26.100
       libavcodec     62. 28.100 / 62. 28.100
       libavformat    62. 12.100 / 62. 12.100
       libavdevice    62.  3.100 / 62.  3.100
       libavfilter    11. 14.100 / 11. 14.100
       libswscale      9.  5.100 /  9.  5.100
       libswresample   6.  3.100 /  6.  3.100
     Input #0, mpegts, from 'test.ts':
       Duration: 00:00:02.00, start: 1.466667, bitrate: 139 kb/s
       Program 1
         Metadata:
           service_name    : Service01
           service_provider: FFmpeg
       Stream #0:0[0x100]: Video: h264 (Main) ([27][0][0][0] / 0x001B), yuv420p(progressive), 1280x720 [SAR 1:1 DAR 16:9], 15 fps, 15 tbr, 90k tbn, start 1.466667

 

즉 AVPlayer로 재생이 가능/불가능한 영상의 차이는 코덱이 다른 차이밖에 없었다.

 

이와 관련하여 자료를 좀 더 찾아보니 apple developer forum에서 다음과 같은 글을 찾았다.

https://developer.apple.com/forums/thread/132291

 

When will support for .ts containe… | Apple Developer Forums

Hi, I have some questions regarding the article "HLS Authoring Specification for Apple Devices". Spec: The container format for HEVC video MUST be fMP4. Questions: Does fmp4 container type dependency persist for HEVC codecs? When will support for .ts conta

developer.apple.com

 

해당 포럼의 답변에 따르면, Apple의 HLS Authoring Specification에서 HEVC 코덱은 fMP4 컨테이너만 허용한다고 명시되어 있었다. 실제로 공식 문서를 확인해 보니 동일한 내용이 적혀 있었다.

 

즉 새롭게 추가된 단말에서 스트리밍은 AVPlayer가 지원하지 않는 포맷이어서 재생이 되지 않았던 것.

 

이 이슈를 수정하기 위해 서버에서 단말로부터 받은 영상을 fmp4 포맷으로 변경하거나 같은 변환 사양을 검토를 해 보았지만, 서버에서 변환 프로세스가 들어갈 경우 스트리밍의 지연이 발생을 이유로 포맷은 그대로 유지, 앱단에서 처리하기로 결정했고, 현재는 AVPlayer가 아닌 다른 영상 플레이어(ffmpeg 기반)를 사용했다.

 

이번 이슈를 통해 AVPlayer가 모든 HLS 스트림을 재생할 수 있는 것은 아니라는 점을 알게 되었다. 같은 m3u8, 같은 HLS 버전이라도 코덱과 컨테이너 조합에 따라 재생 가능 여부가 달라진다. 비슷한 증상으로 고민하고 있다면 ffprobe로 ts 파일의 코덱부터 확인해 보는 것을 추천한다.