changeset 1144:21c85c4ab2f0 libavcodec

error resilience cleanup (its faster too...)
author michaelni
date Thu, 20 Mar 2003 01:00:57 +0000
parents a4facfd78935
children 79e8ed620b17
files avcodec.h error_resilience.c h263.c h263dec.c mpegvideo.h msmpeg4.c wmv2.c
diffstat 7 files changed, 113 insertions(+), 71 deletions(-) [+]
line wrap: on
line diff
--- a/avcodec.h	Tue Mar 18 20:08:57 2003 +0000
+++ b/avcodec.h	Thu Mar 20 01:00:57 2003 +0000
@@ -909,6 +909,7 @@
 #define FF_DEBUG_SKIP      0x00000080
 #define FF_DEBUG_STARTCODE 0x00000100
 #define FF_DEBUG_PTS       0x00000200
+#define FF_DEBUG_ER        0x00000400
     
     /**
      * error.
--- a/error_resilience.c	Tue Mar 18 20:08:57 2003 +0000
+++ b/error_resilience.c	Thu Mar 20 01:00:57 2003 +0000
@@ -26,6 +26,7 @@
 #include "avcodec.h"
 #include "dsputil.h"
 #include "mpegvideo.h"
+#include "common.h"
 
 /**
  * replaces the current MB with a flat dc only version.
@@ -580,12 +581,91 @@
     return is_intra_likely > 0;    
 }
 
-void ff_error_resilience(MpegEncContext *s){
+void ff_er_frame_start(MpegEncContext *s){
+    if(!s->error_resilience) return;
+
+    memset(s->error_status_table, MV_ERROR|AC_ERROR|DC_ERROR|VP_START|AC_END|DC_END|MV_END, s->mb_num*sizeof(uint8_t));
+}
+
+/**
+ * adds a slice.
+ * @param endx x component of the last macroblock, can be -1 for the last of the previous line
+ * @param status the status at the end (MV_END, AC_ERROR, ...), it is assumed that no earlier end or
+ *               error of the same type occured
+ */
+void ff_er_add_slice(MpegEncContext *s, int startx, int starty, int endx, int endy, int status){
+    const int start_xy= clip(startx + starty * s->mb_width, 0, s->mb_num-1);
+    const int end_xy  = clip(endx   + endy   * s->mb_width, 0, s->mb_num);
+    const int mb_count= end_xy - start_xy;
+    int mask= -1;
+    
+    if(!s->error_resilience) return;
+
+    mask &= ~VP_START;
+    if(status & (AC_ERROR|AC_END)) mask &= ~(AC_ERROR|AC_END);
+    if(status & (DC_ERROR|DC_END)) mask &= ~(DC_ERROR|DC_END);
+    if(status & (MV_ERROR|MV_END)) mask &= ~(MV_ERROR|MV_END);    
+
+    if(mask == ~0x7F){
+        memset(&s->error_status_table[start_xy], 0, mb_count * sizeof(uint8_t));
+    }else{
+        int i;
+        for(i=start_xy; i<end_xy; i++){
+            s->error_status_table[i] &= mask;
+        }
+    }
+
+    s->error_status_table[start_xy] |= VP_START;
+    
+    if(end_xy < s->mb_num){
+        s->error_status_table[end_xy] &= mask;
+        s->error_status_table[end_xy] |= status;
+    }
+}
+
+void ff_er_frame_end(MpegEncContext *s){
     int i, mb_x, mb_y, error, error_type;
     int distance;
     int threshold_part[4]= {100,100,100};
     int threshold= 50;
     int is_intra_likely;
+    int num_end_markers=0;
+    
+    if(!s->error_resilience) return;
+
+    error=0;
+    for(i=0; i<s->mb_num; i++){
+        int status= s->error_status_table[i];
+        
+        if(status==0) continue;
+
+        if(status&(DC_ERROR|AC_ERROR|MV_ERROR))
+            error=1;
+        if(status&VP_START){
+            if(num_end_markers) 
+                error=1;
+            num_end_markers=3;
+        }
+        if(status&AC_END)
+            num_end_markers--;
+        if(status&DC_END)
+            num_end_markers--;
+        if(status&MV_END)
+            num_end_markers--;
+    }
+    if(num_end_markers==0 && error==0)
+        return;
+
+    fprintf(stderr, "concealing errors\n");
+
+    if(s->avctx->debug&FF_DEBUG_ER){    
+        for(i=0; i<s->mb_num; i++){
+            int status= s->error_status_table[i];
+            
+            if(i%s->mb_width == 0) printf("\n");
+            printf("%2X ", status); 
+        }
+    }
     
 #if 1
     /* handle overlapping slices */
--- a/h263.c	Tue Mar 18 20:08:57 2003 +0000
+++ b/h263.c	Thu Mar 20 01:00:57 2003 +0000
@@ -2760,8 +2760,6 @@
                     if(dc_pred_dir) dir|=1;
                 }
                 s->pred_dir_table[xy]= dir;
