Video online con Wowza e Amazon Elastic Transcoder

Pubblicato: 2022-03-11

Il successo e l'adozione di qualsiasi app Web oggi dipendono fortemente dalle sue prestazioni, flessibilità e facilità d'uso.

Soprattutto nel mondo ADHD di oggi, gli utenti perderanno rapidamente la pazienza con un'app se il caricamento della pagina richiede troppo tempo. Per le app Web che devono supportare l'elaborazione video, che è intrinsecamente ad alta intensità di elaborazione e I/O, questa sfida è particolarmente acuta. Tuttavia, gli utenti stanno diventando sempre più esigenti, poiché desiderano che i loro video siano di alta qualità e si carichino rapidamente, anche se in esecuzione su uno smartphone o un tablet.

Gli utenti stanno inoltre perdendo la tolleranza per le app Web che non funzionano sul browser o dispositivo preferito o che non supportano il formato dei dati che devono caricare o esportare. La diversità dei formati video che devono essere supportati, quindi, rende particolarmente impegnativo anche l'incorporazione del supporto video in un'app Web.

Questo post descrive come ho sfruttato efficacemente le tecnologie open source e i servizi basati su cloud per incorporare funzionalità video in un'app Web basata su PHP.

Video online Elaborazione in PHP con Wowza e Amazon Elastic Transcoder

Caso d'uso

Facevo parte di un team che aveva bisogno di sviluppare un sito web simile a YouTube, dove gli utenti registrati potessero caricare e condividere i propri video.

Il sistema doveva consentire agli utenti registrati di caricare i propri video in una varietà di formati supportati che sarebbero poi stati convertiti in un formato comune (MP4). Avevamo anche bisogno di generare una serie di miniature e un collage di immagini da utilizzare nel lettore video per mostrare i fotogrammi su una barra di avanzamento del video.

Le cose erano ulteriormente complicate dal fatto che i requisiti del cliente ci impedivano di utilizzare qualsiasi CDN o API di transcodifica disponibile, quindi dovevamo sviluppare la nostra soluzione da zero.

Caricamento video

Dal momento che il processo di caricamento in sé non doveva essere specifico per il video (ci serviva solo una capacità di caricamento dei file facile da usare), aveva senso utilizzare una soluzione open source esistente anziché utilizzare la nostra. Abbiamo selezionato jQuery-File-Upload, principalmente perché supportava due funzionalità che erano essenziali nel nostro caso; vale a dire, una barra di avanzamento del caricamento e caricamenti in blocchi.

Il caricamento in blocchi ci ha consentito di consentire a un utente di caricare un file video di qualsiasi dimensione (particolarmente importante per supportare i file video con risoluzione HD). Con questo approccio, il file è diviso in più "blocchi" sul front-end che richiama l'azione di caricamento con ogni blocco di dati (insieme ai metadati per ciascun blocco, come il numero del blocco e la dimensione totale del file). Il file video completo viene quindi riassemblato sul back-end. Per inciso, includere il numero di blocchi nei metadati si è rivelato particolarmente importante poiché alcuni browser (come Mobile Safari) hanno la tendenza a trasmettere i blocchi in ordine casuale.

Elaborazione video online

