diff options
Diffstat (limited to 'libavcodec/error_resilience.c')
-rw-r--r-- | libavcodec/error_resilience.c | 228 |
1 files changed, 130 insertions, 98 deletions
diff --git a/libavcodec/error_resilience.c b/libavcodec/error_resilience.c index ae9ef68617..2b6bc42ade 100644 --- a/libavcodec/error_resilience.c +++ b/libavcodec/error_resilience.c @@ -3,20 +3,20 @@ * * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at> * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -46,23 +46,37 @@ static void decode_mb(MpegEncContext *s, int ref) s->dest[1] = s->current_picture.f.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.f.data[2] + (s->mb_y * (16 >> s->chroma_y_shift) * s->uvlinesize) + s->mb_x * (16 >> s->chroma_x_shift); + ff_init_block_index(s); + ff_update_block_index(s); + s->dest[1] += (16 >> s->chroma_x_shift) - 8; + s->dest[2] += (16 >> s->chroma_x_shift) - 8; + if (CONFIG_H264_DECODER && s->codec_id == AV_CODEC_ID_H264) { H264Context *h = (void*)s; 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)); - assert(ref >= 0); + av_assert1(ref >= 0); /* FIXME: It is possible albeit uncommon that slice references * differ between slices. We take the easy approach and ignore * it for now. If this turns out to have any relevance in * practice then correct remapping should be added. */ if (ref >= h->ref_count[0]) ref = 0; + if (!h->ref_list[0][ref].f.data[0]) { + av_log(s->avctx, AV_LOG_DEBUG, "Reference not available for error concealing\n"); + ref = 0; + } + if ((h->ref_list[0][ref].f.reference&3) != 3) { + av_log(s->avctx, AV_LOG_DEBUG, "Reference invalid\n"); + return; + } fill_rectangle(&s->current_picture.f.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); - assert(!FRAME_MBAFF); + h->mb_mbaff = + h->mb_field_decoding_flag = 0; ff_h264_hl_decode_mb(h); } else { assert(ref == 0); @@ -78,7 +92,7 @@ static void set_mv_strides(MpegEncContext *s, int *mv_step, int *stride) { if (s->codec_id == AV_CODEC_ID_H264) { H264Context *h = (void*)s; - assert(s->quarter_sample); + av_assert0(s->quarter_sample); *mv_step = 4; *stride = h->b_stride; } else { @@ -170,11 +184,73 @@ static void guess_dc(MpegEncContext *s, int16_t *dc, int w, int h, int stride, int is_luma) { int b_x, b_y; + int16_t (*col )[4] = av_malloc(stride*h*sizeof( int16_t)*4); + uint32_t (*dist)[4] = av_malloc(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++){ + 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->current_picture.f.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][1]= color; + dist[b_x + b_y*stride][1]= distance >= 0 ? b_x-distance : 9999; + } + 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->current_picture.f.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->current_picture.f.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->current_picture.f.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 color[4] = { 1024, 1024, 1024, 1024 }; - int distance[4] = { 9999, 9999, 9999, 9999 }; int mb_index, error, j; int64_t guess, weight_sum; mb_index = (b_x >> is_luma) + (b_y >> is_luma) * s->mb_stride; @@ -185,66 +261,21 @@ static void guess_dc(MpegEncContext *s, int16_t *dc, int w, if (!(error & ER_DC_ERROR)) continue; // dc-ok - /* right block */ - for (j = b_x + 1; j < w; j++) { - int mb_index_j = (j >> 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->current_picture.f.mb_type[mb_index_j]); - if (intra_j == 0 || !(error_j & ER_DC_ERROR)) { - color[0] = dc[j + b_y * stride]; - distance[0] = j - b_x; - break; - } - } - - /* left block */ - for (j = b_x - 1; j >= 0; j--) { - int mb_index_j = (j >> 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->current_picture.f.mb_type[mb_index_j]); - if (intra_j == 0 || !(error_j & ER_DC_ERROR)) { - color[1] = dc[j + b_y * stride]; - distance[1] = b_x - j; - break; - } - } - - /* bottom block */ - for (j = b_y + 1; j < h; j++) { - int mb_index_j = (b_x >> is_luma) + (j >> is_luma) * s->mb_stride; - int error_j = s->error_status_table[mb_index_j]; - int intra_j = IS_INTRA(s->current_picture.f.mb_type[mb_index_j]); - - if (intra_j == 0 || !(error_j & ER_DC_ERROR)) { - color[2] = dc[b_x + j * stride]; - distance[2] = j - b_y; - break; - } - } - - /* top block */ - for (j = b_y - 1; j >= 0; j--) { - int mb_index_j = (b_x >> is_luma) + (j >> is_luma) * s->mb_stride; - int error_j = s->error_status_table[mb_index_j]; - int intra_j = IS_INTRA(s->current_picture.f.mb_type[mb_index_j]); - if (intra_j == 0 || !(error_j & ER_DC_ERROR)) { - color[3] = dc[b_x + j * stride]; - distance[3] = b_y - j; - break; - } - } - weight_sum = 0; guess = 0; for (j = 0; j < 4; j++) { - int64_t weight = 256 * 256 * 256 * 16 / distance[j]; - guess += weight * (int64_t) color[j]; + 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); } /** @@ -414,19 +445,22 @@ static void guess_mv(MpegEncContext *s) fixed[mb_xy] = f; if (f == MV_FROZEN) num_avail++; + else if(s->last_picture.f.data[0] && s->last_picture.f.motion_val[0]){ + const int mb_y= mb_xy / s->mb_stride; + const int mb_x= mb_xy % s->mb_stride; + const int mot_index= (mb_x + mb_y*mot_stride) * mot_step; + s->current_picture.f.motion_val[0][mot_index][0]= s->last_picture.f.motion_val[0][mot_index][0]; + s->current_picture.f.motion_val[0][mot_index][1]= s->last_picture.f.motion_val[0][mot_index][1]; + s->current_picture.f.ref_index[0][4*mb_xy] = s->last_picture.f.ref_index[0][4*mb_xy]; + } } if ((!(s->avctx->error_concealment&FF_EC_GUESS_MVS)) || num_avail <= mb_width / 2) { for (mb_y = 0; mb_y < s->mb_height; mb_y++) { - s->mb_x = 0; - s->mb_y = mb_y; - ff_init_block_index(s); for (mb_x = 0; mb_x < s->mb_width; mb_x++) { const int mb_xy = mb_x + mb_y * s->mb_stride; - ff_update_block_index(s); - if (IS_INTRA(s->current_picture.f.mb_type[mb_xy])) continue; if (!(s->error_status_table[mb_xy] & ER_MV_ERROR)) @@ -461,9 +495,6 @@ static void guess_mv(MpegEncContext *s) changed = 0; for (mb_y = 0; mb_y < s->mb_height; mb_y++) { - s->mb_x = 0; - s->mb_y = mb_y; - ff_init_block_index(s); for (mb_x = 0; mb_x < s->mb_width; mb_x++) { const int mb_xy = mb_x + mb_y * s->mb_stride; int mv_predictor[8][2] = { { 0 } }; @@ -475,15 +506,13 @@ static void guess_mv(MpegEncContext *s) const int mot_index = (mb_x + mb_y * mot_stride) * mot_step; int prev_x, prev_y, prev_ref; - ff_update_block_index(s); - if ((mb_x ^ mb_y ^ pass) & 1) continue; if (fixed[mb_xy] == MV_FROZEN) continue; - assert(!IS_INTRA(s->current_picture.f.mb_type[mb_xy])); - assert(s->last_picture_ptr && s->last_picture_ptr->f.data[0]); + av_assert1(!IS_INTRA(s->current_picture.f.mb_type[mb_xy])); + av_assert1(s->last_picture_ptr && s->last_picture_ptr->f.data[0]); j = 0; if (mb_x > 0 && fixed[mb_xy - 1] == MV_FROZEN) @@ -598,7 +627,7 @@ skip_mean_and_median: /* zero MV */ pred_count++; - if (!fixed[mb_xy]) { + if (!fixed[mb_xy] && 0) { if (s->avctx->codec_id == AV_CODEC_ID_H264) { // FIXME } else { @@ -773,11 +802,9 @@ static int is_intra_more_likely(MpegEncContext *s) ff_thread_await_progress(&s->last_picture_ptr->f, mb_y, 0); } - is_intra_likely += s->dsp.sad[0](NULL, last_mb_ptr, mb_ptr, - s->linesize, 16); - is_intra_likely -= s->dsp.sad[0](NULL, last_mb_ptr, - last_mb_ptr + s->linesize * 16, - s->linesize, 16); + is_intra_likely += s->dsp.sad[0](NULL, last_mb_ptr, mb_ptr , s->linesize, 16); + // FIXME need await_progress() here + is_intra_likely -= s->dsp.sad[0](NULL, last_mb_ptr, last_mb_ptr+s->linesize*16, s->linesize, 16); } else { if (IS_INTRA(s->current_picture.f.mb_type[mb_xy])) is_intra_likely++; @@ -786,6 +813,7 @@ static int is_intra_more_likely(MpegEncContext *s) } } } + // printf("is_intra_likely: %d type:%d\n", is_intra_likely, s->pict_type); return is_intra_likely > 0; } @@ -887,7 +915,7 @@ void ff_er_frame_end(MpegEncContext *s) /* We do not support ER of field pictures yet, * though it should not crash if enabled. */ - if (!s->err_recognition || s->error_count == 0 || + if (!s->err_recognition || s->error_count == 0 || s->avctx->lowres || s->avctx->hwaccel || s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU || s->picture_structure != PICT_FRAME || @@ -896,6 +924,12 @@ void ff_er_frame_end(MpegEncContext *s) return; }; + if ( s->picture_structure == PICT_FRAME + && s->current_picture.f.linesize[0] != s->current_picture_ptr->f.linesize[0]) { + av_log(s->avctx, AV_LOG_ERROR, "Error concealment not possible, frame not fully initialized\n"); + return; + } + if (s->current_picture.f.motion_val[0] == NULL) { av_log(s->avctx, AV_LOG_ERROR, "Warning MVs not available\n"); @@ -919,6 +953,7 @@ void ff_er_frame_end(MpegEncContext *s) } } +#if 1 /* handle overlapping slices */ for (error_type = 1; error_type <= 3; error_type++) { int end_ok = 0; @@ -939,7 +974,8 @@ void ff_er_frame_end(MpegEncContext *s) end_ok = 0; } } - +#endif +#if 1 /* handle slices with partitions of different length */ if (s->partitioned_frame) { int end_ok = 0; @@ -962,7 +998,7 @@ void ff_er_frame_end(MpegEncContext *s) end_ok = 0; } } - +#endif /* handle missing slices */ if (s->err_recognition & AV_EF_EXPLODE) { int end_ok = 1; @@ -989,6 +1025,7 @@ void ff_er_frame_end(MpegEncContext *s) } } +#if 1 /* backward mark errors */ distance = 9999999; for (error_type = 1; error_type <= 3; error_type++) { @@ -1013,6 +1050,7 @@ void ff_er_frame_end(MpegEncContext *s) distance = 9999999; } } +#endif /* forward mark errors */ error = 0; @@ -1027,7 +1065,7 @@ void ff_er_frame_end(MpegEncContext *s) s->error_status_table[mb_xy] |= error; } } - +#if 1 /* handle not partitioned case */ if (!s->partitioned_frame) { for (i = 0; i < s->mb_num; i++) { @@ -1038,6 +1076,7 @@ void ff_er_frame_end(MpegEncContext *s) s->error_status_table[mb_xy] = error; } } +#endif dc_error = ac_error = mv_error = 0; for (i = 0; i < s->mb_num; i++) { @@ -1050,8 +1089,8 @@ void ff_er_frame_end(MpegEncContext *s) if (error & ER_MV_ERROR) mv_error++; } - av_log(s->avctx, AV_LOG_INFO, "concealing %d DC, %d AC, %d MV errors\n", - dc_error, ac_error, mv_error); + av_log(s->avctx, AV_LOG_INFO, "concealing %d DC, %d AC, %d MV errors in %c frame\n", + dc_error, ac_error, mv_error, av_get_picture_type_char(s->pict_type)); is_intra_likely = is_intra_more_likely(s); @@ -1078,16 +1117,11 @@ void ff_er_frame_end(MpegEncContext *s) /* handle inter blocks with damaged AC */ for (mb_y = 0; mb_y < s->mb_height; mb_y++) { - s->mb_x = 0; - s->mb_y = mb_y; - ff_init_block_index(s); 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_type = s->current_picture.f.mb_type[mb_xy]; int dir = !s->last_picture.f.data[0]; - ff_update_block_index(s); - error = s->error_status_table[mb_xy]; if (IS_INTRA(mb_type)) @@ -1125,16 +1159,11 @@ void ff_er_frame_end(MpegEncContext *s) /* guess MVs */ if (s->pict_type == AV_PICTURE_TYPE_B) { for (mb_y = 0; mb_y < s->mb_height; mb_y++) { - s->mb_x = 0; - s->mb_y = mb_y; - ff_init_block_index(s); for (mb_x = 0; mb_x < s->mb_width; mb_x++) { int xy = mb_x * 2 + mb_y * 2 * s->b8_stride; const int mb_xy = mb_x + mb_y * s->mb_stride; const int mb_type = s->current_picture.f.mb_type[mb_xy]; - ff_update_block_index(s); - error = s->error_status_table[mb_xy]; if (IS_INTRA(mb_type)) @@ -1229,15 +1258,17 @@ void ff_er_frame_end(MpegEncContext *s) s->dc_val[2][mb_x + mb_y * s->mb_stride] = (dcv + 4) >> 3; } } - +#if 1 /* guess DC for damaged blocks */ - guess_dc(s, s->dc_val[0], s->mb_width * 2, s->mb_height * 2, s->b8_stride, 1); - guess_dc(s, s->dc_val[1], s->mb_width, s->mb_height, s->mb_stride, 0); - guess_dc(s, s->dc_val[2], s->mb_width, s->mb_height, s->mb_stride, 0); + guess_dc(s, s->dc_val[0], s->mb_width*2, s->mb_height*2, s->b8_stride, 1); + guess_dc(s, s->dc_val[1], s->mb_width , s->mb_height , s->mb_stride, 0); + guess_dc(s, s->dc_val[2], s->mb_width , s->mb_height , s->mb_stride, 0); +#endif /* filter luma DC */ filter181(s->dc_val[0], s->mb_width * 2, s->mb_height * 2, s->b8_stride); +#if 1 /* render DC only intra */ for (mb_y = 0; mb_y < s->mb_height; mb_y++) { for (mb_x = 0; mb_x < s->mb_width; mb_x++) { @@ -1259,6 +1290,7 @@ void ff_er_frame_end(MpegEncContext *s) put_dc(s, dest_y, dest_cb, dest_cr, mb_x, mb_y); } } +#endif if (s->avctx->error_concealment & FF_EC_DEBLOCK) { /* filter horizontal block boundaries */ |