diff -rup common/common.c common/common.c --- common/common.c 2008-04-26 16:45:06.000000000 -0400 +++ common/common.c 2008-11-20 10:44:51.000000000 -0500 @@ -106,6 +106,12 @@ void x264_param_default( x264_param_t param->rc.f_complexity_blur = 20; param->rc.i_zones = 0; + /* Temporal Scalability */ + int i; + param->tscale.i_offset_array_size = 0; + for(i=0; itscale.i_offset_array[i] = 1; + /* Log */ param->pf_log = x264_log_default; param->p_log_private = NULL; diff -rup encoder/encoder.c encoder/encoder.c --- encoder/encoder.c 2008-04-26 16:45:06.000000000 -0400 +++ encoder/encoder.c 2008-11-20 12:29:32.000000000 -0500 @@ -428,6 +428,37 @@ static int x264_validate_parameters( x26 h->param.i_keyint_max = 1; h->param.i_keyint_min = x264_clip3( h->param.i_keyint_min, 1, h->param.i_keyint_max/2+1 ); + //check temporal scalable parameters + if(h->param.tscale.i_offset_array_size > TSCALE_MAX_OFFSET_COUNT) + { + x264_log( h, X264_LOG_ERROR, + "temporal scalable array size %d is greater than maximum %d. If filled out memory corruption has happened!! \n", + h->param.tscale.i_offset_array_size, TSCALE_MAX_OFFSET_COUNT); + return -2; + } + if(h->param.tscale.i_offset_array_size < 0) + h->param.tscale.i_offset_array_size = 0; + int max_offset = 0; + int i; + for(i=0; iparam.tscale.i_offset_array_size; i++) + { + if(h->param.tscale.i_offset_array[i] == 0) + { + x264_log( h, X264_LOG_WARNING, + "temporal scalable offset of 0 not allowed!! In index: %d of array \n",i); + h->param.tscale.i_offset_array[i] = 1; + } + if(h->param.tscale.i_offset_array[i] > max_offset) + max_offset = h->param.tscale.i_offset_array[i]; + } + if(max_offset > h->param.i_frame_reference) + { + x264_log( h, X264_LOG_WARNING, + "max temporal scalable offset %d is greater than maximum # of ref frames %d. Cannot do temporal scalability!! \n", + max_offset, h->param.i_frame_reference); + h->param.tscale.i_offset_array_size = 0; + } + h->param.i_bframe = x264_clip3( h->param.i_bframe, 0, X264_BFRAME_MAX ); h->param.i_bframe_bias = x264_clip3( h->param.i_bframe_bias, -90, 100 ); h->param.b_bframe_pyramid = h->param.b_bframe_pyramid && h->param.i_bframe > 1; @@ -767,6 +798,12 @@ int x264_encoder_reconfig( x264_t *h, x2 COPY( analyse.b_transform_8x8 ); if( h->frames.i_max_ref1 > 1 ) COPY( b_bframe_pyramid ); + + /* temporal scalability*/ + COPY(tscale.i_offset_array_size); + int i; + for(i=0;ii_ref0 = 0; h->i_ref1 = 0; - for( i = 0; h->frames.reference[i]; i++ ) + + /* check to see if temporal scalability is on */ + if (h->param.tscale.i_offset_array_size > 0) { - if( h->frames.reference[i]->i_poc < i_poc ) - { - h->fref0[h->i_ref0++] = h->frames.reference[i]; + int diff = h->fenc->i_frame - h->frames.i_last_idr; + int ref_offset_index = 0; + + //calculate offset only for non-idr + if(diff > 0) + { + //make sure the array index fits into the array + int array_index = (diff-1) % h->param.tscale.i_offset_array_size; + + //the offset table will be relative to current frame + //while internal encoder offsets are relative to i_frame_reference frames ago + if (diff < h->param.i_frame_reference) + ref_offset_index = diff - h->param.tscale.i_offset_array[array_index]; + else + ref_offset_index = h->param.i_frame_reference - h->param.tscale.i_offset_array[array_index]; + + /* Sanity check */ + if (ref_offset_index < 0 || ref_offset_index >= h->param.i_frame_reference) + { + x264_log( h, X264_LOG_WARNING, + "Bad temporal scalable offset for frame %d last idr %d # ref frames %d offset value %d \n", + h->fenc->i_frame, h->frames.i_last_idr, h->param.i_frame_reference, h->param.tscale.i_offset_array[array_index]); + ref_offset_index = 0; + } + + //Put the frame with given offset into the reference list + if(h->frames.reference[ref_offset_index]) + { + if( h->frames.reference[ref_offset_index]->i_poc < i_poc ) + { + h->fref0[h->i_ref0++] = h->frames.reference[ref_offset_index]; + } + else if( h->frames.reference[ref_offset_index]->i_poc > i_poc ) + { + h->fref1[h->i_ref1++] = h->frames.reference[ref_offset_index]; + } + } } - else if( h->frames.reference[i]->i_poc > i_poc ) - { - h->fref1[h->i_ref1++] = h->frames.reference[i]; + } + else + { + for( i = 0; h->frames.reference[i]; i++ ) + { + if( h->frames.reference[i]->i_poc < i_poc ) + { + h->fref0[h->i_ref0++] = h->frames.reference[i]; + } + else if( h->frames.reference[i]->i_poc > i_poc ) + { + h->fref1[h->i_ref1++] = h->frames.reference[i]; + } } } + + /* Order ref0 from higher to lower poc */ do { @@ -882,12 +967,22 @@ static inline void x264_reference_build_ h->b_ref_reorder[1] = 0; if( h->sh.i_type == SLICE_TYPE_P ) { - for( i = 0; i < h->i_ref0 - 1; i++ ) - if( h->fref0[i]->i_frame_num < h->fref0[i+1]->i_frame_num ) - { + if (h->i_ref0 == 1) + { + //make sure reordering happens if temporal scalable offset list + //has put a single frame but more than 1 frame away in the list + if (h->i_frame_num != h->fref0[0]->i_frame_num + 1) h->b_ref_reorder[0] = 1; - break; - } + } + else + { + for( i = 0; i < h->i_ref0 - 1; i++ ) + if( h->fref0[i]->i_frame_num < h->fref0[i+1]->i_frame_num ) + { + h->b_ref_reorder[0] = 1; + break; + } + } } h->i_ref1 = X264_MIN( h->i_ref1, h->frames.i_max_ref1 ); diff -rup x264.h x264.h --- x264.h 2008-04-26 16:45:07.000000000 -0400 +++ x264.h 2008-11-20 09:56:27.000000000 -0500 @@ -282,6 +282,14 @@ typedef struct x264_param_t char *psz_zones; /* alternate method of specifying zones */ } rc; + /* Temporal scalability parameters */ + struct + { +#define TSCALE_MAX_OFFSET_COUNT 16 + int i_offset_array[TSCALE_MAX_OFFSET_COUNT]; + int i_offset_array_size; /* Size of the offset-array. 0 means temporal scalability is disabled */ + } tscale; + /* Muxing parameters */ int b_aud; /* generate access unit delimiters */ int b_repeat_headers; /* put SPS/PPS before each keyframe */