2012-02-14 16 views
5

Per scopi di ricerca, sto cercando di modificare i vettori di movimento H.264 (MV) per ciascun fotogramma P e B prima della compensazione del movimento durante il processo di decodifica. Sto usando FFmpeg per questo scopo. Un esempio di modifica sta sostituendo ogni MV con i suoi vicini spaziali originali e quindi utilizzando i MV risultanti per la compensazione del movimento, piuttosto che quelli originali. Per favore indirizzami in modo appropriato.Modifica dei vettori di movimento nel decodificatore ffmpeg H.264

Finora, sono stato in grado di eseguire una semplice modifica di MV nel file /libavcodec/h264_cavlc.c. Nella funzione, ff_h264_decode_mb_cavlc(), la modifica delle variabili mx e my, ad esempio, aumentando i loro valori modifica le MV utilizzate durante la decodifica.

Ad esempio, come mostrato sotto, il mx e miei valori sono aumentati di 50, allungando le MV utilizzati nel decoder.

mx += get_se_golomb(&s->gb)+50; 
my += get_se_golomb(&s->gb)+50; 

Tuttavia, a questo proposito, non so come accedere i vicini di mx e mia per il mio spaziale significare l'analisi che ho citato nel primo paragrafo. Credo che la chiave per farlo risieda nella manipolazione dell'array, mv_cache.

Un altro esperimento che ho eseguito era nel file, libavcodec/error_resilience.c. In base alla funzione guess_mv(), ho creato una nuova funzione, mean_mv() che viene eseguita in ff_er_frame_end() all'interno della prima istruzione if. La prima istruzione if esce dalla funzione ff_er_frame_end() se una delle condizioni è un conteggio degli errori pari a zero (s-> error_count == 0). Tuttavia, ho deciso di inserire la mia funzione mean_mv() a questo punto in modo che venga sempre eseguita quando c'è un conteggio degli errori pari a zero. Questo esperimento ha in qualche modo prodotto i risultati che desideravo perché potevo iniziare a vedere gli artefatti nelle parti più alte del video, ma erano limitati solo nell'angolo in alto a destra. Immagino che la mia funzione inserita non venga completata in modo da rispettare le scadenze di riproduzione o qualcosa del genere.

Di seguito è riportata l'istruzione if modificata. L'unica aggiunta è la mia funzione, mean_mv (s).

