]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/error_resilience.c
avcodec/movtextdec: Fix decode_styl() cleanup
[ffmpeg] / libavcodec / error_resilience.c
index 2790599744ea23e088c300d0bddcb2e8cb4d6088..3dbcb53b08d8074460182488c5189ce479f2aada 100644 (file)
@@ -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 + 1<mb_height && 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 (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<mb_height && 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 (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);
     }
 }