fixed buffer allocation logic (hopefully) so that decoder does not crash
authorMike Melanson <mike@multimedia.cx>
Wed, 7 May 2003 02:30:37 +0000 (02:30 +0000)
committerMike Melanson <mike@multimedia.cx>
Wed, 7 May 2003 02:30:37 +0000 (02:30 +0000)
most ffmpeg-enabled apps; added a bunch on motion compensation stuff
which is effectively disabled at the moment while details are worked out

Originally committed as revision 1840 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavcodec/vp3.c

index b22af02..2901b6a 100644 (file)
@@ -137,6 +137,9 @@ typedef struct Vp3Fragment {
     int last_coeff;
     int motion_x;
     int motion_y;
+    /* this indicates which ffmpeg put_pixels() function to use:
+     * 00b = no halfpel, 01b = x halfpel, 10b = y halfpel, 11b = both halfpel */
+    int motion_halfpel_index;
     /* address of first pixel taking into account which plane the fragment
      * lives on as well as the plane stride */
     int first_pixel;
@@ -1321,7 +1324,55 @@ static void unpack_modes(Vp3DecodeContext *s, GetBitContext *gb)
             }
         }
     }
+}
+
+/*
+ * This function adjusts the components of a motion vector for the halfpel
+ * motion grid. c_plane indicates whether the vector applies to the U or V
+ * plane. The function returns the halfpel function index to be used in
+ * ffmpeg's put_pixels[]() array of functions.
+ */
+static inline int adjust_vector(int *x, int *y, int c_plane)
+{
+    int motion_halfpel_index = 0;
+    int x_halfpel;
+    int y_halfpel;
+
+    if (!c_plane) {
+
+        x_halfpel = *x & 1;
+        motion_halfpel_index |= x_halfpel;
+        if (*x >= 0)
+            *x >>= 1;
+        else
+            *x = -( (-(*x) >> 1) + x_halfpel);
+
+        y_halfpel = *y & 1;
+        motion_halfpel_index |= (y_halfpel << 1);
+        if (*y >= 0)
+            *y >>= 1;
+        else
+            *y = -( (-(*y) >> 1) + y_halfpel);
+
+    } else {
+
+        x_halfpel = ((*x & 0x03) != 0);
+        motion_halfpel_index |= x_halfpel;
+        if (*x >= 0)
+            *x >>= 2;
+        else
+            *x = -( (-(*x) >> 2) + x_halfpel);
+
+        y_halfpel = ((*y & 0x03) != 0);
+        motion_halfpel_index |= (y_halfpel << 1);
+        if (*y >= 0)
+            *y >>= 2;
+        else
+            *y = -( (-(*y) >> 2) + y_halfpel);
+
+    }
 
+    return motion_halfpel_index;
 }
 
 /*
@@ -1460,6 +1511,14 @@ static void unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb)
                     last_motion_x = motion_x[0];
                     last_motion_y = motion_y[0];
                     break;
+
+                default:
+                    /* covers intra, inter without MV, golden without MV */
+                    memset(motion_x, 0, 6 * sizeof(int));
+                    memset(motion_y, 0, 6 * sizeof(int));
+
+                    /* no vector maintenance */
+                    break;
                 }
 
                 /* assign the motion vectors to the correct fragments */
@@ -1469,10 +1528,14 @@ static void unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb)
                 for (k = 0; k < 6; k++) {
                     current_fragment = 
                         s->macroblock_fragments[current_macroblock * 6 + k];
+                    s->all_fragments[current_fragment].motion_halfpel_index =
+                        adjust_vector(&motion_x[k], &motion_y[k],
+                        ((k == 4) || (k == 5)));
                     s->all_fragments[current_fragment].motion_x = motion_x[k];
-                    s->all_fragments[current_fragment].motion_x = motion_y[k];
-                    debug_vectors("    vector %d: fragment %d = (%d, %d)\n",
-                        k, current_fragment, motion_x[k], motion_y[k]);
+                    s->all_fragments[current_fragment].motion_y = motion_y[k];
+                    debug_vectors("    vector %d: fragment %d = (%d, %d), index %d\n",
+                        k, current_fragment, motion_x[k], motion_y[k],
+                        s->all_fragments[current_fragment].motion_halfpel_index);
                 }
             }
         }
