Codificação ao vivo com VP9 usando FFmpeg

Parâmetros de codificação

O VP9 oferece uma variedade de parâmetros para otimizar a codificação ao vivo. Alguns princípios gerais são discutidos em Modos de taxa de bits.

Exemplo de codificação VP9 do FFmpeg

A tabela abaixo descreve os parâmetros de um exemplo de chamada ffmpeg para codificação VP9.

Parâmetro Descrição
-quality realtime realtime é essencial para transmissões ao vivo e velocidades acima de 5.
-speed 6 A velocidade 5 a 8 deve ser usada para codificação ao vivo / em tempo real. Números menores (5 ou 6) têm qualidade melhor, mas exigem mais poder de CPU. Números mais altos (7 ou 8) terão qualidade inferior, mas serão mais fáceis de gerenciar para casos de uso de baixa latência e também para dispositivos com menor capacidade de CPU, como dispositivos móveis.
-tile-columns 4 O mosaico divide o vídeo em regiões retangulares, o que permite multithreading para codificação e decodificação. O número de blocos é sempre uma potência de dois. 0 = 1 bloco, 1 = 2, 2 = 4, 3 = 8, 4 = 16, 5 = 32.
-frame-parallel 1 Ative os recursos de decodificação paralela.
-threads 8 Número máximo de linhas de execução a serem usadas.
-static-thresh 0 Limite de detecção de movimento.
-max-intra-rate 300 Taxa de bits máxima de frame-I (pct)
-deadline realtime Versão alternativa (legada) do -quality realtime
-lag-in-frames 0 Número máximo de frames a serem atrasados
-qmin 4 -qmax 48 Valores mínimo e máximo para o quantizador. Os valores aqui são apenas uma sugestão, e o ajuste deles ajuda a aumentar/diminuir a qualidade do vídeo às custas da eficiência da compactação.
-row-mt 1 Ativa o multithreading de linhas. Permite o uso de até 2x de linhas como colunas de blocos. 0 = off, 1 = on.
-error-resilient 1 Ative os recursos de capacidade de recuperação de erros.

Escolher parâmetros de codificação

As informações abaixo usam a codificação de taxa de bits constante (CBR) para transmissão adaptativa de taxa de bits (ABR) ao vivo, em que cada taxa de destino é definida explicitamente no manifesto do empacotador. Isso vai resultar em uma "troca" mais limpa entre as taxas para os clientes. A codificação de taxa de bits variável (VBR) e o modo CQ também são opções se a taxa de bits puder ser mais flexível ou se a codificação estiver sendo dividida em partes. O modo Q terá dificuldades com a codificação em tempo real necessária para vídeos ao vivo. Consulte Modos de taxa de bits para mais informações.

Para mais detalhes sobre como manipular o VP9, consulte o artigo complementar sobre configurações de VOD, mas considerando o foco no CBR.

Dicas e sugestões

Ao fazer transmissões ao vivo, tudo é limitado a uma velocidade mínima de codificação em tempo real de 1x (o FFmpeg informa a velocidade de codificação à medida que ela avança). Se a velocidade de codificação cair abaixo de 1x, o processo não vai acompanhar a entrada de vídeo ao vivo, e os usuários vão ter problemas de buffer. Além disso, interrupções na transmissão vão tornar o stream inutilizável durante a transmissão ao vivo (embora o arquivo geralmente possa ser usado).

Exemplos de parâmetros de codificação em ação

A seguir, mostramos a utilização da CPU a 25 fps para vários tamanhos de frame em um desktop quad-core i5 de 3,6 GHz executando o Linux:

