changeset 5040:5c6cd6601371 libavcodec

change brute force search to min-heap. 3.6x faster generate_len_table, 8% faster ffvhuff encoding.
author lorenm
date Sat, 19 May 2007 02:32:59 +0000
parents 325557621708
children 01a165280429
files huffyuv.c
diffstat 1 files changed, 43 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/huffyuv.c	Sat May 19 00:53:41 2007 +0000
+++ b/huffyuv.c	Sat May 19 02:32:59 2007 +0000
@@ -261,57 +261,57 @@
 }
 
 #ifdef CONFIG_ENCODERS
+typedef struct {
+    uint64_t val;
+    int name;
+} heap_elem_t;
+
+static void heap_sift(heap_elem_t *h, int root, int size)
+{
+    while(root*2+1 < size) {
+        int child = root*2+1;
+        if(child < size-1 && h[child].val > h[child+1].val)
+            child++;
+        if(h[root].val > h[child].val) {
+            FFSWAP(heap_elem_t, h[root], h[child]);
+            root = child;
+        } else
+            break;
+    }
+}
+
 static void generate_len_table(uint8_t *dst, uint64_t *stats, int size){
-    uint64_t counts[2*size];
+    heap_elem_t h[size];
     int up[2*size];
+    int len[2*size];
     int offset, i, next;
 
     for(offset=1; ; offset<<=1){
         for(i=0; i<size; i++){
-            counts[i]= stats[i] + offset - 1;
+            h[i].name = i;
+            h[i].val = (stats[i] << 8) + offset;
+        }
+        for(i=size/2-1; i>=0; i--)
+            heap_sift(h, i, size);
+
+        for(next=size; next<size*2-1; next++){
+            // merge the two smallest entries, and put it back in the heap
+            uint64_t min1v = h[0].val;
+            up[h[0].name] = next;
+            h[0].val = INT64_MAX;
+            heap_sift(h, 0, size);
+            up[h[0].name] = next;
+            h[0].name = next;
+            h[0].val += min1v;
+            heap_sift(h, 0, size);
         }
 
-        for(next=size; next<size*2; next++){
-            uint64_t min1, min2;
-            int min1_i, min2_i;
-
-            min1=min2= INT64_MAX;
-            min1_i= min2_i=-1;
-
-            for(i=0; i<next; i++){
-                if(min2 > counts[i]){
-                    if(min1 > counts[i]){
-                        min2= min1;
-                        min2_i= min1_i;
-                        min1= counts[i];
-                        min1_i= i;
-                    }else{
-                        min2= counts[i];
-                        min2_i= i;
-                    }
-                }
-            }
-
-            if(min2==INT64_MAX) break;
-
-            counts[next]= min1 + min2;
-            counts[min1_i]=
-            counts[min2_i]= INT64_MAX;
-            up[min1_i]=
-            up[min2_i]= next;
-            up[next]= -1;
-        }
-
-        for(i=0; i<size; i++){
-            int len;
-            int index=i;
-
-            for(len=0; up[index] != -1; len++)
-                index= up[index];
-
-            if(len >= 32) break;
-
-            dst[i]= len;
+        len[2*size-2] = 0;
+        for(i=2*size-3; i>=size; i--)
+            len[i] = len[up[i]] + 1;
+        for(i=0; i<size; i++) {
+            dst[i] = len[up[i]] + 1;
+            if(dst[i] > 32) break;
         }
         if(i==size) break;
     }