if(!s->error_recognition || s->error_count==0 || s->avctx->lowres || 
     s->avctx->hwaccel || 
     s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU || 
     s->picture_structure != PICT_FRAME || // we dont support ER of field pictures yet, though it should not crash if enabled 
     s->error_count==3*s->mb_width*(s->avctx->skip_top + s->avctx->skip_bottom)) { 
     //av_log(s->avctx, AV_LOG_DEBUG, "ff_er_frame_end in er.c\n"); //KG 
     if(s->pict_type==AV_PICTURE_TYPE_P) 
      mean_mv(s); 
     return; 

Ed ecco il mean_mv() funzione I creati in base guess_mv().

static void mean_mv(MpegEncContext *s){ 
    //uint8_t fixed[s->mb_stride * s->mb_height]; 
    //const int mb_stride = s->mb_stride; 
    const int mb_width = s->mb_width; 
    const int mb_height= s->mb_height; 
    int mb_x, mb_y, mot_step, mot_stride; 

    //av_log(s->avctx, AV_LOG_DEBUG, "mean_mv\n"); //KG 

    set_mv_strides(s, &mot_step, &mot_stride); 

    for(mb_y=0; mb_y<s->mb_height; mb_y++){ 
     for(mb_x=0; mb_x<s->mb_width; mb_x++){ 
      const int mb_xy= mb_x + mb_y*s->mb_stride; 
      const int mot_index= (mb_x + mb_y*mot_stride) * mot_step; 
      int mv_predictor[4][2]={{0}}; 
      int ref[4]={0}; 
      int pred_count=0; 
      int m, n; 

      if(IS_INTRA(s->current_picture.f.mb_type[mb_xy])) continue; 
      //if(!(s->error_status_table[mb_xy]&MV_ERROR)){ 
      //if (1){ 
      if(mb_x>0){ 
       mv_predictor[pred_count][0]= s->current_picture.f.motion_val[0][mot_index - mot_step][0]; 
       mv_predictor[pred_count][1]= s->current_picture.f.motion_val[0][mot_index - mot_step][1]; 
       ref   [pred_count] = s->current_picture.f.ref_index[0][4*(mb_xy-1)]; 
       pred_count++; 
      } 

      if(mb_x+1<mb_width){ 
       mv_predictor[pred_count][0]= s->current_picture.f.motion_val[0][mot_index + mot_step][0]; 
       mv_predictor[pred_count][1]= s->current_picture.f.motion_val[0][mot_index + mot_step][1]; 
       ref   [pred_count] = s->current_picture.f.ref_index[0][4*(mb_xy+1)]; 
       pred_count++; 
      } 

      if(mb_y>0){ 
       mv_predictor[pred_count][0]= s->current_picture.f.motion_val[0][mot_index - mot_stride*mot_step][0]; 
       mv_predictor[pred_count][1]= s->current_picture.f.motion_val[0][mot_index - mot_stride*mot_step][1]; 
       ref   [pred_count] = s->current_picture.f.ref_index[0][4*(mb_xy-s->mb_stride)]; 
       pred_count++; 
      } 

      if(mb_y+1<mb_height){ 
       mv_predictor[pred_count][0]= s->current_picture.f.motion_val[0][mot_index + mot_stride*mot_step][0]; 
       mv_predictor[pred_count][1]= s->current_picture.f.motion_val[0][mot_index + mot_stride*mot_step][1]; 
       ref   [pred_count] = s->current_picture.f.ref_index[0][4*(mb_xy+s->mb_stride)]; 
       pred_count++; 
      } 

      if(pred_count==0) continue; 

      if(pred_count>=1){ 
       int sum_x=0, sum_y=0, sum_r=0; 
       int k; 

       for(k=0; k<pred_count; k++){ 
        sum_x+= mv_predictor[k][0]; // Sum all the MVx from MVs avail. for EC 
        sum_y+= mv_predictor[k][1]; // Sum all the MVy from MVs avail. for EC 
        sum_r+= ref[k]; 
        // if(k && ref[k] != ref[k-1]) 
        // goto skip_mean_and_median; 
       } 

       mv_predictor[pred_count][0] = sum_x/k; 
       mv_predictor[pred_count][1] = sum_y/k; 
       ref   [pred_count] = sum_r/k; 
      } 

      s->mv[0][0][0] = mv_predictor[pred_count][0]; 
      s->mv[0][0][1] = mv_predictor[pred_count][1]; 

      for(m=0; m<mot_step; m++){ 
       for(n=0; n<mot_step; n++){ 
        s->current_picture.f.motion_val[0][mot_index + m + n * mot_stride][0] = s->mv[0][0][0]; 
        s->current_picture.f.motion_val[0][mot_index + m + n * mot_stride][1] = s->mv[0][0][1]; 
       } 
      } 

      decode_mb(s, ref[pred_count]); 

      //} 
     } 
    } 
} 

Apprezzerei molto l'assistenza su come procedere correttamente.

risposta

2

È passato molto tempo che non ero più in contatto con il codice FFMPEG internamente.

Tuttavia, data la mia esperienza con gli orrori di FFMPEG (sapresti cosa intendo), preferirei darti un semplice consiglio pragmatico.

Suggerimento # 1
migliore possibilità è che quando sono identificati vettore di movimento di ciascuno dei blocchi - è possibile creare il proprio allineamento supplementare all'interno contesto encoder FFMPEG (a.k.a s), che memorizza tutti loro. Quando il tuo algoritmo funziona, raccoglierà i valori da lì.

Suggerimento # 2
Un'altra cosa che ho letto (non sono sicuro se ho letto bene)

MX ed i miei valori sono aumentati del 50

penso 50 è un grande vettore di movimento grande. E di solito, la codifica del vettore di movimento del campo di valori F sarebbe prima restrittiva. Se modifichi le cose di +/- 8 (o anche di +/- 16) potrebbe essere solo ok, ma +50 potrebbe essere così alto che il risultato finale potrebbe non codificare correttamente le cose con.

Non ho capito bene il tuo obiettivo sumean_mv()e quale fallimento ti aspetti da lì. Si prega di riformulare un po '.

+0

Grazie per il tuo commento. Esaminerò il tuo primo suggerimento Per quanto riguarda il tuo secondo suggerimento, corrisponde in qualche modo alle mie conclusioni. Quando leggo i valori dei vettori di movimento ('mx' e' my') in 'h264_cavlc.c', ottengo valori straordinariamente grandi come 500. Ciò è altamente irragionevole a meno che non ci sia un ridimensionamento, ad esempio dal fattore proposto di 50 Altrimenti, non so perché i valori dei vettori di movimento siano così grandi. – qontranami

+0

Per quanto riguarda 'mean_mv()' considera un P-frame. Il supporto del frame B verrà aggiunto in seguito. La P-frame contiene macroblocchi con i vettori di movimento (MV). Raggruppiamo quegli MV in un insieme chiamato 'a'. Ora, il lavoro di 'mean_mv()' è di produrre un nuovo insieme di vettori di movimento, 'b', che sostituirà' a' come set finale di MV. Ogni MV in 'b' è una versione modificata della MV corrispondente in' a'. Un modo per modificare una MV in 'a' è prendere la media spaziale delle MV circostanti in' a' e posizionare il risultato in 'b'. In questo modo, posso investigare l'efficacia della media spaziale e altre tecniche per l'occultamento degli errori. – qontranami

+0

'mean_mv()' è davvero un'idea fantastica. Ciò può anche aiutare a indovinare il vettore di movimento globale (nello stile MPEG4-v2). E inoltre, dato che conosci il movimento della scena media, puoi iniziare tutte le previsioni da lì piuttosto tan '(0,0)'. Buona fortuna a scavare 'ffmpeg' –