Codificación en vivo con VP9 mediante FFmpeg

Parámetros de codificación

VP9 proporciona una variedad de parámetros para optimizar la codificación en vivo. Algunos principios amplios se analizan en Modos de tasa.

Ejemplo de codificación de FFmpeg con VP9

En la siguiente tabla, se describen los parámetros de una llamada de ffmpeg de ejemplo para la codificación de VP9.

Parámetro Descripción
-quality realtime realtime es esencial para la transmisión en vivo y para las velocidades superiores a 5.
-speed 6 Se debe usar la velocidad de 5 a 8 para la codificación en tiempo real o en vivo. Los números más bajos (5 o 6) son de mayor calidad, pero requieren más energía de la CPU. Los números más altos (7 o 8) serán de menor calidad, pero más fáciles de administrar en casos de uso de latencia más baja y también en dispositivos con menor consumo de CPU, como dispositivos móviles.
-tile-columns 4 El mosaico divide el video en regiones rectangulares, lo que permite múltiples subprocesos para la codificación y la decodificación. La cantidad de mosaicos siempre es una potencia de dos. 0 = 1 mosaico, 1 = 2, 2 = 4, 3 = 8, 4 = 16, 5 = 32.
-frame-parallel 1 Habilitar funciones de decodificación paralelas.
-threads 8 Cantidad máxima de subprocesos que se usarán.
-static-thresh 0 Umbral de detección de movimiento.
-max-intra-rate 300 Tasa de bits máxima de i-Frame (porcentaje)
-deadline realtime Versión alternativa (heredada) de -quality realtime
-lag-in-frames 0 Cantidad máxima de fotogramas con retraso
-qmin 4 -qmax 48 Valores mínimos y máximos para el cuantizador. Los valores que se muestran son solo una sugerencia. Ajustar la información ayudará a aumentar o disminuir la calidad del video a expensas de la eficiencia de la compresión.
-row-mt 1 Habilita el multiproceso de filas. Permite el uso de un subproceso de hasta 2x como columnas de mosaicos. 0 = apagado, 1 = encendido.
-error-resilient 1 Habilitar funciones de resiliencia de errores

Elige parámetros de codificación

En la siguiente información, se usa la codificación de tasa de bits constante (CBR) para la transmisión de tasa de bits adaptable en vivo (ABR), en la que cada frecuencia objetivo se establece de forma explícita en el manifiesto del empaquetador. Esto permitirá que las tarifas de los clientes sean más claras y de un cambio a otro. La codificación de tasa de bits variable (VBR) y el modo CQ también son opciones si la tasa de bits puede ser más flexible o si la codificación se está fragmentando. El modo Q tendrá dificultades con la codificación en tiempo real necesaria para el video en vivo. Consulta Modos de tasa para obtener más información.

Para obtener más detalles sobre cómo manipular el VP9, también vale la pena consultar el artículo incluido en la configuración de VOD, pero que se tiene en cuenta un enfoque en la CBR.

Consejos y sugerencias

Recuerda que, cuando se transmite en vivo, todo está restringido a una velocidad de codificación mínima en tiempo real de 1x (FFmpeg informa la velocidad de codificación a medida que avanza). Si la velocidad de codificación es inferior a 1x, el proceso de codificación no seguirá el ritmo de la entrada de video en vivo y los usuarios experimentarán almacenamiento en búfer, y las interrupciones de la transmisión harán que la transmisión no se pueda usar durante la transmisión en vivo (aunque el archivo suele poder utilizarse).

Ejemplos de parámetros de codificación en acción

A continuación, se muestra el uso de CPU a 25 fps para varios tamaños de fotogramas en una computadora de escritorio i5 de 3.6 GHz de cuatro núcleos que ejecuta Linux:

