Mercurial > libavcodec.hg
changeset 1238:6eab0df78d47 libavcodec
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
author | tmmm |
---|---|
date | Sat, 10 May 2003 21:46:17 +0000 |
parents | 6ce5cde4e1d4 |
children | fe46bd7c64d4 |
files | vp3.c |
diffstat | 1 files changed, 143 insertions(+), 45 deletions(-) [+] |
line wrap: on
line diff
--- a/vp3.c Sat May 10 21:35:29 2003 +0000 +++ b/vp3.c Sat May 10 21:46:17 2003 +0000 @@ -225,6 +225,10 @@ 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 @@ * 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 @@ /* 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 @@ /* 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 @@ /* 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 @@ } - 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 @@ /* 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 @@ * 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 @@ /* 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 @@ i, j); } - current_width += travel_width_mb[j]; mapping_index++; } } @@ -538,13 +550,13 @@ /* 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 @@ current_fragment += s->fragment_width; } + + return 0; /* successful path out */ } /* @@ -1106,7 +1120,7 @@ * 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 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ } } } + + return 0; } /* @@ -1410,7 +1445,7 @@ * 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 @@ 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 @@ 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 @@ } } } + + return 0; } /* @@ -1632,7 +1686,7 @@ * 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 @@ 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 @@ (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 @@ { 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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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; }