changeset 1644:835cf346975e libavcodec

h263 loop filter fixed h263 modified quantization CODEC_FLAG_OBMC
author michael
date Mon, 01 Dec 2003 15:23:14 +0000
parents 9bb07bd315d9
children 901f928ec1f6
files avcodec.h dsputil.c dsputil.h h263.c h263data.h h263dec.c mpeg12.c mpegvideo.c mpegvideo.h rv10.c
diffstat 10 files changed, 262 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/avcodec.h	Sun Nov 30 19:04:56 2003 +0000
+++ b/avcodec.h	Mon Dec 01 15:23:14 2003 +0000
@@ -260,6 +260,8 @@
 #define CODEC_FLAG_CBP_RD         0x04000000 ///< use rate distortion optimization for cbp
 #define CODEC_FLAG_QP_RD          0x08000000 ///< use rate distortion optimization for qp selectioon
 #define CODEC_FLAG_H263P_AIV      0x00000008 ///< H263 Alternative inter vlc
+#define CODEC_FLAG_OBMC           0x00000001 ///< OBMC
+#define CODEC_FLAG_LOOP_FILTER    0x00000800 ///< loop filter
 /* For advanced prediction mode, we reuse the 4MV flag */
 /* Unsupported options :
  * 		Syntax Arithmetic coding (SAC)
--- a/dsputil.c	Sun Nov 30 19:04:56 2003 +0000
+++ b/dsputil.c	Mon Dec 01 15:23:14 2003 +0000
@@ -2261,6 +2261,75 @@
     wmv2_mspel8_v_lowpass(dst, halfH+8, stride, 8, 8);
 }
 
+static void h263_v_loop_filter_c(uint8_t *src, int stride, int qscale){
+    int x;
+    const int strength= ff_h263_loop_filter_strength[qscale];
+    
+    for(x=0; x<8; x++){
+        int d1, d2, ad1;
+        int p0= src[x-2*stride];
+        int p1= src[x-1*stride];
+        int p2= src[x+0*stride];
+        int p3= src[x+1*stride];
+        int d = (p0 - p3 + 4*(p2 - p1)) / 8;
+
+        if     (d<-2*strength) d1= 0;
+        else if(d<-  strength) d1=-2*strength - d;
+        else if(d<   strength) d1= d;
+        else if(d< 2*strength) d1= 2*strength - d;
+        else                   d1= 0;
+        
+        p1 += d1;
+        p2 -= d1;
+        if(p1&256) p1= ~(p1>>31);
+        if(p2&256) p2= ~(p2>>31);
+        
+        src[x-1*stride] = p1;
+        src[x+0*stride] = p2;
+
+        ad1= ABS(d1);
+        
+        d2= clip((p0-p3)/4, -ad1, ad1);
+        
+        src[x-2*stride] = p0 - d2;
+        src[x+  stride] = p3 + d2;
+    }
+}
+
+static void h263_h_loop_filter_c(uint8_t *src, int stride, int qscale){
+    int y;
+    const int strength= ff_h263_loop_filter_strength[qscale];
+    
+    for(y=0; y<8; y++){
+        int d1, d2, ad1;
+        int p0= src[y*stride-2];
+        int p1= src[y*stride-1];
+        int p2= src[y*stride+0];
+        int p3= src[y*stride+1];
+        int d = (p0 - p3 + 4*(p2 - p1)) / 8;
+
+        if     (d<-2*strength) d1= 0;
+        else if(d<-  strength) d1=-2*strength - d;
+        else if(d<   strength) d1= d;
+        else if(d< 2*strength) d1= 2*strength - d;
+        else                   d1= 0;
+        
+        p1 += d1;
+        p2 -= d1;
+        if(p1&256) p1= ~(p1>>31);
+        if(p2&256) p2= ~(p2>>31);
+        
+        src[y*stride-1] = p1;
+        src[y*stride+0] = p2;
+
+        ad1= ABS(d1)>>1;
+        
+        d2= clip((p0-p3)/4, -ad1, ad1);
+        
+        src[y*stride-2] = p0 - d2;
+        src[y*stride+1] = p3 + d2;
+    }
+}
 
 static inline int pix_abs16x16_c(uint8_t *pix1, uint8_t *pix2, int line_size)
 {
@@ -3048,6 +3117,9 @@
     c->diff_bytes= diff_bytes_c;
     c->sub_hfyu_median_prediction= sub_hfyu_median_prediction_c;
     c->bswap_buf= bswap_buf;
+    
+    c->h263_h_loop_filter= h263_h_loop_filter_c;
+    c->h263_v_loop_filter= h263_v_loop_filter_c;
 
 #ifdef HAVE_MMX
     dsputil_init_mmx(c, avctx);
--- a/dsputil.h	Sun Nov 30 19:04:56 2003 +0000
+++ b/dsputil.h	Mon Dec 01 15:23:14 2003 +0000
@@ -245,6 +245,9 @@
     void (*sub_hfyu_median_prediction)(uint8_t *dst, uint8_t *src1, uint8_t *src2, int w, int *left, int *left_top);
     void (*bswap_buf)(uint32_t *dst, uint32_t *src, int w);
     
+    void (*h263_v_loop_filter)(uint8_t *src, int stride, int qscale);
+    void (*h263_h_loop_filter)(uint8_t *src, int stride, int qscale);
+
     /* (I)DCT */
     void (*fdct)(DCTELEM *block/* align 16*/);
     void (*fdct248)(DCTELEM *block/* align 16*/);