-                
-                s->error_status_table[xy]= AC_ERROR;
             }else{ /* P/S_TYPE */
                 int mx, my, pred_x, pred_y, bits;
                 int16_t * const mot_val= s->motion_val[s->block_index[0]];
@@ -2790,8 +2788,6 @@
 
                     if(s->mbintra_table[xy])
                         ff_clean_intra_table_entries(s);
-
-                    s->error_status_table[xy]= AC_ERROR;
                     continue;
                 }
                 cbpc = get_vlc2(&s->gb, inter_MCBPC_vlc.table, INTER_MCBPC_VLC_BITS, 2);
@@ -2815,7 +2811,6 @@
                     mot_val[0+stride]= mot_val[2+stride]= 0;
                     mot_val[1       ]= mot_val[3       ]=
                     mot_val[1+stride]= mot_val[3+stride]= 0;
-                    s->error_status_table[xy]= DC_ERROR|AC_ERROR;
                 }else{
                     if(s->mbintra_table[xy])
                         ff_clean_intra_table_entries(s);
@@ -2864,7 +2859,6 @@
                             mot_val[1] = my;
                         }
                     }
-                    s->error_status_table[xy]= AC_ERROR;
                 }
             }
         }
@@ -2933,7 +2927,6 @@
                     s->cbp_table[xy]&= 3; //remove dquant
                     s->cbp_table[xy]|= cbpy<<2;
                     s->pred_dir_table[xy]= dir | (ac_pred<<7);
-                    s->error_status_table[xy]&= ~DC_ERROR;
                 }else if(s->mb_type[xy]&MB_TYPE_SKIPED){
                     s->current_picture.qscale_table[xy]= s->qscale;
                     s->cbp_table[xy]= 0;
@@ -2968,13 +2961,18 @@
 int ff_mpeg4_decode_partitions(MpegEncContext *s)
 {
     int mb_num;
+    const int part_a_error= s->pict_type==I_TYPE ? (DC_ERROR|MV_ERROR) : MV_ERROR;
+    const int part_a_end  = s->pict_type==I_TYPE ? (DC_END  |MV_END)   : MV_END;
     
     mb_num= mpeg4_decode_partition_a(s);    
-    if(mb_num<0)
+    if(mb_num<0){
+        ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, part_a_error);
         return -1;
+    }
     
     if(s->resync_mb_x + s->resync_mb_y*s->mb_width + mb_num > s->mb_num){
         fprintf(stderr, "slice below monitor ...\n");
+        ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, part_a_error);
         return -1;
     }
 
@@ -2984,21 +2982,23 @@
         if(get_bits(&s->gb, 19)!=DC_MARKER){
             fprintf(stderr, "marker missing after first I partition at %d %d\n", s->mb_x, s->mb_y);
             return -1;
-        }else
-            s->error_status_table[s->mb_x + s->mb_y*s->mb_width-1]|= MV_END|DC_END;
+        }
     }else{
         if(get_bits(&s->gb, 17)!=MOTION_MARKER){
             fprintf(stderr, "marker missing after first P partition at %d %d\n", s->mb_x, s->mb_y);
             return -1;
-        }else
-            s->error_status_table[s->mb_x + s->mb_y*s->mb_width-1]|= MV_END;
+        }
     }
+    ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x-1, s->mb_y, part_a_end);
     
     if( mpeg4_decode_partition_b(s, mb_num) < 0){
+        if(s->pict_type==P_TYPE)
+            ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, DC_ERROR);
         return -1;
+    }else{
+        if(s->pict_type==P_TYPE)
+            ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x-1, s->mb_y, DC_END);
     }
-    
-    s->error_status_table[s->mb_x + s->mb_y*s->mb_width-1]|= DC_END;
 
     return 0;        
 }
@@ -3071,8 +3071,6 @@
         }
     }
 
