Todas las Noticias en Películas, Avances de Películas y Reseñas.

Extracción de miniaturas más rápido con FFmpeg

Una característica útil de Wistia es la capacidad de configurar fácilmente la miniatura de un video (o una imagen fija o un póster, si lo prefiere) en un cuadro exacto.

abres el personalizar panel, busque el cuadro que desea en el video (para obtener puntos de bonificación, use las teclas de flecha para avanzar de un solo cuadro al cuadro exacto que desea), luego haga clic en Usar el marco actual, y ta-da: tomamos ese marco y lo configuramos como la miniatura del video.

El único problema es que hay casos en los que ese “ta-da” no es exactamente un “ta-da”. Ocasionalmente, tardamos varios minutos en procesar el cambio de miniatura después de seleccionarlo. Taaaaaaaa-zzzzzzz.

Cómo se hacen las miniaturas

Para comprender lo que sucede detrás de escena, aquí hay un poco más de contexto sobre la arquitectura de nuestro sistema.

Cuando subes un video a Wistia, se envía a un servicio interno llamado Bakery. The Bakery maneja toda la ingestión, transcodificación, almacenamiento y entrega de videos. La carga se enruta a un grupo de servidores de carga de Bakery en un centro de datos de Rackspace en las afueras de Chicago. Cuando se completa la carga, extraemos una miniatura de la mitad del video usando ffmpeg, un popular proyecto de código abierto que proporciona herramientas para manipular videos. Debido a que el archivo está en el sistema de archivos local, esta es una operación rápida: generalmente toma menos de un segundo.

Ahora, supongamos que no le gusta la miniatura que el sistema eligió automáticamente para usted y desea elegir la suya propia. En su cuenta de Wistia, pausa el video en el cuadro que desea como miniatura y hace clic en “Usar el cuadro actual”. Esto es lo que sucede cuando haces clic en ese enlace:

    Los servidores de aplicaciones de Wistia envían un mensaje a la API de Bakery, indicándole que extraiga un cuadro del video en el momento que especificó. Bakery verifica y ve que el archivo de video está almacenado localmente en uno de los nodos en el clúster de carga, por lo que enruta la solicitud a la máquina que tiene el archivo de video. El servidor con el archivo de video recibe la solicitud y extrae la miniatura inmediatamente usando ffmpeg.

¡Estupendo! Ahora ves la nueva miniatura, y todo esto tomó solo uno o dos segundos. Ta-da, seguro!

Aquí es donde las cosas empeoran. Han pasado algunos días desde que subiste tu video, estás de vuelta en tu cuenta de Wistia y quieres elegir una nueva miniatura. Tenemos un problema: el video ya no se almacena localmente en el clúster.

Recomendado:  Rootea Android 4.4.3 fácilmente en tu dispositivo Nexus con SuperSU

Debido a que nuestro clúster de carga tiene un espacio de disco limitado, algún tiempo después de que subiera su video, lo transferimos a Amazon S3 para almacenarlo a largo plazo y lo eliminamos del disco local en el clúster.

Este no es el fin del mundo; solo necesitamos hacer las cosas un poco diferentes. Esto es lo que sucede cuando hace clic en “Usar el cuadro actual” para un video que no está almacenado localmente en el clúster:

    Los servidores de aplicaciones de Wistia envían un mensaje a la API de Bakery, indicándole que extraiga un cuadro del video en el momento que especificó. Bakery determina que el archivo de video no está almacenado localmente en un nodo del clúster, por lo que en lugar de procesar el solicitud inmediatamente, Bakery registra una tarea en segundo plano para crear esta miniatura. Una máquina trabajadora (generalmente utilizada para codificar videos) toma esta tarea de la cola y comienza a trabajar en ella. Para extraer la miniatura, la máquina trabajadora primero descarga el video archivo de S3 a su disco local. El trabajador extrae la miniatura usando ffmpeg, como antes.

Esto funciona, pero no es rápido. Los archivos de video pueden ser grandes. No es raro que los archivos tengan muchos cientos de megabytes o varios gigabytes de tamaño. Y no solo eso, sino que las velocidades de red son muy rápidas. Por lo general, vemos velocidades en los bajos 10 MB/s de S3 a nuestras máquinas en Rackspace. Entonces, digamos que su archivo de video es de 1 GB. Eso significa que es probable que tarde entre 20 y 50 segundos en descargar ese archivo.