--- a/h263.c	Sun Nov 30 19:04:56 2003 +0000
+++ b/h263.c	Mon Dec 01 15:23:14 2003 +0000
@@ -237,17 +237,16 @@
             put_bits(&s->pb, 3, format);
             
         put_bits(&s->pb,1,0); /* Custom PCF: off */
-        s->umvplus = s->unrestricted_mv;
         put_bits(&s->pb, 1, s->umvplus); /* Unrestricted Motion Vector */
         put_bits(&s->pb,1,0); /* SAC: off */
         put_bits(&s->pb,1,s->obmc); /* Advanced Prediction Mode */
         put_bits(&s->pb,1,s->h263_aic); /* Advanced Intra Coding */
-        put_bits(&s->pb,1,0); /* Deblocking Filter: off */
+        put_bits(&s->pb,1,s->loop_filter); /* Deblocking Filter */
         put_bits(&s->pb,1,0); /* Slice Structured: off */
         put_bits(&s->pb,1,0); /* Reference Picture Selection: off */
         put_bits(&s->pb,1,0); /* Independent Segment Decoding: off */
         put_bits(&s->pb,1,s->alt_inter_vlc); /* Alternative Inter VLC */
-        put_bits(&s->pb,1,0); /* Modified Quantization: off */
+        put_bits(&s->pb,1,s->modified_quant); /* Modified Quantization: */
         put_bits(&s->pb,1,1); /* "1" to prevent start code emulation */
         put_bits(&s->pb,3,0); /* Reserved */
 		
@@ -279,6 +278,7 @@
         /* Unlimited Unrestricted Motion Vectors Indicator (UUI) */
         if (s->umvplus)
 //            put_bits(&s->pb,1,1); /* Limited according tables of Annex D */
+//FIXME check actual requested range
             put_bits(&s->pb,2,1); /* unlimited */
 
         put_bits(&s->pb, 5, s->qscale);
@@ -1234,6 +1234,93 @@
 }
 #endif
 
