[Ffmpeg-devel] improved [PATCH] fix DV encoder VLC bit accounting

Dan Maas dmaas
Thu Feb 23 00:40:58 CET 2006


Here is an updated patch. I believe this addresses all of Michael's
concerns. It only updates the single affected coefficient. The results
are identical to my previous patch, but the performance hit is more
like 1.5% now.

Unfortunately I can't send you Stuart's test video, but believe me,
without the fix there are very noticeable artifacts on some frames.
They are most visible on frames with a lot of high-frequency content.

Regards,
Dan
-------------- next part --------------
Index: libavcodec/dv.c
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavcodec/dv.c,v
retrieving revision 1.71
diff -u -p -u -r1.71 dv.c
--- libavcodec/dv.c	5 Feb 2006 13:35:16 -0000	1.71
+++ libavcodec/dv.c	22 Feb 2006 23:34:46 -0000
@@ -594,6 +594,7 @@ typedef struct EncBlockInfo {
     int area_q[4];
     int bit_size[4];
     int prev[5];
+    int last_nonzero[4]; /* index of last nonzero AC coefficient within each area */
     int cur_ac;
     int cno;
     int dct_mode;
@@ -658,6 +659,7 @@ static always_inline void dv_set_class_n
     bi->mb[0] = blk[0];
 
     for (area = 0; area < 4; area++) {
+       bi->last_nonzero[area] = -1;
        bi->prev[area] = prev;
        bi->bit_size[area] = 1; // 4 areas 4 bits for EOB :)
        for (i=mb_area_start[area]; i<mb_area_start[area+1]; i++) {
@@ -668,6 +670,7 @@ static always_inline void dv_set_class_n
               bi->mb[i] = level= ABS(level)>>4;
               if(level>max) max= level;
               bi->bit_size[area] += dv_rl2vlc_size(i - prev  - 1, level);
+              bi->last_nonzero[area] = i;
               bi->next[prev]= i;
               prev= i;
           }
@@ -683,6 +686,7 @@ static always_inline void dv_set_class_n
         prev=0;
         i= bi->next[prev];
         for (area = 0; area < 4; area++) {
+            bi->last_nonzero[area] = -1;
             bi->prev[area] = prev;
             bi->bit_size[area] = 1; // 4 areas 4 bits for EOB :)
             for (; i<mb_area_start[area+1]; i= bi->next[i]) {
@@ -691,6 +695,7 @@ static always_inline void dv_set_class_n
                 if (bi->mb[i]) {
                     bi->bit_size[area] += dv_rl2vlc_size(i - prev - 1, bi->mb[i]);
                     bi->next[prev]= i;
+                    bi->last_nonzero[area] = i;
                     prev= i;
                 }
             }
@@ -740,8 +745,15 @@ static inline void dv_guess_qnos(EncBloc
           qnos[i]--;
           size[i] = 0;
           for (j=0; j<6; j++, b++) {
+             /* index of area in which to force update of incoming run length */
+             int update_vlc = -1;
+             /* if update_vlc != -1, the start index of the old run */
+             int old_run = 0;
              for (a=0; a<4; a++) {
                 if (b->area_q[a] != dv_quant_shifts[qnos[i] + dv_quant_offset[b->cno]][a]) {
+                    /* Update quantizations and bit_size */
+                    int last = b->last_nonzero[a];
+                    b->last_nonzero[a] = -1;
                     b->bit_size[a] = 1; // 4 areas 4 bits for EOB :)
                     b->area_q[a]++;
                     prev= b->prev[a];
@@ -749,12 +761,35 @@ static inline void dv_guess_qnos(EncBloc
                        b->mb[k] >>= 1;
                        if (b->mb[k]) {
                            b->bit_size[a] += dv_rl2vlc_size(k - prev - 1, b->mb[k]);
+                           b->last_nonzero[a] = k;
                            prev= k;
                        } else {
+                           /* Coefficient became zero */
                            b->next[prev] = b->next[k];
+                           if (k == last) {
+                               /* Last nonzero coefficient has become zero */
+                               /* Set flag to update bit_size of following area */
+                               update_vlc = a+1;
+                               old_run = k;
+                           }
                        }
                     }
                     b->prev[a+1]= prev;
+                } else if (update_vlc == a) {
+                    /* Update bit_size of following area */
+                    /* We must do this since RLE code lengths depend on run length */
+                    prev = b->prev[a];
+                    k = b->next[prev];
+                    if (k < mb_area_start[a+1]) {
+                        /* Adjust bit_size to account for new incoming run length */
+                        b->bit_size[a] += dv_rl2vlc_size(k - prev - 1, b->mb[k]) -
+                            dv_rl2vlc_size(k - old_run - 1, b->mb[k]);
+                        update_vlc = -1;
+                    } else {
+                        /* This area is all zero, set flag for next area */
+                        update_vlc = a+1;
+                        b->prev[a+1] = prev;
+                    }
                 }
                 size[i] += b->bit_size[a];
              }



More information about the ffmpeg-devel mailing list