Video en línea con Wowza y Amazon Elastic Transcoder

Publicado: 2022-03-11

El éxito y la adopción de cualquier aplicación web actual depende en gran medida de su rendimiento, flexibilidad y facilidad de uso.

Especialmente en el mundo actual del TDAH, los usuarios perderán rápidamente la paciencia con una aplicación si su página tarda demasiado en cargarse. Para las aplicaciones web que necesitan admitir el procesamiento de video, que es inherentemente intensivo en cómputo y E/S, este desafío es particularmente agudo. Sin embargo, los usuarios son cada vez más exigentes y desean que sus videos sean de alta calidad y se carguen rápidamente, incluso si se ejecutan en un teléfono inteligente o tableta.

Los usuarios también están perdiendo la tolerancia hacia las aplicaciones web que no funcionan en su navegador o dispositivo preferido, o que no admiten el formato de datos que necesitan para cargar o exportar. Por lo tanto, la diversidad de formatos de video que deben ser compatibles también hace que la incorporación de soporte de video en una aplicación web sea especialmente desafiante.

Esta publicación describe cómo aproveché de manera efectiva las tecnologías de código abierto y los servicios basados ​​en la nube para incorporar capacidades de video en una aplicación web basada en PHP.

Procesamiento de video en línea en PHP con Wowza y Amazon Elastic Transcoder

Caso de uso

Formaba parte de un equipo que necesitaba desarrollar un sitio web similar a YouTube, donde los usuarios registrados pudieran subir y compartir sus videos.

El sistema necesitaba permitir a los usuarios registrados cargar sus videos en una variedad de formatos admitidos que luego se convertirían a un formato común (MP4). También necesitábamos generar un conjunto de miniaturas y un collage de imágenes para usar en el reproductor de video para mostrar los cuadros en una barra de progreso de video.

Las cosas se complicaron aún más por el hecho de que los requisitos del cliente nos impedían usar cualquier CDN disponible o API de transcodificación, por lo que necesitábamos desarrollar nuestra solución desde cero.

Carga de video

Dado que el proceso de carga en sí no necesitaba ser específico del video (solo necesitábamos una capacidad de carga de archivos fácil de usar), tenía sentido usar una solución de código abierto existente en lugar de implementar la nuestra. Seleccionamos jQuery-File-Upload, principalmente porque admitía dos funciones que eran esenciales en nuestro caso; a saber, una barra de progreso de carga y cargas fragmentadas.

La carga fragmentada nos permitió permitir que un usuario cargue un archivo de video de prácticamente cualquier tamaño (especialmente importante para admitir archivos de video en resolución HD). Con este enfoque, el archivo se divide en varios "fragmentos" en el front-end que invoca la acción de carga con cada fragmento de datos (junto con los metadatos de cada fragmento, como el número de fragmento y el tamaño total del archivo). Luego, el archivo de video completo se vuelve a ensamblar en el back-end. Por cierto, incluir el número de fragmentos en los metadatos resultó particularmente importante ya que algunos navegadores (como Mobile Safari) tienden a transmitir los fragmentos en orden aleatorio.

Procesamiento de video en línea

El procesamiento de video puede ser tan simple como capturar fotogramas como imágenes fijas, o puede implicar operaciones más complejas como la mejora de imágenes, la estabilización de la transmisión de video, etc. En nuestro caso, los únicos requisitos de procesamiento de video eran (a) extraer códecs de video y otros metadatos clave y (b) generar un conjunto de miniaturas y un collage de imágenes (que se usará en el reproductor de video para mostrar los cuadros en el progreso de un video). bar).

FFmpeg , una biblioteca de código abierto ampliamente utilizada y distribuida libremente, fue extremadamente útil para cumplir con estos requisitos. FFmpeg proporciona una solución multiplataforma completa para grabar, convertir y transmitir archivos de audio y video. También se puede usar para convertir videos y realizar ediciones simples (por ejemplo, recortar, cortar, agregar una marca de agua, etc.).