-    s->error_status_table[xy]&= ~AC_ERROR;
-
     /* per-MB end of slice check */
 
     if(--s->mb_num_left <= 0){
@@ -3096,8 +3094,6 @@
     int16_t *mot_val;
     static int8_t quant_tab[4] = { -1, -2, 1, 2 };
 
-    s->error_status_table[s->mb_x + s->mb_y*s->mb_width]= 0;
-
     if(s->mb_x==0) PRINT_MB_TYPE("\n");
 
     if (s->pict_type == P_TYPE || s->pict_type==S_TYPE) {
--- a/h263dec.c	Tue Mar 18 20:08:57 2003 +0000
+++ b/h263dec.c	Thu Mar 20 01:00:57 2003 +0000
@@ -144,6 +144,7 @@
 }
 
 static int decode_slice(MpegEncContext *s){
+    const int part_mask= s->partitioned_frame ? (AC_END|AC_ERROR) : 0x7F;
     s->last_resync_gb= s->gb;
     s->first_slice_line= 1;
         
@@ -174,8 +175,8 @@
         /* per-row end of slice checks */
         if(s->msmpeg4_version){
             if(s->resync_mb_y + s->slice_height == s->mb_y){
-                const int xy= s->mb_x + s->mb_y*s->mb_width;
-                s->error_status_table[xy-1]|= AC_END|DC_END|MV_END;
+                ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x-1, s->mb_y, AC_END|DC_END|MV_END);
+
                 return 0;
             }
         }
@@ -211,9 +212,7 @@
                 const int xy= s->mb_x + s->mb_y*s->mb_width;
                 if(ret==SLICE_END){
 //printf("%d %d %d %06X\n", s->mb_x, s->mb_y, s->gb.size*8 - get_bits_count(&s->gb), show_bits(&s->gb, 24));
-                    s->error_status_table[xy]|= AC_END;
-                    if(!s->partitioned_frame)
-                        s->error_status_table[xy]|= MV_END|DC_END;
+                    ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, (AC_END|DC_END|MV_END)&part_mask);
 
                     s->padding_bug_score--;
                         
@@ -225,12 +224,11 @@
                     return 0; 
                 }else if(ret==SLICE_NOEND){
                     fprintf(stderr,"Slice mismatch at MB: %d\n", xy);
+                    ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x+1, s->mb_y, (AC_END|DC_END|MV_END)&part_mask);
                     return -1;
                 }
                 fprintf(stderr,"Error at MB: %d\n", xy);
-                s->error_status_table[xy]|= AC_ERROR;
-                if(!s->partitioned_frame)
-                    s->error_status_table[xy]|= DC_ERROR|MV_ERROR;
+                ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, (AC_ERROR|DC_ERROR|MV_ERROR)&part_mask);
     
                 return -1;
             }
@@ -290,7 +288,7 @@
         else if(left<0){
             fprintf(stderr, "overreading %d bits\n", -left);
         }else
-            s->error_status_table[s->mb_num-1]|= AC_END|MV_END|DC_END;
+            ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x-1, s->mb_y, AC_END|DC_END|MV_END);
         
         return 0;
     }
@@ -298,6 +296,9 @@
     fprintf(stderr, "slice end not reached but screenspace end (%d left %06X)\n", 
             s->gb.size_in_bits - get_bits_count(&s->gb),
             show_bits(&s->gb, 24));
+            
+    ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, (AC_END|DC_END|MV_END)&part_mask);
+
     return -1;
 }
 
@@ -596,7 +597,6 @@
         || ABS(new_aspect - avctx->aspect_ratio) > 0.001) {
         /* H.263 could change picture size any time */
         MPV_common_end(s);
-        s->context_initialized=0;
     }
     if (!s->context_initialized) {
         avctx->width = s->width;
@@ -641,8 +641,7 @@
     printf("qscale=%d\n", s->qscale);
 #endif
 
-    if(s->error_resilience)
-        memset(s->error_status_table, MV_ERROR|AC_ERROR|DC_ERROR|VP_START|AC_END|DC_END|MV_END, s->mb_num*sizeof(uint8_t));
+    ff_er_frame_start(s);
     
     /* decode each macroblock */
     s->block_wrap[0]=
@@ -655,7 +654,6 @@
     s->mb_y=0;
     
     decode_slice(s);
-    s->error_status_table[0]|= VP_START;
     while(s->mb_y<s->mb_height && s->gb.size_in_bits - get_bits_count(&s->gb)>16){
         if(s->msmpeg4_version){
             if(s->mb_x!=0 || (s->mb_y%s->slice_height)!=0)
@@ -669,8 +667,6 @@
             ff_mpeg4_clean_buffers(s);
 
         decode_slice(s);
-
-        s->error_status_table[s->resync_mb_x + s->resync_mb_y*s->mb_width]|= VP_START;
     }
 
     if (s->h263_msmpeg4 && s->msmpeg4_version<4 && s->pict_type==I_TYPE)
@@ -699,35 +695,7 @@
         }
     }
 
