概念: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);
}