Para nuestros propósitos, pudimos usar FFmpeg para dividir el video en diez secciones y luego capturar una miniatura para cada sección para proporcionar la funcionalidad necesaria.

Desafortunadamente, sin embargo, no hay enlaces de lenguaje PHP para la biblioteca FFmpeg. Como resultado, la única forma de aprovechar FFmpeg de PHP es invocar el binario desde la línea de comandos usando los comandos del sistema. Básicamente, hay dos formas de usar FFmpeg en PHP:

  • libav. Libav es un proyecto de software libre, derivado de FFmpeg en 2011, que produce bibliotecas y programas para manejar datos multimedia. En Ubuntu, por ejemplo, esto se puede instalar con el comando sudo apt-get install libav-tools . Los comandos libav son compatibles con FFmpeg y avconv. PHP necesita tener acceso de línea de comando a ffmpeg/avconv para usar esto mediante programación.
  • PHP-FFMPeg. PHP-FFMPeg es un controlador PHP orientado a objetos para el binario FFMpeg. Se puede acceder simplemente ejecutando composer update "php-ffmpeg/php-ffmpeg" .

Usamos PHP-FFMpeg ya que brinda fácil acceso a la funcionalidad de FFmpeg que nos interesaba. Por ejemplo, la clase FFProbe de este paquete le permite recibir información sobre códecs o la duración de un archivo de video en particular de la siguiente manera:

 $ffprobe = FFMpeg\FFProbe::create(); $ffprobe ->format('/path/to/video/mp4') // extracts file informations ->get('duration');

FFmpeg también facilita guardar cualquier cuadro de video:

 $ffmpeg = FFMpeg\FFMpeg::create(); $video = $ffmpeg->open('video.mpg'); $video ->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(10)) ->save('frame.jpg');

El código de muestra más detallado está disponible aquí.

Una nota de precaución: debido a algunas leyes de patentes, FFmpeg no puede procesar todos los códecs y algunos formatos no son compatibles (o no son totalmente) compatibles. Recuerdo haber tenido problemas hace un par de años, por ejemplo, con el formato .3gp cuando la compatibilidad con teléfonos básicos era imprescindible.

haciendo cola

Después de obtener los códecs de un video y otros metadatos, empujamos el video a una cola de conversión FIFO (primero en entrar, primero en salir). La cola se implementó utilizando un script cron simple que selecciona una cantidad determinada de videos sin procesar cada vez que se ejecuta y los pasa a una utilidad de conversión (código fuente de muestra disponible aquí).

La utilidad de conversión invoca FFMpeg para realizar la conversión y marca cada video como procesado.

También desarrollamos un mecanismo simple de estimación del tiempo de espera, que calcula el tiempo promedio para convertir 1 minuto de video. Usando este promedio, podemos calcular y mostrarle al usuario el tiempo de procesamiento restante estimado después de que un video haya terminado de cargarse, en función de cuántos minutos de video quedan por procesar.

Conversión de formato de vídeo

Ciertos formatos reconocidos universalmente (como JPEG y GIF) han surgido para imágenes fijas que son esencialmente compatibles con todos los dispositivos y software de procesamiento de imágenes. Si bien algunos formatos de video son más comunes que otros, aún no ha surgido un formato compatible universalmente para videos.

En nuestro caso, además de necesitar convertir de una variedad de formatos a un solo formato común (MPEG-4), necesitábamos optimizar los videos convertidos para transmitirlos a dispositivos móviles.

Para la conversión de formato de video (al menos para nuestras necesidades a corto plazo), usar Amazon Elastic Transcoder basado en la nube fue la mejor opción disponible. Además de su facilidad de uso general, el servicio de transcodificador se ocupa de la optimización y de todos los ajustes de codificación. Afortunadamente, está disponible un SDK de AWS para PHP, lo que simplifica la invocación del servicio desde nuestro código PHP.

