Cloud Recording 점프 재생 무한 로딩 — moov / ENDLIST / DISCONTINUITY 트러블슈팅
다운로드는 다 끝났는데 영상을 중간으로 점프하면 무한 로딩이 걸리거나 아예 재생이 안 됩니다. 알고 보면 데이터가 손상된 게 아니라 인덱스가 불완전한 경우가 대부분입니다. 이 글은 MP4의 moov atom 위치, HLS의 ENDLIST 누락, 그리고 DISCONTINUITY 누락이라는 세 가지 패턴을 진단하는 법과 ffmpeg으로 고치는 처방을 정리하고, Agora Cloud Recording 결과물에 바로 쓸 수 있는 후처리 파이프라인까지 안내합니다.
목차(21개 항목)
- 핵심 가설 — 데이터는 멀쩡, 인덱스만 깨짐
패턴 ① MP4 moov atom이 끝에 있을 때
패턴 ② HLS m3u8의 ENDLIST 누락
패턴 ③ DISCONTINUITY 태그 누락
- 통합 진단 흐름
- Agora Cloud Recording 후처리 권장 파이프라인
- 빠른 체크리스트
- 한 줄 결론
- 관련 글
- 참고 자료
"Cloud Recording에서 받은 영상 — 처음부터 재생은 잘 되는데 중간으로 점프하면 무한 로딩, 또는 아예 재생 안 됨". 다운로드는 다 끝났는데도 그렇습니다. 이건 데이터가 손상된 게 아니라 인덱스가 불완전한 것이 원인일 가능성이 높습니다.
이 글은 그 인덱스 불완전성의 3가지 패턴을 분류하고, 각각의 진단·처방을 정리합니다.
핵심 가설 — 데이터는 멀쩡, 인덱스만 깨짐
영상을 점프하려면 "이 시점은 파일의 어느 위치"라는 매핑 정보가 필요합니다. 그 인덱스가 없거나 손상돼도 순차 재생은 가능합니다(처음부터 데이터를 따라가기만 하면 되니까). 점프할 때만 실패합니다.
세 가지 인덱스 문제 패턴:
| 패턴 | 컨테이너 | 증상 트리거 |
|---|---|---|
| ① moov atom이 파일 끝에 있음 | MP4 | 점프할 때마다 파일 끝까지 다녀와서 느림/멈춤 |
② #EXT-X-ENDLIST 누락 | HLS (m3u8) | 플레이어가 "라이브로 인식" → 점프 시 다음 segment 무한 대기 |
③ #EXT-X-DISCONTINUITY 누락 | HLS | 코덱/해상도 변경 지점에서 디코더 초기화 실패 |
패턴 ① MP4 moov atom이 끝에 있을 때
구조
MP4는 두 부분으로 구성됩니다.
녹화 도중엔 전체 길이를 모르므로 인덱스를 끝에 붙이는 게 자연스럽습니다. 하지만 그 상태로 플레이어에 던지면:
- 첫 재생: 파일 끝까지 가서 moov 읽고 → 처음으로 돌아와서 재생
- 점프: 매번 인덱스 참조하느라 디스크/파일 안에서 왔다갔다 → 느림 또는 멈춤
진단
처방 — +faststart
-c copy: 재인코딩 없음 → 2시간 영상도 수십 초+faststart: moov를 파일 앞으로 옮김- 결과물: 어디로 점프해도 즉시 반응
YouTube가 업로드된 영상에 자동으로 적용하는 후처리가 이것입니다.
패턴 ② HLS m3u8의 ENDLIST 누락
정상 m3u8 구조
누락 시 증상
#EXT-X-ENDLIST가 없으면 플레이어는 "라이브 스트리밍인가?" 판단합니다.
- 처음부터 재생: 첫 segment부터 순차 진행, 어느 시점에 마지막 segment 도달 → 다음 segment 기다림 → 멈춤 (이건 사용자가 끝까지 본 경우라 잘 안 보임)
- 점프: 그 위치 segment 받고 → 다음 segment 받으려고 m3u8 새로고침 시도 → 라이브로 인식했으니 "곧 새 segment 올 거야"라며 무한 대기
녹화가 비정상 종료되면 종종 발생합니다. Agora Cloud Recording에서도 stop API 누락·서버 크래시·storage upload 실패 같은 케이스에서 ENDLIST가 안 붙을 수 있습니다.
진단
처방
응급 — 한 줄 추가:
>>는 파일 끝에 줄 추가. 정말 단순하지만 효과적인 응급 처치입니다.
근본 — mp4로 변환:
ffmpeg이 m3u8을 읽어 단일 mp4로 정리. ENDLIST 누락도 자동으로 처리됩니다.
패턴 ③ DISCONTINUITY 태그 누락
개념
HLS의 segment들은 보통 같은 코덱·해상도·프레임레이트로 매끄럽게 이어집니다. 중간에 특성이 바뀌면 #EXT-X-DISCONTINUITY 태그를 넣어 "여기서 stream이 바뀜"을 디코더에 알려야 합니다.
이 태그 없이 segment 특성만 바뀌면:
- 처음부터 재생: segment 1→2→3 순차 진행이라 디코더가 알아서 재초기화 시도
- 점프: 특성 다른 segment로 바로 갔는데 m3u8엔 변경 표시 없음 → 디코더가 이전 segment 기준으로 가정 → 초기화 실패 → 무한 로딩
발생 시나리오 (Cloud Recording 맥락)
| 트리거 | 무엇이 바뀌나 |
|---|---|
| 사용자가 카메라/마이크를 껐다 켬 | stream 구성 변경 (audio-only ↔ audio+video) |
| 누군가 해상도 변경 | width/height/bitrate |
| 채널에 새 사용자 입장/퇴장 (composite mode) | 합쳐진 mixed stream의 구성 |
| Cloud Recording의 High Availability mechanism 작동 | 녹화 서버 자동 전환으로 m3u8이 둘로 쪼개짐 (bak0, bak1 … prefix) |
진단
각 segment의 width/height/codec/framerate가 다르면 그 사이에 DISCONTINUITY가 있어야 합니다.
처방
가장 확실 — 재인코딩으로 정규화:
- 재인코딩하면 모든 frame이 균일한 코덱/해상도로 통일됨 → discontinuity 자체가 사라짐
- 시간: 영상 길이의 0.3~0.5배 정도
- 점프 성능을 더 보장하려면 keyframe 간격도 강제:
-g 60 -keyint_min 60
Agora HA bak 파일 합치기: HA mechanism이 작동하면 fault processing center가 90초 이내에 새 녹화 서버로 전환하고, 그 시점부터의 인덱스를 담은 새 m3u8(bak0, bak1 …)을 생성합니다. Agora는 이 원본 m3u8과 bak m3u8을 단일 mp4로 합쳐주는 자체 transcoder script를 제공합니다(composite/mix mode 한정). Manage Recorded Files 문서의 다운로드 링크 참조. 단순 ffmpeg concat이 아니라 경계에 discontinuity를 적절히 처리해줍니다.
통합 진단 흐름
Agora Cloud Recording 후처리 권장 파이프라인
매번 클라이언트 쪽에서 이 문제를 만나는 게 싫다면, 결과물을 그대로 전달하지 말고 표준 후처리 파이프라인을 한 번 거치는 걸 권장합니다.
핵심 옵션 의미:
| 옵션 | 의미 |
|---|---|
-c copy | 재인코딩 없이 컨테이너만 변경 (빠름, 화질 손실 없음) |
-movflags +faststart | moov atom을 앞으로 |
-fflags +genpts | pts 깨진 경우 ffmpeg이 새로 생성 |
-g 60 -keyint_min 60 | 60프레임마다 keyframe 강제 (#30 참고) |
실무 팁: Cloud Recording의
recordingFileConfig.avFileType: ["hls", "mp4"]로 mp4를 동시에 받도록 설정해도, 그 mp4의 moov 위치까지 보장되는 건 아닙니다. 한 번 후처리를 거치는 게 안전합니다.
빠른 체크리스트
받은 결과물에서 점프 이슈가 있을 때, 5분 안에 원인을 좁히는 순서:
한 줄 결론
"점프가 안 된다"는 건 데이터 손상이 아니라 인덱스 불완전 신호입니다. moov 위치, ENDLIST, DISCONTINUITY — 세 가지 인덱스 단서를 따라가면 거의 다 풀립니다.
관련 글
- #11 Cloud Recording 녹화 파일 저장 — S3 — 후처리 대상인 원본 파일이 어디에 어떤 형태로 떨어지는지
- #15 M3U8과 TS — HLS Deep Dive — ENDLIST/DISCONTINUITY가 왜 필요한지 playlist 구조부터
- #17 FFmpeg 실전 파이프라인 — Agora 녹화 VOD — 본문 후처리 파이프라인의 전체 버전
- #16 FFmpeg 컨테이너/코덱/스트림 — moov atom·
-c copy·재컨테이닝의 컨테이너 기초 - #30 x264 실전 옵션 — ref/tune/keyint — 재인코딩 시
-g/keyint로 점프 성능을 보장하는 키프레임 전략 - #31 라이브 스트림 상태 점검 — ffprobe/gstreamer — segment 특성 비교에 쓴 ffprobe 진단 심화
참고 자료
- Cloud Recording — Manage recorded files (Agora Docs) — HA mechanism의
bak<n>파일 명명 규칙과 transcoder script 다운로드 링크 - Cloud Recording — Core concepts (Agora Docs) — 90초 서버 자동 전환 등 high availability 동작 개요
- ffmpeg(1) — movflags
faststart(FFmpeg Documentation) — moov atom을 파일 앞으로 옮기는+faststart의 공식 설명 - RFC 8216 — HTTP Live Streaming: EXT-X-ENDLIST / EXT-X-DISCONTINUITY / EXT-X-PLAYLIST-TYPE — HLS playlist 태그의 표준 정의와 VOD/Live 구분 의미
- QuickTime File Format — Movie Atom (moov) (Apple Developer) — MP4/QuickTime 인덱스인 moov atom의 구조
- ffmpeg -fflags genpts / -movflags (FFmpeg Formats Documentation) — 파이프라인에서 쓴
+genpts·muxer 플래그의 1차 레퍼런스