Resolução desejada Parâmetros VP9 do FFmpeg CPU / Velocidade (exemplo)
3840x2160 (2160p) -r 30 -g 90 -s 3840x2160 -quality realtime -speed 5 -threads 16 -row-mt 1 -tile-columns 3 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 7800k ~88% 0,39x
2560x1440 (1440p) -r 30 -g 90 -s 2560x1440 -quality realtime -speed 5 -threads 16 -row-mt 1 -tile-columns 3 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 6000k ~86% 0,68x
1920x1080 (1080p) -r 30 -g 90 -s 1920x1080 -quality realtime -speed 5 -threads 8 -row-mt 1 -tile-columns 2 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 4500k ~82% 1,04x
1280x720 (720p) -r 30 -g 90 -s 1280x720 -quality realtime -speed 5 -threads 8 -row-mt 1 -tile-columns 2 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 3000k ~78% 1,77x
854x480 (480p) -r 30 -g 90 -s 854x480 -quality realtime -speed 6 -threads 4 -row-mt 1 -tile-columns 1 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 1800k ~64% 3,51x
640x360 (360p) -r 30 -g 90 -s 640x360 -quality realtime -speed 7 -threads 4 -row-mt 1 -tile-columns 1 -frame-parallel 0 -qmin 4 -qmax 48 -b:v 730k ~62% 5,27x
426x240 (240p) -r 30 -g 90 -s 426x240 -quality realtime -speed 8 -threads 2 -row-mt 1 -tile-columns 0 -frame-parallel 0 -qmin 4 -qmax 48 -b:v 365k ~66% 8,27x

Um exemplo de FFmpeg seria assim:

ffmpeg -stream_loop 100 -i /home/id3as/Videos/120s_tears_of_steel_1080p.webm \
  -r 30 -g 90 -s 3840x2160 -quality realtime -speed 5 -threads 16 -row-mt 1 \
  -tile-columns 3 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 7800k -c:v libvpx-vp9 \
  -b:a 128k -c:a libopus -f webm pipe1

Dicas e sugestões

  • Aqui, estamos gerando saída para um pipe FIFO ("pipe1"), que precisa ser criado antes da execução, antes de executar o comando FFmpeg. Para fazer isso, execute o comando mkfifo pipe1 no diretório de trabalho. Ao usar o Shaka Packager, ele vai detectar esse pipe como origem de entrada para o stream especificado. Outros modelos de embalagem podem exigir um método diferente.

  • Para garantir que os comandos -row-mt sejam reconhecidos, use a versão estável mais recente do FFmpeg (atualmente 3.3.3) em https://www.ffmpeg.org/download.html

Exemplo de conjunto de taxa de bits adaptável

Dependendo da capacidade da máquina que executa a codificação FFmpeg, pode ser possível ou não entregar todas as codificações a seguir ao mesmo tempo. Portanto, um subconjunto adequado aos seus recursos disponíveis e públicos-alvo precisa ser selecionado na lista.

Conjunto completo de ABR do FFmpeg

Em um cenário ideal, combinamos os exemplos de codificação descritos na seção anterior para criar um único comando que os produza todos ao mesmo tempo:

ffmpeg -stream_loop 100 -i lakes1080p.mp4 \
  -y -r 25 -g 75 -s 3840x2160 -quality realtime -speed 5 -threads 8 \
  -tile-columns 2 -frame-parallel 1 \
  -b:v 7800k -c:v libvpx-vp9 -b:a 196k -c:a libopus -f webm pipe1 \
  -y -r 25 -g 75 -s 2560x1440 -quality realtime -speed 5 -threads 8 \
  -tile-columns 2 -frame-parallel 1 \
  -b:v 6000k -c:v libvpx-vp9 -b:a 196k -c:a libopus -f webm pipe2 \
  -y -r 25 -g 75 -s 1920x1080 -quality realtime -speed 5 -threads 4 \
  -tile-columns 2 -frame-parallel 1 \
  -b:v 4500k -c:v libvpx-vp9 -b:a 196k -c:a libopus -f webm pipe3 \
  -y -r 25 -g 75 -s 1280x720 -quality realtime -speed 5 -threads 4 \
  -tile-columns 2 -frame-parallel 1 \
  -b:v 3000k -c:v libvpx-vp9 -b:a 196k -c:a libopus -f webm pipe4 \
  -y -r 25 -g 75 -s 854x480 -quality realtime -speed 6 -threads 4 \
  -tile-columns 2 -frame-parallel 1 \
  -b:v 2000k -c:v libvpx-vp9 -b:a 196k -c:a libopus -f webm pipe5 \
  -y -r 25 -g 75 -s 640x360 -quality realtime -speed 7 -threads 2 \
  -tile-columns 1 -frame-parallel 0 \
  -b:v 730k -c:v libvpx-vp9 -b:a 128k -c:a libopus -f webm pipe6 \
  -y -r 25 -g 75 -s 426x240 -quality realtime -speed 8 -threads 2 \
  -tile-columns 1 -frame-parallel 0 \
  -b:v 365k -c:v libvpx-vp9 -b:a 64k -c:a libopus -f webm pipe7