Nota: El uso de un servicio basado en la nube como Amazon Elastic Transcoder es excelente si desea comenzar a funcionar rápidamente. Sin embargo, tenga en cuenta que esta opción puede resultar costosa para su cliente, especialmente si es probable que su modelo comercial requiera un uso extensivo de videos de gran tamaño. Otro factor a considerar es que no debe asumir necesariamente que los videos o el modelo comercial de su cliente serán compatibles con los Términos de servicio.

Amazon utiliza sus elementos básicos de almacenamiento y cómputo, S3 (Simple Storage Service) y EC2 (Elastic Compute Cloud), combinados con Auto Scaling y SNS (Simple Notification Service), para brindar la capacidad de escalar hacia arriba y hacia abajo de forma prácticamente instantánea.

La instalación de aws-sdk es simple, ya que Amazon mantiene una versión del paquete que se puede instalar con Composer. Simplemente agregue ”aws/aws-sdk-php": "2.*" a su archivo composer.json y realice una composer update .

Obviamente, acceder a Amazon Elastic Transcoder requiere una cuenta de Amazon, por lo que también deberá configurarla si usted (o su cliente) aún no tiene una.

Nuestro uso del servicio Amazon Elastic Transcoder implicaba primero cargar archivos de video en un depósito apropiado en S3. Luego, hicimos que el trabajo del transcodificador fuera responsable de decodificar y generar una miniatura que, al finalizar, envía una solicitud HTTP a la dirección especificada. Esto requiere alguna configuración en el panel de AWS, pero es bastante simple y Amazon proporciona buena documentación sobre cómo hacerlo.

No dude en utilizar nuestro paquete de transcodificador, que ayuda a simplificar la integración de Symfony 2. Incluye una descripción de uso y ofrece un controlador para la implementación rápida de un servicio de notificación enviado por Amazon para recopilar información sobre el video procesado. Un ejemplo de uso está disponible aquí.

Además, aquí está disponible un controlador de ejemplo que maneja las notificaciones de Amazon, que también implementa la confirmación de una dirección de suscripción. El servicio primero publicará la URL para visitar para confirmar que este es un receptor de notificación válido. Entonces, todo lo que realmente se requiere es marcar el video como procesado. A partir de ahí, podemos utilizar el vídeo transcodificado que está almacenado en la nube.

Transmisión

La transmisión de video es una capacidad que requiere un alto rendimiento: las expectativas de los usuarios para la transmisión ininterrumpida son altas y la tolerancia a la latencia es extremadamente baja. Este desafío a menudo se ve agravado por la necesidad de transmitir video a múltiples clientes simultáneamente en tiempo real.

En nuestro caso, necesitábamos ayudar a que cada usuario pudiera crear su propio canal de video y comenzar a transmitir. Nuestra solución constaba de tres componentes:

  • Tablero. Aplicación que sirve como panel de control de un streamer, brindando la capacidad de servir video.
  • Espectador. Cliente de video que consume y muestra una transmisión de video.
  • Motor de transmisión. Servicio de transmisión de video basado en la nube.

Además del hecho de que la tecnología de video a pedido (VOD) todavía está evolucionando, otro problema que enfrentamos fue que el acceso a la cámara no estaba bien respaldado y solo ofrecía una conexión P2P. Además, nuestro objetivo era proporcionar transmisión en línea para múltiples usuarios simultáneos. Además, la compatibilidad con la API getUserMedia/Stream (anteriormente prevista como el elemento <device> ) aún no es uniforme en los navegadores modernos. En base a estos factores, decidí usar la tecnología Flash ya que era realmente la única opción razonable. Por lo tanto, ambas aplicaciones (Dashboard y Viewer) se implementaron utilizando Flex y ActionScript .

Para el motor de transmisión, usamos Wowza . Aunque existen otras soluciones no comerciales (como Red5, que se comercializa esencialmente como un reemplazo directo de Wowza), en nuestro caso, el soporte de productos comerciales fue un factor importante. Además, al menos en el momento en que estábamos construyendo el sistema, Wowza ofrecía una mejor documentación, lo que era una ventaja adicional. (Tenga en cuenta que puede obtener una versión de prueba de Wowza gratis durante 30 días y también hay una versión de prueba para desarrolladores que puede usar hasta 180 días. Pero existen algunas limitaciones; la transmisión solo puede funcionar para dos clientes y hay un límite en el número máximo de conexiones.)

