diff --git a/common/bs.h b/common/bs.h index 1a73690..ea2c140 100644 --- a/common/bs.h +++ b/common/bs.h @@ -141,6 +141,13 @@ static inline void bs_align_1( bs_t *s ) bs_flush( s ); } +static inline void bs_align_10( bs_t *s ) +{ + if( s->i_left&7 ) + bs_write1( s, 1 ); + bs_flush( s ); +} + /* golomb functions */ static const uint8_t x264_ue_size_tab[256] = diff --git a/common/common.c b/common/common.c index 71a29b1..e53417c 100644 --- a/common/common.c +++ b/common/common.c @@ -141,6 +141,8 @@ void x264_param_default( x264_param_t *param ) param->b_repeat_headers = 1; param->b_aud = 0; + param->b_nal_hrd = 0; + param->i_pulldown = 0; } static int parse_enum( const char *arg, const char * const *names, int *dst ) @@ -356,7 +358,23 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) OPT("cabac-idc") p->i_cabac_init_idc = atoi(value); OPT("interlaced") + { + p->b_interlaced = atobool(value); + p->b_nal_hrd = atobool(value); // this is only a bool + p->b_tff = 1; + } + OPT("tff") + { p->b_interlaced = atobool(value); + p->b_nal_hrd = atobool(value); // this is only a bool + p->b_tff = 1; + } + OPT("bff") + { + p->b_interlaced = atobool(value); + p->b_nal_hrd = atobool(value); // this is only a bool + p->b_tff = 0; + } OPT("cqm") { if( strstr( value, "flat" ) ) @@ -548,6 +566,10 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) p->analyse.b_ssim = atobool(value); OPT("aud") p->b_aud = atobool(value); + OPT2("pulldown","pd") + p->i_pulldown = atoi(value); + OPT("nal-hrd") + p->b_nal_hrd = atobool(value); OPT("sps-id") p->i_sps_id = atoi(value); OPT("global-header") diff --git a/common/common.h b/common/common.h index 80648a8..10fda4c 100644 --- a/common/common.h +++ b/common/common.h @@ -271,6 +271,10 @@ struct x264_t int i_poc_lsb; /* decoding only */ int i_poc; /* decoding only */ + int i_cpb_delay; /* Equal to number of fields preceding this field + * since last buffering_period SEI */ + int i_pic_struct_prev; + int i_thread_num; /* threads only */ int i_nal_type; /* threads only */ int i_nal_ref_idc; /* threads only */ diff --git a/common/set.h b/common/set.h index 2d53511..2f656ea 100644 --- a/common/set.h +++ b/common/set.h @@ -124,6 +124,20 @@ typedef struct int i_num_reorder_frames; int i_max_dec_frame_buffering; + int b_nal_hrd_parameters_present; + int i_pulldown_type; + int b_pic_struct_present_flag; + struct + { + int i_bit_rate; + int i_cpb_size; + int b_cbr; + + int i_initial_cpb_removal_delay_length; + int i_cpb_removal_delay_length; + int i_dpb_output_delay_length; + } nal_hrd_parameters; + /* FIXME to complete */ } vui; diff --git a/encoder/encoder.c b/encoder/encoder.c index fb34ca8..d80c027 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -385,6 +385,31 @@ static int x264_validate_parameters( x264_t *h ) } } + if( h->param.b_nal_hrd ) + { + if( h->param.rc.i_vbv_max_bitrate == 0 || h->param.rc.i_vbv_buffer_size == 0 ) + { + x264_log( h, X264_LOG_WARNING, "NAL HRD parameters require VBV max bitrate and buffer size to be specified\n" ); + h->param.b_nal_hrd = 0; + } + } + + if( h->param.i_pulldown > 0 ) // 32 or 64 + { + if( h->param.b_nal_hrd == 0 ) + { + x264_log( h, X264_LOG_WARNING, "pulldown requires NAL HRD parameters setting\n" ); + h->param.i_pulldown = 0; + } + else { + if( h->param.i_pulldown != 32 && h->param.i_pulldown != 64 ) + { + x264_log( h, X264_LOG_WARNING, "32/64 only acceptable values for --pulldown. Forcing to 32 (3:2)" ); + h->param.i_pulldown = 32; + } + } + } + if( h->param.rc.i_rc_method < 0 || h->param.rc.i_rc_method > 2 ) { x264_log( h, X264_LOG_ERROR, "no ratecontrol method specified\n" ); @@ -642,6 +667,7 @@ x264_t *x264_encoder_open ( x264_param_t *param ) h->i_frame = 0; h->i_frame_num = 0; h->i_idr_pic_id = 0; + h->i_cpb_delay = 0; h->sps = &h->sps_array[0]; x264_sps_init( h->sps, h->param.i_sps_id, &h->param ); @@ -822,11 +848,6 @@ int x264_encoder_headers( x264_t *h, x264_nal_t **pp_nal, int *pi_nal ) /* Put SPS and PPS */ if( h->i_frame == 0 ) { - /* identify ourself */ - x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); - x264_sei_version_write( h, &h->out.bs ); - x264_nal_end( h ); - /* generate sequence parameters */ x264_nal_start( h, NAL_SPS, NAL_PRIORITY_HIGHEST ); x264_sps_write( &h->out.bs, h->sps ); @@ -836,6 +857,11 @@ int x264_encoder_headers( x264_t *h, x264_nal_t **pp_nal, int *pi_nal ) x264_nal_start( h, NAL_PPS, NAL_PRIORITY_HIGHEST ); x264_pps_write( &h->out.bs, h->pps ); x264_nal_end( h ); + + /* identify ourself */ + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + x264_sei_version_write( h, &h->out.bs ); + x264_nal_end( h ); } /* now set output*/ *pi_nal = h->out.i_nal; @@ -1293,11 +1319,14 @@ int x264_encoder_encode( x264_t *h, x264_picture_t *pic_in, x264_picture_t *pic_out ) { + + static const int tbt_pattern[] = { 5, 4, 6, 3 }; x264_t *thread_current, *thread_prev, *thread_oldest; int i_nal_type; int i_nal_ref_idc; int i_global_qp; + int cpb_removal_delay; if( h->param.i_threads > 1) { @@ -1495,22 +1524,128 @@ do_encode: /* Write SPS and PPS */ if( i_nal_type == NAL_SLICE_IDR && h->param.b_repeat_headers ) { + /* generate sequence parameters */ + x264_nal_start( h, NAL_SPS, NAL_PRIORITY_HIGHEST ); + x264_sps_write( &h->out.bs, h->sps ); + x264_nal_end( h ); + + /* generate picture parameters */ + x264_nal_start( h, NAL_PPS, NAL_PRIORITY_HIGHEST ); + x264_pps_write( &h->out.bs, h->pps ); + x264_nal_end( h ); + if( h->fenc->i_frame == 0 ) { + if( !h->param.b_nal_hrd ) { // only write here if !nal-hrd , else right in buffperiod nal /* identify ourself */ x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); x264_sei_version_write( h, &h->out.bs ); + bs_rbsp_trailing(&h->out.bs); x264_nal_end( h ); } + } + } - /* generate sequence parameters */ - x264_nal_start( h, NAL_SPS, NAL_PRIORITY_HIGHEST ); - x264_sps_write( &h->out.bs, h->sps ); + if( h->param.b_nal_hrd ) + { + int dpb_output_delay, pic_struct; + pic_struct = 0; + + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + + // write bp sei then close and reopen nal to create separate nal from pt sei + if( i_nal_type == NAL_SLICE_IDR ) { + x264_sei_buffering_period_write( &h->param, &h->out.bs, h->sps ); + if( h->fenc->i_frame == 0 ) // write identifying data after bp in same nal + { + /* identify ourself */ + x264_sei_version_write( h, &h->out.bs ); + bs_rbsp_trailing(&h->out.bs); + } + else bs_rbsp_trailing(&h->out.bs); x264_nal_end( h ); + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + } - /* generate picture parameters */ - x264_nal_start( h, NAL_PPS, NAL_PRIORITY_HIGHEST ); - x264_pps_write( &h->out.bs, h->pps ); + // NEW CALC + if( !h->sh.b_field_pic ) { + int cpbremovaldelayoffset = 0; + if( !h->param.b_interlaced ) { + if( h->sps->vui.i_pulldown_type == 32 ) + pic_struct = tbt_pattern[(h->fenc->i_frame) & 3]; + else if( h->sps->vui.i_pulldown_type == 64 ) + pic_struct = (h->fenc->i_frame & 1) ? 7 : 8; + } + else { + // tff = 3, bff = 4 + pic_struct = h->param.b_tff ? 3 : 4; + } + + dpb_output_delay = ((double)h->fenc->i_poc * ((h->sps->vui.i_pulldown_type >0 ) ? + (h->sps->vui.i_pulldown_type==64 ? 2.50 : 1.25) : 1.00 )); + dpb_output_delay += ((double)h->sps->vui.i_num_reorder_frames * (h->sps->vui.i_pulldown_type > 0 ) ? + (h->sps->vui.i_pulldown_type==64 ? 2.50 : 2.50) : 2.00 ); + dpb_output_delay -= h->i_cpb_delay; + + if( h->sps->vui.i_pulldown_type==64 ) { + if( h->sh.i_type == SLICE_TYPE_P ) { + if( dpb_output_delay >1 && dpb_output_delay < 4 ) dpb_output_delay = 2; + if( dpb_output_delay >3 && dpb_output_delay < 10) dpb_output_delay = 6; + if( dpb_output_delay >9 && dpb_output_delay < 16) dpb_output_delay = 12; + if( dpb_output_delay >15 &&dpb_output_delay < 20) dpb_output_delay = 18; + if( dpb_output_delay >19 &&dpb_output_delay < 25) dpb_output_delay = 24; + + //dpb_adjustment[] = { 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, //9 + // 12, 12, 12, 12, 12, 18, 18, 18, 18, 18, //19 + // 24, 24, 24, 24, 24, + + } + } + + dpb_output_delay = (dpb_output_delay > 1) ? dpb_output_delay : 0; + if( i_nal_type == NAL_SLICE_IDR || (h->sh.i_type == SLICE_TYPE_P && dpb_output_delay < 2) ) + dpb_output_delay = 2; + + cpb_removal_delay = h->i_cpb_delay; + /*fprintf( stderr, "\n i_frame %d prevpicstruct %d thispicstr %d slice_type_b? %s cpb %d \n", h->fenc->i_frame, h->i_pic_struct_prev, pic_struct, + h->sh.i_type == SLICE_TYPE_B ? "yes" : "no", cpb_removal_delay );*/ + if( h->sh.i_type == SLICE_TYPE_B ) { + if( h->sps->vui.i_pulldown_type == 32 && h->i_pic_struct_prev > 4 ) { + + cpbremovaldelayoffset = 1 ; + } + else if( h->sps->vui.i_pulldown_type == 64 ) + cpbremovaldelayoffset = h->i_pic_struct_prev == 8 ? 4 : 2; + } + else { + h->i_pic_struct_prev = pic_struct; + } // else i_type != SLICE_TYPE_B + + cpb_removal_delay -= cpbremovaldelayoffset; + + x264_sei_picture_timing_write( &h->out.bs, h->sps, cpb_removal_delay, dpb_output_delay, pic_struct); + bs_rbsp_trailing(&h->out.bs); + + + cpb_removal_delay = h->i_cpb_delay; + if( i_nal_type == NAL_SLICE_IDR ) + cpb_removal_delay = 0; + //h->i_cpb_delay += h->sh.b_field_pic ? 1 : 2; + cpb_removal_delay += h->sh.b_field_pic ? 1 : 2; + + if( h->sps->vui.i_pulldown_type == 32 ) + { + cpb_removal_delay += ((h->fenc->i_frame)+1)&1; + } + + else if( h->sps->vui.i_pulldown_type == 64 ) + { + //h->i_cpb_delay += (((h->fenc->i_frame)+1)&1)*4; + cpb_removal_delay += (((h->fenc->i_frame)+1)&1) ? 4 : 2; + } + + } + //bs_rbsp_trailing(&h->out.bs); x264_nal_end( h ); } @@ -1530,6 +1665,7 @@ do_encode: && h->param.i_scenecut_threshold >= 0 && !h->param.b_pre_scenecut ) { + const int *mbs = h->stat.frame.i_mb_count; int i_mb_i = mbs[I_16x16] + mbs[I_8x8] + mbs[I_4x4]; int i_mb_p = mbs[P_L0] + mbs[P_8x8]; @@ -1623,7 +1759,7 @@ do_encode: goto do_encode; } } - + h->i_cpb_delay = cpb_removal_delay; x264_encoder_frame_end( thread_oldest, thread_current, pp_nal, pi_nal, pic_out ); return 0; } diff --git a/encoder/set.c b/encoder/set.c index f47954d..e4f6192 100644 --- a/encoder/set.c +++ b/encoder/set.c @@ -209,6 +209,54 @@ void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param ) sps->vui.i_log2_max_mv_length_horizontal = sps->vui.i_log2_max_mv_length_vertical = (int)(log(param->analyse.i_mv_range*4-1)/log(2)) + 1; } + + sps->vui.b_nal_hrd_parameters_present = param->b_nal_hrd; + if( sps->vui.b_nal_hrd_parameters_present ) + { + + int cpbBrVclFactor = 1000; + int cpbBrNalFactor = 1000; + + + sps->vui.nal_hrd_parameters.i_bit_rate = param->rc.i_vbv_max_bitrate * cpbBrNalFactor; + sps->vui.nal_hrd_parameters.i_cpb_size = param->rc.i_vbv_buffer_size * cpbBrNalFactor; + + sps->vui.nal_hrd_parameters.i_initial_cpb_removal_delay_length = 0; + while( (1 << ++sps->vui.nal_hrd_parameters.i_initial_cpb_removal_delay_length) < + (param->rc.i_vbv_buffer_size * 90000.0 / param->rc.i_vbv_max_bitrate) ); + /*FIX ME*/sps->vui.nal_hrd_parameters.i_initial_cpb_removal_delay_length = 32; + + sps->vui.nal_hrd_parameters.i_cpb_removal_delay_length = 0; + while( (1 << ++sps->vui.nal_hrd_parameters.i_cpb_removal_delay_length) < + (param->i_keyint_max * 8) ); //amped up to *3 for higher cpb values + /*FIX ME*/ //if( sps->vui.nal_hrd_parameters.i_cpb_removal_delay_length > 22 ) + sps->vui.nal_hrd_parameters.i_cpb_removal_delay_length = 22; + + + sps->vui.nal_hrd_parameters.i_dpb_output_delay_length = 0; + while( (1 << ++sps->vui.nal_hrd_parameters.i_dpb_output_delay_length) < + ((sps->vui.i_num_reorder_frames + sps->i_num_ref_frames) * 8) ); //amped up to *3 for higher dpb values + /*FIX ME*///if( sps->vui.nal_hrd_parameters.i_dpb_output_delay_length > 22 ) + sps->vui.nal_hrd_parameters.i_dpb_output_delay_length = 22; +} + + sps->vui.b_pic_struct_present_flag = 0; + sps->vui.i_pulldown_type = param->i_pulldown; + if( !param->b_interlaced ) { + if( sps->vui.i_pulldown_type > 0 ) { + if( sps->vui.b_nal_hrd_parameters_present ) { // pulldown and hrd go together + sps->vui.b_pic_struct_present_flag = 1; + sps->vui.i_num_units_in_tick = 1001; + if( sps->vui.i_pulldown_type == 64 ) sps->vui.i_time_scale = 60000*2; + else sps->vui.i_time_scale = 30000*2; + } + } + } + else { + if( sps->vui.b_nal_hrd_parameters_present ) { + sps->vui.b_pic_struct_present_flag = 1; + } + } } @@ -346,9 +394,45 @@ void x264_sps_write( bs_t *s, x264_sps_t *sps ) bs_write1( s, sps->vui.b_fixed_frame_rate ); } - bs_write1( s, 0 ); /* nal_hrd_parameters_present_flag */ + bs_write1( s, sps->vui.b_nal_hrd_parameters_present ); + if( sps->vui.b_nal_hrd_parameters_present ) + { + int bit_rate_scale = 0, cpb_size_scale = 0; + unsigned int bit_rate_tmp, cpb_size_tmp; + + bs_write_ue( s, 0 ); /* cpb_cnt_minus1 */ + + bit_rate_tmp = ( sps->vui.nal_hrd_parameters.i_bit_rate + (1 << 5) ) >> 6; + while( ( bit_rate_tmp & 1) == 0 ) + { + bit_rate_tmp >>= 1; + bit_rate_scale++; + if (bit_rate_scale == 15) + break; + } + cpb_size_tmp = ( sps->vui.nal_hrd_parameters.i_cpb_size + (1 << 3) ) >> 4; + while( ( cpb_size_tmp & 1) == 0 ) + { + cpb_size_tmp >>= 1; + cpb_size_scale++; + if (cpb_size_scale == 15) + break; + } + bs_write( s, 4, bit_rate_scale ); + bs_write( s, 4, cpb_size_scale ); + bs_write_ue_big( s, bit_rate_tmp - 1 ); + bs_write_ue_big( s, cpb_size_tmp - 1 ); + bs_write1( s, 0 ); + bs_write( s, 5, sps->vui.nal_hrd_parameters.i_initial_cpb_removal_delay_length - 1 ); + bs_write( s, 5, sps->vui.nal_hrd_parameters.i_cpb_removal_delay_length - 1 ); + bs_write( s, 5, sps->vui.nal_hrd_parameters.i_dpb_output_delay_length - 1 ); + bs_write( s, 5, 24 ); // time_offset_length + } + bs_write1( s, 0 ); /* vcl_hrd_parameters_present_flag */ - bs_write1( s, 0 ); /* pic_struct_present_flag */ + if( sps->vui.b_nal_hrd_parameters_present ) /* or VCL HRD */ + bs_write1( s, 0); /* low_delay_hrd_flag */ + bs_write1( s, sps->vui.b_pic_struct_present_flag ); /* pic_struct_present_flag */ bs_write1( s, sps->vui.b_bitstream_restriction ); if( sps->vui.b_bitstream_restriction ) { @@ -499,12 +583,80 @@ void x264_sei_version_write( x264_t *h, bs_t *s ) for( i = 0; i < length-16; i++ ) bs_write( s, 8, version[i] ); - bs_rbsp_trailing( s ); + bs_align_10( s ); // does nothing here.. but dangit it belongs x264_free( opts ); x264_free( version ); } +void x264_sei_buffering_period_write( x264_param_t *param, bs_t *s, x264_sps_t *sps ) +{ + int payload_size; + + bs_write( s, 8, 0x0 ); // payload_type = buffering_period + + payload_size = bs_size_ue( sps->i_id ); + if( sps->vui.b_nal_hrd_parameters_present ) + payload_size += sps->vui.nal_hrd_parameters.i_initial_cpb_removal_delay_length * 2; + + bs_write( s, 8, (payload_size + 7) / 8); + + bs_write_ue( s, sps->i_id ); + + if ( sps->vui.b_nal_hrd_parameters_present ) + { + /* NOTE: This should be a loop for each CPB, but we currently only support one */ + + /* FIXME: I have no idea how you're actually supposed to calculate + * initial_cpb_remobal_delay */ + bs_write( s, sps->vui.nal_hrd_parameters.i_initial_cpb_removal_delay_length, + param->rc.f_vbv_buffer_init * param->rc.i_vbv_buffer_size * 90000 / param->rc.i_vbv_max_bitrate); + bs_write( s, sps->vui.nal_hrd_parameters.i_initial_cpb_removal_delay_length, 0); + } + + /* VCL HRD parameters should go here */ + //bs_rbsp_trailing( s ); + bs_align_10( s ); +} + +void x264_sei_picture_timing_write( bs_t *s, x264_sps_t *sps, int cpb_removal_delay, int dpb_output_delay, int pic_struct ) +{ + int payload_size; + + static const int num_clockts[] = { 1, 1, 1, 2, 2, 3, 3, 2, 3 }; + bs_write( s, 8, 0x1 ); // payload_type = pic_timing + + payload_size = 0; + if( sps->vui.b_nal_hrd_parameters_present ) { + payload_size += sps->vui.nal_hrd_parameters.i_cpb_removal_delay_length + + sps->vui.nal_hrd_parameters.i_dpb_output_delay_length; + if( sps->vui.b_pic_struct_present_flag ) { + payload_size += 4; + payload_size += num_clockts[pic_struct]; // pad #num_clockts bytes for 0 (no time code) + } + } + + bs_write( s, 8, (payload_size + 7) / 8); + + if( sps->vui.b_nal_hrd_parameters_present ) + { + /* NOTE: This should be a loop for each CPB, but we currently only support one */ + + bs_write( s, sps->vui.nal_hrd_parameters.i_cpb_removal_delay_length, + cpb_removal_delay); + bs_write( s, sps->vui.nal_hrd_parameters.i_dpb_output_delay_length, + dpb_output_delay); + if( sps->vui.b_pic_struct_present_flag ) { + bs_write( s, 4, pic_struct ); + bs_write( s, num_clockts[ pic_struct ], 0 ); + } + } + + /* VCL HRD parameters should go here */ + //bs_rbsp_trailing( s ); + bs_align_10( s ); +} + const x264_level_t x264_levels[] = { { 10, 1485, 99, 152064, 64, 175, 64, 64, 0, 0, 0, 1 }, diff --git a/encoder/set.h b/encoder/set.h index b4fa6b1..ddc530b 100644 --- a/encoder/set.h +++ b/encoder/set.h @@ -29,6 +29,8 @@ void x264_sps_write( bs_t *s, x264_sps_t *sps ); void x264_pps_init( x264_pps_t *pps, int i_id, x264_param_t *param, x264_sps_t *sps ); void x264_pps_write( bs_t *s, x264_pps_t *pps ); void x264_sei_version_write( x264_t *h, bs_t *s ); +void x264_sei_buffering_period_write( x264_param_t *param, bs_t *s, x264_sps_t *sps ); +void x264_sei_picture_timing_write( bs_t *s, x264_sps_t *sps, int cpb_removal_delay, int dpb_output_delay, int pic_struct ); int x264_validate_levels( x264_t *h, int verbose ); #endif diff --git a/x264.c b/x264.c index 5741d00..8753f0b 100644 --- a/x264.c +++ b/x264.c @@ -171,7 +171,9 @@ static void Help( x264_param_t *defaults, int b_longhelp ) H1( " --no-deblock Disable loop filter\n" ); H0( " -f, --deblock Loop filter AlphaC0 and Beta parameters [%d:%d]\n", defaults->i_deblocking_filter_alphac0, defaults->i_deblocking_filter_beta ); - H0( " --interlaced Enable pure-interlaced mode\n" ); + H0( " --interlaced Enable pure-interlaced mode (tff)\n" ); + H0( " --tff Alias for --interlaced\n" ); + H0( " --bff Enable pure-interlaced mode (bff)\n" ); H0( "\n" ); H0( "Ratecontrol:\n" ); H0( "\n" ); @@ -322,6 +324,10 @@ static void Help( x264_param_t *defaults, int b_longhelp ) H1( " --dump-yuv Save reconstructed frames\n" ); H1( " --sps-id Set SPS and PPS id numbers [%d]\n", defaults->i_sps_id ); H1( " --aud Use access unit delimiters\n" ); + H1( " --nal-hrd Use NAL HRD parameters\n" ); + H1( " --pulldown Use 3:2 pulldown\n" + " - 32: TBT,BT,BTB,BT pattern\n" + " - 64: triple,double *recommended for 720p\n" ); H0( "\n" ); } @@ -387,6 +393,8 @@ static int Parse( int argc, char **argv, { "filter", required_argument, NULL, 0 }, { "deblock", required_argument, NULL, 'f' }, { "interlaced", no_argument, NULL, 0 }, + { "tff", no_argument, NULL, 0 }, + { "bff", no_argument, NULL, 0 }, { "no-cabac",no_argument, NULL, 0 }, { "qp", required_argument, NULL, 'q' }, { "qpmin", required_argument, NULL, 0 }, @@ -451,6 +459,9 @@ static int Parse( int argc, char **argv, { "dump-yuv",required_argument, NULL, 0 }, { "sps-id", required_argument, NULL, 0 }, { "aud", no_argument, NULL, 0 }, + { "nal-hrd", no_argument, NULL, 0 }, + { "pulldown", required_argument,NULL, 0 }, + { "pd", required_argument, NULL, 0 }, { "nr", required_argument, NULL, 0 }, { "cqm", required_argument, NULL, 0 }, { "cqmfile", required_argument, NULL, 0 }, diff --git a/x264.h b/x264.h index 3b678dc..22ce082 100644 --- a/x264.h +++ b/x264.h @@ -197,6 +197,7 @@ typedef struct x264_param_t int i_cabac_init_idc; int b_interlaced; + int b_tff; int i_cqm_preset; char *psz_cqm_file; /* JM format */ @@ -289,6 +290,8 @@ typedef struct x264_param_t int b_aud; /* generate access unit delimiters */ int b_repeat_headers; /* put SPS/PPS before each keyframe */ int i_sps_id; /* SPS and PPS id number */ + int b_nal_hrd; /* Add NAL HRD parameters to bitstream */ + int i_pulldown; /* 3:2 pulldown */ } x264_param_t; typedef struct {