Signed-off-by: Tobias Rapp <t.rapp@noa-archive.com>
Tobias Rapp authored on 2016/02/11 21:35:21... | ... |
@@ -8526,6 +8526,12 @@ Float representation of @code{value} from metadata key. |
8526 | 8526 |
@item VALUE2 |
8527 | 8527 |
Float representation of @code{value} as supplied by user in @code{value} option. |
8528 | 8528 |
@end table |
8529 |
+ |
|
8530 |
+@item file |
|
8531 |
+If specified in @code{print} mode, output is written to the named file. When |
|
8532 |
+filename equals "-" data is written to standard output. |
|
8533 |
+If @code{file} option is not set, output is written to the log with AV_LOG_INFO |
|
8534 |
+loglevel. |
|
8529 | 8535 |
@end table |
8530 | 8536 |
|
8531 | 8537 |
@subsection Examples |
... | ... |
@@ -81,8 +81,12 @@ typedef struct MetadataContext { |
81 | 81 |
AVExpr *expr; |
82 | 82 |
double var_values[VAR_VARS_NB]; |
83 | 83 |
|
84 |
+ FILE *file; |
|
85 |
+ char *file_str; |
|
86 |
+ |
|
84 | 87 |
int (*compare)(struct MetadataContext *s, |
85 | 88 |
const char *value1, const char *value2, size_t length); |
89 |
+ void (*print)(AVFilterContext *ctx, const char *msg, ...) av_printf_format(2, 3); |
|
86 | 90 |
} MetadataContext; |
87 | 91 |
|
88 | 92 |
#define OFFSET(x) offsetof(MetadataContext, x) |
... | ... |
@@ -104,6 +108,7 @@ static const AVOption filt_name##_options[] = { \ |
104 | 104 |
{ "expr", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = METADATAF_EXPR }, 0, 3, FLAGS, "function" }, \ |
105 | 105 |
{ "expr", "set expression for expr function", OFFSET(expr_str), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, FLAGS }, \ |
106 | 106 |
{ "length", "compare up to N chars for string function", OFFSET(length), AV_OPT_TYPE_INT, {.i64 = INT_MAX }, 1, INT_MAX, FLAGS }, \ |
107 |
+ { "file", "set file where to print metadata information", OFFSET(file_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS }, \ |
|
107 | 108 |
{ NULL } \ |
108 | 109 |
} |
109 | 110 |
|
... | ... |
@@ -155,6 +160,27 @@ static int parse_expr(MetadataContext *s, const char *value1, const char *value2 |
155 | 155 |
return av_expr_eval(s->expr, s->var_values, NULL); |
156 | 156 |
} |
157 | 157 |
|
158 |
+static void print_log(AVFilterContext *ctx, const char *msg, ...) |
|
159 |
+{ |
|
160 |
+ va_list argument_list; |
|
161 |
+ |
|
162 |
+ va_start(argument_list, msg); |
|
163 |
+ if (msg) |
|
164 |
+ av_vlog(ctx, AV_LOG_INFO, msg, argument_list); |
|
165 |
+ va_end(argument_list); |
|
166 |
+} |
|
167 |
+ |
|
168 |
+static void print_file(AVFilterContext *ctx, const char *msg, ...) |
|
169 |
+{ |
|
170 |
+ MetadataContext *s = ctx->priv; |
|
171 |
+ va_list argument_list; |
|
172 |
+ |
|
173 |
+ va_start(argument_list, msg); |
|
174 |
+ if (msg) |
|
175 |
+ vfprintf(s->file, msg, argument_list); |
|
176 |
+ va_end(argument_list); |
|
177 |
+} |
|
178 |
+ |
|
158 | 179 |
static av_cold int init(AVFilterContext *ctx) |
159 | 180 |
{ |
160 | 181 |
MetadataContext *s = ctx->priv; |
... | ... |
@@ -203,9 +229,37 @@ static av_cold int init(AVFilterContext *ctx) |
203 | 203 |
} |
204 | 204 |
} |
205 | 205 |
|
206 |
+ if (s->file_str) { |
|
207 |
+ if (!strcmp(s->file_str, "-")) { |
|
208 |
+ s->file = stdout; |
|
209 |
+ } else { |
|
210 |
+ s->file = fopen(s->file_str, "w"); |
|
211 |
+ if (!s->file) { |
|
212 |
+ int err = AVERROR(errno); |
|
213 |
+ char buf[128]; |
|
214 |
+ av_strerror(err, buf, sizeof(buf)); |
|
215 |
+ av_log(ctx, AV_LOG_ERROR, "Could not open file %s: %s\n", |
|
216 |
+ s->file_str, buf); |
|
217 |
+ return err; |
|
218 |
+ } |
|
219 |
+ } |
|
220 |
+ s->print = print_file; |
|
221 |
+ } else { |
|
222 |
+ s->print = print_log; |
|
223 |
+ } |
|
224 |
+ |
|
206 | 225 |
return 0; |
207 | 226 |
} |
208 | 227 |
|
228 |
+static av_cold void uninit(AVFilterContext *ctx) |
|
229 |
+{ |
|
230 |
+ MetadataContext *s = ctx->priv; |
|
231 |
+ |
|
232 |
+ if (s->file && s->file != stdout) |
|
233 |
+ fclose(s->file); |
|
234 |
+ s->file = NULL; |
|
235 |
+} |
|
236 |
+ |
|
209 | 237 |
static int filter_frame(AVFilterLink *inlink, AVFrame *frame) |
210 | 238 |
{ |
211 | 239 |
AVFilterContext *ctx = inlink->dst; |
... | ... |
@@ -245,14 +299,14 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) |
245 | 245 |
break; |
246 | 246 |
case METADATA_PRINT: |
247 | 247 |
if (!s->key && e) { |
248 |
- av_log(ctx, AV_LOG_INFO, "frame %"PRId64" pts %"PRId64"\n", inlink->frame_count, frame->pts); |
|
249 |
- av_log(ctx, AV_LOG_INFO, "%s=%s\n", e->key, e->value); |
|
248 |
+ s->print(ctx, "frame %"PRId64" pts %"PRId64"\n", inlink->frame_count, frame->pts); |
|
249 |
+ s->print(ctx, "%s=%s\n", e->key, e->value); |
|
250 | 250 |
while ((e = av_dict_get(metadata, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL) { |
251 |
- av_log(ctx, AV_LOG_INFO, "%s=%s\n", e->key, e->value); |
|
251 |
+ s->print(ctx, "%s=%s\n", e->key, e->value); |
|
252 | 252 |
} |
253 | 253 |
} else if (e && e->value && (!s->value || (e->value && s->compare(s, e->value, s->value, s->length)))) { |
254 |
- av_log(ctx, AV_LOG_INFO, "frame %"PRId64" pts %"PRId64"\n", inlink->frame_count, frame->pts); |
|
255 |
- av_log(ctx, AV_LOG_INFO, "%s=%s\n", s->key, e->value); |
|
254 |
+ s->print(ctx, "frame %"PRId64" pts %"PRId64"\n", inlink->frame_count, frame->pts); |
|
255 |
+ s->print(ctx, "%s=%s\n", s->key, e->value); |
|
256 | 256 |
} |
257 | 257 |
return ff_filter_frame(outlink, frame); |
258 | 258 |
break; |
... | ... |
@@ -301,6 +355,7 @@ AVFilter ff_af_ametadata = { |
301 | 301 |
.priv_size = sizeof(MetadataContext), |
302 | 302 |
.priv_class = &ametadata_class, |
303 | 303 |
.init = init, |
304 |
+ .uninit = uninit, |
|
304 | 305 |
.query_formats = ff_query_formats_all, |
305 | 306 |
.inputs = ainputs, |
306 | 307 |
.outputs = aoutputs, |
... | ... |
@@ -336,6 +391,7 @@ AVFilter ff_vf_metadata = { |
336 | 336 |
.priv_size = sizeof(MetadataContext), |
337 | 337 |
.priv_class = &metadata_class, |
338 | 338 |
.init = init, |
339 |
+ .uninit = uninit, |
|
339 | 340 |
.inputs = inputs, |
340 | 341 |
.outputs = outputs, |
341 | 342 |
.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, |