Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/common/common.c b/common/common.c
- index 9eed5c3..7b99359 100644
- --- a/common/common.c
- +++ b/common/common.c
- @@ -60,6 +60,9 @@ void x264_param_default( x264_param_t *param )
- param->vui.i_transfer = 2; /* undef */
- param->vui.i_colmatrix = 2; /* undef */
- param->vui.i_chroma_loc= 0; /* left center */
- +
- + param->b_nal_hrd = 0;
- +
- param->i_fps_num = 25;
- param->i_fps_den = 1;
- param->i_level_idc = -1;
- @@ -157,6 +160,13 @@ void x264_param_default( x264_param_t *param )
- param->b_annexb = 1;
- param->b_aud = 0;
- param->b_vfr_input = 1;
- +
- + param->b_nal_hrd = 0;
- + param->b_cbr_hrd = 0;
- + param->b_tff = 1;
- + param->b_pic_struct = 0;
- + param->b_pulldown = 0;
- + param->i_pulldown_delay = 0;
- }
- static int parse_enum( const char *arg, const char * const *names, int *dst )
- @@ -402,6 +412,13 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value )
- p->i_cabac_init_idc = atoi(value);
- OPT("interlaced")
- p->b_interlaced = atobool(value);
- + OPT("tff")
- + p->b_interlaced = atobool(value);
- + OPT("bff")
- + {
- + p->b_interlaced = atobool(value);
- + p->b_tff = !p->b_interlaced;
- + }
- OPT("constrained-intra")
- p->b_constrained_intra = atobool(value);
- OPT("cqm")
- @@ -620,6 +637,13 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value )
- p->b_annexb = atobool(value);
- OPT("force-cfr")
- p->b_vfr_input = !atobool(value);
- + OPT("nal-hrd")
- + {
- + p->b_cbr_hrd = !strcasecmp( value, "cbr" );
- + p->b_nal_hrd = p->b_cbr_hrd || !strcasecmp( value, "vbr" );
- + }
- + OPT("pic-struct")
- + p->b_pic_struct = atobool(value);
- else
- return X264_PARAM_BAD_NAME;
- #undef OPT
- @@ -695,6 +719,7 @@ int x264_picture_alloc( x264_picture_t *pic, int i_csp, int i_width, int i_heigh
- pic->img.i_stride[1] = i_width / 2;
- pic->img.i_stride[2] = i_width / 2;
- pic->param = NULL;
- + pic->i_pic_struct = PIC_STRUCT_AUTO;
- return 0;
- }
- @@ -905,7 +930,8 @@ char *x264_param2string( x264_param_t *p, int b_res )
- s += sprintf( s, " slice_max_mbs=%d", p->i_slice_max_mbs );
- s += sprintf( s, " nr=%d", p->analyse.i_noise_reduction );
- s += sprintf( s, " decimate=%d", p->analyse.b_dct_decimate );
- - s += sprintf( s, " mbaff=%d", p->b_interlaced );
- + s += sprintf( s, " interlaced=%s", p->b_interlaced ? p->b_tff ? "tff" : "bff" : "0" );
- +
- s += sprintf( s, " constrained_intra=%d", p->b_constrained_intra );
- s += sprintf( s, " bframes=%d", p->i_bframe );
- @@ -958,6 +984,9 @@ char *x264_param2string( x264_param_t *p, int b_res )
- s += sprintf( s, " zones" );
- }
- + s += sprintf( s, " pulldown=%d", p->b_pulldown );
- + if( p->rc.i_vbv_buffer_size )
- + s += sprintf( s, " nal_hrd=%d", p->b_nal_hrd );
- return buf;
- }
- diff --git a/common/common.h b/common/common.h
- index 02d1748..dbd3cc4 100644
- --- a/common/common.h
- +++ b/common/common.h
- @@ -67,6 +67,9 @@ do {\
- #define X264_WEIGHTP_FAKE (-1)
- +#define NALU_OVERHEAD 5 // startcode + NAL type costs 5 bytes per frame
- +#define FILLER_SEI_OVERHEAD (NALU_OVERHEAD+3) // SEI payload type byte + one SEI payload size byte + last byte
- +
- /****************************************************************************
- * Includes
- ****************************************************************************/
- @@ -216,6 +219,17 @@ enum slice_type_e
- static const char slice_type_to_char[] = { 'P', 'B', 'I', 'S', 'S' };
- +enum sei_payload_type_e
- +{
- + SEI_BUFFERING_PERIOD = 0,
- + SEI_PIC_TIMING = 1,
- + SEI_PAN_SCAN_RECT = 2,
- + SEI_FILLER = 3,
- + SEI_USER_DATA_REGISTERED_ITU_T_T35 = 4,
- + SEI_USER_DATA_UNREGISTERED = 5,
- + SEI_RECOVERY_POINT = 6,
- +};
- +
- typedef struct
- {
- x264_sps_t *sps;
- @@ -369,6 +383,12 @@ struct x264_t
- int i_poc_lsb; /* decoding only */
- int i_poc; /* decoding only */
- + int i_disp_fields; /* Number of displayed fields (both coded and implied via pic_struct) */
- + int i_coded_fields; /* Number of coded fields (both coded and implied via pic_struct) */
- +
- + int i_cpb_delay; /* Equal to number of fields preceding this field
- + * since last buffering_period SEI */
- +
- int i_thread_num; /* threads only */
- int i_nal_type; /* threads only */
- int i_nal_ref_idc; /* threads only */
- @@ -450,7 +470,10 @@ struct x264_t
- x264_frame_t *fref1[16+3]; /* ref list 1 */
- int b_ref_reorder[2];
- -
- + /* hrd */
- + int initial_cpb_removal_delay;
- + int current_cpb_delay;
- + int dpb_output_delay;
- /* Current MB DCT coeffs */
- struct
- @@ -722,7 +745,6 @@ struct x264_t
- int i_direct_frames[2];
- /* num p-frames weighted */
- int i_wpred[3];
- -
- } stat;
- void *scratch_buffer; /* for any temporary storage that doesn't want repeated malloc */
- diff --git a/common/frame.c b/common/frame.c
- index 08ef87f..c308df0 100644
- --- a/common/frame.c
- +++ b/common/frame.c
- @@ -73,6 +73,10 @@ x264_frame_t *x264_frame_new( x264_t *h, int b_fdec )
- frame->i_frame_num = -1;
- frame->i_lines_completed = -1;
- frame->b_fdec = b_fdec;
- +
- + frame->i_pic_struct = PIC_STRUCT_AUTO;
- + frame->i_field_cnt = -1;
- +
- frame->orig = frame;
- /* all 4 luma planes allocated together, since the cacheline split code
- @@ -225,6 +229,7 @@ int x264_frame_copy_picture( x264_t *h, x264_frame_t *dst, x264_picture_t *src )
- dst->i_qpplus1 = src->i_qpplus1;
- dst->i_pts = dst->i_dts = src->i_pts;
- dst->param = src->param;
- + dst->i_pic_struct = src->i_pic_struct;
- for( i=0; i<3; i++ )
- {
- diff --git a/common/frame.h b/common/frame.h
- index 786869e..ee18d82 100644
- --- a/common/frame.h
- +++ b/common/frame.h
- @@ -40,8 +40,11 @@ typedef struct x264_frame
- int i_frame; /* Presentation frame number */
- int i_coded; /* Coded frame number */
- + int i_field_cnt; /* Presentation field count */
- int i_frame_num; /* 7.4.3 frame_num */
- int b_kept_as_ref;
- + int i_pic_struct;
- + int b_top_field_first;
- int b_keyframe;
- uint8_t b_fdec;
- uint8_t b_last_minigop_bframe; /* this frame is the last b in a sequence of bframes */
- @@ -107,6 +110,9 @@ typedef struct x264_frame
- uint32_t i_pixel_sum;
- uint64_t i_pixel_ssd;
- + /* hrd */
- + x264_hrd_t hrd_timing;
- +
- /* vbv */
- uint8_t i_planned_type[X264_LOOKAHEAD_MAX+1];
- int i_planned_satd[X264_LOOKAHEAD_MAX+1];
- diff --git a/common/osdep.h b/common/osdep.h
- index abae9ac..365ec34 100644
- --- a/common/osdep.h
- +++ b/common/osdep.h
- @@ -212,10 +212,13 @@ static ALWAYS_INLINE uint16_t endian_fix16( uint16_t x )
- #if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 3)
- #define x264_clz(x) __builtin_clz(x)
- +#define x264_ctz(x) __builtin_ctz(x)
- #else
- static int ALWAYS_INLINE x264_clz( uint32_t x )
- {
- static uint8_t lut[16] = {4,3,2,2,1,1,1,1,0,0,0,0,0,0,0,0};
- + if( !x )
- + return 0; // just to be consistent with __builtin_clz
- int y, z = (((x >> 16) - 1) >> 27) & 16;
- x >>= z^16;
- z += y = ((x - 0x100) >> 28) & 8;
- @@ -224,6 +227,20 @@ static int ALWAYS_INLINE x264_clz( uint32_t x )
- x >>= y^4;
- return z + lut[x];
- }
- +
- +static int ALWAYS_INLINE x264_ctz( uint32_t x )
- +{
- + static uint8_t lut[16] = {4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0};
- + if( !x )
- + return 0; // just to be consistent with __builtin_ctz
- + int y, z = (((x & 0xffff) - 1) >> 27) & 16;
- + x >>= z;
- + z += y = (((x & 0xff) - 1) >> 28) & 8;
- + x >>= y;
- + z += y = (((x & 0xf) - 1) >> 29) & 4;
- + x >>= y;
- + return z + lut[x&0xf];
- +}
- #endif
- #ifdef USE_REAL_PTHREAD
- diff --git a/common/set.h b/common/set.h
- index e1b9cd9..f55e6e3 100644
- --- a/common/set.h
- +++ b/common/set.h
- @@ -116,6 +116,27 @@ typedef struct
- int i_time_scale;
- int b_fixed_frame_rate;
- + int b_nal_hrd_parameters_present;
- + int b_vcl_hrd_parameters_present;
- +
- + struct
- + {
- + int i_cpb_cnt;
- + int i_bit_rate_scale;
- + int i_cpb_size_scale;
- + int i_bit_rate_value;
- + int i_cpb_size_value;
- + int i_bit_rate_unscaled;
- + int i_cpb_size_unscaled;
- + int b_cbr_hrd;
- +
- + int i_initial_cpb_removal_delay_length;
- + int i_cpb_removal_delay_length;
- + int i_dpb_output_delay_length;
- + int i_time_offset_length;
- + } hrd;
- +
- + int b_pic_struct_present;
- 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 5c7d6c5..7ac0a63 100644
- --- a/encoder/encoder.c
- +++ b/encoder/encoder.c
- @@ -39,14 +39,14 @@
- //#define DEBUG_MB_TYPE
- -#define NALU_OVERHEAD 5 // startcode + NAL type costs 5 bytes per frame
- -
- #define bs_write_ue bs_write_ue_big
- static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current,
- x264_nal_t **pp_nal, int *pi_nal,
- x264_picture_t *pic_out );
- +static int delta_tfi_divisor[10] = { 0, 2, 1, 1, 2, 2, 3, 3, 4, 6 }; // Number of coded/displayed fields (indexed by i_pic_struct)
- +
- /****************************************************************************
- *
- ******************************* x264 libs **********************************
- @@ -504,6 +504,35 @@ static int x264_validate_parameters( x264_t *h )
- h->param.rc.i_aq_mode = 0;
- h->param.rc.b_mb_tree = 0;
- }
- +
- + if( h->param.rc.i_rc_method == X264_RC_CRF && h->param.rc.b_stat_read )
- + {
- + x264_log(h, X264_LOG_ERROR, "constant rate-factor is incompatible with 2pass.\n");
- + return -1;
- + }
- + if( h->param.rc.i_vbv_buffer_size )
- + {
- + if( h->param.rc.i_rc_method == X264_RC_CQP )
- + {
- + x264_log(h, X264_LOG_WARNING, "VBV is incompatible with constant QP, ignored.\n");
- + h->param.rc.i_vbv_max_bitrate = 0;
- + h->param.rc.i_vbv_buffer_size = 0;
- + }
- + else if( h->param.rc.i_vbv_max_bitrate == 0 )
- + {
- + if( h->param.rc.i_rc_method == X264_RC_ABR )
- + {
- + x264_log( h, X264_LOG_INFO, "VBV maxrate unspecified, assuming CBR\n" );
- + h->param.rc.i_vbv_max_bitrate = h->param.rc.i_bitrate;
- + }
- + else
- + {
- + x264_log( h, X264_LOG_INFO, "VBV bufsize set but maxrate unspecified, ignored\n" );
- + h->param.rc.i_vbv_buffer_size = 0;
- + }
- + }
- + }
- +
- h->param.rc.i_qp_max = x264_clip3( h->param.rc.i_qp_max, 0, 51 );
- h->param.rc.i_qp_min = x264_clip3( h->param.rc.i_qp_min, 0, h->param.rc.i_qp_max );
- @@ -744,6 +773,34 @@ static int x264_validate_parameters( x264_t *h )
- h->param.analyse.b_ssim = 0;
- }
- + if( h->param.b_pulldown && !h->param.i_pulldown_delay )
- + {
- + x264_log( h, X264_LOG_WARNING, "Pulldown requires delay\n" );
- + h->param.b_pulldown = 0;
- + }
- +
- + if( h->param.b_pulldown && h->param.b_vfr_input )
- + {
- + x264_log( h, X264_LOG_WARNING, "Pulldown not compatible with variable framerate\n" );
- + h->param.b_pulldown = 0;
- + }
- +
- + if( h->param.b_pulldown )
- + h->param.b_pic_struct = 1;
- +
- + if( h->param.b_nal_hrd && !h->param.rc.i_vbv_buffer_size )
- + {
- + x264_log( h, X264_LOG_WARNING, "NAL HRD parameters require VBV parameters \n" );
- + h->param.b_nal_hrd = 0;
- + }
- +
- + if( h->param.b_cbr_hrd && ( h->param.rc.i_bitrate != h->param.rc.i_vbv_max_bitrate ||
- + ( h->param.rc.i_vbv_max_bitrate && !h->param.rc.i_bitrate ) ) )
- + {
- + x264_log( h, X264_LOG_WARNING, "CBR HRD requires constant bitrate \n" );
- + h->param.b_cbr_hrd = 0;
- + }
- +
- /* ensure the booleans are 0 or 1 so they can be used in math */
- #define BOOLIFY(x) h->param.x = !!h->param.x
- BOOLIFY( b_cabac );
- @@ -769,6 +826,8 @@ static int x264_validate_parameters( x264_t *h )
- BOOLIFY( rc.b_stat_write );
- BOOLIFY( rc.b_stat_read );
- BOOLIFY( rc.b_mb_tree );
- + BOOLIFY( b_nal_hrd );
- + BOOLIFY( b_cbr_hrd );
- #undef BOOLIFY
- return 0;
- @@ -862,6 +921,7 @@ x264_t *x264_encoder_open( x264_param_t *param )
- h->i_frame = -1;
- 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 );
- @@ -917,7 +977,7 @@ x264_t *x264_encoder_open( x264_param_t *param )
- CHECKED_MALLOCZERO( h->frames.blank_unused, h->param.i_threads * 4 * sizeof(x264_frame_t *) );
- h->i_ref0 = 0;
- h->i_ref1 = 0;
- -
- + h->i_coded_fields = h->i_disp_fields = 0;
- x264_rdo_init();
- /* init CPU functions */
- @@ -1024,6 +1084,12 @@ x264_t *x264_encoder_open( x264_param_t *param )
- if( x264_ratecontrol_new( h ) < 0 )
- goto fail;
- + if( h->param.b_nal_hrd )
- + {
- + x264_log( h, X264_LOG_INFO, "HRD bitrate: %ld bits/sec\n", h->sps->vui.hrd.i_bit_rate_unscaled );
- + x264_log( h, X264_LOG_INFO, "CPB size: %lld bits\n", h->sps->vui.hrd.i_cpb_size_unscaled );
- + }
- +
- if( h->param.psz_dump_yuv )
- {
- /* create or truncate the reconstructed video file */
- @@ -1097,6 +1163,17 @@ int x264_encoder_reconfig( x264_t *h, x264_param_t *param )
- COPY( i_slice_max_size );
- COPY( i_slice_max_mbs );
- COPY( i_slice_count );
- +
- + COPY( b_nal_hrd );
- + COPY( b_cbr_hrd );
- + COPY( b_pic_struct );
- +
- + if( h->param.b_pulldown != param->b_pulldown )
- + {
- + COPY( b_pulldown );
- + COPY( i_pulldown_delay );
- + }
- +
- #undef COPY
- mbcmp_init( h );
- @@ -1147,10 +1224,14 @@ static int x264_nal_end( x264_t *h )
- return x264_nal_check_buffer( h );
- }
- -static int x264_encoder_encapsulate_nals( x264_t *h )
- +static int x264_encoder_encapsulate_nals( x264_t *h, int start )
- {
- - int nal_size = 0, i;
- - for( i = 0; i < h->out.i_nal; i++ )
- + int nal_size = 0, previous_nal_size = 0, i;
- +
- + for( i = 0; i < start; i++ )
- + previous_nal_size += h->out.nal[i].i_payload;
- +
- + for( i = start; i < h->out.i_nal; i++ )
- nal_size += h->out.nal[i].i_payload;
- /* Worst-case NAL unit escaping: reallocate the buffer if it's too small. */
- @@ -1159,13 +1240,15 @@ static int x264_encoder_encapsulate_nals( x264_t *h )
- uint8_t *buf = x264_malloc( nal_size * 2 + h->out.i_nal * 4 );
- if( !buf )
- return -1;
- + if( previous_nal_size )
- + memcpy( buf, h->nal_buffer, previous_nal_size );
- x264_free( h->nal_buffer );
- h->nal_buffer = buf;
- }
- - uint8_t *nal_buffer = h->nal_buffer;
- + uint8_t *nal_buffer = h->nal_buffer + previous_nal_size;
- - for( i = 0; i < h->out.i_nal; i++ )
- + for( i = start; i < h->out.i_nal; i++ )
- {
- int size = x264_nal_encode( nal_buffer, h->param.b_annexb, &h->out.nal[i] );
- h->out.nal[i].i_payload = size;
- @@ -1173,7 +1256,7 @@ static int x264_encoder_encapsulate_nals( x264_t *h )
- nal_buffer += size;
- }
- - return nal_buffer - h->nal_buffer;
- + return nal_buffer - (h->nal_buffer + previous_nal_size);
- }
- /****************************************************************************
- @@ -1187,11 +1270,6 @@ int x264_encoder_headers( x264_t *h, x264_nal_t **pp_nal, int *pi_nal )
- bs_init( &h->out.bs, h->out.p_bitstream, h->out.i_bitstream );
- /* Write SEI, SPS and PPS. */
- - x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
- - if( x264_sei_version_write( h, &h->out.bs ) )
- - return -1;
- - if( x264_nal_end( h ) )
- - return -1;
- /* generate sequence parameters */
- x264_nal_start( h, NAL_SPS, NAL_PRIORITY_HIGHEST );
- @@ -1205,7 +1283,14 @@ int x264_encoder_headers( x264_t *h, x264_nal_t **pp_nal, int *pi_nal )
- if( x264_nal_end( h ) )
- return -1;
- - frame_size = x264_encoder_encapsulate_nals( h );
- + /* identify ourselves */
- + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
- + if( x264_sei_version_write( h, &h->out.bs ) )
- + return -1;
- + if( x264_nal_end( h ) )
- + return -1;
- +
- + frame_size = x264_encoder_encapsulate_nals( h, 0 );
- /* now set output*/
- *pi_nal = h->out.i_nal;
- @@ -1629,7 +1714,14 @@ static inline void x264_slice_init( x264_t *h, int i_nal_type, int i_global_qp )
- if( h->sps->i_poc_type == 0 )
- {
- h->sh.i_poc_lsb = h->fdec->i_poc & ( (1 << h->sps->i_log2_max_poc_lsb) - 1 );
- - h->sh.i_delta_poc_bottom = 0;
- + if( h->param.b_interlaced )
- + {
- + h->sh.i_delta_poc_bottom = h->fenc->b_top_field_first ? 1 : -1;
- + if( h->sh.i_delta_poc_bottom == -1 )
- + h->sh.i_poc_lsb = ( h->fdec->i_poc + 1 ) & ( (1 << h->sps->i_log2_max_poc_lsb) - 1 );
- + }
- + else
- + h->sh.i_delta_poc_bottom = 0;
- }
- else if( h->sps->i_poc_type == 1 )
- {
- @@ -2033,6 +2125,7 @@ int x264_encoder_encode( x264_t *h,
- {
- x264_t *thread_current, *thread_prev, *thread_oldest;
- int i_nal_type, i_nal_ref_idc, i_global_qp, i;
- + int overhead = NALU_OVERHEAD;
- if( h->param.i_threads > 1 && !h->param.b_sliced_threads )
- {
- @@ -2080,6 +2173,21 @@ int x264_encoder_encode( x264_t *h,
- if( h->frames.i_bframe_delay && fenc->i_frame == h->frames.i_bframe_delay )
- h->frames.i_bframe_delay_time = fenc->i_pts;
- + if( fenc->i_pic_struct == PIC_STRUCT_AUTO )
- + {
- + if( h->param.b_interlaced )
- + fenc->i_pic_struct = fenc->b_top_field_first ? PIC_STRUCT_TOP_BOTTOM : PIC_STRUCT_BOTTOM_TOP;
- + else
- + fenc->i_pic_struct = PIC_STRUCT_PROGRESSIVE;
- + }
- + else if( ( fenc->i_pic_struct < PIC_STRUCT_AUTO ) || ( fenc->i_pic_struct > PIC_STRUCT_TRIPLE ) )
- + fenc->i_pic_struct = PIC_STRUCT_PROGRESSIVE;
- +
- + // add number of "displayed" fields
- + fenc->i_field_cnt = h->i_disp_fields;
- +
- + h->i_disp_fields += delta_tfi_divisor[fenc->i_pic_struct];
- +
- if( h->frames.b_have_lowres )
- {
- if( h->param.analyse.i_weighted_pred == X264_WEIGHTP_FAKE || h->param.analyse.i_weighted_pred == X264_WEIGHTP_SMART )
- @@ -2228,13 +2336,12 @@ int x264_encoder_encode( x264_t *h,
- bs_rbsp_trailing( &h->out.bs );
- if( x264_nal_end( h ) )
- return -1;
- + overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;
- }
- h->i_nal_type = i_nal_type;
- h->i_nal_ref_idc = i_nal_ref_idc;
- - int overhead = NALU_OVERHEAD;
- -
- if( h->param.b_intra_refresh && h->fenc->i_type == X264_TYPE_P )
- {
- int pocdiff = (h->fdec->i_poc - h->fref0[0]->i_poc)/2;
- @@ -2256,22 +2363,11 @@ int x264_encoder_encode( x264_t *h,
- h->fdec->i_pir_end_col = X264_MIN( h->fdec->f_pir_position+0.5, h->sps->i_mb_width-1 );
- }
- - /* Write SPS and PPS */
- if( h->fenc->b_keyframe )
- {
- + /* Write SPS and PPS */
- if( h->param.b_repeat_headers )
- {
- - if( h->fenc->i_frame == 0 )
- - {
- - /* identify ourself */
- - x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
- - if( x264_sei_version_write( h, &h->out.bs ) )
- - return -1;
- - if( x264_nal_end( h ) )
- - return -1;
- - overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;
- - }
- -
- /* generate sequence parameters */
- x264_nal_start( h, NAL_SPS, NAL_PRIORITY_HIGHEST );
- x264_sps_write( &h->out.bs, h->sps );
- @@ -2287,6 +2383,32 @@ int x264_encoder_encode( x264_t *h,
- overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;
- }
- + /* generate sei buffering period */
- + if( h->sps->vui.b_nal_hrd_parameters_present )
- + {
- + h->initial_cpb_removal_delay = x264_hrd_fullness( h, 8*overhead );
- +
- + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
- + x264_sei_buffering_period_write( h, &h->out.bs, h->initial_cpb_removal_delay );
- + if( x264_nal_end( h ) )
- + return -1;
- + overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;
- + }
- +
- + if( h->param.b_repeat_headers )
- + {
- + if( h->fenc->i_frame == 0 )
- + {
- + /* identify ourself */
- + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
- + if( x264_sei_version_write( h, &h->out.bs ) )
- + return -1;
- + if( x264_nal_end( h ) )
- + return -1;
- + overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;
- + }
- + }
- +
- if( h->fenc->i_type != X264_TYPE_IDR )
- {
- x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
- @@ -2296,6 +2418,40 @@ int x264_encoder_encode( x264_t *h,
- }
- }
- + /* FIXME support VFR */
- + /* generate sei pic timing */
- + if( h->sps->vui.b_pic_struct_present || h->sps->vui.b_nal_hrd_parameters_present )
- + {
- + h->dpb_output_delay = h->fenc->i_field_cnt - h->i_coded_fields;
- +
- + // add a correction term for pulldown
- + h->dpb_output_delay += h->param.i_pulldown_delay;
- +
- + // add a correction term for frame reordering
- + h->dpb_output_delay += h->sps->vui.i_num_reorder_frames*2;
- +
- + // fix possible negative dpb_output_delay because of pulldown changes
- + if( h->dpb_output_delay < 0 )
- + {
- + h->i_cpb_delay += h->dpb_output_delay;
- + h->dpb_output_delay = 0;
- + }
- +
- + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
- + x264_sei_pic_timing_write( h, &h->out.bs, h->i_cpb_delay, h->dpb_output_delay, h->fenc->i_pic_struct );
- + if( x264_nal_end( h ) )
- + return -1;
- + overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;
- + }
- +
- + h->current_cpb_delay = h->i_cpb_delay;
- +
- + if( h->fenc->b_keyframe )
- + h->i_cpb_delay = 0;
- +
- + h->i_cpb_delay += delta_tfi_divisor[h->fenc->i_pic_struct];
- + h->i_coded_fields += delta_tfi_divisor[h->fenc->i_pic_struct];
- +
- /* Init the rate control */
- /* FIXME: Include slice header bit cost. */
- x264_ratecontrol_start( h, h->fenc->i_qpplus1, overhead*8 );
- @@ -2366,13 +2522,7 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current,
- x264_frame_push_unused( thread_current, h->fenc );
- - /* End bitstream, set output */
- - *pi_nal = h->out.i_nal;
- - *pp_nal = h->out.nal;
- -
- - frame_size = x264_encoder_encapsulate_nals( h );
- -
- - h->out.i_nal = 0;
- + frame_size = x264_encoder_encapsulate_nals( h, 0 );
- /* Set output picture properties */
- if( h->sh.i_type == SLICE_TYPE_I )
- @@ -2396,9 +2546,27 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current,
- /* update rc */
- x264_emms();
- - if( x264_ratecontrol_end( h, frame_size * 8 ) < 0 )
- + int filler = 0;
- + if( x264_ratecontrol_end( h, frame_size * 8, &filler ) < 0 )
- return -1;
- + pic_out->hrd_timing = h->fenc->hrd_timing;
- +
- + if( filler )
- + {
- + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
- + x264_sei_filler_write( h, &h->out.bs, filler );
- + if( x264_nal_end( h ) )
- + return -1;
- + frame_size += x264_encoder_encapsulate_nals( h, h->out.i_nal-1 );
- + }
- +
- + /* End bitstream, set output */
- + *pi_nal = h->out.i_nal;
- + *pp_nal = h->out.nal;
- +
- + h->out.i_nal = 0;
- +
- x264_noise_reduction_update( thread_current );
- /* ---------------------- Compute/Print statistics --------------------- */
- diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c
- index 761ff2c..cf04c66 100644
- --- a/encoder/ratecontrol.c
- +++ b/encoder/ratecontrol.c
- @@ -146,13 +146,19 @@ struct x264_ratecontrol_t
- int i_zones;
- x264_zone_t *zones;
- x264_zone_t *prev_zone;
- +
- + /* hrd stuff */
- + int initial_cpb_removal_delay;
- + int current_cpb_delay;
- + double nrt_first_access_unit;
- + double previous_cpb_final_arrival_time;
- };
- static int parse_zones( x264_t *h );
- static int init_pass2(x264_t *);
- static float rate_estimate_qscale( x264_t *h );
- -static void update_vbv( x264_t *h, int bits );
- +static int update_vbv( x264_t *h, int bits, int *filler_sei_size );
- static void update_vbv_plan( x264_t *h, int overhead );
- static double predict_size( predictor_t *p, double q, double var );
- static void update_predictor( predictor_t *p, double q, double var, double bits );
- @@ -421,25 +427,6 @@ int x264_ratecontrol_new( x264_t *h )
- rc->last_non_b_pict_type = -1;
- rc->cbr_decay = 1.0;
- - if( h->param.rc.i_rc_method == X264_RC_CRF && h->param.rc.b_stat_read )
- - {
- - x264_log(h, X264_LOG_ERROR, "constant rate-factor is incompatible with 2pass.\n");
- - return -1;
- - }
- - if( h->param.rc.i_vbv_buffer_size )
- - {
- - if( h->param.rc.i_rc_method == X264_RC_CQP )
- - {
- - x264_log(h, X264_LOG_WARNING, "VBV is incompatible with constant QP, ignored.\n");
- - h->param.rc.i_vbv_max_bitrate = 0;
- - h->param.rc.i_vbv_buffer_size = 0;
- - }
- - else if( h->param.rc.i_vbv_max_bitrate == 0 )
- - {
- - x264_log( h, X264_LOG_DEBUG, "VBV maxrate unspecified, assuming CBR\n" );
- - h->param.rc.i_vbv_max_bitrate = h->param.rc.i_bitrate;
- - }
- - }
- if( h->param.rc.i_vbv_max_bitrate < h->param.rc.i_bitrate &&
- h->param.rc.i_vbv_max_bitrate > 0)
- x264_log(h, X264_LOG_WARNING, "max bitrate less than average bitrate, ignored.\n");
- @@ -454,8 +441,49 @@ int x264_ratecontrol_new( x264_t *h )
- }
- if( h->param.rc.f_vbv_buffer_init > 1. )
- h->param.rc.f_vbv_buffer_init = x264_clip3f( h->param.rc.f_vbv_buffer_init / h->param.rc.i_vbv_buffer_size, 0, 1 );
- - rc->buffer_rate = h->param.rc.i_vbv_max_bitrate * 1000. / rc->fps;
- - rc->buffer_size = h->param.rc.i_vbv_buffer_size * 1000.;
- +
- + int vbv_buffer_size = h->param.rc.i_vbv_buffer_size * 1000;
- + int vbv_max_bitrate = h->param.rc.i_vbv_max_bitrate * 1000;
- +
- + /* Init HRD */
- + if( h->param.b_nal_hrd )
- + {
- + h->sps->vui.hrd.i_cpb_cnt = 1;
- + h->sps->vui.hrd.b_cbr_hrd = h->param.b_cbr_hrd;
- + h->sps->vui.hrd.i_time_offset_length = 0;
- +
- + #define BR_SHIFT 6
- + #define CPB_SHIFT 4
- +
- + int bitrate = 1000*h->param.rc.i_vbv_max_bitrate;
- + int bufsize = 1000*h->param.rc.i_vbv_buffer_size;
- +
- + // normalize HRD size and rate to the value / scale notation
- + h->sps->vui.hrd.i_bit_rate_scale = x264_clip3( x264_ctz( bitrate ) - BR_SHIFT, 0, 15 );
- + h->sps->vui.hrd.i_bit_rate_value = bitrate >> ( h->sps->vui.hrd.i_bit_rate_scale + BR_SHIFT );
- + h->sps->vui.hrd.i_bit_rate_unscaled = h->sps->vui.hrd.i_bit_rate_value << ( h->sps->vui.hrd.i_bit_rate_scale + BR_SHIFT );
- + h->sps->vui.hrd.i_cpb_size_scale = x264_clip3( x264_ctz( bufsize ) - CPB_SHIFT, 0, 15 );
- + h->sps->vui.hrd.i_cpb_size_value = bufsize >> ( h->sps->vui.hrd.i_cpb_size_scale + CPB_SHIFT );
- + h->sps->vui.hrd.i_cpb_size_unscaled = h->sps->vui.hrd.i_cpb_size_value << ( h->sps->vui.hrd.i_cpb_size_scale + CPB_SHIFT );
- +
- + #undef CPB_SHIFT
- + #undef BR_SHIFT
- +
- + // FIXME should we use the maximums from the levels
- + int max_cpb = 2*h->param.i_keyint_max + 1;
- + int max_dpb = 2 + 2*h->sps->vui.i_max_dec_frame_buffering + 1;
- + int max_delay = (int)(90000.0 * (double)h->sps->vui.hrd.i_cpb_size_unscaled / h->sps->vui.hrd.i_bit_rate_unscaled + 0.5);
- +
- + h->sps->vui.hrd.i_initial_cpb_removal_delay_length = 2 + x264_clip3( 32 - x264_clz( max_delay ), 4, 22);
- + h->sps->vui.hrd.i_cpb_removal_delay_length = x264_clip3( 32 - x264_clz( max_cpb ), 4, 24 );
- + h->sps->vui.hrd.i_dpb_output_delay_length = x264_clip3( 32 - x264_clz( max_dpb ), 4, 24 );
- +
- + vbv_buffer_size = X264_MIN( vbv_buffer_size, h->sps->vui.hrd.i_cpb_size_unscaled );
- + vbv_max_bitrate = X264_MIN( vbv_max_bitrate, h->sps->vui.hrd.i_bit_rate_unscaled );
- + }
- +
- + rc->buffer_rate = (double)vbv_max_bitrate / rc->fps;
- + rc->buffer_size = vbv_buffer_size;
- rc->single_frame_vbv = rc->buffer_rate * 1.1 > rc->buffer_size;
- h->param.rc.f_vbv_buffer_init = X264_MAX( h->param.rc.f_vbv_buffer_init, rc->buffer_rate / rc->buffer_size );
- rc->buffer_fill_final = rc->buffer_size * h->param.rc.f_vbv_buffer_init;
- @@ -1306,11 +1334,11 @@ void x264_ratecontrol_set_weights( x264_t *h, x264_frame_t *frm )
- }
- /* After encoding one frame, save stats and update ratecontrol state */
- -int x264_ratecontrol_end( x264_t *h, int bits )
- +int x264_ratecontrol_end( x264_t *h, int bits, int *filler )
- {
- x264_ratecontrol_t *rc = h->rc;
- const int *mbs = h->stat.frame.i_mb_count;
- - int i;
- + int i, filler_sei_size = 0;
- x264_emms();
- @@ -1417,7 +1445,57 @@ int x264_ratecontrol_end( x264_t *h, int bits )
- }
- }
- - update_vbv( h, bits );
- + *filler = update_vbv( h, bits, &filler_sei_size );
- +
- + if( h->sps->vui.b_nal_hrd_parameters_present )
- + {
- + double cpb_nominal_removal_time;
- + rc->current_cpb_delay = h->current_cpb_delay;
- +
- + if( h->fenc->i_frame == 0 )
- + {
- + // access unit initialises the HRD
- + h->fenc->hrd_timing.cpb_initial_arrival_time = 0;
- + rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay;
- + cpb_nominal_removal_time = rc->nrt_first_access_unit = (double)rc->initial_cpb_removal_delay / 90000;
- + }
- + else
- + {
- + cpb_nominal_removal_time = rc->nrt_first_access_unit +
- + (double)rc->current_cpb_delay * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;
- + if( h->fenc->b_keyframe )
- + {
- + rc->nrt_first_access_unit = cpb_nominal_removal_time;
- + rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay;
- + }
- +
- + if( h->sps->vui.hrd.b_cbr_hrd )
- + h->fenc->hrd_timing.cpb_initial_arrival_time = rc->previous_cpb_final_arrival_time;
- + else
- + {
- + // NOTE: Equation C-4 has initial_cpb_removal_delay_offset which is hardcoded to zero in x264.
- + double cpb_earliest_arrival_time = cpb_nominal_removal_time - (double)rc->initial_cpb_removal_delay / 90000;
- + h->fenc->hrd_timing.cpb_initial_arrival_time = X264_MAX( rc->previous_cpb_final_arrival_time, cpb_earliest_arrival_time );
- + }
- + }
- + // Equation C-6
- + h->fenc->hrd_timing.cpb_final_arrival_time = rc->previous_cpb_final_arrival_time =
- + h->fenc->hrd_timing.cpb_initial_arrival_time + (double)(bits + filler_sei_size*8) / h->sps->vui.hrd.i_bit_rate_unscaled;
- +
- + if( cpb_nominal_removal_time >= h->fenc->hrd_timing.cpb_final_arrival_time )
- + h->fenc->hrd_timing.cpb_removal_time = cpb_nominal_removal_time;
- + else
- + {
- + // access unit is so large it cannot be removed at the nominal cpb removal time
- + h->fenc->hrd_timing.cpb_removal_time = cpb_nominal_removal_time +
- + ceil( (h->fenc->hrd_timing.cpb_final_arrival_time - cpb_nominal_removal_time) *
- + (double)h->sps->vui.i_time_scale / h->sps->vui.i_num_units_in_tick );
- + }
- +
- + h->fenc->hrd_timing.dpb_output_time = (double)h->dpb_output_delay * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale +
- + h->fenc->hrd_timing.cpb_removal_time;
- + }
- +
- return 0;
- fail:
- x264_log(h, X264_LOG_ERROR, "ratecontrol_end: stats file could not be written to\n");
- @@ -1554,8 +1632,10 @@ static void update_predictor( predictor_t *p, double q, double var, double bits
- }
- // update VBV after encoding a frame
- -static void update_vbv( x264_t *h, int bits )
- +static int update_vbv( x264_t *h, int bits, int *filler_sei_size )
- {
- + int filler = 0;
- +
- x264_ratecontrol_t *rcc = h->rc;
- x264_ratecontrol_t *rct = h->thread[0]->rc;
- @@ -1563,14 +1643,41 @@ static void update_vbv( x264_t *h, int bits )
- update_predictor( &rct->pred[h->sh.i_type], qp2qscale(rcc->qpa_rc), rcc->last_satd, bits );
- if( !rcc->b_vbv )
- - return;
- + return filler;
- rct->buffer_fill_final -= bits;
- if( rct->buffer_fill_final < 0 )
- x264_log( h, X264_LOG_WARNING, "VBV underflow (frame %d, %.0f bits)\n", h->i_frame, rct->buffer_fill_final );
- rct->buffer_fill_final = X264_MAX( rct->buffer_fill_final, 0 );
- rct->buffer_fill_final += rct->buffer_rate;
- - rct->buffer_fill_final = X264_MIN( rct->buffer_fill_final, rct->buffer_size );
- +
- + if( h->sps->vui.hrd.b_cbr_hrd && rct->buffer_fill_final >= rct->buffer_size )
- + {
- + // FIXME verify stuffing
- + filler = (rct->buffer_fill_final - rct->buffer_size) / 8;
- + *filler_sei_size = filler + FILLER_SEI_OVERHEAD;// + filler/255 ;
- + rct->buffer_fill_final -= *filler_sei_size * 8;
- + }
- + else
- + rct->buffer_fill_final = X264_MIN( rct->buffer_fill_final, rct->buffer_size );
- +
- + return filler;
- +}
- +
- +int x264_hrd_fullness( x264_t *h, int overhead )
- +{
- + x264_ratecontrol_t *rct = h->thread[0]->rc;
- + double cpb_bits = rct->buffer_fill_final - overhead;
- + double bps = h->sps->vui.hrd.i_bit_rate_unscaled;
- + double cpb_size = h->sps->vui.hrd.i_cpb_size_unscaled;
- + double cpb_fullness = 90000.0*cpb_bits/bps;
- +
- + if( cpb_fullness < 0 || cpb_fullness > cpb_size )
- + {
- + x264_log( h, X264_LOG_WARNING, "CPB %s: %.0lf bits in a %.0lf-bit buffer\n",
- + cpb_fullness < 0 ? "underflow" : "overflow", cpb_bits, cpb_size );
- + }
- + return x264_clip3f( cpb_fullness + 0.5, 0, cpb_size ); // just lie if we are in a weird state
- }
- // provisionally update VBV according to the planned size of all frames currently in progress
- @@ -2045,6 +2152,10 @@ void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next )
- COPY(expected_bits_sum);
- COPY(wanted_bits_window);
- COPY(bframe_bits);
- + COPY(initial_cpb_removal_delay);
- + COPY(current_cpb_delay);
- + COPY(nrt_first_access_unit);
- + COPY(previous_cpb_final_arrival_time);
- #undef COPY
- }
- //FIXME row_preds[] (not strictly necessary, but would improve prediction)
- diff --git a/encoder/ratecontrol.h b/encoder/ratecontrol.h
- index 5a8d088..e76f74d 100644
- --- a/encoder/ratecontrol.h
- +++ b/encoder/ratecontrol.h
- @@ -37,7 +37,7 @@ int x264_ratecontrol_slice_type( x264_t *, int i_frame );
- void x264_ratecontrol_set_weights( x264_t *h, x264_frame_t *frm );
- void x264_ratecontrol_mb( x264_t *, int bits );
- int x264_ratecontrol_qp( x264_t * );
- -int x264_ratecontrol_end( x264_t *, int bits );
- +int x264_ratecontrol_end( x264_t *, int bits, int *filler );
- void x264_ratecontrol_summary( x264_t * );
- void x264_ratecontrol_set_estimated_size( x264_t *, int bits );
- int x264_ratecontrol_get_estimated_size( x264_t const *);
- @@ -45,6 +45,6 @@ int x264_rc_analyse_slice( x264_t *h );
- int x264_weighted_reference_duplicate( x264_t *h, int i_ref, const x264_weight_t *w );
- void x264_threads_distribute_ratecontrol( x264_t *h );
- void x264_threads_merge_ratecontrol( x264_t *h );
- -
- +int x264_hrd_fullness( x264_t *h, int overhead );
- #endif
- diff --git a/encoder/set.c b/encoder/set.c
- index f79919b..af7993d 100644
- --- a/encoder/set.c
- +++ b/encoder/set.c
- @@ -28,6 +28,8 @@
- #define bs_write_ue bs_write_ue_big
- +static int num_clock_ts[10] = { 0, 1, 1, 1, 2, 2, 3, 3, 2, 3 }; // Indexed by pic_struct values
- +
- static void transpose( uint8_t *buf, int w )
- {
- int i, j;
- @@ -179,15 +181,21 @@ void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param )
- sps->vui.i_chroma_loc_bottom = param->vui.i_chroma_loc;
- }
- - sps->vui.b_timing_info_present = 0;
- - if( param->i_timebase_num > 0 && param->i_timebase_den > 0 )
- + sps->vui.b_timing_info_present = !!(param->i_timebase_num && param->i_timebase_den > 0);
- +
- + if( sps->vui.b_timing_info_present )
- {
- - sps->vui.b_timing_info_present = 1;
- sps->vui.i_num_units_in_tick = param->i_timebase_num;
- sps->vui.i_time_scale = param->i_timebase_den * 2;
- sps->vui.b_fixed_frame_rate = !param->b_vfr_input;
- }
- + sps->vui.b_vcl_hrd_parameters_present = 0; // we don't support VCL HRD
- + sps->vui.b_nal_hrd_parameters_present = param->b_nal_hrd;
- + sps->vui.b_pic_struct_present = !!param->b_pic_struct;
- +
- + // NOTE: HRD related parts of the SPS are initialised in ratecontrol_new
- +
- sps->vui.i_num_reorder_frames = param->i_bframe_pyramid ? 2 : param->i_bframe ? 1 : 0;
- /* extra slot with pyramid so that we don't have to override the
- * order of forgetting old pictures */
- @@ -203,11 +211,10 @@ void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param )
- sps->vui.i_max_bytes_per_pic_denom = 0;
- sps->vui.i_max_bits_per_mb_denom = 0;
- 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.i_log2_max_mv_length_vertical = (int)log2( param->analyse.i_mv_range*4-1 ) + 1;
- }
- }
- -
- void x264_sps_write( bs_t *s, x264_sps_t *sps )
- {
- bs_realign( s );
- @@ -343,9 +350,30 @@ 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, 0 ); /* vcl_hrd_parameters_present_flag */
- - bs_write1( s, 0 ); /* pic_struct_present_flag */
- + bs_write1( s, sps->vui.b_nal_hrd_parameters_present );
- + if( sps->vui.b_nal_hrd_parameters_present )
- + {
- + bs_write_ue( s, sps->vui.hrd.i_cpb_cnt - 1 );
- + bs_write( s, 4, sps->vui.hrd.i_bit_rate_scale );
- + bs_write( s, 4, sps->vui.hrd.i_cpb_size_scale );
- +
- + bs_write_ue( s, sps->vui.hrd.i_bit_rate_value - 1 );
- + bs_write_ue( s, sps->vui.hrd.i_cpb_size_value - 1 );
- +
- + bs_write1( s, sps->vui.hrd.b_cbr_hrd );
- +
- + bs_write( s, 5, sps->vui.hrd.i_initial_cpb_removal_delay_length - 1 );
- + bs_write( s, 5, sps->vui.hrd.i_cpb_removal_delay_length - 1 );
- + bs_write( s, 5, sps->vui.hrd.i_dpb_output_delay_length - 1 );
- + bs_write( s, 5, sps->vui.hrd.i_time_offset_length );
- + }
- +
- + bs_write1( s, sps->vui.b_vcl_hrd_parameters_present );
- +
- + if( sps->vui.b_nal_hrd_parameters_present || sps->vui.b_vcl_hrd_parameters_present )
- + bs_write1( s, 0 ); /* low_delay_hrd_flag */
- +
- + bs_write1( s, sps->vui.b_pic_struct_present );
- bs_write1( s, sps->vui.b_bitstream_restriction );
- if( sps->vui.b_bitstream_restriction )
- {
- @@ -476,7 +504,7 @@ void x264_sei_recovery_point_write( x264_t *h, bs_t *s, int recovery_frame_cnt )
- int payload_size;
- bs_realign( s );
- - bs_write( s, 8, 0x06 ); // payload_type = Recovery Point
- + bs_write( s, 8, SEI_USER_DATA_UNREGISTERED );
- payload_size = bs_size_ue( recovery_frame_cnt ) + 4;
- bs_write( s, 8, (payload_size + 7) / 8);
- @@ -512,7 +540,7 @@ int x264_sei_version_write( x264_t *h, bs_t *s )
- length = strlen(version)+1+16;
- bs_realign( s );
- - bs_write( s, 8, 0x5 ); // payload_type = user_data_unregistered
- + bs_write( s, 8, SEI_USER_DATA_UNREGISTERED );
- // payload_size
- for( i = 0; i <= length-255; i += 255 )
- bs_write( s, 8, 255 );
- @@ -534,6 +562,100 @@ fail:
- return -1;
- }
- +void x264_sei_buffering_period_write( x264_t *h, bs_t *s, int initial_cpb_removal_delay )
- +{
- + x264_sps_t *sps = h->sps;
- +
- + int payload_size; // in bits
- +
- + payload_size = bs_size_ue( sps->i_id );
- + if( sps->vui.b_nal_hrd_parameters_present )
- + payload_size += sps->vui.hrd.i_initial_cpb_removal_delay_length * 2;
- +
- + bs_realign( s );
- + bs_write( s, 8, SEI_BUFFERING_PERIOD );
- + bs_write( s, 8, (payload_size + 7) / 8);
- +
- + bs_write_ue( s, sps->i_id );
- +
- + if( sps->vui.b_nal_hrd_parameters_present )
- + {
- + bs_write( s, sps->vui.hrd.i_initial_cpb_removal_delay_length, initial_cpb_removal_delay );
- + bs_write( s, sps->vui.hrd.i_initial_cpb_removal_delay_length, 0 ); /* initial_cpb_removal_delay_offset */
- + }
- +
- + if( s->i_left&7 )
- + bs_write1( s, 1 );
- + if( s->i_left&7 )
- + bs_align_0( s );
- +
- + bs_rbsp_trailing( s );
- + bs_flush( s );
- +}
- +
- +void x264_sei_pic_timing_write( x264_t *h, bs_t *s, int cpb_removal_delay, int dpb_output_delay, int pic_struct )
- +{
- + x264_sps_t *sps = h->sps;
- +
- + int payload_size = 0; // in bits
- +
- + if( sps->vui.b_nal_hrd_parameters_present || sps->vui.b_vcl_hrd_parameters_present ) // if CpbDpbDelaysPresentFlag
- + payload_size += sps->vui.hrd.i_cpb_removal_delay_length + sps->vui.hrd.i_dpb_output_delay_length;
- +
- + if( sps->vui.b_pic_struct_present )
- + {
- + payload_size += 4; // size of (pic_struct)
- + payload_size += num_clock_ts[pic_struct];
- + }
- +
- + bs_realign( s );
- + bs_write( s, 8, SEI_PIC_TIMING );
- + bs_write( s, 8, (payload_size + 7) / 8 );
- +
- + if( sps->vui.b_nal_hrd_parameters_present || sps->vui.b_vcl_hrd_parameters_present )
- + {
- + bs_write( s, sps->vui.hrd.i_cpb_removal_delay_length, cpb_removal_delay );
- + bs_write( s, sps->vui.hrd.i_dpb_output_delay_length, dpb_output_delay );
- + }
- +
- + if( sps->vui.b_pic_struct_present )
- + {
- + int i = 0;
- +
- + bs_write( s, 4, pic_struct-1 ); // We use index 0
- +
- + for( i = 0; i < num_clock_ts[pic_struct]; i++ )
- + bs_write1( s, 0 );
- + }
- +
- + if( s->i_left&7 )
- + bs_write1( s, 1 );
- + if( s->i_left&7 )
- + bs_align_0( s );
- +
- + bs_rbsp_trailing( s );
- + bs_flush( s );
- +}
- +
- +void x264_sei_filler_write( x264_t *h, bs_t *s, int filler )
- +{
- + int i;
- +
- + bs_realign( s );
- + bs_write( s, 8, SEI_FILLER );
- +
- + for( i = 0; i <= filler-255; i += 255 )
- + bs_write( s, 8, 255 );
- +
- + bs_write( s, 8, filler-i );
- +
- + for( i = 0; i < filler; i++ )
- + bs_write( s, 8, 0xff );
- +
- + bs_rbsp_trailing( s );
- + bs_flush( 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 125f7e1..6898678 100644
- --- a/encoder/set.h
- +++ b/encoder/set.h
- @@ -31,5 +31,8 @@ void x264_pps_write( bs_t *s, x264_pps_t *pps );
- void x264_sei_recovery_point_write( x264_t *h, bs_t *s, int recovery_frame_cnt );
- int x264_sei_version_write( x264_t *h, bs_t *s );
- int x264_validate_levels( x264_t *h, int verbose );
- +void x264_sei_buffering_period_write( x264_t *h, bs_t *s, int initial_cpb_removal_delay );
- +void x264_sei_pic_timing_write( x264_t *h, bs_t *s, int cpb_removal_delay, int dpb_output_delay, int pic_struct );
- +void x264_sei_filler_write( x264_t *h, bs_t *s, int filler_bytes );
- #endif
- diff --git a/input/avs.c b/input/avs.c
- index 522f8fe..b69c710 100644
- --- a/input/avs.c
- +++ b/input/avs.c
- @@ -263,6 +263,7 @@ static int picture_alloc( x264_picture_t *pic, int i_csp, int i_width, int i_hei
- pic->img.i_csp = i_csp;
- pic->img.i_plane = 3;
- pic->param = NULL;
- + pic->i_pic_struct = PIC_STRUCT_AUTO;
- return 0;
- }
- diff --git a/output/flv.c b/output/flv.c
- index 8a937cf..75e2753 100644
- --- a/output/flv.c
- +++ b/output/flv.c
- @@ -158,9 +158,9 @@ static int write_headers( hnd_t handle, x264_nal_t *p_nal )
- flv_hnd_t *p_flv = handle;
- flv_buffer *c = p_flv->c;
- - int sei_size = p_nal[0].i_payload;
- - int sps_size = p_nal[1].i_payload;
- - int pps_size = p_nal[2].i_payload;
- + int sps_size = p_nal[0].i_payload;
- + int pps_size = p_nal[1].i_payload;
- + int sei_size = p_nal[2].i_payload;
- // SEI
- /* It is within the spec to write this as-is but for
- @@ -171,10 +171,10 @@ static int write_headers( hnd_t handle, x264_nal_t *p_nal )
- return -1;
- p_flv->sei_len = sei_size;
- - memcpy( p_flv->sei, p_nal[0].p_payload, sei_size );
- + memcpy( p_flv->sei, p_nal[2].p_payload, sei_size );
- // SPS
- - uint8_t *sps = p_nal[1].p_payload + 4;
- + uint8_t *sps = p_nal[0].p_payload + 4;
- x264_put_byte( c, FLV_TAG_TYPE_VIDEO );
- x264_put_be24( c, 0 ); // rewrite later
- @@ -200,7 +200,7 @@ static int write_headers( hnd_t handle, x264_nal_t *p_nal )
- // PPS
- x264_put_byte( c, 1 ); // number of pps
- x264_put_be16( c, pps_size - 4 );
- - flv_append_data( c, p_nal[2].p_payload + 4, pps_size - 4 );
- + flv_append_data( c, p_nal[1].p_payload + 4, pps_size - 4 );
- // rewrite data length info
- unsigned length = c->d_cur - p_flv->start;
- diff --git a/output/matroska.c b/output/matroska.c
- index 8e84f52..af11a36 100644
- --- a/output/matroska.c
- +++ b/output/matroska.c
- @@ -107,13 +107,13 @@ static int write_headers( hnd_t handle, x264_nal_t *p_nal )
- {
- mkv_hnd_t *p_mkv = handle;
- - int sei_size = p_nal[0].i_payload;
- - int sps_size = p_nal[1].i_payload - 4;
- - int pps_size = p_nal[2].i_payload - 4;
- + int sps_size = p_nal[0].i_payload - 4;
- + int pps_size = p_nal[1].i_payload - 4;
- + int sei_size = p_nal[2].i_payload;
- - uint8_t *sei = p_nal[0].p_payload;
- - uint8_t *sps = p_nal[1].p_payload + 4;
- - uint8_t *pps = p_nal[2].p_payload + 4;
- + uint8_t *sps = p_nal[0].p_payload + 4;
- + uint8_t *pps = p_nal[1].p_payload + 4;
- + uint8_t *sei = p_nal[2].p_payload;
- int ret;
- uint8_t *avcC;
- diff --git a/output/mp4.c b/output/mp4.c
- index 7889e4f..e2a51c2 100644
- --- a/output/mp4.c
- +++ b/output/mp4.c
- @@ -233,13 +233,13 @@ static int write_headers( hnd_t handle, x264_nal_t *p_nal )
- mp4_hnd_t *p_mp4 = handle;
- GF_AVCConfigSlot *p_slot;
- - int sei_size = p_nal[0].i_payload;
- - int sps_size = p_nal[1].i_payload - 4;
- - int pps_size = p_nal[2].i_payload - 4;
- + int sps_size = p_nal[0].i_payload - 4;
- + int pps_size = p_nal[1].i_payload - 4;
- + int sei_size = p_nal[2].i_payload;
- - uint8_t *sei = p_nal[0].p_payload;
- - uint8_t *sps = p_nal[1].p_payload + 4;
- - uint8_t *pps = p_nal[2].p_payload + 4;
- + uint8_t *sps = p_nal[0].p_payload + 4;
- + uint8_t *pps = p_nal[1].p_payload + 4;
- + uint8_t *sei = p_nal[2].p_payload;
- // SPS
- diff --git a/x264.c b/x264.c
- index 3a07bb3..1f58ad6 100644
- --- a/x264.c
- +++ b/x264.c
- @@ -57,6 +57,7 @@ typedef struct {
- hnd_t hin;
- hnd_t hout;
- FILE *qpfile;
- + int i_pulldown;
- } cli_opt_t;
- /* i/o file operation function pointer structs */
- @@ -92,10 +93,27 @@ static const char * const muxer_names[] =
- 0
- };
- +static const char * const pulldown_names[] = { "", "32", "64", "double", "triple", "euro", 0 };
- +
- +typedef struct{
- + int mod;
- + int *pattern;
- + int i_delay;
- +} cli_pulldown_t;
- +
- +enum pulldown_type_e
- +{
- + X264_PULLDOWN_32 = 1,
- + X264_PULLDOWN_64 = 2,
- + X264_PULLDOWN_DOUBLE = 3,
- + X264_PULLDOWN_TRIPLE = 4,
- + X264_PULLDOWN_EURO = 5,
- +};
- +
- static void Help( x264_param_t *defaults, int longhelp );
- static int Parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt );
- static int Encode( x264_param_t *param, cli_opt_t *opt );
- -
- +static int set_pulldown( cli_pulldown_t *pulldown, int i_pulldown );
- /****************************************************************************
- * main:
- ****************************************************************************/
- @@ -339,7 +357,8 @@ static void Help( x264_param_t *defaults, int longhelp )
- else H1( " --slices <integer> Number of slices per frame\n" );
- H2( " --slice-max-size <integer> Limit the size of each slice in bytes\n");
- H2( " --slice-max-mbs <integer> Limit the size of each slice in macroblocks\n");
- - H0( " --interlaced Enable pure-interlaced mode\n" );
- + H0( " --interlaced, --tff Enable pure-interlaced mode (top field first)\n" );
- + H0( " --bff Enable pure-interlaced mode (bottom field first)\n" );
- H2( " --constrained-intra Enable constrained intra prediction.\n" );
- H0( "\n" );
- H0( "Ratecontrol:\n" );
- @@ -481,6 +500,11 @@ static void Help( x264_param_t *defaults, int longhelp )
- strtable_lookup( x264_colmatrix_names, defaults->vui.i_colmatrix ) );
- H2( " --chromaloc <integer> Specify chroma sample location (0 to 5) [%d]\n",
- defaults->vui.i_chroma_loc );
- +
- + H0( " --nal-hrd <string> Signal HRD information (needed e.g. for Blu-Ray compliance)\n"
- + " - vbr, cbr. (requires vbv-bufsize; cbr-hrd not allowed in .mp4)\n" );
- + H2( " --pic-struct Send pic_struct in Picture Timing SEI (on for pulldown or interlaced) \n" );
- +
- H0( "\n" );
- H0( "Input/Output:\n" );
- H0( "\n" );
- @@ -513,6 +537,8 @@ static void Help( x264_param_t *defaults, int longhelp )
- H2( " --sps-id <integer> Set SPS and PPS id numbers [%d]\n", defaults->i_sps_id );
- H2( " --aud Use access unit delimiters\n" );
- H2( " --force-cfr Force constant framerate timestamp generation\n" );
- + H0( " --pulldown <string> Use soft pulldown and Timing SEI to change frame rate\n"
- + " - 32, 64, double, triple, euro\n" );
- H0( "\n" );
- }
- @@ -534,6 +560,7 @@ static void Help( x264_param_t *defaults, int longhelp )
- #define OPT_DEMUXER 271
- #define OPT_INDEX 272
- #define OPT_INTERLACED 273
- +#define OPT_PULLDOWN 274
- static char short_options[] = "8A:B:b:f:hI:i:m:o:p:q:r:t:Vvw";
- static struct option long_options[] =
- @@ -562,6 +589,8 @@ static struct option long_options[] =
- { "filter", required_argument, NULL, 0 },
- { "deblock", required_argument, NULL, 'f' },
- { "interlaced", no_argument, NULL, OPT_INTERLACED },
- + { "tff", no_argument, NULL, 0 },
- + { "bff", no_argument, NULL, 0 },
- { "no-interlaced", no_argument, NULL, OPT_INTERLACED },
- { "constrained-intra", no_argument, NULL, 0 },
- { "cabac", no_argument, NULL, 0 },
- @@ -668,6 +697,9 @@ static struct option long_options[] =
- { "colormatrix", required_argument, NULL, 0 },
- { "chromaloc", required_argument, NULL, 0 },
- { "force-cfr", no_argument, NULL, 0 },
- + { "pic-struct", no_argument, NULL, 0 },
- + { "nal-hrd", required_argument, NULL, 0 },
- + { "pulldown", required_argument, NULL, OPT_PULLDOWN },
- {0, 0, 0, 0}
- };
- @@ -682,8 +714,12 @@ static int select_output( const char *muxer, char *filename, x264_param_t *param
- #ifdef MP4_OUTPUT
- output = mp4_output;
- param->b_annexb = 0;
- - param->b_aud = 0;
- param->b_repeat_headers = 0;
- + if( param->b_cbr_hrd )
- + {
- + fprintf( stderr, "x264 [warning]: cbr-hrd is not compatible with mp4\n" );
- + param->b_cbr_hrd = 0;
- + }
- #else
- fprintf( stderr, "x264 [error]: not compiled with MP4 output support\n" );
- return -1;
- @@ -693,14 +729,12 @@ static int select_output( const char *muxer, char *filename, x264_param_t *param
- {
- output = mkv_output;
- param->b_annexb = 0;
- - param->b_aud = 0;
- param->b_repeat_headers = 0;
- }
- else if( !strcasecmp( ext, "flv" ) )
- {
- output = flv_output;
- param->b_annexb = 0;
- - param->b_aud = 0;
- param->b_repeat_headers = 0;
- }
- else
- @@ -790,6 +824,71 @@ static int select_input( const char *demuxer, char *used_demuxer, char *filename
- return 0;
- }
- +static int set_pulldown( cli_pulldown_t *pulldown, int i_pulldown )
- +{
- + switch( i_pulldown )
- + {
- + case X264_PULLDOWN_32:
- + pulldown->mod = 4;
- + pulldown->pattern = malloc( pulldown->mod*sizeof(int) );
- + if( !pulldown->pattern )
- + return -1;
- + pulldown->pattern[0] = PIC_STRUCT_TOP_BOTTOM_TOP;
- + pulldown->pattern[1] = PIC_STRUCT_BOTTOM_TOP;
- + pulldown->pattern[2] = PIC_STRUCT_BOTTOM_TOP_BOTTOM;
- + pulldown->pattern[3] = PIC_STRUCT_TOP_BOTTOM;
- + pulldown->i_delay = 1;
- + break;
- +
- + case X264_PULLDOWN_64:
- + pulldown->mod = 2;
- + pulldown->pattern = malloc( pulldown->mod*sizeof(int) );
- + if( !pulldown->pattern )
- + return -1;
- + pulldown->pattern[0] = PIC_STRUCT_DOUBLE;
- + pulldown->pattern[1] = PIC_STRUCT_TRIPLE;
- + pulldown->i_delay = 4;
- + break;
- +
- + case X264_PULLDOWN_DOUBLE:
- + pulldown->mod = 1;
- + pulldown->pattern = malloc( pulldown->mod*sizeof(int) );
- + if( !pulldown->pattern )
- + return -1;
- + pulldown->pattern[0] = PIC_STRUCT_DOUBLE;
- + pulldown->i_delay = 2;
- + break;
- +
- + case X264_PULLDOWN_TRIPLE:
- + pulldown->mod = 1;
- + pulldown->i_delay = 4;
- + pulldown->pattern = malloc( pulldown->mod*sizeof(int) );
- + if( !pulldown->pattern )
- + return -1;
- + pulldown->pattern[0] = PIC_STRUCT_TRIPLE;
- + break;
- +
- + case X264_PULLDOWN_EURO:
- + pulldown->mod = 24;
- + pulldown->i_delay = 1;
- + pulldown->pattern = malloc( pulldown->mod*sizeof(int) );
- + if( !pulldown->pattern )
- + return -1;
- +
- + int j;
- + for( j = 0; j < 11; j++ )
- + {
- + pulldown->pattern[j+1] = PIC_STRUCT_BOTTOM_TOP;
- + pulldown->pattern[j+13] = PIC_STRUCT_TOP_BOTTOM;
- + }
- + pulldown->pattern[0] = PIC_STRUCT_TOP_BOTTOM_TOP;
- + pulldown->pattern[12] = PIC_STRUCT_BOTTOM_TOP_BOTTOM;
- + break;
- + }
- +
- + return 0;
- +}
- +
- /*****************************************************************************
- * Parse:
- *****************************************************************************/
- @@ -1158,6 +1257,16 @@ psy_failure:
- case OPT_INTERLACED:
- b_user_interlaced = 1;
- goto generic_option;
- + case OPT_PULLDOWN:
- + for( i = 0; pulldown_names[i] && strcasecmp( pulldown_names[i], optarg ); )
- + i++;
- + if( !pulldown_names[i] )
- + {
- + fprintf( stderr, "x264 [error]: invalid pulldown '%s'\n", optarg );
- + return -1;
- + }
- + opt->i_pulldown = i;
- + break;
- default:
- generic_option:
- {
- @@ -1444,6 +1553,7 @@ static int Encode( x264_param_t *param, cli_opt_t *opt )
- {
- x264_t *h;
- x264_picture_t pic;
- + cli_pulldown_t p_pulldown;
- int i_frame, i_frame_total, i_frame_output;
- int64_t i_start, i_end;
- @@ -1467,6 +1577,15 @@ static int Encode( x264_param_t *param, cli_opt_t *opt )
- param->i_frame_total = i_frame_total;
- i_update_interval = i_frame_total ? x264_clip3( i_frame_total / 1000, 1, 10 ) : 10;
- + /* set up pulldown */
- + if( opt->i_pulldown )
- + {
- + param->b_pulldown = 1;
- + if( set_pulldown( &p_pulldown, opt->i_pulldown ) < 0 )
- + return -1;
- + param->i_pulldown_delay = p_pulldown.i_delay;
- + }
- +
- if( ( h = x264_encoder_open( param ) ) == NULL )
- {
- fprintf( stderr, "x264 [error]: x264_encoder_open failed\n" );
- @@ -1549,6 +1668,9 @@ static int Encode( x264_param_t *param, cli_opt_t *opt )
- pic.i_qpplus1 = 0;
- }
- + if( opt->i_pulldown )
- + pic.i_pic_struct = p_pulldown.pattern[ i_frame % p_pulldown.mod ];
- +
- i_frame_size = Encode_frame( h, opt->hout, &pic, &last_pts );
- if( i_frame_size < 0 )
- return -1;
- @@ -1609,5 +1731,8 @@ static int Encode( x264_param_t *param, cli_opt_t *opt )
- (double) i_file * 8 / ( 1000 * duration ) );
- }
- + if( opt->i_pulldown )
- + free(p_pulldown.pattern);
- +
- return 0;
- }
- diff --git a/x264.h b/x264.h
- index 1223df7..6c89101 100644
- --- a/x264.h
- +++ b/x264.h
- @@ -35,7 +35,7 @@
- #include <stdarg.h>
- -#define X264_BUILD 83
- +#define X264_BUILD 84
- /* x264_t:
- * opaque handler for encoder */
- @@ -176,6 +176,9 @@ typedef struct x264_param_t
- int i_level_idc;
- int i_frame_total; /* number of frames to encode if known, else 0 */
- + int b_nal_hrd; /* Use Buffering and Picture Timing SEI's to signal HRD */
- + int b_cbr_hrd; /* Use CBR-HRD mode with filler bytes */
- +
- struct
- {
- /* they will be reduced to be 0 < x <= 65535 and prime */
- @@ -317,6 +320,26 @@ typedef struct x264_param_t
- int i_timebase_num; /* Timebase numerator */
- int i_timebase_den; /* Timebase denominator */
- + int b_tff;
- +
- + /* Custom Pulldown:
- + * Set b_pulldown to use pulldown and pass the correct pic_struct with the frame
- + *
- + * i_pulldown_delay is the number of effective extra frames added to the sequence as a result of pulldown (mandatory)
- + * i_pulldown_delay is added to each frame's dpb output delay
- + * timebase must also be appropriate for the pulldown changes that could be made
- + *
- + * Pulldown changes are not clearly defined in H.264. Therefore, it is the calling app's responsibility to manage this.
- + * Correct timestamps must also be input.
- + *
- + * Use the frame-exact x264_picture_t->param instead of the frame-inexact x264_encoder_reconfig to change pulldown on the fly.
- + */
- +
- + int b_pulldown;
- + int i_pulldown_delay;
- +
- + int b_pic_struct;
- +
- /* Slicing parameters */
- int i_slice_max_size; /* Max size per slice in bytes; includes estimated NAL overhead. */
- int i_slice_max_mbs; /* Max number of MBs per slice; overrides i_slice_count. */
- @@ -365,6 +388,29 @@ int x264_param_parse( x264_param_t *, const char *name, const char *value );
- /****************************************************************************
- * Picture structures and functions.
- ****************************************************************************/
- +
- +enum pic_struct_e
- +{
- + PIC_STRUCT_AUTO = 0, // automatically decide (default)
- + PIC_STRUCT_PROGRESSIVE = 1, // progressive frame
- + // "TOP" and "BOTTOM" are not supported in x264 (PAFF only)
- + PIC_STRUCT_TOP_BOTTOM = 4, // top field followed by bottom
- + PIC_STRUCT_BOTTOM_TOP = 5, // bottom field followed by top
- + PIC_STRUCT_TOP_BOTTOM_TOP = 6, // top field, bottom field, top field repeated
- + PIC_STRUCT_BOTTOM_TOP_BOTTOM = 7, // bottom field, top field, bottom field repeated
- + PIC_STRUCT_DOUBLE = 8, // double frame
- + PIC_STRUCT_TRIPLE = 9 // triple frame
- +};
- +
- +typedef struct
- +{
- + double cpb_initial_arrival_time;
- + double cpb_final_arrival_time;
- + double cpb_removal_time;
- +
- + double dpb_output_time;
- +} x264_hrd_t;
- +
- typedef struct
- {
- int i_csp;
- @@ -385,6 +431,9 @@ typedef struct
- int i_type;
- /* In: force quantizer for > 0 */
- int i_qpplus1;
- + /* In: pic_struct, for pulldown/doubling/etc...used only if b_pic_timing_sei=1.
- + * pic_struct_e for pic_struct inputs */
- + int i_pic_struct;
- /* Out: whether this frame is a keyframe. Important when using modes that result in
- * SEI recovery points being used instead of IDR frames. */
- int b_keyframe;
- @@ -402,6 +451,8 @@ typedef struct
- x264_param_t *param;
- /* In: raw data */
- x264_image_t img;
- + /* Out: HRD timing information. Output only when b_nal_hrd is set. */
- + x264_hrd_t hrd_timing;
- /* private user data. libx264 doesn't touch this,
- not even copy it from input to output frames. */
- void *opaque;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement