X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=x264.c;h=4d693d485ca9f801a8bbcec2abd4719da9ebe07f;hb=11130b0cf9192a296ba8a1521b5f80219294a6d7;hp=ab499005478d8b64352ac7e628f78d07c3232d52;hpb=213a99d070ebd4f9aeffe7cb3ed9bd7fe755ec7f;p=x264 diff --git a/x264.c b/x264.c index ab499005..4d693d48 100644 --- a/x264.c +++ b/x264.c @@ -1,7 +1,7 @@ /***************************************************************************** * x264: top-level x264cli functions ***************************************************************************** - * Copyright (C) 2003-2010 x264 project + * Copyright (C) 2003-2011 x264 project * * Authors: Loren Merritt * Laurent Aimar @@ -27,13 +27,9 @@ * For more information, contact us at licensing@x264.com. *****************************************************************************/ -#include -#include - #include #define _GNU_SOURCE #include - #include "common/common.h" #include "x264cli.h" #include "input/input.h" @@ -45,24 +41,37 @@ #ifdef _WIN32 #include #else +#define GetConsoleTitle(t,n) #define SetConsoleTitle(t) #endif #if HAVE_LAVF +#undef DECLARE_ALIGNED +#include #include #include #endif +#if HAVE_SWSCALE +#include +#endif + +#if HAVE_FFMS +#include +#endif + /* Ctrl-C handler */ -static int b_ctrl_c = 0; -static int b_exit_on_ctrl_c = 0; -static void SigIntHandler( int a ) +static volatile int b_ctrl_c = 0; +static int b_exit_on_ctrl_c = 0; +static void sigint_handler( int a ) { if( b_exit_on_ctrl_c ) exit(0); b_ctrl_c = 1; } +static char UNUSED originalCTitle[200] = ""; + typedef struct { int b_progress; int i_seek; @@ -113,7 +122,8 @@ static const char * const muxer_names[] = static const char * const pulldown_names[] = { "none", "22", "32", "64", "double", "triple", "euro", 0 }; static const char * const log_level_names[] = { "none", "error", "warning", "info", "debug", 0 }; -typedef struct{ +typedef struct +{ int mod; uint8_t pattern[24]; float fps_factor; @@ -153,9 +163,9 @@ static const cli_pulldown_t pulldown_values[] = // indexed by pic_struct enum static const float pulldown_frame_duration[10] = { 0.0, 1, 0.5, 0.5, 1, 1, 1.5, 1.5, 2, 3 }; -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 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 ); /* logging and printing for within the cli system */ static int cli_log_level; @@ -199,38 +209,88 @@ void x264_cli_printf( int i_level, const char *fmt, ... ) va_end( arg ); } -/**************************************************************************** - * main: - ****************************************************************************/ +static void print_version_info() +{ +#ifdef X264_POINTVER + printf( "x264 "X264_POINTVER"\n" ); +#else + printf( "x264 0.%d.X\n", X264_BUILD ); +#endif +#if HAVE_SWSCALE + printf( "(libswscale %d.%d.%d)\n", LIBSWSCALE_VERSION_MAJOR, LIBSWSCALE_VERSION_MINOR, LIBSWSCALE_VERSION_MICRO ); +#endif +#if HAVE_LAVF + printf( "(libavformat %d.%d.%d)\n", LIBAVFORMAT_VERSION_MAJOR, LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO ); +#endif +#if HAVE_FFMS + printf( "(ffmpegsource %d.%d.%d.%d)\n", FFMS_VERSION >> 24, (FFMS_VERSION & 0xff0000) >> 16, (FFMS_VERSION & 0xff00) >> 8, FFMS_VERSION & 0xff ); +#endif + printf( "built on " __DATE__ ", " ); +#ifdef __INTEL_COMPILER + printf( "intel: %.2f (%d)\n", __INTEL_COMPILER / 100.f, __INTEL_COMPILER_BUILD_DATE ); +#elif defined(__GNUC__) + printf( "gcc: " __VERSION__ "\n" ); +#else + printf( "using an unknown compiler\n" ); +#endif + printf( "configuration: --bit-depth=%d\n", x264_bit_depth ); + printf( "x264 license: " ); +#if HAVE_GPL + printf( "GPL version 2 or later\n" ); +#else + printf( "Non-GPL commercial\n" ); +#endif +#if HAVE_SWSCALE + const char *license = swscale_license(); + printf( "libswscale%s%s license: %s\n", HAVE_LAVF ? "/libavformat" : "", HAVE_FFMS ? "/ffmpegsource" : "" , license ); + if( !strcmp( license, "nonfree and unredistributable" ) || + (!HAVE_GPL && (!strcmp( license, "GPL version 2 or later" ) + || !strcmp( license, "GPL version 3 or later" )))) + printf( "WARNING: This binary is unredistributable!\n" ); +#endif +} + int main( int argc, char **argv ) { x264_param_t param; - cli_opt_t opt; - int ret; + cli_opt_t opt = {0}; + int ret = 0; -#if PTW32_STATIC_LIB - pthread_win32_process_attach_np(); - pthread_win32_thread_attach_np(); -#endif + FAIL_IF_ERROR( x264_threading_init(), "unable to initialize threading\n" ) #ifdef _WIN32 _setmode(_fileno(stdin), _O_BINARY); _setmode(_fileno(stdout), _O_BINARY); #endif + GetConsoleTitle( originalCTitle, sizeof(originalCTitle) ); + /* Parse command line */ - if( Parse( argc, argv, ¶m, &opt ) < 0 ) - return -1; + if( parse( argc, argv, ¶m, &opt ) < 0 ) + ret = -1; + + /* Restore title; it can be changed by input modules */ + SetConsoleTitle( originalCTitle ); /* Control-C handler */ - signal( SIGINT, SigIntHandler ); + signal( SIGINT, sigint_handler ); - ret = Encode( ¶m, &opt ); + if( !ret ) + ret = encode( ¶m, &opt ); -#if PTW32_STATIC_LIB - pthread_win32_thread_detach_np(); - pthread_win32_process_detach_np(); -#endif + /* clean up handles */ + if( filter.free ) + filter.free( opt.hin ); + else if( opt.hin ) + input.close_file( opt.hin ); + if( opt.hout ) + output.close_file( opt.hout, 0, 0 ); + if( opt.tcfile_out ) + fclose( opt.tcfile_out ); + if( opt.qpfile ) + fclose( opt.qpfile ); + + SetConsoleTitle( originalCTitle ); return ret; } @@ -271,11 +331,11 @@ static void print_csp_names( int longhelp ) printf( "\n" ); printf( " - valid csps for `lavf' demuxer:\n" ); printf( INDENT ); - int line_len = strlen( INDENT ); + size_t line_len = strlen( INDENT ); for( enum PixelFormat i = PIX_FMT_NONE+1; i < PIX_FMT_NB; i++ ) { const char *pfname = av_pix_fmt_descriptors[i].name; - int name_len = strlen( pfname ); + size_t name_len = strlen( pfname ); if( line_len + name_len > (80 - strlen( ", " )) ) { printf( "\n" INDENT ); @@ -293,10 +353,7 @@ static void print_csp_names( int longhelp ) printf( "\n" ); } -/***************************************************************************** - * Help: - *****************************************************************************/ -static void Help( x264_param_t *defaults, int longhelp ) +static void help( x264_param_t *defaults, int longhelp ) { char buf[50]; #define H0 printf @@ -343,7 +400,7 @@ static void Help( x264_param_t *defaults, int longhelp ) #else "no", #endif - BIT_DEPTH + x264_bit_depth ); H0( "Example usage:\n" ); H0( "\n" ); @@ -355,7 +412,7 @@ static void Help( x264_param_t *defaults, int longhelp ) H0( " x264 --pass 2 --bitrate 1000 -o \n" ); H0( "\n" ); H0( " Lossless:\n" ); - H0( " x264 --crf 0 -o \n" ); + H0( " x264 --qp 0 -o \n" ); H0( "\n" ); H0( " Maximum PSNR at the cost of speed and visual quality:\n" ); H0( " x264 --preset placebo --tune psnr -o \n" ); @@ -365,7 +422,7 @@ static void Help( x264_param_t *defaults, int longhelp ) H0( "\n" ); H0( "Presets:\n" ); H0( "\n" ); - H0( " --profile Force the limits of an H.264 profile\n" + H0( " --profile Force the limits of an H.264 profile\n" " Overrides all settings.\n" ); H2( " - baseline:\n" " --no-8x8dct --bframes 0 --no-cabac\n" @@ -381,7 +438,7 @@ static void Help( x264_param_t *defaults, int longhelp ) " No lossless.\n" " Support for bit depth 8-10.\n" ); else H0( " - baseline,main,high,high10\n" ); - H0( " --preset Use a preset to select encoding settings [medium]\n" + H0( " --preset Use a preset to select encoding settings [medium]\n" " Overridden by user settings.\n" ); H2( " - ultrafast:\n" " --no-8x8dct --aq-mode 0 --b-adapt 0\n" @@ -393,15 +450,16 @@ static void Help( x264_param_t *defaults, int longhelp ) " - superfast:\n" " --no-mbtree --me dia --no-mixed-refs\n" " --partitions i8x8,i4x4 --rc-lookahead 0\n" - " --ref 1 --subme 1 --trellis 0 --weightp 0\n" + " --ref 1 --subme 1 --trellis 0 --weightp 1\n" " - veryfast:\n" " --no-mixed-refs --rc-lookahead 10\n" - " --ref 1 --subme 2 --trellis 0 --weightp 0\n" + " --ref 1 --subme 2 --trellis 0 --weightp 1\n" " - faster:\n" " --no-mixed-refs --rc-lookahead 20\n" " --ref 2 --subme 4 --weightp 1\n" " - fast:\n" " --rc-lookahead 30 --ref 2 --subme 6\n" + " --weightp 1\n" " - medium:\n" " Default settings apply.\n" " - slow:\n" @@ -424,7 +482,7 @@ static void Help( x264_param_t *defaults, int longhelp ) " --trellis 2\n" ); else H0( " - ultrafast,superfast,veryfast,faster,fast\n" " - medium,slow,slower,veryslow,placebo\n" ); - H0( " --tune Tune the settings for a particular type of source\n" + H0( " --tune Tune the settings for a particular type of source\n" " or situation\n" " Overridden by user settings.\n" " Multiple tunings are separated by commas.\n" @@ -483,11 +541,7 @@ static void Help( x264_param_t *defaults, int longhelp ) " - strict: Strictly hierarchical pyramid\n" " - normal: Non-strict (not Blu-ray compatible)\n", strtable_lookup( x264_b_pyramid_names, defaults->i_bframe_pyramid ) ); - H1( " --open-gop Use recovery points to close GOPs [none]\n" - " - none: closed GOPs only\n" - " - normal: standard open GOPs\n" - " (not Blu-ray compatible)\n" - " - bluray: Blu-ray-compatible open GOPs\n" + H1( " --open-gop Use recovery points to close GOPs\n" " Only available with b-frames\n" ); H1( " --no-cabac Disable CABAC\n" ); H1( " -r, --ref Number of reference frames [%d]\n", defaults->i_frame_reference ); @@ -507,12 +561,19 @@ static void Help( x264_param_t *defaults, int longhelp ) H2( " --fake-interlaced Flag stream as interlaced but encode progressive.\n" " Makes it possible to encode 25p and 30p Blu-Ray\n" " streams. Ignored in interlaced mode.\n" ); + H2( " --frame-packing For stereoscopic videos define frame arrangement\n" + " - 0: checkerboard - pixels are alternatively from L and R\n" + " - 1: column alternation - L and R are interlaced by column\n" + " - 2: row alternation - L and R are interlaced by row\n" + " - 3: side by side - L is on the left, R on the right\n" + " - 4: top bottom - L is on top, R on bottom\n" + " - 5: frame alternation - one view per frame\n" ); H0( "\n" ); H0( "Ratecontrol:\n" ); H0( "\n" ); H1( " -q, --qp Force constant QP (0-%d, 0=lossless)\n", QP_MAX ); H0( " -B, --bitrate Set bitrate (kbit/s)\n" ); - H0( " --crf Quality-based VBR (0-%d, 0=lossless) [%.1f]\n", QP_MAX, defaults->rc.f_rf_constant ); + H0( " --crf Quality-based VBR (%d-51) [%.1f]\n", 51 - QP_MAX_SPEC, defaults->rc.f_rf_constant ); H1( " --rc-lookahead Number of frames for frametype lookahead [%d]\n", defaults->rc.i_lookahead ); H0( " --vbv-maxrate Max local bitrate (kbit/s) [%d]\n", defaults->rc.i_vbv_max_bitrate ); H0( " --vbv-bufsize Set size of the VBV buffer (kbit) [%d]\n", defaults->rc.i_vbv_buffer_size ); @@ -550,7 +611,7 @@ static void Help( x264_param_t *defaults, int longhelp ) " or b= (bitrate multiplier)\n" ); H2( " --qpfile Force frametypes and QPs for some or all frames\n" " Format of each line: framenumber frametype QP\n" - " QP of -1 lets x264 choose. Frametypes: I,i,K,P,B,b.\n" + " QP is optional (none lets x264 choose). Frametypes: I,i,K,P,B,b.\n" " K= depending on open-gop setting\n" " QPs are restricted by qpmin/qpmax.\n" ); H1( "\n" ); @@ -566,8 +627,8 @@ static void Help( x264_param_t *defaults, int longhelp ) H2( " --no-weightb Disable weighted prediction for B-frames\n" ); H1( " --weightp Weighted prediction for P-frames [%d]\n" " - 0: Disabled\n" - " - 1: Blind offset\n" - " - 2: Smart analysis\n", defaults->analyse.i_weighted_pred ); + " - 1: Weighted refs\n" + " - 2: Weighted refs + Duplicates\n", defaults->analyse.i_weighted_pred ); H1( " --me Integer pixel motion estimation method [\"%s\"]\n", strtable_lookup( x264_motion_est_names, defaults->analyse.i_me_method ) ); H2( " - dia: diamond search, radius 1 (fast)\n" @@ -590,7 +651,7 @@ static void Help( x264_param_t *defaults, int longhelp ) " - 9: RD refinement for all frames\n" " - 10: QP-RD - requires trellis=2, aq-mode>0\n" ); else H1( " decision quality: 1=fast, 10=best.\n" ); - H1( " --psy-rd Strength of psychovisual optimization [\"%.1f:%.1f\"]\n" + H1( " --psy-rd Strength of psychovisual optimization [\"%.1f:%.1f\"]\n" " #1: RD (requires subme>=6)\n" " #2: Trellis (requires trellis, experimental)\n", defaults->analyse.f_psy_rd, defaults->analyse.f_psy_trellis ); @@ -618,9 +679,9 @@ static void Help( x264_param_t *defaults, int longhelp ) " Takes a comma-separated list of 16 integers.\n" ); H2( " --cqm8 Set all 8x8 quant matrices\n" " Takes a comma-separated list of 64 integers.\n" ); - H2( " --cqm4i, --cqm4p, --cqm8i, --cqm8p\n" + H2( " --cqm4i, --cqm4p, --cqm8i, --cqm8p \n" " Set both luma and chroma quant matrices\n" ); - H2( " --cqm4iy, --cqm4ic, --cqm4py, --cqm4pc\n" + H2( " --cqm4iy, --cqm4ic, --cqm4py, --cqm4pc \n" " Set individual quant matrices\n" ); H2( "\n" ); H2( "Video Usability Info (Annex E):\n" ); @@ -654,17 +715,21 @@ static void Help( x264_param_t *defaults, int longhelp ) H2( " --nal-hrd Signal HRD information (requires vbv-bufsize)\n" " - none, vbr, cbr (cbr not allowed in .mp4)\n" ); H2( " --pic-struct Force pic_struct in Picture Timing SEI\n" ); + H2( " --crop-rect Add 'left,top,right,bottom' to the bitstream-level\n" + " cropping rectangle\n" ); H0( "\n" ); H0( "Input/Output:\n" ); H0( "\n" ); - H0( " -o, --output Specify output file\n" ); + H0( " -o, --output Specify output file\n" ); H1( " --muxer Specify output container format [\"%s\"]\n" " - %s\n", muxer_names[0], stringify_names( buf, muxer_names ) ); H1( " --demuxer Specify input container format [\"%s\"]\n" " - %s\n", demuxer_names[0], stringify_names( buf, demuxer_names ) ); + H1( " --input-fmt Specify input file format (requires lavf support)\n" ); H1( " --input-csp Specify input colorspace format for raw input\n" ); print_csp_names( longhelp ); + H1( " --input-depth Specify input bit depth for raw input\n" ); H1( " --input-res Specify input resolution (width x height)\n" ); H1( " --index Filename for input index file\n" ); H0( " --sar width:height Specify Sample Aspect Ratio\n" ); @@ -672,6 +737,7 @@ static void Help( x264_param_t *defaults, int longhelp ) H0( " --seek First frame to encode\n" ); H0( " --frames Maximum number of frames to encode\n" ); H0( " --level Specify level (as defined by Annex A)\n" ); + H1( " --bluray-compat Enable compatibility hacks for Blu-ray support\n" ); H1( "\n" ); H1( " -v, --verbose Print stats for each frame\n" ); H1( " --no-progress Don't show the progress indicator while encoding\n" ); @@ -698,6 +764,7 @@ static void Help( x264_param_t *defaults, int longhelp ) H2( " --timebase Specify timebase numerator and denominator\n" " Specify timebase numerator for input timecode file\n" " or specify timebase denominator for other input\n" ); + H2( " --dts-compress Eliminate initial delay with container DTS hack\n" ); H0( "\n" ); H0( "Filtering:\n" ); H0( "\n" ); @@ -711,7 +778,8 @@ static void Help( x264_param_t *defaults, int longhelp ) H0( "\n" ); } -enum { +enum +{ OPT_FRAMES = 256, OPT_SEEK, OPT_QPFILE, @@ -736,8 +804,11 @@ enum { OPT_PULLDOWN, OPT_LOG_LEVEL, OPT_VIDEO_FILTER, + OPT_INPUT_FMT, OPT_INPUT_RES, - OPT_INPUT_CSP + OPT_INPUT_CSP, + OPT_INPUT_DEPTH, + OPT_DTS_COMPRESSION } OptionsOPT; static char short_options[] = "8A:B:b:f:hI:i:m:o:p:q:r:t:Vvw"; @@ -757,7 +828,8 @@ static struct option long_options[] = { "no-b-adapt", no_argument, NULL, 0 }, { "b-bias", required_argument, NULL, 0 }, { "b-pyramid", required_argument, NULL, 0 }, - { "open-gop", required_argument, NULL, 0 }, + { "open-gop", no_argument, NULL, 0 }, + { "bluray-compat", no_argument, NULL, 0 }, { "min-keyint", required_argument, NULL, 'i' }, { "keyint", required_argument, NULL, 'I' }, { "intra-refresh", no_argument, NULL, 0 }, @@ -882,13 +954,18 @@ static struct option long_options[] = { "tcfile-out", required_argument, NULL, OPT_TCFILE_OUT }, { "timebase", required_argument, NULL, OPT_TIMEBASE }, { "pic-struct", no_argument, NULL, 0 }, + { "crop-rect", required_argument, NULL, 0 }, { "nal-hrd", required_argument, NULL, 0 }, { "pulldown", required_argument, NULL, OPT_PULLDOWN }, { "fake-interlaced", no_argument, NULL, 0 }, + { "frame-packing", required_argument, NULL, 0 }, { "vf", required_argument, NULL, OPT_VIDEO_FILTER }, { "video-filter", required_argument, NULL, OPT_VIDEO_FILTER }, + { "input-fmt", required_argument, NULL, OPT_INPUT_FMT }, { "input-res", required_argument, NULL, OPT_INPUT_RES }, { "input-csp", required_argument, NULL, OPT_INPUT_CSP }, + { "input-depth", required_argument, NULL, OPT_INPUT_DEPTH }, + { "dts-compress", no_argument, NULL, OPT_DTS_COMPRESSION }, {0, 0, 0, 0} }; @@ -903,7 +980,6 @@ static int select_output( const char *muxer, char *filename, x264_param_t *param #if HAVE_GPAC output = mp4_output; param->b_annexb = 0; - param->b_dts_compress = 0; param->b_repeat_headers = 0; if( param->i_nal_hrd == X264_NAL_HRD_CBR ) { @@ -919,14 +995,12 @@ static int select_output( const char *muxer, char *filename, x264_param_t *param { output = mkv_output; param->b_annexb = 0; - param->b_dts_compress = 0; param->b_repeat_headers = 0; } else if( !strcasecmp( ext, "flv" ) ) { output = flv_output; param->b_annexb = 0; - param->b_dts_compress = 1; param->b_repeat_headers = 0; } else @@ -1050,10 +1124,16 @@ static int init_vid_filters( char *sequence, hnd_t *handle, video_info_t *info, if( csp > X264_CSP_NONE && csp < X264_CSP_MAX ) param->i_csp = info->csp; else - param->i_csp = X264_CSP_I420; + param->i_csp = X264_CSP_I420 | ( info->csp & X264_CSP_HIGH_DEPTH ); if( x264_init_vid_filter( "resize", handle, &filter, info, param, NULL ) ) return -1; + char args[20]; + sprintf( args, "bit_depth=%d", x264_bit_depth ); + + if( x264_init_vid_filter( "depth", handle, &filter, info, param, args ) ) + return -1; + return 0; } @@ -1079,10 +1159,7 @@ static int parse_enum_value( const char *arg, const char * const *names, int *ds return -1; } -/***************************************************************************** - * Parse: - *****************************************************************************/ -static int Parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt ) +static int parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt ) { char *input_filename = NULL; const char *demuxer = demuxer_names[0]; @@ -1098,14 +1175,16 @@ static int Parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt ) int b_user_fps = 0; int b_user_interlaced = 0; cli_input_opt_t input_opt; + cli_output_opt_t output_opt; char *preset = NULL; char *tune = NULL; x264_param_default( &defaults ); cli_log_level = defaults.i_log_level; - memset( opt, 0, sizeof(cli_opt_t) ); memset( &input_opt, 0, sizeof(cli_input_opt_t) ); + memset( &output_opt, 0, sizeof(cli_output_opt_t) ); + input_opt.bit_depth = 8; opt->b_progress = 1; /* Presets are applied before all other options. */ @@ -1144,27 +1223,16 @@ static int Parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt ) switch( c ) { case 'h': - Help( &defaults, 0 ); + help( &defaults, 0 ); exit(0); case OPT_LONGHELP: - Help( &defaults, 1 ); + help( &defaults, 1 ); exit(0); case OPT_FULLHELP: - Help( &defaults, 2 ); + help( &defaults, 2 ); exit(0); case 'V': -#ifdef X264_POINTVER - printf( "x264 "X264_POINTVER"\n" ); -#else - printf( "x264 0.%d.X\n", X264_BUILD ); -#endif - printf( "built on " __DATE__ ", " ); -#ifdef __GNUC__ - printf( "gcc: " __VERSION__ "\n" ); -#else - printf( "using a non-gcc compiler\n" ); -#endif - printf( "configuration: --bit-depth=%d\n", BIT_DEPTH ); + print_version_info(); exit(0); case OPT_FRAMES: param->i_frame_total = X264_MAX( atoi( optarg ), 0 ); @@ -1256,12 +1324,21 @@ static int Parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt ) case OPT_VIDEO_FILTER: vid_filters = optarg; break; + case OPT_INPUT_FMT: + input_opt.format = optarg; + break; case OPT_INPUT_RES: input_opt.resolution = optarg; break; case OPT_INPUT_CSP: input_opt.colorspace = optarg; break; + case OPT_INPUT_DEPTH: + input_opt.bit_depth = atoi( optarg ); + break; + case OPT_DTS_COMPRESSION: + output_opt.use_dts_compress = 1; + break; default: generic_option: { @@ -1306,7 +1383,7 @@ generic_option: if( select_output( muxer, output_filename, param ) ) return -1; - FAIL_IF_ERROR( output.open_file( output_filename, &opt->hout ), "could not open output file `%s'\n", output_filename ) + FAIL_IF_ERROR( output.open_file( output_filename, &opt->hout, &output_opt ), "could not open output file `%s'\n", output_filename ) input_filename = argv[optind++]; video_info_t info = {0}; @@ -1322,6 +1399,8 @@ generic_option: info.tff = param->b_tff; info.vfr = param->b_vfr_input; + input_opt.progress = opt->b_progress; + if( select_input( demuxer, demuxername, input_filename, &opt->hin, &info, &input_opt ) ) return -1; @@ -1343,7 +1422,7 @@ generic_option: else FAIL_IF_ERROR( !info.vfr && input_opt.timebase, "--timebase is incompatible with cfr input\n" ) /* init threaded input while the information about the input video is unaltered by filtering */ -#if HAVE_PTHREAD +#if HAVE_THREAD if( info.thread_safe && (b_thread_input || param->i_threads > 1 || (param->i_threads == X264_THREADS_AUTO && x264_cpu_num_processors() > 1)) ) { @@ -1417,11 +1496,15 @@ generic_option: if( !b_user_interlaced && info.interlaced ) { +#if HAVE_INTERLACED x264_cli_log( "x264", X264_LOG_WARNING, "input appears to be interlaced, enabling %cff interlaced mode.\n" " If you want otherwise, use --no-interlaced or --%cff\n", info.tff ? 't' : 'b', info.tff ? 'b' : 't' ); param->b_interlaced = 1; param->b_tff = !!info.tff; +#else + x264_cli_log( "x264", X264_LOG_WARNING, "input appears to be interlaced, but not compiled with interlaced support\n" ); +#endif } /* Automatically reduce reference frame count to match the user's target level @@ -1453,17 +1536,19 @@ static void parse_qpfile( cli_opt_t *opt, x264_picture_t *pic, int i_frame ) while( num < i_frame ) { file_pos = ftell( opt->qpfile ); - ret = fscanf( opt->qpfile, "%d %c %d\n", &num, &type, &qp ); + qp = -1; + ret = fscanf( opt->qpfile, "%d %c%*[ \t]%d\n", &num, &type, &qp ); + pic->i_type = X264_TYPE_AUTO; + pic->i_qpplus1 = X264_QP_AUTO; if( num > i_frame || ret == EOF ) { - pic->i_type = X264_TYPE_AUTO; - pic->i_qpplus1 = 0; fseek( opt->qpfile, file_pos, SEEK_SET ); break; } - if( num < i_frame && ret == 3 ) + if( num < i_frame && ret >= 2 ) continue; - pic->i_qpplus1 = qp+1; + if( ret == 3 && qp >= 0 ) + pic->i_qpplus1 = qp+1; if ( type == 'I' ) pic->i_type = X264_TYPE_IDR; else if( type == 'i' ) pic->i_type = X264_TYPE_I; else if( type == 'K' ) pic->i_type = X264_TYPE_KEYFRAME; @@ -1471,23 +1556,17 @@ static void parse_qpfile( cli_opt_t *opt, x264_picture_t *pic, int i_frame ) else if( type == 'B' ) pic->i_type = X264_TYPE_BREF; else if( type == 'b' ) pic->i_type = X264_TYPE_B; else ret = 0; - if( ret != 3 || qp < -1 || qp > QP_MAX ) + if( ret < 2 || qp < -1 || qp > QP_MAX ) { x264_cli_log( "x264", X264_LOG_ERROR, "can't parse qpfile for frame %d\n", i_frame ); fclose( opt->qpfile ); opt->qpfile = NULL; - pic->i_type = X264_TYPE_AUTO; - pic->i_qpplus1 = 0; break; } } } -/***************************************************************************** - * Encode: - *****************************************************************************/ - -static int Encode_frame( x264_t *h, hnd_t hout, x264_picture_t *pic, int64_t *last_dts ) +static int encode_frame( x264_t *h, hnd_t hout, x264_picture_t *pic, int64_t *last_dts ) { x264_picture_t pic_out; x264_nal_t *nal; @@ -1507,10 +1586,13 @@ static int Encode_frame( x264_t *h, hnd_t hout, x264_picture_t *pic, int64_t *l return i_frame_size; } -static void Print_status( int64_t i_start, int i_frame, int i_frame_total, int64_t i_file, x264_param_t *param, int64_t last_ts ) +static int64_t print_status( int64_t i_start, int64_t i_previous, int i_frame, int i_frame_total, int64_t i_file, x264_param_t *param, int64_t last_ts ) { - char buf[200]; - int64_t i_elapsed = x264_mdate() - i_start; + char buf[200]; + int64_t i_time = x264_mdate(); + if( i_previous && i_time - i_previous < UPDATE_INTERVAL ) + return i_previous; + int64_t i_elapsed = i_time - i_start; double fps = i_elapsed > 0 ? i_frame * 1000000. / i_elapsed : 0; double bitrate; if( last_ts ) @@ -1531,9 +1613,10 @@ static void Print_status( int64_t i_start, int i_frame, int i_frame_total, int64 fprintf( stderr, "%s \r", buf+5 ); SetConsoleTitle( buf ); fflush( stderr ); // needed in windows + return i_time; } -static void Convert_cli_to_lib_pic( x264_picture_t *lib, cli_pic_t *cli ) +static void convert_cli_to_lib_pic( x264_picture_t *lib, cli_pic_t *cli ) { memcpy( lib->img.i_stride, cli->img.stride, sizeof(cli->img.stride) ); memcpy( lib->img.plane, cli->img.plane, sizeof(cli->img.plane) ); @@ -1542,18 +1625,26 @@ static void Convert_cli_to_lib_pic( x264_picture_t *lib, cli_pic_t *cli ) lib->i_pts = cli->pts; } -static int Encode( x264_param_t *param, cli_opt_t *opt ) +#define FAIL_IF_ERROR2( cond, ... )\ +if( cond )\ +{\ + x264_cli_log( "x264", X264_LOG_ERROR, __VA_ARGS__ );\ + retval = -1;\ + goto fail;\ +} + +static int encode( x264_param_t *param, cli_opt_t *opt ) { - x264_t *h; + x264_t *h = NULL; x264_picture_t pic; cli_pic_t cli_pic; const cli_pulldown_t *pulldown = NULL; // shut up gcc - int i_frame, i_frame_output; - int64_t i_start, i_end; + int i_frame = 0; + int i_frame_output = 0; + int64_t i_end, i_previous = 0, i_start = 0; int64_t i_file = 0; int i_frame_size; - int i_update_interval; int64_t last_dts = 0; int64_t prev_dts = 0; int64_t first_dts = 0; @@ -1563,48 +1654,36 @@ static int Encode( x264_param_t *param, cli_opt_t *opt ) int64_t second_largest_pts = -1; int64_t ticks_per_frame; double duration; - int prev_timebase_den = param->i_timebase_den / gcd( param->i_timebase_num, param->i_timebase_den ); - int dts_compress_multiplier; double pulldown_pts = 0; + int retval = 0; opt->b_progress &= param->i_log_level < X264_LOG_DEBUG; - i_update_interval = param->i_frame_total ? x264_clip3( param->i_frame_total / 1000, 1, 10 ) : 10; - x264_picture_init( &pic ); /* set up pulldown */ if( opt->i_pulldown && !param->b_vfr_input ) { + param->b_pulldown = 1; param->b_pic_struct = 1; pulldown = &pulldown_values[opt->i_pulldown]; param->i_timebase_num = param->i_fps_den; - FAIL_IF_ERROR( fmod( param->i_fps_num * pulldown->fps_factor, 1 ), - "unsupported framerate for chosen pulldown\n" ) + FAIL_IF_ERROR2( fmod( param->i_fps_num * pulldown->fps_factor, 1 ), + "unsupported framerate for chosen pulldown\n" ) param->i_timebase_den = param->i_fps_num * pulldown->fps_factor; } - if( ( h = x264_encoder_open( param ) ) == NULL ) - { - x264_cli_log( "x264", X264_LOG_ERROR, "x264_encoder_open failed\n" ); - filter.free( opt->hin ); - return -1; - } + h = x264_encoder_open( param ); + FAIL_IF_ERROR2( !h, "x264_encoder_open failed\n" ); x264_encoder_parameters( h, param ); - dts_compress_multiplier = param->i_timebase_den / prev_timebase_den; - - if( output.set_param( opt->hout, param ) ) - { - x264_cli_log( "x264", X264_LOG_ERROR, "can't set outfile param\n" ); - filter.free( opt->hin ); - output.close_file( opt->hout, largest_pts, second_largest_pts ); - return -1; - } + FAIL_IF_ERROR2( output.set_param( opt->hout, param ), "can't set outfile param\n" ); i_start = x264_mdate(); + /* ticks/frame = ticks/second / frames/second */ ticks_per_frame = (int64_t)param->i_timebase_den * param->i_fps_den / param->i_timebase_num / param->i_fps_num; - FAIL_IF_ERROR( ticks_per_frame < 1, "ticks_per_frame invalid: %"PRId64"\n", ticks_per_frame ) + FAIL_IF_ERROR2( ticks_per_frame < 1 && !param->b_vfr_input, "ticks_per_frame invalid: %"PRId64"\n", ticks_per_frame ) + ticks_per_frame = X264_MAX( ticks_per_frame, 1 ); if( !param->b_repeat_headers ) { @@ -1612,20 +1691,20 @@ static int Encode( x264_param_t *param, cli_opt_t *opt ) x264_nal_t *headers; int i_nal; - FAIL_IF_ERROR( x264_encoder_headers( h, &headers, &i_nal ) < 0, "x264_encoder_headers failed\n" ) - if( (i_file = output.write_headers( opt->hout, headers )) < 0 ) - return -1; + FAIL_IF_ERROR2( x264_encoder_headers( h, &headers, &i_nal ) < 0, "x264_encoder_headers failed\n" ) + FAIL_IF_ERROR2( (i_file = output.write_headers( opt->hout, headers )) < 0, "error writing headers to output file\n" ); } if( opt->tcfile_out ) fprintf( opt->tcfile_out, "# timecode format v2\n" ); /* Encode frames */ - for( i_frame = 0, i_frame_output = 0; !b_ctrl_c && (i_frame < param->i_frame_total || !param->i_frame_total); i_frame++ ) + for( ; !b_ctrl_c && (i_frame < param->i_frame_total || !param->i_frame_total); i_frame++ ) { if( filter.get_frame( opt->hin, &cli_pic, i_frame + opt->i_seek ) ) break; - Convert_cli_to_lib_pic( &pic, &cli_pic ); + x264_picture_init( &pic ); + convert_cli_to_lib_pic( &pic, &cli_pic ); if( !param->b_vfr_input ) pic.i_pts = i_frame; @@ -1639,41 +1718,35 @@ static int Encode( x264_param_t *param, cli_opt_t *opt ) else if( opt->timebase_convert_multiplier ) pic.i_pts = (int64_t)( pic.i_pts * opt->timebase_convert_multiplier + 0.5 ); - int64_t output_pts = pic.i_pts * dts_compress_multiplier; /* pts libx264 returns */ - if( pic.i_pts <= largest_pts ) { if( cli_log_level >= X264_LOG_DEBUG || pts_warning_cnt < MAX_PTS_WARNING ) x264_cli_log( "x264", X264_LOG_WARNING, "non-strictly-monotonic pts at frame %d (%"PRId64" <= %"PRId64")\n", - i_frame, output_pts, largest_pts * dts_compress_multiplier ); + i_frame, pic.i_pts, largest_pts ); else if( pts_warning_cnt == MAX_PTS_WARNING ) x264_cli_log( "x264", X264_LOG_WARNING, "too many nonmonotonic pts warnings, suppressing further ones\n" ); pts_warning_cnt++; pic.i_pts = largest_pts + ticks_per_frame; - output_pts = pic.i_pts * dts_compress_multiplier; } second_largest_pts = largest_pts; largest_pts = pic.i_pts; if( opt->tcfile_out ) - fprintf( opt->tcfile_out, "%.6f\n", output_pts * ((double)param->i_timebase_num / param->i_timebase_den) * 1e3 ); + fprintf( opt->tcfile_out, "%.6f\n", pic.i_pts * ((double)param->i_timebase_num / param->i_timebase_den) * 1e3 ); if( opt->qpfile ) parse_qpfile( opt, &pic, i_frame + opt->i_seek ); - else - { - /* Do not force any parameters */ - pic.i_type = X264_TYPE_AUTO; - pic.i_qpplus1 = 0; - } prev_dts = last_dts; - i_frame_size = Encode_frame( h, opt->hout, &pic, &last_dts ); + i_frame_size = encode_frame( h, opt->hout, &pic, &last_dts ); if( i_frame_size < 0 ) - return -1; - i_file += i_frame_size; - if( i_frame_size ) { + b_ctrl_c = 1; /* lie to exit the loop */ + retval = -1; + } + else if( i_frame_size ) + { + i_file += i_frame_size; i_frame_output++; if( i_frame_output == 1 ) first_dts = prev_dts = last_dts; @@ -1683,26 +1756,30 @@ static int Encode( x264_param_t *param, cli_opt_t *opt ) break; /* update status line (up to 1000 times per input file) */ - if( opt->b_progress && i_frame_output % i_update_interval == 0 && i_frame_output ) - Print_status( i_start, i_frame_output, param->i_frame_total, i_file, param, 2 * last_dts - prev_dts - first_dts ); + if( opt->b_progress && i_frame_output ) + i_previous = print_status( i_start, i_previous, i_frame_output, param->i_frame_total, i_file, param, 2 * last_dts - prev_dts - first_dts ); } /* Flush delayed frames */ while( !b_ctrl_c && x264_encoder_delayed_frames( h ) ) { prev_dts = last_dts; - i_frame_size = Encode_frame( h, opt->hout, NULL, &last_dts ); + i_frame_size = encode_frame( h, opt->hout, NULL, &last_dts ); if( i_frame_size < 0 ) - return -1; - i_file += i_frame_size; - if( i_frame_size ) { + b_ctrl_c = 1; /* lie to exit the loop */ + retval = -1; + } + else if( i_frame_size ) + { + i_file += i_frame_size; i_frame_output++; if( i_frame_output == 1 ) first_dts = prev_dts = last_dts; } - if( opt->b_progress && i_frame_output % i_update_interval == 0 && i_frame_output ) - Print_status( i_start, i_frame_output, param->i_frame_total, i_file, param, 2 * last_dts - prev_dts - first_dts ); + if( opt->b_progress && i_frame_output ) + i_previous = print_status( i_start, i_previous, i_frame_output, param->i_frame_total, i_file, param, 2 * last_dts - prev_dts - first_dts ); } +fail: if( pts_warning_cnt >= MAX_PTS_WARNING && cli_log_level < X264_LOG_DEBUG ) x264_cli_log( "x264", X264_LOG_WARNING, "%d suppressed nonmonotonic pts warnings\n", pts_warning_cnt-MAX_PTS_WARNING ); @@ -1713,27 +1790,20 @@ static int Encode( x264_param_t *param, cli_opt_t *opt ) duration = (double)(2 * last_dts - prev_dts - first_dts) * param->i_timebase_num / param->i_timebase_den; else duration = (double)(2 * largest_pts - second_largest_pts) * param->i_timebase_num / param->i_timebase_den; - if( !(opt->i_pulldown && !param->b_vfr_input) ) - duration *= dts_compress_multiplier; i_end = x264_mdate(); /* Erase progress indicator before printing encoding stats. */ if( opt->b_progress ) fprintf( stderr, " \r" ); - x264_encoder_close( h ); + if( h ) + x264_encoder_close( h ); fprintf( stderr, "\n" ); if( b_ctrl_c ) fprintf( stderr, "aborted at input frame %d, output frame %d\n", opt->i_seek + i_frame, i_frame_output ); - if( opt->tcfile_out ) - { - fclose( opt->tcfile_out ); - opt->tcfile_out = NULL; - } - - filter.free( opt->hin ); - output.close_file( opt->hout, largest_pts * dts_compress_multiplier, second_largest_pts * dts_compress_multiplier ); + output.close_file( opt->hout, largest_pts, second_largest_pts ); + opt->hout = NULL; if( i_frame_output > 0 ) { @@ -1744,5 +1814,5 @@ static int Encode( x264_param_t *param, cli_opt_t *opt ) (double) i_file * 8 / ( 1000 * duration ) ); } - return 0; + return retval; }