shithub: libvpx

Download patch

ref: 4645c89889aba53a1665934a42f082a23832f493
parent: 91206793c238871b3eaac48261584fed9dabb4c1
parent: 3e10be93f2e9f8707e5b4ce235081fdd2471c31d
author: John Koleszar <jkoleszar@google.com>
date: Fri Aug 12 07:45:26 EDT 2011

Merge "Disable error concealment until first key frame is decoded"

--- a/vp8/decoder/decodframe.c
+++ b/vp8/decoder/decodframe.c
@@ -183,6 +183,7 @@
                               unsigned int mb_idx)
 {
     int eobtotal = 0;
+    int throw_residual = 0;
     MB_PREDICTION_MODE mode;
     int i;
 
@@ -203,7 +204,8 @@
 
     mode = xd->mode_info_context->mbmi.mode;
 
-    if (eobtotal == 0 && mode != B_PRED && mode != SPLITMV)
+    if (eobtotal == 0 && mode != B_PRED && mode != SPLITMV &&
+            !vp8dx_bool_error(xd->current_bc))
     {
         /* Special case:  Force the loopfilter to skip when eobtotal and
          * mb_skip_coeff are zero.
@@ -235,14 +237,21 @@
         vp8_build_inter_predictors_mb(xd);
     }
 
+    /* When we have independent partitions we can apply residual even
+     * though other partitions within the frame are corrupt.
+     */
+    throw_residual = (!pbi->independent_partitions &&
+                      pbi->frame_corrupt_residual);
+    throw_residual = (throw_residual || vp8dx_bool_error(xd->current_bc));
+
 #if CONFIG_ERROR_CONCEALMENT
-    if (pbi->ec_enabled &&
-        (mb_idx >= pbi->mvs_corrupt_from_mb ||
-        vp8dx_bool_error(xd->current_bc)))
+    if (pbi->ec_active &&
+        (mb_idx >= pbi->mvs_corrupt_from_mb || throw_residual))
     {
         /* MB with corrupt residuals or corrupt mode/motion vectors.
          * Better to use the predictor as reconstruction.
          */
+        pbi->frame_corrupt_residual = 1;
         vpx_memset(xd->qcoeff, 0, sizeof(xd->qcoeff));
         vp8_conceal_corrupt_mb(xd);
         return;
@@ -376,22 +385,28 @@
         xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3;
 
 #if CONFIG_ERROR_CONCEALMENT
-        if (pbi->ec_enabled &&
-            xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME &&
-            vp8dx_bool_error(xd->current_bc))
         {
-            /* We have an intra block with corrupt coefficients, better to
-             * conceal with an inter block. Interpolate MVs from neighboring MBs
-             *
-             * Note that for the first mb with corrupt residual in a frame,
-             * we might not discover that before decoding the residual. That
-             * happens after this check, and therefore no inter concealment will
-             * be done.
-             */
-            vp8_interpolate_motion(xd,
-                                   mb_row, mb_col,
-                                   pc->mb_rows, pc->mb_cols,
-                                   pc->mode_info_stride);
+            int corrupt_residual = (!pbi->independent_partitions &&
+                                   pbi->frame_corrupt_residual) ||
+                                   vp8dx_bool_error(xd->current_bc);
+            if (pbi->ec_active &&
+                xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME &&
+                corrupt_residual)
+            {
+                /* We have an intra block with corrupt coefficients, better to
+                 * conceal with an inter block. Interpolate MVs from neighboring
+                 * MBs.
+                 *
+                 * Note that for the first mb with corrupt residual in a frame,
+                 * we might not discover that before decoding the residual. That
+                 * happens after this check, and therefore no inter concealment
+                 * will be done.
+                 */
+                vp8_interpolate_motion(xd,
+                                       mb_row, mb_col,
+                                       pc->mb_rows, pc->mb_cols,
+                                       pc->mode_info_stride);
+            }
         }
 #endif
 
@@ -519,7 +534,7 @@
             (TOKEN_PARTITION)vp8_read_literal(&pbi->bc, 2);
     /* Only update the multi_token_partition field if we are sure the value
      * is correct. */
-    if (!pbi->ec_enabled || !vp8dx_bool_error(&pbi->bc))
+    if (!pbi->ec_active || !vp8dx_bool_error(&pbi->bc))
         pc->multi_token_partition = multi_token_partition;
 
     num_part = 1 << pc->multi_token_partition;
@@ -551,7 +566,7 @@
         {
             if (read_is_valid(partition_size_ptr, 3, user_data_end))
                 partition_size = read_partition_size(partition_size_ptr);
-            else if(pbi->ec_enabled)
+            else if (pbi->ec_active)
                 partition_size = bytes_left;
             else
                 vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
@@ -566,7 +581,7 @@
          */
         if (!read_is_valid(partition, partition_size, user_data_end))
         {
-            if(pbi->ec_enabled)
+            if (pbi->ec_active)
                 partition_size = bytes_left;
             else
                 vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
@@ -659,6 +674,9 @@
             xd->subpixel_predict8x8   = SUBPIX_INVOKE(RTCD_VTABLE(subpix), bilinear8x8);
             xd->subpixel_predict16x16 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), bilinear16x16);
         }
+
+        if (pbi->decoded_key_frame && pbi->ec_enabled && !pbi->ec_active)
+            pbi->ec_active = 1;
     }
 
     xd->left_context = &pc->left_context;
@@ -681,6 +699,8 @@
     int mb_row;
     int i, j, k, l;
     const int *const mb_feature_data_bits = vp8_mb_feature_data_bits;
+    int corrupt_tokens = 0;
+    int prev_independent_partitions = pbi->independent_partitions;
 
     if (pbi->input_partition)
     {
@@ -694,7 +714,7 @@
 
     if (data_end - data < 3)
     {
-        if (pbi->ec_enabled)
+        if (pbi->ec_active)
         {
             /* Declare the missing frame as an inter frame since it will
                be handled as an inter frame when we have estimated its
@@ -719,7 +739,7 @@
             (data[0] | (data[1] << 8) | (data[2] << 16)) >> 5;
         data += 3;
 
-        if (!pbi->ec_enabled && (data + first_partition_length_in_bytes > data_end
+        if (!pbi->ec_active && (data + first_partition_length_in_bytes > data_end
             || data + first_partition_length_in_bytes < data))
             vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
                                "Truncated packet or corrupt partition 0 length");
@@ -734,7 +754,7 @@
             /* When error concealment is enabled we should only check the sync
              * code if we have enough bits available
              */
-            if (!pbi->ec_enabled || data + 3 < data_end)
+            if (!pbi->ec_active || data + 3 < data_end)
             {
                 if (data[0] != 0x9d || data[1] != 0x01 || data[2] != 0x2a)
                     vpx_internal_error(&pc->error, VPX_CODEC_UNSUP_BITSTREAM,
@@ -745,7 +765,7 @@
              * if we have enough data. Otherwise we will end up with the wrong
              * size.
              */
-            if (!pbi->ec_enabled || data + 6 < data_end)
+            if (!pbi->ec_active || data + 6 < data_end)
             {
                 pc->Width = (data[3] | (data[4] << 8)) & 0x3fff;
                 pc->horiz_scale = data[4] >> 6;
@@ -944,7 +964,7 @@
 #if CONFIG_ERROR_CONCEALMENT
         /* Assume we shouldn't refresh golden if the bit is missing */
         xd->corrupted |= vp8dx_bool_error(bc);
-        if (pbi->ec_enabled && xd->corrupted)
+        if (pbi->ec_active && xd->corrupted)
             pc->refresh_golden_frame = 0;
 #endif
 
@@ -952,7 +972,7 @@
 #if CONFIG_ERROR_CONCEALMENT
         /* Assume we shouldn't refresh altref if the bit is missing */
         xd->corrupted |= vp8dx_bool_error(bc);
-        if (pbi->ec_enabled && xd->corrupted)
+        if (pbi->ec_active && xd->corrupted)
             pc->refresh_alt_ref_frame = 0;
 #endif
 
@@ -982,7 +1002,7 @@
 #if CONFIG_ERROR_CONCEALMENT
     /* Assume we should refresh the last frame if the bit is missing */
     xd->corrupted |= vp8dx_bool_error(bc);
-    if (pbi->ec_enabled && xd->corrupted)
+    if (pbi->ec_active && xd->corrupted)
         pc->refresh_last_frame = 1;
 #endif
 
@@ -1000,6 +1020,8 @@
     }
 
     {
+        pbi->independent_partitions = 1;
+
         /* read coef probability tree */
         for (i = 0; i < BLOCK_TYPES; i++)
             for (j = 0; j < COEF_BANDS; j++)
@@ -1014,6 +1036,9 @@
                             *p = (vp8_prob)vp8_read_literal(bc, 8);
 
                         }
+                        if (k > 0 && *p != pc->fc.coef_probs[i][j][k-1][l])
+                            pbi->independent_partitions = 0;
+
                     }
     }
 
@@ -1040,7 +1065,7 @@
     vp8_decode_mode_mvs(pbi);
 
 #if CONFIG_ERROR_CONCEALMENT
-    if (pbi->ec_enabled &&
+    if (pbi->ec_active &&
             pbi->mvs_corrupt_from_mb < (unsigned int)pc->mb_cols * pc->mb_rows)
     {
         /* Motion vectors are missing in this frame. We will try to estimate
@@ -1054,8 +1079,12 @@
 #if CONFIG_MULTITHREAD
     if (pbi->b_multithreaded_rd && pc->multi_token_partition != ONE_PARTITION)
     {
+        int i;
+        pbi->frame_corrupt_residual = 0;
         vp8mt_decode_mb_rows(pbi, xd);
         vp8_yv12_extend_frame_borders_ptr(&pc->yv12_fb[pc->new_fb_idx]);    /*cm->frame_to_show);*/
+        for (i = 0; i < pbi->decoding_thread_count; ++i)
+            corrupt_tokens |= pbi->mb_row_di[i].mbd.corrupted;
     }
     else
 #endif
@@ -1062,6 +1091,7 @@
     {
         int ibc = 0;
         int num_part = 1 << pc->multi_token_partition;
+        pbi->frame_corrupt_residual = 0;
 
         /* Decode the individual macro block */
         for (mb_row = 0; mb_row < pc->mb_rows; mb_row++)
@@ -1078,6 +1108,7 @@
 
             decode_mb_row(pbi, pc, mb_row, xd);
         }
+        corrupt_tokens |= xd->corrupted;
     }
 
     stop_token_decoder(pbi);
@@ -1084,12 +1115,20 @@
 
     /* Collect information about decoder corruption. */
     /* 1. Check first boolean decoder for errors. */
-    pc->yv12_fb[pc->new_fb_idx].corrupted =
-        vp8dx_bool_error(bc);
+    pc->yv12_fb[pc->new_fb_idx].corrupted = vp8dx_bool_error(bc);
     /* 2. Check the macroblock information */
-    pc->yv12_fb[pc->new_fb_idx].corrupted |=
-        xd->corrupted;
+    pc->yv12_fb[pc->new_fb_idx].corrupted |= corrupt_tokens;
 
+    if (!pbi->decoded_key_frame)
+    {
+        if (pc->frame_type == KEY_FRAME &&
+            !pc->yv12_fb[pc->new_fb_idx].corrupted)
+            pbi->decoded_key_frame = 1;
+        else
+            vpx_internal_error(&pbi->common.error, VPX_CODEC_CORRUPT_FRAME,
+                               "A stream must start with a complete key frame");
+    }
+
     /* vpx_log("Decoder: Frame Decoded, Size Roughly:%d bytes  \n",bc->pos+pbi->bc2.pos); */
 
     /* If this was a kf or Gf note the Q used */
@@ -1102,6 +1141,7 @@
     if (pc->refresh_entropy_probs == 0)
     {
         vpx_memcpy(&pc->fc, &pc->lfc, sizeof(pc->fc));
+        pbi->independent_partitions = prev_independent_partitions;
     }
 
 #ifdef PACKET_TESTING
--- a/vp8/decoder/onyxd_if.c
+++ b/vp8/decoder/onyxd_if.c
@@ -101,9 +101,21 @@
 #else
     pbi->ec_enabled = 0;
 #endif
+    /* Error concealment is activated after a key frame has been
+     * decoded without errors when error concealment is enabled.
+     */
+    pbi->ec_active = 0;
 
+    pbi->decoded_key_frame = 0;
+
     pbi->input_partition = oxcf->input_partition;
 
+    /* Independent partitions is activated when a frame updates the
+     * token probability table to have equal probabilities over the
+     * PREV_COEF context.
+     */
+    pbi->independent_partitions = 0;
+
     return (VP8D_PTR) pbi;
 }
 
@@ -346,11 +358,15 @@
             /* If error concealment is disabled we won't signal missing frames to
              * the decoder.
              */
-            if (!pbi->ec_enabled)
+            if (!pbi->ec_active)
             {
                 /* Signal that we have no frame to show. */
                 cm->show_frame = 0;
 
+                pbi->num_partitions = 0;
+                if (pbi->input_partition)
+                    pbi->common.multi_token_partition = 0;
+
                 /* Nothing more to do. */
                 return 0;
             }
@@ -378,6 +394,10 @@
             }
 #endif
             pbi->common.error.setjmp = 0;
+
+            pbi->num_partitions = 0;
+            if (pbi->input_partition)
+                pbi->common.multi_token_partition = 0;
 
            /* We do not know if the missing frame(s) was supposed to update
             * any of the reference buffers, but we act conservative and
--- a/vp8/decoder/onyxd_int.h
+++ b/vp8/decoder/onyxd_int.h
@@ -132,7 +132,11 @@
     unsigned int mvs_corrupt_from_mb;
 #endif
     int ec_enabled;
+    int ec_active;
     int input_partition;
+    int decoded_key_frame;
+    int independent_partitions;
+    int frame_corrupt_residual;
 
 } VP8D_COMP;
 
--- a/vp8/decoder/threading.c
+++ b/vp8/decoder/threading.c
@@ -93,6 +93,7 @@
 static void decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd, int mb_row, int mb_col)
 {
     int eobtotal = 0;
+    int throw_residual = 0;
     int i, do_clamp = xd->mode_info_context->mbmi.need_to_clamp_mvs;
 
     if (xd->mode_info_context->mbmi.mb_skip_coeff)
@@ -112,7 +113,7 @@
 
     eobtotal |= (xd->mode_info_context->mbmi.mode == B_PRED ||
                   xd->mode_info_context->mbmi.mode == SPLITMV);
-    if (!eobtotal)
+    if (!eobtotal && !vp8dx_bool_error(xd->current_bc))
     {
         /* Special case:  Force the loopfilter to skip when eobtotal and
          * mb_skip_coeff are zero.
@@ -154,14 +155,22 @@
         vp8_build_inter_predictors_mb(xd);
     }
 
+    /* When we have independent partitions we can apply residual even
+     * though other partitions within the frame are corrupt.
+     */
+    throw_residual = (!pbi->independent_partitions &&
+                      pbi->frame_corrupt_residual);
+    throw_residual = (throw_residual || vp8dx_bool_error(xd->current_bc));
+
 #if CONFIG_ERROR_CONCEALMENT
-    if (pbi->ec_enabled &&
+    if (pbi->ec_active &&
         (mb_row * pbi->common.mb_cols + mb_col >= pbi->mvs_corrupt_from_mb ||
-        vp8dx_bool_error(xd->current_bc)))
+        throw_residual))
     {
         /* MB with corrupt residuals or corrupt mode/motion vectors.
          * Better to use the predictor as reconstruction.
          */
+        pbi->frame_corrupt_residual = 1;
         vpx_memset(xd->qcoeff, 0, sizeof(xd->qcoeff));
         vp8_conceal_corrupt_mb(xd);
         return;
@@ -314,25 +323,32 @@
                         xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3;
 
 #if CONFIG_ERROR_CONCEALMENT
-                        if (pbi->ec_enabled &&
-                            (xd->mode_info_context->mbmi.ref_frame ==
-                                                                 INTRA_FRAME) &&
-                            vp8dx_bool_error(xd->current_bc))
                         {
-                            /* We have an intra block with corrupt coefficients,
-                             * better to conceal with an inter block.
-                             * Interpolate MVs from neighboring MBs
-                             *
-                             * Note that for the first mb with corrupt residual
-                             * in a frame, we might not discover that before
-                             * decoding the residual. That happens after this
-                             * check, and therefore no inter concealment will be
-                             * done.
-                             */
-                            vp8_interpolate_motion(xd,
-                                                   mb_row, mb_col,
-                                                   pc->mb_rows, pc->mb_cols,
-                                                   pc->mode_info_stride);
+                            int corrupt_residual =
+                                        (!pbi->independent_partitions &&
+                                        pbi->frame_corrupt_residual) ||
+                                        vp8dx_bool_error(xd->current_bc);
+                            if (pbi->ec_active &&
+                                (xd->mode_info_context->mbmi.ref_frame ==
+                                                                 INTRA_FRAME) &&
+                                corrupt_residual)
+                            {
+                                /* We have an intra block with corrupt
+                                 * coefficients, better to conceal with an inter
+                                 * block.
+                                 * Interpolate MVs from neighboring MBs
+                                 *
+                                 * Note that for the first mb with corrupt
+                                 * residual in a frame, we might not discover
+                                 * that before decoding the residual. That
+                                 * happens after this check, and therefore no
+                                 * inter concealment will be done.
+                                 */
+                                vp8_interpolate_motion(xd,
+                                                       mb_row, mb_col,
+                                                       pc->mb_rows, pc->mb_cols,
+                                                       pc->mode_info_stride);
+                            }
                         }
 #endif
 
@@ -355,9 +371,19 @@
                         xd->pre.u_buffer = pc->yv12_fb[ref_fb_idx].u_buffer + recon_uvoffset;
                         xd->pre.v_buffer = pc->yv12_fb[ref_fb_idx].v_buffer + recon_uvoffset;
 
+                        if (xd->mode_info_context->mbmi.ref_frame !=
+                                INTRA_FRAME)
+                        {
+                            /* propagate errors from reference frames */
+                            xd->corrupted |= pc->yv12_fb[ref_fb_idx].corrupted;
+                        }
+
                         vp8_build_uvmvs(xd, pc->full_pixel);
                         decode_macroblock(pbi, xd, mb_row, mb_col);
 
+                        /* check if the boolean decoder has suffered an error */
+                        xd->corrupted |= vp8dx_bool_error(xd->current_bc);
+
                         if (pbi->common.filter_level)
                         {
                             int skip_lf = (xd->mode_info_context->mbmi.mode != B_PRED &&
@@ -803,23 +829,28 @@
                 xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3;
 
 #if CONFIG_ERROR_CONCEALMENT
-                if (pbi->ec_enabled &&
-                    (xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME) &&
-                    vp8dx_bool_error(xd->current_bc))
                 {
-                    /* We have an intra block with corrupt coefficients, better
-                     * to conceal with an inter block. Interpolate MVs from
-                     * neighboring MBs
-                     *
-                     * Note that for the first mb with corrupt residual in a
-                     * frame, we might not discover that before decoding the
-                     * residual. That happens after this check, and therefore no
-                     * inter concealment will be done.
-                     */
-                    vp8_interpolate_motion(xd,
-                                           mb_row, mb_col,
-                                           pc->mb_rows, pc->mb_cols,
-                                           pc->mode_info_stride);
+                    int corrupt_residual = (!pbi->independent_partitions &&
+                                            pbi->frame_corrupt_residual) ||
+                                            vp8dx_bool_error(xd->current_bc);
+                    if (pbi->ec_active &&
+                        (xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME) &&
+                        corrupt_residual)
+                    {
+                        /* We have an intra block with corrupt coefficients,
+                         * better to conceal with an inter block. Interpolate
+                         * MVs from neighboring MBs
+                         *
+                         * Note that for the first mb with corrupt residual in a
+                         * frame, we might not discover that before decoding the
+                         * residual. That happens after this check, and
+                         * therefore no inter concealment will be done.
+                         */
+                        vp8_interpolate_motion(xd,
+                                               mb_row, mb_col,
+                                               pc->mb_rows, pc->mb_cols,
+                                               pc->mode_info_stride);
+                    }
                 }
 #endif