Error concealment of h264 with multiple references.

Originally committed as revision 22603 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
Michael Niedermayer 2010-03-20 00:52:08 +00:00
parent 1bafdcbd0a
commit 673fc6388f
1 changed files with 35 additions and 18 deletions

View File

@ -38,7 +38,7 @@
*/ */
#undef mb_intra #undef mb_intra
static void decode_mb(MpegEncContext *s){ static void decode_mb(MpegEncContext *s, int ref){
s->dest[0] = s->current_picture.data[0] + (s->mb_y * 16* s->linesize ) + s->mb_x * 16; s->dest[0] = s->current_picture.data[0] + (s->mb_y * 16* s->linesize ) + s->mb_x * 16;
s->dest[1] = s->current_picture.data[1] + (s->mb_y * (16>>s->chroma_y_shift) * s->uvlinesize) + s->mb_x * (16>>s->chroma_x_shift); s->dest[1] = s->current_picture.data[1] + (s->mb_y * (16>>s->chroma_y_shift) * s->uvlinesize) + s->mb_x * (16>>s->chroma_x_shift);
s->dest[2] = s->current_picture.data[2] + (s->mb_y * (16>>s->chroma_y_shift) * s->uvlinesize) + s->mb_x * (16>>s->chroma_x_shift); s->dest[2] = s->current_picture.data[2] + (s->mb_y * (16>>s->chroma_y_shift) * s->uvlinesize) + s->mb_x * (16>>s->chroma_x_shift);
@ -47,12 +47,16 @@ static void decode_mb(MpegEncContext *s){
H264Context *h= (void*)s; H264Context *h= (void*)s;
h->mb_xy= s->mb_x + s->mb_y*s->mb_stride; h->mb_xy= s->mb_x + s->mb_y*s->mb_stride;
memset(h->non_zero_count_cache, 0, sizeof(h->non_zero_count_cache)); memset(h->non_zero_count_cache, 0, sizeof(h->non_zero_count_cache));
fill_rectangle(&h->ref_cache[0][scan8[0]], 4, 4, 8, 0, 1); assert(ref>=0);
if(ref >= h->ref_count[0]) //FIXME it is posible albeit uncommon that slice references differ between slices, we take the easy approuch and ignore it for now. If this turns out to have any relevance in practice then correct remapping should be added
ref=0;
fill_rectangle(&s->current_picture.ref_index[0][4*h->mb_xy], 2, 2, 2, ref, 1);
fill_rectangle(&h->ref_cache[0][scan8[0]], 4, 4, 8, ref, 1);
fill_rectangle(h->mv_cache[0][ scan8[0] ], 4, 4, 8, pack16to32(s->mv[0][0][0],s->mv[0][0][1]), 4); fill_rectangle(h->mv_cache[0][ scan8[0] ], 4, 4, 8, pack16to32(s->mv[0][0][0],s->mv[0][0][1]), 4);
assert(h->list_count==1);
assert(!FRAME_MBAFF); assert(!FRAME_MBAFF);
ff_h264_hl_decode_mb(h); ff_h264_hl_decode_mb(h);
}else{ }else{
assert(ref==0);
MPV_decode_mb(s, s->block); MPV_decode_mb(s, s->block);
} }
} }
@ -397,7 +401,7 @@ static void guess_mv(MpegEncContext *s){
s->mb_y= mb_y; s->mb_y= mb_y;
s->mv[0][0][0]= 0; s->mv[0][0][0]= 0;
s->mv[0][0][1]= 0; s->mv[0][0][1]= 0;
decode_mb(s); decode_mb(s, 0);
} }
} }
return; return;
@ -417,6 +421,7 @@ int score_sum=0;
for(mb_x=0; mb_x<s->mb_width; mb_x++){ for(mb_x=0; mb_x<s->mb_width; mb_x++){
const int mb_xy= mb_x + mb_y*s->mb_stride; const int mb_xy= mb_x + mb_y*s->mb_stride;
int mv_predictor[8][2]={{0}}; int mv_predictor[8][2]={{0}};
int ref[8]={0};
int pred_count=0; int pred_count=0;
int j; int j;
int best_score=256*256*256*64; int best_score=256*256*256*64;
@ -450,60 +455,73 @@ int score_sum=0;
if(mb_x>0 && fixed[mb_xy-1]){ if(mb_x>0 && fixed[mb_xy-1]){
mv_predictor[pred_count][0]= s->current_picture.motion_val[0][mot_index - mot_step][0]; mv_predictor[pred_count][0]= s->current_picture.motion_val[0][mot_index - mot_step][0];
mv_predictor[pred_count][1]= s->current_picture.motion_val[0][mot_index - mot_step][1]; mv_predictor[pred_count][1]= s->current_picture.motion_val[0][mot_index - mot_step][1];
ref [pred_count] = s->current_picture.ref_index[0][4*(mb_xy-1)];
pred_count++; pred_count++;
} }
if(mb_x+1<mb_width && fixed[mb_xy+1]){ if(mb_x+1<mb_width && fixed[mb_xy+1]){
mv_predictor[pred_count][0]= s->current_picture.motion_val[0][mot_index + mot_step][0]; mv_predictor[pred_count][0]= s->current_picture.motion_val[0][mot_index + mot_step][0];
mv_predictor[pred_count][1]= s->current_picture.motion_val[0][mot_index + mot_step][1]; mv_predictor[pred_count][1]= s->current_picture.motion_val[0][mot_index + mot_step][1];
ref [pred_count] = s->current_picture.ref_index[0][4*(mb_xy+1)];
pred_count++; pred_count++;
} }
if(mb_y>0 && fixed[mb_xy-mb_stride]){ if(mb_y>0 && fixed[mb_xy-mb_stride]){
mv_predictor[pred_count][0]= s->current_picture.motion_val[0][mot_index - mot_stride*mot_step][0]; mv_predictor[pred_count][0]= s->current_picture.motion_val[0][mot_index - mot_stride*mot_step][0];
mv_predictor[pred_count][1]= s->current_picture.motion_val[0][mot_index - mot_stride*mot_step][1]; mv_predictor[pred_count][1]= s->current_picture.motion_val[0][mot_index - mot_stride*mot_step][1];
ref [pred_count] = s->current_picture.ref_index[0][4*(mb_xy-s->mb_stride)];
pred_count++; pred_count++;
} }
if(mb_y+1<mb_height && fixed[mb_xy+mb_stride]){ if(mb_y+1<mb_height && fixed[mb_xy+mb_stride]){
mv_predictor[pred_count][0]= s->current_picture.motion_val[0][mot_index + mot_stride*mot_step][0]; mv_predictor[pred_count][0]= s->current_picture.motion_val[0][mot_index + mot_stride*mot_step][0];
mv_predictor[pred_count][1]= s->current_picture.motion_val[0][mot_index + mot_stride*mot_step][1]; mv_predictor[pred_count][1]= s->current_picture.motion_val[0][mot_index + mot_stride*mot_step][1];
ref [pred_count] = s->current_picture.ref_index[0][4*(mb_xy+s->mb_stride)];
pred_count++; pred_count++;
} }
if(pred_count==0) continue; if(pred_count==0) continue;
if(pred_count>1){ if(pred_count>1){
int sum_x=0, sum_y=0; int sum_x=0, sum_y=0, sum_r=0;
int max_x, max_y, min_x, min_y; int max_x, max_y, min_x, min_y, max_r, min_r;
for(j=0; j<pred_count; j++){ for(j=0; j<pred_count; j++){
sum_x+= mv_predictor[j][0]; sum_x+= mv_predictor[j][0];
sum_y+= mv_predictor[j][1]; sum_y+= mv_predictor[j][1];
sum_r+= ref[j];
if(j && ref[j] != ref[j-1])
goto skip_mean_and_median;
} }
/* mean */ /* mean */
mv_predictor[pred_count][0] = sum_x/j; mv_predictor[pred_count][0] = sum_x/j;
mv_predictor[pred_count][1] = sum_y/j; mv_predictor[pred_count][1] = sum_y/j;
ref [pred_count] = sum_r/j;
/* median */ /* median */
if(pred_count>=3){ if(pred_count>=3){
min_y= min_x= 99999; min_y= min_x= min_r= 99999;
max_y= max_x=-99999; max_y= max_x= max_r=-99999;
}else{ }else{
min_x=min_y=max_x=max_y=0; min_x=min_y=max_x=max_y=min_r=max_r=0;
} }
for(j=0; j<pred_count; j++){ for(j=0; j<pred_count; j++){
max_x= FFMAX(max_x, mv_predictor[j][0]); max_x= FFMAX(max_x, mv_predictor[j][0]);
max_y= FFMAX(max_y, mv_predictor[j][1]); max_y= FFMAX(max_y, mv_predictor[j][1]);
max_r= FFMAX(max_r, ref[j]);
min_x= FFMIN(min_x, mv_predictor[j][0]); min_x= FFMIN(min_x, mv_predictor[j][0]);
min_y= FFMIN(min_y, mv_predictor[j][1]); min_y= FFMIN(min_y, mv_predictor[j][1]);
min_r= FFMIN(min_r, ref[j]);
} }
mv_predictor[pred_count+1][0] = sum_x - max_x - min_x; mv_predictor[pred_count+1][0] = sum_x - max_x - min_x;
mv_predictor[pred_count+1][1] = sum_y - max_y - min_y; mv_predictor[pred_count+1][1] = sum_y - max_y - min_y;
ref [pred_count+1] = sum_r - max_r - min_r;
if(pred_count==4){ if(pred_count==4){
mv_predictor[pred_count+1][0] /= 2; mv_predictor[pred_count+1][0] /= 2;
mv_predictor[pred_count+1][1] /= 2; mv_predictor[pred_count+1][1] /= 2;
ref [pred_count+1] /= 2;
} }
pred_count+=2; pred_count+=2;
} }
skip_mean_and_median:
/* zero MV */ /* zero MV */
pred_count++; pred_count++;
@ -511,6 +529,7 @@ int score_sum=0;
/* last MV */ /* last MV */
mv_predictor[pred_count][0]= s->current_picture.motion_val[0][mot_index][0]; mv_predictor[pred_count][0]= s->current_picture.motion_val[0][mot_index][0];
mv_predictor[pred_count][1]= s->current_picture.motion_val[0][mot_index][1]; mv_predictor[pred_count][1]= s->current_picture.motion_val[0][mot_index][1];
ref [pred_count] = s->current_picture.ref_index[0][4*mb_xy];
pred_count++; pred_count++;
s->mv_dir = MV_DIR_FORWARD; s->mv_dir = MV_DIR_FORWARD;
@ -530,7 +549,10 @@ int score_sum=0;
s->current_picture.motion_val[0][mot_index][0]= s->mv[0][0][0]= mv_predictor[j][0]; s->current_picture.motion_val[0][mot_index][0]= s->mv[0][0][0]= mv_predictor[j][0];
s->current_picture.motion_val[0][mot_index][1]= s->mv[0][0][1]= mv_predictor[j][1]; s->current_picture.motion_val[0][mot_index][1]= s->mv[0][0][1]= mv_predictor[j][1];
decode_mb(s); if(ref[j]<0) //predictor intra or otherwise not available
continue;
decode_mb(s, ref[j]);
if(mb_x>0 && fixed[mb_xy-1]){ if(mb_x>0 && fixed[mb_xy-1]){
int k; int k;
@ -568,7 +590,7 @@ score_sum+= best_score;
s->current_picture.motion_val[0][mot_index+i+j*mot_stride][1]= s->mv[0][0][1]; s->current_picture.motion_val[0][mot_index+i+j*mot_stride][1]= s->mv[0][0][1];
} }
decode_mb(s); decode_mb(s, ref[best_pred]);
if(s->mv[0][0][0] != prev_x || s->mv[0][0][1] != prev_y){ if(s->mv[0][0][0] != prev_x || s->mv[0][0][1] != prev_y){
@ -746,11 +768,6 @@ void ff_er_frame_end(MpegEncContext *s){
s->current_picture= *s->current_picture_ptr; s->current_picture= *s->current_picture_ptr;
} }
for(i=0; i<2; i++){
if(pic->ref_index[i])
memset(pic->ref_index[i], 0, size * sizeof(uint8_t));
}
if(s->avctx->debug&FF_DEBUG_ER){ if(s->avctx->debug&FF_DEBUG_ER){
for(mb_y=0; mb_y<s->mb_height; mb_y++){ for(mb_y=0; mb_y<s->mb_height; mb_y++){
for(mb_x=0; mb_x<s->mb_width; mb_x++){ for(mb_x=0; mb_x<s->mb_width; mb_x++){
@ -948,7 +965,7 @@ void ff_er_frame_end(MpegEncContext *s){
s->mb_x= mb_x; s->mb_x= mb_x;
s->mb_y= mb_y; s->mb_y= mb_y;
decode_mb(s); decode_mb(s, 0/*FIXME h264 partitioned slices need this set*/);
} }
} }
@ -990,7 +1007,7 @@ void ff_er_frame_end(MpegEncContext *s){
s->dsp.clear_blocks(s->block[0]); s->dsp.clear_blocks(s->block[0]);
s->mb_x= mb_x; s->mb_x= mb_x;
s->mb_y= mb_y; s->mb_y= mb_y;
decode_mb(s); decode_mb(s, 0);
} }
} }
}else }else