No entanto, o conjunto completo acima vai exigir uma CPU muito potente ou talvez suporte de descarga de GPU de hardware, como alguns chipsets oferecem cada vez mais. O Intel Kabylake (e versões mais recentes) tem um pipeline completo de codificação de hardware. A GPU Kabylake pode fazer codificação VP9 de 8 bits, mas não de 10 bits.

Um exemplo prático para computador usando o Shaka Packager

Um exemplo mais prático para máquinas desktop comuns pode usar o Shaka Packager. Uma maneira simples de configurar o Shaka é instalá-lo em um contêiner Docker usando a imagem do DockerHub do Google. Confira as instruções aqui:

https://github.com/google/shaka-packager#using-docker-for-testing--development

Neste exemplo, usamos uma máquina com a seguinte configuração:

Sistema Host: obs Kernel: 4.4.0-91-lowlatency x86_64 (64 bits)
Computador Xfce 4.12.3 Distro: SO: https://ubuntustudio.org/2016/10/ubuntu-studio-16-10-released/
CPU Intel Core i5-6500 (-MCP-) com quatro núcleos
cache: 6144 KB
velocidades de clock: máx.: 3600 MHz 1: 800 MHz 2: 800 MHz 3: 800 MHz 4: 800 MHz
Placa de vídeo Placa de vídeo integrada Intel Skylake
Memória 8 GB de RAM

Na prática, essa máquina pode produzir de maneira ideal o seguinte intervalo útil de codificações ABR, com o FFmpeg informando consistentemente uma velocidade de codificação de 1x:

ffmpeg -stream_loop 100 -i 120s_tears_of_steel_1080p.webm \
  -y -r 30 -g 90 -s 1920x1080 -quality realtime -speed 7 -threads 8 \
  -row-mt 1 -tile-columns 2 -frame-parallel 1 -qmin 4 -qmax 48 \
  -b:v 4500k -c:v libvpx-vp9 -b:a 128k -c:a libopus -f webm pipe1 \
  -y -r 30 -g 90 -s 1280x720 -quality realtime -speed 8 -threads 6 \
  -row-mt 1 -tile-columns 2 -frame-parallel 1 -qmin 4 -qmax 48 \
  -b:v 3000k -c:v libvpx-vp9 -b:a 128k -c:a libopus -f webm pipe2 \
  -y -r 30 -g 90 -s 640x360 -quality realtime -speed 8 -threads 2 \
  -row-mt 1 -tile-columns 1 -frame-parallel 1 -qmin 4 -qmax 48 \
  -b:v 730k -c:v libvpx-vp9 -b:a 128k -c:a libopus -f webm pipe3

As configurações de -speed são bastante altas. Essas configurações foram estabelecidas experimentalmente e vão variar de máquina para máquina.

Sobrecarga do Shaka Packager

O empacotamento não é uma atividade que exige muito da CPU. O Shaka Packager pode ser configurado para detectar todas as saídas, mesmo que apenas um subconjunto esteja sendo entregue pelo FFmpeg. Estas são as configurações do empacotador testadas na máquina descrita acima:

packager \
  in=pipe1,stream=audio,init_segment=livehd-audio-1080.webm,segment_template=livehd-audio-1080-\$Number\$.webm \
  in=pipe1,stream=video,init_segment=livehd-video-1080.webm,template=livehd-video-1080-\$Number\$.webm \
  in=pipe2,stream=audio,init_segment=livehd-audio-720.webm,segment_template=livehd-audio-720-\$Number\$.webm \
  in=pipe2,stream=video,init_segment=livehd-video-720.webm,template=livehd-video-720-\$Number\$.webm \
  in=pipe3,stream=audio,init_segment=livehd-audio-360.webm,segment_template=livehd-audio-360-\$Number\$.webm \
  in=pipe3,stream=video,init_segment=livehd-video-360.webm,template=livehd-video-360-\$Number\$.webm \
  --mpd_output livehd.mpd --dump_stream_info --min_buffer_time=10 --time_shift_buffer_depth=300 \
  --segment_duration=3 --io_block_size 65536