2012-02-14 20 views
5

Para fines de investigación, estoy tratando de modificar vectores de movimiento H.264 (MV) para cada fotograma P y B antes de la compensación de movimiento durante el proceso de decodificación. Estoy usando FFmpeg para este propósito. Un ejemplo de una modificación es reemplazar cada MV con sus vecinos espaciales originales y luego usar los MV resultantes para la compensación de movimiento, en lugar de los originales. Por favor dirígeme apropiadamente.Modificación de vectores de movimiento en ffmpeg decodificador H.264

Hasta ahora, he podido hacer una modificación simple de MVs en el archivo /libavcodec/h264_cavlc.c. En la función, ff_h264_decode_mb_cavlc(), modificando mx y mis variables, por ejemplo, al aumentar sus valores se modifican los MV utilizados durante la decodificación.

Por ejemplo, como se muestra a continuación, la mx y mis valores se incrementan en 50, alargando así las MVs utilizados en el decodificador.

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

Sin embargo, en este sentido, no sé cómo acceder a los vecinos de mx y mi para mi análisis espacial que he mencionado en el primer párrafo significar. Creo que la clave para hacerlo radica en la manipulación de la matriz, mv_cache.

Otro experimento que realicé estaba en el archivo, libavcodec/error_resilience.c. De acuerdo con la función guess_mv(), creé una nueva función, mean_mv() que se ejecuta en ff_er_frame_end() dentro de la primera instrucción if. Esa primera instrucción if sale de la función ff_er_frame_end() si una de las condiciones es un recuento de errores cero (s-> error_count == 0). Sin embargo, decidí insertar mi función mean_mv() en este punto para que siempre se ejecute cuando hay un recuento de errores cero. Este experimento produjo un poco los resultados que quería, ya que podía comenzar a ver artefactos en las partes superiores del video, pero estaban restringidos solo a la esquina superior derecha. Supongo que mi función insertada no se está completando para cumplir con los plazos de reproducción o algo así.

A continuación se muestra la instrucción If modificada. La única adición es mi función, 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; 

y aquí está la mean_mv() función que crea basándose en 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]); 

      //} 
     } 
    } 
} 

Realmente agradecería algo de ayuda sobre cómo hacerlo correctamente.

Respuesta

2

Hacía mucho tiempo que no mantenía contacto con el código de FFMPEG internamente.

Sin embargo, dada mi experiencia con los horrores de FFMPEG (sabrá a qué me refiero), preferiría darle un consejo pragmático simple.

Sugerencia # 1
mejor posibilidad es que cuando se identifican vector de movimiento de cada uno de los bloques - puede crear su propia serie adicional dentro de contexto codificador FFmpeg (a.k.a s) que almacenará todos ellos. Cuando su algoritmo se ejecuta, recogerá los valores desde allí.

Sugerencia # 2
Otra cosa que he leído (no estoy seguro si he leído bien)

el MX y mis valores se incrementaron en un 50

creo que 50 es un vector de movimiento muy grande . Y, por lo general, la codificación del vector de rango de movimiento del valor F sería restrictiva antes. Si altera las cosas por +/- 8 (o incluso +/- 16) podría estar bien, pero +50 podría ser tan alto que el resultado final puede no codificar las cosas correctamente.

No entendí bien su objetivo sobremean_mv()y qué falla espera de allí. Por favor, vuelva a redactar un poco.

+0

Gracias por su comentario. Veré su primera sugerencia. En cuanto a su segunda sugerencia, corresponde algo a mis hallazgos. Cuando leo los valores del vector de movimiento ('mx' y' my') en 'h264_cavlc.c', obtengo valores extraordinariamente grandes, como 500. Eso es muy irrazonable a menos que exista una escala tal como por el factor propuesto de 50 De lo contrario, no sé por qué los valores de vectores de movimiento son tan grandes. – qontranami

+0

En cuanto a 'mean_mv()' considere un P-frame. El soporte de B-frame se agregará más tarde. El cuadro P contiene macrobloques con vectores de movimiento (MV). Vamos a agrupar esos MV en un conjunto llamado 'a'. Ahora, el trabajo de 'mean_mv()' es producir un nuevo conjunto de vectores de movimiento, 'b', que reemplazará' a' como el conjunto final de MV. Cada MV en 'b' es una versión modificada del MV correspondiente en' a'. Una manera de modificar un MV en 'a' es tomando el promedio espacial de los MVs circundantes en 'a' y colocando el resultado en 'b'. De esta forma, puedo investigar la efectividad de la media espacial y otras técnicas para la ocultación de errores. – qontranami

+0

'mean_mv()' es realmente una idea fantástica. Esto también puede ayudar a adivinar el vector de movimiento global (en estilo MPEG4-v2). Y también, dado que conoces el movimiento promedio de la escena, puedes comenzar toda la predicción desde allí en lugar de '(0,0)'. La mejor suerte cavando 'ffmpeg' –

Cuestiones relacionadas