약 40초 분량의 녹화 파일을 HLS 목록에 넣었는데 브라우저에는 8.10초로 잡혔습니다. 공통 init을 분리해도 8.10초였습니다. 그 상태에서 tfdt 시간값만 바꾸자 39.87초 전체가 잡혔습니다. 무엇을 바꿔서 재생이 달라졌는지를 고정한 뒤에야 직접 전달 경로의 변환을 설계할 수 있었습니다.

저는 init 분리와 시간 변경을 한 번에 적용하지 않고 나눠 비교하도록 했습니다. 실험·분석은 AI와 협업했으며, 결과를 근거로 원본을 보존하고 재생 산출물의 시간축만 구성하는 규칙을 채택했습니다. 2026년 8월 30일, MediaMTX 1.20.1로 녹화한 같은 파일 10개와 hls.js 1.5.15의 대조입니다.

공식 playback을 생략하면 그 역할도 옮겨야 합니다

MediaMTX는 녹화 파일을 각각 읽을 수 있도록 tfdt를 파일 시작 기준의 상대 시각으로 기록합니다. 방송 안에서 파일이 놓이는 위치는 mtxi에 따로 남기고, 공식 playback 경로에서 재배치합니다. 파일마다 시간이 다시 시작하는 것은 저장 설계의 일부입니다. 공식 playback 기능과 우리가 선택한 전달 경로를 먼저 구분해야 했습니다.

PokeClip은 S3·CDN에서 브라우저로 파일을 직접 전달하려 했습니다. 이 경로에는 공식 playback 서버의 재배치가 없으므로, 상대 시각이 겹치는 원본을 나열하면 이어 재생할 시간축이 만들어지지 않습니다. CDN은 저장된 바이트를 전달할 뿐, 그 바이트 안의 시간 의미를 변환해 주지 않습니다.

B와 C의 차이를 193바이트 위치로 제한했습니다

초기화 정보와 시간 배치를 한꺼번에 고치면 둘 중 무엇이 필요했는지 알 수 없습니다. 그래서 A는 원본 나열, B는 공통 init만 분리, C는 B에서 tfdt만 연속 시간축으로 바꾼 파일로 만들었습니다. A→B는 init의 효과, B→C는 시간값의 효과를 보는 비교입니다.

변형 바꾼 부분 브라우저 인식 길이
A 원본 파일 그대로 나열 8.10초
B 공통 init 분리, 기존 tfdt 유지 8.10초
C B에서 tfdt만 변경 39.87초

B와 C를 바이트 단위로 비교했을 때 차이는 tfdt 페이로드 안의 193바이트 위치에만 있었습니다. 나머지 바이트는 같았습니다. C에서는 전체 구간 버퍼와 20초 탐색 성공도 확인했습니다. 단순히 길이 숫자 하나가 달라진 결과에 그치지 않고, 실제로 찾을 수 있는 구간을 대조했습니다. 실험 표와 조건에 이 통제를 남겼습니다.

각 트랙에 같은 시작 간격을 더했습니다

변환은 파일의 mtxi.DTS에서 첫 파일의 mtxi.DTS를 뺀 시작 간격을 사용합니다. 그 간격을 각 트랙의 timescale 단위로 바꾸고 기존 tfdt에 더합니다. 다음은 실행 코드가 아니라 시간 관계를 나타낸 식입니다.

새 tfdt = 기존 tfdt + 트랙 단위로 환산한 (현재 파일 mtxi.DTS − 첫 파일 mtxi.DTS)

예를 들어 첫 파일보다 12초 뒤의 파일에 영상 시작 0.32초, 오디오 시작 0초가 있다면 새 위치는 12.32초와 12.00초입니다. 이는 변환 방식을 설명하기 위한 예시이며 새로운 측정값이 아닙니다. 두 트랙에 같은 기준 간격을 더하므로 파일 내부의 A/V 차이 0.32초는 유지됩니다.

여기서 각 트랙을 따로 “앞 트랙이 끝난 곳”에 붙이면 다른 문제가 생깁니다. 영상과 오디오의 시작·끝 차이가 누적되면서 파일 안의 A/V 관계가 달라질 수 있습니다. 저는 트랙별 누적 길이 대신 하나의 방송 내 시작 간격을 공통으로 더했습니다. 파일 내부 차이는 보존하고 방송 안의 위치만 옮기는 규칙입니다. EXTINF도 파일 간격과 대조해 목록이 안내하는 길이와 내부 시각이 어긋나지 않는지 봤습니다.

교차 확인 결과
EXTINF 합 39.873초
오디오 span 39.872초
목록 반올림 차이 약 1ms
브라우저 39.87초 전체 버퍼·20초 탐색 성공

이 대조에서는 MP4 상자와 바이트 차이뿐 아니라 길이·버퍼·탐색도 함께 확인했습니다. HLS의 fMP4 요구와 실제 플레이어 관측을 둘 다 봤습니다. 규격 설명만으로 특정 브라우저에서 정상 재생된다고 가정하지 않았습니다.

고정 입력의 대조에서 생산 계층으로

이 실험으로 init 분리만으로는 부족하고 시간축 변환이 필요하다는 근거를 얻었습니다. MediaMTX의 저장 방식을 고친 것이 아니라, 공식 playback을 생략한 S3·CDN 직접 전달 경로에서 맡아야 할 변환을 확인한 것입니다. 처리 속도는 이 시험의 비교 대상이 아닙니다.

같은 파일 10개의 고정 대조 다음에는 입력이 바뀌는 경계가 남았습니다. 재접속, 인코더 설정 변화, 새로운 init, 슬라이딩 DVR은 별도로 검증해야 합니다. 재현 스크립트를 그대로 운영 구현으로 삼지 않고, Go 생산 계층과 재접속 경계 검증으로 이어 갔습니다.

B와 C를 가른 것은 tfdt 안의 193바이트 위치였습니다. 그 밖의 바이트가 같고 전체 버퍼·20초 탐색까지 달라졌으므로, 다음 구현에서 책임질 대상을 “HLS 태그 보완”보다 구체적인 시간 변환 규칙으로 좁힐 수 있었습니다.


이 글은 PokeClip의 개발·검증 기록을 2026년 10월 15일 기준으로 정리한 CASE 23입니다. 전체 기술 기록에서 연결되는 결정을 함께 읽을 수 있습니다.