L'elaborazione video può essere semplice come acquisire fotogrammi come immagini fisse o può comportare operazioni più complesse come il miglioramento dell'immagine, la stabilizzazione del flusso video e così via. Nel nostro caso, gli unici requisiti di elaborazione video erano (a) estrarre codec video e altri metadati chiave e (b) generare una serie di miniature e un collage di immagini (da utilizzare nel lettore video per mostrare i fotogrammi sull'avanzamento di un video sbarra).

FFmpeg , una libreria open source ampiamente utilizzata, distribuita gratuitamente, è stata estremamente utile per soddisfare questi requisiti. FFmpeg fornisce una soluzione completa e multipiattaforma per la registrazione, la conversione e lo streaming di file audio e video. Può anche essere utilizzato per convertire video ed eseguire semplici modifiche (ad esempio, ritaglio, taglio, aggiunta di una filigrana, ecc.).

Per i nostri scopi, siamo stati in grado di utilizzare FFmpeg per dividere il video in dieci sezioni e quindi acquisire una miniatura per ciascuna sezione per fornire la funzionalità necessaria.

Sfortunatamente, però, non ci sono collegamenti del linguaggio PHP per la libreria FFmpeg. Di conseguenza, l'unico modo per sfruttare FFmpeg da PHP è invocare il binario dalla riga di comando usando i comandi di sistema. Esistono fondamentalmente due modi per utilizzare FFmpeg in PHP:

  • libav. Libav è un progetto di software libero, biforcato da FFmpeg nel 2011, che produce librerie e programmi per la gestione di dati multimediali. Su Ubuntu, ad esempio, questo può essere installato con il comando sudo apt-get install libav-tools . I comandi libav sono compatibili con FFmpeg e avconv. PHP deve avere accesso alla riga di comando a ffmpeg/avconv per usarlo a livello di codice.
  • PHP-FFMpeg. PHP-FFMpeg è un driver PHP orientato agli oggetti per il binario FFMpeg. È possibile accedervi semplicemente eseguendo composer update "php-ffmpeg/php-ffmpeg" .

Abbiamo utilizzato PHP-FFMpeg poiché fornisce un facile accesso alla funzionalità FFmpeg a cui eravamo interessati. Ad esempio, la classe FFProbe di questo pacchetto consente di ricevere informazioni sui codec o sulla lunghezza di un particolare file video come segue:

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

FFmpeg semplifica anche il salvataggio di qualsiasi fotogramma video:

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

Un codice di esempio più dettagliato è disponibile qui.

Una nota di cautela: a causa di alcune leggi sui brevetti, non tutti i codec possono essere elaborati da FFmpeg e alcuni formati non sono supportati correttamente (o completamente). Ricordo di aver lottato un paio di anni fa, ad esempio, con il formato .3gp quando il supporto per i feature phone era un must.

In coda

Dopo aver ottenuto i codec di un video e altri metadati, inseriamo il video in una coda di conversione FIFO (first in first out). La coda è stata implementata utilizzando un semplice script cron che seleziona un determinato numero di video non elaborati ogni volta che viene eseguito e li passa a un'utilità di conversione (codice sorgente di esempio disponibile qui).

L'utilità di conversione richiama FFMpeg per eseguire la conversione e contrassegna ogni video come elaborato.

Abbiamo anche sviluppato un semplice meccanismo di stima del tempo di attesa, che calcola il tempo medio per convertire 1 minuto di video. Utilizzando questa media, siamo in grado di calcolare e visualizzare per l'utente il tempo di elaborazione rimanente stimato al termine del caricamento di un video, in base a quanti minuti di video rimangono da elaborare.

Conversione del formato video

Alcuni formati universalmente riconosciuti (come JPEG e GIF) sono emersi per i fermi immagine che sono essenzialmente supportati da tutti i dispositivi e software di elaborazione delle immagini. Sebbene alcuni formati video siano più comuni di altri, per i video non è ancora emerso alcun formato supportato universalmente.

Nel nostro caso, oltre a dover convertire da una varietà di formati in un unico formato comune (MPEG-4), avevamo bisogno che i video convertiti fossero ottimizzati per lo streaming su dispositivi mobili.

Per la conversione del formato video (almeno per le nostre esigenze a breve termine), l'utilizzo di Amazon Elastic Transcoder basato su cloud è stata la migliore opzione disponibile. Oltre alla sua facilità d'uso generale, il servizio transcoder si occupa dell'ottimizzazione e di tutte le impostazioni di codifica. Fortunatamente, è disponibile un SDK AWS per PHP, che semplifica il richiamo del servizio dal nostro codice PHP.

Nota: l'utilizzo di un servizio basato su cloud come Amazon Elastic Transcoder è ottimo se desideri iniziare a funzionare rapidamente. Tuttavia, tieni presente che questa opzione può diventare costosa per il tuo cliente, soprattutto se è probabile che il suo modello di business richieda un uso estensivo di video di grandi dimensioni. Un altro fattore da considerare è che non dovresti necessariamente presumere che i video o il modello di business del tuo cliente siano compatibili con i Termini di servizio.

Amazon utilizza i suoi elementi di archiviazione e calcolo di base, S3 (Simple Storage Service) ed EC2 (Elastic Compute Cloud), combinati con Auto Scaling e SNS (Simple Notification Service), per offrire la possibilità di aumentare e diminuire in modo praticamente istantaneo.

L'installazione di aws-sdk è semplice, poiché Amazon mantiene una versione del pacchetto installabile da Composer. Aggiungi semplicemente ”aws/aws-sdk-php": "2.*" al tuo file composer.json ed esegui un composer update .

Ovviamente, l'accesso ad Amazon Elastic Transcoder richiede un account Amazon, quindi dovrai anche configurarlo se tu (o il tuo cliente) non ne avete già uno.

Il nostro utilizzo del servizio Amazon Elastic Transcoder ha comportato il primo caricamento di file video in un bucket appropriato su S3. Abbiamo quindi reso il lavoro di transcodificatore responsabile della decodifica e della generazione di una miniatura che, al termine, invia una richiesta HTTP all'indirizzo specificato. Ciò richiede una certa configurazione nel pannello AWS, ma è abbastanza semplice e Amazon fornisce una buona documentazione su come farlo.

Sentiti libero di utilizzare il nostro pacchetto transcoder, che aiuta a semplificare l'integrazione per Symfony 2. Include una descrizione dell'utilizzo e offre un controller per una rapida implementazione di un servizio di avviso inviato da Amazon per raccogliere informazioni sul video elaborato. Un esempio di utilizzo è disponibile qui.

Inoltre, qui è disponibile un controller di esempio che gestisce le notifiche Amazon che implementa anche la conferma di un indirizzo di abbonamento. Il servizio pubblicherà prima l'URL da visitare per confermare che questo è un destinatario di notifica valido. Tutto ciò che è veramente necessario è contrassegnare il video come elaborato. Da quel momento in poi, possiamo utilizzare il video transcodificato archiviato nel cloud.

Streaming

Lo streaming video è una funzionalità che richiede prestazioni elevate: le aspettative degli utenti per lo streaming ininterrotto sono elevate e la tolleranza per la latenza è estremamente bassa. Questa sfida è spesso esacerbata dalla necessità di trasmettere video in streaming a più client contemporaneamente in tempo reale.

Nel nostro caso, dovevamo supportare ogni utente nella possibilità di creare il proprio canale video e iniziare a trasmettere. La nostra soluzione era composta da tre componenti:

  • Pannello. Applicazione che funge da dashboard di uno streamer, offrendo la possibilità di pubblicare video.
  • Spettatore. Client video che consuma e visualizza un flusso video.
  • Motore di streaming. Servizio di streaming video basato su cloud.

Oltre al fatto che la tecnologia Video on Demand (VOD) è ancora in evoluzione, un altro problema che abbiamo dovuto affrontare è stato che l'accesso alla telecamera non era ben supportato e offriva solo una connessione P2P. Inoltre, il nostro obiettivo era fornire la trasmissione online per più utenti simultanei. Inoltre, il supporto per l'API getUserMedia/Stream (precedentemente concepita come elemento <device> ) non è ancora coerente tra i browser moderni. Sulla base di questi fattori, ho deciso di utilizzare la tecnologia Flash poiché era davvero l'unica scelta ragionevole. Entrambe le applicazioni (Dashboard e Viewer) sono state quindi implementate utilizzando Flex e ActionScript .

Per il motore di streaming, abbiamo utilizzato Wowza . Sebbene esistano altre soluzioni non commerciali (come Red5, commercializzato essenzialmente come un sostituto dropin di Wowza), nel nostro caso il supporto commerciale del prodotto è stato un fattore importante. Inoltre, almeno nel momento in cui stavamo creando il sistema, Wowza offriva una documentazione migliore, il che rappresentava un ulteriore vantaggio. (Nota che puoi ottenere una versione di prova di Wowza gratuitamente per 30 giorni e c'è anche una versione di prova per sviluppatori che puoi utilizzare per un massimo di 180 giorni. Ma ci sono alcune limitazioni; lo streaming può funzionare solo per due client e c'è un limite sul numero massimo di connessioni.)

Motore di streaming Wowza

Abbiamo utilizzato l'applicazione LiveStream fornita con Wowza. Per configurarlo, lascia vuoto applications/app_name e in conf/app_name copia il file Application.xml dal catalogo conf . Modifica il file per configurare la sezione <Streams> come segue:

 <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>

Il parametro chiave è <StreamType>live</StreamType> che definisce che questo sarà uno stream da un feed video live (ad esempio, una telecamera). Nota che dopo aver modificato e salvato questo file, dovrai riavviare Wowza.

Applicazioni Flash (Flex/ActionScript).

Flash fornisce un sistema completamente integrato per collegare una fotocamera e un microfono a un server di streaming Wowza. Ciò è particolarmente utile se la tua esperienza con ActionScript è limitata.

L'intera applicazione si basa essenzialmente sull'interazione tra i seguenti oggetti:

  • Connessione di rete. La classe NetConnection crea una connessione bidirezionale tra un client e un server. Il client può essere un'applicazione Flash Player o AIR. Il server può essere un server Web, Flash Media Server, un server delle applicazioni che esegue Flash Remoting o il servizio Adobe Stratus.
  • Telecamera. La classe Camera viene utilizzata per acquisire video dal sistema client o dalla fotocamera del dispositivo.
  • Microfono. La classe Microphone viene utilizzata per monitorare o acquisire l'audio da un microfono.
  • Netstream. La classe NetStream apre un canale di streaming unidirezionale su NetConnection.

Innanzitutto, ci colleghiamo al server di streaming Wowza utilizzando l'istanza NetConnection e quindi colleghiamo il listener di eventi che ascolterà le modifiche allo stato della connessione di rete:

 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? );

Ecco un esempio minimalista di listener di eventi che collega la telecamera e il microfono al server di streaming:

 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; }

Il codice client è molto simile, tranne per il fatto che visualizziamo solo l'input video sul lato utente. Questo viene fatto collegando lo stream all'oggetto Video , come mostrato in questo semplice esempio:

 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 }

Incartare

Ci si può aspettare che lo streaming live e il video svolgano un ruolo sempre più significativo nelle applicazioni mobili e web. È quindi importante che gli sviluppatori web acquisiscano familiarità con la transcodifica, l'elaborazione e lo streaming video. Oggi esistono numerosi strumenti, librerie e servizi per incorporare queste capacità nelle applicazioni web. Questo articolo mostra come abbiamo sfruttato e integrato una serie di queste tecnologie per creare con successo un sito di base simile a YouTube con relativa facilità.