ffmpeg错误隐藏:guess_dc分析

概念:DC系数和AC系数

图像DCT变换的公式


当u=v=0时,有,直流系数F(0,0)称为DC系数,

可知DC系数反映了图像像素的平均值,包含了图像能量的主要部分

以8×8的DCT变换为例,第一个系数为DC系数,其余63个系数为AC系数。

图像中像素间灰度变化缓慢,所以相邻块的DC系数接近;


guess_dc对Intra类型的宏块做DC系数的恢复,以8×8块为单位,通过上下左右四个方向的正确解码块的DC系数插值得到受损块的DC系数。


static void guess_dc(ERContext *s, int16_t *dc, int w,
                     int h, int stride, int is_luma)
{
    int b_x, b_y;
    int16_t  (*col )[4] = av_malloc_array(stride, h*sizeof( int16_t)*4);
    uint32_t (*dist)[4] = av_malloc_array(stride, h*sizeof(uint32_t)*4);

    if(!col || !dist) {
        av_log(s->avctx, AV_LOG_ERROR, "guess_dc() is out of memory\n");
        goto fail;
    }

    for(b_y=0; b_y<h; b_y++){
        int color= 1024;
        int distance= -1;
        for(b_x=0; b_x<w; b_x++){                                //从左至右扫描,保存左边正确解码块的DC值和distance
            int mb_index_j= (b_x>>is_luma) + (b_y>>is_luma)*s->mb_stride;                  
            int error_j= s->error_status_table[mb_index_j];
            int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]);
            if(intra_j==0 || !(error_j&ER_DC_ERROR)){
                color= dc[b_x + b_y*stride];                       //将正确解码宏块的dc值和d_x保存到color和distance
                distance= b_x;
            }
            col [b_x + b_y*stride][1]= color;                             //当前块为错误块时,保存上一个正确块的dc值
            dist[b_x + b_y*stride][1]= distance >= 0 ? b_x-distance : 9999;//保存到上一个正确块的距离b_x-distance
        }
        color= 1024;
        distance= -1;
        for(b_x=w-1; b_x>=0; b_x--){                                       //从右至左,同上
            int mb_index_j= (b_x>>is_luma) + (b_y>>is_luma)*s->mb_stride;
            int error_j= s->error_status_table[mb_index_j];
            int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]);
            if(intra_j==0 || !(error_j&ER_DC_ERROR)){
                color= dc[b_x + b_y*stride];
                distance= b_x;
            }
            col [b_x + b_y*stride][0]= color;
            dist[b_x + b_y*stride][0]= distance >= 0 ? distance-b_x : 9999;
        }
    }
    for(b_x=0; b_x<w; b_x++){
        int color= 1024;
        int distance= -1;
        for(b_y=0; b_y<h; b_y++){                                             //从上至下
            int mb_index_j= (b_x>>is_luma) + (b_y>>is_luma)*s->mb_stride;
            int error_j= s->error_status_table[mb_index_j];
            int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]);
            if(intra_j==0 || !(error_j&ER_DC_ERROR)){
                color= dc[b_x + b_y*stride];
                distance= b_y;
            }
            col [b_x + b_y*stride][3]= color;
            dist[b_x + b_y*stride][3]= distance >= 0 ? b_y-distance : 9999;
        }
        color= 1024;
        distance= -1;
        for(b_y=h-1; b_y>=0; b_y--){                                       //从下至上
            int mb_index_j= (b_x>>is_luma) + (b_y>>is_luma)*s->mb_stride;
            int error_j= s->error_status_table[mb_index_j];
            int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]);
            if(intra_j==0 || !(error_j&ER_DC_ERROR)){
                color= dc[b_x + b_y*stride];
                distance= b_y;
            }
            col [b_x + b_y*stride][2]= color;
            dist[b_x + b_y*stride][2]= distance >= 0 ? distance-b_y : 9999;
        }
    }

    for (b_y = 0; b_y < h; b_y++) {
        for (b_x = 0; b_x < w; b_x++) {
            int mb_index, error, j;
            int64_t guess, weight_sum;
            mb_index = (b_x >> is_luma) + (b_y >> is_luma) * s->mb_stride;
            error    = s->error_status_table[mb_index];

            if (IS_INTER(s->cur_pic.mb_type[mb_index]))
                continue; // inter
            if (!(error & ER_DC_ERROR))
                continue; // dc-ok
            weight_sum = 0;
            guess      = 0;  
            for (j = 0; j < 4; j++) {                                    //插值得到Intra错误块的DC值                            
                int64_t weight  = 256 * 256 * 256 * 16 / FFMAX(dist[b_x + b_y*stride][j], 1);
                guess          += weight*(int64_t)col[b_x + b_y*stride][j];
                weight_sum     += weight;
            }
            guess = (guess + weight_sum / 2) / weight_sum;
            dc[b_x + b_y * stride] = guess;
        }
    }

fail:
    av_freep(&col);
    av_freep(&dist);
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值