+int ff_h263_loop_filter(MpegEncContext * s){
+    int qp_c;
+    const int linesize  = s->linesize;
+    const int uvlinesize= s->uvlinesize;
+    const int xy = s->mb_y * s->mb_stride + s->mb_x;
+    uint8_t *dest_y = s->dest[0];
+    uint8_t *dest_cb= s->dest[1];
+    uint8_t *dest_cr= s->dest[2];
+    
+//    if(s->pict_type==B_TYPE && !s->readable) return;
+
+    /*
+       Diag Top
+       Left Center
+    */
+    if(!IS_SKIP(s->current_picture.mb_type[xy])){
+        qp_c= s->qscale;
+        s->dsp.h263_v_loop_filter(dest_y+8*linesize  , linesize, qp_c);
+        s->dsp.h263_v_loop_filter(dest_y+8*linesize+8, linesize, qp_c);
+    }else
+        qp_c= 0;
+
+    if(s->mb_y){
+        int qp_dt, qp_t, qp_tc;
+
+        if(IS_SKIP(s->current_picture.mb_type[xy-s->mb_stride]))
+            qp_t=0;
+        else 
+            qp_t= s->current_picture.qscale_table[xy-s->mb_stride];
+
+        if(qp_c) 
+            qp_tc= qp_c;
+        else
+            qp_tc= qp_t;
+            
+        if(qp_tc){
+            const int chroma_qp= s->chroma_qscale_table[qp_tc];
+            s->dsp.h263_v_loop_filter(dest_y  ,   linesize, qp_tc);
+            s->dsp.h263_v_loop_filter(dest_y+8,   linesize, qp_tc);
+        
+            s->dsp.h263_v_loop_filter(dest_cb , uvlinesize, chroma_qp);
+            s->dsp.h263_v_loop_filter(dest_cr , uvlinesize, chroma_qp);
+        }
+        
+        if(qp_t)
+            s->dsp.h263_h_loop_filter(dest_y-8*linesize+8  ,   linesize, qp_t);
+        
+        if(s->mb_x){
+            if(qp_t || IS_SKIP(s->current_picture.mb_type[xy-1-s->mb_stride]))
+                qp_dt= qp_t;
+            else
+                qp_dt= s->current_picture.qscale_table[xy-1-s->mb_stride];
+            
+            if(qp_dt){
+                const int chroma_qp= s->chroma_qscale_table[qp_dt];
+                s->dsp.h263_h_loop_filter(dest_y -8*linesize  ,   linesize, qp_dt);
+                s->dsp.h263_h_loop_filter(dest_cb-8*uvlinesize, uvlinesize, chroma_qp);
+                s->dsp.h263_h_loop_filter(dest_cb-8*uvlinesize, uvlinesize, chroma_qp);
+            }
+        }
+    }
+
+    if(qp_c){
+        s->dsp.h263_h_loop_filter(dest_y +8,   linesize, qp_c);
+        if(s->mb_y + 1 == s->mb_height)
+            s->dsp.h263_h_loop_filter(dest_y+8*linesize+8,   linesize, qp_c);
+    }
+    
+    if(s->mb_x){
+        int qp_lc;
+        if(qp_c || IS_SKIP(s->current_picture.mb_type[xy-1]))
+            qp_lc= qp_c;
+        else
+            qp_lc= s->current_picture.qscale_table[xy-1];
+        
+        if(qp_lc){
+            s->dsp.h263_h_loop_filter(dest_y,   linesize, qp_lc);
+            if(s->mb_y + 1 == s->mb_height){
+                const int chroma_qp= s->chroma_qscale_table[qp_lc];
+                s->dsp.h263_h_loop_filter(dest_y +8*  linesize,   linesize, qp_lc);
+                s->dsp.h263_h_loop_filter(dest_cb             , uvlinesize, chroma_qp);
+                s->dsp.h263_h_loop_filter(dest_cr             , uvlinesize, chroma_qp);
+            }
+        }
+    }
+}
+
 static int h263_pred_dc(MpegEncContext * s, int n, uint16_t **dc_val_ptr)
 {
     int x, y, wrap, a, c, pred_dc, scale;
@@ -2162,9 +2249,11 @@
         s->qscale = 1;
     else if (s->qscale > 31)
         s->qscale = 31;
+        
+    s->chroma_qscale= s->chroma_qscale_table[s->qscale];
 
     s->y_dc_scale= s->y_dc_scale_table[ s->qscale ];
-    s->c_dc_scale= s->c_dc_scale_table[ s->qscale ];
+    s->c_dc_scale= s->c_dc_scale_table[ s->chroma_qscale ];
 }
 
 /**
@@ -2657,6 +2746,8 @@
     s->qscale = get_bits(&s->gb, 5); /* GQUANT */
     if(s->qscale==0) 
         return -1;
+    s->chroma_qscale= s->chroma_qscale_table[s->qscale];
+
     s->mb_x= 0;
     s->mb_y= s->gob_index* s->gob_number;
     if(s->mb_y >= s->mb_height) 
