... | ... |
@@ -55,6 +55,8 @@ AVDictionary *format_opts, *codec_opts; |
55 | 55 |
|
56 | 56 |
static const int this_year = 2011; |
57 | 57 |
|
58 |
+static FILE *report_file; |
|
59 |
+ |
|
58 | 60 |
void init_opts(void) |
59 | 61 |
{ |
60 | 62 |
#if CONFIG_SWSCALE |
... | ... |
@@ -77,6 +79,20 @@ void log_callback_help(void* ptr, int level, const char* fmt, va_list vl) |
77 | 77 |
vfprintf(stdout, fmt, vl); |
78 | 78 |
} |
79 | 79 |
|
80 |
+static void log_callback_report(void *ptr, int level, const char *fmt, va_list vl) |
|
81 |
+{ |
|
82 |
+ va_list vl2; |
|
83 |
+ char line[1024]; |
|
84 |
+ static int print_prefix = 1; |
|
85 |
+ |
|
86 |
+ va_copy(vl2, vl); |
|
87 |
+ av_log_default_callback(ptr, level, fmt, vl); |
|
88 |
+ av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix); |
|
89 |
+ va_end(vl2); |
|
90 |
+ fputs(line, report_file); |
|
91 |
+ fflush(report_file); |
|
92 |
+} |
|
93 |
+ |
|
80 | 94 |
double parse_number_or_die(const char *context, const char *numstr, int type, double min, double max) |
81 | 95 |
{ |
82 | 96 |
char *tail; |
... | ... |
@@ -344,6 +360,30 @@ static int locate_option(int argc, char **argv, const OptionDef *options, const |
344 | 344 |
return 0; |
345 | 345 |
} |
346 | 346 |
|
347 |
+static void dump_argument(const char *a) |
|
348 |
+{ |
|
349 |
+ const unsigned char *p; |
|
350 |
+ |
|
351 |
+ for (p = a; *p; p++) |
|
352 |
+ if (!((*p >= '+' && *p <= ':') || (*p >= '@' && *p <= 'Z') || |
|
353 |
+ *p == '_' || (*p >= 'a' && *p <= 'z'))) |
|
354 |
+ break; |
|
355 |
+ if (!*p) { |
|
356 |
+ fputs(a, report_file); |
|
357 |
+ return; |
|
358 |
+ } |
|
359 |
+ fputc('"', report_file); |
|
360 |
+ for (p = a; *p; p++) { |
|
361 |
+ if (*p == '\\' || *p == '"' || *p == '$' || *p == '`') |
|
362 |
+ fprintf(report_file, "\\%c", *p); |
|
363 |
+ else if (*p < ' ' || *p > '~') |
|
364 |
+ fprintf(report_file, "\\x%02x", *p); |
|
365 |
+ else |
|
366 |
+ fputc(*p, report_file); |
|
367 |
+ } |
|
368 |
+ fputc('"', report_file); |
|
369 |
+} |
|
370 |
+ |
|
347 | 371 |
void parse_loglevel(int argc, char **argv, const OptionDef *options) |
348 | 372 |
{ |
349 | 373 |
int idx = locate_option(argc, argv, options, "loglevel"); |
... | ... |
@@ -351,6 +391,19 @@ void parse_loglevel(int argc, char **argv, const OptionDef *options) |
351 | 351 |
idx = locate_option(argc, argv, options, "v"); |
352 | 352 |
if (idx && argv[idx + 1]) |
353 | 353 |
opt_loglevel("loglevel", argv[idx + 1]); |
354 |
+ idx = locate_option(argc, argv, options, "report"); |
|
355 |
+ if (idx || getenv("FFREPORT")) { |
|
356 |
+ opt_report("report"); |
|
357 |
+ if (report_file) { |
|
358 |
+ int i; |
|
359 |
+ fprintf(report_file, "Command line:\n"); |
|
360 |
+ for (i = 0; i < argc; i++) { |
|
361 |
+ dump_argument(argv[i]); |
|
362 |
+ fputc(i < argc - 1 ? ' ' : '\n', report_file); |
|
363 |
+ } |
|
364 |
+ fflush(report_file); |
|
365 |
+ } |
|
366 |
+ } |
|
354 | 367 |
} |
355 | 368 |
|
356 | 369 |
#define FLAGS(o) ((o)->type == AV_OPT_TYPE_FLAGS) ? AV_DICT_APPEND : 0 |
... | ... |
@@ -424,6 +477,38 @@ int opt_loglevel(const char *opt, const char *arg) |
424 | 424 |
return 0; |
425 | 425 |
} |
426 | 426 |
|
427 |
+int opt_report(const char *opt) |
|
428 |
+{ |
|
429 |
+ char filename[64]; |
|
430 |
+ time_t now; |
|
431 |
+ struct tm *tm; |
|
432 |
+ |
|
433 |
+ if (report_file) /* already opened */ |
|
434 |
+ return 0; |
|
435 |
+ time(&now); |
|
436 |
+ tm = localtime(&now); |
|
437 |
+ snprintf(filename, sizeof(filename), "%s-%04d%02d%02d-%02d%02d%02d.log", |
|
438 |
+ program_name, |
|
439 |
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, |
|
440 |
+ tm->tm_hour, tm->tm_min, tm->tm_sec); |
|
441 |
+ report_file = fopen(filename, "w"); |
|
442 |
+ if (!report_file) { |
|
443 |
+ av_log(NULL, AV_LOG_ERROR, "Failed to open report \"%s\": %s\n", |
|
444 |
+ filename, strerror(errno)); |
|
445 |
+ return AVERROR(errno); |
|
446 |
+ } |
|
447 |
+ av_log_set_callback(log_callback_report); |
|
448 |
+ av_log(NULL, AV_LOG_INFO, |
|
449 |
+ "%s started on %04d-%02d-%02d at %02d:%02d:%02d\n" |
|
450 |
+ "Report written to \"%s\"\n", |
|
451 |
+ program_name, |
|
452 |
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, |
|
453 |
+ tm->tm_hour, tm->tm_min, tm->tm_sec, |
|
454 |
+ filename); |
|
455 |
+ av_log_set_level(FFMAX(av_log_get_level(), AV_LOG_VERBOSE)); |
|
456 |
+ return 0; |
|
457 |
+} |
|
458 |
+ |
|
427 | 459 |
int opt_codec_debug(const char *opt, const char *arg) |
428 | 460 |
{ |
429 | 461 |
av_log_set_level(AV_LOG_DEBUG); |
... | ... |
@@ -14,3 +14,4 @@ |
14 | 14 |
{ "loglevel", HAS_ARG, {(void*)opt_loglevel}, "set libav* logging level", "loglevel" }, |
15 | 15 |
{ "v", HAS_ARG, {(void*)opt_loglevel}, "set libav* logging level", "loglevel" }, |
16 | 16 |
{ "debug", HAS_ARG, {(void*)opt_codec_debug}, "set debug flags", "flags" }, |
17 |
+ { "report", 0, {(void*)opt_report}, "generate a report" }, |
... | ... |
@@ -123,6 +123,16 @@ the environment variable @env{FFMPEG_FORCE_COLOR}. |
123 | 123 |
The use of the environment variable @env{NO_COLOR} is deprecated and |
124 | 124 |
will be dropped in a following FFmpeg version. |
125 | 125 |
|
126 |
+@item -report |
|
127 |
+Dump full command line and console output to a file named |
|
128 |
+@code{@var{program}-@var{YYYYMMDD}-@var{HHMMSS}.log} in the current |
|
129 |
+directory. |
|
130 |
+This file can be useful for bug reports. |
|
131 |
+It also implies @code{-loglevel verbose}. |
|
132 |
+ |
|
133 |
+Note: setting the environment variable @code{FFREPORT} to any value has the |
|
134 |
+same effect. |
|
135 |
+ |
|
126 | 136 |
@end table |
127 | 137 |
|
128 | 138 |
@section AVOptions |