ffmpeg: Decodificando vídeos via hardware

A decodificação padrão de vídeos do ffmpeg, bem como outros players no Linux, é via software. Isso não tem lá grandes impactos, pela minha experiência, com processadores rápidos como o i7-4770 (o meu, atual), mas, é claro, se a placa de vídeo pode fazer o trabalho de decodificação, liberamos o processador para tarefas mais nobres.

Tanto o VLC quanto o ffmpeg suportam a decodificação por hardware usando uma das duas bibliotecas desenvolvidas para isso: A VA-API (Video Acceleration Aplication Programming Interface) e a VDPAU (Video Decode and Presentation API for Unix). Das duas, prefira a VDPAU. Foi desenvolvida pela nVidia e é suportada por todos os melhores fabricantes de placas de vídeo… Exceto se você tem uma Intel on-board! A Intel só suporta a VA-API… Existe um driver surrogate chamado vdpau-va-driver que funciona como uma camada de abstração para a VA API usando o VDPAU, caso vocẽ queira abstrair as configurações e usar VA API em todas, mesmo em máquinas que tenham uma GForce ou uma placa de ATI… Mas, recomendo mesmo o uso de VDPAU.

No caso do VLC, não há muito o que fazer. A configuração default detecta se você tem um dos decoders de hardware funcionais e os usa, automaticamente. Mas, no caso do ffmpeg, você precisa usar a opção -hwaccel apenas como DECODER para os vídeos (não tem como usar para codificar os pacotes que serão salvos num arquivo!). Para saber quais decodecs estão disponíveis, é só usar:

$ ffmpeg -hide_banner -hwaccels
Hardware acceleration methods:
vdpau
vaapi

Se aparecer vdpau ou vaapi eles podem ser usados… Geralmente basta instalar o pacote libvdpau-va-gl1 e esses decoders são habilitados para você.

Instale também o pacote vdpauinfo para poder obter o que sua placa de vídeo pode ou não fazer. No caso da minha:

$ vdpauinfo
display: :0   screen: 0
API version: 1
Information string: NVIDIA VDPAU Driver Shared Library  367.57  Mon Oct  3 20:32:14 PDT 2016

Video surface:

name   width height types
-------------------------------------------
420     4096  4096  NV12 YV12 
422     4096  4096  UYVY YUYV 

Decoder capabilities:

name                        level macbs width height
----------------------------------------------------
MPEG1                           0 65536  4032  4048
MPEG2_SIMPLE                    3 65536  4032  4048
MPEG2_MAIN                      3 65536  4032  4048
H264_BASELINE                  41 65536  4032  4080
H264_MAIN                      41 65536  4032  4080
H264_HIGH                      41 65536  4032  4080
VC1_SIMPLE                      1  8190  2048  2048
VC1_MAIN                        2  8190  2048  2048
VC1_ADVANCED                    4  8190  2048  2048
MPEG4_PART2_SP                  3  8192  2048  2048
MPEG4_PART2_ASP                 5  8192  2048  2048
DIVX4_QMOBILE                   0  8192  2048  2048
DIVX4_MOBILE                    0  8192  2048  2048
DIVX4_HOME_THEATER              0  8192  2048  2048
DIVX4_HD_1080P                  0  8192  2048  2048
DIVX5_QMOBILE                   0  8192  2048  2048
DIVX5_MOBILE                    0  8192  2048  2048
DIVX5_HOME_THEATER              0  8192  2048  2048
DIVX5_HD_1080P                  0  8192  2048  2048
H264_CONSTRAINED_BASELINE      41 65536  4032  4080
H264_EXTENDED                  41 65536  4032  4080
H264_PROGRESSIVE_HIGH          41 65536  4032  4080
H264_CONSTRAINED_HIGH          41 65536  4032  4080
H264_HIGH_444_PREDICTIVE       41 65536  4032  4080
HEVC_MAIN                      --- not supported ---
HEVC_MAIN_10                   --- not supported ---
HEVC_MAIN_STILL                --- not supported ---
HEVC_MAIN_12                   --- not supported ---
HEVC_MAIN_444                  --- not supported ---

Output surface:

name              width height nat types
----------------------------------------------------
B8G8R8A8         16384 16384    y  Y8U8V8A8 V8U8Y8A8 A4I4 I4A4 A8I8 I8A8 
R10G10B10A2      16384 16384    y  Y8U8V8A8 V8U8Y8A8 A4I4 I4A4 A8I8 I8A8 

Bitmap surface:

name              width height
------------------------------
B8G8R8A8         16384 16384
R8G8B8A8         16384 16384
R10G10B10A2      16384 16384
B10G10R10A2      16384 16384
A8               16384 16384

Video mixer:

feature name                    sup
------------------------------------
DEINTERLACE_TEMPORAL             y
DEINTERLACE_TEMPORAL_SPATIAL     y
INVERSE_TELECINE                 y
NOISE_REDUCTION                  y
SHARPNESS                        y
LUMA_KEY                         y
HIGH QUALITY SCALING - L1        y
HIGH QUALITY SCALING - L2        -
HIGH QUALITY SCALING - L3        -
HIGH QUALITY SCALING - L4        -
HIGH QUALITY SCALING - L5        -
HIGH QUALITY SCALING - L6        -
HIGH QUALITY SCALING - L7        -
HIGH QUALITY SCALING - L8        -
HIGH QUALITY SCALING - L9        -

parameter name                  sup      min      max
-----------------------------------------------------
VIDEO_SURFACE_WIDTH              y         1     4096
VIDEO_SURFACE_HEIGHT             y         1     4096
CHROMA_TYPE                      y  
LAYERS                           y         0        4

attribute name                  sup      min      max
-----------------------------------------------------
BACKGROUND_COLOR                 y  
CSC_MATRIX                       y  
NOISE_REDUCTION_LEVEL            y      0.00     1.00
SHARPNESS_LEVEL                  y     -1.00     1.00
LUMA_KEY_MIN_LUMA                y  
LUMA_KEY_MAX_LUMA                y

Minha placa é uma low end, OEM, GForce 635GT, e é bem limitada. No entanto, repare que ela aceita a decodificação de todos os profiles para os codecs MPEG1, MPEG2, h.264, VC1, DIVX4 e DIVX5, não suportando apenas o h.265 (ou HEVC)…

Para recodificar um vídeo, por exemplo, vocẽ poderia fazer:

$ ffmpeg -hwaccel vdpau \
   -i video.mp4 -c:v libx264 -crf 18 \
   -c:a libvo_aacenc -b:v 128k \
   video-out.mp4

Note que a opção, agora, é -hwaccel sem o ‘s’. Desse jeito, o ffmpeg vai decodificar o vídeo usando VDPAU e recodificá-lo usando a libx264. Mas, ATENÇÃO! Se o vídeo não estiver estritamente dentro do padrão h264 (ou de algum outro decoder suportado pelo VDPAU), vão aparecer um monte de erros e você acaba sem o stream de vídeo no arquivo final.

Use a decodificação por hardware com cuidado, se for fazer algum script de conversão de vídeos, por exemplo…

Anúncios