@@ -2820,7 +2911,7 @@
     if(s->shape != BIN_ONLY_SHAPE){
         int qscale= get_bits(&s->gb, s->quant_precision); 
         if(qscale)
-            s->qscale= qscale;
+            s->chroma_qscale=s->qscale= qscale;
     }
 
     if(s->shape == RECT_SHAPE){
@@ -3302,9 +3393,9 @@
     cbp = s->cbp_table[xy];
 
     if(s->current_picture.qscale_table[xy] != s->qscale){
-        s->qscale= s->current_picture.qscale_table[xy];
+        s->chroma_qscale=s->qscale= s->current_picture.qscale_table[xy];
         s->y_dc_scale= s->y_dc_scale_table[ s->qscale ];
-        s->c_dc_scale= s->c_dc_scale_table[ s->qscale ];
+        s->c_dc_scale= s->c_dc_scale_table[ s->chroma_qscale ];
     }
     
     if (s->pict_type == P_TYPE || s->pict_type==S_TYPE) {
@@ -3495,7 +3586,7 @@
                 s->mcsel=0;
                 s->mv[0][0][0] = 0;
                 s->mv[0][0][1] = 0;
-                s->mb_skiped = !s->obmc;
+                s->mb_skiped = !(s->obmc | s->loop_filter);
             }
             goto end;
         }
@@ -4440,7 +4531,7 @@
             av_log(s->avctx, AV_LOG_ERROR, "H263 PB frame not supported\n");
             return -1;	/* not PB frame */
         }
-        s->qscale = get_bits(&s->gb, 5);
+        s->chroma_qscale= s->qscale = get_bits(&s->gb, 5);
         skip_bits1(&s->gb);	/* Continuous Presence Multipoint mode: off */
 
         s->width = width;
@@ -4459,14 +4550,14 @@
             dprintf("ufep=1, format: %d\n", format);
             skip_bits(&s->gb,1); /* Custom PCF */
             s->umvplus = get_bits(&s->gb, 1); /* Unrestricted Motion Vector */
-            skip_bits1(&s->gb); /* Syntax-based Arithmetic Coding (SAC) */
+            if (get_bits1(&s->gb) != 0) {
+                av_log(s->avctx, AV_LOG_ERROR, "Syntax-based Arithmetic Coding (SAC) not supported\n");
+            }
             s->obmc= get_bits1(&s->gb); /* Advanced prediction mode */
-            s->unrestricted_mv = s->umvplus || s->obmc;
             s->h263_aic = get_bits1(&s->gb); /* Advanced Intra Coding (AIC) */
-	    
-            if (get_bits1(&s->gb) != 0) {
-                av_log(s->avctx, AV_LOG_ERROR, "Deblocking Filter not supported\n");
-            }
+            s->loop_filter= get_bits1(&s->gb);
+            s->unrestricted_mv = s->umvplus || s->obmc || s->loop_filter;
+            
             if (get_bits1(&s->gb) != 0) {
                 av_log(s->avctx, AV_LOG_ERROR, "Slice Structured not supported\n");
             }
@@ -4478,6 +4569,8 @@
             }
             s->alt_inter_vlc= get_bits1(&s->gb);
             s->modified_quant= get_bits1(&s->gb);
+            if(s->modified_quant)
+                s->chroma_qscale_table= ff_h263_chroma_qscale_table;
             
             skip_bits(&s->gb, 1); /* Prevent start code emulation */
 
@@ -4539,6 +4632,7 @@
         }
             
         s->qscale = get_bits(&s->gb, 5);
