diff -uNrp a/cli_common.h b/cli_common.h --- a/cli_common.h 1970-01-01 02:00:00 +0200 +++ b/cli_common.h 2009-10-09 12:18:58 +0300 @@ -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 a/common/common.c b/common/common.c --- a/common/common.c 2009-10-08 11:56:21 +0300 +++ b/common/common.c 2009-10-09 12:20:18 +0300 @@ -117,6 +117,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; @@ -467,6 +468,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 VISUALIZE OPT("visualize") p->b_visualize = atobool(value); @@ -625,6 +630,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: ****************************************************************************/ @@ -640,6 +671,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 a/common/common.h b/common/common.h --- a/common/common.h 2009-10-08 11:56:21 +0300 +++ b/common/common.h 2009-10-09 12:20:37 +0300 @@ -406,7 +406,8 @@ struct x264_t x264_frame_t *fref1[16+3]; /* ref list 1 */ int b_ref_reorder[2]; - + /* log */ + FILE *p_log_file; /* Current MB DCT coeffs */ struct diff -uNrp a/encoder/encoder.c b/encoder/encoder.c --- a/encoder/encoder.c 2009-10-08 11:56:21 +0300 +++ b/encoder/encoder.c 2009-10-09 12:43:06 +0300 @@ -740,6 +740,14 @@ static void x264_set_aspect_ratio( x264_ } } +#define LOG_CLEANUP \ +{ \ + if( h->p_log_file ) \ + { \ + fclose( h->p_log_file ); \ + h->p_log_file = NULL; \ + } \ +} /**************************************************************************** * x264_encoder_open: ****************************************************************************/ @@ -757,12 +765,28 @@ 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 ) + { + LOG_CLEANUP; goto fail; + } if( h->param.psz_cqm_file ) if( x264_cqm_parse_file( h, h->param.psz_cqm_file ) < 0 ) + { + LOG_CLEANUP; goto fail; + } if( h->param.rc.psz_stat_out ) h->param.rc.psz_stat_out = strdup( h->param.rc.psz_stat_out ); @@ -789,7 +813,10 @@ x264_t *x264_encoder_open( x264_param_t h->chroma_qp_table = i_chroma_qp_table + 12 + h->pps->i_chroma_qp_index_offset; if( x264_cqm_init( h ) < 0 ) + { + LOG_CLEANUP; goto fail; + } h->mb.i_mb_count = h->sps->i_mb_width * h->sps->i_mb_height; @@ -870,12 +897,20 @@ x264_t *x264_encoder_open( x264_param_t for( qp = h->param.rc.i_qp_min; qp <= h->param.rc.i_qp_max; qp++ ) if( x264_analyse_init_costs( h, qp ) ) + { + LOG_CLEANUP; goto fail; + } if( x264_analyse_init_costs( h, X264_LOOKAHEAD_QP ) ) + { + LOG_CLEANUP; goto fail; + } + if( h->cost_mv[1][2013] != 24 ) { x264_log( h, X264_LOG_ERROR, "MV cost test failed: x264 has been miscompiled!\n" ); + LOG_CLEANUP; goto fail; } @@ -898,20 +933,32 @@ x264_t *x264_encoder_open( x264_param_t *h->thread[i] = *h; h->thread[i]->fdec = x264_frame_pop_unused( h, 1 ); if( !h->thread[i]->fdec ) + { + LOG_CLEANUP; goto fail; + } CHECKED_MALLOC( h->thread[i]->out.p_bitstream, h->out.i_bitstream ); /* Start each thread with room for 8 NAL units; it'll realloc later if needed. */ CHECKED_MALLOC( h->thread[i]->out.nal, 8*sizeof(x264_nal_t) ); h->thread[i]->out.i_nals_allocated = 8; if( x264_macroblock_cache_init( h->thread[i] ) < 0 ) + { + LOG_CLEANUP; goto fail; + } } if( x264_lookahead_init( h, i_slicetype_length ) ) + { + LOG_CLEANUP; goto fail; + } if( x264_ratecontrol_new( h ) < 0 ) + { + LOG_CLEANUP; goto fail; + } if( h->param.psz_dump_yuv ) { @@ -922,6 +969,7 @@ x264_t *x264_encoder_open( x264_param_t else { x264_log( h, X264_LOG_ERROR, "can't write to fdec.yuv\n" ); + LOG_CLEANUP; goto fail; } } @@ -2337,6 +2385,13 @@ void x264_encoder_close ( x264_t *h 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->param.i_threads > 1) h = h->thread[ h->i_thread_phase % h->param.i_threads ]; diff -uNrp a/muxers.c b/muxers.c --- a/muxers.c 2009-10-08 11:56:21 +0300 +++ b/muxers.c 2009-10-09 12:50:52 +0300 @@ -25,6 +25,7 @@ #include "x264.h" #include "matroska.h" #include "muxers.h" +#include "cli_common.h" #include "config.h" #include @@ -75,6 +76,7 @@ int open_file_yuv( char *psz_filename, h return -1; *p_handle = (hnd_t)h; + CLOSE_LOG; return 0; } @@ -192,7 +194,7 @@ int open_file_y4m( char *psz_filename, h case 'C': /* Color space */ if( strncmp( "420", tokstart, 3 ) ) { - fprintf( stderr, "Colorspace unhandled\n" ); + LOG( p_param, NONE, ERROR, "Colorspace unhandled\n"); return -1; } tokstart = strchr( tokstart, 0x20 ); @@ -206,7 +208,7 @@ int open_file_y4m( char *psz_filename, h case 'b': case 'm': default: - fprintf( stderr, "Warning, this sequence might be interlaced\n" ); + LOG( p_param, WARNING, WARNING, "Warning, this sequence might be interlaced\n" ); } break; case 'F': /* Frame rate - 0:0 if unknown */ @@ -237,7 +239,7 @@ int open_file_y4m( char *psz_filename, h strncmp( "420MPEG2",tokstart, 8 ) && strncmp( "420PALDV",tokstart, 8 ) ) { - fprintf( stderr, "Unsupported extended colorspace\n" ); + LOG( p_param, NONE, ERROR, "Unsupported extended colorspace\n"); return -1; } } @@ -246,11 +248,12 @@ int open_file_y4m( char *psz_filename, h } } - fprintf( stderr, "yuv4mpeg: %ix%i@%i/%ifps, %i:%i\n", + LOG( p_param, INFO, INFO, "yuv4mpeg: %ix%i@%i/%ifps, %i:%i\n", h->width, h->height, p_param->i_fps_num, p_param->i_fps_den, p_param->vui.i_sar_width, p_param->vui.i_sar_height ); *p_handle = (hnd_t)h; + CLOSE_LOG; return 0; } @@ -364,7 +367,7 @@ int open_file_avis( char *psz_filename, // check input format if( info.fccHandler != MAKEFOURCC('Y', 'V', '1', '2') ) { - fprintf( stderr, "avis [error]: unsupported input format (%c%c%c%c)\n", + LOG( p_param, NONE, ERROR, "avis [error]: unsupported input format (%c%c%c%c)\n", (char)(info.fccHandler & 0xff), (char)((info.fccHandler >> 8) & 0xff), (char)((info.fccHandler >> 16) & 0xff), (char)((info.fccHandler >> 24)) ); @@ -382,11 +385,12 @@ int open_file_avis( char *psz_filename, p_param->i_fps_den = info.dwScale / i; p_param->i_fps_num = info.dwRate / i; - fprintf( stderr, "avis [info]: %dx%d @ %.2f fps (%d frames)\n", + LOG( p_param, INFO, INFO, "avis [info]: %dx%d @ %.2f fps (%d frames)\n", p_param->i_width, p_param->i_height, (double)p_param->i_fps_num / (double)p_param->i_fps_den, (int)info.dwLength ); + CLOSE_LOG; return 0; } @@ -451,7 +455,7 @@ int open_file_thread( char *psz_filename thread_input_t *h = malloc( sizeof(thread_input_t) ); if( !h || x264_picture_alloc( &h->pic, X264_CSP_I420, p_param->i_width, p_param->i_height ) < 0 ) { - fprintf( stderr, "x264 [error]: malloc failed\n" ); + LOG( p_param, NONE, ERROR, "x264 [error]: malloc failed\n" ); return -1; } h->p_read_frame = p_read_frame; @@ -731,6 +735,7 @@ int set_param_mp4( hnd_t handle, x264_pa fprintf( stderr, "mp4 [info]: initial delay %d (scale %d)\n", p_mp4->i_init_delay, p_mp4->i_time_res ); + CLOSE_LOG; return 0; } diff -uNrp a/x264.c b/x264.c --- a/x264.c 2009-10-08 11:56:21 +0300 +++ b/x264.c 2009-10-09 13:06:48 +0300 @@ -32,6 +32,7 @@ #include "common/cpu.h" #include "x264.h" #include "muxers.h" +#include "cli_common.h" #include "config.h" #ifdef _WIN32 @@ -84,6 +85,7 @@ static int Encode( x264_param_t *param, ****************************************************************************/ int main( int argc, char **argv ) { + f_log_file = NULL; x264_param_t param; cli_opt_t opt; int ret; @@ -372,6 +374,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( " --thread-input Run Avisynth in its own thread\n" ); H2( " --sync-lookahead Number of buffer frames for threaded lookahead\n" ); @@ -498,6 +503,8 @@ static struct option long_options[] = { "quiet", no_argument, NULL, OPT_QUIET }, { "verbose", no_argument, NULL, 'v' }, { "no-progress", no_argument, NULL, OPT_NOPROGRESS }, + { "log-file" ,required_argument, NULL, 0 }, + { "log-file-level",required_argument, NULL, 0 }, { "visualize", no_argument, NULL, OPT_VISUALIZE }, { "dump-yuv", required_argument, NULL, 0 }, { "sps-id", required_argument, NULL, 0 }, @@ -663,7 +670,7 @@ static int Parse( int argc, char **argv } else { - fprintf( stderr, "x264 [error]: invalid preset: %s\n", optarg ); + LOG( param, NONE, ERROR, "x264 [error]: invalid preset: %s\n", optarg ); return -1; } } @@ -736,7 +743,7 @@ static int Parse( int argc, char **argv } else { - fprintf( stderr, "x264 [error]: invalid tune: %s\n", optarg ); + LOG( param, NONE, ERROR, "x264 [error]: invalid tune: %s\n", optarg ); return -1; } } @@ -797,7 +804,7 @@ static int Parse( int argc, char **argv p_set_eop = set_eop_mp4; p_close_outfile = close_file_mp4; #else - fprintf( stderr, "x264 [error]: not compiled with MP4 output support\n" ); + LOG( param, NONE, ERROR, "x264 [error]: not compiled with MP4 output support\n" ); return -1; #endif } @@ -813,7 +820,7 @@ static int Parse( int argc, char **argv opt->hout = stdout; else if( p_open_outfile( optarg, &opt->hout ) ) { - fprintf( stderr, "x264 [error]: can't open output file `%s'\n", optarg ); + LOG( param, NONE, ERROR, "x264 [error]: can't open output file `%s'\n", optarg ); return -1; } break; @@ -821,7 +828,7 @@ static int Parse( int argc, char **argv opt->qpfile = fopen( optarg, "rb" ); if( !opt->qpfile ) { - fprintf( stderr, "x264 [error]: can't open `%s'\n", optarg ); + LOG( param, NONE, ERROR, "x264 [error]: can't open `%s'\n", optarg ); return -1; } break; @@ -842,7 +849,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: @@ -889,7 +896,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, NONE, ERROR, "x264 [error]: invalid argument: %s = %s\n", name, optarg ); return -1; } } @@ -916,7 +923,7 @@ generic_option: param->i_bframe = 0; if( param->b_interlaced ) { - fprintf( stderr, "x264 [error]: baseline profile doesn't support interlacing\n" ); + LOG( param, NONE, ERROR, "x264 [error]: baseline profile doesn't support interlacing\n" ); return -1; } } @@ -931,13 +938,13 @@ generic_option: } else { - fprintf( stderr, "x264 [error]: invalid profile: %s\n", profile ); + LOG( param, NONE, 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, NONE, ERROR, "x264 [error]: %s profile doesn't support lossless\n", profile ); return -1; } } @@ -945,7 +952,7 @@ generic_option: /* Get the file name */ if( optind > argc - 1 || !opt->hout ) { - fprintf( stderr, "x264 [error]: No %s file. Run x264 --help for a list of options.\n", + LOG( param, NONE, ERROR, "x264 [error]: No %s file. Run x264 --help for a list of options.\n", optind > argc - 1 ? "input" : "output" ); return -1; } @@ -960,6 +967,8 @@ generic_option: if( !strncasecmp( psz, ".y4m", 4 ) ) b_y4m = 1; + OPEN_LOG( param, "wb"); + if( !(b_avis || b_y4m) ) // raw yuv { if( optind > argc - 1 ) @@ -970,8 +979,7 @@ generic_option: if( *psz >= '0' && *psz <= '9' && sscanf( psz, "%ux%u", ¶m->i_width, ¶m->i_height ) == 2 ) { - if( param->i_log_level >= X264_LOG_INFO ) - fprintf( stderr, "x264 [info]: %dx%d (given by file name) @ %.2f fps\n", param->i_width, param->i_height, (double)param->i_fps_num / (double)param->i_fps_den); + LOG( param, INFO, INFO, "x264 [info]: %dx%d (given by file name) @ %.2f fps\n", param->i_width, param->i_height, (double)param->i_fps_num / (double)param->i_fps_den); break; } } @@ -979,14 +987,13 @@ generic_option: else { sscanf( argv[optind++], "%ux%u", ¶m->i_width, ¶m->i_height ); - if( param->i_log_level >= X264_LOG_INFO ) - fprintf( stderr, "x264 [info]: %dx%d @ %.2f fps\n", param->i_width, param->i_height, (double)param->i_fps_num / (double)param->i_fps_den); + LOG( param, INFO, INFO, "x264 [info]: %dx%d @ %.2f fps\n", param->i_width, param->i_height, (double)param->i_fps_num / (double)param->i_fps_den); } } if( !(b_avis || b_y4m) && ( !param->i_width || !param->i_height ) ) { - fprintf( stderr, "x264 [error]: Rawyuv input requires a resolution.\n" ); + LOG( param, NONE, ERROR, "x264 [error]: Rawyuv input requires a resolution.\n" ); return -1; } @@ -1002,7 +1009,7 @@ generic_option: p_read_frame = read_frame_avis; p_close_infile = close_file_avis; #else - fprintf( stderr, "x264 [error]: not compiled with AVIS input support\n" ); + LOG( param, ERROR, ERROR, "x264 [error]: not compiled with AVIS input support\n" ); return -1; #endif } @@ -1016,7 +1023,7 @@ generic_option: if( p_open_infile( psz_filename, &opt->hin, param ) ) { - fprintf( stderr, "x264 [error]: could not open input file '%s'\n", psz_filename ); + LOG( param, NONE, ERROR, "x264 [error]: could not open input file '%s'\n", psz_filename ); return -1; } /* Restore the user's frame rate if fps has been explicitly set on the commandline. */ @@ -1033,7 +1040,7 @@ generic_option: { if( open_file_thread( NULL, &opt->hin, param ) ) { - fprintf( stderr, "x264 [error]: threaded input failed\n" ); + LOG( param, WARNING, WARNING, "x264 [warning]: threaded input failed\n" ); return -1; } else @@ -1119,7 +1126,7 @@ static int Encode_frame( x264_t *h, hnd if( x264_encoder_encode( h, &nal, &i_nal, pic, &pic_out ) < 0 ) { - fprintf( stderr, "x264 [error]: x264_encoder_encode failed\n" ); + LOG( (&h->param), NONE, ERROR, "x264 [error]: x264_encoder_encode failed\n" ); return -1; } @@ -1180,25 +1187,29 @@ static int Encode( x264_param_t *param, 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" ); p_close_infile( opt->hin ); + CLOSE_LOG; return -1; } if( p_set_outfile_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" ); p_close_infile( opt->hin ); p_close_outfile( opt->hout ); + CLOSE_LOG; return -1; } /* Create a new pic */ if( x264_picture_alloc( &pic, X264_CSP_I420, param->i_width, param->i_height ) < 0 ) { - fprintf( stderr, "x264 [error]: malloc failed\n" ); + LOG( param, NONE, ERROR, "x264 [error]: malloc failed\n" ); + CLOSE_LOG; return -1; } + CLOSE_LOG; i_start = x264_mdate(); @@ -1254,8 +1265,9 @@ static int Encode( x264_param_t *param, x264_free( mux_buffer ); fprintf( stderr, "\n" ); + OPEN_LOG( param, "ab" ); 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 ); p_close_infile( opt->hin ); p_close_outfile( opt->hout ); @@ -1265,10 +1277,11 @@ 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 * param->i_fps_num / ( (double) param->i_fps_den * i_frame_output * 1000 ) ); } + CLOSE_LOG; return 0; } diff -uNrp a/x264.h b/x264.h --- a/x264.h 2009-10-08 11:56:21 +0300 +++ b/x264.h 2009-10-09 13:10:58 +0300 @@ -221,6 +221,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 */