X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=common%2Fcommon.c;h=4b8f803a839e530fff09ec06571f5ba59f3b76d1;hb=dd6b7b974e0057da726f71e10c24d057a339605b;hp=aaccdf25158047d55777ae43cbbccdf454fa800b;hpb=50582675b0f20b923e629fb7e245900459e1e0b2;p=x264 diff --git a/common/common.c b/common/common.c index aaccdf25..4b8f803a 100644 --- a/common/common.c +++ b/common/common.c @@ -1,7 +1,7 @@ /***************************************************************************** - * common.c: h264 library + * common.c: misc common functions ***************************************************************************** - * Copyright (C) 2003-2008 x264 project + * Copyright (C) 2003-2016 x264 project * * Authors: Loren Merritt * Laurent Aimar @@ -19,24 +19,33 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + * + * This program is also available under a commercial proprietary license. + * For more information, contact us at licensing@x264.com. *****************************************************************************/ #include "common.h" -#include "cpu.h" #include #include -#ifdef HAVE_MALLOC_H +#if HAVE_MALLOC_H #include #endif +#if HAVE_THP +#include +#endif + +const int x264_bit_depth = BIT_DEPTH; + +const int x264_chroma_format = X264_CHROMA_FORMAT; static void x264_log_default( void *, int, const char *, va_list ); /**************************************************************************** * x264_param_default: ****************************************************************************/ -void x264_param_default( x264_param_t *param ) +void x264_param_default( x264_param_t *param ) { /* */ memset( param, 0, sizeof( x264_param_t ) ); @@ -44,21 +53,22 @@ void x264_param_default( x264_param_t *param ) /* CPU autodetect */ param->cpu = x264_cpu_detect(); param->i_threads = X264_THREADS_AUTO; + param->i_lookahead_threads = X264_THREADS_AUTO; param->b_deterministic = 1; param->i_sync_lookahead = X264_SYNC_LOOKAHEAD_AUTO; /* Video properties */ - param->i_csp = X264_CSP_I420; + param->i_csp = X264_CHROMA_FORMAT ? X264_CHROMA_FORMAT : X264_CSP_I420; param->i_width = 0; param->i_height = 0; param->vui.i_sar_width = 0; param->vui.i_sar_height= 0; param->vui.i_overscan = 0; /* undef */ param->vui.i_vidformat = 5; /* undef */ - param->vui.b_fullrange = 0; /* off */ + param->vui.b_fullrange = -1; /* default depends on input */ param->vui.i_colorprim = 2; /* undef */ param->vui.i_transfer = 2; /* undef */ - param->vui.i_colmatrix = 2; /* undef */ + param->vui.i_colmatrix = -1; /* default depends on input */ param->vui.i_chroma_loc= 0; /* left center */ param->i_fps_num = 25; param->i_fps_den = 1; @@ -70,12 +80,12 @@ void x264_param_default( x264_param_t *param ) /* Encoder parameters */ param->i_frame_reference = 3; param->i_keyint_max = 250; - param->i_keyint_min = 25; + param->i_keyint_min = X264_KEYINT_MIN_AUTO; param->i_bframe = 3; param->i_scenecut_threshold = 40; param->i_bframe_adaptive = X264_B_ADAPT_FAST; param->i_bframe_bias = 0; - param->i_bframe_pyramid = 0; + param->i_bframe_pyramid = X264_B_PYRAMID_NORMAL; param->b_interlaced = 0; param->b_constrained_intra = 0; @@ -92,10 +102,10 @@ void x264_param_default( x264_param_t *param ) param->rc.i_vbv_max_bitrate = 0; param->rc.i_vbv_buffer_size = 0; param->rc.f_vbv_buffer_init = 0.9; - param->rc.i_qp_constant = 23; + param->rc.i_qp_constant = 23 + QP_BD_OFFSET; param->rc.f_rf_constant = 23; - param->rc.i_qp_min = 10; - param->rc.i_qp_max = 51; + param->rc.i_qp_min = 0; + param->rc.i_qp_max = QP_MAX; param->rc.i_qp_step = 4; param->rc.f_ip_factor = 1.4; param->rc.f_pb_factor = 1.3; @@ -146,25 +156,368 @@ void x264_param_default( x264_param_t *param ) param->analyse.b_ssim = 0; param->i_cqm_preset = X264_CQM_FLAT; - memset( param->cqm_4iy, 16, 16 ); - memset( param->cqm_4ic, 16, 16 ); - memset( param->cqm_4py, 16, 16 ); - memset( param->cqm_4pc, 16, 16 ); - memset( param->cqm_8iy, 16, 64 ); - memset( param->cqm_8py, 16, 64 ); + memset( param->cqm_4iy, 16, sizeof( param->cqm_4iy ) ); + memset( param->cqm_4py, 16, sizeof( param->cqm_4py ) ); + memset( param->cqm_4ic, 16, sizeof( param->cqm_4ic ) ); + memset( param->cqm_4pc, 16, sizeof( param->cqm_4pc ) ); + memset( param->cqm_8iy, 16, sizeof( param->cqm_8iy ) ); + memset( param->cqm_8py, 16, sizeof( param->cqm_8py ) ); + memset( param->cqm_8ic, 16, sizeof( param->cqm_8ic ) ); + memset( param->cqm_8pc, 16, sizeof( param->cqm_8pc ) ); param->b_repeat_headers = 1; param->b_annexb = 1; param->b_aud = 0; param->b_vfr_input = 1; - param->b_dts_compress = 0; + param->i_nal_hrd = X264_NAL_HRD_NONE; + param->b_tff = 1; + param->b_pic_struct = 0; + param->b_fake_interlaced = 0; + param->i_frame_packing = -1; + param->b_opencl = 0; + param->i_opencl_device = 0; + param->opencl_device_id = NULL; + param->psz_clbin_file = NULL; +} + +static int x264_param_apply_preset( x264_param_t *param, const char *preset ) +{ + char *end; + int i = strtol( preset, &end, 10 ); + if( *end == 0 && i >= 0 && i < sizeof(x264_preset_names)/sizeof(*x264_preset_names)-1 ) + preset = x264_preset_names[i]; + + if( !strcasecmp( preset, "ultrafast" ) ) + { + param->i_frame_reference = 1; + param->i_scenecut_threshold = 0; + param->b_deblocking_filter = 0; + param->b_cabac = 0; + param->i_bframe = 0; + param->analyse.intra = 0; + param->analyse.inter = 0; + param->analyse.b_transform_8x8 = 0; + param->analyse.i_me_method = X264_ME_DIA; + param->analyse.i_subpel_refine = 0; + param->rc.i_aq_mode = 0; + param->analyse.b_mixed_references = 0; + param->analyse.i_trellis = 0; + param->i_bframe_adaptive = X264_B_ADAPT_NONE; + param->rc.b_mb_tree = 0; + param->analyse.i_weighted_pred = X264_WEIGHTP_NONE; + param->analyse.b_weighted_bipred = 0; + param->rc.i_lookahead = 0; + } + else if( !strcasecmp( preset, "superfast" ) ) + { + param->analyse.inter = X264_ANALYSE_I8x8|X264_ANALYSE_I4x4; + param->analyse.i_me_method = X264_ME_DIA; + param->analyse.i_subpel_refine = 1; + param->i_frame_reference = 1; + param->analyse.b_mixed_references = 0; + param->analyse.i_trellis = 0; + param->rc.b_mb_tree = 0; + param->analyse.i_weighted_pred = X264_WEIGHTP_SIMPLE; + param->rc.i_lookahead = 0; + } + else if( !strcasecmp( preset, "veryfast" ) ) + { + param->analyse.i_me_method = X264_ME_HEX; + param->analyse.i_subpel_refine = 2; + param->i_frame_reference = 1; + param->analyse.b_mixed_references = 0; + param->analyse.i_trellis = 0; + param->analyse.i_weighted_pred = X264_WEIGHTP_SIMPLE; + param->rc.i_lookahead = 10; + } + else if( !strcasecmp( preset, "faster" ) ) + { + param->analyse.b_mixed_references = 0; + param->i_frame_reference = 2; + param->analyse.i_subpel_refine = 4; + param->analyse.i_weighted_pred = X264_WEIGHTP_SIMPLE; + param->rc.i_lookahead = 20; + } + else if( !strcasecmp( preset, "fast" ) ) + { + param->i_frame_reference = 2; + param->analyse.i_subpel_refine = 6; + param->analyse.i_weighted_pred = X264_WEIGHTP_SIMPLE; + param->rc.i_lookahead = 30; + } + else if( !strcasecmp( preset, "medium" ) ) + { + /* Default is medium */ + } + else if( !strcasecmp( preset, "slow" ) ) + { + param->analyse.i_me_method = X264_ME_UMH; + param->analyse.i_subpel_refine = 8; + param->i_frame_reference = 5; + param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS; + param->analyse.i_direct_mv_pred = X264_DIRECT_PRED_AUTO; + param->rc.i_lookahead = 50; + } + else if( !strcasecmp( preset, "slower" ) ) + { + param->analyse.i_me_method = X264_ME_UMH; + param->analyse.i_subpel_refine = 9; + param->i_frame_reference = 8; + param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS; + param->analyse.i_direct_mv_pred = X264_DIRECT_PRED_AUTO; + param->analyse.inter |= X264_ANALYSE_PSUB8x8; + param->analyse.i_trellis = 2; + param->rc.i_lookahead = 60; + } + else if( !strcasecmp( preset, "veryslow" ) ) + { + param->analyse.i_me_method = X264_ME_UMH; + param->analyse.i_subpel_refine = 10; + param->analyse.i_me_range = 24; + param->i_frame_reference = 16; + param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS; + param->analyse.i_direct_mv_pred = X264_DIRECT_PRED_AUTO; + param->analyse.inter |= X264_ANALYSE_PSUB8x8; + param->analyse.i_trellis = 2; + param->i_bframe = 8; + param->rc.i_lookahead = 60; + } + else if( !strcasecmp( preset, "placebo" ) ) + { + param->analyse.i_me_method = X264_ME_TESA; + param->analyse.i_subpel_refine = 11; + param->analyse.i_me_range = 24; + param->i_frame_reference = 16; + param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS; + param->analyse.i_direct_mv_pred = X264_DIRECT_PRED_AUTO; + param->analyse.inter |= X264_ANALYSE_PSUB8x8; + param->analyse.b_fast_pskip = 0; + param->analyse.i_trellis = 2; + param->i_bframe = 16; + param->rc.i_lookahead = 60; + } + else + { + x264_log( NULL, X264_LOG_ERROR, "invalid preset '%s'\n", preset ); + return -1; + } + return 0; +} + +static int x264_param_apply_tune( x264_param_t *param, const char *tune ) +{ + char *tmp = x264_malloc( strlen( tune ) + 1 ); + if( !tmp ) + return -1; + tmp = strcpy( tmp, tune ); + char *s = strtok( tmp, ",./-+" ); + int psy_tuning_used = 0; + while( s ) + { + if( !strncasecmp( s, "film", 4 ) ) + { + if( psy_tuning_used++ ) goto psy_failure; + param->i_deblocking_filter_alphac0 = -1; + param->i_deblocking_filter_beta = -1; + param->analyse.f_psy_trellis = 0.15; + } + else if( !strncasecmp( s, "animation", 9 ) ) + { + if( psy_tuning_used++ ) goto psy_failure; + param->i_frame_reference = param->i_frame_reference > 1 ? param->i_frame_reference*2 : 1; + param->i_deblocking_filter_alphac0 = 1; + param->i_deblocking_filter_beta = 1; + param->analyse.f_psy_rd = 0.4; + param->rc.f_aq_strength = 0.6; + param->i_bframe += 2; + } + else if( !strncasecmp( s, "grain", 5 ) ) + { + if( psy_tuning_used++ ) goto psy_failure; + param->i_deblocking_filter_alphac0 = -2; + param->i_deblocking_filter_beta = -2; + param->analyse.f_psy_trellis = 0.25; + param->analyse.b_dct_decimate = 0; + param->rc.f_pb_factor = 1.1; + param->rc.f_ip_factor = 1.1; + param->rc.f_aq_strength = 0.5; + param->analyse.i_luma_deadzone[0] = 6; + param->analyse.i_luma_deadzone[1] = 6; + param->rc.f_qcompress = 0.8; + } + else if( !strncasecmp( s, "stillimage", 10 ) ) + { + if( psy_tuning_used++ ) goto psy_failure; + param->i_deblocking_filter_alphac0 = -3; + param->i_deblocking_filter_beta = -3; + param->analyse.f_psy_rd = 2.0; + param->analyse.f_psy_trellis = 0.7; + param->rc.f_aq_strength = 1.2; + } + else if( !strncasecmp( s, "psnr", 4 ) ) + { + if( psy_tuning_used++ ) goto psy_failure; + param->rc.i_aq_mode = X264_AQ_NONE; + param->analyse.b_psy = 0; + } + else if( !strncasecmp( s, "ssim", 4 ) ) + { + if( psy_tuning_used++ ) goto psy_failure; + param->rc.i_aq_mode = X264_AQ_AUTOVARIANCE; + param->analyse.b_psy = 0; + } + else if( !strncasecmp( s, "fastdecode", 10 ) ) + { + param->b_deblocking_filter = 0; + param->b_cabac = 0; + param->analyse.b_weighted_bipred = 0; + param->analyse.i_weighted_pred = X264_WEIGHTP_NONE; + } + else if( !strncasecmp( s, "zerolatency", 11 ) ) + { + param->rc.i_lookahead = 0; + param->i_sync_lookahead = 0; + param->i_bframe = 0; + param->b_sliced_threads = 1; + param->b_vfr_input = 0; + param->rc.b_mb_tree = 0; + } + else if( !strncasecmp( s, "touhou", 6 ) ) + { + if( psy_tuning_used++ ) goto psy_failure; + param->i_frame_reference = param->i_frame_reference > 1 ? param->i_frame_reference*2 : 1; + param->i_deblocking_filter_alphac0 = -1; + param->i_deblocking_filter_beta = -1; + param->analyse.f_psy_trellis = 0.2; + param->rc.f_aq_strength = 1.3; + if( param->analyse.inter & X264_ANALYSE_PSUB16x16 ) + param->analyse.inter |= X264_ANALYSE_PSUB8x8; + } + else + { + x264_log( NULL, X264_LOG_ERROR, "invalid tune '%s'\n", s ); + x264_free( tmp ); + return -1; + } + if( 0 ) + { + psy_failure: + x264_log( NULL, X264_LOG_WARNING, "only 1 psy tuning can be used: ignoring tune %s\n", s ); + } + s = strtok( NULL, ",./-+" ); + } + x264_free( tmp ); + return 0; +} + +int x264_param_default_preset( x264_param_t *param, const char *preset, const char *tune ) +{ + x264_param_default( param ); + + if( preset && x264_param_apply_preset( param, preset ) < 0 ) + return -1; + if( tune && x264_param_apply_tune( param, tune ) < 0 ) + return -1; + return 0; +} + +void x264_param_apply_fastfirstpass( x264_param_t *param ) +{ + /* Set faster options in case of turbo firstpass. */ + if( param->rc.b_stat_write && !param->rc.b_stat_read ) + { + param->i_frame_reference = 1; + param->analyse.b_transform_8x8 = 0; + param->analyse.inter = 0; + param->analyse.i_me_method = X264_ME_DIA; + param->analyse.i_subpel_refine = X264_MIN( 2, param->analyse.i_subpel_refine ); + param->analyse.i_trellis = 0; + param->analyse.b_fast_pskip = 1; + } +} + +static int profile_string_to_int( const char *str ) +{ + if( !strcasecmp( str, "baseline" ) ) + return PROFILE_BASELINE; + if( !strcasecmp( str, "main" ) ) + return PROFILE_MAIN; + if( !strcasecmp( str, "high" ) ) + return PROFILE_HIGH; + if( !strcasecmp( str, "high10" ) ) + return PROFILE_HIGH10; + if( !strcasecmp( str, "high422" ) ) + return PROFILE_HIGH422; + if( !strcasecmp( str, "high444" ) ) + return PROFILE_HIGH444_PREDICTIVE; + return -1; +} + +int x264_param_apply_profile( x264_param_t *param, const char *profile ) +{ + if( !profile ) + return 0; + + int p = profile_string_to_int( profile ); + if( p < 0 ) + { + x264_log( NULL, X264_LOG_ERROR, "invalid profile: %s\n", profile ); + return -1; + } + if( p < PROFILE_HIGH444_PREDICTIVE && ((param->rc.i_rc_method == X264_RC_CQP && param->rc.i_qp_constant <= 0) || + (param->rc.i_rc_method == X264_RC_CRF && (int)(param->rc.f_rf_constant + QP_BD_OFFSET) <= 0)) ) + { + x264_log( NULL, X264_LOG_ERROR, "%s profile doesn't support lossless\n", profile ); + return -1; + } + if( p < PROFILE_HIGH444_PREDICTIVE && (param->i_csp & X264_CSP_MASK) >= X264_CSP_I444 ) + { + x264_log( NULL, X264_LOG_ERROR, "%s profile doesn't support 4:4:4\n", profile ); + return -1; + } + if( p < PROFILE_HIGH422 && (param->i_csp & X264_CSP_MASK) >= X264_CSP_I422 ) + { + x264_log( NULL, X264_LOG_ERROR, "%s profile doesn't support 4:2:2\n", profile ); + return -1; + } + if( p < PROFILE_HIGH10 && BIT_DEPTH > 8 ) + { + x264_log( NULL, X264_LOG_ERROR, "%s profile doesn't support a bit depth of %d\n", profile, BIT_DEPTH ); + return -1; + } + + if( p == PROFILE_BASELINE ) + { + param->analyse.b_transform_8x8 = 0; + param->b_cabac = 0; + param->i_cqm_preset = X264_CQM_FLAT; + param->psz_cqm_file = NULL; + param->i_bframe = 0; + param->analyse.i_weighted_pred = X264_WEIGHTP_NONE; + if( param->b_interlaced ) + { + x264_log( NULL, X264_LOG_ERROR, "baseline profile doesn't support interlacing\n" ); + return -1; + } + if( param->b_fake_interlaced ) + { + x264_log( NULL, X264_LOG_ERROR, "baseline profile doesn't support fake interlacing\n" ); + return -1; + } + } + else if( p == PROFILE_MAIN ) + { + param->analyse.b_transform_8x8 = 0; + param->i_cqm_preset = X264_CQM_FLAT; + param->psz_cqm_file = NULL; + } + return 0; } static int parse_enum( const char *arg, const char * const *names, int *dst ) { - int i; - for( i = 0; names[i]; i++ ) - if( !strcmp( arg, names[i] ) ) + for( int i = 0; names[i]; i++ ) + if( !strcasecmp( arg, names[i] ) ) { *dst = i; return 0; @@ -187,12 +540,12 @@ static int parse_cqm( const char *str, uint8_t *cqm, int length ) static int x264_atobool( const char *str, int *b_error ) { if( !strcmp(str, "1") || - !strcmp(str, "true") || - !strcmp(str, "yes") ) + !strcasecmp(str, "true") || + !strcasecmp(str, "yes") ) return 1; if( !strcmp(str, "0") || - !strcmp(str, "false") || - !strcmp(str, "no") ) + !strcasecmp(str, "false") || + !strcasecmp(str, "no") ) return 0; *b_error = 1; return 0; @@ -217,6 +570,8 @@ static double x264_atof( const char *str, int *b_error ) } #define atobool(str) ( name_was_bool = 1, x264_atobool( str, &b_error ) ) +#undef atoi +#undef atof #define atoi(str) x264_atoi( str, &b_error ) #define atof(str) x264_atof( str, &b_error ) @@ -224,9 +579,9 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) { char *name_buf = NULL; int b_error = 0; + int errortype = X264_PARAM_BAD_VALUE; int name_was_bool; int value_was_null = !value; - int i; if( !name ) return X264_PARAM_BAD_NAME; @@ -238,17 +593,20 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) if( strchr( name, '_' ) ) // s/_/-/g { - char *p; + char *c; name_buf = strdup(name); - while( (p = strchr( name_buf, '_' )) ) - *p = '-'; + if( !name_buf ) + return X264_PARAM_BAD_NAME; + while( (c = strchr( name_buf, '_' )) ) + *c = '-'; name = name_buf; } - if( (!strncmp( name, "no-", 3 ) && (i = 3)) || - (!strncmp( name, "no", 2 ) && (i = 2)) ) + if( !strncmp( name, "no", 2 ) ) { - name += i; + name += 2; + if( name[0] == '-' ) + name++; value = atobool(value) ? "false" : "true"; } name_was_bool = 0; @@ -259,48 +617,70 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) OPT("asm") { p->cpu = isdigit(value[0]) ? atoi(value) : - !strcmp(value, "auto") || atobool(value) ? x264_cpu_detect() : 0; + !strcasecmp(value, "auto") || atobool(value) ? x264_cpu_detect() : 0; if( b_error ) { - char *buf = strdup(value); - char *tok, UNUSED *saveptr=NULL, *init; - b_error = 0; - p->cpu = 0; - for( init=buf; (tok=strtok_r(init, ",", &saveptr)); init=NULL ) + char *buf = strdup( value ); + if( buf ) { - for( i=0; x264_cpu_names[i].flags && strcasecmp(tok, x264_cpu_names[i].name); i++ ); - p->cpu |= x264_cpu_names[i].flags; - if( !x264_cpu_names[i].flags ) - b_error = 1; + char *tok, UNUSED *saveptr=NULL, *init; + b_error = 0; + p->cpu = 0; + for( init=buf; (tok=strtok_r(init, ",", &saveptr)); init=NULL ) + { + int i = 0; + while( x264_cpu_names[i].flags && strcasecmp(tok, x264_cpu_names[i].name) ) + i++; + p->cpu |= x264_cpu_names[i].flags; + if( !x264_cpu_names[i].flags ) + b_error = 1; + } + free( buf ); + if( (p->cpu&X264_CPU_SSSE3) && !(p->cpu&X264_CPU_SSE2_IS_SLOW) ) + p->cpu |= X264_CPU_SSE2_IS_FAST; } - free( buf ); } } OPT("threads") { - if( !strcmp(value, "auto") ) + if( !strcasecmp(value, "auto") ) p->i_threads = X264_THREADS_AUTO; else p->i_threads = atoi(value); } + OPT("lookahead-threads") + { + if( !strcasecmp(value, "auto") ) + p->i_lookahead_threads = X264_THREADS_AUTO; + else + p->i_lookahead_threads = atoi(value); + } OPT("sliced-threads") p->b_sliced_threads = atobool(value); OPT("sync-lookahead") { - if( !strcmp(value, "auto") ) + if( !strcasecmp(value, "auto") ) p->i_sync_lookahead = X264_SYNC_LOOKAHEAD_AUTO; else p->i_sync_lookahead = atoi(value); } OPT2("deterministic", "n-deterministic") p->b_deterministic = atobool(value); + OPT("cpu-independent") + p->b_cpu_independent = atobool(value); OPT2("level", "level-idc") { - if( atof(value) < 6 ) + if( !strcmp(value, "1b") ) + p->i_level_idc = 9; + else if( atof(value) < 6 ) p->i_level_idc = (int)(10*atof(value)+.5); else p->i_level_idc = atoi(value); } + OPT("bluray-compat") + p->b_bluray_compat = atobool(value); + OPT("avcintra-class") + p->i_avcintra_class = atoi(value); OPT("sar") { b_error = ( 2 != sscanf( value, "%d:%d", &p->vui.i_sar_width, &p->vui.i_sar_height ) && @@ -325,22 +705,31 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) } OPT("fps") { - if( sscanf( value, "%d/%d", &p->i_fps_num, &p->i_fps_den ) == 2 ) - ; - else + if( sscanf( value, "%u/%u", &p->i_fps_num, &p->i_fps_den ) != 2 ) { - float fps = atof(value); - p->i_fps_num = (int)(fps * 1000 + .5); - p->i_fps_den = 1000; + double fps = atof(value); + if( fps > 0.0 && fps <= INT_MAX/1000.0 ) + { + p->i_fps_num = (int)(fps * 1000.0 + .5); + p->i_fps_den = 1000; + } + else + { + p->i_fps_num = atoi(value); + p->i_fps_den = 1; + } } } OPT2("ref", "frameref") p->i_frame_reference = atoi(value); + OPT("dpb-size") + p->i_dpb_size = atoi(value); OPT("keyint") { - p->i_keyint_max = atoi(value); - if( p->i_keyint_min > p->i_keyint_max ) - p->i_keyint_min = p->i_keyint_max; + if( strstr( value, "infinite" ) ) + p->i_keyint_max = X264_KEYINT_MAX_INFINITE; + else + p->i_keyint_max = atoi(value); } OPT2("min-keyint", "keyint-min") { @@ -373,7 +762,16 @@ 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") + { b_error |= parse_enum( value, x264_b_pyramid_names, &p->i_bframe_pyramid ); + if( b_error ) + { + b_error = 0; + p->i_bframe_pyramid = atoi(value); + } + } + OPT("open-gop") + p->b_open_gop = atobool(value); OPT("nf") p->b_deblocking_filter = !atobool(value); OPT2("filter", "deblock") @@ -395,14 +793,25 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) p->i_slice_max_size = atoi(value); OPT("slice-max-mbs") p->i_slice_max_mbs = atoi(value); + OPT("slice-min-mbs") + p->i_slice_min_mbs = atoi(value); OPT("slices") p->i_slice_count = atoi(value); + OPT("slices-max") + p->i_slice_count_max = atoi(value); OPT("cabac") p->b_cabac = atobool(value); OPT("cabac-idc") p->i_cabac_init_idc = atoi(value); OPT("interlaced") p->b_interlaced = atobool(value); + OPT("tff") + p->b_interlaced = p->b_tff = 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") @@ -420,8 +829,8 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) { p->i_cqm_preset = X264_CQM_CUSTOM; b_error |= parse_cqm( value, p->cqm_4iy, 16 ); - b_error |= parse_cqm( value, p->cqm_4ic, 16 ); b_error |= parse_cqm( value, p->cqm_4py, 16 ); + b_error |= parse_cqm( value, p->cqm_4ic, 16 ); b_error |= parse_cqm( value, p->cqm_4pc, 16 ); } OPT("cqm8") @@ -429,6 +838,8 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) p->i_cqm_preset = X264_CQM_CUSTOM; b_error |= parse_cqm( value, p->cqm_8iy, 64 ); b_error |= parse_cqm( value, p->cqm_8py, 64 ); + b_error |= parse_cqm( value, p->cqm_8ic, 64 ); + b_error |= parse_cqm( value, p->cqm_8pc, 64 ); } OPT("cqm4i") { @@ -466,18 +877,16 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) { p->i_cqm_preset = X264_CQM_CUSTOM; b_error |= parse_cqm( value, p->cqm_8iy, 64 ); + b_error |= parse_cqm( value, p->cqm_8ic, 64 ); } OPT("cqm8p") { p->i_cqm_preset = X264_CQM_CUSTOM; b_error |= parse_cqm( value, p->cqm_8py, 64 ); + b_error |= parse_cqm( value, p->cqm_8pc, 64 ); } OPT("log") p->i_log_level = atoi(value); -#ifdef HAVE_VISUALIZE - OPT("visualize") - p->b_visualize = atobool(value); -#endif OPT("dump-yuv") p->psz_dump_yuv = strdup(value); OPT2("analyse", "partitions") @@ -515,7 +924,8 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) OPT("psy-rd") { if( 2 == sscanf( value, "%f:%f", &p->analyse.f_psy_rd, &p->analyse.f_psy_trellis ) || - 2 == sscanf( value, "%f,%f", &p->analyse.f_psy_rd, &p->analyse.f_psy_trellis ) ) + 2 == sscanf( value, "%f,%f", &p->analyse.f_psy_rd, &p->analyse.f_psy_trellis ) || + 2 == sscanf( value, "%f|%f", &p->analyse.f_psy_rd, &p->analyse.f_psy_trellis )) { } else if( sscanf( value, "%f", &p->analyse.f_psy_rd ) ) { @@ -560,6 +970,8 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) p->rc.f_rf_constant = atof(value); p->rc.i_rc_method = X264_RC_CRF; } + OPT("crf-max") + p->rc.f_rf_constant_max = atof(value); OPT("rc-lookahead") p->rc.i_lookahead = atoi(value); OPT2("qpmin", "qp-min") @@ -586,9 +998,9 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) p->rc.f_aq_strength = atof(value); OPT("pass") { - int i = x264_clip3( atoi(value), 0, 3 ); - p->rc.b_stat_write = i & 1; - p->rc.b_stat_read = i & 2; + int pass = x264_clip3( atoi(value), 0, 3 ); + p->rc.b_stat_write = pass & 1; + p->rc.b_stat_read = pass & 2; } OPT("stats") { @@ -605,6 +1017,9 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) p->rc.f_complexity_blur = atof(value); OPT("zones") p->rc.psz_zones = strdup(value); + OPT("crop-rect") + b_error |= sscanf( value, "%u,%u,%u,%u", &p->crop_rect.i_left, &p->crop_rect.i_top, + &p->crop_rect.i_right, &p->crop_rect.i_bottom ) != 4; OPT("psnr") p->analyse.b_psnr = atobool(value); OPT("ssim") @@ -621,8 +1036,29 @@ 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") + b_error |= parse_enum( value, x264_nal_hrd_names, &p->i_nal_hrd ); + OPT("filler") + p->rc.b_filler = atobool(value); + OPT("pic-struct") + p->b_pic_struct = atobool(value); + OPT("fake-interlaced") + p->b_fake_interlaced = atobool(value); + OPT("frame-packing") + p->i_frame_packing = atoi(value); + OPT("stitchable") + p->b_stitchable = atobool(value); + OPT("opencl") + p->b_opencl = atobool( value ); + OPT("opencl-clbin") + p->psz_clbin_file = strdup( value ); + OPT("opencl-device") + p->i_opencl_device = atoi( value ); else - return X264_PARAM_BAD_NAME; + { + b_error = 1; + errortype = X264_PARAM_BAD_NAME; + } #undef OPT #undef OPT2 #undef atobool @@ -633,7 +1069,7 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) free( name_buf ); b_error |= value_was_null && !name_was_bool; - return b_error ? X264_PARAM_BAD_VALUE : 0; + return b_error ? errortype : 0; } /**************************************************************************** @@ -675,7 +1111,18 @@ static void x264_log_default( void *p_unused, int i_level, const char *psz_fmt, break; } fprintf( stderr, "x264 [%s]: ", psz_prefix ); - vfprintf( stderr, psz_fmt, arg ); + x264_vfprintf( stderr, psz_fmt, arg ); +} + +/**************************************************************************** + * x264_picture_init: + ****************************************************************************/ +void x264_picture_init( x264_picture_t *pic ) +{ + memset( pic, 0, sizeof( x264_picture_t ) ); + pic->i_type = X264_TYPE_AUTO; + pic->i_qpplus1 = X264_QP_AUTO; + pic->i_pic_struct = PIC_STRUCT_AUTO; } /**************************************************************************** @@ -683,19 +1130,51 @@ static void x264_log_default( void *p_unused, int i_level, const char *psz_fmt, ****************************************************************************/ int x264_picture_alloc( x264_picture_t *pic, int i_csp, int i_width, int i_height ) { - pic->i_type = X264_TYPE_AUTO; - pic->i_qpplus1 = 0; + typedef struct + { + int planes; + int width_fix8[3]; + int height_fix8[3]; + } x264_csp_tab_t; + + static const x264_csp_tab_t x264_csp_tab[] = + { + [X264_CSP_I420] = { 3, { 256*1, 256/2, 256/2 }, { 256*1, 256/2, 256/2 } }, + [X264_CSP_YV12] = { 3, { 256*1, 256/2, 256/2 }, { 256*1, 256/2, 256/2 } }, + [X264_CSP_NV12] = { 2, { 256*1, 256*1 }, { 256*1, 256/2 }, }, + [X264_CSP_NV21] = { 2, { 256*1, 256*1 }, { 256*1, 256/2 }, }, + [X264_CSP_I422] = { 3, { 256*1, 256/2, 256/2 }, { 256*1, 256*1, 256*1 } }, + [X264_CSP_YV16] = { 3, { 256*1, 256/2, 256/2 }, { 256*1, 256*1, 256*1 } }, + [X264_CSP_NV16] = { 2, { 256*1, 256*1 }, { 256*1, 256*1 }, }, + [X264_CSP_I444] = { 3, { 256*1, 256*1, 256*1 }, { 256*1, 256*1, 256*1 } }, + [X264_CSP_YV24] = { 3, { 256*1, 256*1, 256*1 }, { 256*1, 256*1, 256*1 } }, + [X264_CSP_BGR] = { 1, { 256*3 }, { 256*1 }, }, + [X264_CSP_BGRA] = { 1, { 256*4 }, { 256*1 }, }, + [X264_CSP_RGB] = { 1, { 256*3 }, { 256*1 }, }, + }; + + int csp = i_csp & X264_CSP_MASK; + if( csp <= X264_CSP_NONE || csp >= X264_CSP_MAX || csp == X264_CSP_V210 ) + return -1; + x264_picture_init( pic ); pic->img.i_csp = i_csp; - pic->img.i_plane = 3; - pic->img.plane[0] = x264_malloc( 3 * i_width * i_height / 2 ); + pic->img.i_plane = x264_csp_tab[csp].planes; + int depth_factor = i_csp & X264_CSP_HIGH_DEPTH ? 2 : 1; + int plane_offset[3] = {0}; + int frame_size = 0; + for( int i = 0; i < pic->img.i_plane; i++ ) + { + int stride = (((int64_t)i_width * x264_csp_tab[csp].width_fix8[i]) >> 8) * depth_factor; + int plane_size = (((int64_t)i_height * x264_csp_tab[csp].height_fix8[i]) >> 8) * stride; + pic->img.i_stride[i] = stride; + plane_offset[i] = frame_size; + frame_size += plane_size; + } + pic->img.plane[0] = x264_malloc( frame_size ); if( !pic->img.plane[0] ) return -1; - pic->img.plane[1] = pic->img.plane[0] + i_width * i_height; - pic->img.plane[2] = pic->img.plane[1] + i_width * i_height / 4; - pic->img.i_stride[0] = i_width; - pic->img.i_stride[1] = i_width / 2; - pic->img.i_stride[2] = i_width / 2; - pic->param = NULL; + for( int i = 1; i < pic->img.i_plane; i++ ) + pic->img.plane[i] = pic->img.plane[0] + plane_offset[i]; return 0; } @@ -711,78 +1190,38 @@ void x264_picture_clean( x264_picture_t *pic ) } /**************************************************************************** - * x264_nal_encode: + * x264_malloc: ****************************************************************************/ -int x264_nal_encode( uint8_t *dst, int b_annexb, x264_nal_t *nal ) +void *x264_malloc( int i_size ) { - uint8_t *src = nal->p_payload; - uint8_t *end = nal->p_payload + nal->i_payload; - uint8_t *orig_dst = dst; - int i_count = 0, size; - - /* long nal start code (we always use long ones) */ - if( b_annexb ) - { - *dst++ = 0x00; - *dst++ = 0x00; - *dst++ = 0x00; - *dst++ = 0x01; - } - else /* save room for size later */ - dst += 4; - - /* nal header */ - *dst++ = ( 0x00 << 7 ) | ( nal->i_ref_idc << 5 ) | nal->i_type; - - while( src < end ) + uint8_t *align_buf = NULL; +#if HAVE_MALLOC_H +#if HAVE_THP +#define HUGE_PAGE_SIZE 2*1024*1024 +#define HUGE_PAGE_THRESHOLD HUGE_PAGE_SIZE*7/8 /* FIXME: Is this optimal? */ + /* Attempt to allocate huge pages to reduce TLB misses. */ + if( i_size >= HUGE_PAGE_THRESHOLD ) { - if( i_count == 2 && *src <= 0x03 ) + align_buf = memalign( HUGE_PAGE_SIZE, i_size ); + if( align_buf ) { - *dst++ = 0x03; - i_count = 0; + /* Round up to the next huge page boundary if we are close enough. */ + size_t madv_size = (i_size + HUGE_PAGE_SIZE - HUGE_PAGE_THRESHOLD) & ~(HUGE_PAGE_SIZE-1); + madvise( align_buf, madv_size, MADV_HUGEPAGE ); } - if( *src == 0 ) - i_count++; - else - i_count = 0; - *dst++ = *src++; } - size = (dst - orig_dst) - 4; - - /* Write the size header for mp4/etc */ - if( !b_annexb ) - { - /* Size doesn't include the size of the header we're writing now. */ - orig_dst[0] = size>>24; - orig_dst[1] = size>>16; - orig_dst[2] = size>> 8; - orig_dst[3] = size>> 0; - } - - return size+4; -} - - - -/**************************************************************************** - * x264_malloc: - ****************************************************************************/ -void *x264_malloc( int i_size ) -{ - uint8_t *align_buf = NULL; -#ifdef SYS_MACOSX - /* Mac OS X always returns 16 bytes aligned memory */ - align_buf = malloc( i_size ); -#elif defined( HAVE_MALLOC_H ) - align_buf = memalign( 16, i_size ); + else +#undef HUGE_PAGE_SIZE +#undef HUGE_PAGE_THRESHOLD +#endif + align_buf = memalign( NATIVE_ALIGN, i_size ); #else - uint8_t *buf = malloc( i_size + 15 + sizeof(void **) + sizeof(int) ); + uint8_t *buf = malloc( i_size + (NATIVE_ALIGN-1) + sizeof(void **) ); if( buf ) { - align_buf = buf + 15 + sizeof(void **) + sizeof(int); - align_buf -= (intptr_t) align_buf & 15; + align_buf = buf + (NATIVE_ALIGN-1) + sizeof(void **); + align_buf -= (intptr_t) align_buf & (NATIVE_ALIGN-1); *( (void **) ( align_buf - sizeof(void **) ) ) = buf; - *( (int *) ( align_buf - sizeof(void **) - sizeof(int) ) ) = i_size; } #endif if( !align_buf ) @@ -797,7 +1236,7 @@ void x264_free( void *p ) { if( p ) { -#if defined( HAVE_MALLOC_H ) || defined( SYS_MACOSX ) +#if HAVE_MALLOC_H free( p ); #else free( *( ( ( void **) p ) - 1 ) ); @@ -808,54 +1247,68 @@ void x264_free( void *p ) /**************************************************************************** * x264_reduce_fraction: ****************************************************************************/ -void x264_reduce_fraction( int *n, int *d ) -{ - int a = *n; - int b = *d; - int c; - if( !a || !b ) - return; - c = a % b; - while(c) - { - a = b; - b = c; - c = a % b; - } - *n /= b; - *d /= b; +#define REDUCE_FRACTION( name, type )\ +void name( type *n, type *d )\ +{ \ + type a = *n; \ + type b = *d; \ + type c; \ + if( !a || !b ) \ + return; \ + c = a % b; \ + while( c ) \ + { \ + a = b; \ + b = c; \ + c = a % b; \ + } \ + *n /= b; \ + *d /= b; \ } +REDUCE_FRACTION( x264_reduce_fraction , uint32_t ) +REDUCE_FRACTION( x264_reduce_fraction64, uint64_t ) + /**************************************************************************** * x264_slurp_file: ****************************************************************************/ char *x264_slurp_file( const char *filename ) { int b_error = 0; - int i_size; + int64_t i_size; char *buf; - FILE *fh = fopen( filename, "rb" ); + FILE *fh = x264_fopen( filename, "rb" ); if( !fh ) return NULL; + b_error |= fseek( fh, 0, SEEK_END ) < 0; b_error |= ( i_size = ftell( fh ) ) <= 0; + if( WORD_SIZE == 4 ) + b_error |= i_size > INT32_MAX; b_error |= fseek( fh, 0, SEEK_SET ) < 0; if( b_error ) - return NULL; + goto error; + buf = x264_malloc( i_size+2 ); - if( buf == NULL ) - return NULL; + if( !buf ) + goto error; + b_error |= fread( buf, 1, i_size, fh ) != i_size; - if( buf[i_size-1] != '\n' ) - buf[i_size++] = '\n'; - buf[i_size] = 0; fclose( fh ); if( b_error ) { x264_free( buf ); return NULL; } + + if( buf[i_size-1] != '\n' ) + buf[i_size++] = '\n'; + buf[i_size] = '\0'; + return buf; +error: + fclose( fh ); + return NULL; } /**************************************************************************** @@ -874,9 +1327,13 @@ char *x264_param2string( x264_param_t *p, int b_res ) if( b_res ) { s += sprintf( s, "%dx%d ", p->i_width, p->i_height ); - s += sprintf( s, "fps=%d/%d ", p->i_fps_num, p->i_fps_den ); + s += sprintf( s, "fps=%u/%u ", p->i_fps_num, p->i_fps_den ); + s += sprintf( s, "timebase=%u/%u ", p->i_timebase_num, p->i_timebase_den ); + s += sprintf( s, "bitdepth=%d ", BIT_DEPTH ); } + if( p->b_opencl ) + s += sprintf( s, "opencl=%d ", p->b_opencl ); s += sprintf( s, "cabac=%d", p->b_cabac ); s += sprintf( s, " ref=%d", p->i_frame_reference ); s += sprintf( s, " deblock=%d:%d:%d", p->b_deblocking_filter, @@ -897,35 +1354,48 @@ char *x264_param2string( x264_param_t *p, int b_res ) s += sprintf( s, " fast_pskip=%d", p->analyse.b_fast_pskip ); s += sprintf( s, " chroma_qp_offset=%d", p->analyse.i_chroma_qp_offset ); s += sprintf( s, " threads=%d", p->i_threads ); + s += sprintf( s, " lookahead_threads=%d", p->i_lookahead_threads ); s += sprintf( s, " sliced_threads=%d", p->b_sliced_threads ); if( p->i_slice_count ) s += sprintf( s, " slices=%d", p->i_slice_count ); + if( p->i_slice_count_max ) + s += sprintf( s, " slices_max=%d", p->i_slice_count_max ); if( p->i_slice_max_size ) s += sprintf( s, " slice_max_size=%d", p->i_slice_max_size ); if( p->i_slice_max_mbs ) s += sprintf( s, " slice_max_mbs=%d", p->i_slice_max_mbs ); + if( p->i_slice_min_mbs ) + s += sprintf( s, " slice_min_mbs=%d", p->i_slice_min_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" : p->b_fake_interlaced ? "fake" : "0" ); + s += sprintf( s, " bluray_compat=%d", p->b_bluray_compat ); + if( p->b_stitchable ) + s += sprintf( s, " stitchable=%d", p->b_stitchable ); + s += sprintf( s, " constrained_intra=%d", p->b_constrained_intra ); s += sprintf( s, " bframes=%d", p->i_bframe ); if( p->i_bframe ) { - s += sprintf( s, " b_pyramid=%d b_adapt=%d b_bias=%d direct=%d wpredb=%d", + s += sprintf( s, " b_pyramid=%d b_adapt=%d b_bias=%d direct=%d weightb=%d open_gop=%d", p->i_bframe_pyramid, p->i_bframe_adaptive, p->i_bframe_bias, - p->analyse.i_direct_mv_pred, p->analyse.b_weighted_bipred ); + p->analyse.i_direct_mv_pred, p->analyse.b_weighted_bipred, p->b_open_gop ); } - s += sprintf( s, " wpredp=%d", p->analyse.i_weighted_pred > 0 ? p->analyse.i_weighted_pred : 0 ); + s += sprintf( s, " weightp=%d", p->analyse.i_weighted_pred > 0 ? p->analyse.i_weighted_pred : 0 ); - s += sprintf( s, " keyint=%d keyint_min=%d scenecut=%d intra_refresh=%d", - p->i_keyint_max, p->i_keyint_min, p->i_scenecut_threshold, p->b_intra_refresh ); + if( p->i_keyint_max == X264_KEYINT_MAX_INFINITE ) + s += sprintf( s, " keyint=infinite" ); + else + s += sprintf( s, " keyint=%d", p->i_keyint_max ); + s += sprintf( s, " keyint_min=%d scenecut=%d intra_refresh=%d", + p->i_keyint_min, p->i_scenecut_threshold, p->b_intra_refresh ); if( p->rc.b_mb_tree || p->rc.i_vbv_buffer_size ) s += sprintf( s, " rc_lookahead=%d", p->rc.i_lookahead ); s += sprintf( s, " rc=%s mbtree=%d", p->rc.i_rc_method == X264_RC_ABR ? - ( p->rc.b_stat_read ? "2pass" : p->rc.i_vbv_buffer_size ? "cbr" : "abr" ) + ( p->rc.b_stat_read ? "2pass" : p->rc.i_vbv_max_bitrate == p->rc.i_bitrate ? "cbr" : "abr" ) : p->rc.i_rc_method == X264_RC_CRF ? "crf" : "cqp", p->rc.b_mb_tree ); if( p->rc.i_rc_method == X264_RC_ABR || p->rc.i_rc_method == X264_RC_CRF ) { @@ -940,11 +1410,24 @@ char *x264_param2string( x264_param_t *p, int b_res ) s += sprintf( s, " cplxblur=%.1f qblur=%.1f", p->rc.f_complexity_blur, p->rc.f_qblur ); if( p->rc.i_vbv_buffer_size ) + { s += sprintf( s, " vbv_maxrate=%d vbv_bufsize=%d", p->rc.i_vbv_max_bitrate, p->rc.i_vbv_buffer_size ); + if( p->rc.i_rc_method == X264_RC_CRF ) + s += sprintf( s, " crf_max=%.1f", p->rc.f_rf_constant_max ); + } } else if( p->rc.i_rc_method == X264_RC_CQP ) s += sprintf( s, " qp=%d", p->rc.i_qp_constant ); + + if( p->rc.i_vbv_buffer_size ) + s += sprintf( s, " nal_hrd=%s filler=%d", x264_nal_hrd_names[p->i_nal_hrd], p->rc.b_filler ); + if( p->crop_rect.i_left | p->crop_rect.i_top | p->crop_rect.i_right | p->crop_rect.i_bottom ) + s += sprintf( s, " crop_rect=%u,%u,%u,%u", p->crop_rect.i_left, p->crop_rect.i_top, + p->crop_rect.i_right, p->crop_rect.i_bottom ); + if( p->i_frame_packing >= 0 ) + s += sprintf( s, " frame-packing=%d", p->i_frame_packing ); + if( !(p->rc.i_rc_method == X264_RC_CQP && p->rc.i_qp_constant == 0) ) { s += sprintf( s, " ip_ratio=%.2f", p->rc.f_ip_factor );