Do MC and IDCT in coding (hilbert) order

This increases the slice size to 64 pixels, due to having to decode an
entire chroma superblock row per slice.

This can be up to 6% slower depending on clip and CPU, but is necessary
for future optimizations that gain significantly more than was lost.

Originally committed as revision 22189 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
David Conrad 2010-03-03 23:27:40 +00:00
parent 35c28d23cb
commit 7a095ea6fb

View File

@ -122,6 +122,13 @@ static const int ModeAlphabet[6][CODING_MODE_COUNT] =
}; };
static const uint8_t hilbert_offset[16][2] = {
{0,0}, {1,0}, {1,1}, {0,1},
{0,2}, {0,3}, {1,3}, {1,2},
{2,2}, {2,3}, {3,3}, {3,2},
{3,1}, {2,1}, {2,0}, {3,0}
};
#define MIN_DEQUANT_VAL 2 #define MIN_DEQUANT_VAL 2
typedef struct Vp3DecodeContext { typedef struct Vp3DecodeContext {
@ -1369,19 +1376,19 @@ static void vp3_draw_horiz_band(Vp3DecodeContext *s, int y)
/* /*
* Perform the final rendering for a particular slice of data. * Perform the final rendering for a particular slice of data.
* The slice number ranges from 0..(macroblock_height - 1). * The slice number ranges from 0..(c_superblock_height - 1).
*/ */
static void render_slice(Vp3DecodeContext *s, int slice) static void render_slice(Vp3DecodeContext *s, int slice)
{ {
int x; int x, y, i, j;
int16_t *dequantizer; int16_t *dequantizer;
LOCAL_ALIGNED_16(DCTELEM, block, [64]); LOCAL_ALIGNED_16(DCTELEM, block, [64]);
int motion_x = 0xdeadbeef, motion_y = 0xdeadbeef; int motion_x = 0xdeadbeef, motion_y = 0xdeadbeef;
int motion_halfpel_index; int motion_halfpel_index;
uint8_t *motion_source; uint8_t *motion_source;
int plane; int plane, first_pixel;
if (slice >= s->macroblock_height) if (slice >= s->c_superblock_height)
return; return;
for (plane = 0; plane < 3; plane++) { for (plane = 0; plane < 3; plane++) {
@ -1391,9 +1398,14 @@ static void render_slice(Vp3DecodeContext *s, int slice)
int stride = s->current_frame.linesize[plane]; int stride = s->current_frame.linesize[plane];
int plane_width = s->width >> !!plane; int plane_width = s->width >> !!plane;
int plane_height = s->height >> !!plane; int plane_height = s->height >> !!plane;
int y = slice * FRAGMENT_PIXELS << !plane ;
int slice_height = y + (FRAGMENT_PIXELS << !plane); int sb_x, sb_y = slice << !plane;
int i = s->fragment_start[plane] + (y>>3)*(s->fragment_width>>!!plane); int slice_height = sb_y + (plane ? 1 : 2);
int slice_width = plane ? s->c_superblock_width : s->y_superblock_width;
int fragment_width = s->fragment_width >> !!plane;
int fragment_height = s->fragment_height >> !!plane;
int fragment_start = s->fragment_start[plane];
if (!s->flipped_image) stride = -stride; if (!s->flipped_image) stride = -stride;
if (CONFIG_GRAY && plane && (s->avctx->flags & CODEC_FLAG_GRAY)) if (CONFIG_GRAY && plane && (s->avctx->flags & CODEC_FLAG_GRAY))
@ -1403,17 +1415,24 @@ static void render_slice(Vp3DecodeContext *s, int slice)
if(FFABS(stride) > 2048) if(FFABS(stride) > 2048)
return; //various tables are fixed size return; //various tables are fixed size
/* for each fragment row in the slice (both of them)... */ /* for each superblock row in the slice (both of them)... */
for (; y < slice_height; y += 8) { for (; sb_y < slice_height; sb_y++) {
/* for each fragment in a row... */ /* for each superblock in a row... */
for (x = 0; x < plane_width; x += 8, i++) { for (sb_x = 0; sb_x < slice_width; sb_x++) {
int first_pixel = y*stride + x;
if ((i < 0) || (i >= s->fragment_count)) { /* for each block in a superblock... */
av_log(s->avctx, AV_LOG_ERROR, " vp3:render_slice(): bad fragment number (%d)\n", i); for (j = 0; j < 16; j++) {
return; x = 4*sb_x + hilbert_offset[j][0];
} y = 4*sb_y + hilbert_offset[j][1];
i = fragment_start + y*fragment_width + x;
// bounds check
if (x >= fragment_width || y >= fragment_height)
continue;
first_pixel = 8*y*stride + 8*x;
/* transform if this block was coded */ /* transform if this block was coded */
if (s->all_fragments[i].coding_method != MODE_COPY) { if (s->all_fragments[i].coding_method != MODE_COPY) {
@ -1439,8 +1458,8 @@ static void render_slice(Vp3DecodeContext *s, int slice)
motion_y= (motion_y>>1) | (motion_y&1); motion_y= (motion_y>>1) | (motion_y&1);
} }
src_x= (motion_x>>1) + x; src_x= (motion_x>>1) + 8*x;
src_y= (motion_y>>1) + y; src_y= (motion_y>>1) + 8*y;
if ((motion_x == 127) || (motion_y == 127)) if ((motion_x == 127) || (motion_y == 127))
av_log(s->avctx, AV_LOG_ERROR, " help! got invalid motion vector! (%X, %X)\n", motion_x, motion_y); av_log(s->avctx, AV_LOG_ERROR, " help! got invalid motion vector! (%X, %X)\n", motion_x, motion_y);
@ -1526,11 +1545,11 @@ static void render_slice(Vp3DecodeContext *s, int slice)
stride, 8); stride, 8);
} }
}
} }
// Filter the previous block row. We can't filter the current row yet
// since it needs pixels from the next row // Filter up to the last row in the superblock row
if (y > 0) apply_loop_filter(s, plane, 4*sb_y - !!sb_y, FFMIN(4*sb_y+3, fragment_height-1));
apply_loop_filter(s, plane, (y>>3)-1, (y>>3));
} }
} }
@ -1542,9 +1561,7 @@ static void render_slice(Vp3DecodeContext *s, int slice)
* dispatch (slice - 1); * dispatch (slice - 1);
*/ */
// now that we've filtered the last rows, they're safe to display vp3_draw_horiz_band(s, 64*slice + 64-16);
if (slice)
vp3_draw_horiz_band(s, 16*slice);
} }
/* /*
@ -1875,7 +1892,7 @@ static int vp3_decode_frame(AVCodecContext *avctx,
} }
s->last_slice_end = 0; s->last_slice_end = 0;
for (i = 0; i < s->macroblock_height; i++) for (i = 0; i < s->c_superblock_height; i++)
render_slice(s, i); render_slice(s, i);
// filter the last row // filter the last row