구글애드센스


[FFMPEG] NVENC 적용 STUDY



* NVIDIA 그래픽 가속을 이용한 H.264  Encoding with FFMPEG-NVENC


0. 개요
- 지포스 계열의 그래픽 카드 파워를 사용하여 H.264 인코딩이 가능. FFMPEG에서도 nvenc라는 이름으로 인코딩 기능을 지원한다. 최근에 업데이트된 SDK에서는 Decoding 인 nvdec 도 지원하는 것으로 되어있지만 아쉽게도 FFMPEG 과는 아직 연동되지 않는다. 따로 SDK를 사용해서는 가능한 것 같다. (예제를 돌려보진 않음)

1. Pre-Condition

- 당연하지만 Nvidia 그래픽카드가 필요. 그리고 Nvidia 라고 다되는건 아니고 페르미 이후 버전부터 가능하다. HEVC, 그러니까 H.265 부터는 맥스웰 이후 세대부터 가능하다. 


2. 환경

- Intel I7-4700MQ @ 2.40GHz
- 8GB RAM
- Nvidia Geforge GT 750M (Driver Version. 353.62)
- MSYS 2.0 / Mingw64
- FFMPEG 3.1.1
- Nvidia Video Codec SDK 6.0

(주의 : SDK는 그래픽카드 드라이버와 종속성이 있으므로 테스트PC의 드라이버 확인이 필요하다.)

3. FFMPEG BUILD

- MINGW64 / MSYS2.0 을 이용하여 FFMPEG을 빌드한다.
- MINGW64 / MSYS2.0 설치는 검색해보면 많은 정보가 있으므로 따로 설명하지 않는다.
- configuration 정보는 아래와 같으며 libx264는 SW 방식의 h.264와 어느정도 차이가 있는지 비교하기 위해 추가해서 빌드했다.

1
./configure --enable-libx264 --enable-small --disable-debug --enable-swscale --enable-gpl --enable-nonfree --enable-nvenc --target-os=mingw32 --enable-cross-compile --arch=x86_64 --disable-ffplay --disable-ffprobe --disable-ffserver --extra-cflags=-I/home/JayShin/nvidia_video_sdk_6.0.1/Samples/common/inc --extra-cflags=-I/home/JayShin/ffmpeg_build/include --extra-ldflags=-L/home/JayShin/ffmpeg_build/lib --enable-shared --disable-static


4. 테스트

- 약 3초 분량의 YUV420P 이미지를 10회 인코딩
- 영상 설정 : HD급 (1280 x 720)  YUV420P 이미지 / 30 FPS
- GOP SIZE : 30
- Baseline Encoding
- 1pass
- VBR : min 1Mbps  max 1Mbps

5. 결과

 1
2
3
4
5
6
7
8
9
10
11
12
libx264 (ultrafast) : 3.7 sec
libx264 (fast) : 9.5 sec
libx264 (medium) : 10.6 sec
libx264 (slow) : 19.55 sec
libx264 (veryslow) : 49.73 sec
NVENC (Default) : 4 sec
NVENC (hq) : 5.48 sec
NVENC (hp) : 3.5 sec
NVENC (bd) : 5.49 sec
NVENC (ll) : 5.5 sec
NVENC (llhq) : 6.84 sec
NVENC (llhp) : 3.78 sec

