1.시스템&인프라/스트리밍

[FFmpeg] 인코딩 실습: CPU(libx264)와 CUDA(h264_nvenc) 비교

쿼드큐브 2025. 11. 5. 16:46
반응형
반응형

[FFmpeg] 인코딩 실습: CPU(libx264)와 CUDA(h264_nvenc) 비교

 

📚 목차
1. libx264(CPU) 기반 트랜스코딩 실습
2. h264_nvenc(CUDA) 기반 트랜스코딩 실습
3. CPU(libx264)와 GPU(h264_nvenc) preset 비교
✔ 마무리 - 실시간 인코딩 전략

 

실시간 RTSP 스트림을 초저지연 환경에서 다른 장치로 송출하려면 인코딩 지연 최소화가 핵심입니다.

하지만 인코딩 방식에 따라 시스템 부하와 지연 시간이 크게 달라집니다.

libx264 (CPU 기반):

▸ 별도 하드웨어 없이 누구나 쉽게 실행 가능.

▸ 하지만 고화질·다중 스트림에서는 CPU 부하가 폭증.

 

h264_nvenc (GPU 기반):

▸ NVIDIA GPU를 활용한 하드웨어 인코딩. 초저지연·저부하 환경에 최적화.


이 글에서는 동일한 RTSP 입력에 대해 CPU와 CUDA 인코딩을 각각 실습하고, 성능·지연·시스템 부하 비교를 통해 어떤 상황에서 어떤 선택이 최적인지 확인합니다.

 

CPU와 CUDA 인코딩 개념
CPU와 CUDA 인코딩 개념

1. libx264 (CPU) 기반 트랜스코딩 실습

FFmpeg에서 가장 널리 사용되는 소프트웨어 기반 인코더는 바로 libx264입니다.

이 인코더는 별도의 GPU 없이도 CPU만으로 안정적인 H.264 인코딩을 수행할 수 있다는 장점이 있습니다. 특히 초기 개발 단계나 테스트 환경에서는 “추가 장비 없이도 바로 실행 가능하다”는 점에서 매우 유용합니다.

 

🔷 명령어 예제 (CPU 인코딩)

▸ 아래는 RTSP 스트림을 입력받아 CPU 기반 libx264 인코딩 → fMP4 컨테이너 변환 → TCP 포트 송출 과정을 구성한 예시 명령어입니다.

ffmpeg -hide_banner \
-rtsp_transport tcp -fflags nobuffer -flags low_delay \
-i rtsp://xxxxxxxxxxx \
-an -c:v libx264 -preset ultrafast -tune zerolatency -pix_fmt yuv420p \
-g 30 -sc_threshold 0 \
-crf 23 \
-f mp4 -movflags frag_keyframe+empty_moov+default_base_moof \
tcp://127.0.0.1:9000

#파이프 예시
#pipe:1 | \
#ffplay -hide_banner -fflags nobuffer -flags low_delay -f mp4 -i -

 

다음은 예시 명령어에 사용된 옵션에 대한 상세 설명입니다.

옵션 설명
-hide_banner FFmpeg 실행 시 불필요한 라이브러리/환경 정보 숨김
-rtsp_transport tcp RTSP 수신 시 TCP 사용 (UDP보다 안정적)
-fflags nobuffer 디코딩 시 내부 버퍼 제거 → 지연 최소화
-flags low_delay 인코딩 시 low delay 모드 적용
-c:v libx264 CPU 기반 H.264 인코딩 수행
-preset ultrafast 인코딩 속도 최우선, 압축 효율은 낮음
-tune zerolatency 초저지연 모드, B-프레임 제거 & 버퍼 최소화
-pix_fmt yuv420p 가장 호환성 높은 픽셀 포맷 (웹 브라우저, ffplay 등과 호환)
-g 30 GOP 크기를 30 프레임으로 고정 (약 1초 단위)
-sc_threshold 0 씬 전환 시 강제 키프레임 방지 → 일정한 GOP 유지
-crf 23 품질 기반 인코딩 (값이 낮을수록 화질↑, 파일 크기↑)
-f mp4 MP4 컨테이너 사용 (실시간 송출을 위해 fMP4 구조 적용)
-movflags frag_keyframe+empty_moov+default_base_moof MP4를 실시간 스트림 형태로 구성

 

