changeset 753:8e1f0939d15d libavcodec

complete mpeg4 GMC decoding support
author michaelni
date Wed, 16 Oct 2002 19:55:49 +0000
parents 97077dd24bfa
children b2767c9d6455
files common.h dsputil.c dsputil.h h263.c mpegvideo.c mpegvideo.h
diffstat 6 files changed, 349 insertions(+), 177 deletions(-) [+]
line wrap: on
line diff
--- a/common.h	Wed Oct 16 17:23:18 2002 +0000
+++ b/common.h	Wed Oct 16 19:55:49 2002 +0000
@@ -157,6 +157,8 @@
 
 #    define av_abort()      do { fprintf(stderr, "Abort at %s:%d\n", __FILE__, __LINE__); abort(); } while (0)
 
+//rounded divison & shift
+#define RSHIFT(a,b) ((a) > 0 ? ((a) + (1<<((b)-1)))>>(b) : ((a) + (1<<((b)-1))-1)>>(b))
 /* assume b>0 */
 #define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b))
 #define ABS(a) ((a) >= 0 ? (a) : (-(a)))
--- a/dsputil.c	Wed Oct 16 17:23:18 2002 +0000
+++ b/dsputil.c	Wed Oct 16 19:55:49 2002 +0000
@@ -25,7 +25,9 @@
 void (*diff_pixels)(DCTELEM *block, const UINT8 *s1, const UINT8 *s2, int stride);
 void (*put_pixels_clamped)(const DCTELEM *block, UINT8 *pixels, int line_size);
 void (*add_pixels_clamped)(const DCTELEM *block, UINT8 *pixels, int line_size);
-void (*gmc1)(UINT8 *dst, UINT8 *src, int srcStride, int h, int x16, int y16, int rounder);
+void (*ff_gmc1)(UINT8 *dst, UINT8 *src, int srcStride, int h, int x16, int y16, int rounder);
+void (*ff_gmc )(UINT8 *dst, UINT8 *src, int stride, int h, int ox, int oy, 
+                  int dxx, int dxy, int dyx, int dyy, int shift, int r, int width, int height);
 void (*clear_blocks)(DCTELEM *blocks);
 int (*pix_sum)(UINT8 * pix, int line_size);
 int (*pix_norm1)(UINT8 * pix, int line_size);
@@ -822,6 +824,7 @@
 #define avg2(a,b) ((a+b+1)>>1)
 #define avg4(a,b,c,d) ((a+b+c+d+2)>>2)
 
+
 static void gmc1_c(UINT8 *dst, UINT8 *src, int stride, int h, int x16, int y16, int rounder)
 {
     const int A=(16-x16)*(16-y16);
@@ -829,7 +832,6 @@
     const int C=(16-x16)*(   y16);
     const int D=(   x16)*(   y16);
     int i;
-    rounder= 128 - rounder;
 
     for(i=0; i<h; i++)
     {
@@ -846,6 +848,64 @@
     }
 }
 