+        s->chroma_qscale= s->chroma_qscale_table[s->qscale];
     }
     /* PEI */
     while (get_bits1(&s->gb) != 0) {
@@ -4555,7 +4649,7 @@
     }
 
      if(s->avctx->debug&FF_DEBUG_PICT_INFO){
-         av_log(s->avctx, AV_LOG_DEBUG, "qp:%d %c size:%d rnd:%d%s%s%s%s%s%s%s\n", 
+         av_log(s->avctx, AV_LOG_DEBUG, "qp:%d %c size:%d rnd:%d%s%s%s%s%s%s%s%s\n", 
          s->qscale, av_get_pict_type_char(s->pict_type),
          s->gb.size_in_bits, 1-s->no_rounding,
          s->obmc ? " AP" : "",
@@ -4564,7 +4658,8 @@
          s->h263_plus ? " +" : "",
          s->h263_aic ? " AIC" : "",
          s->alt_inter_vlc ? " AIV" : "",
-         s->modified_quant ? " MQ" : ""
+         s->modified_quant ? " MQ" : "",
+         s->loop_filter ? " LOOP" : ""
          ); 
      }
 #if 1
@@ -4895,7 +4990,7 @@
         
         s->progressive_sequence= get_bits1(gb)^1;
         if(!get_bits1(gb) && (s->avctx->debug & FF_DEBUG_PICT_INFO)) 
-            av_log(s->avctx, AV_LOG_ERROR, "OBMC not supported (very likely buggy encoder)\n");   /* OBMC Disable */
+            av_log(s->avctx, AV_LOG_INFO, "MPEG4 OBMC not supported (very likely buggy encoder)\n");   /* OBMC Disable */
         if (vo_ver_id == 1) {
             s->vol_sprite_usage = get_bits1(gb); /* vol_sprite_usage */
         } else {
@@ -5251,7 +5346,7 @@
      }
 
      if (s->shape != BIN_ONLY_SHAPE) {
-         s->qscale = get_bits(gb, s->quant_precision);
+         s->chroma_qscale= s->qscale = get_bits(gb, s->quant_precision);
          if(s->qscale==0){
              av_log(s->avctx, AV_LOG_ERROR, "Error, header damaged or not MPEG4 header (qscale=0)\n");
              return -1; // makes no sense to continue, as there is nothing left from the image then
@@ -5445,7 +5540,7 @@
     /* skip unknown header garbage */
     skip_bits(&s->gb, 41);
 
-    s->qscale = get_bits(&s->gb, 5);
+    s->chroma_qscale= s->qscale = get_bits(&s->gb, 5);
     skip_bits1(&s->gb);	/* Continuous Presence Multipoint mode: off */
 
     /* PEI */
@@ -5519,7 +5614,7 @@
     if (s->pict_type > P_TYPE)
         s->pict_type = P_TYPE;
     skip_bits1(&s->gb);	/* deblocking flag */
-    s->qscale = get_bits(&s->gb, 5);
+    s->chroma_qscale= s->qscale = get_bits(&s->gb, 5);
 
     s->h263_plus = 0;
 
--- a/h263data.h	Sun Nov 30 19:04:56 2003 +0000
+++ b/h263data.h	Mon Dec 01 15:23:14 2003 +0000
@@ -222,7 +222,7 @@
 }   
 };
 
-static const uint8_t chroma_qscale_tab[32]={
+const uint8_t ff_h263_chroma_qscale_table[32]={
 //  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
     0, 1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 9,10,10,11,11,12,12,12,13,13,13,14,14,14,14,14,15,15,15,15,15
 };
@@ -234,3 +234,9 @@
 const uint8_t ff_mba_length[6]={
       6,   7,   9,  11,  13,  14
 };
+
+const uint8_t ff_h263_loop_filter_strength[32]={
+//  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+    0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9,10,10,10,11,11,11,12,12,12
+};
+
--- a/h263dec.c	Sun Nov 30 19:04:56 2003 +0000
+++ b/h263dec.c	Mon Dec 01 15:23:14 2003 +0000
@@ -207,6 +207,8 @@
                 const int xy= s->mb_x + s->mb_y*s->mb_stride;
                 if(ret==SLICE_END){
                     MPV_decode_mb(s, s->block);
+                    if(s->loop_filter)
+                        ff_h263_loop_filter(s);
 
 //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));
                     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);
@@ -231,6 +233,8 @@
             }
 
             MPV_decode_mb(s, s->block);
+            if(s->loop_filter)
+                ff_h263_loop_filter(s);
         }
         
         ff_draw_horiz_band(s, s->mb_y*16, 16);
--- a/mpeg12.c	Sun Nov 30 19:04:56 2003 +0000
+++ b/mpeg12.c	Mon Dec 01 15:23:14 2003 +0000
@@ -2126,6 +2126,7 @@
 	s->dsp.clear_blocks(s->block[0]);
 
         ret = mpeg_decode_mb(s, s->block);
