diff options
author | Mike Melanson <mike@multimedia.cx> | 2003-05-07 02:30:37 +0000 |
---|---|---|
committer | Mike Melanson <mike@multimedia.cx> | 2003-05-07 02:30:37 +0000 |
commit | 44ae98ddef565e03080012bb22467bc7ed1ca1d2 (patch) | |
tree | 053b839f740c6521a9509852a9c1aa9608beb291 | |
parent | e20c40697cb6b40804acac9a92005779382c6e7e (diff) | |
download | ffmpeg-44ae98ddef565e03080012bb22467bc7ed1ca1d2.tar.gz |
fixed buffer allocation logic (hopefully) so that decoder does not crash
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
-rw-r--r-- | libavcodec/vp3.c | 199 |
1 files changed, 162 insertions, 37 deletions
diff --git a/libavcodec/vp3.c b/libavcodec/vp3.c index b22af02b49..2901b6aaca 100644 --- a/libavcodec/vp3.c +++ b/libavcodec/vp3.c @@ -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)); |