diff --git a/common/common.c b/common/common.c index 8a8f660..139e708 100644 --- a/common/common.c +++ b/common/common.c @@ -356,7 +356,20 @@ 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->i_field_order = 0; + } + OPT("tff") + { p->b_interlaced = atobool(value); + p->i_field_order = 1; + } + OPT("bff") + { + p->b_interlaced = atobool(value); + p->i_field_order = 2; + } OPT("cqm") { if( strstr( value, "flat" ) ) diff --git a/common/common.h b/common/common.h index 04f5243..ad6d074 100644 --- a/common/common.h +++ b/common/common.h @@ -274,6 +274,8 @@ struct x264_t int i_nal_type; /* threads only */ int i_nal_ref_idc; /* threads only */ + int i_pic_struct; + /* We use only one SPS and one PPS */ x264_sps_t sps_array[1]; x264_sps_t *sps; diff --git a/common/set.h b/common/set.h index e6173b0..477fc45 100644 --- a/common/set.h +++ b/common/set.h @@ -115,6 +115,8 @@ typedef struct int i_time_scale; int b_fixed_frame_rate; + int b_pic_struct_present_flag; + int b_bitstream_restriction; int b_motion_vectors_over_pic_boundaries; int i_max_bytes_per_pic_denom; diff --git a/encoder/encoder.c b/encoder/encoder.c index 533e8a8..a873bb9 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -806,6 +806,25 @@ 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 ); + + if( h->sps->vui.b_pic_struct_present_flag ) + { + switch( h->param.i_field_order ) + { + case 1: + h->i_pic_struct = 3; + break; + case 2: + h->i_pic_struct = 4; + break; + default: + h->i_pic_struct = 0; + break; + } + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + x264_sei_pic_timing_write( h, &h->out.bs ); + x264_nal_end( h ); + } } /* now set output*/ *pi_nal = h->out.i_nal; @@ -1454,6 +1473,25 @@ do_encode: x264_nal_start( h, NAL_PPS, NAL_PRIORITY_HIGHEST ); x264_pps_write( &h->out.bs, h->pps ); x264_nal_end( h ); + + if( h->sps->vui.b_pic_struct_present_flag ) + { + switch( h->param.i_field_order ) + { + case 1: + h->i_pic_struct = 3; + break; + case 2: + h->i_pic_struct = 4; + break; + default: + h->i_pic_struct = 0; + break; + } + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + x264_sei_pic_timing_write( h, &h->out.bs ); + x264_nal_end( h ); + } } /* Write frame */ diff --git a/encoder/set.c b/encoder/set.c index 6cf8773..cec31e2 100644 --- a/encoder/set.c +++ b/encoder/set.c @@ -198,6 +198,8 @@ void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param ) sps->vui.i_max_dec_frame_buffering = sps->i_num_ref_frames = X264_MIN(16, X264_MAX(param->i_frame_reference, 1 + sps->vui.i_num_reorder_frames)); + sps->vui.b_pic_struct_present_flag = sps->b_vui && param->i_field_order; + sps->vui.b_bitstream_restriction = 1; if( sps->vui.b_bitstream_restriction ) { @@ -346,7 +348,7 @@ void x264_sps_write( bs_t *s, x264_sps_t *sps ) bs_write1( s, 0 ); /* nal_hrd_parameters_present_flag */ bs_write1( s, 0 ); /* vcl_hrd_parameters_present_flag */ - bs_write1( s, 0 ); /* pic_struct_present_flag */ + bs_write1( s, sps->vui.b_pic_struct_present_flag ); bs_write1( s, sps->vui.b_bitstream_restriction ); if( sps->vui.b_bitstream_restriction ) { @@ -503,6 +505,31 @@ void x264_sei_version_write( x264_t *h, bs_t *s ) x264_free( version ); } +void x264_sei_pic_timing_write( x264_t *h, bs_t *s ) +{ + static const int NumClockTS[] = { 1, 1, 1, 2, 2, 3, 3, 2, 3 }; + int payload_size_bits = 0; + + //(CpbDpbDelaysPresentFlag == 0), because (nal_hrd_parameters_present_flag == 0) && (vcl_hrd_parameters_present_flag == 0) + + if( h->sps->vui.b_pic_struct_present_flag ) + { + assert( h->i_pic_struct >= 0 && h->i_pic_struct <= 8 ); + payload_size_bits += 4 + NumClockTS[h->i_pic_struct]; + } + + bs_write( s, 8, 0x1 ); // payload_type = pic_timing + bs_write( s, 8, (payload_size_bits + 7) / 8 ); + + if( h->sps->vui.b_pic_struct_present_flag ) + { + bs_write( s, 4, h->i_pic_struct ); + bs_write( s, NumClockTS[h->i_pic_struct], 0 ); + } + + bs_rbsp_trailing( 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 6672b44..eac3255 100644 --- a/encoder/set.h +++ b/encoder/set.h @@ -29,6 +29,7 @@ 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_pic_timing_write( x264_t *h, bs_t *s ); void x264_validate_levels( x264_t *h ); #endif diff --git a/x264.c b/x264.c index d78461f..36f1060 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 interlaced mode (no field order signaling)\n" ); + H0( " --tff Enable interlaced mode with top field first\n" ); + H0( " --bff Enable interlaced mode with bottom field first\n" ); H0( "\n" ); H0( "Ratecontrol:\n" ); H0( "\n" ); @@ -387,6 +389,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 }, diff --git a/x264.h b/x264.h index 0e257a1..2e66242 100644 --- a/x264.h +++ b/x264.h @@ -196,6 +196,7 @@ typedef struct x264_param_t int i_cabac_init_idc; int b_interlaced; + int i_field_order; /* 0=undef, 1=tff, 2=bff */ int i_cqm_preset; char *psz_cqm_file; /* JM format */