@ -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:
* 00 b = no halfpel , 01 b = x halfpel , 10 b = y halfpel , 11 b = 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 ) ) ;