Expression Encoder Object Model

image

Per poter implementare una completa architettura per l'erogazione dei contenuti video in formato windows media, oltre all'infrastruttura per l'erogazione dei filmati di cui in un precedente post ho illustrato le principali componenti, svolge un ruolo particolarmente importante l'infrastruttura per la codifica dei file che permette la preparazione dei contenuti che dovranno poi essere distribuiti e consumati.

La nuova versione del tool Microsoft Expression Encoder 2 che nasce proprio per permettere  la codifica dei video, oltre a poter essere utilizzato direttamente dalla interfaccia utente del tool, offre anche un modello ad oggetti esposto attraverso delle librerie .NET che consentono di pilotarne le funzionalità attraverso nostre applicazioni. Queste nuove librerie permettono con  semplicità di agganciare le funzionalità dell'encoder a sistemi di Content Management o altre applicazioni che sui nostri siti vengono appunto utilizzate per gestire i contenuti  da parte della redazione del sito Internet , intranet in cui vogliamo aggiungere una parte di contenuti video.

Si possono ad esempio sviluppare servizi che sfruttando un event watcher sul file system , possono pilotare la codifica di video partendo dal loro inserimento in una specifica directory. Si posono sviluppare servizi  che ricevono le informazioni dei video da codificare e procedono automaticamente a codifica e pubblicazione, sfruttando ad esempio code asincrone come MSMQ o dei Web Service  per la ricezione dei dati dei video e Workflow Foundation per gestire in modo flessibile il processo di pubblicazione.

Le librerie che vengono esposte dal tool sono dei classici assembly .NET che possono facilmente essere utilizzate da qualsiasi progetto  Visual Studio, sia esso una Web Application , sia un applicazione a finestre o un servizio windows. Disponible anche un SDK per Expression Encoder che potete scaricare e che contiene documentazione ed esempi.

Di seguito un immagine del modello ad oggetti esposto:

Full Object Hierarchy

Per poter sfruttare il modello ad oggetti occorre referenziare le tre librerie esposte dall'Encoder che sono illustrate nella seguente immagine e che trovate successivamente all'installazione di Microsoft Expression Encoder 2 .

image

Occorre anche selezionare WindowsBase perchè alcuni tipi contenuti nelle classi derivano da ObservableCollection .

Referenziate le librerie si può accedere alle classi  esposte dalle librerie dell'Encoder importando il seguente namespace principale:

using Microsoft.Expression.Encoder;

La classe principale che ci permette di gestire un "lavoro" di codifica è per l'appunto la classe Job. Attraverso una collezione di MediaItems , la classe Job ci consente di definire le attività di codifica da realizzare, definire la directory di output  e di avviare le codifiche  attraverso il metodo Encode. La classe Job espone poi una serie di eventi che permettono di ricevere notifiche relative allo stato di avanzamento del Job come ad esempio gli eventi:

public event EventHandler<EncodeCompletedEventArgs> EncodeCompleted

 public event EventHandler<EncodeProgressEventArgs> EncodeProgress
 public event EventHandler<StartFileEncodingEventArgs> StartFileEncoding

La classe MediaItem consente di rappresentare le informazioni realtive al Media da codificare , comprese le informazioni di codifica che devono essere realizzate. La classe consente anche di ottenere le informazioni sulla attuale configurazione del contenuto media.

Per poter codificare uno specifico filmato ad esempio da un formato .avi ottenuto da una telecamera in un formato wmv ottimizzato per l'erogazione ad esempio in streming con uno specifico profilo di birate, dimensioni del video etc , si procede via codice a definire con la classe MediaItem il filmato da codificare come ad esempio:

MediaItem mediaItem = new MediaItem(@"C:\ingresso\videotest.avi");

con le proprietà  VideoProfile e AudioProfile si possono modificare le impostazioni della codifica come ad esempio bitrate e dimensioni del video:

mediaItem.VideoProfile.Bitrate = 64000;

mediaItem.VideoProfile.Height = 80;

mediaItem.VideoProfile.Width = 120;

Attraverso la classe VideoProfile è possibile anche caricare ed assegnare al MediaItem un profilo tra quelli salvati nei template di ExpressionEncoder utilizzando lo specifico nome assegnato al profilo:

mediaItem.VideoProfile = Microsoft.Expression.Encoder.Profiles.VideoProfile.FindProfile("VC-1 Streaming 512k DSL modificato");

