2009-11-20 10 views
16

La nuova roba della webcam in Silverlight 4 è dannatamente cool. Esponendolo come un pennello, consente scenari che vanno ben oltre qualsiasi cosa che Flash ha.Streaming di una webcam da Silverlight 4 (Beta)

Allo stesso tempo, l'accesso alla webcam localmente sembra che sia solo metà della storia. Nessuno compra una webcam in modo da poter scattare foto di se stessi e fare facce buffe da loro. Comprano una webcam perché vogliono che le altre persone vedano il flusso video risultante, cioè, vogliono trasmettere il video in streaming a Internet, un laico Skype o una qualsiasi delle dozzine di altri siti/applicazioni di chat video. E finora, non ho capito come farlo con

Si scopre che è piuttosto semplice ottenere una sospensione del raw (Format32bppArgb formattato) da test, come dimostrato here.

Ma a meno che non desideriamo trasmettere quel grezzo puntatore ad un server (che potrebbe trangugiare troppo banda), dobbiamo codificarlo in qualche modo. E questo è più complicato. MS ha implementato diversi codec in Silverlight, ma per quanto posso dire, sono tutti focalizzati sulla decodifica di un flusso video, non sulla codifica in primo luogo. E questo a parte il fatto che non riesco a capire come ottenere l'accesso diretto, per esempio, al codec H.264, in primo luogo.

Ci sono un sacco di codec open source (ad esempio, nel progetto ffmpeg here), ma sono tutti scritti in C, e non sembrano facili da portare in C#. A meno che non traducendo 10000+ righe di codice che assomigliano a questa è la vostra idea di divertimento :-)

const int b_xy= h->mb2b_xy[left_xy[i]] + 3; 
const int b8_xy= h->mb2b8_xy[left_xy[i]] + 1; 
*(uint32_t*)h->mv_cache[list][cache_idx ]= *(uint32_t*)s->current_picture.motion_val[list][b_xy + h->b_stride*left_block[0+i*2]]; 
*(uint32_t*)h->mv_cache[list][cache_idx+8]= *(uint32_t*)s->current_picture.motion_val[list][b_xy + h->b_stride*left_block[1+i*2]]; 
h->ref_cache[list][cache_idx ]= s->current_picture.ref_index[list][b8_xy + h->b8_stride*(left_block[0+i*2]>>1)]; 
h->ref_cache[list][cache_idx+8]= s->current_picture.ref_index[list][b8_xy + h->b8_stride*(left_block[1+i*2]>>1)]; 

La cartella mooncodecs nell'ambito del progetto Mono (here) ha diversi codec audio in C# (ADPCM e Ogg Vorbis), e un codec video (Dirac), ma sembrano tutti implementare solo la parte di decodifica dei rispettivi formati, così come le implementazioni java da cui sono stati portati.

Ho trovato un codec C# per Ogg Theora (csTheora, http://www.wreckedgames.com/forum/index.php?topic=1053.0), ma ancora una volta, è solo decodificare, come è il codec jheora su cui è basato.

Ovviamente, sarebbe presumibilmente più semplice effettuare il porting di un codec da Java che da C o C++, ma gli unici codec video java che ho trovato erano solo decodificati (come jheora o jirac).

Quindi sono tornato al punto di partenza. Sembra che le nostre opzioni per collegare una webcam (o un microfono) tramite Silverlight a Internet siano:

(1) Aspettare che Microsoft fornisca indicazioni su questo;

(2) Passa i cicli cerebrali a trasferire uno dei codec C o C++ su C# compatibile con Silverlight;

(3) Inviare il sommario, non compresso su un server (o forse leggermente compresso con qualcosa come zlib), quindi codificarlo sul lato server; oppure

(4) Attendere qualcuno più intelligente di me per capirlo e fornire una soluzione.

