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

kostya subversion at mplayerhq.hu
Mon Aug 20 11:50:08 CEST 2007


Author: kostya
Date: Mon Aug 20 11:50:07 2007
New Revision: 1043

Log:
B-frames motion prediction and compensation

Modified:
   rv40/rv40.c

Modified: rv40/rv40.c
==============================================================================
--- rv40/rv40.c	(original)
+++ rv40/rv40.c	Mon Aug 20 11:50:07 2007
@@ -879,6 +879,160 @@ static void rv40_pred_mv(RV40DecContext 
 }
 
 /**
+ * Predict motion vector for B-frame macroblock.
+ */
+static inline void rv40_pred_b_vector(int A[2], int B[2], int C[2], int no_A, int no_B, int no_C, int *mx, int *my)
+{
+    switch(no_A + no_B + no_C){
+    case 0:
+        *mx = mid_pred(A[0], B[0], C[0]);
+        *my = mid_pred(A[1], B[1], C[1]);
+        break;
+    case 1:
+        if(no_A){
+            *mx = (B[0] + C[0]) / 2;
+            *my = (B[1] + C[1]) / 2;
+        }else if(no_B){
+            *mx = (A[0] + C[0]) / 2;
+            *my = (A[1] + C[1]) / 2;
+        }else{
+            *mx = (A[0] + B[0]) / 2;
+            *my = (A[1] + B[1]) / 2;
+        }
+        break;
+    case 2:
+        if(!no_A){
+            *mx = A[0];
+            *my = A[1];
+        }else if(!no_B){
+            *mx = B[0];
+            *my = B[1];
+        }else{
+            *mx = C[0];
+            *my = C[1];
+        }
+        break;
+    default:
+        *mx = *my = 0;
+        break;
+    }
+}
+
+/**
+ * Motion vector prediction for B-frames.
+ */
+static void rv40_pred_mv_b(RV40DecContext *r, int block_type)
+{
+    MpegEncContext *s = &r->s;
+    int mb_pos = s->mb_x + s->mb_y * s->mb_stride;
+    int mv_pos = s->mb_x * 2 + s->mb_y * 2 * s->b8_stride;
+    int A[2][2], B[2][2], C[2][2];
+    int no_A[2], no_B[2], no_C[2];
+    int c_mv_pos;
+    int mx[2], my[2];
+    int i, j;
+
+    memset(A, 0, sizeof(A));
+    memset(B, 0, sizeof(B));
+    memset(C, 0, sizeof(C));
+    memset(mx, 0, sizeof(mx));
+    memset(my, 0, sizeof(my));
+    if(!s->mb_x)
+        no_A[0] = no_A[1] = 1;
+    else{
+        no_A[0] = no_A[1] = s->first_slice_line && s->mb_x == s->resync_mb_x;
+        if(r->mb_type[mb_pos - 1] != RV40_MB_B_FORWARD  && r->mb_type[mb_pos - 1] != RV40_MB_B_DIRECT)
+            no_A[0] = 1;
+        if(r->mb_type[mb_pos - 1] != RV40_MB_B_BACKWARD && r->mb_type[mb_pos - 1] != RV40_MB_B_DIRECT)
+            no_A[1] = 1;
+        if(!no_A[0]){
+            A[0][0] = s->current_picture_ptr->motion_val[0][mv_pos - 1][0];
+            A[0][1] = s->current_picture_ptr->motion_val[0][mv_pos - 1][1];
+        }
+        if(!no_A[1]){
+            A[1][0] = s->current_picture_ptr->motion_val[1][mv_pos - 1][0];
+            A[1][1] = s->current_picture_ptr->motion_val[1][mv_pos - 1][1];
+        }
+    }
+    if(s->first_slice_line){
+        no_B[0] = no_B[1] = 1;
+    }else{
+        no_B[0] = no_B[1] = 0;
+        if(r->mb_type[mb_pos - s->mb_stride] != RV40_MB_B_FORWARD  && r->mb_type[mb_pos - s->mb_stride] != RV40_MB_B_DIRECT)
+            no_B[0] = 1;
+        if(r->mb_type[mb_pos - s->mb_stride] != RV40_MB_B_BACKWARD && r->mb_type[mb_pos - s->mb_stride] != RV40_MB_B_DIRECT)
+            no_B[1] = 1;
+        if(!no_B[0]){
+            B[0][0] = s->current_picture_ptr->motion_val[0][mv_pos - s->b8_stride][0];
+            B[0][1] = s->current_picture_ptr->motion_val[0][mv_pos - s->b8_stride][1];
+        }
+        if(!no_B[1]){
+            B[1][0] = s->current_picture_ptr->motion_val[1][mv_pos - s->b8_stride][0];
+            B[1][1] = s->current_picture_ptr->motion_val[1][mv_pos - s->b8_stride][1];
+        }
+    }
+    if(s->mb_x+1 != s->mb_width && !s->first_slice_line){
+        no_C[0] = no_C[1] = 0;
+        if(r->mb_type[mb_pos - s->mb_stride + 1] != RV40_MB_B_FORWARD  && r->mb_type[mb_pos - s->mb_stride + 1] != RV40_MB_B_DIRECT)
+            no_C[0] = 1;
+        if(r->mb_type[mb_pos - s->mb_stride + 1] != RV40_MB_B_BACKWARD && r->mb_type[mb_pos - s->mb_stride + 1] != RV40_MB_B_DIRECT)
+            no_C[1] = 1;
+        c_mv_pos = mv_pos - s->b8_stride + 2;
+    }else if(s->mb_x+1 == s->mb_width && !s->first_slice_line){
+        no_C[0] = no_C[1] = 0;
+        if(r->mb_type[mb_pos - s->mb_stride - 1] != RV40_MB_B_FORWARD  && r->mb_type[mb_pos - s->mb_stride - 1] != RV40_MB_B_DIRECT)
+            no_C[0] = 1;
+        if(r->mb_type[mb_pos - s->mb_stride - 1] != RV40_MB_B_BACKWARD && r->mb_type[mb_pos - s->mb_stride - 1] != RV40_MB_B_DIRECT)
+            no_C[1] = 1;
+        c_mv_pos = mv_pos - s->b8_stride - 1;
+    }else{
+        no_C[0] = no_C[1] = 1;
+        c_mv_pos = 0;
+    }
+    if(!no_C[0]){
+        C[0][0] = s->current_picture_ptr->motion_val[0][c_mv_pos][0];
+        C[0][1] = s->current_picture_ptr->motion_val[0][c_mv_pos][1];
+    }
+    if(!no_C[1]){
+        C[1][0] = s->current_picture_ptr->motion_val[1][c_mv_pos][0];
+        C[1][1] = s->current_picture_ptr->motion_val[1][c_mv_pos][1];
+    }
+    switch(block_type){
+    case RV40_MB_B_FORWARD:
+        rv40_pred_b_vector(A[0], B[0], C[0], no_A[0], no_B[0], no_C[0], &mx[0], &my[0]);
+        r->dmv[1][0] = 0;
+        r->dmv[1][1] = 0;
+        break;
+    case RV40_MB_B_BACKWARD:
+        r->dmv[1][0] = r->dmv[0][0];
+        r->dmv[1][1] = r->dmv[0][1];
+        r->dmv[0][0] = 0;
+        r->dmv[0][1] = 0;
+        rv40_pred_b_vector(A[1], B[1], C[1], no_A[1], no_B[1], no_C[1], &mx[1], &my[1]);
+        break;
+    case RV40_MB_B_DIRECT:
+        rv40_pred_b_vector(A[0], B[0], C[0], no_A[0], no_B[0], no_C[0], &mx[0], &my[0]);
+        rv40_pred_b_vector(A[1], B[1], C[1], no_A[1], no_B[1], no_C[1], &mx[1], &my[1]);
+        break;
+    default:
+        no_A[0] = no_A[1] = no_B[0] = no_B[1] = no_C[0] = no_C[1] = 1;
+    }
+
+    mx[0] += r->dmv[0][0];
+    my[0] += r->dmv[0][1];
+    mx[1] += r->dmv[1][0];
+    my[1] += r->dmv[1][1];
+    for(j = 0; j < 2; j++){
+        for(i = 0; i < 2; i++){
+            s->current_picture_ptr->motion_val[0][mv_pos + i + j*s->b8_stride][0] = mx[0];
+            s->current_picture_ptr->motion_val[0][mv_pos + i + j*s->b8_stride][1] = my[0];
+            s->current_picture_ptr->motion_val[1][mv_pos + i + j*s->b8_stride][0] = mx[1];
+            s->current_picture_ptr->motion_val[1][mv_pos + i + j*s->b8_stride][1] = my[1];
+        }
+    }
+}
+
+/**
  * Generic motion compensation function - hopefully compiler will optimize it for each case
  *
  * @param r decoder context
@@ -957,6 +1111,111 @@ static inline void rv40_mc(RV40DecContex
 }
 
 /**
+ * B-frame specific motion compensation function
+ *
+ * @param r decoder context
+ * @param block_type type of the current block
+ */
+static inline void rv40_mc_b(RV40DecContext *r, const int block_type)
+{
+    MpegEncContext *s = &r->s;
+    uint8_t *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;
+
+    if(block_type != RV40_MB_B_BACKWARD){
+        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];
+    }else{
+        mx = s->current_picture_ptr->motion_val[1][mv_pos][0];
+        my = s->current_picture_ptr->motion_val[1][mv_pos][1];
+        srcY = s->next_picture_ptr->data[0];
+        srcU = s->next_picture_ptr->data[1];
+        srcV = s->next_picture_ptr->data[2];
+    }
+    src_x = s->mb_x * 16 + (mx >> 2);
+    src_y = s->mb_y * 16 + (my >> 2);
+    uvsrc_x = s->mb_x * 8 + (mx >> 3);
+    uvsrc_y = s->mb_y * 8 + (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 - !!(mx&3)*2) > s->h_edge_pos - !!(mx&3)*2 - 16 - 3
+       || (unsigned)(src_y - !!(my&3)*2) > s->v_edge_pos - !!(my&3)*2 - 16 - 3){
+        uint8_t *uvbuf= s->edge_emu_buffer + 20 * s->linesize;
+
+        srcY -= 2 + 2*s->linesize;
+        ff_emulated_edge_mc(s->edge_emu_buffer, srcY, s->linesize, 16+4, 16+4,
+                            src_x - 2, src_y - 2, s->h_edge_pos, s->v_edge_pos);
+        srcY = s->edge_emu_buffer + 2 + 2*s->linesize;
+        ff_emulated_edge_mc(uvbuf     , srcU, s->uvlinesize, 8+1, 8+1,
+                            uvsrc_x, uvsrc_y, s->h_edge_pos >> 1, s->v_edge_pos >> 1);
+        ff_emulated_edge_mc(uvbuf + 16, srcV, s->uvlinesize, 8+1, 8+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;
+    s->dsp.put_h264_qpel_pixels_tab[0][dxy](s->dest[0], srcY, s->linesize);
+    s->dsp.put_h264_chroma_pixels_tab[0]   (s->dest[1], srcU, s->uvlinesize, 8, uvmx, uvmy);
+    s->dsp.put_h264_chroma_pixels_tab[0]   (s->dest[2], srcV, s->uvlinesize, 8, uvmx, uvmy);
+}
+
+/**
+ * B-frame specific motion compensation function - for direct/interpolated blocks
+ *
+ * @param r decoder context
+ * @param block_type type of the current block
+ */
+static inline void rv40_mc_b_interp(RV40DecContext *r, const int block_type)
+{
+    MpegEncContext *s = &r->s;
+    uint8_t *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;
+
+    mx = s->current_picture_ptr->motion_val[1][mv_pos][0];
+    my = s->current_picture_ptr->motion_val[1][mv_pos][1];
+    srcY = s->next_picture_ptr->data[0];
+    srcU = s->next_picture_ptr->data[1];
+    srcV = s->next_picture_ptr->data[2];
+
+    src_x = s->mb_x * 16 + (mx >> 2);
+    src_y = s->mb_y * 16 + (my >> 2);
+    uvsrc_x = s->mb_x * 8 + (mx >> 3);
+    uvsrc_y = s->mb_y * 8 + (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 - !!(mx&3)*2) > s->h_edge_pos - !!(mx&3)*2 - 16 - 3
+       || (unsigned)(src_y - !!(my&3)*2) > s->v_edge_pos - !!(my&3)*2 - 16 - 3){
+        uint8_t *uvbuf= s->edge_emu_buffer + 20 * s->linesize;
+
+        srcY -= 2 + 2*s->linesize;
+        ff_emulated_edge_mc(s->edge_emu_buffer, srcY, s->linesize, 16+4, 16+4,
+                            src_x - 2, src_y - 2, s->h_edge_pos, s->v_edge_pos);
+        srcY = s->edge_emu_buffer + 2 + 2*s->linesize;
+        ff_emulated_edge_mc(uvbuf     , srcU, s->uvlinesize, 8+1, 8+1,
+                            uvsrc_x, uvsrc_y, s->h_edge_pos >> 1, s->v_edge_pos >> 1);
+        ff_emulated_edge_mc(uvbuf + 16, srcV, s->uvlinesize, 8+1, 8+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;
+    s->dsp.avg_h264_qpel_pixels_tab[0][dxy](s->dest[0], srcY, s->linesize);
+    s->dsp.avg_h264_chroma_pixels_tab[0]   (s->dest[1], srcU, s->uvlinesize, 8, uvmx, uvmy);
+    s->dsp.avg_h264_chroma_pixels_tab[0]   (s->dest[2], srcV, s->uvlinesize, 8, uvmx, uvmy);
+}
+
+/**
  * Decode motion vector differences
  * and perform motion vector reconstruction and motion compensation.
  */
@@ -983,16 +1242,28 @@ static int rv40_decode_mv(RV40DecContext
         rv40_mc(r, block_type, 0, 0, 0, 2, 2);
         break;
     case RV40_MB_B_INTERP:
+        r->dmv[0][0] = 0;
+        r->dmv[0][1] = 0;
+        r->dmv[1][0] = 0;
+        r->dmv[1][1] = 0;
+        rv40_pred_mv_b  (r, block_type);
+        rv40_mc_b       (r, block_type);
+        rv40_mc_b_interp(r, block_type);
         break;
     case RV40_MB_P_16x16:
-    case RV40_MB_B_FORWARD:
-    case RV40_MB_B_BACKWARD:
     case RV40_MB_P_MIX16x16:
         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_B_FORWARD:
+    case RV40_MB_B_BACKWARD:
+        r->dmv[0][0] = get_omega_signed(gb);
+        r->dmv[0][1] = get_omega_signed(gb);
+        rv40_pred_mv_b  (r, block_type);
+        rv40_mc_b       (r, block_type);
+        break;
     case RV40_MB_P_16x8:
     case RV40_MB_P_8x16:
     case RV40_MB_B_DIRECT:
@@ -1010,6 +1281,11 @@ static int rv40_decode_mv(RV40DecContext
             rv40_mc(r, block_type, 0, 0, 0, 1, 2);
             rv40_mc(r, block_type, 8, 0, 1, 1, 2);
         }
+        if(block_type == RV40_MB_B_DIRECT){
+            rv40_pred_mv_b  (r, block_type);
+            rv40_mc_b       (r, block_type);
+            rv40_mc_b_interp(r, block_type);
+        }
         break;
     case RV40_MB_P_8x8:
         for(i=0;i< 4;i++){
@@ -1599,6 +1875,7 @@ 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;
+    avctx->max_b_frames = 8;
     avctx->has_b_frames = 1;
     s->low_delay = 0;
 



More information about the FFmpeg-soc mailing list