@@ -1942,8 +2005,8 @@ static void reverse_dc_prediction(Vp3DecodeContext *s,
  */
 static void render_fragments(Vp3DecodeContext *s,
                              int first_fragment,
-                             int fragment_width,
-                             int fragment_height,
+                             int width,
+                             int height,
                              int plane /* 0 = Y, 1 = U, 2 = V */) 
 {
     int x, y;
@@ -1956,6 +2019,10 @@ static void render_fragments(Vp3DecodeContext *s,
     unsigned char *last_plane;
     unsigned char *golden_plane;
     int stride;
+    int motion_x, motion_y;
+    int motion_x_limit, motion_y_limit;
+    int motion_halfpel_index;
+    unsigned char *motion_source;
 
     debug_vp3("  vp3: rendering final fragments for %s\n",
         (plane == 0) ? "Y plane" : (plane == 1) ? "U plane" : "V plane");
@@ -1981,22 +2048,70 @@ static void render_fragments(Vp3DecodeContext *s,
         stride = -s->current_frame.linesize[2];
     }
 
+    motion_x_limit = width - 8;
+    motion_y_limit = height - 8;
+
     /* for each fragment row... */
-    for (y = 0; y < fragment_height; y++) {
+    for (y = 0; y < height; y += 8) {
 
         /* for each fragment in a row... */
-        for (x = 0; x < fragment_width; x++, i++) {
+        for (x = 0; x < width; x += 8, i++) {
 
             /* transform if this block was coded */
-            if (s->all_fragments[i].coding_method == MODE_INTRA) {
+            if (s->all_fragments[i].coding_method != MODE_COPY) {
+//            if (s->all_fragments[i].coding_method == MODE_INTRA) {
+
+                /* sort out the motion vector */
+                motion_x = x + s->all_fragments[i].motion_x;
+                motion_y = y + s->all_fragments[i].motion_y;
+                motion_halfpel_index = s->all_fragments[i].motion_halfpel_index;
+
+                if (motion_x < 0)
+                    motion_x = 0;
+                if (motion_y < 0)
+                    motion_y = 0;
+                if (motion_x > motion_x_limit)
+                    motion_x = motion_x_limit;
+                if (motion_y > motion_y_limit)
+                    motion_y = motion_y_limit;
+
+                /* first, take care of copying a block from either the
+                 * previous or the golden frame */
+                if ((s->all_fragments[i].coding_method == MODE_USING_GOLDEN) ||
+                    (s->all_fragments[i].coding_method == MODE_GOLDEN_MV)) {
+
+                    motion_source = golden_plane;
+                    motion_source += motion_x;
+                    motion_source += (motion_y * -stride);
+
+                    s->dsp.put_pixels_tab[1][motion_halfpel_index](
+                        output_plane + s->all_fragments[i].first_pixel,
+                        motion_source,
+                        stride, 8);
+
+                } else 
+                if (s->all_fragments[i].coding_method != MODE_INTRA) {
+
+                    motion_source = last_plane;
+                    motion_source += motion_x;
+                    motion_source += (motion_y * -stride);
+
+                    s->dsp.put_pixels_tab[1][motion_halfpel_index](
+                        output_plane + s->all_fragments[i].first_pixel,
+                        motion_source,
+                        stride, 8);
+                }
+
                 /* dequantize the DCT coefficients */
+                debug_idct("fragment %d, coding mode %d, DC = %d, dequant = %d:\n", 
+                    i, s->all_fragments[i].coding_method, 
+                    s->all_fragments[i].coeffs[0], dequantizer[0]);
                 for (j = 0; j < 64; j++)
                     dequant_block[dequant_index[j]] =
                         s->all_fragments[i].coeffs[j] *
                         dequantizer[j];
                 dequant_block[0] += 1024;
 
-                debug_idct("fragment %d:\n", i);
                 debug_idct("dequantized block:\n");
                 for (m = 0; m < 8; m++) {
                     for (n = 0; n < 8; n++) {
@@ -2007,32 +2122,36 @@ static void render_fragments(Vp3DecodeContext *s,
                 debug_idct("\n");
 
                 /* invert DCT and place in final output */
-                s->dsp.idct_put(
-                    output_plane + s->all_fragments[i].first_pixel,
-                    stride, dequant_block);
 
-/*
-                debug_idct("idct block:\n");
+                if (s->all_fragments[i].coding_method == MODE_INTRA)
+                    s->dsp.idct_put(
+                        output_plane + s->all_fragments[i].first_pixel,
+                        stride, dequant_block);
+                else
+//                    s->dsp.idct_add(
+                    s->dsp.idct_put(
+                        output_plane + s->all_fragments[i].first_pixel,
+                        stride, dequant_block);
+
+                debug_idct("block after idct_%s():\n",
+                    (s->all_fragments[i].coding_method == MODE_INTRA)?
+                    "put" : "add");
                 for (m = 0; m < 8; m++) {
                     for (n = 0; n < 8; n++) {
-                        debug_idct(" %3d", pixels[m * 8 + n]);
+                        debug_idct(" %3d", *(output_plane + 
+                            s->all_fragments[i].first_pixel + (m * stride + n)));
                     }
                     debug_idct("\n");
                 }
                 debug_idct("\n");
-*/
-            } else if (s->all_fragments[i].coding_method == MODE_COPY) {
-
-                /* copy directly from the previous frame */
-                for (m = 0; m < 8; m++)
-                    memcpy(
-                        output_plane + s->all_fragments[i].first_pixel + stride * m,
-                        last_plane + s->all_fragments[i].first_pixel + stride * m,
-                        8);
 
             } else {
 
-                /* carry out the motion compensation */
+                /* copy directly from the previous frame */
+                s->dsp.put_pixels_tab[1][0](
+                    output_plane + s->all_fragments[i].first_pixel,
+                    last_plane + s->all_fragments[i].first_pixel,
+                    stride, 8);
 
             }
         }
@@ -2187,10 +2306,10 @@ static int vp3_decode_init(AVCodecContext *avctx)
     s->macroblock_coded = av_malloc(s->macroblock_count + 1);
     init_block_mapping(s);
 
-    /* make sure that frames are available to be freed on the first decode */
-    if(avctx->get_buffer(avctx, &s->golden_frame) < 0) {
-        printf("vp3: get_buffer() failed\n");
-        return -1;
+    for (i = 0; i < 3; i++) {
+        s->current_frame.data[i] = NULL;
+        s->last_frame.data[i] = NULL;
+        s->golden_frame.data[i] = NULL;
     }
 
     return 0;
@@ -2224,7 +2343,12 @@ static int vp3_decode_frame(AVCodecContext *avctx,
 
     if (s->keyframe) {
         /* release the previous golden frame and get a new one */
-        avctx->release_buffer(avctx, &s->golden_frame);
+        if (s->golden_frame.data[0])
+            avctx->release_buffer(avctx, &s->golden_frame);
+
+        /* last frame, if allocated, is hereby invalidated */
+        if (s->last_frame.data[0])
+            avctx->release_buffer(avctx, &s->last_frame);
 
         s->golden_frame.reference = 0;
         if(avctx->get_buffer(avctx, &s->golden_frame) < 0) {
@@ -2270,17 +2394,18 @@ static int vp3_decode_frame(AVCodecContext *avctx,
     reverse_dc_prediction(s, s->v_fragment_start,
         s->fragment_width / 2, s->fragment_height / 2);
 
-    render_fragments(s, 0, s->fragment_width, s->fragment_height, 0);
-    render_fragments(s, s->u_fragment_start,
-        s->fragment_width / 2, s->fragment_height / 2, 1);
-    render_fragments(s, s->v_fragment_start,
-        s->fragment_width / 2, s->fragment_height / 2, 2);
+    render_fragments(s, 0, s->width, s->height, 0);
+    render_fragments(s, s->u_fragment_start, s->width / 2, s->height / 2, 1);
+    render_fragments(s, s->v_fragment_start, s->width / 2, s->height / 2, 2);
 
     *data_size=sizeof(AVFrame);
     *(AVFrame*)data= s->current_frame;
 
-    /* release the last frame, if it was allocated */
-    avctx->release_buffer(avctx, &s->last_frame);
+    /* release the last frame, if it is allocated and if it is not the
+     * golden frame */
+    if ((s->last_frame.data[0]) &&
+        (s->last_frame.data[0] != s->golden_frame.data[0]))
+        avctx->release_buffer(avctx, &s->last_frame);
 
     /* shuffle frames (last = current) */
     memcpy(&s->last_frame, &s->current_frame, sizeof(AVFrame));