Qualcun altro ha una guida migliore? Ho perso qualcosa che è semplicemente apparentemente ovvio per tutti gli altri? (Ad esempio, Silverlight 4 da qualche parte ha alcune classi che ho perso che si prendono cura di questo?)

risposta

3

Ho pensato di far sapere alle persone interessate l'approccio che effettivamente ho preso. Sto usando CSpeex per codificare la voce, ma ho scritto il mio codec video basato su blocchi per codificare il video. Divide ciascun frame in blocchi 16x16, determina quali blocchi sono sufficientemente modificati per meritare la trasmissione, e quindi codifica in Jpeg i blocchi modificati utilizzando una versione pesantemente modificata di FJCore. (FJCore è generalmente ben fatto, ma doveva essere modificato per non scrivere le intestazioni JFIF e per accelerare l'inizializzazione dei vari oggetti.) Tutto questo viene passato a un server multimediale proprietario usando un protocollo proprietario basato approssimativamente su RTP.

Con uno stream up e quattro stream down a 144x176, attualmente ottengo 5 frame al secondo, utilizzando un totale di 474 Kbps (~ 82 Kbps/stream video + 32 Kbps/audio) e masticando circa 30 % CPU nella mia casella di sviluppo. La qualità non è eccezionale, ma è accettabile per la maggior parte delle applicazioni di chat video.

Da quando ho inviato la mia domanda iniziale, ci sono stati diversi tentativi di implementare una soluzione. Probabilmente il migliore è sul sito web SocketCoder here (e here).

Tuttavia, poiché il codec video in stile JPEG di Motion SocketCoder traduce la totalità di ogni frame anziché solo i blocchi che sono stati modificati, suppongo che i requisiti di CPU e larghezza di banda saranno proibitivi per la maggior parte delle applicazioni.