+static void gmc_c(UINT8 *dst, UINT8 *src, int stride, int h, int ox, int oy, 
+                  int dxx, int dxy, int dyx, int dyy, int shift, int r, int width, int height)
+{
+    int y, vx, vy;
+    const int s= 1<<shift;
+    
+    width--;
+    height--;
+
+    for(y=0; y<h; y++){
+        int x;
+
+        vx= ox;
+        vy= oy;
+        for(x=0; x<8; x++){ //XXX FIXME optimize
+            int src_x, src_y, frac_x, frac_y, index;
+
+            src_x= vx>>16;
+            src_y= vy>>16;
+            frac_x= src_x&(s-1);
+            frac_y= src_y&(s-1);
+            src_x>>=shift;
+            src_y>>=shift;
+  
+            if((unsigned)src_x < width){
+                if((unsigned)src_y < height){
+                    index= src_x + src_y*stride;
+                    dst[y*stride + x]= (  (  src[index         ]*(s-frac_x)
+                                           + src[index       +1]*   frac_x )*(s-frac_y)
+                                        + (  src[index+stride  ]*(s-frac_x)
+                                           + src[index+stride+1]*   frac_x )*   frac_y
+                                        + r)>>(shift*2);
+                }else{
+                    index= src_x + clip(src_y, 0, height)*stride;                    
+                    dst[y*stride + x]= ( (  src[index         ]*(s-frac_x) 
+                                          + src[index       +1]*   frac_x )*s
+                                        + r)>>(shift*2);
+                }
+            }else{
+                if((unsigned)src_y < height){
+                    index= clip(src_x, 0, width) + src_y*stride;                    
+                    dst[y*stride + x]= (  (  src[index         ]*(s-frac_y) 
+                                           + src[index+stride  ]*   frac_y )*s
+                                        + r)>>(shift*2);
+                }else{
+                    index= clip(src_x, 0, width) + clip(src_y, 0, height)*stride;                    
+                    dst[y*stride + x]=    src[index         ];
+                }
+            }
+            
+            vx+= dxx;
+            vy+= dyx;
+        }
+        ox += dxy;
+        oy += dyy;
+    }
+}
+
 static inline void copy_block17(UINT8 *dst, UINT8 *src, int dstStride, int srcStride, int h)
 {
     int i;
@@ -1528,7 +1588,8 @@
     diff_pixels = diff_pixels_c;
     put_pixels_clamped = put_pixels_clamped_c;
     add_pixels_clamped = add_pixels_clamped_c;
-    gmc1= gmc1_c;
+    ff_gmc1= gmc1_c;
+    ff_gmc= gmc_c;
     clear_blocks= clear_blocks_c;
     pix_sum= pix_sum_c;
     pix_norm1= pix_norm1_c;
--- a/dsputil.h	Wed Oct 16 17:23:18 2002 +0000
+++ b/dsputil.h	Wed Oct 16 19:55:49 2002 +0000
@@ -62,7 +62,9 @@
 extern void (*diff_pixels)(DCTELEM *block/*align 16*/, const UINT8 *s1/*align 8*/, const UINT8 *s2/*align 8*/, int stride);
 extern void (*put_pixels_clamped)(const DCTELEM *block/*align 16*/, UINT8 *pixels/*align 8*/, int line_size);
 extern void (*add_pixels_clamped)(const DCTELEM *block/*align 16*/, UINT8 *pixels/*align 8*/, int line_size);
-extern void (*gmc1)(UINT8 *dst/*align 8*/, UINT8 *src/*align 1*/, int srcStride, int h, int x16, int y16, int rounder);
+extern void (*ff_gmc1)(UINT8 *dst/*align 8*/, UINT8 *src/*align 1*/, int srcStride, int h, int x16, int y16, int rounder);
+extern void (*ff_gmc )(UINT8 *dst/*align 8*/, UINT8 *src/*align 1*/, int stride, int h, int ox, int oy, 
+                  int dxx, int dxy, int dyx, int dyy, int shift, int r, int width, int height);
 extern void (*clear_blocks)(DCTELEM *blocks/*align 16*/);
 extern int (*pix_sum)(UINT8 * pix, int line_size);
 extern int (*pix_norm1)(UINT8 * pix, int line_size);
--- a/h263.c	Wed Oct 16 17:23:18 2002 +0000
+++ b/h263.c	Wed Oct 16 19:55:49 2002 +0000
@@ -34,9 +34,6 @@
 //#undef NDEBUG
 //#include <assert.h>
 
-//rounded divison & shift
-#define RSHIFT(a,b) ((a) > 0 ? ((a) + (1<<((b)-1)))>>(b) : ((a) + (1<<((b)-1))-1)>>(b))
-
 #if 1
 #define PRINT_MB_TYPE(a) {}
 #else
@@ -2433,6 +2430,49 @@
 }
 
 /**
+ * @param n either 0 for the x component or 1 for y
+ * @returns the average MV for a GMC MB
+ */
+static inline int get_amv(MpegEncContext *s, int n){
+    int x, y, mb_v, sum, dx, dy, shift;
+    int len = 1 << (s->f_code + 4);
+    const int a= s->sprite_warping_accuracy;
+
+    if(s->real_sprite_warping_points==1){
+        if(s->divx_version==500 && s->divx_build==413)
+            sum= s->sprite_offset[0][n] / (1<<(a - s->quarter_sample));
+        else
+            sum= RSHIFT(s->sprite_offset[0][n]<<s->quarter_sample, a);
+    }else{
+        dx= s->sprite_delta[n][0];
+        dy= s->sprite_delta[n][1];
+        shift= s->sprite_shift[0];
+        if(n) dy -= 1<<(shift + a + 1);
+        else  dx -= 1<<(shift + a + 1);
+        mb_v= s->sprite_offset[0][n] + dx*s->mb_x*16 + dy*s->mb_y*16;
+
+        sum=0;
+        for(y=0; y<16; y++){
+            int v;
+        
+            v= mb_v + dy*y;
+            //XXX FIXME optimize
+            for(x=0; x<16; x++){
+                sum+= v>>shift;
+                v+= dx;
+            }
+        }
+        sum /= 256;
+        sum= RSHIFT(sum<<s->quarter_sample, a);
+    }
+
+    if      (sum < -len) sum= -len;
+    else if (sum >= len) sum= len-1;
+
+    return sum;
+}
+
+/**
  * decodes first partition.
  * @return number of MBs decoded or <0 if an error occured
  */
@@ -2508,20 +2548,12 @@
                     /* skip mb */
                     s->mb_type[xy]= MB_TYPE_SKIPED;
                     if(s->pict_type==S_TYPE && s->vol_sprite_usage==GMC_SPRITE){
-                        const int a= s->sprite_warping_accuracy;
                         PRINT_MB_TYPE("G");
-                        if(s->divx_version==500 && s->divx_build==413){
-                            mx = s->sprite_offset[0][0] / (1<<(a-s->quarter_sample));
-                            my = s->sprite_offset[0][1] / (1<<(a-s->quarter_sample));
-                        }else{
-                            mx = RSHIFT(s->sprite_offset[0][0], a-s->quarter_sample);
-                            my = RSHIFT(s->sprite_offset[0][1], a-s->quarter_sample);
-                            s->mb_type[xy]= MB_TYPE_GMC | MB_TYPE_SKIPED;
-                        }
+                        mx= get_amv(s, 0);
+                        my= get_amv(s, 1);
                     }else{
                         PRINT_MB_TYPE("S");
-                        mx = 0;
-                        my = 0;
+                        mx=my=0;
                     }
                     mot_val[0       ]= mot_val[2       ]=
                     mot_val[0+stride]= mot_val[2+stride]= mx;
@@ -2570,31 +2602,19 @@
                         s->mb_type[xy]= MB_TYPE_INTER;
 
                         h263_pred_motion(s, 0, &pred_x, &pred_y);