Resolución de destino Parámetros de FFmpeg de VP9 CPU / velocidad (ejemplo)
3840x2160 (2160p) -r 30 -g 90 -s 3840x2160 -calidad en tiempo real -speed 5 -thread 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 -calidad en tiempo real -speed 5 -thread 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 -calidad en tiempo real -speed 5 -thread 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 -calidad en tiempo real -speed 5 -thread 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 -calidad en tiempo real -speed 6 -thread 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 -calidad realtime -speed 7 -thread 4 -row-mt 1 -tile-columns 1 -frame-monolith 0 -qmin 4 -qmax 48 -b:v 730k Aproximadamente el 62% y 5.27 veces
426x240 (240p) -r 30 -g 90 -s 426x240 -calidad realtime -speed 8 -thread 2 -row-mt 1 -tile-columns 0 -frame-Parallel 0 -qmin 4 -qmax 48 -b:v 365k ~66% 8.27

Un ejemplo de FFmpeg podría verse así:

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

Consejos y sugerencias

  • Ten en cuenta que, aquí, emitimos un resultado a una canalización con FIFO (&pipt1;pipe1), que se debe crear antes de ejecutar el comando de FFmpeg. Para hacerlo, asigna el comando mkfifo pipe1 a tu directorio de trabajo. Cuando se usa Shaka Packager, escuchará esa canalización como la fuente de entrada para la transmisión determinada. Es posible que otros modelos de empaquetado requieran un método diferente.

  • Para asegurarte de que se reconozcan los comandos de -row-mt, usa la versión estable más reciente de FFmpeg (3.3.3 actualmente) de https://www.ffmpeg.org/download.html.

Ejemplo de tasa de bits adaptable

Según la potencia de la máquina que ejecuta la codificación FFmpeg, puede o no entregar todas las siguientes codificaciones al mismo tiempo, por lo que se debe seleccionar un subconjunto adecuado para tus propios recursos y públicos objetivo de la lista.

Conjunto de ABR de FFmpeg completo

En una situación ideal, combinamos los ejemplos de codificación descritos en la sección anterior para crear un solo comando que los produce a la vez:

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

Sin embargo, el conjunto completo anterior requerirá una CPU muy potente o, en lo posible, admitir la descarga de la GPU del hardware, como algunos conjuntos de chips, cada vez más. Intel Kabylake (y más allá) tiene una canalización de codificación de hardware completa. (ten en cuenta que la GPU Kabylake puede codificar con VP9 de 8 bits, pero no de 10 bits).

Ejemplo práctico de escritorio que usa Shaka Packager

Un ejemplo más práctico para máquinas de escritorio comunes podría usar Shaka Packager. Una forma sencilla de configurar Shaka es instalarla en un contenedor de Docker con la imagen de DockerHub de Google. Puedes encontrar las instrucciones aquí:

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

Para este ejemplo, usamos una máquina con la siguiente configuración:

Sistema Host: Kernel obsoleto: 4.4.0-91-lowlatency x86_64 (64 bits)
Desktop Distro de Xfce 4.12.3: SO: https://ubuntustudio.org/2016/10/ubuntu-studio-16-10-released/
CPU Intel Core i5-6500 de cuatro núcleos (-MCP-)
memoria caché: 6,144 KB
velocidad del reloj: máx. 3,600 MHz 1:800 MHz 2: 800 MHz 3: 800 MHz 4: 800 MHz
Tarjeta gráfica Gráficos integrados Intel Skylake
Memoria 8 GB de RAM

En la práctica, esta máquina podría producir de manera óptima el siguiente rango utilizable de codificaciones ABR, con FFmpeg que informa constantemente una velocidad de codificación 1 veces:

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

Ten en cuenta que la configuración de -speed es bastante alta. Esta configuración se estableció de manera experimental y variará de una máquina a otra.

Sobrecarga de Shaka Packager

El empaquetado no es una actividad que requiera mucha CPU. Se puede configurar Shaka Packager para escuchar todos los resultados, incluso si solo FFmpeg entrega un subconjunto. Esta es la configuración del empaquetador que se probó en la máquina descrita anteriormente:

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