🔷 실습 포인트

🔸 CPU 전용 인코딩 환경 구성
▸ 별도 GPU가 없어도 CPU만으로 RTSP 입력을 인코딩해 즉시 송출할 수 있습니다.
▸ 테스트, PoC(Proof of Concept), 소규모 장비에서 유용합니다.

🔸 초저지연 환경 최적화
▸ -preset ultrafast와 -tune zerolatency 조합으로 내부 버퍼를 최소화하고 B-프레임을 제거하여 지연을 크게 줄였습니다.
▸ -g 30과 -sc_threshold 0 설정을 통해 GOP 구조를 일정하게 유지하여 실시간 송출에서 안정성을 높였습니다.

 

🔸 호환성 강화
▸ -pix_fmt yuv420p는 대부분의 플레이어와 브라우저가 지원하는 표준 포맷입니다.
▸ fMP4 구조(movflags)를 적용해 네트워크 송출에 최적화된 스트림을 만들 수 있습니다.

 

🔸 재생 파이프라인 통합
▸ 출력(pipe:1)을 곧바로 ffplay로 넘겨주어, 별도 파일 저장 과정 없이 바로 화면에서 확인 가능합니다.
▸ 실제 서비스 전에는 송출 파이프라인을 서버 모듈이나 소켓 출력으로 교체하면 됩니다.

 

🔷 실행 결과 예시 (CPU 인코딩)

✔️ ffmpeg h264 트랜스코딩 로그

FFmpeg h264 트랜스코딩 로그
FFmpeg h264 트랜스코딩 로그

 

▸ fps는 출력 영상의 처리 프레임레이트를 의미하며, 입력 소스의 fps와 거의 동일하다면 인코딩 성능이 충분하다는 의미입니다.
▸ speed는 인코딩 처리 효율을 나타내며, 1.0x 이상이면 실시간 인코딩이 가능하고, 1.0 미만으로 떨어지면 프레임 드롭이나 버퍼링이 발생할 수 있습니다.

 

현재 로그를 보면

▸ fps가 입력과 동일한 약 15fps 근처에서 안정적으로 유지되고 있으며,
▸ speed도 1.02x로 실시간보다 약간 여유 있게 동작하고 있습니다.
결론적으로, CPU(libx264) 인코딩이 실시간 속도를 맞추면서 여유 있게 동작하고 있음을 확인할 수 있습니다.

 

✔️ ffplay fMP4 수신 로그

ffplay fmp4 수신 로그 화면
ffplay fmp4 수신 로그 화면

 

▸ 입력 컨테이너가 mov/mp4로 인식되었고, 이는 -movflags frag_keyframe+empty_moov+default_base_moof 옵션을 통해 송출된 fMP4 스트림을 정상적으로 수신하고 있다는 의미입니다.
▸ major_brand: iso5로 표시된 부분은 ISO 기반 fragmented MP4(fMP4) 프로파일임을 나타냅니다.
▸ 일반 MP4 파일은 전체 Duration이 고정되지만, 여기서는 Duration: 2초로만 잡히고 이후 조각 단위로 이어집니다.

→ 이는 fMP4의 특성으로, 실시간 프래그먼트 단위 전송이 이루어지고 있음을 보여줍니다.

 

✔️ CPU 사용율 예시

CPU 사용률 예시
CPU 사용률 예시

2. h264_nvenc (CUDA) 기반 트랜스코딩 실습

CPU 기반 libx264 인코딩은 빠르게 테스트하기엔 적합하지만, 1080p 이상의 고화질 스트림이나 다중 스트림 처리 상황에서는 금세 CPU 부하가 한계에 도달합니다. 이런 경우 NVIDIA GPU의 하드웨어 인코딩(h264_nvenc)을 활용하면, 낮은 지연·낮은 부하·높은 안정성을 동시에 확보할 수 있습니다.


특히 브라우저 환경에서 MSE(Media Source Extensions)를 통해 직접 영상을 재생하려면, fMP4(Fragmented MP4) 포맷과 적절한 키프레임 구조가 필요합니다. FFmpeg의 h264_nvenc는 이런 요구에 최적화된 옵션을 제공합니다.

 