-                        if(!s->mcsel)
-                           mx = h263_decode_motion(s, pred_x, s->f_code);
-                        else {
-                            const int a= s->sprite_warping_accuracy;
-                            if(s->divx_version==500 && s->divx_build==413){
-                                mx = s->sprite_offset[0][0] / (1<<(a-s->quarter_sample));
-                            }else{
-                                mx = RSHIFT(s->sprite_offset[0][0], a-s->quarter_sample);
-                            }
+                        if(!s->mcsel){
+                            mx = h263_decode_motion(s, pred_x, s->f_code);
+                            if (mx >= 0xffff)
+                                return -1;
+
+                            my = h263_decode_motion(s, pred_y, s->f_code);
+                            if (my >= 0xffff)
+                                return -1;
+                        } else {
+                            mx = get_amv(s, 0);
+                            my = get_amv(s, 1);
                         }
-                        if (mx >= 0xffff)
-                            return -1;
-            
-                        if(!s->mcsel)
-                           my = h263_decode_motion(s, pred_y, s->f_code);
-                        else{
-                           const int a= s->sprite_warping_accuracy;
-                            if(s->divx_version==500 && s->divx_build==413){
-                                my = s->sprite_offset[0][1] / (1<<(a-s->quarter_sample));
-                            }else{
-                                my = RSHIFT(s->sprite_offset[0][1], a-s->quarter_sample);
-                            }
-                        }
-                        if (my >= 0xffff)
-                            return -1;
+
                         mot_val[0       ]= mot_val[2       ] =
                         mot_val[0+stride]= mot_val[2+stride]= mx;
                         mot_val[1       ]= mot_val[3       ]=
@@ -2876,21 +2896,10 @@
             s->mv_dir = MV_DIR_FORWARD;
             s->mv_type = MV_TYPE_16X16;
             if(s->pict_type==S_TYPE && s->vol_sprite_usage==GMC_SPRITE){
-                const int a= s->sprite_warping_accuracy;
-//                int l = (1 << (s->f_code - 1)) * 32;
                 PRINT_MB_TYPE("G");
                 s->mcsel=1;
-                if(s->divx_version==500 && s->divx_build==413){
-                    s->mv[0][0][0] = s->sprite_offset[0][0] / (1<<(a-s->quarter_sample));
-                    s->mv[0][0][1] = s->sprite_offset[0][1] / (1<<(a-s->quarter_sample));
-                }else{
-                    s->mv[0][0][0] = RSHIFT(s->sprite_offset[0][0], a-s->quarter_sample);
-                    s->mv[0][0][1] = RSHIFT(s->sprite_offset[0][1], a-s->quarter_sample);
-                }
-/*                if (s->mv[0][0][0] < -l) s->mv[0][0][0]= -l;
-                else if (s->mv[0][0][0] >= l) s->mv[0][0][0]= l-1;
-                if (s->mv[0][0][1] < -l) s->mv[0][0][1]= -l;
-                else if (s->mv[0][0][1] >= l) s->mv[0][0][1]= l-1;*/
+                s->mv[0][0][0]= get_amv(s, 0);
+                s->mv[0][0][1]= get_amv(s, 1);
 
                 s->mb_skiped = 0;
             }else{
@@ -2929,19 +2938,11 @@
         s->mv_dir = MV_DIR_FORWARD;
         if ((cbpc & 16) == 0) {
             if(s->mcsel){
-                const int a= s->sprite_warping_accuracy;
                 PRINT_MB_TYPE("G");
                 /* 16x16 global motion prediction */
                 s->mv_type = MV_TYPE_16X16;
-//        int l = (1 << (s->f_code - 1)) * 32;
-                if(s->divx_version==500 && s->divx_build==413){
-                    mx = s->sprite_offset[0][0] / (1<<(a-s->quarter_sample));
-                    my = s->sprite_offset[0][1] / (1<<(a-s->quarter_sample));
-                }else{
-                    mx = RSHIFT(s->sprite_offset[0][0], a-s->quarter_sample);
-                    my = RSHIFT(s->sprite_offset[0][1], a-s->quarter_sample);
-                }
-//       int l = (1 << (s->f_code - 1)) * 32;
+                mx= get_amv(s, 0);
+                my= get_amv(s, 1);
                 s->mv[0][0][0] = mx;
                 s->mv[0][0][1] = my;
             }else if((!s->progressive_sequence) && get_bits1(&s->gb)){
@@ -3862,11 +3863,12 @@
     int d[4][2]={{0,0}, {0,0}, {0,0}, {0,0}};
     int sprite_ref[4][2];
     int virtual_ref[2][2];
-    int w2, h2;
+    int w2, h2, w3, h3;
     int alpha=0, beta=0;
     int w= s->width;
     int h= s->height;
-//printf("SP %d\n", s->sprite_warping_accuracy);
+    int min_ab;
+
     for(i=0; i<s->num_sprite_warping_points; i++){
         int length;
         int x=0, y=0;
@@ -3874,7 +3876,7 @@
         length= get_vlc(&s->gb, &sprite_trajectory);
         if(length){
             x= get_bits(&s->gb, length);
-//printf("lx %d %d\n", length, x);
+
             if ((x >> (length - 1)) == 0) /* if MSB not set it is negative*/
                 x = - (x ^ ((1 << length) - 1));
         }
@@ -3883,14 +3885,12 @@
         length= get_vlc(&s->gb, &sprite_trajectory);
         if(length){
             y=get_bits(&s->gb, length);
-//printf("ly %d %d\n", length, y);
+
             if ((y >> (length - 1)) == 0) /* if MSB not set it is negative*/
                 y = - (y ^ ((1 << length) - 1));
         }
         skip_bits1(&s->gb); /* marker bit */
 //printf("%d %d %d %d\n", x, y, i, s->sprite_warping_accuracy);
-//if(i>0 && (x!=0 || y!=0)) printf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n");
-//x=y=0;
         d[i][0]= x;
         d[i][1]= y;
     }
@@ -3931,7 +3931,7 @@
         + ROUNDED_DIV(((h - h2)*(r*sprite_ref[0][0] - 16*vop_ref[0][0]) + h2*(r*sprite_ref[2][0] - 16*vop_ref[2][0])),h);
     virtual_ref[1][1]= 16*(vop_ref[0][1] + h2) 
         + ROUNDED_DIV(((h - h2)*(r*sprite_ref[0][1] - 16*vop_ref[0][1]) + h2*(r*sprite_ref[2][1] - 16*vop_ref[2][1])),h);
-
+        
     switch(s->num_sprite_warping_points)
     {
         case 0:
@@ -3939,107 +3939,133 @@
             s->sprite_offset[0][1]= 0;
             s->sprite_offset[1][0]= 0;
             s->sprite_offset[1][1]= 0;
-            s->sprite_delta[0][0][0]= a;
-            s->sprite_delta[0][0][1]= 0;
-            s->sprite_delta[0][1][0]= 0;
-            s->sprite_delta[0][1][1]= a;
-            s->sprite_delta[1][0][0]= a;
-            s->sprite_delta[1][0][1]= 0;
-            s->sprite_delta[1][1][0]= 0;
-            s->sprite_delta[1][1][1]= a;
-            s->sprite_shift[0][0]= 0;
-            s->sprite_shift[0][1]= 0;
-            s->sprite_shift[1][0]= 0;
-            s->sprite_shift[1][1]= 0;
+            s->sprite_delta[0][0]= a;
+            s->sprite_delta[0][1]= 0;
+            s->sprite_delta[1][0]= 0;
+            s->sprite_delta[1][1]= a;
+            s->sprite_shift[0]= 0;
+            s->sprite_shift[1]= 0;
             break;
         case 1: //GMC only
             s->sprite_offset[0][0]= sprite_ref[0][0] - a*vop_ref[0][0];
             s->sprite_offset[0][1]= sprite_ref[0][1] - a*vop_ref[0][1];
             s->sprite_offset[1][0]= ((sprite_ref[0][0]>>1)|(sprite_ref[0][0]&1)) - a*(vop_ref[0][0]/2);
             s->sprite_offset[1][1]= ((sprite_ref[0][1]>>1)|(sprite_ref[0][1]&1)) - a*(vop_ref[0][1]/2);
-            s->sprite_delta[0][0][0]= a;
-            s->sprite_delta[0][0][1]= 0;
-            s->sprite_delta[0][1][0]= 0;
-            s->sprite_delta[0][1][1]= a;
-            s->sprite_delta[1][0][0]= a;
-            s->sprite_delta[1][0][1]= 0;
-            s->sprite_delta[1][1][0]= 0;
-            s->sprite_delta[1][1][1]= a;
-            s->sprite_shift[0][0]= 0;
-            s->sprite_shift[0][1]= 0;
-            s->sprite_shift[1][0]= 0;
-            s->sprite_shift[1][1]= 0;
+            s->sprite_delta[0][0]= a;
+            s->sprite_delta[0][1]= 0;
+            s->sprite_delta[1][0]= 0;
+            s->sprite_delta[1][1]= a;
+            s->sprite_shift[0]= 0;
+            s->sprite_shift[1]= 0;
             break;
         case 2:
-        case 3: //FIXME
             s->sprite_offset[0][0]= (sprite_ref[0][0]<<(alpha+rho))
-                                                  + ((-r*sprite_ref[0][0] + virtual_ref[0][0])*(-vop_ref[0][0])
-                                                    +( r*sprite_ref[0][1] - virtual_ref[0][1])*(-vop_ref[0][1]));
+                                                  + (-r*sprite_ref[0][0] + virtual_ref[0][0])*(-vop_ref[0][0])
+                                                  + ( r*sprite_ref[0][1] - virtual_ref[0][1])*(-vop_ref[0][1])
+                                                  + (1<<(alpha+rho-1));
             s->sprite_offset[0][1]= (sprite_ref[0][1]<<(alpha+rho))
-                                                  + ((-r*sprite_ref[0][1] + virtual_ref[0][1])*(-vop_ref[0][0])
-                                                    +(-r*sprite_ref[0][0] + virtual_ref[0][0])*(-vop_ref[0][1]));
-            s->sprite_offset[1][0]= ((-r*sprite_ref[0][0] + virtual_ref[0][0])*(-2*vop_ref[0][0] + 1)
-                                 +( r*sprite_ref[0][1] - virtual_ref[0][1])*(-2*vop_ref[0][1] + 1)
-                                 +2*w2*r*sprite_ref[0][0] - 16*w2);
-            s->sprite_offset[1][1]= ((-r*sprite_ref[0][1] + virtual_ref[0][1])*(-2*vop_ref[0][0] + 1) 
-                                 +(-r*sprite_ref[0][0] + virtual_ref[0][0])*(-2*vop_ref[0][1] + 1)
-                                 +2*w2*r*sprite_ref[0][1] - 16*w2);
-            s->sprite_delta[0][0][0]=   (-r*sprite_ref[0][0] + virtual_ref[0][0]);
-            s->sprite_delta[0][0][1]=   ( r*sprite_ref[0][1] - virtual_ref[0][1]);
-            s->sprite_delta[0][1][0]=   (-r*sprite_ref[0][1] + virtual_ref[0][1]);
-            s->sprite_delta[0][1][1]=   (-r*sprite_ref[0][0] + virtual_ref[0][0]);
-            s->sprite_delta[1][0][0]= 4*(-r*sprite_ref[0][0] + virtual_ref[0][0]);
-            s->sprite_delta[1][0][1]= 4*( r*sprite_ref[0][1] - virtual_ref[0][1]);
-            s->sprite_delta[1][1][0]= 4*(-r*sprite_ref[0][1] + virtual_ref[0][1]);
-            s->sprite_delta[1][1][1]= 4*(-r*sprite_ref[0][0] + virtual_ref[0][0]);
-            s->sprite_shift[0][0]= alpha+rho;
-            s->sprite_shift[0][1]= alpha+rho;
-            s->sprite_shift[1][0]= alpha+rho+2;
-            s->sprite_shift[1][1]= alpha+rho+2;
+                                                  + (-r*sprite_ref[0][1] + virtual_ref[0][1])*(-vop_ref[0][0])
+                                                  + (-r*sprite_ref[0][0] + virtual_ref[0][0])*(-vop_ref[0][1])
+                                                  + (1<<(alpha+rho-1));
+            s->sprite_offset[1][0]= ( (-r*sprite_ref[0][0] + virtual_ref[0][0])*(-2*vop_ref[0][0] + 1)
+                                     +( r*sprite_ref[0][1] - virtual_ref[0][1])*(-2*vop_ref[0][1] + 1)
+                                     +2*w2*r*sprite_ref[0][0] 
+                                     - 16*w2 
+                                     + (1<<(alpha+rho+1)));
+            s->sprite_offset[1][1]= ( (-r*sprite_ref[0][1] + virtual_ref[0][1])*(-2*vop_ref[0][0] + 1) 
+                                     +(-r*sprite_ref[0][0] + virtual_ref[0][0])*(-2*vop_ref[0][1] + 1)
+                                     +2*w2*r*sprite_ref[0][1] 
+                                     - 16*w2
+                                     + (1<<(alpha+rho+1)));
+            s->sprite_delta[0][0]=   (-r*sprite_ref[0][0] + virtual_ref[0][0]);
+            s->sprite_delta[0][1]=   (+r*sprite_ref[0][1] - virtual_ref[0][1]);
+            s->sprite_delta[1][0]=   (-r*sprite_ref[0][1] + virtual_ref[0][1]);
+            s->sprite_delta[1][1]=   (-r*sprite_ref[0][0] + virtual_ref[0][0]);
+            
+            s->sprite_shift[0]= alpha+rho;
+            s->sprite_shift[1]= alpha+rho+2;
             break;
-//        case 3:
+        case 3:
+            min_ab= MIN(alpha, beta);
+            w3= w2>>min_ab;
+            h3= h2>>min_ab;
+            s->sprite_offset[0][0]=  (sprite_ref[0][0]<<(alpha+beta+rho-min_ab))
+                                   + (-r*sprite_ref[0][0] + virtual_ref[0][0])*h3*(-vop_ref[0][0])
+                                   + (-r*sprite_ref[0][0] + virtual_ref[1][0])*w3*(-vop_ref[0][1])
+                                   + (1<<(alpha+beta+rho-min_ab-1));
+            s->sprite_offset[0][1]=  (sprite_ref[0][1]<<(alpha+beta+rho-min_ab))
+                                   + (-r*sprite_ref[0][1] + virtual_ref[0][1])*h3*(-vop_ref[0][0])
+                                   + (-r*sprite_ref[0][1] + virtual_ref[1][1])*w3*(-vop_ref[0][1])
+                                   + (1<<(alpha+beta+rho-min_ab-1));
+            s->sprite_offset[1][0]=  (-r*sprite_ref[0][0] + virtual_ref[0][0])*h3*(-2*vop_ref[0][0] + 1)
+                                   + (-r*sprite_ref[0][0] + virtual_ref[1][0])*w3*(-2*vop_ref[0][1] + 1)
+                                   + 2*w2*h3*r*sprite_ref[0][0]
+                                   - 16*w2*h3
+                                   + (1<<(alpha+beta+rho-min_ab+1));
+            s->sprite_offset[1][1]=  (-r*sprite_ref[0][1] + virtual_ref[0][1])*h3*(-2*vop_ref[0][0] + 1)
+                                   + (-r*sprite_ref[0][1] + virtual_ref[1][1])*w3*(-2*vop_ref[0][1] + 1)
+                                   + 2*w2*h3*r*sprite_ref[0][1]
+                                   - 16*w2*h3
+                                   + (1<<(alpha+beta+rho-min_ab+1));
+            s->sprite_delta[0][0]=   (-r*sprite_ref[0][0] + virtual_ref[0][0])*h3;
+            s->sprite_delta[0][1]=   (-r*sprite_ref[0][0] + virtual_ref[1][0])*w3;
+            s->sprite_delta[1][0]=   (-r*sprite_ref[0][1] + virtual_ref[0][1])*h3;
+            s->sprite_delta[1][1]=   (-r*sprite_ref[0][1] + virtual_ref[1][1])*w3;
+                                   
+            s->sprite_shift[0]= alpha + beta + rho - min_ab;
+            s->sprite_shift[1]= alpha + beta + rho - min_ab + 2;
             break;
     }
-/*printf("%d %d\n", s->sprite_delta[0][0][0], a<<s->sprite_shift[0][0]);
-printf("%d %d\n", s->sprite_delta[0][0][1], 0);
-printf("%d %d\n", s->sprite_delta[0][1][0], 0);
-printf("%d %d\n", s->sprite_delta[0][1][1], a<<s->sprite_shift[0][1]);
-printf("%d %d\n", s->sprite_delta[1][0][0], a<<s->sprite_shift[1][0]);
-printf("%d %d\n", s->sprite_delta[1][0][1], 0);
-printf("%d %d\n", s->sprite_delta[1][1][0], 0);
-printf("%d %d\n", s->sprite_delta[1][1][1], a<<s->sprite_shift[1][1]);*/
     /* try to simplify the situation */ 
-    if(   s->sprite_delta[0][0][0] == a<<s->sprite_shift[0][0]
-       && s->sprite_delta[0][0][1] == 0
-       && s->sprite_delta[0][1][0] == 0
-       && s->sprite_delta[0][1][1] == a<<s->sprite_shift[0][1]
-       && s->sprite_delta[1][0][0] == a<<s->sprite_shift[1][0]
-       && s->sprite_delta[1][0][1] == 0
-       && s->sprite_delta[1][1][0] == 0
-       && s->sprite_delta[1][1][1] == a<<s->sprite_shift[1][1])
+    if(   s->sprite_delta[0][0] == a<<s->sprite_shift[0]
+       && s->sprite_delta[0][1] == 0
+       && s->sprite_delta[1][0] == 0
+       && s->sprite_delta[1][1] == a<<s->sprite_shift[0])
     {
-        s->sprite_offset[0][0]>>=s->sprite_shift[0][0];
-        s->sprite_offset[0][1]>>=s->sprite_shift[0][1];
-        s->sprite_offset[1][0]>>=s->sprite_shift[1][0];
-        s->sprite_offset[1][1]>>=s->sprite_shift[1][1];
-        s->sprite_delta[0][0][0]= a;
-        s->sprite_delta[0][0][1]= 0;
-        s->sprite_delta[0][1][0]= 0;
-        s->sprite_delta[0][1][1]= a;
-        s->sprite_delta[1][0][0]= a;
-        s->sprite_delta[1][0][1]= 0;
-        s->sprite_delta[1][1][0]= 0;
-        s->sprite_delta[1][1][1]= a;
-        s->sprite_shift[0][0]= 0;
-        s->sprite_shift[0][1]= 0;
-        s->sprite_shift[1][0]= 0;
-        s->sprite_shift[1][1]= 0;
+        s->sprite_offset[0][0]>>=s->sprite_shift[0];
+        s->sprite_offset[0][1]>>=s->sprite_shift[0];
+        s->sprite_offset[1][0]>>=s->sprite_shift[1];
+        s->sprite_offset[1][1]>>=s->sprite_shift[1];
+        s->sprite_delta[0][0]= a;
+        s->sprite_delta[0][1]= 0;
+        s->sprite_delta[1][0]= 0;
+        s->sprite_delta[1][1]= a;
+        s->sprite_shift[0]= 0;
+        s->sprite_shift[1]= 0;
         s->real_sprite_warping_points=1;
     }
-    else
+    else{
+        int shift_y= 16 - s->sprite_shift[0];
+        int shift_c= 16 - s->sprite_shift[1];
+//printf("shifts %d %d\n", shift_y, shift_c);
+        for(i=0; i<2; i++){
+            s->sprite_offset[0][i]<<= shift_y;
+            s->sprite_offset[1][i]<<= shift_c;
+            s->sprite_delta[0][i]<<= shift_y;
+            s->sprite_delta[1][i]<<= shift_y;
+            s->sprite_shift[i]= 16;
+        }
         s->real_sprite_warping_points= s->num_sprite_warping_points;
-
-//printf("%d %d %d %d\n", d[0][0], d[0][1], s->sprite_offset[0][0], s->sprite_offset[0][1]);
+    }
+#if 0
+printf("vop:%d:%d %d:%d %d:%d, sprite:%d:%d %d:%d %d:%d, virtual: %d:%d %d:%d\n",
+    vop_ref[0][0], vop_ref[0][1],
+    vop_ref[1][0], vop_ref[1][1],
+    vop_ref[2][0], vop_ref[2][1],
+    sprite_ref[0][0], sprite_ref[0][1], 
+    sprite_ref[1][0], sprite_ref[1][1], 
+    sprite_ref[2][0], sprite_ref[2][1], 
+    virtual_ref[0][0], virtual_ref[0][1], 
+    virtual_ref[1][0], virtual_ref[1][1]
+    );
+    
+printf("offset: %d:%d , delta: %d %d %d %d, shift %d\n",
+    s->sprite_offset[0][0], s->sprite_offset[0][1],
+    s->sprite_delta[0][0], s->sprite_delta[0][1],
+    s->sprite_delta[1][0], s->sprite_delta[1][1],
+    s->sprite_shift[0]
+    );
+#endif
 }
 
 static int decode_vol_header(MpegEncContext *s, GetBitContext *gb){
@@ -4337,8 +4363,7 @@
         printf("low_delay flag set, but shouldnt, clearing it\n");
         s->low_delay=0;
     }
-// printf("pic: %d, qpel:%d part:%d resync:%d\n", s->pict_type, s->quarter_sample, s->data_partitioning, s->resync_marker); 
-    
+ 
     s->partitioned_frame= s->data_partitioning && s->pict_type!=B_TYPE;
     if(s->partitioned_frame)
         s->decode_mb= mpeg4_decode_partitioned_mb;
@@ -4483,11 +4508,12 @@
          }else
              s->b_code=1;
 #if 0
-printf("qp:%d fc:%d bc:%d type:%s size:%d pro:%d alt:%d top:%d qpel:%d part:%d resync:%d\n", 
+printf("qp:%d fc:%d bc:%d type:%s size:%d pro:%d alt:%d top:%d qpel:%d part:%d resync:%d w:%d a:%d\n", 
     s->qscale, s->f_code, s->b_code, 
     s->pict_type == I_TYPE ? "I" : (s->pict_type == P_TYPE ? "P" : (s->pict_type == B_TYPE ? "B" : "S")), 
     gb->size,s->progressive_sequence, s->alternate_scan, s->top_field_first, 
-    s->quarter_sample, s->data_partitioning, s->resync_marker); 
+    s->quarter_sample, s->data_partitioning, s->resync_marker, s->num_sprite_warping_points,
+    s->sprite_warping_accuracy); 
 #endif
          if(!s->scalability){
              if (s->shape!=RECT_SHAPE && s->pict_type!=I_TYPE) {
--- a/mpegvideo.c	Wed Oct 16 17:23:18 2002 +0000
+++ b/mpegvideo.c	Wed Oct 16 19:55:49 2002 +0000
@@ -1032,15 +1032,13 @@
 static inline void gmc1_motion(MpegEncContext *s,
                                UINT8 *dest_y, UINT8 *dest_cb, UINT8 *dest_cr,
                                int dest_offset,
-                               UINT8 **ref_picture, int src_offset,
-                               int h)
+                               UINT8 **ref_picture, int src_offset)
 {
     UINT8 *ptr;
     int offset, src_x, src_y, linesize, uvlinesize;
     int motion_x, motion_y;
     int emu=0;
 
-    if(s->real_sprite_warping_points>1) printf("more than 1 warp point isnt supported\n");
     motion_x= s->sprite_offset[0][0];
     motion_y= s->sprite_offset[0][1];
     src_x = s->mb_x * 16 + (motion_x >> (s->sprite_warping_accuracy+1));
@@ -1053,22 +1051,37 @@
     src_y = clip(src_y, -16, s->height);
     if (src_y == s->height)
         motion_y =0;
-    
+
     linesize = s->linesize;
     uvlinesize = s->uvlinesize;
+    
     ptr = ref_picture[0] + (src_y * linesize) + src_x + src_offset;
 
     dest_y+=dest_offset;
     if(s->flags&CODEC_FLAG_EMU_EDGE){
         if(src_x<0 || src_y<0 || src_x + (motion_x&15) + 16 > s->h_edge_pos
-                              || src_y + (motion_y&15) + h  > s->v_edge_pos){
-            emulated_edge_mc(s, ptr, linesize, 17, h+1, src_x, src_y, s->h_edge_pos, s->v_edge_pos);
+                              || src_y + (motion_y&15) + 16 > s->v_edge_pos){
+            emulated_edge_mc(s, ptr, linesize, 17, 17, src_x, src_y, s->h_edge_pos, s->v_edge_pos);
             ptr= s->edge_emu_buffer;
             emu=1;
         }
     }
-    gmc1(dest_y  , ptr  , linesize, h, motion_x&15, motion_y&15, s->no_rounding);
-    gmc1(dest_y+8, ptr+8, linesize, h, motion_x&15, motion_y&15, s->no_rounding);
+    
+    if((motion_x|motion_y)&7){
+        ff_gmc1(dest_y  , ptr  , linesize, 16, motion_x&15, motion_y&15, 128 - s->no_rounding);
+        ff_gmc1(dest_y+8, ptr+8, linesize, 16, motion_x&15, motion_y&15, 128 - s->no_rounding);
+    }else{
+        int dxy;
+        
+        dxy= ((motion_x>>3)&1) | ((motion_y>>2)&2);
+        if (s->no_rounding){
+            put_no_rnd_pixels_tab[0][dxy](dest_y, ptr, linesize, 16);
+        }else{
+            put_pixels_tab       [0][dxy](dest_y, ptr, linesize, 16);
+        }        
+    }
+    
+    if(s->flags&CODEC_FLAG_GRAY) return;
 
     motion_x= s->sprite_offset[1][0];
     motion_y= s->sprite_offset[1][1];
@@ -1086,21 +1099,85 @@
     offset = (src_y * uvlinesize) + src_x + (src_offset>>1);
     ptr = ref_picture[1] + offset;
     if(emu){
-        emulated_edge_mc(s, ptr, uvlinesize, 9, (h>>1)+1, src_x, src_y, s->h_edge_pos>>1, s->v_edge_pos>>1);
+        emulated_edge_mc(s, ptr, uvlinesize, 9, 9, src_x, src_y, s->h_edge_pos>>1, s->v_edge_pos>>1);
         ptr= s->edge_emu_buffer;
     }
-    gmc1(dest_cb + (dest_offset>>1), ptr, uvlinesize, h>>1, motion_x&15, motion_y&15, s->no_rounding);
+    ff_gmc1(dest_cb + (dest_offset>>1), ptr, uvlinesize, 8, motion_x&15, motion_y&15, 128 - s->no_rounding);
     
     ptr = ref_picture[2] + offset;
     if(emu){
-        emulated_edge_mc(s, ptr, uvlinesize, 9, (h>>1)+1, src_x, src_y, s->h_edge_pos>>1, s->v_edge_pos>>1);
+        emulated_edge_mc(s, ptr, uvlinesize, 9, 9, src_x, src_y, s->h_edge_pos>>1, s->v_edge_pos>>1);
         ptr= s->edge_emu_buffer;
     }
-    gmc1(dest_cr + (dest_offset>>1), ptr, uvlinesize, h>>1, motion_x&15, motion_y&15, s->no_rounding);
+    ff_gmc1(dest_cr + (dest_offset>>1), ptr, uvlinesize, 8, motion_x&15, motion_y&15, 128 - s->no_rounding);
     
     return;
 }
 
+static inline void gmc_motion(MpegEncContext *s,
+                               UINT8 *dest_y, UINT8 *dest_cb, UINT8 *dest_cr,
+                               int dest_offset,
+                               UINT8 **ref_picture, int src_offset)
+{
+    UINT8 *ptr;
+    int linesize, uvlinesize;
+    const int a= s->sprite_warping_accuracy;
+    int ox, oy;
+
+    linesize = s->linesize;
+    uvlinesize = s->uvlinesize;
+
+    ptr = ref_picture[0] + src_offset;
+
+    dest_y+=dest_offset;
+    
+    ox= s->sprite_offset[0][0] + s->sprite_delta[0][0]*s->mb_x*16 + s->sprite_delta[0][1]*s->mb_y*16;
+    oy= s->sprite_offset[0][1] + s->sprite_delta[1][0]*s->mb_x*16 + s->sprite_delta[1][1]*s->mb_y*16;
+
+    ff_gmc(dest_y, ptr, linesize, 16, 
+           ox, 
+           oy, 
+           s->sprite_delta[0][0], s->sprite_delta[0][1],
+           s->sprite_delta[1][0], s->sprite_delta[1][1], 
+           a+1, (1<<(2*a+1)) - s->no_rounding,
+           s->h_edge_pos, s->v_edge_pos);
+    ff_gmc(dest_y+8, ptr, linesize, 16, 
+           ox + s->sprite_delta[0][0]*8, 
+           oy + s->sprite_delta[1][0]*8, 
+           s->sprite_delta[0][0], s->sprite_delta[0][1],
+           s->sprite_delta[1][0], s->sprite_delta[1][1], 
+           a+1, (1<<(2*a+1)) - s->no_rounding,
+           s->h_edge_pos, s->v_edge_pos);
+
+    if(s->flags&CODEC_FLAG_GRAY) return;
+
+
+    dest_cb+=dest_offset>>1;
+    dest_cr+=dest_offset>>1;
+    
+    ox= s->sprite_offset[1][0] + s->sprite_delta[0][0]*s->mb_x*8 + s->sprite_delta[0][1]*s->mb_y*8;
+    oy= s->sprite_offset[1][1] + s->sprite_delta[1][0]*s->mb_x*8 + s->sprite_delta[1][1]*s->mb_y*8;
+
+    ptr = ref_picture[1] + (src_offset>>1);
+    ff_gmc(dest_cb, ptr, uvlinesize, 8, 
+           ox, 
+           oy, 
+           s->sprite_delta[0][0], s->sprite_delta[0][1],
+           s->sprite_delta[1][0], s->sprite_delta[1][1], 
+           a+1, (1<<(2*a+1)) - s->no_rounding,
+           s->h_edge_pos>>1, s->v_edge_pos>>1);
+    
+    ptr = ref_picture[2] + (src_offset>>1);
+    ff_gmc(dest_cr, ptr, uvlinesize, 8, 
+           ox, 
+           oy, 
+           s->sprite_delta[0][0], s->sprite_delta[0][1],
+           s->sprite_delta[1][0], s->sprite_delta[1][1], 
+           a+1, (1<<(2*a+1)) - s->no_rounding,
+           s->h_edge_pos>>1, s->v_edge_pos>>1);
+}
+
+
 static void emulated_edge_mc(MpegEncContext *s, UINT8 *src, int linesize, int block_w, int block_h, 
                                     int src_x, int src_y, int w, int h){
     int x, y;
@@ -1357,9 +1434,13 @@
     switch(s->mv_type) {
     case MV_TYPE_16X16:
         if(s->mcsel){
-            gmc1_motion(s, dest_y, dest_cb, dest_cr, 0,
-                        ref_picture, 0,
-                        16);
+            if(s->real_sprite_warping_points==1){
+                gmc1_motion(s, dest_y, dest_cb, dest_cr, 0,
+                            ref_picture, 0);
+            }else{
+                gmc_motion(s, dest_y, dest_cb, dest_cr, 0,
+                            ref_picture, 0);
+            }
         }else if(s->quarter_sample){
             qpel_motion(s, dest_y, dest_cb, dest_cr, 0,
                         ref_picture, 0,
--- a/mpegvideo.h	Wed Oct 16 17:23:18 2002 +0000
+++ b/mpegvideo.h	Wed Oct 16 19:55:49 2002 +0000
@@ -369,9 +369,9 @@
     int sprite_brightness_change;
     int num_sprite_warping_points;
     int real_sprite_warping_points;
-    int sprite_offset[2][2];
-    int sprite_delta[2][2][2];
-    int sprite_shift[2][2];
+    int sprite_offset[2][2];         /* sprite offset[isChroma][isMVY] */
+    int sprite_delta[2][2];          /* sprite_delta [isY][isMVY] */ 
+    int sprite_shift[2];             /* sprite shift [isChroma] */
     int mcsel;
     int quant_precision;
     int quarter_sample;              /* 1->qpel, 0->half pel ME/MC */