diff -uNrp c/cli_common.h b/cli_common.h --- c/cli_common.h 1970-01-01 02:00:00 +0200 +++ b/cli_common.h 2010-02-25 11:29:25 +0200 @@ -0,0 +1,29 @@ +#ifndef X264_CLI_H +#define X264_CLI_H + +/** + * Contains necessities common to CLI elements but not the library. + */ + +/* log macros */ +FILE *f_log_file; +#define OPEN_LOG(prm,mode) \ +{\ + if( prm->psz_log_file )\ + f_log_file = fopen( prm->psz_log_file, mode );\ +} +#define CLOSE_LOG \ +{\ + if( f_log_file )\ + fclose( f_log_file );\ + f_log_file = NULL;\ +} +#define LOG(prm,lvl1,lvl2,...) \ +{\ + if( prm->i_log_level>=X264_LOG_##lvl1 )\ + fprintf( stderr, __VA_ARGS__ );\ + if( f_log_file && prm->i_log_file_level>=X264_LOG_##lvl2 )\ + fprintf( f_log_file, __VA_ARGS__ );\ +} + +#endif diff -uNrp c/common/common.c b/common/common.c --- c/common/common.c 2010-02-25 11:28:56 +0200 +++ b/common/common.c 2010-02-25 11:29:25 +0200 @@ -117,6 +117,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; @@ -758,6 +759,10 @@ 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") + p->i_log_file_level = x264_clip3( atoi(value), -1, 3 ); #ifdef HAVE_VISUALIZE OPT("visualize") p->b_visualize = atobool(value); @@ -925,6 +930,32 @@ int x264_param_parse( x264_param_t *p, c return b_error ? X264_PARAM_BAD_VALUE : 0; } +static void x264_log_file( FILE *p_file, 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; + } + fprintf( p_file, "x264 [%s]: ", psz_prefix ); + vfprintf( p_file, psz_fmt, arg ); + fflush( p_file ); +} + /**************************************************************************** * x264_log: ****************************************************************************/ @@ -940,6 +971,14 @@ 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( i_level <= h->param.i_log_file_level ) + { + va_list arg; + va_start( arg, psz_fmt ); + if( h->p_log_file ) + x264_log_file( h->p_log_file, i_level, psz_fmt, arg ); + va_end( arg ); + } } static void x264_log_default( void *p_unused, int i_level, const char *psz_fmt, va_list arg ) diff -uNrp c/common/common.h b/common/common.h --- c/common/common.h 2010-02-25 11:29:01 +0200 +++ b/common/common.h 2010-02-25 11:29:25 +0200 @@ -465,6 +465,9 @@ struct x264_t int b_have_sub8x8_esa; } frames; + /* log */ + FILE *p_log_file; + /* current frame being encoded */ x264_frame_t *fenc; diff -uNrp c/encoder/encoder.c b/encoder/encoder.c --- c/encoder/encoder.c 2010-02-25 11:29:05 +0200 +++ b/encoder/encoder.c 2010-02-25 11:29:25 +0200 @@ -945,6 +945,16 @@ x264_t *x264_encoder_open( x264_param_t if( param->param_free ) param->param_free( param ); + if( h->param.psz_log_file ) + { + h->p_log_file = fopen( h->param.psz_log_file, "ab" ); + if( !h->p_log_file ) + { + x264_log( h, X264_LOG_ERROR, "can't write log to \"%s\"\n", h->param.psz_log_file ); + goto fail; + } + } + if( x264_validate_parameters( h ) < 0 ) goto fail; @@ -1198,6 +1208,11 @@ x264_t *x264_encoder_open( x264_param_t return h; fail: + if( h && h->p_log_file ) + { + fclose( h->p_log_file ); + h->p_log_file = NULL; + } x264_free( h ); return NULL; } @@ -3158,6 +3173,13 @@ void x264_encoder_close ( x264_t *h x264_free( h->nal_buffer ); x264_analyse_free_costs( h ); + if( h->p_log_file ) + { + fflush( h->p_log_file ); + fclose( h->p_log_file ); + h->p_log_file = NULL; + } + if( h->i_thread_frames > 1) h = h->thread[h->i_thread_phase]; diff -uNrp c/x264.c b/x264.c --- c/x264.c 2010-02-25 11:28:56 +0200 +++ b/x264.c 2010-02-25 11:29:52 +0200 @@ -34,6 +34,7 @@ #include "common/cpu.h" #include "x264.h" #include "muxers.h" +#include "cli_common.h" #ifdef _WIN32 #include @@ -123,6 +124,7 @@ static int set_pulldown( cli_pulldown_t ****************************************************************************/ int main( int argc, char **argv ) { + f_log_file = NULL; x264_param_t param; cli_opt_t opt; int ret; @@ -522,6 +524,9 @@ static void Help( x264_param_t *defaults H0( " --quiet Quiet Mode\n" ); H1( " --psnr Enable PSNR computation\n" ); H1( " --ssim Enable SSIM computation\n" ); + H0( " --log-file Save log to file\n" ); + H1( " --log-file-level Log-file level information [%d]\n", + defaults->i_log_file_level ); H1( " --threads Force a specific number of threads\n" ); H2( " --sliced-threads Low-latency but lower-efficiency threading\n" ); H2( " --thread-input Run Avisynth in its own thread\n" ); @@ -668,6 +673,8 @@ static struct option long_options[] = { "ssim", no_argument, NULL, 0 }, { "quiet", no_argument, NULL, OPT_QUIET }, { "verbose", no_argument, NULL, 'v' }, + { "log-file" ,required_argument, NULL, 0 }, + { "log-file-level",required_argument, NULL, 0 }, { "no-progress", no_argument, NULL, OPT_NOPROGRESS }, { "visualize", no_argument, NULL, OPT_VISUALIZE }, { "dump-yuv", required_argument, NULL, 0 }, @@ -715,11 +722,11 @@ static int select_output( const char *mu param->b_repeat_headers = 0; if( param->i_nal_hrd == X264_NAL_HRD_CBR ) { - fprintf( stderr, "x264 [warning]: cbr nal-hrd is not compatible with mp4\n" ); + LOG( param, ERROR, ERROR, "x264 [warning]: cbr nal-hrd is not compatible with mp4\n" ); param->i_nal_hrd = X264_NAL_HRD_VBR; } #else - fprintf( stderr, "x264 [error]: not compiled with MP4 output support\n" ); + LOG( param, ERROR, ERROR, "x264 [error]: not compiled with MP4 output support\n" ); return -1; #endif } @@ -1002,7 +1009,7 @@ static int Parse( int argc, char **argv, i++; if( !muxer_names[i] ) { - fprintf( stderr, "x264 [error]: invalid muxer '%s'\n", optarg ); + LOG( param, ERROR, ERROR, "x264 [error]: invalid muxer '%s'\n", optarg ); return -1; } muxer = optarg; @@ -1012,7 +1019,7 @@ static int Parse( int argc, char **argv, i++; if( !demuxer_names[i] ) { - fprintf( stderr, "x264 [error]: invalid demuxer '%s'\n", optarg ); + LOG( param, ERROR, ERROR, "x264 [error]: invalid demuxer '%s'\n", optarg ); return -1; } demuxer = optarg; @@ -1024,12 +1031,12 @@ static int Parse( int argc, char **argv, opt->qpfile = fopen( optarg, "rb" ); if( !opt->qpfile ) { - fprintf( stderr, "x264 [error]: can't open qpfile `%s'\n", optarg ); + LOG( param, ERROR, ERROR, "x264 [error]: can't open qpfile `%s'\n", optarg ); return -1; } else if( !x264_is_regular_file( opt->qpfile ) ) { - fprintf( stderr, "x264 [error]: qpfile incompatible with non-regular file `%s'\n", optarg ); + LOG( param, ERROR, ERROR, "x264 [error]: qpfile incompatible with non-regular file `%s'\n", optarg ); fclose( opt->qpfile ); return -1; } @@ -1051,7 +1058,7 @@ static int Parse( int argc, char **argv, param->b_visualize = 1; b_exit_on_ctrl_c = 1; #else - fprintf( stderr, "x264 [warning]: not compiled with visualization support\n" ); + LOG( param, WARNING, WARNING, "x264 [warning]: not compiled with visualization support\n" ); #endif break; case OPT_TUNE: @@ -1078,7 +1085,7 @@ static int Parse( int argc, char **argv, i++; if( !pulldown_names[i] ) { - fprintf( stderr, "x264 [error]: invalid pulldown '%s'\n", optarg ); + LOG( param, ERROR, ERROR, "x264 [error]: invalid pulldown '%s'\n", optarg ); return -1; } opt->i_pulldown = i; @@ -1109,7 +1116,7 @@ generic_option: if( b_error ) { const char *name = long_options_index > 0 ? long_options[long_options_index].name : argv[optind-2]; - fprintf( stderr, "x264 [error]: invalid argument: %s = %s\n", name, optarg ); + LOG( param, ERROR, ERROR, "x264 [error]: invalid argument: %s = %s\n", name, optarg ); return -1; } } @@ -1125,7 +1132,7 @@ generic_option: /* Get the file name */ if( optind > argc - 1 || !output_filename ) { - fprintf( stderr, "x264 [error]: No %s file. Run x264 --help for a list of options.\n", + LOG( param, ERROR, ERROR, "x264 [error]: No %s file. Run x264 --help for a list of options.\n", optind > argc - 1 ? "input" : "output" ); return -1; } @@ -1134,7 +1141,7 @@ generic_option: return -1; if( output.open_file( output_filename, &opt->hout ) ) { - fprintf( stderr, "x264 [error]: could not open output file `%s'\n", output_filename ); + LOG( param, ERROR, ERROR, "x264 [error]: could not open output file `%s'\n", output_filename ); return -1; } @@ -1157,14 +1164,14 @@ generic_option: if( !opt->hin && input.open_file( input_filename, &opt->hin, &info, &input_opt ) ) { - fprintf( stderr, "x264 [error]: could not open input file `%s'\n", input_filename ); + LOG( param, ERROR, ERROR, "x264 [error]: could not open input file `%s'\n", input_filename ); return -1; } x264_reduce_fraction( &info.sar_width, &info.sar_height ); x264_reduce_fraction( &info.fps_num, &info.fps_den ); if( param->i_log_level >= X264_LOG_INFO ) - fprintf( stderr, "%s [info]: %dx%d%c %d:%d @ %d/%d fps (%cfr)\n", demuxername, info.width, + LOG( param, ERROR, ERROR, "%s [info]: %dx%d%c %d:%d @ %d/%d fps (%cfr)\n", demuxername, info.width, info.height, info.interlaced ? 'i' : 'p', info.sar_width, info.sar_height, info.fps_num, info.fps_den, info.vfr ? 'v' : 'c' ); @@ -1175,7 +1182,7 @@ generic_option: param->i_width = info.width; if( !b_user_interlaced && info.interlaced ) { - fprintf( stderr, "x264 [warning]: input appears to be interlaced, enabling interlaced mode.\n" + LOG( param, ERROR, ERROR, "x264 [warning]: input appears to be interlaced, enabling interlaced mode.\n" " If you want otherwise, use --no-interlaced\n" ); param->b_interlaced = 1; } @@ -1206,7 +1213,7 @@ generic_option: { if( thread_input.open_file( NULL, &opt->hin, &info, NULL ) ) { - fprintf( stderr, "x264 [error]: threaded input failed\n" ); + LOG( param, ERROR, ERROR, "x264 [error]: threaded input failed\n" ); return -1; } else @@ -1363,10 +1370,12 @@ static int Encode( x264_param_t *param, return -1; } + OPEN_LOG( param, "ab" ); if( ( h = x264_encoder_open( param ) ) == NULL ) { - fprintf( stderr, "x264 [error]: x264_encoder_open failed\n" ); + LOG( param, ERROR, ERROR, "x264 [error]: x264_encoder_open failed\n" ); input.close_file( opt->hin ); + CLOSE_LOG; return -1; } @@ -1376,16 +1385,18 @@ static int Encode( x264_param_t *param, if( output.set_param( opt->hout, param ) ) { - fprintf( stderr, "x264 [error]: can't set outfile param\n" ); + LOG( param, ERROR, ERROR, "x264 [error]: can't set outfile param\n" ); input.close_file( opt->hin ); output.close_file( opt->hout, largest_pts, second_largest_pts ); + CLOSE_LOG; return -1; } /* Create a new pic */ if( input.picture_alloc( &pic, param->i_csp, param->i_width, param->i_height ) ) { - fprintf( stderr, "x264 [error]: malloc failed\n" ); + LOG( param, ERROR, ERROR, "x264 [error]: malloc failed\n" ); + CLOSE_LOG; return -1; } @@ -1394,7 +1405,8 @@ static int Encode( x264_param_t *param, ticks_per_frame = (int64_t)param->i_timebase_den * param->i_fps_den / param->i_timebase_num / param->i_fps_num; if( ticks_per_frame < 1 ) { - fprintf( stderr, "x264 [error]: ticks_per_frame invalid: %"PRId64"\n", ticks_per_frame ); + LOG( param, ERROR, ERROR, "x264 [error]: ticks_per_frame invalid: %"PRId64"\n", ticks_per_frame ); + CLOSE_LOG; return -1; } @@ -1406,14 +1418,19 @@ static int Encode( x264_param_t *param, if( x264_encoder_headers( h, &headers, &i_nal ) < 0 ) { - fprintf( stderr, "x264 [error]: x264_encoder_headers failed\n" ); + LOG( param, ERROR, ERROR, "x264 [error]: x264_encoder_headers failed\n" ); + CLOSE_LOG; return -1; } if( (i_file = output.write_headers( opt->hout, headers )) < 0 ) + { + CLOSE_LOG; return -1; + } } + CLOSE_LOG; /* Encode frames */ for( i_frame = 0, i_frame_output = 0; b_ctrl_c == 0 && (i_frame < i_frame_total || i_frame_total == 0); ) { @@ -1435,10 +1452,14 @@ static int Encode( x264_param_t *param, if( param->i_log_level >= X264_LOG_WARNING ) { if( param->i_log_level >= X264_LOG_DEBUG || pts_warning_cnt < MAX_PTS_WARNING ) - fprintf( stderr, "x264 [warning]: non-strictly-monotonic pts at frame %d (%"PRId64" <= %"PRId64")\n", + { + LOG( param, WARNING, WARNING, "x264 [warning]: non-strictly-monotonic pts at frame %d (%"PRId64" <= %"PRId64")\n", i_frame, pic.i_pts * dts_compress_multiplier, largest_pts * dts_compress_multiplier ); + } else if( pts_warning_cnt == MAX_PTS_WARNING ) - fprintf( stderr, "x264 [warning]: too many nonmonotonic pts warnings, suppressing further ones\n" ); + { + LOG( param, WARNING, WARNING, "x264 [warning]: too many nonmonotonic pts warnings, suppressing further ones\n" ); + } pts_warning_cnt++; } pic.i_pts = largest_pts + ticks_per_frame; @@ -1485,7 +1506,7 @@ static int Encode( x264_param_t *param, Print_status( i_start, i_frame_output, i_frame_total, i_file, param, last_pts ); } if( pts_warning_cnt >= MAX_PTS_WARNING && param->i_log_level < X264_LOG_DEBUG ) - fprintf( stderr, "x264 [warning]: %d suppressed nonmonotonic pts warnings\n", pts_warning_cnt-MAX_PTS_WARNING ); + LOG( param, WARNING, WARNING, "x264 [warning]: %d suppressed nonmonotonic pts warnings\n", pts_warning_cnt-MAX_PTS_WARNING ); /* duration algorithm fails when only 1 frame is output */ if( i_frame_output == 1 ) @@ -1503,7 +1524,7 @@ static int Encode( x264_param_t *param, 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 ); + LOG( param, INFO, INFO, "aborted at input frame %d, output frame %d\n", opt->i_seek + i_frame, i_frame_output ); input.close_file( opt->hin ); output.close_file( opt->hout, largest_pts, second_largest_pts ); @@ -1513,12 +1534,13 @@ static int Encode( x264_param_t *param, 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, + LOG( param, INFO, INFO, "encoded %d frames, %.2f fps, %.2f kb/s\n", i_frame_output, fps, (double) i_file * 8 / ( 1000 * duration ) ); } if( param->b_pulldown ) free( pulldown.pattern ); + CLOSE_LOG; return 0; } diff -uNrp c/x264.h b/x264.h --- c/x264.h 2010-02-25 11:28:56 +0200 +++ b/x264.h 2010-02-25 11:29:25 +0200 @@ -239,6 +239,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; int b_visualize; char *psz_dump_yuv; /* filename for reconstructed frames */