[FFmpeg-soc] [soc]: r787 - rv40/rv40.c

kostya subversion at mplayerhq.hu
Tue Aug 14 19:13:29 CEST 2007


Author: kostya
Date: Tue Aug 14 19:13:29 2007
New Revision: 787

Log:
Introduce motion prediction, compensation and use these functions
in P-frame decoding.



Modified:
   rv40/rv40.c

Modified: rv40/rv40.c
==============================================================================
--- rv40/rv40.c	(original)
+++ rv40/rv40.c	Tue Aug 14 19:13:29 2007
@@ -109,6 +109,7 @@ typedef struct RV40DecContext{
     int luma_vlc;            ///< which VLC set will be used for luma blocks decoding
     int chroma_vlc;          ///< which VLC set will be used for chroma blocks decoding
     int is16;                ///< current block has additional 16x16 specific features or not
+    int dmv[4][2];           ///< differential motion vectors for the current macroblock
 }RV40DecContext;
 
 static RV40VLC intra_vlcs[NUM_INTRA_TABLES], inter_vlcs[NUM_INTER_TABLES];
@@ -737,39 +738,247 @@ static int rv40_decode_mb_info(RV40DecCo
     return 0;
 }
 
+/** Macroblock partition width in 8x8 blocks */
+const int part_sizes_w[RV40_MB_TYPES] = { 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2 };
+
+/** Macroblock partition height in 8x8 blocks */
+const int part_sizes_h[RV40_MB_TYPES] = { 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2 };
+
+/**
+ * Motion vectors prediction
+ *
+ * Motion prediction performed for the block by using median prediction of
+ * motion vector from the left, top and right top blocks but in corener cases
+ * some other vectors may be used instead
+ */
+static void rv40_pred_mv(RV40DecContext *r, int block_type, int subblock_no)
+{
+    MpegEncContext *s = &r->s;
+    int mv_pos = s->mb_x * 2 + s->mb_y * 2 * s->b8_stride;
+    int A[2], B[2], C[2];
+    int no_A = 1, no_B = 1, no_C = 1;
+    int i, j;
+    int mx, my;
+
+    memset(A, 0, sizeof(A));
+    memset(B, 0, sizeof(B));
+    memset(C, 0, sizeof(C));
+    no_A = s->mb_x < 1 || (s->first_slice_line && s->mb_x == s->resync_mb_x);
+    no_B = s->first_slice_line;
+    no_C = s->first_slice_line || (s->mb_x + 1) == s->mb_width;
+    switch(block_type){
+    case RV40_MB_P_16x16:
+    case RV40_MB_P_MIX16x16:
+        if(!no_C){
+            C[0] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride+2][0];
+            C[1] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride+2][1];
+        }
+        break;
+    case RV40_MB_P_8x8:
+        mv_pos += (subblock_no & 1) + (subblock_no >> 1)*s->b8_stride;
+        if(subblock_no & 1) no_A = 0;
+        if(subblock_no & 2) no_B = 0;
+        no_C |= (subblock_no == 3);
+        if(subblock_no == 2) no_C = 0;
+        if(!no_C){
+            C[0] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride+1][0];
+            C[1] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride+1][1];
+        }
+        if(subblock_no == 3){
+            no_C = 0;
+            C[0] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride-1][0];
+            C[1] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride-1][1];
+        }
+        break;
+    case RV40_MB_P_16x8:
+        mv_pos += subblock_no*s->b8_stride;
+        no_B &= ~subblock_no;
+        no_C |= subblock_no;
+        if(!no_C){
+            C[0] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride+2][0];
+            C[1] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride+2][1];
+        }
+        break;
+    case RV40_MB_P_8x16:
+        mv_pos += subblock_no;
+        no_A &= ~subblock_no;
+        if(!no_C){
+            C[0] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride+1][0];
+            C[1] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride+1][1];
+        }
+        break;
+    default:
+        no_A = no_B = no_C = 1;
+    }
+    if(!no_A){
+        A[0] = s->current_picture_ptr->motion_val[0][mv_pos-1][0];
+        A[1] = s->current_picture_ptr->motion_val[0][mv_pos-1][1];
+    }
+    if(!no_B){
+        B[0] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride][0];
+        B[1] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride][1];
+    }else{
+        B[0] = A[0];
+        B[1] = A[1];
+    }
+    if(no_C){
+        if(no_B){
+            C[0] = A[0];
+            C[1] = A[1];
+        }else{
+            if(!no_A){
+                C[0] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride-1][0];
+                C[1] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride-1][1];
+            }else{
+                C[0] = A[0];
+                C[1] = A[1];
+            }
+        }
+    }
+    mx = mid_pred(A[0], B[0], C[0]);
+    my = mid_pred(A[1], B[1], C[1]);
+    mx += r->dmv[subblock_no][0];
+    my += r->dmv[subblock_no][1];
+    for(j = 0; j < part_sizes_h[block_type]; j++){
+        for(i = 0; i < part_sizes_w[block_type]; i++){
+            s->current_picture_ptr->motion_val[0][mv_pos + i + j*s->b8_stride][0] = mx;
+            s->current_picture_ptr->motion_val[0][mv_pos + i + j*s->b8_stride][1] = my;
+        }
+    }
+}
+
+/**
+ * Generic motion compensation function - hopefully compiler will optimize it for each case
+ *
+ * @param r decoder context
+ * @param block_type type of the current block
+ * @param xoff horizontal offset from the start of the current block
+ * @param yoff vertical offset from the start of the current block
+ * @param mv_off offset to the motion vector information
+ * @param width width of the current partition in 8x8 blocks
+ * @param height height of the current partition in 8x8 blocks
+ */
+static inline void rv40_mc(RV40DecContext *r, const int block_type,
+                          const int xoff, const int yoff, int mv_off,
+                          const int width, const int height)
+{
+    MpegEncContext *s = &r->s;
+    uint8_t *Y, *U, *V, *srcY, *srcU, *srcV;
+    int dxy, mx, my, uvmx, uvmy, src_x, src_y, uvsrc_x, uvsrc_y;
+    int mv_pos = s->mb_x * 2 + s->mb_y * 2 * s->b8_stride + mv_off;
+
+    mx = s->current_picture_ptr->motion_val[0][mv_pos][0];
+    my = s->current_picture_ptr->motion_val[0][mv_pos][1];
+    srcY = s->last_picture_ptr->data[0];
+    srcU = s->last_picture_ptr->data[1];
+    srcV = s->last_picture_ptr->data[2];
+    src_x = s->mb_x * 16 + xoff + (mx >> 2);
+    src_y = s->mb_y * 16 + yoff + (my >> 2);
+    uvsrc_x = s->mb_x * 8 + (xoff >> 1) + (mx >> 3);
+    uvsrc_y = s->mb_y * 8 + (yoff >> 1) + (my >> 3);
+    srcY += src_y * s->linesize + src_x;
+    srcU += uvsrc_y * s->uvlinesize + uvsrc_x;
+    srcV += uvsrc_y * s->uvlinesize + uvsrc_x;
+    if(   (unsigned)src_x > s->h_edge_pos - (mx&3) - (width <<3)
+       || (unsigned)src_y > s->v_edge_pos - (my&3) - (height<<3)){
+        uint8_t *uvbuf= s->edge_emu_buffer + 19 * s->linesize;
+
+        ff_emulated_edge_mc(s->edge_emu_buffer, srcY, s->linesize, (width<<3)+1, (height<<3)+1,
+                            src_x, src_y, s->h_edge_pos, s->v_edge_pos);
+        srcY = s->edge_emu_buffer;
+        ff_emulated_edge_mc(uvbuf     , srcU, s->uvlinesize, (width<<2)+1, (height<<2)+1,
+                            uvsrc_x, uvsrc_y, s->h_edge_pos >> 1, s->v_edge_pos >> 1);
+        ff_emulated_edge_mc(uvbuf + 16, srcV, s->uvlinesize, (width<<2)+1, (height<<2)+1,
+                            uvsrc_x, uvsrc_y, s->h_edge_pos >> 1, s->v_edge_pos >> 1);
+        srcU = uvbuf;
+        srcV = uvbuf + 16;
+    }
+    dxy = ((my & 3) << 2) | (mx & 3);
+    uvmx = mx & 6;
+    uvmy = my & 6;
+    Y = s->dest[0] + xoff + yoff*s->linesize;
+    U = s->dest[1] + (xoff>>1) + (yoff>>1)*s->uvlinesize;
+    V = s->dest[2] + (xoff>>1) + (yoff>>1)*s->uvlinesize;
+    if(block_type == RV40_MB_P_16x8){
+        s->dsp.put_h264_qpel_pixels_tab[1][dxy](Y, srcY, s->linesize);
+        Y    += 8;
+        srcY += 8;
+        s->dsp.put_h264_qpel_pixels_tab[1][dxy](Y, srcY, s->linesize);
+        s->dsp.put_h264_chroma_pixels_tab[0]   (U, srcU, s->uvlinesize, 4, uvmx, uvmy);
+        s->dsp.put_h264_chroma_pixels_tab[0]   (V, srcV, s->uvlinesize, 4, uvmx, uvmy);
+    }else if(block_type == RV40_MB_P_8x16){
+        s->dsp.put_h264_qpel_pixels_tab[1][dxy](Y, srcY, s->linesize);
+        Y    += 8 * s->linesize;
+        srcY += 8 * s->linesize;
+        s->dsp.put_h264_qpel_pixels_tab[1][dxy](Y, srcY, s->linesize);
+        s->dsp.put_h264_chroma_pixels_tab[1]   (U, srcU, s->uvlinesize, 8, uvmx, uvmy);
+        s->dsp.put_h264_chroma_pixels_tab[1]   (V, srcV, s->uvlinesize, 8, uvmx, uvmy);
+    }else if(block_type == RV40_MB_P_8x8){
+        s->dsp.put_h264_qpel_pixels_tab[1][dxy](Y, srcY, s->linesize);
+        s->dsp.put_h264_chroma_pixels_tab[1]   (U, srcU, s->uvlinesize, 4, uvmx, uvmy);
+        s->dsp.put_h264_chroma_pixels_tab[1]   (V, srcV, s->uvlinesize, 4, uvmx, uvmy);
+    }else{
+        s->dsp.put_h264_qpel_pixels_tab[0][dxy](Y, srcY, s->linesize);
+        s->dsp.put_h264_chroma_pixels_tab[0]   (U, srcU, s->uvlinesize, 8, uvmx, uvmy);
+        s->dsp.put_h264_chroma_pixels_tab[0]   (V, srcV, s->uvlinesize, 8, uvmx, uvmy);
+    }
+}
+
 static int rv40_decode_mv(RV40DecContext *r, int block_type)
 {
     MpegEncContext *s = &r->s;
     GetBitContext *gb = &s->gb;
-    int mv[16][2];
-    int i;
+    int i, j;
 
     switch(block_type){
     case RV40_MB_TYPE_INTRA:
     case RV40_MB_TYPE_INTRA16x16:
-    case RV40_MB_SKIP:
+        for(j = 0; j < 2; j++){
+            for(i = 0; i < 2; i++){
+                s->current_picture_ptr->motion_val[0][s->mb_x * 2 + s->mb_y * 2 * s->b8_stride + i + j*s->b8_stride][0] = 0;
+                s->current_picture_ptr->motion_val[0][s->mb_x * 2 + s->mb_y * 2 * s->b8_stride + i + j*s->b8_stride][1] = 0;
+            }
+        }
         return 0;
+    case RV40_MB_SKIP:
+        rv40_pred_mv(r, block_type, 0);
+        rv40_mc(r, block_type, 0, 0, 0, 2, 2);
+        break;
     case RV40_MB_B_INTERP:
         break;
     case RV40_MB_P_16x16:
     case RV40_MB_B_FORWARD:
     case RV40_MB_B_BACKWARD:
     case RV40_MB_P_MIX16x16:
-        mv[0][0] = get_omega_signed(gb);
-        mv[0][1] = get_omega_signed(gb);
+        r->dmv[0][0] = get_omega_signed(gb);
+        r->dmv[0][1] = get_omega_signed(gb);
+        rv40_pred_mv(r, block_type, 0);
+        rv40_mc(r, block_type, 0, 0, 0, 2, 2);
         break;
     case RV40_MB_P_16x8:
     case RV40_MB_P_8x16:
     case RV40_MB_B_DIRECT:
-        mv[0][0] = get_omega_signed(gb);
-        mv[0][1] = get_omega_signed(gb);
-        mv[1][0] = get_omega_signed(gb);
-        mv[1][1] = get_omega_signed(gb);
+        r->dmv[0][0] = get_omega_signed(gb);
+        r->dmv[0][1] = get_omega_signed(gb);
+        r->dmv[1][0] = get_omega_signed(gb);
+        r->dmv[1][1] = get_omega_signed(gb);
+        rv40_pred_mv(r, block_type, 0);
+        rv40_pred_mv(r, block_type, 1);
+        if(block_type == RV40_MB_P_16x8){
+            rv40_mc(r, block_type, 0, 0, 0,            2, 1);
+            rv40_mc(r, block_type, 0, 8, s->b8_stride, 2, 1);
+        }
+        if(block_type == RV40_MB_P_8x16){
+            rv40_mc(r, block_type, 0, 0, 0, 1, 2);
+            rv40_mc(r, block_type, 8, 0, 1, 1, 2);
+        }
         break;
     case RV40_MB_P_8x8:
         for(i=0;i< 4;i++){
-            mv[i][0] = get_omega_signed(gb);
-            mv[i][1] = get_omega_signed(gb);
+            r->dmv[i][0] = get_omega_signed(gb);
+            r->dmv[i][1] = get_omega_signed(gb);
+            rv40_pred_mv(r, block_type, i);
+            rv40_mc(r, block_type, (i&1)<<3, (i&2)<<2, (i&1)+(i>>1)*s->b8_stride, 1, 1);
         }
         break;
     }
@@ -978,6 +1187,30 @@ static int rv40_decode_mb_header(RV40Dec
     return rv40_decode_cbp(gb, r->cur_vlcs, r->is16);
 }
 
+/** Mask for retrieving all bits in coded block pattern
+ * corresponding to one 8x8 block
+ */
+#define LUMA_CBP_BLOCK_MASK 0x303
+
+#define U_CBP_MASK 0x0F0000
+#define V_CBP_MASK 0xF00000
+
+
+static void rv40_apply_differences(RV40DecContext *r, int cbp)
+{
+    static const int shifts[4] = { 0, 2, 8, 10 };
+    MpegEncContext *s = &r->s;
+    int i;
+
+    for(i = 0; i < 4; i++)
+        if(cbp & (LUMA_CBP_BLOCK_MASK << shifts[i]))
+            s->dsp.add_pixels_clamped(s->block[i], s->dest[0] + (i & 1)*8 + (i&2)*4*s->linesize, s->linesize);
+    if(cbp & U_CBP_MASK)
+        s->dsp.add_pixels_clamped(s->block[4], s->dest[1], s->uvlinesize);
+    if(cbp & V_CBP_MASK)
+        s->dsp.add_pixels_clamped(s->block[5], s->dest[2], s->uvlinesize);
+}
+
 static int rv40_decode_macroblock(RV40DecContext *r, int *intra_types)
 {
     MpegEncContext *s = &r->s;
@@ -1018,7 +1251,10 @@ static int rv40_decode_macroblock(RV40De
         rv40_dequant4x4(s->block[blknum], blkoff, rv40_qscale_tab[rv40_chroma_quant[1][r->quant]],rv40_qscale_tab[rv40_chroma_quant[0][r->quant]]);
         rv40_intra_inv_transform(s->block[blknum], blkoff);
     }
-    rv40_output_macroblock(r, intra_types, cbp2, r->is16);
+    if(IS_INTRA(s->current_picture_ptr->mb_type[s->mb_x + s->mb_y*s->mb_stride]))
+        rv40_output_macroblock(r, intra_types, cbp2, r->is16);
+    else
+        rv40_apply_differences(r, cbp2);
 
     return 0;
 }
@@ -1049,12 +1285,12 @@ static int rv40_decode_slice(RV40DecCont
         ff_er_frame_start(s);
         s->current_picture_ptr = &s->current_picture;
     }
-if(r->prev_si.type){
-memcpy(s->current_picture_ptr->data[0],s->last_picture_ptr->data[0],s->linesize*s->avctx->height);
-memcpy(s->current_picture_ptr->data[1],s->last_picture_ptr->data[1],s->uvlinesize*s->avctx->height/2);
-memcpy(s->current_picture_ptr->data[2],s->last_picture_ptr->data[2],s->uvlinesize*s->avctx->height/2);
-ff_er_add_slice(s, 0, 0, s->mb_width-1, s->mb_height-1, AC_END|DC_END|MV_END);
-return 0;
+if(s->pict_type == B_TYPE){
+    memcpy(s->current_picture_ptr->data[0], s->last_picture_ptr->data[0], s->linesize*s->avctx->height);
+    memcpy(s->current_picture_ptr->data[1], s->last_picture_ptr->data[1], s->uvlinesize*s->avctx->height/2);
+    memcpy(s->current_picture_ptr->data[2], s->last_picture_ptr->data[2], s->uvlinesize*s->avctx->height/2);
+    ff_er_add_slice(s, 0, 0, s->mb_width-1, s->mb_height-1, AC_END|DC_END|MV_END);
+    return 0;
 }
 
     r->skip_blocks = 0;
@@ -1116,7 +1352,8 @@ static int rv40_decode_init(AVCodecConte
     avctx->flags |= CODEC_FLAG_EMU_EDGE;
     r->s.flags |= CODEC_FLAG_EMU_EDGE;
     avctx->pix_fmt = PIX_FMT_YUV420P;
-    s->low_delay = 1;
+    avctx->has_b_frames = 1;
+    s->low_delay = 0;
 
     if (MPV_common_init(s) < 0)
         return -1;



More information about the FFmpeg-soc mailing list