La foret rouge
Published on

자주 쓰는 FFmpeg 명령어

Authors
  • avatar
    Name
    신주용

FFmpeg은 오디오와 비디오 등의 미디어를 다양하게 다룰 수 있는 솔루션입니다1. 영상을 녹화하거나, 변환할 수 있고, 특정 필터를 적용하거나, 자르고, 붙이고, 빨리감기 등등... 굉장히 할 수 있는 게 많죠. 하지만 기능이 많다는건 초보자가 사용하기 쉽지 않다는 뜻이기도 합니다.

그래서 이번 글에서는 제가 주로 사용하는 (1) 용량을 줄여 보관하거나 (2) README.md 등에 포함할 때 유용한 명령어를 소개합니다.

설치

일단 가장 먼저 설치입니다.

# macOS
brew install ffmpeg

# Ubuntu
sudo apt install ffmpeg

# Windows
choco install ffmpeg

참고로 여기서 Windows는 Chocolatey로 설치하는 방법을 적어뒀는데, 맥의 brew나 우분투의 apt, snap 같이 CLI 환경에서 편하게 설치할 수 있어서 좋습니다.

파일 정보 확인

hevc 같은 최신 코덱을 사용하면 보편적으로 쓰이는 같은 화질의 h264 영상에 비해 용량을 더 줄일 수 있다는 장점이 있습니다. 하지만 아직 충분히 보편화되지는 않아 호환이 안되는 환경이 존재한다는 단점이 있습니다. 아래와 같은 상황처럼요.

ffmpeg
ffmpeg

이 파일의 정보를 FFmpeg으로 확인해봅시다.

➜ ffmpeg -i input.mp4
# ...
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'input.mp4':
  # ...
  Duration: 00:00:13.10, start: 0.000000, bitrate: 9083 kb/s
  Stream #0:0[0x1](und): Video: hevc (Main) (hvc1 / 0x31637668), yuv420p(tv, bt709, progressive), 1920x1080, 9075 kb/s, 60 fps, 60 tbr, 15360 tbn (default)
  # ...
  • -i input.mp4: 입력 파일의 경로입니다. 다른 폴더에 있을 경우 상대 경로 또는 절대 경로 입력도 가능합니다.

Input > Stream #0:0을 보면 Video: hevc (Main) (hvc1 ...이라고 나옵니다.

인코딩

그러면 재생이 가능하도록 h264로 인코딩을 하기 전에 먼저 제 컴퓨터에서 사용 가능한 h264 인코더가 어떤 것이 있는지부터 봅시다.

➜ ffmpeg -h encoder=h264 | grep AVOptions
# ...
libx264 AVOptions:
libx264rgb AVOptions:
h264_videotoolbox AVOptions:

3개가 나왔는데, 이 중 libx264는 CPU를 사용하는 인코더이고, h264_videotoolbox는 mac의 GPU를 사용하는 인코더입니다. 만약 데스크탑에서 nvidia의 그래픽 카드를 사용하는 분이시면 h264_nvenc가 보일 것입니다. 각 인코더에서 사용 가능한 자세한 설정값을 알아보고 싶다면 인코더를 정확히 명시해주면 됩니다.

➜ ffmpeg -h encoder=libx264

그러면 이제 본격적으로 h264로 인코딩을 해봅시다. 사용할 명령어는 다음과 같습니다.

➜ ffmpeg -i input.mp4 -c:v libx264 -crf 0 output.mp4
  • -c:v libx264: codec:video를 나타냅니다. 위에서 인코더에 대해 얘기했는데, 여기서는 CPU를 사용하는 libx264를 사용했습니다.
    그래픽 카드는 없을 수도 있지만 CPU는 모든 컴퓨터에 다 있으니까요..!
  • -crf 0: 압축률을 설정하는 파라미터입니다. 0으로 하면 거의 원본에 가깝게 인코딩을 합니다.
    • ⚠️ 참고 ⚠️ 이런 옵션은 인코더마다 다를 수 있습니다. 어떤 인코더는 -crf 옵션을 사용할 수 없을 수도 있으니 위에서 설명한 것처럼 사용할 인코더에서 사용 가능한 자세한 설정값을 꼭 확인하세요.
  • output.mp4: 출력 파일 경로입니다.

용량 줄이기

위에서 압축률에 대한 얘기를 잠깐 했는데, 영상은 꽤나 용량이 큽니다. 초당 30장의 사진을 수 백, 수 천 초동안 재생하는 파일이니까요. 영화나 드라마를 제공하는 OTT 플랫폼에서는 고화질 영상이 중요하겠지만, 제 경우에는 그렇지 않습니다. 영상이 너무 고화질인 경우 어딘가에 제출을 해야될 때 용량 제한에 걸리거나, 프로젝트 발표 때 화상 회의 플랫폼을 통해 시연해야 하는 영상의 경우 대역폭 문제로 영상이 끊기듯 재생되는 문제도 있을 수 있기 때문입니다.

그래서 이런 경우에 영상의 용량을 줄이는데, (1) 비트레이트를 낮추거나 (2) 영상 크기를 리사이징하는 방법을 사용합니다.