-    if(s->error_resilience){
-        int error=0, num_end_markers=0;
-        for(i=0; i<s->mb_num; i++){
-            int status= s->error_status_table[i];
-#if 0
-            if(i%s->mb_width == 0) printf("\n");
-            printf("%2X ", status); 
-#endif
-            if(status==0) continue;
-
-            if(status&(DC_ERROR|AC_ERROR|MV_ERROR))
-                error=1;
-            if(status&VP_START){
-                if(num_end_markers) 
-                    error=1;
-                num_end_markers=3;
-            }
-            if(status&AC_END)
-                num_end_markers--;
-            if(status&DC_END)
-                num_end_markers--;
-            if(status&MV_END)
-                num_end_markers--;
-        }
-        if(num_end_markers || error){
-            fprintf(stderr, "concealing errors\n");
-            ff_error_resilience(s);
-        }
-    }
+    ff_er_frame_end(s);
 
     MPV_frame_end(s);
 
--- a/mpegvideo.h	Tue Mar 18 20:08:57 2003 +0000
+++ b/mpegvideo.h	Thu Mar 20 01:00:57 2003 +0000
@@ -629,17 +629,20 @@
 void MPV_common_init_ppc(MpegEncContext *s);
 #endif
 extern void (*draw_edges)(uint8_t *buf, int wrap, int width, int height, int w);
-void ff_conceal_past_errors(MpegEncContext *s, int conceal_all);
 void ff_copy_bits(PutBitContext *pb, uint8_t *src, int length);
 void ff_clean_intra_table_entries(MpegEncContext *s);
 void ff_init_scantable(MpegEncContext *s, ScanTable *st, const uint8_t *src_scantable);
-void ff_error_resilience(MpegEncContext *s);
 void ff_draw_horiz_band(MpegEncContext *s, int y, int h);
 void ff_emulated_edge_mc(MpegEncContext *s, uint8_t *src, int linesize, int block_w, int block_h, 
                                     int src_x, int src_y, int w, int h);
 char ff_get_pict_type_char(int pict_type);
 int ff_combine_frame( MpegEncContext *s, int next, uint8_t **buf, int *buf_size);
 
+void ff_er_frame_start(MpegEncContext *s);
+void ff_er_frame_end(MpegEncContext *s);
+void ff_er_add_slice(MpegEncContext *s, int startx, int starty, int endx, int endy, int status);
+
+
 extern enum PixelFormat ff_yuv420p_list[2];
 
 static inline void ff_init_block_index(MpegEncContext *s){
--- a/msmpeg4.c	Tue Mar 18 20:08:57 2003 +0000
+++ b/msmpeg4.c	Thu Mar 20 01:00:57 2003 +0000
@@ -1486,8 +1486,6 @@
 {
     int cbp, code, i;
     
-    s->error_status_table[s->mb_x + s->mb_y*s->mb_width]= 0;
-    
     if (s->pict_type == P_TYPE) {
         if (s->use_skip_mb_code) {
             if (get_bits1(&s->gb)) {
@@ -1581,8 +1579,6 @@
 }
 #endif
 
-    s->error_status_table[s->mb_x + s->mb_y*s->mb_width]= 0;
-    
     if (s->pict_type == P_TYPE) {
         set_stat(ST_INTER_MB);
         if (s->use_skip_mb_code) {
--- a/wmv2.c	Tue Mar 18 20:08:57 2003 +0000
+++ b/wmv2.c	Thu Mar 20 01:00:57 2003 +0000
@@ -710,8 +710,6 @@
 
     if(w->j_type) return 0;
     
-    s->error_status_table[s->mb_x + s->mb_y*s->mb_width]= 0;
-    
     if (s->pict_type == P_TYPE) {
         if(s->mb_type[s->mb_y * s->mb_width + s->mb_x]&MB_TYPE_SKIPED){
             /* skip mb */