🔷 CUDA 기반 인코딩 명령어 (브라우저 MSE 대응)

▸ RTSP 입력 → GPU로 디코딩 + 인코딩 → fMP4 → TCP로 실시간 전송

ffmpeg -hide_banner \
-hwaccel cuda -hwaccel_output_format cuda \
-rtsp_transport tcp -fflags nobuffer -flags low_delay \
-i rtsp://10.1.73.227/ONVIF/MediaInput?profile=1_def_profile1 \
-an -vf "scale_cuda=format=yuv420p" \
-c:v h264_nvenc -preset p1 -tune ull -g 30 \
-b:v 4M -maxrate 4M -bufsize 4M \
-f mp4 -movflags frag_keyframe+empty_moov+default_base_moof \
tcp://127.0.0.1:9000

# Pipe 예시
#pipe:1 | \
#ffplay -hide_banner -fflags nobuffer -flags low_delay -f mp4 -i -

 

다음은 예시 명령어에 사용된 옵션에 대한 상세 설명입니다.

 

옵션 설명
-hide_banner 불필요한 FFmpeg 빌드 정보 배너를 출력하지 않음
-hwaccel cuda 입력 스트림을 GPU에서 직접 디코딩
-hwaccel_output_format cuda 디코딩된 프레임을 GPU 메모리에 유지 (zero-copy 인코딩)
-rtsp_transport tcp RTSP 전송 시 TCP를 사용해 안정성 강화
-fflags nobuffer / -flags low_delay 내부 버퍼를 최소화해 인코딩 지연을 줄임
-an 오디오 스트림 제외
-vf "scale_cuda=format=yuv420p" GPU에서 색공간 변환 및 스케일 처리 (출력 호환성을 위해 YUV420p 고정)
-c:v h264_nvenc NVIDIA 하드웨어 인코더 사용
-preset p1 가장 빠른 인코딩 프리셋 (속도 최우선)
-tune ull Ultra Low Latency 모드 (B-frame 제거, 버퍼 최소화)
-g 30 GOP 크기 지정 (30fps 기준 약 1초마다 키프레임 생성)
-b:v 4M 목표 비트레이트 설정 (4 Mbps)
-maxrate 4M 인코딩 시 최대 비트레이트 제한
-bufsize 4M 비트레이트 버퍼 크기 설정 (CBR-like 동작)
-f mp4 MP4 컨테이너 사용
-movflags frag_keyframe+empty_moov+default_base_moof 실시간 스트리밍에 적합한 fMP4 구조 생성
tcp://127.0.0.1:9000 TCP 소켓으로 출력 (수신 애플리케이션과 연결)

 

🔷 실습 포인트

1. zero-copy 인코딩
▸ -hwaccel cuda + -hwaccel_output_format cuda를 조합하면, 프레임이 CPU 메모리로 복사되지 않고 GPU 내부에서 바로 처리됩니다.
▸ 이 구조는 성능 저하와 지연을 줄이는 핵심입니다.

 

2. GPU 필터 체인 활용
▸ -vf "scale_cuda=format=yuv420p" 옵션은 필수적인 색공간 변환을 GPU에서 직접 처리합니다.
▸ 이후 scale_cuda, transpose_cuda 같은 다른 필터도 GPU에서 연속적으로 적용 가능해, 전체 파이프라인이 GPU 내부에서 완결됩니다.


3. 비트레이트 제어

▸-b:v, -maxrate, -bufsize 조합은 네트워크 대역폭을 일정하게 유지하는 데 중요합니다.
▸ 특히 다중 스트림을 운영할 때는 각 스트림의 비트레이트를 엄격히 제한해 전체 네트워크 대역폭을 관리해야 합니다.


4. 실시간 스트리밍 구조
▸ frag_keyframe+empty_moov+default_base_moof 옵션은 fMP4 스트림을 실시간으로 전송할 수 있게 해 줍니다.

▸덕분에 브라우저 MSE(Media Source Extensions)나 TCP 수신 서버에서 안정적으로 재생할 수 있습니다.

 