Attraverso la classe Job si defisisce un nuovo Job e si inserisce il mediaItem nella collezione del Job, si definisce la directory di output  e con Encode si avvia il lavoro:

Job job = new Job();
job.MediaItems.Add(mediaItem);

job.OutputDirectory = @"C:\videocodificati";

job.Encode();

Per provare il modello ad oggetti ho implementato un piccolo progetto windows form contenente un classe che  consente di gestire l'encoding utilizzando un thread diverso da quello di UI per evitare di bloccare l'intefraccia utente e consentire così il refresh dei dati di progresso di avanzamento del Job

image

Di seguito il codice della classe che pilota l'encoding:

public class EncodeJob
   {

       protected string _inputFile;
       protected string _outputFile;
       protected string _videoProfile;
       protected string _audioProfile;

       protected new EventHandler<EncodeProgressEventArgs> _callback;
       public EncodeJob(string inputFile, string  outputFile, EventHandler<EncodeProgressEventArgs> callBack,string  videoProfile, string  audioProfile)
       {
           _inputFile=inputFile;
           _outputFile=outputFile;
           _videoProfile=videoProfile;
           _audioProfile=audioProfile;
           _callback = callBack;
       }

       public void StartEncoding()
       {
           System.Threading.ThreadPool.QueueUserWorkItem(new WaitCallback(this._doEncoding));       
       }

       protected void  _doEncoding(object state)
       {
           MediaItem mediaItem = new MediaItem(_inputFile);

           Job job = new Job();
           job.EncodeProgress += _callback ;

           if (string.IsNullOrEmpty(_videoProfile) == false)
             mediaItem.VideoProfile = Microsoft.Expression.Encoder.Profiles.VideoProfile.FindProfile(_videoProfile );
           if (string.IsNullOrEmpty (_audioProfile)==false )
             mediaItem.AudioProfile = Microsoft.Expression.Encoder.Profiles.AudioProfile.FindProfile(_audioProfile); 

           job.MediaItems.Add(mediaItem);            // Set the output directory and encode
           job.OutputDirectory = _outputFile;
           job.Encode();

       }
   }

Che viene lanciata dal codice inserito sull'evento click del bottone inserito nell'interfaccia windows form:

private void button1_Click(object sender, EventArgs e)
      {
          EncodeJob job = new EncodeJob(@"C:\video\input\capodeicapi.avi", @"C:\video\output",new EventHandler<EncodeProgressEventArgs>(job_EncodeProgress), "VC-1 Streaming 512k DSL modificato", "");

          job.StartEncoding();
      }

La callback che riceve le notifiche di avanzamento del lavoro di codifica è gestita dal seguente codice che riporta sul thread della UI l'aggiornamento di una label con il valore della progressione del lavoro di encoding:

void job_EncodeProgress(object sender, EncodeProgressEventArgs e)
        {
            if (this.InvokeRequired)
            {
                label1.Invoke(new EventHandler<EncodeProgressEventArgs>(job_EncodeProgress), new object[] { sender, e });  
            }
            else
            {
                label1.Text = e.Progress.ToString();
            }
        }

Come potete vedere dal codice sopra, all'invocazione del metodo StartEncoding sull' istanza della classe EncodeJob su cui sono stati impostati i valori per l'encoding e la callback , viene utilizzato il ThreadPool di .NET per accodare l'esecuzione del metodo _doEncoding  sul primo thread libero dal threadpool , svincolando l'esecuzione dell'encoding dal thread di UI. Il metodo _doEncoding  utilizza le classi dell'encoder per definire e gestire un il nuovo Job. Le notifiche di progressione vengono ricevute dal thread di background dal metodo di callback impostato  e riaccodate sulla pompa dei messaggi del thread di UI con il metodo invoke. Il piccolo esempio descritto sopra lo potete scaricare da qui .

Oltre ad esporre un modello che consente di pilotare la codifica, Expression Encoder  ci mette a disposizione la possibilità di estendere l'interfaccia del tool costruendo  dei plugin come ad esempio i plugin di publishing (attraverso l'implementazione di una classe che deriva da PublishPlugin) che consentono di agganciare il tool Expression Encoder direttamente ad un vostro sistema di publishing. Ulteriori informazioni, compreso un esempio di pluging di pubblicazione le trovate all'interno dell'SDK di Expression Encoder 2 , dove trovate anche altri esempi di utilizzo delle classi esposte dal Tool.