diff options
author | Mike Melanson <mike@multimedia.cx> | 2003-05-10 21:46:17 +0000 |
---|---|---|
committer | Mike Melanson <mike@multimedia.cx> | 2003-05-10 21:46:17 +0000 |
commit | 892fc83e88a20f9543c6c5be3626712be7a2e6f2 (patch) | |
tree | 3ab5a550761da5f45722207e90621f4f7e5180ca /libavcodec/vp3.c | |
parent | 85ea6b29582da35c5ebf9356537e0a00d8d47cb3 (diff) | |
download | ffmpeg-892fc83e88a20f9543c6c5be3626712be7a2e6f2.tar.gz |
squashed a bunch of subtle array indexing bugs, fixed block mapping
added more error checking, added (and enabled, for the time being) a
keyframe-only mode
Originally committed as revision 1849 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavcodec/vp3.c')
-rw-r--r-- | libavcodec/vp3.c | 188 |
1 files changed, 143 insertions, 45 deletions
diff --git a/libavcodec/vp3.c b/libavcodec/vp3.c index e5ecd67dd9..461be0918a 100644 --- a/libavcodec/vp3.c +++ b/libavcodec/vp3.c @@ -225,6 +225,10 @@ typedef struct Vp3DecodeContext { int superblock_count; int superblock_width; int superblock_height; + int y_superblock_width; + int y_superblock_height; + int c_superblock_width; + int c_superblock_height; int u_superblock_start; int v_superblock_start; unsigned char *superblock_coding; @@ -292,8 +296,10 @@ typedef struct Vp3DecodeContext { * This function sets up all of the various blocks mappings: * superblocks <-> fragments, macroblocks <-> fragments, * superblocks <-> macroblocks + * + * Returns 0 is successful; returns 1 if *anything* went wrong. */ -static void init_block_mapping(Vp3DecodeContext *s) +static int init_block_mapping(Vp3DecodeContext *s) { int i, j; signed int hilbert_walk_y[16]; @@ -387,9 +393,10 @@ static void init_block_mapping(Vp3DecodeContext *s) /* start of Y superblocks */ right_edge = s->fragment_width; bottom_edge = s->fragment_height; - current_width = 0; + current_width = -1; current_height = 0; - superblock_row_inc = 3 * s->fragment_width; + superblock_row_inc = 3 * s->fragment_width - + (s->y_superblock_width * 4 - s->fragment_width); hilbert = hilbert_walk_y; /* the first operation for this variable is to advance by 1 */ @@ -400,9 +407,10 @@ static void init_block_mapping(Vp3DecodeContext *s) /* start of U superblocks */ right_edge = s->fragment_width / 2; bottom_edge = s->fragment_height / 2; - current_width = 0; + current_width = -1; current_height = 0; - superblock_row_inc = 3 * (s->fragment_width / 2); + superblock_row_inc = 3 * (s->fragment_width / 2) - + (s->c_superblock_width * 4 - s->fragment_width / 2); hilbert = hilbert_walk_c; /* the first operation for this variable is to advance by 1 */ @@ -413,9 +421,10 @@ static void init_block_mapping(Vp3DecodeContext *s) /* start of V superblocks */ right_edge = s->fragment_width / 2; bottom_edge = s->fragment_height / 2; - current_width = 0; + current_width = -1; current_height = 0; - superblock_row_inc = 3 * (s->fragment_width / 2); + superblock_row_inc = 3 * (s->fragment_width / 2) - + (s->c_superblock_width * 4 - s->fragment_width / 2); hilbert = hilbert_walk_c; /* the first operation for this variable is to advance by 1 */ @@ -423,9 +432,9 @@ static void init_block_mapping(Vp3DecodeContext *s) } - if (current_width >= right_edge) { + if (current_width >= right_edge - 1) { /* reset width and move to next superblock row */ - current_width = 0; + current_width = -1; current_height += 4; /* fragment is now at the start of a new superblock row */ @@ -435,21 +444,23 @@ static void init_block_mapping(Vp3DecodeContext *s) /* iterate through all 16 fragments in a superblock */ for (j = 0; j < 16; j++) { current_fragment += hilbert[j]; + current_width += travel_width[j]; current_height += travel_height[j]; /* check if the fragment is in bounds */ - if ((current_width <= right_edge) && + if ((current_width < right_edge) && (current_height < bottom_edge)) { s->superblock_fragments[mapping_index] = current_fragment; - debug_init(" mapping fragment %d to superblock %d, position %d\n", - s->superblock_fragments[mapping_index], i, j); + debug_init(" mapping fragment %d to superblock %d, position %d (%d/%d x %d/%d)\n", + s->superblock_fragments[mapping_index], i, j, + current_width, right_edge, current_height, bottom_edge); } else { s->superblock_fragments[mapping_index] = -1; - debug_init(" superblock %d, position %d has no fragment\n", - i, j); + debug_init(" superblock %d, position %d has no fragment (%d/%d x %d/%d)\n", + i, j, + current_width, right_edge, current_height, bottom_edge); } - current_width += travel_width[j]; mapping_index++; } } @@ -458,9 +469,10 @@ static void init_block_mapping(Vp3DecodeContext *s) * all of the Y plane superblocks to build this mapping */ right_edge = s->macroblock_width; bottom_edge = s->macroblock_height; - current_width = 0; + current_width = -1; current_height = 0; - superblock_row_inc = s->macroblock_width; + superblock_row_inc = s->macroblock_width - + (s->y_superblock_width * 2 - s->macroblock_width);; hilbert = hilbert_walk_mb; mapping_index = 0; current_macroblock = -1; @@ -478,10 +490,11 @@ static void init_block_mapping(Vp3DecodeContext *s) /* iterate through each potential macroblock in the superblock */ for (j = 0; j < 4; j++) { current_macroblock += hilbert_walk_mb[j]; + current_width += travel_width_mb[j]; current_height += travel_height_mb[j]; /* check if the macroblock is in bounds */ - if ((current_width <= right_edge) && + if ((current_width < right_edge) && (current_height < bottom_edge)) { s->superblock_macroblocks[mapping_index] = current_macroblock; debug_init(" mapping macroblock %d to superblock %d, position %d\n", @@ -492,7 +505,6 @@ static void init_block_mapping(Vp3DecodeContext *s) i, j); } - current_width += travel_width_mb[j]; mapping_index++; } } @@ -538,13 +550,13 @@ static void init_block_mapping(Vp3DecodeContext *s) /* C planes */ c_fragment = s->u_fragment_start + (i * s->fragment_width / 4) + (j / 2); - s->all_fragments[c_fragment].macroblock = s->macroblock_count; + s->all_fragments[c_fragment].macroblock = s->macroblock_count; s->macroblock_fragments[mapping_index++] = c_fragment; debug_init("%d ", c_fragment); c_fragment = s->v_fragment_start + (i * s->fragment_width / 4) + (j / 2); - s->all_fragments[c_fragment].macroblock = s->macroblock_count; + s->all_fragments[c_fragment].macroblock = s->macroblock_count; s->macroblock_fragments[mapping_index++] = c_fragment; debug_init("%d ", c_fragment); @@ -559,6 +571,8 @@ static void init_block_mapping(Vp3DecodeContext *s) current_fragment += s->fragment_width; } + + return 0; /* successful path out */ } /* @@ -1106,7 +1120,7 @@ static int get_motion_vector_fixed(GetBitContext *gb) * This function unpacks all of the superblock/macroblock/fragment coding * information from the bitstream. */ -static void unpack_superblocks(Vp3DecodeContext *s, GetBitContext *gb) +static int unpack_superblocks(Vp3DecodeContext *s, GetBitContext *gb) { int bit = 0; int current_superblock = 0; @@ -1212,6 +1226,11 @@ static void unpack_superblocks(Vp3DecodeContext *s, GetBitContext *gb) /* if the fragment is in bounds, check its coding status */ current_fragment = s->superblock_fragments[i * 16 + j]; + if (current_fragment >= s->fragment_count) { + printf (" vp3:unpack_superblocks(): bad fragment number (%d >= %d)\n", + current_fragment, s->fragment_count); + return 1; + } if (current_fragment != -1) { if (s->superblock_coding[i] == SB_NOT_CODED) { @@ -1286,13 +1305,15 @@ static void unpack_superblocks(Vp3DecodeContext *s, GetBitContext *gb) s->last_coded_y_fragment, s->first_coded_c_fragment, s->last_coded_c_fragment); + + return 0; } /* * This function unpacks all the coding mode data for individual macroblocks * from the bitstream. */ -static void unpack_modes(Vp3DecodeContext *s, GetBitContext *gb) +static int unpack_modes(Vp3DecodeContext *s, GetBitContext *gb) { int i, j, k; int scheme; @@ -1334,6 +1355,11 @@ static void unpack_modes(Vp3DecodeContext *s, GetBitContext *gb) if ((current_macroblock == -1) || (!s->macroblock_coded[current_macroblock])) continue; + if (current_macroblock >= s->macroblock_count) { + printf (" vp3:unpack_modes(): bad macroblock number (%d >= %d)\n", + current_macroblock, s->macroblock_count); + return 1; + } /* mode 7 means get 3 bits for each coding mode */ if (scheme == 7) @@ -1344,6 +1370,13 @@ static void unpack_modes(Vp3DecodeContext *s, GetBitContext *gb) for (k = 0; k < 6; k++) { current_fragment = s->macroblock_fragments[current_macroblock * 6 + k]; + if (current_fragment == -1) + continue; + if (current_fragment >= s->fragment_count) { + printf (" vp3:unpack_modes(): bad fragment number (%d >= %d)\n", + current_fragment, s->fragment_count); + return 1; + } if (s->all_fragments[current_fragment].coding_method != MODE_COPY) s->all_fragments[current_fragment].coding_method = @@ -1355,6 +1388,8 @@ static void unpack_modes(Vp3DecodeContext *s, GetBitContext *gb) } } } + + return 0; } /* @@ -1410,7 +1445,7 @@ static inline int adjust_vector(int *x, int *y, int c_plane) * This function unpacks all the motion vectors for the individual * macroblocks from the bitstream. */ -static void unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb) +static int unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb) { int i, j, k; int coding_mode; @@ -1448,8 +1483,18 @@ static void unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb) if ((current_macroblock == -1) || (!s->macroblock_coded[current_macroblock])) continue; + if (current_macroblock >= s->macroblock_count) { + printf (" vp3:unpack_vectors(): bad macroblock number (%d >= %d)\n", + current_macroblock, s->macroblock_count); + return 1; + } current_fragment = s->macroblock_fragments[current_macroblock * 6]; + if (current_fragment >= s->fragment_count) { + printf (" vp3:unpack_vectors(): bad fragment number (%d >= %d\n", + current_fragment, s->fragment_count); + return 1; + } switch (s->all_fragments[current_fragment].coding_method) { case MODE_INTER_PLUS_MV: @@ -1559,6 +1604,13 @@ static void unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb) for (k = 0; k < 6; k++) { current_fragment = s->macroblock_fragments[current_macroblock * 6 + k]; + if (current_fragment == -1) + continue; + if (current_fragment >= s->fragment_count) { + printf (" vp3:unpack_vectors(): bad fragment number (%d >= %d)\n", + current_fragment, s->fragment_count); + return 1; + } s->all_fragments[current_fragment].motion_halfpel_index = adjust_vector(&motion_x[k], &motion_y[k], ((k == 4) || (k == 5))); @@ -1571,6 +1623,8 @@ static void unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb) } } } + + return 0; } /* @@ -1632,7 +1686,7 @@ static int unpack_vlcs(Vp3DecodeContext *s, GetBitContext *gb, * This function unpacks all of the DCT coefficient data from the * bitstream. */ -static void unpack_dct_coeffs(Vp3DecodeContext *s, GetBitContext *gb) +static int unpack_dct_coeffs(Vp3DecodeContext *s, GetBitContext *gb) { int i; int dc_y_table; @@ -1716,6 +1770,8 @@ static void unpack_dct_coeffs(Vp3DecodeContext *s, GetBitContext *gb) residual_eob_run = unpack_vlcs(s, gb, &s->ac_vlc_4[ac_c_table], i, s->first_coded_c_fragment, s->last_coded_c_fragment, residual_eob_run); } + + return 0; } /* @@ -2072,6 +2128,7 @@ static void render_fragments(Vp3DecodeContext *s, (motion_source > lower_motion_limit)) { // printf (" vp3: help! motion source (%d) out of range (%d..%d)\n", // motion_source, upper_motion_limit, lower_motion_limit); + continue; } /* first, take care of copying a block from either the @@ -2210,6 +2267,10 @@ static int vp3_decode_init(AVCodecContext *avctx) { Vp3DecodeContext *s = avctx->priv_data; int i; + int c_width; + int c_height; + int y_superblock_count; + int c_superblock_count; s->avctx = avctx; s->width = avctx->width; @@ -2222,11 +2283,20 @@ static int vp3_decode_init(AVCodecContext *avctx) * in the first frame decode */ s->quality_index = -1; - s->superblock_width = (s->width + 31) / 32; - s->superblock_height = (s->height + 31) / 32; - s->superblock_count = s->superblock_width * s->superblock_height * 3 / 2; - s->u_superblock_start = s->superblock_width * s->superblock_height; - s->v_superblock_start = s->superblock_width * s->superblock_height * 5 / 4; + s->y_superblock_width = (s->width + 31) / 32; + s->y_superblock_height = (s->height + 31) / 32; + y_superblock_count = s->y_superblock_width * s->y_superblock_height; + + /* work out the dimensions for the C planes */ + c_width = s->width / 2; + c_height = s->height / 2; + s->c_superblock_width = (c_width + 31) / 32; + s->c_superblock_height = (c_height + 31) / 32; + c_superblock_count = s->c_superblock_width * s->c_superblock_height; + + s->superblock_count = y_superblock_count + (c_superblock_count * 2); + s->u_superblock_start = y_superblock_count; + s->v_superblock_start = s->u_superblock_start + c_superblock_count; s->superblock_coding = av_malloc(s->superblock_count); s->macroblock_width = (s->width + 15) / 16; @@ -2241,9 +2311,14 @@ static int vp3_decode_init(AVCodecContext *avctx) s->u_fragment_start = s->fragment_width * s->fragment_height; s->v_fragment_start = s->fragment_width * s->fragment_height * 5 / 4; - debug_init(" width: %d x %d\n", s->width, s->height); - debug_init(" superblocks: %d x %d, %d total\n", - s->superblock_width, s->superblock_height, s->superblock_count); + debug_init(" Y plane: %d x %d\n", s->width, s->height); + debug_init(" C plane: %d x %d\n", c_width, c_height); + debug_init(" Y superblocks: %d x %d, %d total\n", + s->y_superblock_width, s->y_superblock_height, y_superblock_count); + debug_init(" C superblocks: %d x %d, %d total\n", + s->c_superblock_width, s->c_superblock_height, c_superblock_count); + debug_init(" total superblocks = %d, U starts @ %d, V starts @ %d\n", + s->superblock_count, s->u_superblock_start, s->v_superblock_start); debug_init(" macroblocks: %d x %d, %d total\n", s->macroblock_width, s->macroblock_height, s->macroblock_count); debug_init(" %d fragments, %d x %d, u starts @ %d, v starts @ %d\n", @@ -2333,12 +2408,10 @@ static int vp3_decode_frame(AVCodecContext *avctx, counter++; if (s->keyframe) { - /* release the previous golden frame and get a new one */ - if (s->golden_frame.data[0]) + if ((s->golden_frame.data[0]) && + (s->last_frame.data[0] == 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]) + else if (s->last_frame.data[0]) avctx->release_buffer(avctx, &s->last_frame); s->golden_frame.reference = 0; @@ -2374,10 +2447,28 @@ static int vp3_decode_frame(AVCodecContext *avctx, init_frame(s, &gb); - unpack_superblocks(s, &gb); - unpack_modes(s, &gb); - unpack_vectors(s, &gb); - unpack_dct_coeffs(s, &gb); +#define KEYFRAMES_ONLY 1 +#if KEYFRAMES_ONLY +if (!s->keyframe) { + + memcpy(s->current_frame.data[0], s->golden_frame.data[0], + s->current_frame.linesize[0] * s->height); + memcpy(s->current_frame.data[1], s->golden_frame.data[1], + s->current_frame.linesize[1] * s->height / 2); + memcpy(s->current_frame.data[2], s->golden_frame.data[2], + s->current_frame.linesize[2] * s->height / 2); + +} else { +#endif + + if (unpack_superblocks(s, &gb) || + unpack_modes(s, &gb) || + unpack_vectors(s, &gb) || + unpack_dct_coeffs(s, &gb)) { + + printf(" vp3: could not decode frame\n"); + return -1; + } reverse_dc_prediction(s, 0, s->fragment_width, s->fragment_height); reverse_dc_prediction(s, s->u_fragment_start, @@ -2389,6 +2480,10 @@ static int vp3_decode_frame(AVCodecContext *avctx, 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); +#if KEYFRAMES_ONLY +} +#endif + *data_size=sizeof(AVFrame); *(AVFrame*)data= s->current_frame; @@ -2419,9 +2514,12 @@ static int vp3_decode_end(AVCodecContext *avctx) av_free(s->macroblock_coded); /* release all frames */ - avctx->release_buffer(avctx, &s->golden_frame); - avctx->release_buffer(avctx, &s->last_frame); - avctx->release_buffer(avctx, &s->current_frame); + if (s->golden_frame.data[0]) + avctx->release_buffer(avctx, &s->golden_frame); + if (s->last_frame.data[0]) + avctx->release_buffer(avctx, &s->last_frame); + /* no need to release the current_frame since it will always be pointing + * to the same frame as either the golden or last frame */ return 0; } |