+        s->chroma_qscale= s->qscale;
 
         dprintf("ret=%d\n", ret);
         if (ret < 0)
--- a/mpegvideo.c	Sun Nov 30 19:04:56 2003 +0000
+++ b/mpegvideo.c	Mon Dec 01 15:23:14 2003 +0000
@@ -88,6 +88,11 @@
     0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
 };
 
+static const uint8_t ff_default_chroma_qscale_table[32]={
+//  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+};
+
 #ifdef CONFIG_ENCODERS
 static uint8_t (*default_mv_penalty)[MAX_MV*2+1]=NULL;
 static uint8_t default_fcode_tab[MAX_MV*2+1];
@@ -384,6 +389,10 @@
     s->block_wrap[4]=
     s->block_wrap[5]= s->mb_width + 2;
 
+    s->y_dc_scale_table=
+    s->c_dc_scale_table= ff_mpeg1_dc_scale_table;
+    s->chroma_qscale_table= ff_default_chroma_qscale_table;    
+    
     y_size = (2 * s->mb_width + 2) * (2 * s->mb_height + 2);
     c_size = (s->mb_width + 2) * (s->mb_height + 2);
     yc_size = y_size + 2 * c_size;
@@ -668,8 +677,8 @@
     
     s->progressive_sequence= !(avctx->flags & CODEC_FLAG_INTERLACED_DCT);
     
-    s->obmc=    (s->codec_id == CODEC_ID_H263 || s->codec_id == CODEC_ID_H263P) 
-             && (s->flags & CODEC_FLAG_4MV);
+    s->obmc= (s->flags & CODEC_FLAG_OBMC);
+    s->loop_filter= (s->flags & CODEC_FLAG_LOOP_FILTER);
 
     if((s->flags & CODEC_FLAG_4MV) && s->codec_id != CODEC_ID_MPEG4 
        && s->codec_id != CODEC_ID_H263 && s->codec_id != CODEC_ID_H263P){
@@ -682,6 +691,11 @@
         return -1;
     }
     
+    if(s->obmc && s->codec_id != CODEC_ID_H263 && s->codec_id != CODEC_ID_H263P){
+        av_log(avctx, AV_LOG_ERROR, "OBMC is only supported with H263(+)\n");
+        return -1;
+    }
+    
     if(s->quarter_sample && s->codec_id != CODEC_ID_MPEG4){
         av_log(avctx, AV_LOG_ERROR, "qpel not supported by codec\n");
         return -1;
@@ -770,6 +784,7 @@
             return -1;
         }
         s->out_format = FMT_H263;
+	s->obmc= (avctx->flags & CODEC_FLAG_OBMC) ? 1:0;
         avctx->delay=0;
         s->low_delay=1;
         break;
@@ -777,12 +792,18 @@
         s->out_format = FMT_H263;
         s->h263_plus = 1;
 	/* Fx */
-	s->unrestricted_mv=(avctx->flags & CODEC_FLAG_H263P_UMV) ? 1:0;
+        s->umvplus = (avctx->flags & CODEC_FLAG_H263P_UMV) ? 1:0;
 	s->h263_aic= (avctx->flags & CODEC_FLAG_H263P_AIC) ? 1:0;
+	s->modified_quant= s->h263_aic;
 	s->alt_inter_vlc= (avctx->flags & CODEC_FLAG_H263P_AIV) ? 1:0;
+	s->obmc= (avctx->flags & CODEC_FLAG_OBMC) ? 1:0;
+	s->loop_filter= (avctx->flags & CODEC_FLAG_LOOP_FILTER) ? 1:0;
+	s->unrestricted_mv= s->obmc || s->loop_filter || s->umvplus;
+        if(s->modified_quant)
+            s->chroma_qscale_table= ff_h263_chroma_qscale_table;
+
 	/* /Fx */
         /* These are just to be sure */
-        s->umvplus = 1;
         avctx->delay=0;
         s->low_delay=1;
         break;
@@ -876,8 +897,6 @@
     }
     s->me.mv_penalty= default_mv_penalty;
     s->fcode_tab= default_fcode_tab;
