X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Ferror_resilience.c;h=3dbcb53b08d8074460182488c5189ce479f2aada;hb=ee4aa388b2231e988eccdab652c55df080d6ad45;hp=2790599744ea23e088c300d0bddcb2e8cb4d6088;hpb=127cc6dd3d0b8ce8875aecacc5c2aaf45bf52243;p=ffmpeg diff --git a/libavcodec/error_resilience.c b/libavcodec/error_resilience.c index 2790599744e..3dbcb53b08d 100644 --- a/libavcodec/error_resilience.c +++ b/libavcodec/error_resilience.c @@ -373,23 +373,39 @@ static void v_block_filter(ERContext *s, uint8_t *dst, int w, int h, } } +#define MV_FROZEN 8 +#define MV_CHANGED 4 +#define MV_UNCHANGED 2 +#define MV_LISTED 1 +static av_always_inline void add_blocklist(int (*blocklist)[2], int *blocklist_length, uint8_t *fixed, int mb_x, int mb_y, int mb_xy) +{ + if (fixed[mb_xy]) + return; + fixed[mb_xy] = MV_LISTED; + blocklist[ *blocklist_length ][0] = mb_x; + blocklist[(*blocklist_length)++][1] = mb_y; +} + static void guess_mv(ERContext *s) { - uint8_t *fixed = s->er_temp_buffer; -#define MV_FROZEN 3 -#define MV_CHANGED 2 -#define MV_UNCHANGED 1 + int (*blocklist)[2], (*next_blocklist)[2]; + uint8_t *fixed; const int mb_stride = s->mb_stride; const int mb_width = s->mb_width; int mb_height = s->mb_height; int i, depth, num_avail; int mb_x, mb_y, mot_step, mot_stride; + int blocklist_length, next_blocklist_length; if (s->last_pic.f && s->last_pic.f->data[0]) mb_height = FFMIN(mb_height, (s->last_pic.f->height+15)>>4); if (s->next_pic.f && s->next_pic.f->data[0]) mb_height = FFMIN(mb_height, (s->next_pic.f->height+15)>>4); + blocklist = s->er_temp_buffer; + next_blocklist = (s->er_temp_buffer + 2 * sizeof(int) * s->mb_stride * s->mb_height); + fixed = s->er_temp_buffer + 4 * sizeof(int) * s->mb_stride * s->mb_height; + set_mv_strides(s, &mot_step, &mot_stride); num_avail = 0; @@ -439,237 +455,265 @@ static void guess_mv(ERContext *s) return; } + blocklist_length = 0; + for (mb_y = 0; mb_y < mb_height; mb_y++) { + for (mb_x = 0; mb_x < mb_width; mb_x++) { + const int mb_xy = mb_x + mb_y * mb_stride; + if (fixed[mb_xy] == MV_FROZEN) { + if (mb_x) add_blocklist(blocklist, &blocklist_length, fixed, mb_x - 1, mb_y, mb_xy - 1); + if (mb_y) add_blocklist(blocklist, &blocklist_length, fixed, mb_x, mb_y - 1, mb_xy - mb_stride); + if (mb_x+1 < mb_width) add_blocklist(blocklist, &blocklist_length, fixed, mb_x + 1, mb_y, mb_xy + 1); + if (mb_y+1 < mb_height) add_blocklist(blocklist, &blocklist_length, fixed, mb_x, mb_y + 1, mb_xy + mb_stride); + } + } + } + for (depth = 0; ; depth++) { int changed, pass, none_left; + int blocklist_index; none_left = 1; changed = 1; for (pass = 0; (changed || pass < 2) && pass < 10; pass++) { - int mb_x, mb_y; int score_sum = 0; changed = 0; - for (mb_y = 0; mb_y < mb_height; mb_y++) { - 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 } }; - int ref[8] = { 0 }; - int pred_count = 0; - int j; - int best_score = 256 * 256 * 256 * 64; - int best_pred = 0; - const int mot_index = (mb_x + mb_y * mot_stride) * mot_step; - int prev_x = 0, prev_y = 0, prev_ref = 0; - - if ((mb_x ^ mb_y ^ pass) & 1) - continue; - - if (fixed[mb_xy] == MV_FROZEN) - continue; - av_assert1(!IS_INTRA(s->cur_pic.mb_type[mb_xy])); - av_assert1(s->last_pic.f && s->last_pic.f->data[0]); - - j = 0; - if (mb_x > 0 && fixed[mb_xy - 1] == MV_FROZEN) - j = 1; - if (mb_x + 1 < mb_width && fixed[mb_xy + 1] == MV_FROZEN) - j = 1; - if (mb_y > 0 && fixed[mb_xy - mb_stride] == MV_FROZEN) - j = 1; - if (mb_y + 1 < mb_height && fixed[mb_xy + mb_stride] == MV_FROZEN) - j = 1; - if (j == 0) - continue; + for (blocklist_index = 0; blocklist_index < blocklist_length; blocklist_index++) { + const int mb_x = blocklist[blocklist_index][0]; + const int mb_y = blocklist[blocklist_index][1]; + const int mb_xy = mb_x + mb_y * mb_stride; + int mv_predictor[8][2]; + int ref[8]; + int pred_count; + int j; + int best_score; + int best_pred; + int mot_index; + int prev_x, prev_y, prev_ref; - j = 0; - if (mb_x > 0 && fixed[mb_xy - 1 ] == MV_CHANGED) - j = 1; - if (mb_x + 1 < mb_width && fixed[mb_xy + 1 ] == MV_CHANGED) - j = 1; - if (mb_y > 0 && fixed[mb_xy - mb_stride] == MV_CHANGED) - j = 1; - if (mb_y + 1 < mb_height && fixed[mb_xy + mb_stride] == MV_CHANGED) - j = 1; - if (j == 0 && pass > 1) - continue; + if ((mb_x ^ mb_y ^ pass) & 1) + continue; + av_assert2(fixed[mb_xy] != MV_FROZEN); - none_left = 0; - if (mb_x > 0 && fixed[mb_xy - 1]) { - mv_predictor[pred_count][0] = - s->cur_pic.motion_val[0][mot_index - mot_step][0]; - mv_predictor[pred_count][1] = - s->cur_pic.motion_val[0][mot_index - mot_step][1]; - ref[pred_count] = - s->cur_pic.ref_index[0][4 * (mb_xy - 1)]; - pred_count++; - } - if (mb_x + 1 < mb_width && fixed[mb_xy + 1]) { - mv_predictor[pred_count][0] = - s->cur_pic.motion_val[0][mot_index + mot_step][0]; - mv_predictor[pred_count][1] = - s->cur_pic.motion_val[0][mot_index + mot_step][1]; - ref[pred_count] = - s->cur_pic.ref_index[0][4 * (mb_xy + 1)]; - pred_count++; - } - if (mb_y > 0 && fixed[mb_xy - mb_stride]) { - mv_predictor[pred_count][0] = - s->cur_pic.motion_val[0][mot_index - mot_stride * mot_step][0]; - mv_predictor[pred_count][1] = - s->cur_pic.motion_val[0][mot_index - mot_stride * mot_step][1]; - ref[pred_count] = - s->cur_pic.ref_index[0][4 * (mb_xy - s->mb_stride)]; - pred_count++; - } - if (mb_y + 1cur_pic.motion_val[0][mot_index + mot_stride * mot_step][0]; - mv_predictor[pred_count][1] = - s->cur_pic.motion_val[0][mot_index + mot_stride * mot_step][1]; - ref[pred_count] = - s->cur_pic.ref_index[0][4 * (mb_xy + s->mb_stride)]; - pred_count++; - } - if (pred_count == 0) - continue; + av_assert1(!IS_INTRA(s->cur_pic.mb_type[mb_xy])); + av_assert1(s->last_pic.f && s->last_pic.f->data[0]); - if (pred_count > 1) { - int sum_x = 0, sum_y = 0, sum_r = 0; - int max_x, max_y, min_x, min_y, max_r, min_r; - - for (j = 0; j < pred_count; j++) { - sum_x += mv_predictor[j][0]; - sum_y += mv_predictor[j][1]; - sum_r += ref[j]; - if (j && ref[j] != ref[j - 1]) - goto skip_mean_and_median; - } - - /* mean */ - mv_predictor[pred_count][0] = sum_x / j; - mv_predictor[pred_count][1] = sum_y / j; - ref[pred_count] = sum_r / j; - - /* median */ - if (pred_count >= 3) { - min_y = min_x = min_r = 99999; - max_y = max_x = max_r = -99999; - } else { - min_x = min_y = max_x = max_y = min_r = max_r = 0; - } - for (j = 0; j < pred_count; j++) { - max_x = FFMAX(max_x, mv_predictor[j][0]); - 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_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][1] = sum_y - max_y - min_y; - ref[pred_count + 1] = sum_r - max_r - min_r; - - if (pred_count == 4) { - mv_predictor[pred_count + 1][0] /= 2; - mv_predictor[pred_count + 1][1] /= 2; - ref[pred_count + 1] /= 2; - } - pred_count += 2; - } + j = 0; + if (mb_x > 0) + j |= fixed[mb_xy - 1]; + if (mb_x + 1 < mb_width) + j |= fixed[mb_xy + 1]; + if (mb_y > 0) + j |= fixed[mb_xy - mb_stride]; + if (mb_y + 1 < mb_height) + j |= fixed[mb_xy + mb_stride]; -skip_mean_and_median: - /* zero MV */ - pred_count++; + av_assert2(j & MV_FROZEN); - prev_x = s->cur_pic.motion_val[0][mot_index][0]; - prev_y = s->cur_pic.motion_val[0][mot_index][1]; - prev_ref = s->cur_pic.ref_index[0][4 * mb_xy]; + if (!(j & MV_CHANGED) && pass > 1) + continue; - /* last MV */ - mv_predictor[pred_count][0] = prev_x; - mv_predictor[pred_count][1] = prev_y; - ref[pred_count] = prev_ref; + none_left = 0; + pred_count = 0; + mot_index = (mb_x + mb_y * mot_stride) * mot_step; + + if (mb_x > 0 && fixed[mb_xy - 1] > 1) { + mv_predictor[pred_count][0] = + s->cur_pic.motion_val[0][mot_index - mot_step][0]; + mv_predictor[pred_count][1] = + s->cur_pic.motion_val[0][mot_index - mot_step][1]; + ref[pred_count] = + s->cur_pic.ref_index[0][4 * (mb_xy - 1)]; + pred_count++; + } + if (mb_x + 1 < mb_width && fixed[mb_xy + 1] > 1) { + mv_predictor[pred_count][0] = + s->cur_pic.motion_val[0][mot_index + mot_step][0]; + mv_predictor[pred_count][1] = + s->cur_pic.motion_val[0][mot_index + mot_step][1]; + ref[pred_count] = + s->cur_pic.ref_index[0][4 * (mb_xy + 1)]; pred_count++; + } + if (mb_y > 0 && fixed[mb_xy - mb_stride] > 1) { + mv_predictor[pred_count][0] = + s->cur_pic.motion_val[0][mot_index - mot_stride * mot_step][0]; + mv_predictor[pred_count][1] = + s->cur_pic.motion_val[0][mot_index - mot_stride * mot_step][1]; + ref[pred_count] = + s->cur_pic.ref_index[0][4 * (mb_xy - s->mb_stride)]; + pred_count++; + } + if (mb_y + 1 1) { + mv_predictor[pred_count][0] = + s->cur_pic.motion_val[0][mot_index + mot_stride * mot_step][0]; + mv_predictor[pred_count][1] = + s->cur_pic.motion_val[0][mot_index + mot_stride * mot_step][1]; + ref[pred_count] = + s->cur_pic.ref_index[0][4 * (mb_xy + s->mb_stride)]; + pred_count++; + } + if (pred_count == 0) + continue; + + if (pred_count > 1) { + int sum_x = 0, sum_y = 0, sum_r = 0; + int max_x, max_y, min_x, min_y, max_r, min_r; for (j = 0; j < pred_count; j++) { - int *linesize = s->cur_pic.f->linesize; - int score = 0; - uint8_t *src = s->cur_pic.f->data[0] + - mb_x * 16 + mb_y * 16 * linesize[0]; + sum_x += mv_predictor[j][0]; + sum_y += mv_predictor[j][1]; + sum_r += ref[j]; + if (j && ref[j] != ref[j - 1]) + goto skip_mean_and_median; + } - s->cur_pic.motion_val[0][mot_index][0] = - s->mv[0][0][0] = mv_predictor[j][0]; - s->cur_pic.motion_val[0][mot_index][1] = - s->mv[0][0][1] = mv_predictor[j][1]; - - // predictor intra or otherwise not available - if (ref[j] < 0) - continue; - - s->decode_mb(s->opaque, ref[j], MV_DIR_FORWARD, - MV_TYPE_16X16, &s->mv, mb_x, mb_y, 0, 0); - - if (mb_x > 0 && fixed[mb_xy - 1]) { - int k; - for (k = 0; k < 16; k++) - score += FFABS(src[k * linesize[0] - 1] - - src[k * linesize[0]]); - } - if (mb_x + 1 < mb_width && fixed[mb_xy + 1]) { - int k; - for (k = 0; k < 16; k++) - score += FFABS(src[k * linesize[0] + 15] - - src[k * linesize[0] + 16]); - } - if (mb_y > 0 && fixed[mb_xy - mb_stride]) { - int k; - for (k = 0; k < 16; k++) - score += FFABS(src[k - linesize[0]] - src[k]); - } - if (mb_y + 1 < mb_height && fixed[mb_xy + mb_stride]) { - int k; - for (k = 0; k < 16; k++) - score += FFABS(src[k + linesize[0] * 15] - - src[k + linesize[0] * 16]); - } - - if (score <= best_score) { // <= will favor the last MV - best_score = score; - best_pred = j; - } + /* mean */ + mv_predictor[pred_count][0] = sum_x / j; + mv_predictor[pred_count][1] = sum_y / j; + ref[pred_count] = sum_r / j; + + /* median */ + if (pred_count >= 3) { + min_y = min_x = min_r = 99999; + max_y = max_x = max_r = -99999; + } else { + min_x = min_y = max_x = max_y = min_r = max_r = 0; + } + for (j = 0; j < pred_count; j++) { + max_x = FFMAX(max_x, mv_predictor[j][0]); + 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_y = FFMIN(min_y, mv_predictor[j][1]); + min_r = FFMIN(min_r, ref[j]); } - score_sum += best_score; - s->mv[0][0][0] = mv_predictor[best_pred][0]; - s->mv[0][0][1] = mv_predictor[best_pred][1]; + mv_predictor[pred_count + 1][0] = sum_x - max_x - min_x; + 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) { + mv_predictor[pred_count + 1][0] /= 2; + mv_predictor[pred_count + 1][1] /= 2; + ref[pred_count + 1] /= 2; + } + pred_count += 2; + } - for (i = 0; i < mot_step; i++) - for (j = 0; j < mot_step; j++) { - s->cur_pic.motion_val[0][mot_index + i + j * mot_stride][0] = s->mv[0][0][0]; - s->cur_pic.motion_val[0][mot_index + i + j * mot_stride][1] = s->mv[0][0][1]; - } +skip_mean_and_median: + /* zero MV */ + mv_predictor[pred_count][0] = + mv_predictor[pred_count][1] = + ref[pred_count] = 0; + pred_count++; + + prev_x = s->cur_pic.motion_val[0][mot_index][0]; + prev_y = s->cur_pic.motion_val[0][mot_index][1]; + prev_ref = s->cur_pic.ref_index[0][4 * mb_xy]; + + /* last MV */ + mv_predictor[pred_count][0] = prev_x; + mv_predictor[pred_count][1] = prev_y; + ref[pred_count] = prev_ref; + pred_count++; + + best_pred = 0; + best_score = 256 * 256 * 256 * 64; + for (j = 0; j < pred_count; j++) { + int *linesize = s->cur_pic.f->linesize; + int score = 0; + uint8_t *src = s->cur_pic.f->data[0] + + mb_x * 16 + mb_y * 16 * linesize[0]; + + s->cur_pic.motion_val[0][mot_index][0] = + s->mv[0][0][0] = mv_predictor[j][0]; + s->cur_pic.motion_val[0][mot_index][1] = + s->mv[0][0][1] = mv_predictor[j][1]; + + // predictor intra or otherwise not available + if (ref[j] < 0) + continue; - s->decode_mb(s->opaque, ref[best_pred], MV_DIR_FORWARD, + s->decode_mb(s->opaque, ref[j], MV_DIR_FORWARD, MV_TYPE_16X16, &s->mv, mb_x, mb_y, 0, 0); + if (mb_x > 0 && fixed[mb_xy - 1] > 1) { + int k; + for (k = 0; k < 16; k++) + score += FFABS(src[k * linesize[0] - 1] - + src[k * linesize[0]]); + } + if (mb_x + 1 < mb_width && fixed[mb_xy + 1] > 1) { + int k; + for (k = 0; k < 16; k++) + score += FFABS(src[k * linesize[0] + 15] - + src[k * linesize[0] + 16]); + } + if (mb_y > 0 && fixed[mb_xy - mb_stride] > 1) { + int k; + for (k = 0; k < 16; k++) + score += FFABS(src[k - linesize[0]] - src[k]); + } + if (mb_y + 1 < mb_height && fixed[mb_xy + mb_stride] > 1) { + int k; + for (k = 0; k < 16; k++) + score += FFABS(src[k + linesize[0] * 15] - + src[k + linesize[0] * 16]); + } - if (s->mv[0][0][0] != prev_x || s->mv[0][0][1] != prev_y) { - fixed[mb_xy] = MV_CHANGED; - changed++; - } else - fixed[mb_xy] = MV_UNCHANGED; + if (score <= best_score) { // <= will favor the last MV + best_score = score; + best_pred = j; + } } + score_sum += best_score; + s->mv[0][0][0] = mv_predictor[best_pred][0]; + s->mv[0][0][1] = mv_predictor[best_pred][1]; + + for (i = 0; i < mot_step; i++) + for (j = 0; j < mot_step; j++) { + s->cur_pic.motion_val[0][mot_index + i + j * mot_stride][0] = s->mv[0][0][0]; + s->cur_pic.motion_val[0][mot_index + i + j * mot_stride][1] = s->mv[0][0][1]; + } + + s->decode_mb(s->opaque, ref[best_pred], MV_DIR_FORWARD, + MV_TYPE_16X16, &s->mv, mb_x, mb_y, 0, 0); + + + if (s->mv[0][0][0] != prev_x || s->mv[0][0][1] != prev_y) { + fixed[mb_xy] = MV_CHANGED; + changed++; + } else + fixed[mb_xy] = MV_UNCHANGED; } } if (none_left) return; - for (i = 0; i < mb_width * mb_height; i++) { - int mb_xy = s->mb_index2xy[i]; - if (fixed[mb_xy]) + next_blocklist_length = 0; + + for (blocklist_index = 0; blocklist_index < blocklist_length; blocklist_index++) { + const int mb_x = blocklist[blocklist_index][0]; + const int mb_y = blocklist[blocklist_index][1]; + const int mb_xy = mb_x + mb_y * mb_stride; + + if (fixed[mb_xy] & (MV_CHANGED|MV_UNCHANGED|MV_FROZEN)) { fixed[mb_xy] = MV_FROZEN; + if (mb_x > 0) + add_blocklist(next_blocklist, &next_blocklist_length, fixed, mb_x - 1, mb_y, mb_xy - 1); + if (mb_y > 0) + add_blocklist(next_blocklist, &next_blocklist_length, fixed, mb_x, mb_y - 1, mb_xy - mb_stride); + if (mb_x + 1 < mb_width) + add_blocklist(next_blocklist, &next_blocklist_length, fixed, mb_x + 1, mb_y, mb_xy + 1); + if (mb_y + 1 < mb_height) + add_blocklist(next_blocklist, &next_blocklist_length, fixed, mb_x, mb_y + 1, mb_xy + mb_stride); + } } + av_assert0(next_blocklist_length <= mb_height * mb_width); + FFSWAP(int , blocklist_length, next_blocklist_length); + FFSWAP(void*, blocklist, next_blocklist); } }