6

研究目的で、デコード処理中の動き補償の前に、各 P フレームと B フレームの H.264 動きベクトル (MV) を変更しようとしています。この目的のためにFFmpegを使用しています。変更の例としては、各 MV を元の空間近傍に置き換えてから、元の MV ではなく、結果の MV を動き補償に使用します。適当に誘導してください。

これまでのところ、ファイル/libavcodec/h264_cavlc.c内の MV を簡単に変更することができました。関数ff_h264_decode_mb_cavlc()では、mx変数とmy変数を変更します。たとえば、それらの値を増やすことで、デコード中に使用される MV が変更されます。

たとえば、以下に示すように、mxmy の値が 50 増加し、デコーダで使用される MV が長くなります。

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

ただし、この点に関して、最初の段落で述べた空間平均分析のためにmxmyの近傍にアクセスする方法がわかりません。そうするための鍵は、配列mv_cacheを操作することにあると思います。

私が実行した別の実験は、ファイルlibavcodec/error_resilience.cで行われました。guess_mv()関数に基づいて、最初の if ステートメント内のff_er_frame_end()で実行される新しい関数mean_mv()を作成しました。その最初の if ステートメントは、条件の 1 つがエラー カウントがゼロの場合 (s->error_count == 0) 、関数ff_er_frame_end()を終了します。ただし、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;

そしてこれが、 guess_mv()に基づいて作成したmean_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]);

            //}
        }
    }
}

これを適切に行う方法について、いくつかの支援をいただければ幸いです。

4

1 に答える 1

2

内部的にFFMPEGのコードに触れていないのは長い間です。

ただし、FFMPEG の恐怖の中での私の経験を考えると (私が何を意味するかわかるでしょう)、単純な実用的なアドバイスをしたいと思います。

提案#1最良の可能性は、各ブロックのモーションベクトルが識別されたときに、それらすべてを保存する
FFMPEGエンコーダーコンテキスト(別名)内に独自の追加配列を作成できることです。sアルゴリズムが実行されると、そこから値が取得されます。

提案#2
私が読んだもう1つのこと(正しく読んだかどうかわかりません)

mx と my の値が 50 増加します

50 は非常に大きなモーション ベクトルだと思います。そして通常、動きベクトル符号化の F 値範囲は事前に制限されます。+/- 8 (または +/- 16) だけ変更しても問題ないかもしれませんが、+50 が高すぎて、最終結果が適切にエンコードされない可能性があります。

mean_mv() あなたの目的と、そこから予想される失敗についてはよくわかりませんでした。ちょっと言い直してください。

于 2012-02-14T13:23:44.497 に答える