리사이즈

인코딩 시 출력된 콘솔 로그입니다. Input/Output Stream을 보면 1920x1080 픽셀(우리가 흔히 말하는 FHD)으로 나옵니다.

➜ ffmpeg -i input.mp4 -c:v libx264 -crf 0 output.mp4
# ...
Output #0, mp4, to 'output.mp4':
  # ...
  Stream #0:0(und): Video: h264 (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1920x1080, q=2-31, 60 fps, 15360 tbn (default)

이를 1280x720(HD)으로 줄여봅시다.

➜ ffmpeg -i input.mp4 -c:v libx264 -crf 0 -vf "scale=-1:720" output.mp4
# ...
Output #0, mp4, to 'output.mp4':
  # ...
  Stream #0:0(und): Video: h264 (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1280x720, q=2-31, 60 fps, 15360 tbn (default)
  # ...

ls -alh *.mp4
Permissions Size User Date Modified Name
.rw-r--r--   15M refo  7 Apr 12:30   input.mp4
.rw-r--r--@ 7.0M refo  7 Apr 13:28   output.mp4
  • -vf "scale=-1:720": 비디오(v)에 필터(f)를 적용합니다.
    • scale 필터를 사용하고 너비(w):높이(h) 형식으로 파라미터를 입력합니다. 만약 둘 중 하나를 -1로 입력하면 원본 영상 비율에 맞게 자동으로 계산됩니다.

영상의 크기를 줄여서 용량도 15MB에서 7MB로 줄어든 것을 볼 수 있습니다.

비트레이트 낮추기

비트레이트(bit rate)란 초당 비트 전송률을 나타낸다고 하면 똑같이 어렵죠..ㅎ 쉽게 말하자면 1초당 용량입니다2. 아까 영상은 사진이 1초당 30장이 모여있는 파일이라고 했습니다. 사진 한 장 한 장의 용량이 줄어들면 전체 영상의 용량도 줄어들겠죠. 유튜브는 HD 영상의 비트레이트로 5Mbps를 권장합니다3. 하지만 제가 사용하는 용도에는 조금 더 낮춰도 괜찮았습니다.

이전 리사이징의 결과 파일 정보를 다시 봅시다.

➜ ffmpeg -i output.mp4
# ...
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'output.mp4':
  # ...
  Duration: 00:00:13.12, start: 0.000000, bitrate: 4243 kb/s

4,200kbps가 나오네요. 이 파일을 2,500kbps 수준으로 낮춰봅시다. 방법은 크게 두 가지가 있습니다.

압축률 설정

FFmpeg 문서를 보면 -crf 옵션을 사용해 화질을 조절할 수 있다고 나옵니다4. 위에서 사용했던 것처럼 0을 사용하면 거의 원본에 가깝고, 기본값은 23, 최악은 51이라고 하며, 0이 아니라 17이나 18 정도로만 사용해도 '눈으로 보기에 거의 손실이 없는' 수준이라고 합니다. 그러면 -crf 17로 한 번 비교해보겠습니다.

➜ ffmpeg -i output.mp4 -c:v libx264 -crf 17 output_crf17.mp4

-crf 17으로 하니 700Kbps 정도가 되는데, 2500Kbps 정도가 나오도록 값을 조금 수정해보죠.

➜ ffmpeg -i output.mp4 -c:v libx264 -crf 5 output_crf5.mp4

비트레이트 명시

위 경우처럼 의도한 비트레이트가 있다면 -crf 값을 바꿔가면서 하는게 아니라 -b:v 2500k와 같은 옵션을 사용할 수 있습니다.

➜ ffmpeg -i output.mp4 -c:v libx264 -b:v 2500k output_bv2500k.mp4

결과적으로 원본 input.mp4에서 리사이즈를 해서 용량을 절반 정도로 줄인 output.mp4를 만들었고, 거기서 비트레이트를 조절해서 output_bv2500k.mp4, output_crf3.mp4와 같이 또 절반 정도로 줄일 수 있었습니다.

ls -alh
Permissions Size User Date Modified Name
.rw-r--r--@  15M refo  7 Apr 12:30   input.mp4
.rw-r--r--@ 7.0M refo  7 Apr 14:37   output.mp4
.rw-r--r--  3.2M refo 13 Apr 10:14   output_bv2500k.mp4
.rw-r--r--@ 3.9M refo 13 Apr 09:55   output_crf3.mp4

영상 자르기

영상의 일부만 사용해야 될 때가 있습니다. 제 경우에는 프로젝트 README에 포함할 화면 녹화를 할 때 실제 동작을 보여주는 전후로 녹화 시작/종료 버튼을 누르러 마우스를 옮기는 과정이 몇 초 되지는 않지만 포함시키기는 별로여서 자르는 편입니다. 다음은 영상의 2초부터 11초까지 9초짜리로 자르는 예시입니다.

