From cf5ba8134a4bdd381e75a5c2ea434198a7174a36 Mon Sep 17 00:00:00 2001 From: Lamont Alston Date: Mon, 12 Oct 2009 23:32:16 -0700 Subject: [PATCH] Make B-pyramid spec-compliant The rules of the specification with regard to picture buffering for pyramid coding are widely ignored. x264's b-pyramid implementation, despite being practically identical to that proposed by the original paper, was technically not compliant. Now it is. Two modes are now available: 1) strict b-pyramid, while worse for compression, follows the rule mandated by Blu-ray (no P-frames can reference B-frames) 2) normal b-pyramid, which is like the old mode except fully compliant. This patch also adds MMCO support (necessary for compliant pyramid in some cases). MB-tree still doesn't support b-pyramid (but will soon). --- common/common.c | 6 +-- common/common.h | 12 ++++- common/frame.h | 3 +- common/macroblock.c | 2 +- encoder/encoder.c | 121 ++++++++++++++++++++++++++++++++++-------- encoder/lookahead.c | 6 ++- encoder/ratecontrol.c | 6 ++- encoder/set.c | 10 ++-- encoder/slicetype.c | 7 +++ muxers.c | 2 +- x264.c | 8 ++- x264.h | 8 ++- 12 files changed, 150 insertions(+), 41 deletions(-) diff --git a/common/common.c b/common/common.c index fe02d657..fc8b06a1 100644 --- a/common/common.c +++ b/common/common.c @@ -75,7 +75,7 @@ void x264_param_default( x264_param_t *param ) param->i_scenecut_threshold = 40; param->i_bframe_adaptive = X264_B_ADAPT_FAST; param->i_bframe_bias = 0; - param->b_bframe_pyramid = 0; + param->i_bframe_pyramid = 0; param->b_interlaced = 0; param->b_constrained_intra = 0; @@ -366,7 +366,7 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) OPT("b-bias") p->i_bframe_bias = atoi(value); OPT("b-pyramid") - p->b_bframe_pyramid = atobool(value); + b_error |= parse_enum( value, x264_b_pyramid_names, &p->i_bframe_pyramid ); OPT("nf") p->b_deblocking_filter = !atobool(value); OPT2("filter", "deblock") @@ -900,7 +900,7 @@ char *x264_param2string( x264_param_t *p, int b_res ) if( p->i_bframe ) { s += sprintf( s, " b_pyramid=%d b_adapt=%d b_bias=%d direct=%d wpredb=%d", - p->b_bframe_pyramid, p->i_bframe_adaptive, p->i_bframe_bias, + p->i_bframe_pyramid, p->i_bframe_adaptive, p->i_bframe_bias, p->analyse.i_direct_mv_pred, p->analyse.b_weighted_bipred ); } diff --git a/common/common.h b/common/common.h index 5ec141ce..12e1c267 100644 --- a/common/common.h +++ b/common/common.h @@ -34,6 +34,7 @@ #define X264_MIN4(a,b,c,d) X264_MIN((a),X264_MIN3((b),(c),(d))) #define X264_MAX4(a,b,c,d) X264_MAX((a),X264_MAX3((b),(c),(d))) #define XCHG(type,a,b) do{ type t = a; a = b; b = t; } while(0) +#define IS_DISPOSABLE(type) ( type == X264_TYPE_B ) #define FIX8(f) ((int)(f*(1<<8)+.5)) #define CHECKED_MALLOC( var, size )\ @@ -224,11 +225,20 @@ typedef struct int b_ref_pic_list_reordering_l0; int b_ref_pic_list_reordering_l1; - struct { + struct + { int idc; int arg; } ref_pic_list_order[2][16]; + int i_mmco_remove_from_end; + int i_mmco_command_count; + struct /* struct for future expansion */ + { + int i_difference_of_pic_nums; + int i_poc; + } mmco[16]; + int i_cabac_init_idc; int i_qp; diff --git a/common/frame.h b/common/frame.h index c9e1bfd5..02cc31a4 100644 --- a/common/frame.h +++ b/common/frame.h @@ -38,7 +38,8 @@ typedef struct x264_param_t *param; int i_frame; /* Presentation frame number */ - int i_frame_num; /* Coded frame number */ + int i_dts; /* Coded frame number */ + int i_frame_num; /* 7.4.3 frame_num */ int b_kept_as_ref; uint8_t b_fdec; uint8_t b_last_minigop_bframe; /* this frame is the last b in a sequence of bframes */ diff --git a/common/macroblock.c b/common/macroblock.c index f27152f0..3139077d 100644 --- a/common/macroblock.c +++ b/common/macroblock.c @@ -694,7 +694,7 @@ int x264_macroblock_cache_init( x264_t *h ) for( i=0; i<2; i++ ) { - int i_refs = X264_MIN(16, (i ? 1 : h->param.i_frame_reference) + h->param.b_bframe_pyramid) << h->param.b_interlaced; + int i_refs = X264_MIN(16, (i ? 1 + !!h->param.i_bframe_pyramid : h->param.i_frame_reference) ) << h->param.b_interlaced; for( j=0; j < i_refs; j++ ) CHECKED_MALLOC( h->mb.mvr[i][j], 2 * i_mb_count * sizeof(int16_t) ); } diff --git a/encoder/encoder.c b/encoder/encoder.c index fd3d8365..266b7a0b 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -272,7 +272,17 @@ static void x264_slice_header_write( bs_t *s, x264_slice_header_t *sh, int i_nal } else { - bs_write1( s, 0 ); /* adaptive_ref_pic_marking_mode_flag */ + bs_write1( s, sh->i_mmco_command_count > 0 ); /* adaptive_ref_pic_marking_mode_flag */ + if( sh->i_mmco_command_count > 0 ) + { + int i; + for( i = 0; i < sh->i_mmco_command_count; i++ ) + { + bs_write_ue( s, 1 ); /* mark short term ref as unused */ + bs_write_ue( s, sh->mmco[i].i_difference_of_pic_nums - 1 ); + } + bs_write_ue( s, 0 ); /* end command list */ + } } } @@ -498,7 +508,9 @@ static int x264_validate_parameters( x264_t *h ) if( h->param.i_keyint_max == 1 ) h->param.i_bframe = 0; 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; + if( h->param.i_bframe <= 1 ) + h->param.i_bframe_pyramid = X264_B_PYRAMID_NONE; + h->param.i_bframe_pyramid = x264_clip3( h->param.i_bframe_pyramid, X264_B_PYRAMID_NONE, X264_B_PYRAMID_NORMAL ); if( !h->param.i_bframe ) { h->param.i_bframe_adaptive = X264_B_ADAPT_NONE; @@ -602,10 +614,10 @@ static int x264_validate_parameters( x264_t *h ) h->param.rc.i_aq_mode = 1; h->param.rc.f_aq_strength = 0; } - if( h->param.rc.b_mb_tree && h->param.b_bframe_pyramid ) + if( h->param.rc.b_mb_tree && h->param.i_bframe_pyramid ) { x264_log( h, X264_LOG_WARNING, "b-pyramid + mb-tree is not supported\n" ); - h->param.b_bframe_pyramid = 0; + h->param.i_bframe_pyramid = X264_B_PYRAMID_NONE; } h->param.analyse.i_noise_reduction = x264_clip3( h->param.analyse.i_noise_reduction, 0, 1<<16 ); if( h->param.analyse.i_subpel_refine == 10 && (h->param.analyse.i_trellis != 2 || !h->param.rc.i_aq_mode) ) @@ -980,7 +992,7 @@ int x264_encoder_reconfig( x264_t *h, x264_param_t *param ) if( h->pps->b_transform_8x8_mode ) COPY( analyse.b_transform_8x8 ); if( h->frames.i_max_ref1 > 1 ) - COPY( b_bframe_pyramid ); + COPY( i_bframe_pyramid ); COPY( i_slice_max_size ); COPY( i_slice_max_mbs ); COPY( i_slice_count ); @@ -1091,6 +1103,21 @@ int x264_encoder_headers( x264_t *h, x264_nal_t **pp_nal, int *pi_nal ) return frame_size; } +/* Check to see whether we have chosen a reference list ordering different + * from the standard's default. */ +static inline void x264_reference_check_reorder( x264_t *h ) +{ + int i; + for( i = 0; i < h->i_ref0 - 1; i++ ) + /* P and B-frames use different default orders. */ + if( h->sh.i_type == SLICE_TYPE_P ? h->fref0[i]->i_frame_num < h->fref0[i+1]->i_frame_num + : h->fref0[i]->i_poc < h->fref0[i+1]->i_poc ) + { + h->b_ref_reorder[0] = 1; + break; + } +} + static inline void x264_reference_build_list( x264_t *h, int i_poc ) { int i; @@ -1125,6 +1152,15 @@ static inline void x264_reference_build_list( x264_t *h, int i_poc ) } } } while( !b_ok ); + + if( h->sh.i_mmco_remove_from_end ) + for( i = h->i_ref0-1; i >= h->i_ref0 - h->sh.i_mmco_remove_from_end; i-- ) + { + int diff = h->i_frame_num - h->fref0[i]->i_frame_num; + h->sh.mmco[h->sh.i_mmco_command_count].i_poc = h->fref0[i]->i_poc; + h->sh.mmco[h->sh.i_mmco_command_count++].i_difference_of_pic_nums = diff; + } + /* Order ref1 from lower to higher poc (bubble sort) for B-frame */ do { @@ -1140,6 +1176,8 @@ static inline void x264_reference_build_list( x264_t *h, int i_poc ) } } while( !b_ok ); + x264_reference_check_reorder( h ); + h->i_ref1 = X264_MIN( h->i_ref1, h->frames.i_max_ref1 ); h->i_ref0 = X264_MIN( h->i_ref0, h->frames.i_max_ref0 ); h->i_ref0 = X264_MIN( h->i_ref0, h->param.i_frame_reference ); // if reconfig() has lowered the limit @@ -1226,6 +1264,7 @@ static void x264_fdec_filter_row( x264_t *h, int mb_y ) static inline int x264_reference_update( x264_t *h ) { + int i, j; if( !h->fdec->b_kept_as_ref ) { if( h->param.i_threads > 1 ) @@ -1238,9 +1277,15 @@ static inline int x264_reference_update( x264_t *h ) return 0; } + /* apply mmco from previous frame. */ + for( i = 0; i < h->sh.i_mmco_command_count; i++ ) + for( j = 0; h->frames.reference[j]; j++ ) + if( h->frames.reference[j]->i_poc == h->sh.mmco[i].i_poc ) + x264_frame_push_unused( h, x264_frame_shift( &h->frames.reference[j] ) ); + /* move frame in the buffer */ x264_frame_push( h->frames.reference, h->fdec ); - if( h->frames.reference[h->frames.i_max_dpb] ) + if( h->frames.reference[h->sps->i_num_ref_frames] ) x264_frame_push_unused( h, x264_frame_shift( h->frames.reference ) ); h->fdec = x264_frame_pop_unused( h, 1 ); if( !h->fdec ) @@ -1256,6 +1301,40 @@ static inline void x264_reference_reset( x264_t *h ) h->fenc->i_poc = 0; } +static inline void x264_reference_hierarchy_reset( x264_t *h ) +{ + int i, ref; + int b_hasdelayframe = 0; + if( !h->param.i_bframe_pyramid ) + return; + + /* look for delay frames -- chain must only contain frames that are disposable */ + for( i = 0; h->frames.current[i] && IS_DISPOSABLE( h->frames.current[i]->i_type ); i++ ) + b_hasdelayframe |= h->frames.current[i]->i_dts + != h->frames.current[i]->i_frame + h->sps->vui.i_num_reorder_frames; + + if( h->param.i_bframe_pyramid != X264_B_PYRAMID_STRICT && !b_hasdelayframe ) + return; + + /* Remove last BREF. There will never be old BREFs in the + * dpb during a BREF decode when pyramid == STRICT */ + for( ref = 0; h->frames.reference[ref]; ref++ ) + { + if( h->param.i_bframe_pyramid == X264_B_PYRAMID_STRICT + && h->frames.reference[ref]->i_type == X264_TYPE_BREF ) + { + int diff = h->i_frame_num - h->frames.reference[ref]->i_frame_num; + h->sh.mmco[h->sh.i_mmco_command_count++].i_difference_of_pic_nums = diff; + x264_frame_push_unused( h, x264_frame_pop( h->frames.reference ) ); + h->b_ref_reorder[0] = 1; + break; + } + } + + /* Prepare to room in the dpb for the delayed display time of the later b-frame's */ + h->sh.i_mmco_remove_from_end = X264_MAX( ref + 2 - h->frames.i_max_dpb, 0 ); +} + static inline void x264_slice_init( x264_t *h, int i_nal_type, int i_global_qp ) { /* ------------------------ Create slice header ----------------------- */ @@ -1622,7 +1701,7 @@ int x264_encoder_encode( x264_t *h, x264_picture_t *pic_out ) { x264_t *thread_current, *thread_prev, *thread_oldest; - int i_nal_type, i; + int i_nal_type; int i_nal_ref_idc; int i_global_qp; @@ -1721,35 +1800,41 @@ int x264_encoder_encode( x264_t *h, h->frames.i_last_idr = h->fenc->i_frame; h->i_frame_num = 0; } + h->sh.i_mmco_command_count = 0; + h->sh.i_mmco_remove_from_end = 0; + h->b_ref_reorder[0] = + h->b_ref_reorder[1] = 0; /* ------------------- Setup frame context ----------------------------- */ /* 5: Init data dependent of frame type */ if( h->fenc->i_type == X264_TYPE_IDR ) { /* reset ref pictures */ - x264_reference_reset( h ); - i_nal_type = NAL_SLICE_IDR; i_nal_ref_idc = NAL_PRIORITY_HIGHEST; h->sh.i_type = SLICE_TYPE_I; + x264_reference_reset( h ); } else if( h->fenc->i_type == X264_TYPE_I ) { i_nal_type = NAL_SLICE; i_nal_ref_idc = NAL_PRIORITY_HIGH; /* Not completely true but for now it is (as all I/P are kept as ref)*/ h->sh.i_type = SLICE_TYPE_I; + x264_reference_hierarchy_reset( h ); } else if( h->fenc->i_type == X264_TYPE_P ) { i_nal_type = NAL_SLICE; i_nal_ref_idc = NAL_PRIORITY_HIGH; /* Not completely true but for now it is (as all I/P are kept as ref)*/ h->sh.i_type = SLICE_TYPE_P; + x264_reference_hierarchy_reset( h ); } else if( h->fenc->i_type == X264_TYPE_BREF ) { i_nal_type = NAL_SLICE; - i_nal_ref_idc = NAL_PRIORITY_HIGH; /* maybe add MMCO to forget it? -> low */ + i_nal_ref_idc = h->param.i_bframe_pyramid == X264_B_PYRAMID_STRICT ? NAL_PRIORITY_LOW : NAL_PRIORITY_HIGH; h->sh.i_type = SLICE_TYPE_B; + x264_reference_hierarchy_reset( h ); } else /* B frame */ { @@ -1839,20 +1924,10 @@ int x264_encoder_encode( x264_t *h, h->fdec->i_qpplus1 = i_global_qp + 1; if( h->param.rc.b_stat_read && h->sh.i_type != SLICE_TYPE_I ) + { x264_reference_build_list_optimal( h ); - - /* Check to see whether we have chosen a reference list ordering different - * from the standard's default. */ - h->b_ref_reorder[0] = - h->b_ref_reorder[1] = 0; - for( i = 0; i < h->i_ref0 - 1; i++ ) - /* P and B-frames use different default orders. */ - if( h->sh.i_type == SLICE_TYPE_P ? h->fref0[i]->i_frame_num < h->fref0[i+1]->i_frame_num - : h->fref0[i]->i_poc < h->fref0[i+1]->i_poc ) - { - h->b_ref_reorder[0] = 1; - break; - } + x264_reference_check_reorder( h ); + } if( h->sh.i_type == SLICE_TYPE_B ) x264_macroblock_bipred_init( h ); diff --git a/encoder/lookahead.c b/encoder/lookahead.c index 968d0fc1..b211c96a 100644 --- a/encoder/lookahead.c +++ b/encoder/lookahead.c @@ -217,18 +217,22 @@ static void x264_lookahead_encoder_shift( x264_t *h ) } if( h->lookahead->ofbuf.list[i_frames] ) { + int i_dts = h->lookahead->ofbuf.list[0]->i_frame; + h->lookahead->ofbuf.list[bframes]->i_dts = i_dts; x264_frame_push( h->frames.current, x264_frame_shift( &h->lookahead->ofbuf.list[bframes] ) ); h->lookahead->ofbuf.i_size--; - if( h->param.b_bframe_pyramid && bframes > 1 ) + if( h->param.i_bframe_pyramid && bframes > 1 ) { x264_frame_t *mid = x264_frame_shift( &h->lookahead->ofbuf.list[bframes/2] ); h->lookahead->ofbuf.i_size--; mid->i_type = X264_TYPE_BREF; + mid->i_dts = ++i_dts; x264_frame_push( h->frames.current, mid ); bframes--; } while( bframes-- ) { + h->lookahead->ofbuf.list[0]->i_dts = ++i_dts; x264_frame_push( h->frames.current, x264_frame_shift( h->lookahead->ofbuf.list ) ); h->lookahead->ofbuf.i_size--; } diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 7054c35a..360c2065 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -525,6 +525,7 @@ int x264_ratecontrol_new( x264_t *h ) { int i; char *opts = stats_buf; + char buf[12]; stats_in = strchr( stats_buf, '\n' ); if( !stats_in ) return -1; @@ -541,8 +542,9 @@ int x264_ratecontrol_new( x264_t *h ) /* since B-adapt doesn't (yet) take into account B-pyramid, * the converse is not a problem */ - if( strstr( opts, "b_pyramid=1" ) && !h->param.b_bframe_pyramid ) - x264_log( h, X264_LOG_WARNING, "1st pass used B-pyramid, 2nd doesn't\n" ); + sprintf( buf, "b_pyramid=%d", h->param.i_bframe_pyramid ); + if( !strstr( opts, buf ) ) + x264_log( h, X264_LOG_WARNING, "different B-pyramid setting than 1st pass\n" ); if( ( p = strstr( opts, "keyint=" ) ) && sscanf( p, "keyint=%d", &i ) && h->param.i_keyint_max != i ) diff --git a/encoder/set.c b/encoder/set.c index f6dd8303..e087f834 100644 --- a/encoder/set.c +++ b/encoder/set.c @@ -189,11 +189,13 @@ void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param ) sps->vui.b_fixed_frame_rate = 1; } - sps->vui.i_num_reorder_frames = param->b_bframe_pyramid ? 2 : param->i_bframe ? 1 : 0; + 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 */ 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->i_num_ref_frames = X264_MIN(16, X264_MAX3(param->i_frame_reference, 1 + sps->vui.i_num_reorder_frames, + param->i_bframe_pyramid ? 4 : 1 )); + sps->i_num_ref_frames -= param->i_bframe_pyramid == X264_B_PYRAMID_STRICT; sps->vui.b_bitstream_restriction = 1; if( sps->vui.b_bitstream_restriction ) @@ -540,7 +542,7 @@ int x264_validate_levels( x264_t *h, int verbose ) { int ret = 0; int mbs = h->sps->i_mb_width * h->sps->i_mb_height; - int dpb = mbs * 384 * h->sps->i_num_ref_frames; + int dpb = mbs * 384 * h->sps->vui.i_max_dec_frame_buffering; int cbp_factor = h->sps->i_profile_idc==PROFILE_HIGH ? 5 : 4; const x264_level_t *l = x264_levels; @@ -554,7 +556,7 @@ int x264_validate_levels( x264_t *h, int verbose ) h->sps->i_mb_width, h->sps->i_mb_height, l->frame_size ); if( dpb > l->dpb ) ERROR( "DPB size (%d frames, %d bytes) > level limit (%d frames, %d bytes)\n", - h->sps->i_num_ref_frames, dpb, (int)(l->dpb / (384*mbs)), l->dpb ); + h->sps->vui.i_max_dec_frame_buffering, dpb, (int)(l->dpb / (384*mbs)), l->dpb ); #define CHECK( name, limit, val ) \ if( (val) > (limit) ) \ diff --git a/encoder/slicetype.c b/encoder/slicetype.c index e9c70089..d4d4d1c3 100644 --- a/encoder/slicetype.c +++ b/encoder/slicetype.c @@ -937,6 +937,13 @@ void x264_slicetype_decide( x264_t *h ) for( bframes = 0;; bframes++ ) { frm = h->lookahead->next.list[bframes]; + if( h->param.i_bframe_pyramid < X264_B_PYRAMID_NORMAL && !h->param.rc.b_stat_read + && frm->i_type == X264_TYPE_BREF ) + { + frm->i_type = X264_TYPE_B; + x264_log( h, X264_LOG_WARNING, "Externally supplied B-ref at frame %d incompatible with B-pyramid %s\n", + frm->i_frame, x264_b_pyramid_names[h->param.i_bframe_pyramid] ); + } /* Limit GOP size */ if( frm->i_frame - h->lookahead->i_last_idr >= h->param.i_keyint_max ) diff --git a/muxers.c b/muxers.c index c9b8dfa2..1a8187d0 100644 --- a/muxers.c +++ b/muxers.c @@ -726,7 +726,7 @@ int set_param_mp4( hnd_t handle, x264_param_t *p_param ) p_mp4->i_time_res = p_param->i_fps_num; p_mp4->i_time_inc = p_param->i_fps_den; - p_mp4->i_init_delay = p_param->i_bframe ? (p_param->b_bframe_pyramid ? 2 : 1) : 0; + p_mp4->i_init_delay = p_param->i_bframe ? (p_param->i_bframe_pyramid ? 2 : 1) : 0; p_mp4->i_init_delay *= p_mp4->i_time_inc; fprintf( stderr, "mp4 [info]: initial delay %d (scale %d)\n", p_mp4->i_init_delay, p_mp4->i_time_res ); diff --git a/x264.c b/x264.c index a440ab7f..fc4e44f1 100644 --- a/x264.c +++ b/x264.c @@ -207,7 +207,11 @@ static void Help( x264_param_t *defaults, int longhelp ) " - 1: Fast\n" " - 2: Optimal (slow with high --bframes)\n", defaults->i_bframe_adaptive ); H2( " --b-bias Influences how often B-frames are used [%d]\n", defaults->i_bframe_bias ); - H1( " --b-pyramid Keep some B-frames as references\n" ); + H1( " --b-pyramid Keep some B-frames as references [%s]\n" + " - none: Disabled\n" + " - strict: Strictly heirarchical pyramid\n" + " - normal: Non-strict (not Blu-ray compatible)\n", + strtable_lookup( x264_b_pyramid_names, defaults->i_bframe_pyramid ) ); H1( " --no-cabac Disable CABAC\n" ); H1( " -r, --ref Number of reference frames [%d]\n", defaults->i_frame_reference ); H1( " --no-deblock Disable loop filter\n" ); @@ -416,7 +420,7 @@ static struct option long_options[] = { "b-adapt", required_argument, NULL, 0 }, { "no-b-adapt", no_argument, NULL, 0 }, { "b-bias", required_argument, NULL, 0 }, - { "b-pyramid", no_argument, NULL, 0 }, + { "b-pyramid", required_argument, NULL, 0 }, { "min-keyint", required_argument, NULL, 'i' }, { "keyint", required_argument, NULL, 'I' }, { "scenecut", required_argument, NULL, 0 }, diff --git a/x264.h b/x264.h index 7bc2d36a..0c10c8ca 100644 --- a/x264.h +++ b/x264.h @@ -35,7 +35,7 @@ #include -#define X264_BUILD 77 +#define X264_BUILD 78 /* x264_t: * opaque handler for encoder */ @@ -95,9 +95,13 @@ typedef struct x264_t x264_t; #define X264_B_ADAPT_NONE 0 #define X264_B_ADAPT_FAST 1 #define X264_B_ADAPT_TRELLIS 2 +#define X264_B_PYRAMID_NONE 0 +#define X264_B_PYRAMID_STRICT 1 +#define X264_B_PYRAMID_NORMAL 2 static const char * const x264_direct_pred_names[] = { "none", "spatial", "temporal", "auto", 0 }; static const char * const x264_motion_est_names[] = { "dia", "hex", "umh", "esa", "tesa", 0 }; +static const char * const x264_b_pyramid_names[] = { "none", "strict", "normal", 0 }; static const char * const x264_overscan_names[] = { "undef", "show", "crop", 0 }; static const char * const x264_vidformat_names[] = { "component", "pal", "ntsc", "secam", "mac", "undef", 0 }; static const char * const x264_fullrange_names[] = { "off", "on", 0 }; @@ -196,7 +200,7 @@ typedef struct x264_param_t int i_bframe; /* how many b-frame between 2 references pictures */ int i_bframe_adaptive; int i_bframe_bias; - int b_bframe_pyramid; /* Keep some B-frames as references */ + int i_bframe_pyramid; /* Keep some B-frames as references: 0=off, 1=strict heirarchical, 2=normal */ int b_deblocking_filter; int i_deblocking_filter_alphac0; /* [-6, 6] -6 light filter, 6 strong */ -- 2.40.0