FFmpeg 1.2배속 만들기: setpts·atempo로 영상과 소리의 시간 맞추기
FFmpeg의 setpts·atempo로 1.1배속과 1.2배속을 만들고, 합성 영상·사인파 7개 실험으로 길이와 음높이를 검증한다. 시작 시각, 자막, 인트로·아웃트로 처리의 주의점도 정리한다.
영상과 소리를 함께 1.2배속으로 줄이려면 두 스트림에 같은 속도 비율을 적용해야 한다. 영상은 setpts, 오디오는 atempo로 처리한다. 영상만 빨라지면 소리가 뒤에 남고, 소리만 빨라지면 화면이 뒤에 남는다. 짧은 합성 영상을 직접 변환해 차이를 확인해 보자.
영상 프레임과 오디오 파형을 함께 압축하는 개념 일러스트다. 실제 필터 구조나 측정값을 나타낸 도식은 아니다.
작성: 2026-11-06. 검증 환경은 Linux, FFmpeg 7.1.5, Python 3.12, NumPy 2.3.5다. 12초·30fps 합성 영상과 48kHz·440Hz 사인파를 사용했다. 실제 인물의 음성이나 비공개 영상은 사용하지 않았다.
1.2배속은 길이를 20% 줄이는 계산이 아니다
속도 배율을 S라고 하면 목표 길이는 원본 길이 / S다. 12초 영상은 1.2배속에서 10초, 1.1배속에서 약 10.909초가 된다. 길이에 0.8을 곱하면 9.6초이므로 1.25배속에 해당한다.
영상의 setpts는 프레임의 표시 시각을 바꾸고, 오디오의 atempo는 템포를 바꾼다. 따라서 setpts=PTS/1.2와 atempo=1.2가 짝이 된다. 반면 asetrate는 PCM 데이터는 그대로 두고 샘플레이트를 바꿔 속도와 음높이가 함께 달라진다. FFmpeg 필터 공식 문서
나레이션에서 원하는 것은 보통 재생 시간의 단축이다. 목소리까지 높아지는 효과가 목적이 아니라면 asetrate 대신 atempo부터 검토한다. 다만 템포 변경 뒤의 발음·호흡·음색은 실제로 들어 보고 결정해야 한다.
실행 예제: 먼저 조건이 분명한 원본 만들기
다음 명령은 12초 테스트 영상과 소리를 만든다. 기존 파일을 덮어쓰지 않도록 -n을 사용했다. FFmpeg에 libx264 인코더가 포함되어 있어야 한다.
이 원본은 영상과 오디오가 같은 시각에 시작한다. 아래 명령의 PTS-STARTPTS는 각 스트림의 시작을 0으로 맞추므로, 원래부터 의도적인 A/V 시작 시각 차이가 있는 파일에 그대로 적용하면 그 차이를 없앨 수 있다. 먼저 원본의 시작 시각과 실제 재생을 확인한다. 이 주의점은 STARTPTS의 정의에서 도출한 적용상의 판단이다. setpts·asetpts 정의
영상·오디오를 같은 배율로 처리하기
1.1배속 파일은 위 필터의 두 1.2를 모두 1.1로 바꾸고 출력 이름도 바꿔 만든다. 한쪽만 바꾸지 않는다.
여기서 fps=30은 출력 영상을 30fps로 만들겠다는 명시적인 선택이다. 원본 프레임레이트를 자동 보존하는 설정이 아니다. fps는 필요하면 프레임을 버리거나 복제한다. 60fps 영상이나 가변 프레임레이트 원본을 다룬다면 납품 조건에 맞게 다시 정한다. fps 공식 문서
이 명령은 첫 번째 영상과 첫 번째 오디오만 선택한다. 여러 언어의 음성, 별도 자막, 첨부 파일까지 자동으로 유지하지 않는다. 필터를 적용하는 스트림은 재인코딩하므로 그대로 복사하는 -c copy 경로와도 다르다. 예제의 ultrafast는 빠른 재현을 위한 선택이며 배포 파일의 용량·화질 최적값을 뜻하지 않는다. FFmpeg 스트림 선택과 인코딩 문서
7개 로컬 실험에서 확인한 것
같은 원본에 영상 배율과 오디오 배율을 달리 적용한 뒤, 출력 스트림의 길이를 ffprobe로 읽었다. 아래 숫자는 이 환경의 실제 결과다.
앞의 다섯 사례는 위와 같은 H.264·AAC 출력이다. 마지막 두 사례는 음높이 비교를 위해 별도 PCM WAV로 저장했다. asetrate 경로는 48kHz 입력에 asetrate=57600,aresample=48000을 적용했다. 440 × 1.2 = 528이므로 음높이도 올라간다.
주파수는 각 출력의 1~3초 구간에 Hann 창을 적용한 FFT에서 가장 큰 성분으로 측정했다. atempo 경로에서는 440Hz 성분이 유지됐다. 단일 사인파 결과가 사람 목소리의 자연스러움이나 전체 음질을 보증하지는 않는다.
길이도 완전히 같은 소수값으로 끝나지는 않았다. 30fps 영상은 프레임 간격으로 양자화되고 오디오는 필터·인코더의 처리 단위를 거친다. 이 실험의 두 스트림 차이는 1.2배속에서 약 1ms, 1.1배속에서 약 8ms였다. 원본 12초를 정확히 나눈 이론값과 파일에 기록된 길이를 구분해서 읽는다.
다섯 길이 실험에서는 각 스트림이 이론값에서 50ms 이내인지 검사했다. 두 배속을 맞춘 파일에서는 A/V 길이 차이도 50ms 이내였고, 한쪽만 바꾼 파일에서는 1.9초 이상 벌어졌다. 이는 이 짧은 합성 입력의 회귀 검사 기준이지, 모든 영상의 합격 기준은 아니다.
파일 길이 확인과 실제 싱크 확인은 별개다
원본과 출력에 각각 다음 명령을 실행한다.
컨테이너 전체 길이만 보면 어느 스트림이 길게 남았는지 놓칠 수 있다. 영상·오디오의 start_time과 duration을 따로 본다. 일부 컨테이너에서는 스트림 길이가 나오지 않을 수 있으므로 그 경우 패킷·프레임 타임스탬프나 실제 디코딩 결과를 추가로 확인한다. ffprobe 공식 문서
메타데이터 길이가 비슷해도 중간에 어긋날 수 있다. 실제 파일에서는 다음 세 지점을 재생해 확인한다.
- 시작: 첫 발음과 화면 전환이 맞는가.
- 중간: 입 모양이나 화면 속 동작과 소리가 계속 맞는가.
- 끝: 마지막 문장이나 효과음이 잘리거나 긴 무음이 남지 않는가.
-shortest를 추가해 길이 차이를 감추지 않는다. 이 옵션은 가장 짧은 출력 스트림이 끝날 때 인코딩을 종료한다. 속도 비율이나 시작 시각을 수정하지 않으므로, 문제를 해결하기보다 긴 쪽의 끝부분을 잘라낼 수 있다. FFmpeg의 -shortest 설명
인트로·아웃트로·자막은 언제 붙일까
본문만 빨라지고 공통 인트로와 아웃트로는 원래 박자를 유지해야 한다면, 본문 배속을 먼저 끝내고 공통 구간을 붙이는 순서가 명확하다. 합쳐진 완성본 전체에 배속을 걸면 로고 애니메이션과 음악까지 빨라진다.
별도 자막의 시간도 본문과 같은 비율로 바꿔야 한다. 예를 들어 본문의 6초 지점은 1.2배속에서 5초가 된다. 그 앞에 3초짜리 인트로를 붙이면 완성본에서는 8초다. 이 관계를 편집 파이프라인의 한곳에서 계산하면 영상과 자막에 서로 다른 배율을 넣는 실수를 줄일 수 있다.
화면에 이미 구워진 자막은 영상과 함께 빨라지지만 읽을 시간도 줄어든다. 속도를 정할 때는 발음뿐 아니라 화면의 글자 밀도와 장면 전환도 함께 확인한다. 이 글의 로컬 실험에는 자막·인트로 연결·실제 음성 품질 평가는 포함하지 않았다.
정리
배속 작업의 핵심은 같은 배율을 영상과 오디오에 적용하고, 원본의 시작 시각을 존중하는 것이다. setpts와 atempo로 처리한 뒤 스트림별 길이를 확인하고, 실제 재생으로 시작·중간·끝의 싱크를 검사한다. 마지막으로 자막과 공통 구간의 시간을 같은 계산 기준에 맞춘다. 명령이 성공했다는 사실과 사람이 보기 좋은 결과가 나왔다는 판단은 각각 확인해야 한다.