➜ ffmpeg -i output.mp4 -c:v libx264 -ss 00:00:02 -to 00:00:11 output_trim.mp4
  • -ss HH:MM:SS: 시작 시간입니다. 0초부터 이 시간까지의 영상이 잘립니다(사라집니다). 0초부터 사용할 때는 없어도 됩니다.
  • -t HH:MM:SS: 지속 시간입니다. 시작 시간부터 이 시간동안의 영상이 출력됩니다.
  • -to HH:MM:SS: 종료 시간입니다. 이 시간부터 영상 끝까지가 잘립니다. 영상 끝까지 사용할 때는 없어도 됩니다.

제 경우에는 -ss-to를 조합해서 주로 사용합니다.

➜ ffmpeg -i output.mp4
# ...
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'output.mp4':
  # ...
  Duration: 00:00:13.12, start: 0.000000, bitrate: 4243 kb/s
  # ...

➜ ffmpeg -i output_trim.mp4
# ...
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'output_trim.mp4':
  # ...
  Duration: 00:00:11.12, start: 0.000000, bitrate: 455 kb/s
  # ...

영상 이어붙이기

잘랐으면 이어붙이는 경우도 있겠죠? 9초짜리 영상과 3초짜리 영상을 이어붙여볼텐데 우선 두 개 파일의 정보를 확인해봅니다.

➜ ffmpeg -y -i concat1.mp4 -i concat2.mp4
# ...
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'concat1.mp4':
  # ...
  Duration: 00:00:09.00, start: 0.000000, bitrate: 864 kb/s
  # ...
Input #1, mov,mp4,m4a,3gp,3g2,mj2, from 'concat2.mp4':
  # ...
  Duration: 00:00:03.00, start: 0.000000, bitrate: 1206 kb/s
  # ...

그 다음은 합칠 파일명을 모아둔 list.txt 파일을 생성합니다. 위에서처럼 concat1.mp4, concat2.mp4와 같이 이름을 미리 바꿔뒀다면 간단히 명령어로 해결할 수 있고, 그렇지 않고 파일 개수가 많지 않다면 메모장으로 만드는게 더 빠를 수도 있습니다.

printf "file '%s'\n" concat*.mp4 > list.txt
cat list.txt
file 'concat1.mp4'
file 'concat2.mp4'

마지막으로 이 목록에 있는 여러 파일을 concat_out.mp4로 합치는 명령어입니다.

➜ ffmpeg -f concat -safe 0 -i list.txt -c copy concat_out.mp4
# ...
Input #0, concat, from 'list.txt':
  Duration: N/A, start: -0.021333, bitrate: 854 kb/s
  # ...
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
  Stream #0:1 -> #0:1 (copy)
Output #0, mp4, to 'concat_out.mp4':
  # ...
size=    1392KiB time=00:00:12.02 bitrate= 948.6kbits/s speed=1.23e+03x

결과적으로 9초와 3초짜리 영상 두 개를 합쳐 12초짜리 concat_out.mp4를 생성하였습니다.

영상 빨리감기

영상 재생이 너무 느려 조금 빨리 재생해야 할 때가 있을 수도 있습니다. 영상을 2배속으로 재생하는 명령은 다음과 같습니다.

➜ ffmpeg -i output.mp4 -c:v libx264 \
  -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" \
  -map "[v]" -map "[a]" \
  output_ff.mp4

재생시간이 절반이 된 것을 확인할 수 있습니다.

➜ ffmpeg -i output.mp4
# ...
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'output.mp4':
  # ...
  Duration: 00:00:13.12, start: 0.000000, bitrate: 4243 kb/s
  # ...

➜ ffmpeg -i output_ff.mp4
# ...
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'output_ff.mp4':
  # ...
  Duration: 00:00:06.60, start: 0.000000, bitrate: 415 kb/s
  # ...

GIF 만들기

영상을 사용해 GIF 파일을 만들 수 있습니다. 영상 자르기를 설명할 때 README에 포함한다고 했는데 보통 README에는 영상을 포함하기보다는 GIF 파일을 포함하는 편이고, 이 때 빨리감기도 주로 같이 사용하는 편입니다.

➜ ffmpeg -i output_ff.mp4 -r 15 -loop 0 output.gif
  • -r 15: 초당 프레임 수입니다. GIF에서는 이 숫자가 높아질수록 원본 영상(30fps)처럼 부드러워 보이지만, 영상보다 용량이 더 커질 수도 있습니다.
  • -loop 0: 무한 반복합니다.
ffmpeg

Footnotes

  1. FFmpeg. "ffmpeg Documentation." ffmpeg.org. https://ffmpeg.org/ffmpeg.html (accessed Apr. 07, 2024).

  2. Wikipedia. "Bit rate." Wikipedia. https://en.wikipedia.org/wiki/Bit_rate (accessed Apr. 07, 2024).

  3. YouTube. "YouTube 권장 업로드 인코딩 설정." YouTube 고객센터. https://support.google.com/youtube/answer/1722171?hl=ko#zippy=%2C비트-전송률 (accessed Apr. 07, 2024).

  4. FFmpeg. "H.264 Video Encoding Guide." ffmpeg.org. https://trac.ffmpeg.org/wiki/Encode/H.264#a1.ChooseaCRFvalue (accessed Apr. 07, 2024).