🔷 실무 적용 팁

▸ GPU 모니터링: nvidia-smi 명령어로 GPU 사용률과 인코딩 세션 상태를 항상 확인하세요.
▸ 다중 스트림 운영: 여러 카메라 스트림을 동시에 처리할 경우, 프로세스 단위로 분리하거나 -gpu 옵션으로 GPU 리소스를 분산시켜야 합니다.
▸ 에러 대응: RTSP 연결 오류가 잦다면 -stimeout 5000000 또는 -max_delay 500000 같은 옵션을 추가해 안정성을 보강할 수 있습니다.

 

🔷 실행 결과 예시 (CPU 인코딩)

✔️ ffmpeg h264_nvenc 트랜스코딩 로그

ffmpeg h264_nvenc 트랜스코딩 로그
ffmpeg h264_nvenc 트랜스코딩 로그

이 FFmpeg 실행 결과는 GPU 디코딩 + NVENC 인코딩 파이프라인이 정상 동작하며, 설정한 4Mbps 비트레이트에 안정적으로 수렴하고 있습니다. 출력 속도도 실시간(1x) 으로 유지되어 인코딩 성능에는 문제가 없습니다.


다만 로그에 보이는 drop=2341은 인코더 과부하가 아니라 입력 스트림의 실제 fps(≈15)와 컨테이너 메타데이터(30fps)의 불일치 때문에 발생한 동기화 보정 값입니다. 따라서 -vsync 0 또는 -fps_mode passthrough 같은 옵션을 주거나 -r 15 -g 15로 fps를 명시하면 불필요한 드롭을 줄이고 더 안정적인 결과를 얻을 수 있습니다.

 

✔️ ffplay fMP4 수신 로그

ffplay fMP4 수신 로그
ffplay fMP4 수신 로그

TCP로 수신한 fMP4 스트림이 정상적으로 열렸으며, 해상도 1280x960 / 약 15fps / 비트레이트 약 3.7Mbps의 H.264(Main) 영상으로 인코딩 되어 재생되고 있습니다. 인코더는 h264_nvenc로 기록되어 있어 GPU 기반 인코딩 결과가 맞게 전달된 상태입니다.

로그에 보이는 [swscaler ... deprecated pixel format used] 메시지는 색공간(YUV → YUVJ) 변환 과정에서 나오는 단순 경고이며, 재생에는 큰 문제가 없습니다.

 

✔️ GPU 사용률 예시

GPU 사용률 예시
GPU 사용률 예시

3. CPU(libx264)와 GPU(h264_nvenc) preset 비교

한두 개의 RTSP 스트림은 CPU로도 처리할 수 있습니다. 하지만 고해상도 CCTV 영상이 3개 이상만 붙어도 CPU는 금방 한계에 도달합니다.

이럴 때는 GPU 기반 인코딩이 현실적인 해법입니다.

특히 NVIDIA GPU를 사용하는 h264_nvenc 인코더는 낮은 지연 + 낮은 부하라는 이상적인 조건을 만족하며, 병렬 처리에도 매우 유리합니다.

 

🔷 libx264 (CPU 기반) preset

libx264는 ultrafast부터 veryslow까지 약 10단계의 프리셋을 제공합니다.
이 프리셋은 단순히 화질을 바꾸는 옵션이 아니라, 인코딩 속도와 압축 효율(화질·비트레이트)의 균형을 조절하는 핵심 요소입니다.

🔸빠른 preset(예: ultrafast)은 CPU 연산을 단순화하기 때문에 인코딩 속도는 매우 빠르지만, 그만큼 압축 효율이 떨어져 같은 비트레이트에서도 화질이 낮아질 수 있습니다.


🔸반대로 느린 preset(예: slow, veryslow)은 더 정교한 알고리즘을 사용해 같은 비트레이트에서 더 좋은 화질을 얻을 수 있지만, 그만큼 인코딩 속도는 느려집니다.

 

✔️ 자주 쓰이는 preset과 특징

