FFmpeg 사용법 및 하드웨어 가속 [NVIDIA CUDA, Intel 퀵싱크(quicksync)]
필자가 운영하는 VOD서비스 'TV다시 보기'는 그동안 SD채널을 받아서 녹화, 480p.ts로 저장된다. UHD시대에 SD라니 이 글을 보는 분 중에는 의아하게 생각할 지도 모르겠다. 여러가지 이유가 있지만 그동안 SD로 저장할 수밖에 없었던 이유는 동 시간대의 방송되는 여러 TV프로그램을 각각 동시에 녹화,(많은 때는 7~8개의 TV프로가 녹화된다.) HD로 저장 하기에는 스토로지 용량 문제와 이에 따른 데이터 처리에 필자가 운영하는 하드웨어로는 처리하기가 버거울 거란 판단 이었다.
필자의 PVR(녹화)서버의 하드웨어 사양
CPU : Intel Q8400(코어™2 쿼드 프로세서)
GPU : NVIDIA GTX 660
스토리지 : 4TBx4
운영체제 : 리눅스 우분투 18.04 LTS
운영소프트웨어 : TVheadend, PLEX Server
실제 FFmpeg를 사용, 1080p.ts 동영상을 인코딩(encoding)을 안 해본 것은 아니다. 하지만 CPU점유율을 100% 풀가동해도 느려터진 인코딩 속도로 좌절하기 일쑤였다.(1시간 짜리 동영상을 엔코딩 하는데 3~4시간이 걸렸다. OTL) 하드웨어 가속을 알기 전까지는.. 헤헷
그러던 중 얼마 전에 하드디스크 하나가 사망하였다. 하필 TV프로그램을 녹화를 받아 저장하는 주 디스크였으므로 반년 가까이 녹화 됐든 모든 데이터가 한순간에 증발 되었다. 다행히 무상 A/S기간이라 하드 디스크는 교체 받으면 되지만 자료들의 복구는 불가능했다. 백업의 중요성은 알고 있지만 상대적으로 용량이 큰 동영상은 백업하기가 그리 만만치 않고 그에 따른 비용도 많이 든다. 앞으로도 백업 시스템에 대한 도입은 생각은 없다.
서론이 너무 길었나요? 어떤 사연이 있어 FFmepg의 하드웨어 가속을 이용한 인코딩을 고려하게 되었는지 이해를 돕기위해서 필자가 현재 처한 상황을 잠시 설명 드렸습니다. 각설하고 오늘의 주제인 하드웨어 가속을 사용한 FFmpeg 사용법에 대해 알아 보겠습니다.
필자의 구닥다리 시스템에서도 동시에 4~5개의 TV프로그램을 동시에 HD로 녹화하기에는 무리는 없습니다. 하지만 원본 소스 그대로 녹화가 되기 때문에 용량이 장난이 아닙니다. 보통 1시간 기준으로 7~8 기가바이트를 차지합니다. 이 정도의 용량 증가 속도라면 스토리지를 도입에 비용이 많이 발생되며 그것도 무한대로 늘리 수 있는 것도 아닙니다. 그래서 약간의 절충이 필요합니다. 인코딩을 통해 동영상의 용량을 줄이는 것이지요. 물론 데이터 압축에 따른 화질 손상이 있지만 이것도 적절하게 타협하면 크게 나쁘지 않은 화질로 다이어트한 용량으로 저장이 가능합니다.
기본 FFmpeg 사용법(명령어)
ffmpge '입력 옵션' '입력 파일' '출력 옵션' '출력 파일'
입력 옵션
- 입력 파일 지정 : -i input.ts
- 형식 강제 지정 : -f mkv
ex) ffmpeg -i input.ts -c:v libx264 output.mkv
소프트웨어 인코딩 코덱
-c:v libx264 (H.264)
-c:v libx265 (H.265, HEVC)
위 출력 옵션인 -vcodec libx264는 소프트웨어 방식입니다. 즉, cpu연산에만 의존해서 엔코딩을 진행하기 때문에 시스템에 부하가 많이 걸립니다. 물론 쓰레드 및 프로파일 옵션 등으로 약간의 조절은 할 수 있으나 크게 의미가 없다는게 필자의 결론 입니다. 시간도 엄청 걸리고요. 동시에 3~4개의 동영상을 처리한다건 필자의 시스템에서는 상상도 할 수 없는 일 입니다.
NVIDIA 하드웨어 가속을 이용하자
NVIDIA 그래픽 카드를 가지고 있는 PC에서는 FFmpeg 하드웨어 가속을 이용해서 인코딩이 가능합니다. 낮은 CPU점유율과 많게는 15배 에서 2배까지 시간을 단축하여 인코딩이 가능합니다. CPU점유율을 적게 사용하니 동시에 여러 개의 동영상도 처리 가능하겠죠. 하지만 필자의 리눅스 시스템에서는 최대 동시 입력 가능한 숫자는 2여였습니다. 즉, 하드웨어 가속을 사용해서 2개의 동영상을 동시에 처리 가능합니다. 왜 2개 밖에 되지 않는지 정확한 이유는 모르겠으나 이게 어딥니까??
ex) ffmpeg -hwaccel cuvid -c:v h264_cuvid -i input.ts -c:v h264_nvenc -b:v 3600k -acodec ac3 -b:a 192k output.mkv
옵션 설명 : FFmepg 하드웨어 가속을 사용하고 입력은 h264_cuvid, 출력은 h264_nvenc 코덱을 쓰며 bitrate는 비디오 3600k, 오디오 ac3코덱 사용 192k로 인코딩을 한다.
NVIDIA GPU 가속
입력 옵션
-hwaccel cuvid -c:v h264_cuvid (H.264)
-hwaccel cuvid -c:v hevc_cuvid (H.265, HEVC)
출력 옵션 (인코딩 코덱)
-c:v h264_nvenc (H.264)
-c:v hevc_nvenc (H.265, HEVC)
bitrate 설정
-b:v 3600k (비디오) bitrate는 아래 품질 옵션과 함께 인코딩 하는데 있어 가장 중요한 옵션인데요. FHD 방송의 원본 화질의 bitrate는 10000k 전후입니다. 저는 용량 문제 때문에 3600k 정도 주는데 화질 손상을 최소화 하려면 6000k정도가 적당합니다. 참고로 아래 품질 옵션(-qp)과 같이 써봤는데 이럴 경우 원본보다 용량이 더 많아지는 경우도 있더군요. 둘 중 하나만 쓰는게 맞는것 같습니다. 그리고 여러가지 테스트를 해본 바 쇼 프로, 스포츠, 다큐 등 영상이 비교적 변화가 많고 동적인 방송 원본(ts)은 bitrate 옵션을 사용하는게 유리하고 반대로 드라마, 시사, 교양 등 영상이 정적인 방송을 인코딩 할때는 아래 품질 옵션으로 조절하는 것이 여러모로 이득이 많습니다.
-b:a 192k (오디오) 일반적으로 오디오는 동영상에 비해 차지하는 용량이 작음으로 -acodec copy 옵션으로 인코딩 없이 그대로 복사하는 경우가 많습니다. 하지만 조금이라도 용량을 줄이려면 코덱(ac, aac 등)과 함께 bitate 옵션을 줄 수도 있습니다.
퀄리티 (quantizer scale), 품질 옵션
ex) ffmpeg -hwaccel cuvid -c:v h264_cuvid -i input.ts -c:v h264_nvenc -qp 30 -acodec copy output.mkv
-qp quantization parameter , -1 ~ 51 , 기본 -1 (숫자가 높을수록 압축률은 좋지만 화질이 떨어짐)
-cq constant quality mode in VBR rate , 0~51, 기본 0 , h264_nvenc 용
-crf constant quality mode ,-1 ~ FLT_MAX(float최대), 기본 -1 , libx264 용
framerate 설정(fps)
-r 29 (초당 29프레임)
크기 조정 옵션
-s 1280x720 또는 -s hd720
FFmpeg를 통한 NVIDIA GPU 하드웨어 가속 인코딩은 이 정도의 옵션만 알고 있으면 무난히 사용할 수 있다.
Intel(인텔) Quicksync(퀵싱크)를 이용하자
인텔 CPU에도 GPU가 포함되어 있습니다. 최근 2~3년 내 출시된 인텔 CPU를 사용하고 있다면 퀵싱크를 지원하는 CPU일 것입니다. 흔히 내장 그래픽으로 불리기도 하지요. 아래는 인텔CPU에서 하드웨어 가속으로 인코딩하는 명령어의 예 입니다.
ex) ffmpeg -i input.ts -c:v h264_qsv -preset veryfast -acodec copy -b:v 6000k output.mkv
사용 방법은 NVIDIA와 많이 다르지 않습니다. -acodec copy는 오디오 인코딩 없이 그대로 사용하겠다는 옵션입니다. 하드웨어 가속을 지원하는 인텔 코덱은 다음과 같습니다.
h264_qsv, hevc_qsv, mpeg2_qsv, vc1_qsv 등
-preset (기본값 medium, 1단계 부터 7단계로 나뉜다)
veryfast, faster, fast, medium, slow, slower, veryslow 순, 빠를수록 압축률이 낮아 용량이 커짐
이런 명령어도 있습니다.
ffmpeg -y -rtbufsize 100M -f gdigrab -framerate 30 -probesize 10M -draw_mouse 1 -i desktop -c:v h264_qsv -r 30 -preset veryfast -tune zerolatency -crf 25 -pix_fmt yuv420p "output.mkv"
입력 옵션 (윈도우 화면 캡처)
-f gdigrab : FFMPEG에서 지원하는 윈도우 화면 캡처 장치
-i desktop : 화면 전체 캡처 (desktop 대신 title=windows_title 입력시 특정 윈도우만 캡처 가능)
예) -i title="Windows PowerShell" : Windows PowerShell 창 만 캡처
-framerate 30 : 입력 프레임 수 30fps
-draw_mouse 1 : 마우스 포함 녹화 (0으로 하면 마우스 표시 안됨)
출력 옵션
-c:v h264_qsv : 인텔 퀵싱크 h.264 코덱 사용
-r 30 : 녹화 프레임 수 (30fps)
-preset ultrafast : 속도를 최대로 (대신 압축률이 낮아 용량이 커짐)
-tune zerolatency : 지연시간 최소
-crf 25 : 영상 손실 값 (기본 23, 0 ~ 51, 0에 가까우면 무손실, 51에 가까우면 손실)
-pix_fmt yuv420p : 이미지 포맷 YUV420
이상으로 FFmepg를 이용한 하드웨어 가속 인코딩이었습니다.
참고. FFmpeg를 이용한 동영상 자르기
ex) ffmpeg -i input.avi -ss 600 -t 120 -vcodec copy -acodec copy clip.avi
-ss 10분(600초)부터 부분파일을 시작
-t 2분간(120초) 해당하는 부분 선택
10분짜리 avi파일을 반절로 나눌때
ffmpeg -i input.avi -vcodec copy -acodec copy -t 300 before.avi
-t 300(초) 5분 까지라는 뜻으로 시작점이 지정되지 않았기 때문에 처음부터 5분 까지 이다.
ffmpeg -i input.avi -vcodec copy -acodec copy -ss 300 after.avi
-ss 300(초) 5분 부터라는 뜻으로, 끝부분이 지정되지 않았기 때문에 5분부터 끝까지 이다.
참고. FFmpeg를 이용한 동영상 합치기
합칠 동영상의 리스트를 텍스트 파일로 만든다.
$ cat > list.txt
file a.mkv
file b.mkv
$ ffmpeg -f concat -i list.txt -c copy output.mkv
참고로 입력 파일 이름이 한글일 경우 메모리 오버플로우(overflow) 나고 무한 루푸에 빠질 수도 있다.(어제 경험 했음, 필자 시스템만 그럴 수도..) 그러니 영문으로 바꾸고 합쳐라. 출력 파일은 한글로 해도 이상 없었음, 이상 입니다.
댓글