Eso es lento. Y es especialmente molesto porque desde tu perspectiva, nada ha cambiado. ¿Por qué fue muy rápido seleccionar una miniatura la primera vez y dolorosamente lento la próxima vez? Lo más probable es que, debido a que fue tan rápido la primera vez, cuando tardó 30 segundos la próxima vez, ni siquiera lo esperó, asumió que algo estaba roto. ¡Eso es lo que asumiría!

Aparte: sí, probablemente podamos obtener esa velocidad de descarga desde S3 mediante la descarga de subprocesos múltiples, pero todavía estamos buscando decenas de segundos para archivos de varios gigabytes. Además, las velocidades de la red en Internet pública no son las más confiables en general, por lo que si bien esto aceleraría las cosas, no resolvería realmente el problema.

Una nueva esperanza

Afortunadamente, hay una mejor manera. ffmpeg admite varios protocolos de entrada de video además del sistema de archivos local, uno de los cuales es https. Cuando descubrí esto por primera vez, noté que había una opción de búsqueda. Después de leer detenidamente la fuente, parecía que ffmpeg era capaz de realizar solicitudes de rango de bytes. Esto es genial. En lugar de descargar todo el archivo para extraer un solo cuadro, quizás ffmpeg solo obtenga las partes que necesita.

Recomendado:  LG Display se asocia con Google y Apple para pantallas plegables

Probar el comportamiento es bastante fácil. Aquí hay un video de 36 minutos y 1.5 GB de un registro de navidad (¡felices fiestas tardías!):

~  curl -I https://embed-ssl.wistia.com/deliveries/b1663daaa577df844103db4d189bd7611c3c6573.bin
HTTP/1.1 200 OK
Accept-Ranges: bytes
Access-Control-Allow-Methods: GET, HEAD, OPTIONS
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Origin, Content-Type, Accept, Server, x-amz-version-id, X-Cache
Access-Control-Request-Method: *
Cache-Control: max-age=31557600
Cache-Control: max-age=31557600
Content-Type: video/mp4
Date: Mon, 15 Dec 2014 22:59:22 GMT
Etag: "06511b715e105fe2a240a2f4deeb6d75"
Last-Modified: Tue, 09 Dec 2014 00:02:44 GMT
Server: nginx/1.4.6 (Ubuntu)
Set-Cookie: __bakery_session=BAh7BkkiD3Nlc3Npb25faWQGOgZFVEkiRTFmOTY0ZWI2ZGExZTg5NTI0M2Qx%0ANzY1NWZiYjFlNmJlNWRlM2QxNWJmZTYxODZhMzhiNmVlMDIwYjc3Y2Q1MDgG%0AOwBG%0A--4fb22b894277098a63d09479bca459c51a417aef; path=/; HttpOnly
Set-Cookie: rack.session=BAh7BkkiD3Nlc3Npb25faWQGOgZFVEkiRTFmOTY0ZWI2ZGExZTg5NTI0M2Qx%0ANzY1NWZiYjFlNmJlNWRlM2QxNWJmZTYxODZhMzhiNmVlMDIwYjc3Y2Q1MDgG%0AOwBG%0A; path=/; HttpOnly
x-amz-version-id: _n0VW.055MJfZhuzOBBnsVbSjfgNS_0z
X-Served-By: bakery-breadroute-naan,bakery-prime-cyclops
Content-Length: 1537868391

La descarga de este archivo desde una de nuestras cajas de trabajadores tomó 27 segundos (bastante rápido, en realidad):

—— bakery-prime-zoo.ord.wistia.land 23:00:55 —— ~
$ wget https://embed-ssl.wistia.com/deliveries/b1663daaa577df844103db4d189bd7611c3c6573.bin
--2014-12-15 23:01:02--  https://embed-ssl.wistia.com/deliveries/b1663daaa577df844103db4d189bd7611c3c6573.bin
Resolving embed.wistia.com (embed.wistia.com)... 72.21.81.253
Connecting to embed.wistia.com (embed.wistia.com)|72.21.81.253|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1537868391 (1.4G) 
Saving to: ‘b1663daaa577df844103db4d189bd7611c3c6573.bin’

