diff options
Diffstat (limited to 'libavcodec/error_resilience.c')
-rw-r--r-- | libavcodec/error_resilience.c | 217 |
1 files changed, 144 insertions, 73 deletions
diff --git a/libavcodec/error_resilience.c b/libavcodec/error_resilience.c index a07787a..b9924a6 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 */ @@ -40,7 +40,7 @@ static void set_mv_strides(ERContext *s, int *mv_step, int *stride) { if (s->avctx->codec_id == AV_CODEC_ID_H264) { - assert(s->quarter_sample); + av_assert0(s->quarter_sample); *mv_step = 4; *stride = s->mb_width * 4; } else { @@ -133,11 +133,73 @@ 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(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->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][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->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 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; @@ -148,66 +210,21 @@ static void guess_dc(ERContext *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->cur_pic->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->cur_pic->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->cur_pic->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->cur_pic->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); } /** @@ -377,6 +394,14 @@ static void guess_mv(ERContext *s) fixed[mb_xy] = f; if (f == MV_FROZEN) num_avail++; + else if(s->last_pic->f.data[0] && s->last_pic->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->cur_pic->motion_val[0][mot_index][0]= s->last_pic->motion_val[0][mot_index][0]; + s->cur_pic->motion_val[0][mot_index][1]= s->last_pic->motion_val[0][mot_index][1]; + s->cur_pic->ref_index[0][4*mb_xy] = s->last_pic->ref_index[0][4*mb_xy]; + } } if ((!(s->avctx->error_concealment&FF_EC_GUESS_MVS)) || @@ -427,8 +452,8 @@ static void guess_mv(ERContext *s) if (fixed[mb_xy] == MV_FROZEN) continue; - assert(!IS_INTRA(s->cur_pic->mb_type[mb_xy])); - assert(s->last_pic && s->last_pic->f.data[0]); + av_assert1(!IS_INTRA(s->cur_pic->mb_type[mb_xy])); + av_assert1(s->last_pic && s->last_pic->f.data[0]); j = 0; if (mb_x > 0 && fixed[mb_xy - 1] == MV_FROZEN) @@ -543,7 +568,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 { @@ -710,6 +735,7 @@ static int is_intra_more_likely(ERContext *s) } is_intra_likely += s->dsp->sad[0](NULL, last_mb_ptr, mb_ptr, linesize[0], 16); + // FIXME need await_progress() here is_intra_likely -= s->dsp->sad[0](NULL, last_mb_ptr, last_mb_ptr + linesize[0] * 16, linesize[0], 16); @@ -721,6 +747,7 @@ static int is_intra_more_likely(ERContext *s) } } } +// av_log(NULL, AV_LOG_ERROR, "is_intra_likely: %d type:%d\n", is_intra_likely, s->pict_type); return is_intra_likely > 0; } @@ -800,13 +827,15 @@ void ff_er_add_slice(ERContext *s, int startx, int starty, s->error_status_table[start_xy] |= VP_START; - if (start_xy > 0 && s->avctx->thread_count <= 1 && + if (start_xy > 0 && !(s->avctx->active_thread_type & FF_THREAD_SLICE) && s->avctx->skip_top * s->mb_width < start_i) { int prev_status = s->error_status_table[s->mb_index2xy[start_i - 1]]; prev_status &= ~ VP_START; - if (prev_status != (ER_MV_END | ER_DC_END | ER_AC_END)) + if (prev_status != (ER_MV_END | ER_DC_END | ER_AC_END)) { + s->error_occurred = 1; s->error_count = INT_MAX; + } } } @@ -823,12 +852,45 @@ void ff_er_frame_end(ERContext *s) /* We do not support ER of field pictures yet, * though it should not crash if enabled. */ if (!s->avctx->err_recognition || s->error_count == 0 || + s->avctx->lowres || s->avctx->hwaccel || + s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU || !s->cur_pic || s->cur_pic->field_picture || s->error_count == 3 * s->mb_width * (s->avctx->skip_top + s->avctx->skip_bottom)) { return; - }; + } + for (mb_x = 0; mb_x < s->mb_width; mb_x++) { + int status = s->error_status_table[mb_x + (s->mb_height - 1) * s->mb_stride]; + if (status != 0x7F) + break; + } + + if ( mb_x == s->mb_width + && s->avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO + && (s->avctx->height&16) + && s->error_count == 3 * s->mb_width * (s->avctx->skip_top + s->avctx->skip_bottom + 1) + ) { + av_log(s->avctx, AV_LOG_DEBUG, "ignoring last missing slice\n"); + return; + } + + if (s->last_pic) { + if (s->last_pic->f.width != s->cur_pic->f.width || + s->last_pic->f.height != s->cur_pic->f.height || + s->last_pic->f.format != s->cur_pic->f.format) { + av_log(s->avctx, AV_LOG_WARNING, "Cannot use previous picture in error concealment\n"); + s->last_pic = NULL; + } + } + if (s->next_pic) { + if (s->next_pic->f.width != s->cur_pic->f.width || + s->next_pic->f.height != s->cur_pic->f.height || + s->next_pic->f.format != s->cur_pic->f.format) { + av_log(s->avctx, AV_LOG_WARNING, "Cannot use next picture in error concealment\n"); + s->next_pic = NULL; + } + } if (s->cur_pic->motion_val[0] == NULL) { av_log(s->avctx, AV_LOG_ERROR, "Warning MVs not available\n"); @@ -863,6 +925,7 @@ void ff_er_frame_end(ERContext *s) } } +#if 1 /* handle overlapping slices */ for (error_type = 1; error_type <= 3; error_type++) { int end_ok = 0; @@ -883,7 +946,8 @@ void ff_er_frame_end(ERContext *s) end_ok = 0; } } - +#endif +#if 1 /* handle slices with partitions of different length */ if (s->partitioned_frame) { int end_ok = 0; @@ -906,7 +970,7 @@ void ff_er_frame_end(ERContext *s) end_ok = 0; } } - +#endif /* handle missing slices */ if (s->avctx->err_recognition & AV_EF_EXPLODE) { int end_ok = 1; @@ -933,6 +997,7 @@ void ff_er_frame_end(ERContext *s) } } +#if 1 /* backward mark errors */ distance = 9999999; for (error_type = 1; error_type <= 3; error_type++) { @@ -957,6 +1022,7 @@ void ff_er_frame_end(ERContext *s) distance = 9999999; } } +#endif /* forward mark errors */ error = 0; @@ -971,7 +1037,7 @@ void ff_er_frame_end(ERContext *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++) { @@ -982,6 +1048,7 @@ void ff_er_frame_end(ERContext *s) s->error_status_table[mb_xy] = error; } } +#endif dc_error = ac_error = mv_error = 0; for (i = 0; i < s->mb_num; i++) { @@ -994,8 +1061,8 @@ void ff_er_frame_end(ERContext *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->cur_pic->f.pict_type)); is_intra_likely = is_intra_more_likely(s); @@ -1085,6 +1152,7 @@ void ff_er_frame_end(ERContext *s) int time_pp = s->pp_time; int time_pb = s->pb_time; + av_assert0(s->avctx->codec_id != AV_CODEC_ID_H264); ff_thread_await_progress(&s->next_pic->tf, mb_y, 0); s->mv[0][0][0] = s->next_pic->motion_val[0][xy][0] * time_pb / time_pp; @@ -1152,15 +1220,17 @@ void ff_er_frame_end(ERContext *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++) { @@ -1182,6 +1252,7 @@ void ff_er_frame_end(ERContext *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 */ |