preset 값 특징
ultrafast 인코딩 속도 최우선. 화질과 압축 효율은 낮음
superfast / veryfast 속도를 중시한 실시간 스트리밍에 적합
medium 기본값. 속도와 화질의 균형이 가장 무난
slow / slower / veryslow 인코딩 속도는 느리지만 고화질·고효율 압축 가능

▸ 실시간 스트리밍 환경에서는 지연을 최소화해야 하므로 ultrafast, superfast, veryfast 같은 빠른 프리셋이 적합합니다.

▸ 영상 보관이나 고화질 인코딩 목적이라면 medium 이상의 느린 프리셋을 선택하는 것이 좋습니다.

 

🔷 h264_nvenc (NVIDIA GPU 기반) preset

NVENC는 GPU 전용 하드웨어 인코더이기 때문에, CPU 기반의 libx264처럼 ultrafast ~ veryslow 체계를 사용하지 않고 p1 ~ p7 단계의 프리셋을 제공합니다.

 

숫자가 낮을수록 속도가 빠르고 지연이 적지만 화질과 압축 효율은 떨어집니다. 반대로 숫자가 높을수록 인코딩 속도는 느려지지만, 같은 비트레이트에서 더 좋은 화질을 기대할 수 있습니다.

 

✔️ 자주 쓰이는 preset과 특징

preset 값 특징
p1 최속(fastest). 지연 최소화, 하지만 화질·압축 효율은 낮음
p2 ~ p4 중간 단계. 속도와 화질의 균형을 맞출 때 사용
p7 최고 품질(best quality). 속도는 가장 느리지만 화질과 압축 효율이 가장 뛰어남

▸ 실시간 전송, CCTV 관제와 같은 초저지연 환경 → p1 ~ p2 권장
▸ 파일 저장, VOD 인코딩처럼 화질이 중요한 환경 → p5 ~ p7 권장

 

✔ 마무리 - 실시간 인코딩 전략

실시간 RTSP 스트림을 다른 장치로 초저지연으로 송출하는 시스템을 구성할 때, 인코딩 방식의 선택은 단순 성능을 넘어 전체 안정성까지 좌우하는 요소입니다.


이번 실습에서는 동일한 RTSP 입력을 기준으로 CPU 기반의 libx264와 CUDA 기반의 h264_nvenc 인코딩 방식을 비교하고, 각각의 장단점을 명확히 확인할 수 있었습니다.

항목 libx264(CPU) h264_nvenc(GPU)
처리 방식 순수 소프트웨어 NVIDIA 하드웨어 가속
장점 셋업 간단, 호환성 높음 속도 빠름, 다중 스트림 효율적
단점 CPU 병목, 부하 급증 GPU 의존, 드라이버/설정 필요
적합 환경 테스트, 소규모 시스템 실서비스, 다채널 환경

▸ 개발 초기 또는 장비 제한 환경이라면 libx264 기반으로 빠르게 구조를 검증합니다.

▸ 스트림이 늘어나거나 고해상도 요구가 높아진다면, 반드시 h264_nvenc로 전환합니다.
▸ 인코딩 실패나 지연 현상에 대비해 스크립트화 + Supervisor 연동 + 로그 모니터링 체계를 함께 구성해야 실서비스에서 안정성이 확보됩니다.

 

 

👉 관련 글 링크

1. [FFmpeg] Windows 환경에서 FFmpeg 7.1 정적 빌드하기 – MinGW64 + H.264 인코딩 지원

2. [FFmpeg] FFmpeg 7.1 + H.265(libx265) 지원 정적 빌드 – 기존 MinGW64 환경 확장

3. [FFmpeg] CUDA 가속 포함 FFmpeg 7.1 정적 빌드 – MinGW64 + libx264/x265 + NVENC

4. [FFmpeg] SHA-256 Digest 인증 대응 FFmpeg 7.1 정적 빌드 – MinGW64 + CUDA + 인증 로직 패치

5. [FFmpeg] RTSP 스트림을 fMP4로 변환해 초저지연 TCP 전송하기

6. [FFmpeg] 인코딩 실습: CPU(libx264)와 CUDA(h264_nvenc) 비교

 

 

 

반응형

※ 게시된 글 및 이미지 중 일부는 AI 도구의 도움을 받아 생성되거나 다듬어졌습니다.

반응형