2014-04-15 15 views
6

[AGGIORNATO CON RISPOSTA PARZIALE]
Ecco il mio codice:Ottieni frame dal video con libvlc smem e convertilo in opencv Mat. (C++)

void cbVideoPrerender(void *p_video_data, uint8_t **pp_pixel_buffer, int size) { 
    // Locking 
    imageMutex.lock(); 
    videoBuffer = (uint8_t *)malloc(size); 
    *pp_pixel_buffer = videoBuffer; 
} 
void cbVideoPostrender(void *p_video_data, uint8_t *p_pixel_buffer 
     , int width, int height, int pixel_pitch, int size, int64_t pts) { 
    // Unlocking 
    imageMutex.unlock(); 
    Mat img = Mat(Size(width,height), CV_8UC3, p_pixel_buffer); 
    //cvtColor(img,img,CV_RGB2BGR); 
} 
int main(int argc, char ** argv) 
{ 
    libvlc_instance_t * inst; 
    char smem_options[1000]; 
    sprintf(smem_options 
     , "#transcode{vcodec=RV24}:smem{" 
     "video-prerender-callback=%lld," 
     "video-postrender-callback=%lld," 
     "video-data=%lld," 
     "no-time-sync}," 
     , (long long int)(intptr_t)(void*)&cbVideoPrerender 
     , (long long int)(intptr_t)(void*)&cbVideoPostrender //This would normally be useful data, 100 is just test data 
     , (long long int)200 //Test data 
    ); 
    const char * const vlc_args[] = { 
       "-I", "dummy", // Don't use any interface 
       "--ignore-config", // Don't use VLC's config 
       "--extraintf=logger", // Log anything 
       "--verbose=1", // Be verbose 
       "--sout", smem_options // Stream to memory 
       }; 

    // We launch VLC 
    inst = libvlc_new(sizeof(vlc_args)/sizeof(vlc_args[0]), vlc_args); 
... 
return 0; 
} 

domanda aggiornato
ho controllato le mie due funzioni di callback sembrano eseguite correttamente.
_Che tipo di dati RV32 emette esattamente? Si colloca il CV_8U3C (8bits unsigned int 3 canali richiesto qui _DO ho bisogno di aggiungere un passaggio per la mia classe di Mat (passo -?? Numero di byte occupa ogni riga della matrice)
UPDATED2
ho cambiato RV32 a RV24 che ha più senso. Aggiungo cvtColor perché la matrice Mat sembra aver bisogno di BGR pixel e non RGB ma l'immagine non è visualizzata correttamente
_C'è un vcodec che mi darebbe un formato YUV come output in modo da poter testare il pixel dati prima di provare ad emettere un opencv :: Mat img?
[EDIT OUTPUT IMG] (Cambiando il tipo vlc in CV_8UC4 a quattro canali (non so perché) possiamo quasi vedere il fotogramma ma in veramente povero qua Perché è così? img updated 2
[SOLUZIONE]
ho scoperto che le immagini all'inizio del mio video erano di scarsa qualità è per questo che il mio Mat imshow() mi ha mostrato una cosa brutta il codice di cui sopra dovrebbe funzionare ora (Apperently senza bisogno di cvtColor)

+0

afaik, i pixel sono in p_pixel_buffer, non in p_video_data. inoltre, non dovrebbe lo sblocco() passare * dopo * l'impostazione dei pixel del Mat? – berak

+0

Anch'io ho avuto questo pensiero, ma come posso assegnare il mio array di pixel al costruttore Mat? – grll

+0

nello stesso modo, lo fai ora. basta cambiare i nomi dei corrieri – berak

risposta

5

In primo luogo, un avvertimento rapido: a partire da VLC2.2 (versione git corrente, da rilasciare a breve), il parametro size è un size_t. Non ci sono API per smem (ancora? Si spera che questo cambierà), che fa schifo, quindi questo silenziosamente interromperà la tua applicazione.

Quindi, un rapido commento sul parametro "dati": deve contenere ciò che è necessario per eseguire l'elaborazione. Essendo un puntatore a una struttura, un'istanza di una classe, tu la dai un nome. Dubito fortemente che passare un lungo tempo potrebbe funzionare su una macchina a 32 bit, dato che dovresti forzare 64 bit in qualcosa che può contenere solo 32. Quello che dovresti fare è dichiarare una struttura e memorizzare ciò che ti serve. Ecco un buon esempio:

struct MyParamStruct 
{ 
    YourMutexType imageMutex; // Here mutex is not a global variable anymore 
    int otherParam; // You can use this to store the value 200 that you were passing before 
}; 
//... 

// Init the struct somewhere 
MyParamStruct* param = new MyStructParam; 
param->otherParam = 200; 
//... 

sprintf(smem_options 
     , "#transcode{vcodec=h264}:smem{" 
     "video-prerender-callback=%lld," 
     "video-postrender-callback=%lld," 
     "video-data=%lld," 
     "no-time-sync}," 
     , (long long int)(intptr_t)(void*)&cbVideoPrerender 
     , (long long int)(intptr_t)(void*)&cbVideoPostrender //This would normally be useful data, 100 is just test data 
     , (long long int)(intptr_t)(void*)param 
    ); 

Informazioni sull'utilizzo di mutex, mi sembra buono. In realtà sembra che non ci siano problemi di concorrenza qui, dato che assegni in modo sincrono un nuovo buffer per ogni frame. Se si stesse utilizzando un buffer preallocato ogni volta, è necessario considerare il blocco quando si esce dalla funzione postrender.

In effetti non sono nemmeno sicuro di quale sia esattamente il puntatore vuoto p_video_data.

Dipende dal formato dell'immagine. Per H264, dipenderebbe dal formato pixel che verrà emesso dal decodificatore. Dato che stai richiedendo l'output H264, è probabile che otterrai un formato pixel planare, sebbene il tipo esatto dipenda dal tuo profilo H264.

Se ci si aspetta dati non elaborati come risultato (il che sembra essere il caso, visto che CV_8UC3 sembra riferirsi a un'immagine raw a 3 canali, dopo una rapida occhiata a google), ti consiglio di passare a RV32 : #transcode{vcodec=RV32}

Quello che è necessario passare al modulo di transcodifica è il vostro uscita fourcc, VLC si occuperà con l'ingresso per voi :)

Aggiornamento

non ho idea se la classe Mat prende la proprietà del tuo puntatore, ma potresti wa nt per controllare anche quello.

Update 2

Per rispondere alla tua domanda ulteriore su ciò che è RV32:

/* 24 bits RGB */ 
#define VLC_CODEC_RGB24   VLC_FOURCC('R','V','2','4') 
/* 24 bits RGB padded to 32 bits */ 
#define VLC_CODEC_RGB32   VLC_FOURCC('R','V','3','2') 
/* 32 bits RGBA */ 
#define VLC_CODEC_RGBA   VLC_FOURCC('R','G','B','A') 

se si prevede solo 3 byte, allora probabilmente dovrebbe RV24 una prova! Probabilmente avrei dovuto suggerirlo sin dall'inizio, dal momento che l'8CU3 suggerisce decisamente solo 3 byte ...