Codificação ao vivo com VP9 usando FFmpeg

Parâmetros de codificação

O VP9 oferece uma série de parâmetros para otimizar a codificação em tempo real. Alguns princípios gerais deles são discutidos em Modos taxados.

Exemplo de codificação FFmpeg VP9

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

Parâmetro Descrição
-quality realtime realtime é essencial para transmissões ao vivo e para velocidades acima de 5.
-speed 6 A velocidade 5 até 8 precisa ser usada para codificação em tempo real / ao vivo. Números menores (5 ou 6) têm qualidade mais alta, mas exigem mais energia da CPU. Números mais altos (7 ou 8) terão qualidade inferior, mas serão mais gerenciáveis para casos de uso com menor latência e também para dispositivos com baixo consumo de energia, como os dispositivos móveis.
-tile-columns 4 O compartilhamento divide o vídeo em regiões retangulares, o que permite várias linhas de execução 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 codificância 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 máxima de bits do i-Frame (pct)
-deadline realtime Versão alternativa (legada) de -quality realtime
-lag-in-frames 0 Número máximo de frames para atrasar
-qmin 4 -qmax 48 Valores mínimo e máximo do quantizador. Os valores exibidos são apenas uma sugestão, e isso ajudará a aumentar/diminuir a qualidade do vídeo à custa da compactação.
-row-mt 1 Ativar o multi-threading. Permite o uso de até duas vezes a linha de execução como colunas de bloco. 0 = desativado, 1 = ativado.
-error-resilient 1 Ativar recursos de resiliência de erros.

Como escolher parâmetros de codificação

As informações abaixo usam codificação de taxa de bits constante (CBR) para streaming de taxa de bits adaptável (ABR, na sigla em inglês), em que cada taxa de destino é definida explicitamente no manifesto do Packager. Isso resultará em uma "mudança" mais clara entre as taxas para os clientes. A codificação de taxa de bits variável (VBR) e o modo CQ também serão opções se a taxa de bits for mais flexível ou se a codificação estiver sendo fragmentada. O modo Q terá um problema com a codificação em tempo real necessária para vídeo ao vivo. Consulte Modos taxados para ver mais informações.

Para mais detalhes sobre como manipular o VP9, também vale a pena consultar o artigo associado sobre as configurações de VOD, mas considerando o foco na CBR.

Dicas e sugestões

Lembre-se de que, na transmissão ao vivo, tudo é restrito a uma velocidade de codificação mínima de 1x em tempo real. O FFmpeg informa a velocidade de codificação à medida que avança. Se a velocidade de codificação diminuir para menos de 1x, o processo de codificação não acompanhará a entrada de vídeo ao vivo, e os usuários enfrentarão buffer, e as interrupções na transmissão tornarão o stream inutilizável durante a transmissão ao vivo, embora o arquivo seja geralmente utilizável.

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

Veja a seguir a utilização da CPU a 25 fps para vários tamanhos de frame em uma área de trabalho quad-core i5 de 3,6 Ghz com Linux:

Resolução-alvo Parâmetros FFmpeg VP9 CPU / Velocidade (exemplo)
3.840 x 2.160 (2160p) -r 30 -g 90 -s 3840 x 2160 -qualidade em tempo real -velocidade 5 -linhas de execução 16 -row-mt 1 -colunas-coluna 3 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 7800k ~88% 0.39x
2.560 x 1.440 (1440p) -r 30 -g 90 -s 2560 x 1440 -qualidade em tempo real -velocidade 5 -linhas de execução 16 -row-mt 1 -colunas-3 - -frame-parallel 1 -qmin 4 -qmax 48 -b:v 6.000k Cerca de 86% 0,68x
1.920 x 1.080 (1080p) -r 30 -g 90 -s 1920 x 1080 -qualidade em tempo real -velocidade 5 -linhas de execução 8 -row-mt 1 -colunas-coluna 2 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 4500 mil Cerca de 82% 1,04x
1.280 x 720 (720p) -r 30 -g 90 -s 1.280 x 720 -qualidade em tempo real -velocidade 5 -linhas de execução 8 -linha-mt 1 -colunas-coluna 2 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 3.000k Cerca de 78% 1,77x
854x480 (480p) -r 30 -g 90 -s 854 x 480 -qualidade em tempo real -velocidade 6 -linhas de execução 4 -linha-mt 1 -tile-columns 1 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 1800k Cerca de 64% 3,51x
640x360 (360p) -r 30 -g 90 -s 640 x 360 -qualidade em tempo real -velocidade 7 -linhas de execução 4 -linha-mt 1 -tile-columns 1 -frame-parallel 0 -qmin 4 -qmax 48 -b:v 730k Cerca de 62% 5,27x
426x240 (240p) -r 30 -g 90 -s 426 x 240 -qualidade em tempo real -velocidade 8 -linhas de execução 2 -linha-mt 1 -tile-columns 0 -frame-parallel 0 -qmin 4 -qmax 48 -b:v 365k Cerca de 66% 8,27x

Veja um exemplo de FFmpeg:

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 vp9 \
  -b:a 128k -c:a libopus -f webm pipe1

Dicas e sugestões

  • Aqui, a saída está sendo feita para um pipeline FIFO ("pipe1"), que precisa ser criado antes da execução, antes de executar o comando FFmpeg. Para fazer isso, forneça o comando mkfifo pipe1 no seu diretório de trabalho. Ao usar o Shaka Packager, ele detecta esse pipeline como origem de entrada do stream especificado. Outros modelos de empacotamento 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 (3.3.3 atualmente) de https://www.ffmpeg.org/download.html.

Exemplo de taxa de bits adaptável definida

Dependendo da capacidade da máquina que executa a codificação do FFmpeg, ela pode ou não ser capaz de entregar todas as codificações a seguir ao mesmo tempo. Portanto, um subconjunto adequado para seus próprios recursos disponíveis e os públicos-alvo precisam ser selecionados na lista.

Pacote 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 produza todos eles 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 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 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 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 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 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 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 vp9 -b:a 64k -c:a libopus -f webm pipe7

No entanto, o conjunto completo acima exigirá uma CPU muito poderosa ou possivelmente suporte de descarga de GPU de hardware, como alguns chipsets fornecem cada vez mais. O Intel Kabylake (e além) tem um pipeline completo de codificação de hardware. A GPU Kabylake pode codificar VP9 de 8 bits, mas não de 10 bits.

Um exemplo prático de computador usando o Shaka Packager

Um exemplo prático para máquinas comuns de computador pode ser o Shaka Packager. Uma maneira simples de configurar o Shaka é instalá-lo em um contêiner do Docker, usando a imagem do DockerHub do Google. As instruções podem ser encontradas 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-lowlat 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-) de quatro núcleos
cache: 6.144 KB
velocidades de relógio: máx. 3.600 MHz 1: 800 MHz 2: 800 MHz 3: 800 MHz 4: 800 MHz
Placa gráfica Gráficos integrados do Intel PageSpeed
Memória 8 GB de RAM

Na prática, essa máquina consegue produzir de maneira ideal o seguinte intervalo utilizável de codificações ABR, com o FFmpeg informando consistentemente uma velocidade de codificação 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 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 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 vp9 -b:a 128k -c:a libopus -f webm pipe3

As configurações de -speed são muito altas. Essas configurações foram estabelecidas experimental e varia de acordo com a máquina.

Sobrecarga do Shaka Packager

O empacotamento não é uma atividade particularmente intensa. O Shaka Packager pode ser configurado para detectar todas as saídas, mesmo que apenas um subconjunto seja enviado pelo FFmpeg. Estas são as configurações do Packager 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