100%[======================================================================================================================================>] 1,537,868,391 67.3MB/s   in 27s

2014-12-15 23:01:30 (53.3 MB/s) - ‘b1663daaa577df844103db4d189bd7611c3c6573.bin’ saved [1537868391/1537868391]

Ahora tomemos la miniatura de 30 minutos en el video que descargamos:

time ffmpeg -ss 1800 -i b1663daaa577df844103db4d189bd7611c3c6573.bin -vframes 1 -vcodec png -an -y %d.png
real   0m0.376s
user  0m0.463s
sys   0m0.061s

En total, tenemos 27 segundos para descargar y 0,376 segundos para que ffmpeg obtenga la miniatura. Así que ~27,4 segundos en total.

Ahora intentemos que ffmpeg capture la imagen fija directamente desde la URL:

time ffmpeg -ss 1800 -i https://embed-ssl.wistia.com/deliveries/b1663daaa577df844103db4d189bd7611c3c6573.bin -vframes 1 -vcodec png -an -y %d.png
real   0m0.438s
user  0m0.469s
sys   0m0.068s

Wow, todo tomó menos de medio segundo. Eso es más de 60 veces más rápido. Y eso es con las velocidades de descarga que fueron significativamente más rápidas de lo que normalmente observamos.

Tijeras de cable

Para los más curiosos, puede usar Wireshark para ver qué está haciendo realmente ffmpeg:

Podemos ver aquí que ffmpeg realiza 4 llamadas HTTP separadas, cada una para un rango de bytes diferente. Para cada llamada, se especifica el inicio del rango, pero no el final. Esto se debe a que no sabemos cuántos bytes necesitamos realmente, sabemos dónde queremos comenzar a leer cada vez. Cuando conseguimos lo que necesitamos, cerramos la conexión. Aquí hay un desglose de las solicitudes de este archivo y por qué ffmpeg las está haciendo:

    Bytes 0-: Comienza al principio del archivo. La mayoría de los archivos de video comienzan con un identificador para que pueda saber qué formato es. Esto es importante porque una vez que sepamos el formato, sabremos en qué parte del archivo debemos ir a continuación. En este caso, este es un contenedor de video MPEG-4. Bytes 55198-: Aquí es donde está el átomo stsc. Esta es la tabla de muestra a fragmento. En el lenguaje MPEG-4, un video se compone de uno o más fragmentos, y cada fragmento se compone de muchas muestras. Esta tabla le indica qué muestras pertenecen a qué fragmentos. El átomo stsc también es seguido inmediatamente por el átomo stsz, o el átomo de tamaño de muestra. El átomo stsz contiene un mapa de los tamaños en bytes de todas las muestras. Con esta información, podemos calcular el desplazamiento de bytes para el fotograma clave más cercano a los 30 minutos. Bytes 887549-: aquí es donde comienza el átomo mdat. Este átomo contiene la transmisión de video en sí. No estoy completamente seguro de por qué se necesita esta solicitud. Parece que podríamos haber ido directamente a la solicitud n.° 4 con la información que obtuvimos de la solicitud n.° 2. Si sabe la respuesta, ¡me encantaría saberla! Bytes 1421450149-: este es el fotograma clave más cercano a los 30 minutos en la transmisión de video. ¡Buscamos aquí agarrar el marco que queremos!
Recomendado:  HTC One M9 tiene un nuevo menú de cargador de arranque, Fastboot ahora se llama "Modo de descarga" y los androides que bailan ya no existen

Aparte: utilicé AtomicParsley para analizar a qué corresponden todos estos desplazamientos de bytes. Es una práctica herramienta de línea de comandos que analizará archivos MPEG-4 e imprimirá la ubicación de todos los átomos en el archivo.

Y si tiene curiosidad por saber exactamente por qué ffmpeg está haciendo las solicitudes, vaya directamente a la fuente.

¡Es tan rápido ahora!

Después de poner este cambio en producción, hemos visto una aceleración de más de 5 veces en los tiempos de extracción de miniaturas para videos que no están almacenados localmente en nuestro clúster. ¡No está nada mal!