정리 :
ffmpeg는 영상 파일을 다루는 도구입니다. 워낙 유명하고 많이 쓰이는 프로그램이라 어도비를 제외한 거의 대부분의 인코딩 툴은 ffmpeg를 사용하기 쉽게 포장한 프로그램이라고 보셔도 됩니다.
저런 프로그램 대신에 ffmpeg를 직접 사용하시면 좀 더 세밀한 부분을 제어할 수 있습니다. 예를 들면 파일 2개를 합친다던지, 비디오는 복사하고 오디오만 인코딩 한다던지, 영상 파일에 자막을 끼워넣는다던지가 가능합니다. 또한 ffmpeg는 영상 뿐만 아니라 오디오 파일과 자막 파일도 제어할 수 있습니다.
참고로 아래 글에서 "명령어를 입력" 한다는 말은 명령어를 타이핑 하고 엔터까지 누르는 걸 뜻합니다.
2. 기초 사용법
이번에는 간단하게 mp4파일을 mkv파일로 변환하는 예시를 보여드리겠습니다.
ffmpeg의 명령은 <전역 인자> <인자> [파일명] <인자> [파일명] 순으로 이루어집니다. 모든 인자는 - (마이너스 기호)로 시작합니다. 그리고 파일명 앞에 -i를 붙이면 입력파일, 안붙이면 출력파일입니다.
예를 들어 Big Buck Bunny.mp4를 aaa.mkv로 변환한다면
ffmpeg -i "Big Buck Bunny.mp4" -c copy aaa.mkv
라고 명령어를 입력하시면 됩니다. "Big Buck Bunny.mp4" 는 파일이름에 공백이 들어있어서 따옴표로 둘러쌌고요, 그 앞에 -i 가 있으니 입력 파일로 인식됩니다. 그리고 -c copy는 인코딩을 하지 않고 단순 복사하라는 인자입니다. aaa.mkv는 -로 시작하지 않으니 파일명으로 인식되고, -i 가 없으니 출력 파일로 인식됩니다.
참고로 윈도우에서는 한글 파일 이름이 잘 인식되지 않을 수 있습니다. ffmpeg를 사용하기 전에 chcp 65001 명령어를 입력하시면 해결이 될수도 있습니다.
3. 인코딩을 하는법
ffmpeg의 인자 -c는 코덱을 지정하는 인자입니다. 위에서 사용한 copy도 일종의 코덱으로 취급받습니다. 코덱을 사용하지 않는 코덱 (?) 인 셈이죠. ffmpeg는 아주 다양한 코덱을 지원하는데요, 주로 사용하는 코덱은 영상 중에는 libx264, libx265, nvenc_h264 등이 있습니다. 오디오 코덱으로는 mp3, aac, libvorbis, libopus가 있습니다.
우선 오디오 인코딩 하는법부터 알려 드리겠습니다. aa.mp3를 bb.aac로 인코딩 하는 예제입니다.
ffmpeg -i aa.mp3 -c:a aac -b:a 160k bb.aac
-c 뒤에 :a 가 붙었는데요, 이 의미는 코덱을 지정하되, 오디오에만 지정하라는 의미입니다. 반대로 비디오 코덱을 지정하실때는 -c:v를 사용하시면 됩니다. 그리고 -b:a 옵션은 오디오 비트레이트 (품질)을 설정하는 옵션입니다. mp3의 경우에는 320k를, aac의 경우에는 160k 에서 192k 정도를 사용하시면 적당합니다. 참고로 별로 의미는 없지만 k를 쓰는 대신 192000이라고 입력하셔도 무방합니다.
다른 예시로 aa.mkv를 bb.mp4로 변환하는데 오디오는 aac로 인코딩하고 비디오는 복사하려면
ffmpeg -i aa.mkv -c:a aac -b:a 192k -c:v copy bb.mp4
입니다.
이어서 비디오를 인코딩 하는 방법입니다. 비디오도 위와 크게 다르지 않은데, 비디오는 코덱별로 옵션이 조금 차이가 납니다. 우선은 가장 많이 사용되는 H.264 코덱 libx264를 기준으로 설명 드리겠습니다.
aa.mp4 를 bb.webm으로 인코딩 하면서 비디오는 libx264로 인코딩하고 오디오는 복사하는 명령입니다.
ffmpeg -i aa.mp4 -c:a copy -c:v libx264 -crf 18 -preset veryfast bb.webm
이 명령에서 crf와 preset이 추가되었는데요, crf는 품질을 지정하는 인자이고, preset는 처리 속도를 지정하는 인자입니다. crf는 작을수록 파일 크기가 커지지만 품질이 향상됩니다. 대략 18정도면 원본과 거의 차이가 없는 수준이고, 필요에 따라 숫자를 늘리시면 됩니다. crf를 6 증가하면 용량이 절반이 되고, 6 감소하면 용량이 두배가 됩니다.
이어서 preset은 처리 속도를 지정하는데, 빠를수록 압축이 덜 됩니다. 만약 시간에 관계 없이 최대한 압축이 되기만 한다면 veryslow를 사용하고, 용량이 커지더라도 빨리 처리해야 한다면 veryfast를 쓰시면 됩니다. 기본값은 medium이고, help라고 치면 가능한 목록을 보여줍니다.
libx265도 위와 같은 방식으로 사용하시면 되는데, libx264에 비해 crf값을 4~5 정도 증가시켜서 사용하시면 비슷한 품질을 얻으실 수 있습니다.
아래 예시는 aa.mp4를 bb.mkv로 변환하되, 영상은 H.264 (libx264)로, 오디오는 aac로 인코딩 하는 예시입니다.
ffmpeg -i aa.mp4 -c:a aac -b:a 160k -c:v libx264 -crf 22 -preset veryfast bb.mkv
그리고 덤으로 아래 예시는 EUC-KR로 된 smi 자막을 srt 자막으로 변환하는 예시입니다.
ffmpeg -sub_charenc euc_kr -i a.smi -c:s srt b.srt
참고로 저는 플레이어 지원 여부를 확인해서 가급적이면 srt대신 ass자막을 사용하시는걸 권장드립니다.
4. 영상에 자막을 합치는 법
제가 이 글을 쓰기로 결심한 이유입니다. ㅎㅎㅎ
우선 자막을 합치는 방식에는 하드랑 소프트가 있습니다. 전자는 자막을 아예 영상에 포함시키는 방식이고, 후자는 자막 파일을 동영상 파일에 녹여넣는 방식입니다. 후자가 처리 속도도 빠르고 싱크도 조절할 수 있는 등 장점이 많지만 몇몇 플레이어가 지원하지 않는다는 단점이 있습니다. 그래도 제가 사용하는 프로그램들은 문제가 없어서 저는 후자를 주로 사용합니다.
소프트 방식부터 보여드리겠습니다.
ffmpeg -i aa.mp4 -sub_charenc euc_kr -i aa.smi -c:a copy -c:v copy -c:s ass bb.mkv
파일별로 끊어보면 "-i aa.mp4" 랑 "-sub_charenc euc_kr -i aa.smi" 랑 "-c:a copy -c:v copy -c:s ass bb.mkv "로 나눠집니다. 자세한 별도의 설명은 드리지 않겠습니다. 입력 파일이든 출력 파일이든 파일을 하나 지정할 때 마다 인자가 초기화된다는 점이랑 자막 끼워넣기는 mkv를 비롯해 소수의 포맷만 지원한다는 점만 아시면 될 것 같습니다. mp4도 mov_text를 통해 지원하기는 하는데, 플레이어 호환성이 그닥 좋지 못합니다.
이어서 하드 방식입니다. 이 방식은 영상을 수정하는 것이기 때문에 반드시 영상을 재 인코딩 해야합니다.
ffmpeg -i aa.mp4 -vf subtitles=aa.smi:charenc=euc_kr -c:a aac -b:a 160k -c:v libx265 -crf 24 -preset veryfast bb.mkv
charenc 부분은 자막 파일의 인코딩에 따라 수정해서 사용하시면 됩니다.
5. 하드웨어 가속을 사용하는법
이 내용은 엔비디아 그래픽 카드를 사용중이신 분에게만 해당됩니다. 인텔 내장그래픽을 사용하는것도 가능한데, 제가 써본적이 없어서 잘 모르겠습니다.
우선은 ffmpeg 의 바로 뒤에 -hwaccel cuda를 붙이셔야 합니다. 이 옵션이 없어도 작동은 하나, 성능상의 손해가 있을 수 있습니다.
디코딩을 가속하려면 우선 영상의 코덱을 아셔야 합니다. 그러려면 ffmpeg -i aa.mp4 처럼 출력 파일 없이 명령을 실행하면 오류가 뜨면서 영상 정보를 출력하는데, "Stream #0:1(eng): Video: vp9" 같은 부분을 유심히 보시면 됩니다. 이 영상은 코덱이 vp9네요. 흔히 쓰이는 코덱으로는 h264, h265, vp9, av1 등이 있습니다.
영상의 코덱을 아셨다면 디코딩을 가속하는건 간단합니다.
ffmpeg -hwaccel cuda -c:v vp9_cuvid aa.mp4 (후략)
처럼 입력 파일의 인자로 코덱을 지정해주시면 됩니다. 코덱 이름 뒤에 _cuvid를 붙이는 방식입니다.
다음으로 인코딩을 가속하는것도 쉽습니다.
ffmpeg -hwaccel cuda (중략) -c:v h264_nvenc -qp 22 bb.mp4
처럼 사용하시면 됩니다. 여기서 crf 대신 qp를 사용했고, preset은 생략했습니다. qp 옵션이 crf랑 비슷하기는 하지만 의미가 조금 다른 옵션이라서 몇 번 사용해보시며 자신에게 맞는 숫자를 찾으시면 되겠습니다.
마지막으로 하드웨어를 디코딩과 인코딩에 전부 사용하는 예시입니다.
ffmpeg -hwaccel cuda -c:v h265_cuvid -i aa.mp4 -c:a copy -c:v h264_nvenc -qp 22 bb.mp4
6. 마치며
더 많은 옵션이 궁금하다면 구글에서 ffmpeg wiki (원하는 내용) 으로 검색하셔서 ffmpeg 위키를 참고해주세요.
ffmpeg를 이용해 영상 인코딩 하는법 : 클리앙
https://www.clien.net/service/board/lecture/15601536
alias 설정
FFmpeg를 그냥 사용할 수도 있지만, 다음처럼 alias를 사용해서 공통 옵션을 설정해두면 조금 더 편리합니다.
alias ffmpegu='ffmpeg -hide_banner -loglevel info -stats -analyzeduration 10M -probesize 50M -user_agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.2 Safari/605.1.15" -allowed_extensions ALL -protocol_whitelist "file,http,https,tcp,tls,crypto" '
-hide_banner -loglevel info -stats는 실행할 때 나오는 FFmpeg 정보를 숨기고 로그 레벨은 info, 진행 상황 정보는 출력하겠다는 내용입니다. -loglevel warning이나 -loglevel error로 바꾸면 어떤 이상이 생겼을 때만 로그가 출력되어서 조금 더 화면이 깔끔해집니다.
-analyzeduration 10M -probesize 50M는 입력 파일을 분석할 버퍼를 설정하는 옵션입니다. 이 옵션을 사용하면 초반에 음성 트랙이 여러 개이거나 비디오 ID가 바뀌는 경우도 정상적으로 처리할 수 있게 됩니다.
-user_agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.2 Safari/605.1.15"는 마치 브라우저에서 보는 것처럼 유저 정보를 서버에 보내고 싶을 때 사용합니다. 가끔 이 정보를 확인하기도 하므로 미리 추가해 둡시다.
-allowed_extensions ALL -protocol_whitelist "file,http,https,tcp,tls,crypto"는 보안상 기본적으로 사용하지 못하게 하는 프로토콜이나 확장 기능을 사용할 수 있도록 하는 옵션입니다. 파일 목록으로 합치기 등등의 기능을 사용하려면 필요한 옵션입니다.
이 내용을 .zshrc나 .bashrc에 추가해 두면 앞으로 설명하는 명령어 예문에서 ffmpeg 대신에 ffmpegu를 사용하면 됩니다.
인코딩
아마도 FFmpeg를 사용하는 가장 주된 목적은 인코딩이겠지요. FFmpeg가 지원하는 인코딩 코덱은 ffmpeg -encoders로 확인 가능한데 그중에서도 요즘 자주 쓰이는 MP4로 인코딩하는 명령어 예를 가지고 살펴 봅시다. FFmpeg 옵션은 지정 순서가 무척 중요해서 순서를 잘못 지정하면 에러가 발생하기도 하니 주의해야 합니다.
# 입력 파일을 디인터페이스해서 1280x720 해상도인 mp4로 저장하기
ffmpeg -fflags +discardcorrupt -i '입력 파일' -vf "yadif=0:-1:0,scale=1280:720" -c:v libx264 -preset:v veryfast -crf 22 -movflags +faststart -c:a aac -b:a 160k '출력 파일.mp4'
-fflags +discardcorrupt는 입력 파일에 있는 깨진 패킷은 무시하겠다는 옵션입니다. 불안정한 인터넷 상태나 저장 실패 때문에 손상된 파일을 처리할 때 유용합니다. 이런 옵션은 FFmpeg 공식 도움말에서 확인 가능합니다.
-i '입력 파일'은 input을 지정하는 옵션입니다. 변환할 원본 파일 경로를 지정하면 됩니다.
-vf "yadif=0:-1:0,scale=1280:720" 이 옵션은 디인터레이스(yadif=0:-1:0), 해상도 변환(scale=1280:720)을 실시하는 video filter를 지정하는 부분입니다. 더욱 자세한 내용은 도움말 참조하세요.
-c:v libx264 -preset:v veryfast -crf 22는 libx264 인코더로 영상을 mpeg-4 코덱으로 인코딩하겠다는 옵션입니다. crf 22로 화질을 정하고(숫자가 작을수록 고화질, 고용량) preset:v veryfast으로 인코딩 시간과 압축 효율을 결정합니다. 경험상 veryfast가 일반적인 사용에 적당합니다.
-movflags +faststart는 MP4 영상의 크기, 재생 시간 같은 메타 정보가 든 moov atom을 파일 첫부분으로 옮겨서 스트리밍 등으로 볼 때 빠르게 재생할 수 있도록 만들어 주는 옵션입니다.
--c:a aac -b:a 160k 옵션은 음성 코덱 지정 부분으로 aac 코덱으로 인코딩한다는 의미입니다. 비트레이트로 160k를 지정했는데 보다 고음질을 원하면 256k 등을 지정하면 됩니다.
복잡해 보이지만 FFmpeg는 이렇게 영상 관련 옵션, 음성 관련 옵션을 조합해서 사용하는 것이 기본 방식입니다.
일부분 자르기
# 영상을 00:01:00~00:03:00(2분간) 잘라서 저장하기
ffmpeg -ss 00:01:00 -i "in.ts" -to 00:02:00 -c copy "cut.ts"
-ss 00:01:00은 영상 자르기 시작점을 지정하는 옵션입니다. ss 뒤에 오는 숫자는 시:분:초 형식입니다. 따라서 1분이 시작점이 됩니다.
-to 00:02:00은 시작점으로부터 얼마나 영상을 자를지 지정하는 옵션입니다. -to 뒤에 오는 시간은 영상 전체의 플레이 시간이 아니라 시작점으로부터 재생 시간(2분)이라는 점에 주의해야 합니다. 따라서 위 예제에서는 영상의 1분부터 3분 사이의 2분간(00:02:00)을 cut.ts라는 이름으로 저장하겠다는 뜻이 됩니다.
영상을 프레임 단위로 이미지 저장하기
# 초당 10 프레임 단위로 디인터페이스, 720 해상도로 변환한 jpg 파일 저장하기
FPS=10 ffmpeg -i "in.ts" -vf "yadif=0:-1:0,scale=1280:720,fps=${FPS}" -qscale:v 2 "thumb_%04d.jpg"
영상에 어떤 내용이 들어 있는지 빠르게 훑어 보고 싶거나 프레임 단위로 확인해 보고 싶을 때 유용한 명령어입니다.
-vf "yadif=0:-1:0,scale=1280:720,fps=${FPS}"에서 앞의 두 옵션은 인코딩 옵션 때 본 것과 같습니다. fps 옵션이 초당 몇 프레임을 추출할지 지정하는 값인데, 여기서는 환경변수 옵션 FPS에 10을 지정해서 사용했습니다. -vf "yadif=0:-1:0,scale=1280:720,fps=10" 처럼 직접 숫자를 지정할 수도 있지만 이렇게 상황에 따라 바뀔 수도 있는 값은 변수를 사용하는 것이 조금 더 편리합니다.
` -qscale:v 2`는 jpg 파일 화질을 지정하는 옵션입니다. 숫자가 클수록 화질이 떨어지는데 2~5 값을 추천합니다.
"thumb_%04d.jpg"는 출력할 파일명을 지정하는 옵션입니다. 추출한 프레임이 thumb_0001.jpg, thumb_0002.jpg, thumb_0003.jpg… 식으로 자동으로 번호순서대로 저장됩니다.
영상 파일 간편 합치기
ffmpeg -i "concat:in1.mp4|in2.mp4" -c copy "out.mp4"
재인코딩 없이 두 영상을 하나로 합쳐서 저장하는 명령어입니다. in1.mp4와 in2.mp4가 입력 파일, out.mp4가 출력 파일이 됩니다. 입력의 두 파일은 같은 해상도, 같은 코덱을 사용해야 합니다.
음성 파일에 섬네일을 지정해서 영상 파일 만들기
ffmpeg -loop 1 -i "thumb.jpg" -i "in.aac" -c:v libx264 -tune stillimage -acodec copy -pix_fmt yuv420p -shortest "out.mp4"
유튜브 등에 음성을 올릴 때 사용할 수 있는 방법입니다. thumb.jpg라는 이미지를 이용해서 in.aac 음성 파일이 재생이 끝날 때까지 같은 이미지가 계속 출력되는 mp4 영상 파일을 작성할 수 있습니다.
영상 회전하기
# 90도 회전
ffmpeg -i "in.mp4" -metadata:s:v "rotate=90" -c copy "out.mp4"
어쩌다 보니 옆으로 누워서 출력되는 영상을 회전시키고 싶을 때 사용하는 명령어입니다. 위 옵션을 사용하면 재인코딩 없이 90도 각도로 회전시킬 수 있습니다. 90에 회전시키고 싶은 각도 값을 지정하면 됩니다.
다른 영상과 음성을 합쳐서 새로운 파일로 저장하기
ffmpeg -stream_loop -1 -i "video.mp4" -i "audio.aac" -c copy -shortest -map 0:v:0 -map 1:a:0 -y "out.mp4"
기존에 존재하는 영상에 있는 음성을 좀 더 고음질 음성으로 교체하거나, 음성 출력 시간 동안 영상을 반복 재생하는 영상을 만들고 싶을 때 유용한 명령어입니다.
자막 파일을 내장하는 MP4 파일 만들기
ffmpeg -i "in.mp4" -i "sub.srt" -map 0:v:0 -c:v copy -map 0:a:0 -c:a copy -map 1 -c:s:0 mov_text -metadata:s:s:0 title=srt -metadata:s:s:0 language=kor "out.mp4"
-map 옵션은 여러 입력 파일이 있을 때 사용하는 옵션입니다. -map 입력 인덱스:스트림 종류:스트림 인덱스 형식으로 지정하는데 자세한 내용은 위키를 참조하기 바랍니다. 복잡하지만 익숙해지면 활용법이 무궁무진한 옵션입니다.
-map 0:v:0 -c:v copy -map 0:a:0 -c:a copy은 0번 입력 파일(in.mp4)에서 영상과 음성을 복사해서 0번 출력(out.mp4)으로 보낸다는 의미입니다.
-map 1 -c:s:0 mov_text -metadata:s:s:0 title=srt -metadata:s:s:0 language=kor은 1번 입력 파일(sub.srt)에서 자막을 복사해서 0번 출력(out.mp4)으로 보낸다는 의미입니다. FFmpeg는 srt 형식 자막을 지원합니다.
번외편: Nvidia 하드웨어 인코딩 사용하기
ffmpeg -y -hide_banner -analyzeduration 30M -probesize 100M -fflags +discardcorrupt -i "in.ts" -vf "yadif=0:-1:0,scale=1280:720" -map 0:v:0 -c:v h264_nvenc -preset:v fast -rc constqp -qp 29.5 -profile:v high -movflags +faststart -map 0:a:0 -c:a:0 aac -b:a:0 160k -metadata:s:a:0 title="Audio#1" "out.mp4"
맥에서는 더이상 사용할 수 없는 Nvidia이지만 윈도나 리눅스라면 이런 방식으로 하드웨어 인코딩을 사용할 수 있습니다. 하드웨어 인코딩은 CPU 인코딩에 비해 훨씬 빠르게 인코딩할 수 있는데 사용하는 그래픽 카드 성능에 따라 10배 이상 차이가 나기도 합니다. 훨씬 다양한 옵션이 존재하므로 자세한 내용은 검색해 보세요.
해당 인코더를 사용하려면 공식 홈페이지에서 배포하는 파일이 아니라 직접 빌드해서 사용해야 합니다.
자주 쓰는 FFmpeg 명령어들 - NuRi’s 몰라도 되는 개발 이야기
https://www.nuridol.net/command/ffmpeg/
댓글