-    s->y_dc_scale_table=
-    s->c_dc_scale_table= ff_mpeg1_dc_scale_table;
  
     /* dont use mv_penalty table for crap MV as it would be confused */
     //FIXME remove after fixing / removing old ME
@@ -2648,10 +2667,10 @@
 }
 
 static inline void add_dequant_dct(MpegEncContext *s, 
-                           DCTELEM *block, int i, uint8_t *dest, int line_size)
+                           DCTELEM *block, int i, uint8_t *dest, int line_size, int qscale)
 {
     if (s->block_last_index[i] >= 0) {
-        s->dct_unquantize(s, block, i, s->qscale);
+        s->dct_unquantize(s, block, i, qscale);
 
         s->dsp.idct_add (dest, line_size, block);
     }
@@ -2810,14 +2829,14 @@
             /* add dct residue */
             if(s->encoding || !(   s->h263_msmpeg4 || s->codec_id==CODEC_ID_MPEG1VIDEO || s->codec_id==CODEC_ID_MPEG2VIDEO
                                 || (s->codec_id==CODEC_ID_MPEG4 && !s->mpeg_quant))){
-                add_dequant_dct(s, block[0], 0, dest_y, dct_linesize);
-                add_dequant_dct(s, block[1], 1, dest_y + 8, dct_linesize);
-                add_dequant_dct(s, block[2], 2, dest_y + dct_offset, dct_linesize);
-                add_dequant_dct(s, block[3], 3, dest_y + dct_offset + 8, dct_linesize);
+                add_dequant_dct(s, block[0], 0, dest_y, dct_linesize, s->qscale);
+                add_dequant_dct(s, block[1], 1, dest_y + 8, dct_linesize, s->qscale);
+                add_dequant_dct(s, block[2], 2, dest_y + dct_offset, dct_linesize, s->qscale);
+                add_dequant_dct(s, block[3], 3, dest_y + dct_offset + 8, dct_linesize, s->qscale);
 
                 if(!(s->flags&CODEC_FLAG_GRAY)){
-                    add_dequant_dct(s, block[4], 4, dest_cb, uvlinesize);
-                    add_dequant_dct(s, block[5], 5, dest_cr, uvlinesize);
+                    add_dequant_dct(s, block[4], 4, dest_cb, uvlinesize, s->chroma_qscale);
+                    add_dequant_dct(s, block[5], 5, dest_cr, uvlinesize, s->chroma_qscale);
                 }
             } else if(s->codec_id != CODEC_ID_WMV2){
                 add_dct(s, block[0], 0, dest_y, dct_linesize);
@@ -3105,8 +3124,9 @@
             }
         }
         s->qscale= last_qp + s->dquant;
+        s->chroma_qscale= s->chroma_qscale_table[ s->qscale ];
         s->y_dc_scale= s->y_dc_scale_table[ s->qscale ];
-        s->c_dc_scale= s->c_dc_scale_table[ s->qscale ];
+        s->c_dc_scale= s->c_dc_scale_table[ s->chroma_qscale ];
     }
 
     if (s->mb_intra) {
@@ -3844,8 +3864,9 @@
         s->mb_x=0;
         s->mb_y= mb_y;
 
+        s->chroma_qscale= s->chroma_qscale_table[ s->qscale ];
         s->y_dc_scale= s->y_dc_scale_table[ s->qscale ];
-        s->c_dc_scale= s->c_dc_scale_table[ s->qscale ];
+        s->c_dc_scale= s->c_dc_scale_table[ s->chroma_qscale ];
         ff_init_block_index(s);
         
         for(mb_x=0; mb_x < s->mb_width; mb_x++) {
@@ -4208,6 +4229,8 @@
                     s, s->new_picture    .data[2] + s->mb_x*8  + s->mb_y*s->uvlinesize*8,
                     s->dest[2], w>>1, h>>1, s->uvlinesize);
             }
+            if(s->loop_filter)
+                ff_h263_loop_filter(s);
 //printf("MB %d %d bits\n", s->mb_x+s->mb_y*s->mb_stride, get_bit_count(&s->pb));
         }
     }