Purtroppo, la mia soluzione sta per avere a rimanere proprietaria per il prossimo futuro :-(

Edit 7/3/10:.. Ho appena ricevuto autorizzazioni per condividere le mie modifiche alla biblioteca FJCore I' ve postato il progetto (senza alcun codice di esempio, purtroppo) qui:

http://www.alanta.com/Alanta.Client.Media.Jpeg.zip

Un esempio (molto approssimativa) di come usarlo:

public void EncodeAsJpeg() 
    { 
     byte[][,] raster = GetSubsampledRaster(); 
     var image = new Alanta.Client.Media.Jpeg.Image(colorModel, raster); 
     EncodedStream = new MemoryStream(); 
     var encoder = new JpegFrameEncoder(image, MediaConstants.JpegQuality, EncodedStream); 
     encoder.Encode(); 
    } 


    public void DecodeFromJpeg() 
    { 
     EncodedStream.Seek(0, SeekOrigin.Begin); 
     var decoder = new JpegFrameDecoder(EncodedStream, height, width, MediaConstants.JpegQuality); 
     var raster = decoder.Decode(); 
    } 

Molte delle mie modifiche riguardano le due nuove classi JpegFrameEncoder (anziché JpegEncoder) e JpegFrameDecoder (anziché JpegDecoder). Fondamentalmente, JpegFrameEncoder scrive il frame codificato senza intestazioni JFIF e JpegFrameDecoder decodifica il frame senza aspettarsi alcun header JFIF per dirgli quali valori usare (si presuppone che condividerai i valori in qualche altro modo fuori banda). Crea istantaneamente qualsiasi oggetto di cui ha bisogno solo una volta (come "statico"), in modo da poter istanziare rapidamente JpegFrameEncoder e JpegFrameDecoder, con un sovraccarico minimo. Le classi preesistenti di JpegEncoder e JpegDecoder dovrebbero funzionare più o meno come hanno sempre fatto, anche se ho fatto solo un po 'di test per confermarlo.

Ci sono molte cose che mi piacerebbe migliorare (non mi piacciono gli oggetti statici - dovrebbero essere istanziati e passati separatamente), ma al momento funziona abbastanza bene per i nostri scopi. Spero sia utile per qualcun altro. Vedrò se riesco a migliorare il codice/documentazione/codice di esempio/ecc. se ho tempo.

+0

Grazie per l'esempio, Ken. Ho un'applicazione Silverlight che mi piacerebbe poter consentire di caricare i video creati dagli utenti su Facebook. Tuttavia, anche se ho la codifica m-jpeg funzionante, non è un codec supportato tramite FB. Grrrr. È un peccato che la SM non ci stia aiutando. – tyshock

3

Ho appena ricevuto questa risposta da Jason Clary sul mio blog:


visto il tuo post sul blog di Mike Taulty circa VideoSink/AudioSink in Silverlight 4 Beta.

Ho pensato di sottolineare che OnSample di VideoSink offre un singolo frame ARGB 32 bit non compresso che può essere copiato direttamente in un WritableBitmap.

Con questo in mano afferrare FJCore, un codec jpeg in C#, e modificarlo per non emettere l'intestazione JFIF. Quindi basta scriverli uno dopo l'altro e ti sei procurato un codec Motion JPEG. RFC2435 spiega come riempirlo nei pacchetti RTP per lo streaming RTSP.

La compressione audio PCM in ADPCM è abbastanza semplice, ma non ho ancora trovato un'implementazione già pronta. RFC3551 spiega come inserire PCM o ADPCM in pacchetti RTP.

Dovrebbe anche essere ragionevolmente facile inserire MJPEG e PCM o ADPCM in un file AVI. MS ha alcuni documenti decenti sul formato RIFF modificato di AVI e sia MJPEG che ADPCM sono ampiamente supportati dai codec.

È comunque un inizio.

Naturalmente, una volta che avrete superato tutti i problemi, la prossima Beta probabilmente uscirà con il supporto nativo per la compressione e lo streaming su WMS con i codec WMV molto migliori.


Ho pensato di pubblicarlo. È il miglior consiglio che ho visto finora.

0

Aggiungerò un altro commento. Ho appena saputo da un contatto Microsoft che Microsoft è non e che prevede di aggiungere qualsiasi supporto per la codifica/streaming audio e video a Silverlight, quindi l'opzione n. 1 sembra essere fuori dal tavolo, almeno per ora. La mia ipotesi è che capire il supporto per questo sarà responsabilità della comunità, cioè, fino a te e me.

0

Stop-Gap?

È possibile utilizzare il codificatore di Windows Media come metodo di compressione per il video raw fornito da Silverlight? Dopo l'acquisizione su ISO Storage, codificare con WME e inviare al server tramite il WebClient. Due grandi temi sono:

  • richiede all'utente di installare il codificatore
  • WME non sarà più supportato

Sembra che potrebbe essere una soluzione tappabuchi fino a quando arriva qualcosa di meglio lungo. Non ho ancora lavorato con WME, quindi non so quanto sarebbe fattibile. Pensieri?

+0

Oltre alla necessità per gli utenti di installare Codificatore di Windows Media, Silverlight non sarebbe in grado di parlare con WME a meno che l'app non stia funzionando fuori dal browser e in modalità Fiducia totale: a quel punto, non è più completamente chiaro il motivo per cui dobbiamo farlo in Silverlight :-). –

-4
+0

A meno che non manchi qualcosa di enorme, WME non è una soluzione per la codifica in tempo reale di Silverlight sul lato client. –

+0

Ti sei perso qualcosa. Questo non è WME. Perché fa QuickTime, H.264, AAC-LC, non tutti attualmente supportati in Windows Media Encoder. Fa anche AVI, MPEG-2 e altri. Non proprio sicuro della tua domanda, ma questo è il nucleo dello strumento Microsoft Expressions Endcoder, che è un'app lato client e supporta molto più del semplice formato Windows Media. –

+0

Nick, l'enfasi di Ken non è su "WME" ma su "tempo reale". –

Problemi correlati