2012-11-15 17 views
8

Attualmente sto cercando di utilizzare Android come endpoint Skype. A questo punto, ho bisogno di codificare il video in H.264 (poiché è l'unico formato supportato da Skype) e incapsularlo con RTP per far funzionare lo streaming.Uso MediaCodec per streaming H264

Apparentemente il MediaRecorder non è molto adatto per questo per vari motivi. Uno è perché aggiunge le intestazioni MP4 o 3GP dopo che è finito. Un altro è perché al fine di ridurre al minimo la latenza, l'accelaration dell'hardware può tornare utile. Ecco perché mi piacerebbe utilizzare le recenti aggiunte di basso livello al framework, essendo MediaCodec, MediaExtractor, ecc.

Al momento, ho intenzione di lavorare come segue. La fotocamera scrive il suo video in un buffer. MediaCodec codifica il video con H264 e scrive il risultato su un altro buffer. Questo buffer viene letto da un encapsulator RTP, che invia i dati del flusso al server. Ecco la mia prima domanda: questo piano ti sembra fattibile?

Ora sono già bloccato con il primo passaggio. Poiché tutta la documentazione su Internet sull'uso della fotocamera fa uso di MediaRecorder, non riesco a trovare un modo per memorizzare i dati grezzi in un buffer prima della codifica. addCallbackBuffer è adatto per questo? Qualcuno ha un link con un esempio?

Successivamente, non riesco a trovare molta documentazione su MediaCodec (dal momento che è abbastanza nuovo). Chiunque abbia un solido tutorial?

Infine: eventuali consigli sulle librerie RTP?

Grazie mille in anticipo!

risposta

5

Non so ancora nulla su MediaCodec o MediaExtractor, ma sono abbastanza familiare con MediaRecorder e ho implementato con successo un server RTSP, basato su SpyDroid, che cattura l'output H264/AMRNB da MediaRecorder. L'idea di base è che il codice crea una coppia di socket locale e utilizza setOutputFile del MediaRecorder per scrivere l'output su uno degli zoccoli della coppia. Quindi, il programma legge il flusso video o audio dall'altro socket, lo analizza in pacchetti e quindi avvolge ciascun pacchetto in uno o più pacchetti RTP che vengono inviati su UDP.

È vero che MediaRecorder aggiunge le intestazioni MOOV dopo che è terminato, ma non è un problema se stai servendo video H264 in formato RTP. Fondamentalmente, c'è un'intestazione "mdat" all'inizio del flusso video. Ha 4 byte per la lunghezza dell'intestazione, seguito dai 4 byte "mdat". Leggi la lunghezza per scoprire per quanto tempo è l'intestazione, verifica che sia l'intestazione mdat e poi salta il resto dei dati dell'intestazione. Da lì in poi, si ottiene un flusso di unità NAL, che iniziano con 4 byte per la lunghezza dell'unità. Piccole unità NAL possono essere inviate in un singolo pacchetto RTP e unità più grandi vengono suddivise in pacchetti FU. Per RTSP, devi anche pubblicare un'intestazione SDP che descriva lo stream. SpyDroid calcola le informazioni nell'intestazione SDP scrivendo un filmato molto breve sul file, quindi legge questo file per estrarre l'intestazione MOOV dalla fine. La mia app utilizza sempre la stessa dimensione, formato e velocità in bit, quindi ho solo servire una stringa statica:

public static final String SDP_STRING = 
     "m=video 5006 RTP/AVP 96\n" 
       + "b=RR:0\n" 
       + "a=rtpmap:96 H264/90000\n" 
       + "a=fmtp:96 packetization-mode=1;profile-level-id=428028;sprop-parameter-sets=Z0KAKJWgKA9E,aM48gA==;\n" 
       + "a=control:trackID=0\n" 
       + "m=audio 5004 RTP/AVP 96\n" 
       + "b=AS:128\n" 
       + "b=RR:0\n" 
       + "a=rtpmap:96 AMR/8000\n" 
       + "a=fmtp:96 octet-align=1;\n" 
       + "a=control:trackID=1\n"; 

Questa è la mia intestazione per 640x480x10fps, il video H264, con audio 8000/16/1 AMRNB.

Una cosa di cui posso avvertirti: Se stai usando MediaRecorder, la tua richiamata di anteprima non verrà mai chiamata. Funziona solo in modalità fotocamera, non quando si registra un video. Non sono stato in grado di trovare alcun modo per accedere all'immagine di anteprima in formato non compresso mentre il video sta registrando.

Consiglio vivamente di consultare il codice per SpyDroid. Ci vuole un po 'a scavare, ma scommetto che quello che vuoi è già lì dentro.

+0

So che questo commento è molto tardi (non sono sicuro se questo è consentito o meno), ma ora che sono passati 3 anni, è ancora rilevante o ci sono modi migliori per farlo ora? –

0

Ciò che si pianifica è sicuramente fattibile. È possibile registrare un Camera.PreviewCallback che acquisisce i dati dell'immagine e li inserisce in MediaCodec. Leggi l'output e invialo come RTP. In generale è facile, ma ci sono varie insidie ​​come spazi di colore non documentati e diversi comportamenti di MediaCodec su dispositivi diversi, ma è sicuramente possibile.

8

UPDATE
sono stato finalmente in grado di creare adeguati pacchetti RTP dai telai H264. Ecco cosa devi tenere a mente (in realtà è piuttosto semplice):

Il codificatore crea intestazioni NAL per ciascun frame. Ma restituisce ogni fotogramma come un h264 a doppio schermo. Ciò significa che ogni frame inizia con tre 0 byte e un 1 byte. Tutto quello che devi fare è rimuovere quei prefissi di partenza e mettere il frame in un pacchetto RTP (o dividerli usando FU-As).

Ora alle tue domande:

non riesco a trovare un modo per archiviare i propri dati grezzi in un buffer prima della codifica. AddCallbackBuffer è adatto per questo?

È necessario utilizzare camera.setPreviewCallback (...) e aggiungere ciascun frame all'encoder.

Non riesco a trovare molta documentazione su MediaCodec (dato che è abbastanza nuovo). Chiunque abbia un solido tutorial?

Questa dovrebbe essere una buona introduzione su come funziona MediaCodec. http://dpsm.wordpress.com/2012/07/28/android-mediacodec-decoded/

Infine: eventuali consigli sulle librerie RTP?

Sto usando jlibrtp che porta a termine il lavoro.

Problemi correlati