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-15 15:05:17 +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-15 15:03:35 +0200 +++ b/common/common.c 2010-02-15 15:05:17 +0200 @@ -120,6 +120,7 @@ void x264_param_default( x264_param_t 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; @@ -490,6 +491,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); @@ -660,6 +665,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: ****************************************************************************/ @@ -675,6 +706,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-15 15:03:39 +0200 +++ b/common/common.h 2010-02-15 15:05:17 +0200 @@ -464,6 +464,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-15 15:03:43 +0200 +++ b/encoder/encoder.c 2010-02-15 15:05:17 +0200 @@ -984,6 +984,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; @@ -1236,6 +1246,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; } @@ -3209,6 +3224,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-15 15:03:35 +0200 +++ b/x264.c 2010-02-15 15:06:44 +0200 @@ -34,6 +34,7 @@ #include "common/cpu.h" #include "x264.h" #include "muxers.h" +#include "cli_common.h" #ifdef _WIN32 #include @@ -119,6 +120,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; @@ -520,6 +522,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" ); @@ -666,6 +671,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 }, @@ -717,7 +724,7 @@ static int select_output( const char *mu param->b_cbr_hrd = 0; } #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 } @@ -1016,7 +1023,7 @@ static int Parse( int argc, char **argv, } else { - fprintf( stderr, "x264 [error]: invalid preset '%s'\n", optarg ); + LOG( param, ERROR, ERROR, "x264 [error]: invalid preset '%s'\n", optarg ); return -1; } } @@ -1113,13 +1120,13 @@ static int Parse( int argc, char **argv, } else { - fprintf( stderr, "x264 [error]: invalid tune '%s'\n", s ); + LOG( param, ERROR, ERROR, "x264 [error]: invalid tune '%s'\n", s ); return -1; } if( 0 ) { psy_failure: - fprintf( stderr, "x264 [warning]: only 1 psy tuning can be used: ignoring tune %s\n", s ); + LOG( param, WARNING, WARNING, "x264 [warning]: only 1 psy tuning can be used: ignoring tune %s\n", s ); } s = strtok( NULL, ",./-+" ); } @@ -1179,7 +1186,7 @@ psy_failure: 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; @@ -1189,7 +1196,7 @@ psy_failure: 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; @@ -1201,12 +1208,12 @@ psy_failure: 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; } @@ -1228,7 +1235,7 @@ psy_failure: 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: @@ -1289,7 +1296,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; } } @@ -1317,7 +1324,7 @@ generic_option: param->analyse.i_weighted_pred = X264_WEIGHTP_NONE; if( param->b_interlaced ) { - fprintf( stderr, "x264 [error]: baseline profile doesn't support interlacing\n" ); + LOG( param, ERROR, ERROR, "x264 [error]: baseline profile doesn't support interlacing\n" ); return -1; } } @@ -1332,13 +1339,13 @@ generic_option: } else { - fprintf( stderr, "x264 [error]: invalid profile: %s\n", profile ); + LOG( param, ERROR, ERROR, "x264 [error]: invalid profile: %s\n", profile ); return -1; } if( (param->rc.i_rc_method == X264_RC_CQP && param->rc.i_qp_constant == 0) || (param->rc.i_rc_method == X264_RC_CRF && param->rc.f_rf_constant == 0) ) { - fprintf( stderr, "x264 [error]: %s profile doesn't support lossless\n", profile ); + LOG( param, ERROR, ERROR, "x264 [error]: %s profile doesn't support lossless\n", profile ); return -1; } } @@ -1346,7 +1353,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; } @@ -1355,7 +1362,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; } @@ -1378,7 +1385,7 @@ 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; } @@ -1396,7 +1403,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; } @@ -1427,7 +1434,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 @@ -1510,7 +1517,7 @@ static int Encode_frame( x264_t *h, hnd if( i_frame_size < 0 ) { - fprintf( stderr, "x264 [error]: x264_encoder_encode failed\n" ); + LOG( (&h->param), ERROR, ERROR, "x264 [error]: x264_encoder_encode failed\n" ); return -1; } @@ -1584,10 +1591,12 @@ static int Encode( x264_param_t *param, param->i_pulldown_delay = p_pulldown.i_delay; } + OPEN_LOG( param, "ab" ); if( ( h = x264_encoder_open( param ) ) == NULL ) { - fprintf( stderr, "x264 [error]: x264_encoder_open failed\n" ); + LOG( param, NONE, ERROR, "x264 [error]: x264_encoder_open failed\n" ); input.close_file( opt->hin ); + CLOSE_LOG; return -1; } @@ -1597,16 +1606,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, NONE, 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, NONE, ERROR, "x264 [error]: malloc failed\n" ); + CLOSE_LOG; return -1; } @@ -1615,7 +1626,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, NONE, ERROR, "x264 [error]: ticks_per_frame invalid: %"PRId64"\n", ticks_per_frame ); + CLOSE_LOG; return -1; } @@ -1627,7 +1639,8 @@ 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, NONE, ERROR, "x264 [error]: x264_encoder_headers failed\n" ); + CLOSE_LOG; return -1; } @@ -1648,10 +1661,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, NONE, 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, NONE, WARNING, "x264 [warning]: too many nonmonotonic pts warnings, suppressing further ones\n" ); + } pts_warning_cnt++; } pic.i_pts = largest_pts + ticks_per_frame; @@ -1700,7 +1717,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, NONE, 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 ) @@ -1718,7 +1735,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, NONE, 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 ); @@ -1728,12 +1745,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, NONE, INFO, "encoded %d frames, %.2f fps, %.2f kb/s\n", i_frame_output, fps, (double) i_file * 8 / ( 1000 * duration ) ); } if( opt->i_pulldown ) free(p_pulldown.pattern); + CLOSE_LOG; return 0; } diff -uNrp c/x264.h b/x264.h --- c/x264.h 2010-02-15 15:03:35 +0200 +++ b/x264.h 2010-02-15 15:05:17 +0200 @@ -234,6 +234,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 */