Модификация векторов движения в декодере ffmpeg H.264 - PullRequest
5 голосов
/ 14 февраля 2012

В исследовательских целях я пытаюсь изменить векторы движения H.264 (MV) для каждого P- и B-кадра до компенсации движения во время процесса декодирования.Я использую FFmpeg для этой цели.Примером модификации является замена каждого MV его исходными пространственными соседями, а затем использование результирующих MV для компенсации движения, а не исходных.Пожалуйста, направьте меня соответствующим образом.

До сих пор я смог сделать простую модификацию MV в файле / libavcodec / h264_cavlc.c .В функции ff_h264_decode_mb_cavlc () , модифицируя переменные mx и my , например, путем увеличения их значений, модифицирует MV, используемые при декодировании.

Например, как показано ниже, значения mx и my увеличиваются на 50, что удлиняет MV, используемые в декодере.

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

Однако в этом отношении я не знаю, как получить доступ к соседям mx и my для моего анализа пространственного среднего, который я упоминал в первом абзаце.Я полагаю, что ключ к этому лежит в манипулировании массивом, mv_cache .

Другой эксперимент, который я провел, был в файле, libavcodec / error_resilience.c .На основе функции guess_mv () я создал новую функцию, mean_mv () , которая выполняется в ff_er_frame_end () в первом операторе if.Этот первый оператор if выходит из функции ff_er_frame_end () , если одним из условий является нулевой счетчик ошибок (s-> error_count == 0).Однако в этот момент я решил вставить свою функцию mean_mv () , чтобы она всегда выполнялась при нулевом количестве ошибок.Этот эксперимент несколько дал желаемые результаты, так как я мог начать видеть артефакты в верхних частях видео, но они были ограничены только правым верхним углом.Я предполагаю, что моя вставленная функция не завершена, чтобы уложиться в сроки воспроизведения или что-то в этом роде.

Ниже приведен модифицированный оператор if.Единственным дополнением является моя функция, 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;

А вот функция mean_mv () , которую я создал на основе 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]);

            //}
        }
    }
}

Буду очень признателен за помощь в правильном подходе.

1 Ответ

2 голосов
/ 14 февраля 2012

Я давно не общался с внутренним кодом FFMPEG.

Однако, учитывая мой опыт работы с внутренними ужасами FFMPEG (вы бы знали, что я имею в виду), я бы лучше дал вам простой прагматический совет.

Предложение № 1
Наилучшая возможность состоит в том, что когда вектор движения каждого из блоков идентифицирован - вы можете создать свой собственный дополнительный массив в контексте кодировщика FFMPEG (a.k.a s), который будет хранить все из них. Когда ваш алгоритм запустится, он получит значения оттуда.

Предложение № 2
Еще одна вещь, которую я прочитал (я не уверен, правильно ли я ее прочитал)

МХ и мои значения увеличены на 50

Я думаю, что 50 - очень большой вектор движения. И, как правило, диапазон F-значения кодирования вектора движения был бы ранее ограничительным. Если вы измените вещи на +/- 8 (или даже +/- 16), это может быть просто нормально, но +50 может быть настолько высоким, что конечный результат может не кодировать вещи должным образом.

Я не совсем понял вашу цель относительно mean_mv() и какого сбоя вы ожидаете от него. Пожалуйста, перефразируйте немного.

...