FFmpeg로 영상 합치기: concat 디먹서 vs concat 필터
FFmpeg로 영상을 이어 붙일 때 설정이 같은 파일은 concat 디먹서와 -c copy로 재인코딩 없이 잇고, 서로 다른 클립은 concat 필터로 재인코딩해 잇습니다.

FFmpeg로 영상을 이어 붙여 합치려면, 모든 파일의 스트림과 설정이 같을 때는 concat 디먹서를 쓰세요. 텍스트 파일에 파일 목록을 적고 ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4를 실행하면 재인코딩 없이 이어집니다. 클립마다 크기, 프레임 레이트, 코덱이 다르면 대신 concat 필터를 쓰세요. 이 필터는 클립을 디코딩해 이어 붙인 뒤 결과를 인코딩합니다.
FFmpeg 관련 내용은 포맷, 필터, ffmpeg 문서에서, Sume 관련 내용은 Timeline 1.0과 오디오 분리 문서에서 가져왔으며, 모두 2026-09-28에 확인했습니다. 현재 동작이라고 설명한 내용은 Sume의 코드에서 확인한 것입니다.
재인코딩 없이 MP4 파일을 이어 붙이려면 어떻게 하나요?
클립마다 file 줄을 하나씩, 재생 순서대로 적은 목록 파일을 만든 다음, concat 디먹서로 읽고 스트림을 복사하세요.
- concat 디먹서는 모든 패킷을 한데 먹싱한 것처럼 파일을 하나씩 차례로 읽습니다. 타임스탬프는 각 파일이 앞 파일이 끝나는 지점에서 시작하도록 옮겨집니다.
-f concat은 이 디먹서를 선택합니다. 대신 첫 줄에ffconcat version 1.0을 쓰면 FFmpeg가 스크립트를 스스로 알아봅니다.-safe 0옵션은 어떤 파일 이름이든 받아들입니다. 기본적으로 FFmpeg는 절대 경로, 프로토콜을 지정한 경로, 글자·숫자·마침표·밑줄·하이픈 외의 문자를 쓴 경로를 거부합니다.- 모든 파일의 스트림이 같아야 합니다. 즉 코덱, 타임 베이스 등이 일치해야 합니다. 타임스탬프 이동은 모든 스트림에 한꺼번에 적용되므로, 한 파일 안에서 스트림 길이가 서로 다르면 틈이 생길 수 있고, 파일 길이가 잘못 지정되면 아티팩트가 생길 수 있습니다.
-c copy는 디코딩도 인코딩도 하지 않는다는 뜻이므로 화질 손실이 없습니다.
# list.txt
file 'part1.mp4'
file 'part2.mp4'
file 'part3.mp4'
ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4해상도나 코덱이 다른 영상은 어떻게 이어 붙이나요?
concat 필터를 쓰세요. 이 필터는 디코딩된 프레임에서 동작하므로 각 입력을 먼저 한 가지 크기로 맞출 수 있습니다. 다음 명령은 소리가 있는 클립 두 개를 1920×1080 파일 하나로 이어 붙이며, 모양이 다른 클립은 검은 여백을 넣어 프레임 안에 맞춥니다.
concat=n=2:v=1:a=1은 각각 영상 스트림 하나와 오디오 스트림 하나로 된 세그먼트 두 개를 잇습니다. 모든 세그먼트는 유형별 스트림 수가 같아야 하므로, 소리가 없는 클립이 있으면 이 방식으로는 이을 수 없습니다.- FFmpeg는 공통 픽셀 포맷, 샘플레이트, 채널 레이아웃은 스스로 고르지만, 해상도 같은 다른 설정은 명시적으로 변환해야 합니다. 그 단계가
scale과pad입니다. - 프레임 레이트가 달라도 받아들이지만 출력이 가변 프레임 레이트가 되므로, 예시에서는
fps필터로 레이트를 하나로 맞춥니다. - 이 필터는 마지막 세그먼트를 제외한 각 세그먼트에서 가장 긴 스트림의 길이를 따르고, 더 짧은 오디오는 무음으로 채웁니다.
- 출력은 재인코딩되며, FFmpeg 문서에 따르면 인코딩은 대부분의 경우 화질을 떨어뜨립니다.
ffmpeg -i a.mp4 -i b.mp4 -filter_complex \
'[0:v]scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,setsar=1,fps=30[v0];
[1:v]scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,setsar=1,fps=30[v1];
[v0][0:a][v1][1:a]concat=n=2:v=1:a=1[v][a]' \
-map '[v]' -map '[a]' -c:v libx264 -c:a aac output.mp4어떤 방법을 써야 하나요?
한 녹화본에서 스트림 카피로 잘라 낸 조각처럼 모든 파일의 스트림이 같다면 복사하세요. 그렇지 않다면 재인코딩하세요. 디먹서는 코덱과 타임 베이스가 일치해야 하고, 클립의 크기나 레이트를 바꾸려면 필터가 필요한데 스트림 카피로는 필터를 적용할 수 없기 때문입니다.
| 방법 | 재인코딩 | 클립 일치 필요 | 소리 |
|---|---|---|---|
-c copy를 쓴 concat 디먹서 | 아니요 | 예: 스트림, 코덱, 타임 베이스가 같아야 함 | 각 파일의 소리 |
| concat 필터 | 예 | 스트림 수만 같으면 됨. 크기는 먼저 변환 | 각 세그먼트의 소리. 짧은 오디오는 무음으로 채움 |
| Sume Timeline 1.0 렌더 | 예, 현재 코드에서는 libx264로 | 아니요: 각 슬롯을 출력 크기 하나에 맞춤 | 렌더의 오디오 스파인과 사운드트랙만 |
Sume API로 영상을 이어 붙일 수 있나요?
네, 다만 재인코딩 방식으로만 가능합니다. Timeline 1.0 렌더는 video[] 슬롯 1–200개를 최대 1,800초 길이의 MP4 하나에 차례로 이어 놓고, fit(cover, contain, stretch, blur)으로 각 클립을 출력 크기 하나에 맞춥니다. 현재 코드에서는 항상 libx264로 영상을 재인코딩하며, 스트림 카피 모드는 없습니다. 전체 요청은 해상도가 다른 영상 두 개를 합치는 방법에서 볼 수 있습니다.
- 현재 코드에서 렌더의 소리는 오디오 스파인과 선택 사항인 사운드트랙에서만 나오고, 클립에서는 나오지 않습니다. 각 클립의 소리를 살리려면
POST /v1/audio-detach로 분리한 뒤, 그 파일들을 순서대로audio.parts[]에 최대 20개까지 넘기세요. - 모든 URL은 이전 Sume Job의 출력처럼 이미 워크스페이스에 있는
media.sume.com아티팩트나 에셋이어야 합니다. 이 규칙은 엔드포인트별로 받는 URL에서 설명합니다. 현재 코드에서는 300 MiB가 넘는 소스 파일이source_too_large로, 파일 크기 합계가 4 GiB를 넘는 렌더가download_budget_exceeded로 거부됩니다. - API 요금에는 렌더가 출력 분당 $0.10로 나와 있으며, 렌더는
ceil(audio.duration_seconds / 60)분을 예약하고 기본적으로 5.5% 에이전트 수수료가 더해집니다. 긴 영상을 이어 붙일 때는 롱폼 영상을 조립하는 방법을 참고하세요.
출처
관련 글
개발자 카테고리의 다른 글
- FFmpeg로 영상에서 오디오 추출하기: 복사, MP3, WAV
FFmpeg로 영상에서 오디오를 추출하려면 -vn으로 화면을 빼고, -c:a copy로 오디오를 그대로 두거나 인코더로 WAV나 MP3를 쓰세요.
- FFmpeg로 영상에서 프레임 추출하기: 한 장, 매초, 전체
FFmpeg로 프레임을 추출할 때 -frames:v 1은 이미지 한 장을, -r 1은 초당 한 장을 저장하고, 번호를 붙인 파일 패턴은 모든 프레임을 씁니다.
- FFmpeg height not divisible by 2 오류 원인과 해결
yuv420p 인코딩에 홀수 높이(또는 너비)가 들어갔다는 오류입니다. -2로 스케일하거나 trunc(ih/2)*2로 내림해 두 변을 짝수로 만드세요. Sume가 크기를 맞추는 방식도 다룹니다.
- HMAC과 디지털 서명의 차이: 웹훅에서 각각 무엇을 증명하나요?
HMAC은 송신자가 공유 시크릿을 가졌음을 증명합니다. 디지털 서명은 개인 키로 만들고 공개 키로 확인하며, 부인 방지까지 더합니다.
작성자 Sume