From f44b08a5a0ee46b52a9a608cbf2d075eab93db61 Mon Sep 17 00:00:00 2001 From: Mike Melanson Date: Sat, 21 May 2005 05:20:52 +0000 Subject: [PATCH] apply the loop filter to fragments as they are rendered into the final output Originally committed as revision 4291 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavcodec/vp3.c | 117 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 95 insertions(+), 22 deletions(-) diff --git a/libavcodec/vp3.c b/libavcodec/vp3.c index 2a07fb2acc..1fba635c3d 100644 --- a/libavcodec/vp3.c +++ b/libavcodec/vp3.c @@ -317,12 +317,15 @@ typedef struct Vp3DecodeContext { uint8_t edge_emu_buffer[9*2048]; //FIXME dynamic alloc uint8_t qscale_table[2048]; //FIXME dynamic alloc (width+15)/16 - /* Huffman decode */ - int hti; - unsigned int hbits; - int entries; - int huff_code_size; - uint16_t huffman_table[80][32][2]; + /* Huffman decode */ + int hti; + unsigned int hbits; + int entries; + int huff_code_size; + uint16_t huffman_table[80][32][2]; + + uint32_t filter_limit_values[64]; + int bounding_values_array[256]; } Vp3DecodeContext; static int theora_decode_comments(AVCodecContext *avctx, GetBitContext gb); @@ -862,7 +865,7 @@ static void init_frame(Vp3DecodeContext *s, GetBitContext *gb) } /* - * This function sets of the dequantization tables used for a particular + * This function sets up the dequantization tables used for a particular * frame. */ static void init_dequantizer(Vp3DecodeContext *s) @@ -957,6 +960,28 @@ static void init_dequantizer(Vp3DecodeContext *s) debug_dequantizers("\n"); } +/* + * This function initializes the loop filter boundary limits if the frame's + * quality index is different from the previous frame's. + */ +static void init_loop_filter(Vp3DecodeContext *s) +{ + int *bounding_values= s->bounding_values_array+127; + int filter_limit; + int x; + + filter_limit = s->filter_limit_values[s->quality_index]; + + /* set up the bounding values */ + memset(s->bounding_values_array, 0, 256 * sizeof(int)); + for (x = 0; x < filter_limit; x++) { + bounding_values[-x - filter_limit] = -filter_limit + x; + bounding_values[-x] = -x; + bounding_values[x] = x; + bounding_values[x + filter_limit] = filter_limit - x; + } +} + /* * This function is used to fetch runs of 1s or 0s from the bitstream for * use in determining which superblocks are fully and partially coded. @@ -2143,6 +2168,12 @@ static void reverse_dc_prediction(Vp3DecodeContext *s, } } + +static void horizontal_filter(unsigned char *first_pixel, int stride, + int *bounding_values); +static void vertical_filter(unsigned char *first_pixel, int stride, + int *bounding_values); + /* * Perform the final rendering for a particular slice of data. * The slice number ranges from 0..(macroblock_height - 1). @@ -2167,6 +2198,8 @@ static void render_slice(Vp3DecodeContext *s, int slice) int plane_height; int slice_height; int current_macroblock_entry = slice * s->macroblock_width * 6; + int *bounding_values= s->bounding_values_array+127; + int fragment_width; if (slice >= s->macroblock_height) return; @@ -2214,6 +2247,7 @@ static void render_slice(Vp3DecodeContext *s, int slice) slice_height = y + FRAGMENT_PIXELS; i = s->macroblock_fragments[current_macroblock_entry + 5]; } + fragment_width = plane_width / 2; if(ABS(stride) > 2048) return; //various tables are fixed size @@ -2361,25 +2395,54 @@ static void render_slice(Vp3DecodeContext *s, int slice) stride, 8); } + + /* do not perform left edge filter for left columns frags */ + if ((x > 0) && + (s->all_fragments[i].coding_method != MODE_COPY)) { + horizontal_filter( + output_plane + s->all_fragments[i].first_pixel - 7*stride, + stride, bounding_values); + } + + /* do not perform top edge filter for top row fragments */ + if ((y > 0) && + (s->all_fragments[i].coding_method != MODE_COPY)) { + vertical_filter( + output_plane + s->all_fragments[i].first_pixel + stride, + stride, bounding_values); + } + + /* do not perform right edge filter for right column + * fragments or if right fragment neighbor is also coded + * in this frame (it will be filtered for next fragment) */ + if ((x < plane_width - 1) && + (s->all_fragments[i].coding_method != MODE_COPY) && + (s->all_fragments[i + 1].coding_method == MODE_COPY)) { + horizontal_filter( + output_plane + s->all_fragments[i + 1].first_pixel - 7*stride, + stride, bounding_values); + } + + /* do not perform bottom edge filter for bottom row + * fragments or if bottom fragment neighbor is also coded + * in this frame (it will be filtered in the next row) */ + if ((y < plane_height - 1) && + (s->all_fragments[i].coding_method != MODE_COPY) && + (s->all_fragments[i + fragment_width].coding_method == MODE_COPY)) { + vertical_filter( + output_plane + s->all_fragments[i + fragment_width].first_pixel + stride, + stride, bounding_values); + } } } } - /* future loop filter logic goes here... */ - /* algorithm: - * if (slice != 0) - * run filter on 1st row of Y slice - * run filter on U slice - * run filter on V slice - * run filter on 2nd row of Y slice - */ - /* this looks like a good place for slice dispatch... */ /* algorithm: - * if (slice > 0) - * dispatch (slice - 1); * if (slice == s->macroblock_height - 1) - * dispatch (slice); // handle last slice + * dispatch (both last slice & 2nd-to-last slice); + * else if (slice > 0) + * dispatch (slice - 1); */ emms_c(); @@ -2628,9 +2691,10 @@ static void apply_loop_filter(Vp3DecodeContext *s) int fragment; int stride; unsigned char *plane_data; + int *bounding_values= s->bounding_values_array+127; +#if 0 int bounding_values_array[256]; - int *bounding_values= bounding_values_array+127; int filter_limit; /* find the right loop limit value */ @@ -2648,6 +2712,7 @@ static void apply_loop_filter(Vp3DecodeContext *s) bounding_values[x] = x; bounding_values[x + filter_limit] = filter_limit - x; } +#endif for (plane = 0; plane < 3; plane++) { @@ -2915,6 +2980,8 @@ static int vp3_decode_init(AVCodecContext *avctx) s->coded_intra_c_dequant[i] = vp31_intra_c_dequant[i]; for (i = 0; i < 64; i++) s->coded_inter_dequant[i] = vp31_inter_dequant[i]; + for (i = 0; i < 64; i++) + s->filter_limit_values[i] = vp31_filter_limit_values[i]; /* init VLC tables */ for (i = 0; i < 16; i++) { @@ -3054,8 +3121,10 @@ static int vp3_decode_frame(AVCodecContext *avctx, s->keyframe?"key":"", counter, s->quality_index); counter++; - if (s->quality_index != s->last_quality_index) + if (s->quality_index != s->last_quality_index) { init_dequantizer(s); + init_loop_filter(s); + } if (s->keyframe) { if (!s->theora) @@ -3185,7 +3254,7 @@ if (!s->keyframe) { STOP_TIMER("render_fragments")} {START_TIMER - apply_loop_filter(s); +// apply_loop_filter(s); STOP_TIMER("apply_loop_filter")} #if KEYFRAMES_ONLY } @@ -3433,6 +3502,10 @@ static int theora_decode_tables(AVCodecContext *avctx, GetBitContext gb) } } + /* XXX FIXME: these limit values need to come from the Theora header */ + for (i = 0; i < 64; i++) + s->filter_limit_values[i] = vp31_filter_limit_values[i]; + s->theora_tables = 1; return 0; -- GitLab