--- a/mpegvideo.h	Sun Nov 30 19:04:56 2003 +0000
+++ b/mpegvideo.h	Mon Dec 01 15:23:14 2003 +0000
@@ -337,6 +337,7 @@
     int y_dc_scale, c_dc_scale;
     uint8_t *y_dc_scale_table;     ///< qscale -> y_dc_scale table 
     uint8_t *c_dc_scale_table;     ///< qscale -> c_dc_scale table 
+    const uint8_t *chroma_qscale_table;  ///< qscale -> chroma_qscale (h263)
     uint8_t *coded_block;          ///< used for coded block pattern prediction (msmpeg4v3, wmv1)
     int16_t (*ac_val[3])[16];      ///< used for for mpeg4 AC prediction, all 3 arrays must be continuous 
     int ac_pred;
@@ -352,6 +353,7 @@
     uint8_t *edge_emu_buffer;     ///< points into the middle of allocated_edge_emu_buffer  
 
     int qscale;                 ///< QP 
+    int chroma_qscale;          ///< chroma QP 
     int lambda;                 ///< lagrange multipler used in rate distortion
     int lambda2;                ///< (lambda*lambda) >> FF_LAMBDA_SHIFT 
     int *lambda_table;
@@ -526,6 +528,7 @@
     int h263_aic_dir;               ///< AIC direction: 0 = left, 1 = top 
     int alt_inter_vlc;              ///< alternative inter vlc
     int modified_quant;
+    int loop_filter;
     
     /* mpeg4 specific */
     int time_increment_resolution;
@@ -819,6 +822,8 @@
 extern const int16_t ff_mpeg4_default_non_intra_matrix[64];
 extern const uint16_t ff_mba_max[6];
 extern const uint8_t ff_mba_length[6];
+extern const uint8_t ff_h263_chroma_qscale_table[32];
+extern const uint8_t ff_h263_loop_filter_strength[32];
 
 int ff_h263_decode_init(AVCodecContext *avctx);
 int ff_h263_decode_frame(AVCodecContext *avctx, 
@@ -846,6 +851,7 @@
 int ff_h263_decode_gob_header(MpegEncContext *s);
 int ff_mpeg4_decode_picture_header(MpegEncContext * s, GetBitContext *gb);
 void ff_h263_update_motion_val(MpegEncContext * s);
+int ff_h263_loop_filter(MpegEncContext * s);
 
 
 int intel_h263_decode_picture_header(MpegEncContext *s);
--- a/rv10.c	Sun Nov 30 19:04:56 2003 +0000
+++ b/rv10.c	Mon Dec 01 15:23:14 2003 +0000
@@ -382,7 +382,8 @@
 //    s->alt_inter_vlc=1;
 //    s->obmc=1;
 //    s->umvplus=1;
-//    s->modified_quant=1;
+    s->modified_quant=1;
+    s->loop_filter=1;
     
     if(s->avctx->debug & FF_DEBUG_PICT_INFO){
             av_log(s->avctx, AV_LOG_INFO, "num:%5d x:%2d y:%2d type:%d qscale:%2d rnd:%d\n", 
@@ -522,9 +523,14 @@
         s->y_dc_scale_table=
         s->c_dc_scale_table= ff_mpeg1_dc_scale_table;
     }
+
+    if(s->modified_quant)
+        s->chroma_qscale_table= ff_h263_chroma_qscale_table;
+        
+    s->chroma_qscale= s->chroma_qscale_table[ s->qscale ];
     s->y_dc_scale= s->y_dc_scale_table[ s->qscale ];
-    s->c_dc_scale= s->c_dc_scale_table[ s->qscale ];
-    
+    s->c_dc_scale= s->c_dc_scale_table[ s->chroma_qscale ];
+
     s->rv10_first_dc_coded[0] = 0;
     s->rv10_first_dc_coded[1] = 0;
     s->rv10_first_dc_coded[2] = 0;
@@ -555,6 +561,9 @@
         }
         ff_h263_update_motion_val(s);
         MPV_decode_mb(s, s->block);
+        if(s->loop_filter)
+            ff_h263_loop_filter(s);
+
         if (++s->mb_x == s->mb_width) {
             s->mb_x = 0;
             s->mb_y++;