diff -uNrp src/common/common.c src.new/common/common.c --- src/common/common.c 2013-10-31 14:38:48 +0300 +++ src.new/common/common.c 2013-10-31 14:40:26 +0300 @@ -41,6 +41,7 @@ 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 ); +static void x264_log_file( char *, int, const char *, va_list ); /**************************************************************************** * x264_param_default: @@ -127,6 +128,7 @@ void x264_param_default( x264_param_t *p param->pf_log = x264_log_default; param->p_log_private = NULL; param->i_log_level = X264_LOG_INFO; + param->i_log_file_level = X264_LOG_INFO; /* */ param->analyse.intra = X264_ANALYSE_I4x4 | X264_ANALYSE_I8x8; @@ -881,6 +883,13 @@ int x264_param_parse( x264_param_t *p, c } OPT("log") p->i_log_level = atoi(value); + OPT("log-file") + p->psz_log_file = strdup(value); + OPT("log-file-level") + if( !parse_enum( value, x264_log_level_names, &p->i_log_file_level ) ) + p->i_log_file_level += X264_LOG_NONE; + else + p->i_log_file_level = atoi(value); OPT("dump-yuv") p->psz_dump_yuv = strdup(value); OPT2("analyse", "partitions") @@ -1078,6 +1087,44 @@ void x264_log( x264_t *h, int i_level, c h->param.pf_log( h->param.p_log_private, i_level, psz_fmt, arg ); va_end( arg ); } + + if( h && h->param.psz_log_file && i_level <= h->param.i_log_file_level ) + { + va_list arg; + va_start( arg, psz_fmt ); + x264_log_file( h->param.psz_log_file, i_level, psz_fmt, arg ); + va_end( arg ); + } +} + +static void x264_log_file( char *p_file_name, int i_level, const char *psz_fmt, va_list arg ) +{ + char *psz_prefix; + switch( i_level ) + { + case X264_LOG_ERROR: + psz_prefix = "error"; + break; + case X264_LOG_WARNING: + psz_prefix = "warning"; + break; + case X264_LOG_INFO: + psz_prefix = "info"; + break; + case X264_LOG_DEBUG: + psz_prefix = "debug"; + break; + default: + psz_prefix = "unknown"; + break; + } + FILE *p_log_file = x264_fopen( p_file_name, "ab" ); + if( p_log_file ) + { + fprintf( p_log_file, "x264 [%s]: ", psz_prefix ); + vfprintf( p_log_file, psz_fmt, arg ); + fclose( p_log_file ); + } } static void x264_log_default( void *p_unused, int i_level, const char *psz_fmt, va_list arg ) diff -uNrp src/encoder/encoder.c src.new/encoder/encoder.c --- src/encoder/encoder.c 2013-10-31 14:38:48 +0300 +++ src.new/encoder/encoder.c 2013-10-31 14:41:13 +0300 @@ -1026,7 +1026,7 @@ static int x264_validate_parameters( x26 if( h->param.rc.f_aq_strength == 0 ) h->param.rc.i_aq_mode = 0; - if( h->param.i_log_level < X264_LOG_INFO ) + if( h->param.i_log_level < X264_LOG_INFO && (!h->param.psz_log_file || h->param.i_log_file_level < X264_LOG_INFO) ) { h->param.analyse.b_psnr = 0; h->param.analyse.b_ssim = 0; @@ -2778,7 +2778,7 @@ cont: int b_intra = IS_INTRA( h->mb.i_type ); int b_skip = IS_SKIP( h->mb.i_type ); - if( h->param.i_log_level >= X264_LOG_INFO || h->param.rc.b_stat_write ) + if( h->param.i_log_level >= X264_LOG_INFO || (h->param.psz_log_file && h->param.i_log_file_level >= X264_LOG_INFO) || h->param.rc.b_stat_write ) { if( !b_intra && !b_skip && !IS_DIRECT( h->mb.i_type ) ) { @@ -2798,7 +2798,7 @@ cont: } } - if( h->param.i_log_level >= X264_LOG_INFO ) + if( h->param.i_log_level >= X264_LOG_INFO || (h->param.psz_log_file && h->param.i_log_file_level >= X264_LOG_INFO) ) { if( h->mb.i_cbp_luma | h->mb.i_cbp_chroma ) { diff -uNrp src/x264.c src.new/x264.c --- src/x264.c 2013-10-31 14:38:49 +0300 +++ src.new/x264.c 2013-10-31 14:45:33 +0300 @@ -258,9 +258,32 @@ static int parse( int argc, char **argv static int encode( x264_param_t *param, cli_opt_t *opt ); /* logging and printing for within the cli system */ +static char *psz_log_file = NULL; +static int cli_log_file_level = -1; + +static inline void x264_log_done() +{ + if( psz_log_file ) free( psz_log_file ); + psz_log_file = NULL; +} + +static inline void x264_log_init( const char *file_name ) +{ + x264_log_done(); + psz_log_file = strdup( file_name ); +} + static int cli_log_level; void x264_cli_log( const char *name, int i_level, const char *fmt, ... ) { + if( psz_log_file && *psz_log_file && i_level <= cli_log_file_level ) + { + va_list arg; + va_start( arg, fmt ); + x264_cli_log_file( psz_log_file, i_level, fmt, arg ); + va_end( arg ); + } + if( i_level > cli_log_level ) return; char *s_level; @@ -289,8 +312,46 @@ void x264_cli_log( const char *name, int va_end( arg ); } +void x264_cli_log_file( char *p_file_name, int i_level, const char *psz_fmt, va_list arg ) +{ + char *psz_prefix; + switch( i_level ) + { + case X264_LOG_ERROR: + psz_prefix = "error"; + break; + case X264_LOG_WARNING: + psz_prefix = "warning"; + break; + case X264_LOG_INFO: + psz_prefix = "info"; + break; + case X264_LOG_DEBUG: + psz_prefix = "debug"; + break; + default: + psz_prefix = "unknown"; + break; + } + FILE *p_log_file = x264_fopen( p_file_name, "ab" ); + if( p_log_file ) + { + fprintf( p_log_file, "x264 [%s]: ", psz_prefix ); + vfprintf( p_log_file, psz_fmt, arg ); + fclose( p_log_file ); + } + } + void x264_cli_printf( int i_level, const char *fmt, ... ) { + if( psz_log_file && *psz_log_file ) + { + va_list arg; + va_start( arg, fmt ); + x264_cli_log_file( psz_log_file, X264_LOG_INFO, fmt, arg ); + va_end( arg ); + } + if( i_level > cli_log_level ) return; va_list arg; @@ -389,6 +450,7 @@ int main( int argc, char **argv ) free( argv ); #endif + x264_log_done(); return ret; } @@ -890,8 +952,12 @@ static void help( x264_param_t *defaults H1( " --no-progress Don't show the progress indicator while encoding\n" ); H0( " --quiet Quiet Mode\n" ); H1( " --log-level Specify the maximum level of logging [\"%s\"]\n" - " - %s\n", strtable_lookup( log_level_names, cli_log_level - X264_LOG_NONE ), - stringify_names( buf, log_level_names ) ); + " - %s\n", strtable_lookup( x264_log_level_names, cli_log_level - X264_LOG_NONE ), + stringify_names( buf, x264_log_level_names ) ); + H1( " --log-file Save log to file\n" ); + H1( " --log-file-level Log-file level information [\"%s\"]\n" + " - %s\n", strtable_lookup( x264_log_level_names, defaults->i_log_file_level - X264_LOG_NONE ), + stringify_names( buf, x264_log_level_names ) ); H1( " --psnr Enable PSNR computation\n" ); H1( " --ssim Enable SSIM computation\n" ); H1( " --threads Force a specific number of threads\n" ); @@ -955,6 +1021,8 @@ typedef enum OPT_TIMEBASE, OPT_PULLDOWN, OPT_LOG_LEVEL, + OPT_LOG_FILE, + OPT_LOG_FILE_LEVEL, OPT_DEMUXER_THREADS, OPT_VIDEO_FILTER, OPT_INPUT_FMT, @@ -1089,6 +1157,8 @@ static struct option long_options[] = { "quiet", no_argument, NULL, OPT_QUIET }, { "verbose", no_argument, NULL, 'v' }, { "log-level", required_argument, NULL, OPT_LOG_LEVEL }, + { "log-file", required_argument, NULL, OPT_LOG_FILE }, + { "log-file-level", required_argument, NULL, OPT_LOG_FILE_LEVEL }, { "no-progress", no_argument, NULL, OPT_NOPROGRESS }, { "dump-yuv", required_argument, NULL, 0 }, { "sps-id", required_argument, NULL, 0 }, @@ -1374,6 +1444,7 @@ static int parse( int argc, char **argv, x264_param_default( &defaults ); cli_log_level = defaults.i_log_level; + cli_log_file_level = defaults.i_log_file_level; memset( &input_opt, 0, sizeof(cli_input_opt_t) ); memset( &output_opt, 0, sizeof(cli_output_opt_t) ); @@ -1470,12 +1541,21 @@ static int parse( int argc, char **argv, cli_log_level = param->i_log_level = X264_LOG_DEBUG; break; case OPT_LOG_LEVEL: - if( !parse_enum_value( optarg, log_level_names, &cli_log_level ) ) + if( !parse_enum_value( optarg, x264_log_level_names, &cli_log_level ) ) cli_log_level += X264_LOG_NONE; else cli_log_level = atoi( optarg ); param->i_log_level = cli_log_level; break; + case OPT_LOG_FILE: + x264_log_init( optarg ); + goto generic_option; + case OPT_LOG_FILE_LEVEL: + if( !parse_enum_value( optarg, x264_log_level_names, &cli_log_file_level ) ) + cli_log_file_level += X264_LOG_NONE; + else + cli_log_file_level = atoi( optarg ); + goto generic_option; case OPT_NOPROGRESS: opt->b_progress = 0; break; @@ -1643,7 +1723,7 @@ generic_option: { if( thread_input.open_file( NULL, &opt->hin, &info, NULL ) ) { - fprintf( stderr, "x264 [error]: threaded input failed\n" ); + x264_cli_log( "x264", X264_LOG_ERROR, "threaded input failed\n" ); return -1; } cli_input = thread_input; @@ -2021,7 +2101,7 @@ fail: 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 ); + x264_cli_printf( X264_LOG_INFO, "aborted at input frame %d, output frame %d\n", opt->i_seek + i_frame, i_frame_output ); cli_output.close_file( opt->hout, largest_pts, second_largest_pts ); opt->hout = NULL; @@ -2031,7 +2111,7 @@ fail: double fps = (double)i_frame_output * (double)1000000 / (double)( i_end - i_start ); - fprintf( stderr, "encoded %d frames, %.2f fps, %.2f kb/s\n", i_frame_output, fps, + x264_cli_printf( X264_LOG_INFO, "encoded %d frames, %.2f fps, %.2f kb/s\n", i_frame_output, fps, (double) i_file * 8 / ( 1000 * duration ) ); } diff -uNrp src/x264.h src.new/x264.h --- src/x264.h 2013-10-31 14:19:54 +0300 +++ src.new/x264.h 2013-10-31 14:46:00 +0300 @@ -205,6 +205,7 @@ static const char * const x264_transfer_ "iec61966-2-4", "bt1361e", "iec61966-2-1", "bt2020-10", "bt2020-12", 0 }; static const char * const x264_colmatrix_names[] = { "GBR", "bt709", "undef", "", "fcc", "bt470bg", "smpte170m", "smpte240m", "YCgCo", "bt2020nc", "bt2020c", 0 }; static const char * const x264_nal_hrd_names[] = { "none", "vbr", "cbr", 0 }; +static const char * const x264_log_level_names[] = { "none", "error", "warning", "info", "debug", 0 }; /* Colorspace type */ #define X264_CSP_MASK 0x00ff /* */ @@ -348,6 +349,8 @@ typedef struct x264_param_t void (*pf_log)( void *, int i_level, const char *psz, va_list ); void *p_log_private; int i_log_level; + int i_log_file_level; + char *psz_log_file; /* filename (in UTF-8) of log-file */ int b_full_recon; /* fully reconstruct frames, even when not necessary for encoding. Implied by psz_dump_yuv */ char *psz_dump_yuv; /* filename (in UTF-8) for reconstructed frames */ diff -uNrp src/x264cli.h src.new/x264cli.h --- src/x264cli.h 2013-08-26 14:10:46 +0300 +++ src.new/x264cli.h 2013-10-31 14:46:15 +0300 @@ -61,6 +61,7 @@ static inline char *get_filename_extensi } void x264_cli_log( const char *name, int i_level, const char *fmt, ... ); +void x264_cli_log_file( char *p_file_name, int i_level, const char *psz_fmt, va_list arg ); void x264_cli_printf( int i_level, const char *fmt, ... ); #ifdef _WIN32