Motor de transmisión Wowza

Usamos la aplicación LiveStream provista con Wowza. Para configurarlo, deje applications/app_name vacío y en conf/app_name copie el archivo Application.xml del catálogo conf . Edite el archivo para configurar la sección <Streams> de la siguiente manera:

 <Streams> <StreamType>live</StreamType> <StorageDir>${com.wowza.wms.context.VHostConfigHome}/content</StorageDir> <KeyDir>${com.wowza.wms.context.VHostConfigHome}/keys</KeyDir> <LiveStreamPacketizers></LiveStreamPacketizers> <Properties></Properties> </Streams>

El parámetro clave es <StreamType>live</StreamType> que define que será una transmisión de un video en vivo (por ejemplo, una cámara). Tenga en cuenta que después de editar y guardar este archivo, deberá reiniciar Wowza.

Aplicaciones Flash (Flex/ActionScript)

Flash proporciona un sistema totalmente integrado para conectar una cámara y un micrófono a un servidor de transmisión de Wowza. Esto es particularmente útil si su experiencia con ActionScript es limitada.

Toda la aplicación se basa esencialmente en la interacción entre los siguientes objetos:

  • Conexión de red. La clase NetConnection crea una conexión bidireccional entre un cliente y un servidor. El cliente puede ser una aplicación Flash Player o AIR. El servidor puede ser un servidor web, Flash Media Server, un servidor de aplicaciones que ejecute Flash Remoting o el servicio Adobe Stratus.
  • Cámara. La clase Camera se usa para capturar video desde el sistema cliente o la cámara del dispositivo.
  • Micrófono. La clase Microphone se usa para monitorear o capturar audio desde un micrófono.
  • NetStream. La clase NetStream abre un canal de transmisión unidireccional a través de NetConnection.

Primero, nos conectamos al servidor de transmisión de Wowza usando la instancia de NetConnection y luego adjuntamos el detector de eventos que escuchará los cambios en el estado de la conexión de red:

 nc = new NetConnection(); nc.connect(serverAddress:string); nc.addEventListener( NetStatusEvent.NET_STATUS, // event type eNetStatus, // listener function false, // use capture? 0, // priority true // use weak reference? );

Aquí hay un ejemplo minimalista de un detector de eventos que conecta la cámara y el micrófono al servidor de transmisión:

 private function eNetStatus(e:NetStatusEvent):void { switch (e.info.code) { case "NetConnection.Connect.Success": camera = Camera.getCamera(); mic = Microphone.getMicrophone(); ns = new NetStream(nc); ns.publish(streamName, "live"); ns.attachCamera(camera); ns.attachAudio(mic); break; case "NetConnection.Connect.Closed": // debug trace... display user message break; }

El código del cliente es muy similar, excepto que solo mostramos la entrada de video en el lado del usuario. Esto se hace conectando la transmisión al objeto Video , como se muestra en este sencillo ejemplo:

 if(event.info.code == "NetConnection.Connect.Success") { ns = new NetStream(nc); ns.client = nsClient; ns.addEventListener(NetStatusEvent.NET_STATUS, nsClient.onNetStatus); ns.play(streamName); video = new Video(); addChild(video); // this will display video video.attachNetStream(ns); // connect NetStream to video }

Envolver

Se puede esperar que la transmisión en vivo y el video desempeñen un papel cada vez más importante en las aplicaciones móviles y web. Por lo tanto, es importante que los desarrolladores web se familiaricen con la transcodificación, el procesamiento y la transmisión de video. Numerosas herramientas, bibliotecas y servicios existen hoy en día para incorporar estas capacidades en las aplicaciones web. Este artículo muestra cómo aprovechamos e integramos varias de estas tecnologías para crear con éxito un sitio básico similar a YouTube con relativa facilidad.