- NVENC 괄호 안의 내용은 프리셋이다. NVENC는 저런 프리셋을 지원한다.
- 참고로 프리셋 내용은 libavcodec/nvenc_h264.c 에 정의되어있다.
- x264의 ultrafast는 NVENC의 hp 와 얼추 비슷한 수행속도를 보인다. 다만 화질이 x264쪽이 약간 더 낫다고 보여진다.

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
static const AVOption options[] = {
{ "preset", "Set the encoding preset", OFFSET(preset), AV_OPT_TYPE_INT, { .i64 = PRESET_MEDIUM }, PRESET_DEFAULT, PRESET_LOSSLESS_HP, VE, "preset" },
{ "default", "", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_DEFAULT }, 0, 0, VE, "preset" },
{ "slow", "hq 2 passes", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_SLOW }, 0, 0, VE, "preset" },
{ "medium", "hq 1 pass", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_MEDIUM }, 0, 0, VE, "preset" },
{ "fast", "hp 1 pass", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_FAST }, 0, 0, VE, "preset" },
{ "hp", "", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_HP }, 0, 0, VE, "preset" },
{ "hq", "", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_HQ }, 0, 0, VE, "preset" },
{ "bd", "", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_BD }, 0, 0, VE, "preset" },
{ "ll", "low latency", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_LOW_LATENCY_DEFAULT }, 0, 0, VE, "preset" },
{ "llhq", "low latency hq", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_LOW_LATENCY_HQ }, 0, 0, VE, "preset" },
{ "llhp", "low latency hp", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_LOW_LATENCY_HP }, 0, 0, VE, "preset" },
{ "lossless", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_LOSSLESS_DEFAULT }, 0, 0, VE, "preset" },
{ "losslesshp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_LOSSLESS_HP }, 0, 0, VE, "preset" },


6. 결론


- 적어도 내 카드에서는 SW 방식보다 성능상 이점이 있다고 보긴 힘들 것 같다. 어쨌거나 최대 속도를 내는 프리셋에선 NVENC가 더 빠르긴 하지만 거의 오차 이하라고 보여진다. GPU 파워를 쓸 수 있다는 것이 역시 가장 큰 장점 아닐까 생각된다. 
- GPU Shark로 확인해본 것처럼 GPU 퍼포먼스의 10%정도밖에 사용을 하지 않았는데 이는 성능 상한선이 걸려있는게 아닌가 싶다. 여러개를 동시에 실행해도 퍼포먼스를 더 잡아먹지 않는다.
- 잘만 하면 개이득일 각

7. 기타

- 인스턴스를 3개이상 생성하지 못한다.

- 회사분이 설명하기론 이거 제한걸려있다는데 쿼드로급은 몇 개 까지 될런지 모르겠다. 
- 또한 퍼포먼스 제한선도 풀 수 있는 방법이 있을거 같기도 한데.. 이건 차차 알아보기로 하자.

관련 페이지 :

https://developer.nvidia.com/ffmpeg
https://developer.nvidia.com/nvidia-video-codec-sdk

작업 소스 :

https://github.com/JayShinMuzie/ProjLenaky/tree/master/ffmpeg



덧글

  • sa 2017/02/25 17:05 # 삭제 답글

    안녕하세요?
    NVENC 관련해서 여쭤보고싶은게 있습니다.
    windows 7 64bit / Visual studio 2010 / GTX 1060 환경에서
    비디오코덱 SDK 다운을 받아서 설정을 하고
    명령인수를 넣으 2010환경에서 프로젝트를 돌렸는데,
    인코더가 돌지를 않습니다. 아무키나 누르라더군요

    usage : NvEncoder하고 파라미터 종류가 뜨는 것으로 보아
    설정은 얼추 된것 같은데 돌지 않으니 답답합니다 ㅜㅜ..

    현재 넣어둔 명령인수는 -i rec.yuv -o out.h265 -size 416 240 -codec 1 -preset hp -fps 25 입니다.

    조언 부탁드립니다..
  • muzie 2017/02/27 09:03 #

    명령인자 넣어서 실행하신단게 어떤 의미인지 잘 모르겠습니다. vs2010 으로 실행환경 만드셨는데 인자값이 있다면 system 콜로 ffmpeg.exe를 실행하셨다는 얘긴가요?
  • sa 2017/02/28 14:16 # 삭제 답글

    사진첨부가 안되어서 설명하기가 조금 어렵네요
    NvEncoder 픞로젝트의 속성 페이지 > 구성속성 > 명령인수 부분에 집어넣고 빌드했습니다.

    디버그모드로 확인해보니
    InitCuda(encodeConfig.deviceID);함수 실행 직후
    nvStatus = m_pNvHWEncoder->Initialize(m_pDevice, NV_ENC_DEVICE_TYPE_CUDA);로 들어오는데
    nvStatus가 NV_ENC_SUCCESS를 반환하지 않아서 바로 프로그램이 종료되는 것 같습니다.

    왜그럴까요..?
  • muzie 2017/02/28 22:04 #

    ffmpeg 관련된 작업이 아니고 그냥 video codec sdk 쪽을 건드리고 계시는거군요..
    파악은 힘들지만 비슷한 경우는 드라이버 버전이 SDK 버전과 맞지 않아서 cuda 인스턴스가 생성이 되지 않았던 문제를 겪었던 적이 있습니다. video codec sdk 다운로드 페이지에 아마 버전 몇 이상이라고 명시되어있을겁니다. 확인해보세요.
  • dd 2019/01/07 22:55 # 삭제 답글

    쿼드로 p2000부터는 인스턴스 수에 상관이 없습니다만 가격이 너무 비쌉니다.
댓글 입력 영역