diff --git a/common/common.c b/common/common.c index 64ba37a1fc9dca4127bfe87a597d7930f5c1b6b4..e771dc07fcf7b8aebba5837bb022a16abbe14b94 100644 --- a/common/common.c +++ b/common/common.c @@ -862,8 +862,11 @@ char *x264_slurp_file( const char *filename ) ****************************************************************************/ char *x264_param2string( x264_param_t *p, int b_res ) { - char *buf = x264_malloc( 1000 ); - char *s = buf; + int len = 1000; + char *buf, *s; + if( p->rc.psz_zones ) + len += strlen(p->rc.psz_zones); + buf = s = x264_malloc( len ); if( b_res ) { @@ -932,7 +935,9 @@ char *x264_param2string( x264_param_t *p, int b_res ) s += sprintf( s, " ip_ratio=%.2f", p->rc.f_ip_factor ); if( p->i_bframe ) s += sprintf( s, " pb_ratio=%.2f", p->rc.f_pb_factor ); - if( p->rc.i_zones ) + if( p->rc.psz_zones ) + s += sprintf( s, " zones=%s", p->rc.psz_zones ); + else if( p->rc.i_zones ) s += sprintf( s, " zones" ); } diff --git a/encoder/encoder.c b/encoder/encoder.c index 9723da63e57d44fe1a72d2c346374548f695e826..8917ae1ac6af79aae3696ccfaef718842b5e7dcb 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -757,10 +757,12 @@ int x264_encoder_reconfig( x264_t *h, x264_param_t *param ) COPY( analyse.b_dct_decimate ); COPY( analyse.b_fast_pskip ); COPY( analyse.b_mixed_references ); -#undef COPY - + // can only twiddle these if they were enabled to begin with: if( h->pps->b_transform_8x8_mode ) - h->param.analyse.b_transform_8x8 = param->analyse.b_transform_8x8; + COPY( analyse.b_transform_8x8 ); + if( h->frames.i_max_ref1 > 1 ) + COPY( b_bframe_pyramid ); +#undef COPY mbcmp_init( h ); diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index dce7d331badb07a7b7b6f023e469481182fa24c5..9b92dbeb55f41d5179254dd44126ded6025a8c90 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -144,6 +144,7 @@ struct x264_ratecontrol_t int i_zones; x264_zone_t *zones; + x264_zone_t *prev_zone; }; @@ -302,7 +303,10 @@ int x264_ratecontrol_new( x264_t *h ) *rc->pred_b_from_p = rc->pred[0]; if( parse_zones( h ) < 0 ) + { + x264_log( h, X264_LOG_ERROR, "failed to parse zones\n" ); return -1; + } /* Load stat file and init 2pass algo */ if( h->param.rc.b_stat_read ) @@ -475,34 +479,68 @@ int x264_ratecontrol_new( x264_t *h ) return 0; } +static int parse_zone( x264_t *h, x264_zone_t *z, char *p ) +{ + int len = 0; + char *tok, *saveptr; + z->param = NULL; + z->f_bitrate_factor = 1; + if( 3 <= sscanf(p, "%u,%u,q=%u%n", &z->i_start, &z->i_end, &z->i_qp, &len) ) + z->b_force_qp = 1; + else if( 3 <= sscanf(p, "%u,%u,b=%f%n", &z->i_start, &z->i_end, &z->f_bitrate_factor, &len) ) + z->b_force_qp = 0; + else if( 2 <= sscanf(p, "%u,%u%n", &z->i_start, &z->i_end, &len) ) + z->b_force_qp = 0; + else + { + x264_log( h, X264_LOG_ERROR, "invalid zone: \"%s\"\n", p ); + return -1; + } + p += len; + if( !*p ) + return 0; + z->param = malloc( sizeof(x264_param_t) ); + memcpy( z->param, &h->param, sizeof(x264_param_t) ); + while( (tok = strtok_r( p, ",", &saveptr )) ) + { + char *val = strchr( tok, '=' ); + if( val ) + { + *val = '\0'; + val++; + } + if( x264_param_parse( z->param, tok, val ) ) + { + x264_log( h, X264_LOG_ERROR, "invalid zone param: %s = %s\n", tok, val ); + return -1; + } + p = NULL; + } + return 0; +} + static int parse_zones( x264_t *h ) { x264_ratecontrol_t *rc = h->rc; int i; if( h->param.rc.psz_zones && !h->param.rc.i_zones ) { - char *p; + char *p, *tok, *saveptr; + char *psz_zones = x264_malloc( strlen(h->param.rc.psz_zones)+1 ); + strcpy( psz_zones, h->param.rc.psz_zones ); h->param.rc.i_zones = 1; - for( p = h->param.rc.psz_zones; *p; p++ ) + for( p = psz_zones; *p; p++ ) h->param.rc.i_zones += (*p == '/'); h->param.rc.zones = x264_malloc( h->param.rc.i_zones * sizeof(x264_zone_t) ); - p = h->param.rc.psz_zones; - for( i = 0; i < h->param.rc.i_zones; i++) + p = psz_zones; + for( i = 0; i < h->param.rc.i_zones; i++ ) { - x264_zone_t *z = &h->param.rc.zones[i]; - if( 3 == sscanf(p, "%u,%u,q=%u", &z->i_start, &z->i_end, &z->i_qp) ) - z->b_force_qp = 1; - else if( 3 == sscanf(p, "%u,%u,b=%f", &z->i_start, &z->i_end, &z->f_bitrate_factor) ) - z->b_force_qp = 0; - else - { - char *slash = strchr(p, '/'); - if(slash) *slash = '\0'; - x264_log( h, X264_LOG_ERROR, "invalid zone: \"%s\"\n", p ); + tok = strtok_r( p, "/", &saveptr ); + if( !tok || parse_zone( h, &h->param.rc.zones[i], tok ) ) return -1; - } - p = strchr(p, '/') + 1; + p = NULL; } + x264_free( psz_zones ); } if( h->param.rc.i_zones > 0 ) @@ -524,9 +562,22 @@ static int parse_zones( x264_t *h ) } } - rc->i_zones = h->param.rc.i_zones; + rc->i_zones = h->param.rc.i_zones + 1; rc->zones = x264_malloc( rc->i_zones * sizeof(x264_zone_t) ); - memcpy( rc->zones, h->param.rc.zones, rc->i_zones * sizeof(x264_zone_t) ); + memcpy( rc->zones+1, h->param.rc.zones, (rc->i_zones-1) * sizeof(x264_zone_t) ); + + // default zone to fall back to if none of the others match + rc->zones[0].i_start = 0; + rc->zones[0].i_end = INT_MAX; + rc->zones[0].b_force_qp = 0; + rc->zones[0].f_bitrate_factor = 1; + rc->zones[0].param = x264_malloc( sizeof(x264_param_t) ); + memcpy( rc->zones[0].param, &h->param, sizeof(x264_param_t) ); + for( i = 1; i < rc->i_zones; i++ ) + { + if( !rc->zones[i].param ) + rc->zones[i].param = rc->zones[0].param; + } } return 0; @@ -559,6 +610,7 @@ void x264_ratecontrol_summary( x264_t *h ) void x264_ratecontrol_delete( x264_t *h ) { x264_ratecontrol_t *rc = h->rc; + int i; if( rc->p_stat_file_out ) { @@ -574,7 +626,15 @@ void x264_ratecontrol_delete( x264_t *h ) x264_free( rc->pred ); x264_free( rc->pred_b_from_p ); x264_free( rc->entry ); - x264_free( rc->zones ); + if( rc->zones ) + { + x264_free( rc->zones[0].param ); + if( h->param.rc.psz_zones ) + for( i=1; ii_zones; i++ ) + if( rc->zones[i].param != rc->zones[0].param ) + x264_free( rc->zones[i].param ); + x264_free( rc->zones ); + } x264_free( rc ); } @@ -595,10 +655,15 @@ void x264_ratecontrol_start( x264_t *h, int i_force_qp ) { x264_ratecontrol_t *rc = h->rc; ratecontrol_entry_t *rce = NULL; + x264_zone_t *zone = get_zone( h, h->fenc->i_frame ); float q; x264_cpu_restore( h->param.cpu ); + if( zone && (!rc->prev_zone || zone->param != rc->prev_zone->param) ) + x264_encoder_reconfig( h, zone->param ); + rc->prev_zone = zone; + rc->qp_force = i_force_qp; if( h->param.rc.b_stat_read ) @@ -646,7 +711,6 @@ void x264_ratecontrol_start( x264_t *h, int i_force_qp ) } else /* CQP */ { - x264_zone_t *zone = get_zone( h, h->fenc->i_frame ); if( h->sh.i_type == SLICE_TYPE_B && h->fdec->b_kept_as_ref ) q = ( rc->qp_constant[ SLICE_TYPE_B ] + rc->qp_constant[ SLICE_TYPE_P ] ) / 2; else @@ -1384,6 +1448,7 @@ void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next ) COPY(short_term_cplxsum); COPY(short_term_cplxcount); COPY(bframes); + COPY(prev_zone); #undef COPY } if( cur != next ) diff --git a/encoder/set.c b/encoder/set.c index dba5571c1ade047098630d3fc59d55c6da23c4ee..200840b5cda5eb2eb12d967d2aefed0ae5b99bbc 100644 --- a/encoder/set.c +++ b/encoder/set.c @@ -479,14 +479,13 @@ void x264_sei_version_write( x264_t *h, bs_t *s ) 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, 0xef }; - char version[1200]; - int length; char *opts = x264_param2string( &h->param, 0 ); + char *version = x264_malloc( 200 + strlen(opts) ); + int length; sprintf( version, "x264 - core %d%s - H.264/MPEG-4 AVC codec - " "Copyleft 2005 - http://www.videolan.org/x264.html - options: %s", X264_BUILD, X264_VERSION, opts ); - x264_free( opts ); length = strlen(version)+1+16; bs_write( s, 8, 0x5 ); // payload_type = user_data_unregistered @@ -501,6 +500,9 @@ void x264_sei_version_write( x264_t *h, bs_t *s ) bs_write( s, 8, version[i] ); bs_rbsp_trailing( s ); + + x264_free( opts ); + x264_free( version ); } const x264_level_t x264_levels[] = diff --git a/x264.h b/x264.h index ae0e87dcad3037fe8cade8c3ae903f05ddfbc611..c5b16984140a3d2ae0c89b72ede91911a0015c9c 100644 --- a/x264.h +++ b/x264.h @@ -35,7 +35,7 @@ #include -#define X264_BUILD 55 +#define X264_BUILD 56 /* x264_t: * opaque handler for encoder */ @@ -122,15 +122,19 @@ static const char * const x264_colmatrix_names[] = { "GBR", "bt709", "undef", "" #define X264_LOG_INFO 2 #define X264_LOG_DEBUG 3 +/* Zones: override ratecontrol or other options for specific sections of the video. + * See x264_encoder_reconfig() for which options can be changed. + * If zones overlap, whichever comes later in the list takes precedence. */ typedef struct { - int i_start, i_end; - int b_force_qp; + int i_start, i_end; /* range of frame numbers */ + int b_force_qp; /* whether to use qp vs bitrate factor */ int i_qp; float f_bitrate_factor; + struct x264_param_t *param; } x264_zone_t; -typedef struct +typedef struct x264_param_t { /* CPU flags */ unsigned int cpu;