Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6148 | serge | 1 | /* |
2 | * filter layer |
||
3 | * Copyright (c) 2007 Bobby Bingham |
||
4 | * |
||
5 | * This file is part of FFmpeg. |
||
6 | * |
||
7 | * FFmpeg is free software; you can redistribute it and/or |
||
8 | * modify it under the terms of the GNU Lesser General Public |
||
9 | * License as published by the Free Software Foundation; either |
||
10 | * version 2.1 of the License, or (at your option) any later version. |
||
11 | * |
||
12 | * FFmpeg is distributed in the hope that it will be useful, |
||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
15 | * Lesser General Public License for more details. |
||
16 | * |
||
17 | * You should have received a copy of the GNU Lesser General Public |
||
18 | * License along with FFmpeg; if not, write to the Free Software |
||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||
20 | */ |
||
21 | |||
22 | #include "libavutil/atomic.h" |
||
23 | #include "libavutil/avassert.h" |
||
24 | #include "libavutil/avstring.h" |
||
25 | #include "libavutil/channel_layout.h" |
||
26 | #include "libavutil/common.h" |
||
27 | #include "libavutil/eval.h" |
||
28 | #include "libavutil/imgutils.h" |
||
29 | #include "libavutil/internal.h" |
||
30 | #include "libavutil/opt.h" |
||
31 | #include "libavutil/pixdesc.h" |
||
32 | #include "libavutil/rational.h" |
||
33 | #include "libavutil/samplefmt.h" |
||
34 | |||
35 | #include "audio.h" |
||
36 | #include "avfilter.h" |
||
37 | #include "formats.h" |
||
38 | #include "internal.h" |
||
39 | |||
40 | static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame); |
||
41 | |||
42 | void ff_tlog_ref(void *ctx, AVFrame *ref, int end) |
||
43 | { |
||
44 | av_unused char buf[16]; |
||
45 | ff_tlog(ctx, |
||
46 | "ref[%p buf:%p data:%p linesize[%d, %d, %d, %d] pts:%"PRId64" pos:%"PRId64, |
||
47 | ref, ref->buf, ref->data[0], |
||
48 | ref->linesize[0], ref->linesize[1], ref->linesize[2], ref->linesize[3], |
||
49 | ref->pts, av_frame_get_pkt_pos(ref)); |
||
50 | |||
51 | if (ref->width) { |
||
52 | ff_tlog(ctx, " a:%d/%d s:%dx%d i:%c iskey:%d type:%c", |
||
53 | ref->sample_aspect_ratio.num, ref->sample_aspect_ratio.den, |
||
54 | ref->width, ref->height, |
||
55 | !ref->interlaced_frame ? 'P' : /* Progressive */ |
||
56 | ref->top_field_first ? 'T' : 'B', /* Top / Bottom */ |
||
57 | ref->key_frame, |
||
58 | av_get_picture_type_char(ref->pict_type)); |
||
59 | } |
||
60 | if (ref->nb_samples) { |
||
61 | ff_tlog(ctx, " cl:%"PRId64"d n:%d r:%d", |
||
62 | ref->channel_layout, |
||
63 | ref->nb_samples, |
||
64 | ref->sample_rate); |
||
65 | } |
||
66 | |||
67 | ff_tlog(ctx, "]%s", end ? "\n" : ""); |
||
68 | } |
||
69 | |||
70 | unsigned avfilter_version(void) |
||
71 | { |
||
72 | av_assert0(LIBAVFILTER_VERSION_MICRO >= 100); |
||
73 | return LIBAVFILTER_VERSION_INT; |
||
74 | } |
||
75 | |||
76 | const char *avfilter_configuration(void) |
||
77 | { |
||
78 | return FFMPEG_CONFIGURATION; |
||
79 | } |
||
80 | |||
81 | const char *avfilter_license(void) |
||
82 | { |
||
83 | #define LICENSE_PREFIX "libavfilter license: " |
||
84 | return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; |
||
85 | } |
||
86 | |||
87 | void ff_command_queue_pop(AVFilterContext *filter) |
||
88 | { |
||
89 | AVFilterCommand *c= filter->command_queue; |
||
90 | av_freep(&c->arg); |
||
91 | av_freep(&c->command); |
||
92 | filter->command_queue= c->next; |
||
93 | av_free(c); |
||
94 | } |
||
95 | |||
96 | int ff_insert_pad(unsigned idx, unsigned *count, size_t padidx_off, |
||
97 | AVFilterPad **pads, AVFilterLink ***links, |
||
98 | AVFilterPad *newpad) |
||
99 | { |
||
100 | AVFilterLink **newlinks; |
||
101 | AVFilterPad *newpads; |
||
102 | unsigned i; |
||
103 | |||
104 | idx = FFMIN(idx, *count); |
||
105 | |||
106 | newpads = av_realloc_array(*pads, *count + 1, sizeof(AVFilterPad)); |
||
107 | newlinks = av_realloc_array(*links, *count + 1, sizeof(AVFilterLink*)); |
||
108 | if (newpads) |
||
109 | *pads = newpads; |
||
110 | if (newlinks) |
||
111 | *links = newlinks; |
||
112 | if (!newpads || !newlinks) |
||
113 | return AVERROR(ENOMEM); |
||
114 | |||
115 | memmove(*pads + idx + 1, *pads + idx, sizeof(AVFilterPad) * (*count - idx)); |
||
116 | memmove(*links + idx + 1, *links + idx, sizeof(AVFilterLink*) * (*count - idx)); |
||
117 | memcpy(*pads + idx, newpad, sizeof(AVFilterPad)); |
||
118 | (*links)[idx] = NULL; |
||
119 | |||
120 | (*count)++; |
||
121 | for (i = idx + 1; i < *count; i++) |
||
122 | if ((*links)[i]) |
||
123 | (*(unsigned *)((uint8_t *) (*links)[i] + padidx_off))++; |
||
124 | |||
125 | return 0; |
||
126 | } |
||
127 | |||
128 | int avfilter_link(AVFilterContext *src, unsigned srcpad, |
||
129 | AVFilterContext *dst, unsigned dstpad) |
||
130 | { |
||
131 | AVFilterLink *link; |
||
132 | |||
133 | if (src->nb_outputs <= srcpad || dst->nb_inputs <= dstpad || |
||
134 | src->outputs[srcpad] || dst->inputs[dstpad]) |
||
135 | return -1; |
||
136 | |||
137 | if (src->output_pads[srcpad].type != dst->input_pads[dstpad].type) { |
||
138 | av_log(src, AV_LOG_ERROR, |
||
139 | "Media type mismatch between the '%s' filter output pad %d (%s) and the '%s' filter input pad %d (%s)\n", |
||
140 | src->name, srcpad, (char *)av_x_if_null(av_get_media_type_string(src->output_pads[srcpad].type), "?"), |
||
141 | dst->name, dstpad, (char *)av_x_if_null(av_get_media_type_string(dst-> input_pads[dstpad].type), "?")); |
||
142 | return AVERROR(EINVAL); |
||
143 | } |
||
144 | |||
145 | link = av_mallocz(sizeof(*link)); |
||
146 | if (!link) |
||
147 | return AVERROR(ENOMEM); |
||
148 | |||
149 | src->outputs[srcpad] = dst->inputs[dstpad] = link; |
||
150 | |||
151 | link->src = src; |
||
152 | link->dst = dst; |
||
153 | link->srcpad = &src->output_pads[srcpad]; |
||
154 | link->dstpad = &dst->input_pads[dstpad]; |
||
155 | link->type = src->output_pads[srcpad].type; |
||
156 | av_assert0(AV_PIX_FMT_NONE == -1 && AV_SAMPLE_FMT_NONE == -1); |
||
157 | link->format = -1; |
||
158 | |||
159 | return 0; |
||
160 | } |
||
161 | |||
162 | void avfilter_link_free(AVFilterLink **link) |
||
163 | { |
||
164 | if (!*link) |
||
165 | return; |
||
166 | |||
167 | av_frame_free(&(*link)->partial_buf); |
||
168 | |||
169 | av_freep(link); |
||
170 | } |
||
171 | |||
172 | int avfilter_link_get_channels(AVFilterLink *link) |
||
173 | { |
||
174 | return link->channels; |
||
175 | } |
||
176 | |||
177 | void avfilter_link_set_closed(AVFilterLink *link, int closed) |
||
178 | { |
||
179 | link->closed = closed; |
||
180 | } |
||
181 | |||
182 | int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt, |
||
183 | unsigned filt_srcpad_idx, unsigned filt_dstpad_idx) |
||
184 | { |
||
185 | int ret; |
||
186 | unsigned dstpad_idx = link->dstpad - link->dst->input_pads; |
||
187 | |||
188 | av_log(link->dst, AV_LOG_VERBOSE, "auto-inserting filter '%s' " |
||
189 | "between the filter '%s' and the filter '%s'\n", |
||
190 | filt->name, link->src->name, link->dst->name); |
||
191 | |||
192 | link->dst->inputs[dstpad_idx] = NULL; |
||
193 | if ((ret = avfilter_link(filt, filt_dstpad_idx, link->dst, dstpad_idx)) < 0) { |
||
194 | /* failed to link output filter to new filter */ |
||
195 | link->dst->inputs[dstpad_idx] = link; |
||
196 | return ret; |
||
197 | } |
||
198 | |||
199 | /* re-hookup the link to the new destination filter we inserted */ |
||
200 | link->dst = filt; |
||
201 | link->dstpad = &filt->input_pads[filt_srcpad_idx]; |
||
202 | filt->inputs[filt_srcpad_idx] = link; |
||
203 | |||
204 | /* if any information on supported media formats already exists on the |
||
205 | * link, we need to preserve that */ |
||
206 | if (link->out_formats) |
||
207 | ff_formats_changeref(&link->out_formats, |
||
208 | &filt->outputs[filt_dstpad_idx]->out_formats); |
||
209 | if (link->out_samplerates) |
||
210 | ff_formats_changeref(&link->out_samplerates, |
||
211 | &filt->outputs[filt_dstpad_idx]->out_samplerates); |
||
212 | if (link->out_channel_layouts) |
||
213 | ff_channel_layouts_changeref(&link->out_channel_layouts, |
||
214 | &filt->outputs[filt_dstpad_idx]->out_channel_layouts); |
||
215 | |||
216 | return 0; |
||
217 | } |
||
218 | |||
219 | int avfilter_config_links(AVFilterContext *filter) |
||
220 | { |
||
221 | int (*config_link)(AVFilterLink *); |
||
222 | unsigned i; |
||
223 | int ret; |
||
224 | |||
225 | for (i = 0; i < filter->nb_inputs; i ++) { |
||
226 | AVFilterLink *link = filter->inputs[i]; |
||
227 | AVFilterLink *inlink; |
||
228 | |||
229 | if (!link) continue; |
||
230 | |||
231 | inlink = link->src->nb_inputs ? link->src->inputs[0] : NULL; |
||
232 | link->current_pts = AV_NOPTS_VALUE; |
||
233 | |||
234 | switch (link->init_state) { |
||
235 | case AVLINK_INIT: |
||
236 | continue; |
||
237 | case AVLINK_STARTINIT: |
||
238 | av_log(filter, AV_LOG_INFO, "circular filter chain detected\n"); |
||
239 | return 0; |
||
240 | case AVLINK_UNINIT: |
||
241 | link->init_state = AVLINK_STARTINIT; |
||
242 | |||
243 | if ((ret = avfilter_config_links(link->src)) < 0) |
||
244 | return ret; |
||
245 | |||
246 | if (!(config_link = link->srcpad->config_props)) { |
||
247 | if (link->src->nb_inputs != 1) { |
||
248 | av_log(link->src, AV_LOG_ERROR, "Source filters and filters " |
||
249 | "with more than one input " |
||
250 | "must set config_props() " |
||
251 | "callbacks on all outputs\n"); |
||
252 | return AVERROR(EINVAL); |
||
253 | } |
||
254 | } else if ((ret = config_link(link)) < 0) { |
||
255 | av_log(link->src, AV_LOG_ERROR, |
||
256 | "Failed to configure output pad on %s\n", |
||
257 | link->src->name); |
||
258 | return ret; |
||
259 | } |
||
260 | |||
261 | switch (link->type) { |
||
262 | case AVMEDIA_TYPE_VIDEO: |
||
263 | if (!link->time_base.num && !link->time_base.den) |
||
264 | link->time_base = inlink ? inlink->time_base : AV_TIME_BASE_Q; |
||
265 | |||
266 | if (!link->sample_aspect_ratio.num && !link->sample_aspect_ratio.den) |
||
267 | link->sample_aspect_ratio = inlink ? |
||
268 | inlink->sample_aspect_ratio : (AVRational){1,1}; |
||
269 | |||
270 | if (inlink && !link->frame_rate.num && !link->frame_rate.den) |
||
271 | link->frame_rate = inlink->frame_rate; |
||
272 | |||
273 | if (inlink) { |
||
274 | if (!link->w) |
||
275 | link->w = inlink->w; |
||
276 | if (!link->h) |
||
277 | link->h = inlink->h; |
||
278 | } else if (!link->w || !link->h) { |
||
279 | av_log(link->src, AV_LOG_ERROR, |
||
280 | "Video source filters must set their output link's " |
||
281 | "width and height\n"); |
||
282 | return AVERROR(EINVAL); |
||
283 | } |
||
284 | break; |
||
285 | |||
286 | case AVMEDIA_TYPE_AUDIO: |
||
287 | if (inlink) { |
||
288 | if (!link->time_base.num && !link->time_base.den) |
||
289 | link->time_base = inlink->time_base; |
||
290 | } |
||
291 | |||
292 | if (!link->time_base.num && !link->time_base.den) |
||
293 | link->time_base = (AVRational) {1, link->sample_rate}; |
||
294 | } |
||
295 | |||
296 | if ((config_link = link->dstpad->config_props)) |
||
297 | if ((ret = config_link(link)) < 0) { |
||
298 | av_log(link->src, AV_LOG_ERROR, |
||
299 | "Failed to configure input pad on %s\n", |
||
300 | link->dst->name); |
||
301 | return ret; |
||
302 | } |
||
303 | |||
304 | link->init_state = AVLINK_INIT; |
||
305 | } |
||
306 | } |
||
307 | |||
308 | return 0; |
||
309 | } |
||
310 | |||
311 | void ff_tlog_link(void *ctx, AVFilterLink *link, int end) |
||
312 | { |
||
313 | if (link->type == AVMEDIA_TYPE_VIDEO) { |
||
314 | ff_tlog(ctx, |
||
315 | "link[%p s:%dx%d fmt:%s %s->%s]%s", |
||
316 | link, link->w, link->h, |
||
317 | av_get_pix_fmt_name(link->format), |
||
318 | link->src ? link->src->filter->name : "", |
||
319 | link->dst ? link->dst->filter->name : "", |
||
320 | end ? "\n" : ""); |
||
321 | } else { |
||
322 | char buf[128]; |
||
323 | av_get_channel_layout_string(buf, sizeof(buf), -1, link->channel_layout); |
||
324 | |||
325 | ff_tlog(ctx, |
||
326 | "link[%p r:%d cl:%s fmt:%s %s->%s]%s", |
||
327 | link, (int)link->sample_rate, buf, |
||
328 | av_get_sample_fmt_name(link->format), |
||
329 | link->src ? link->src->filter->name : "", |
||
330 | link->dst ? link->dst->filter->name : "", |
||
331 | end ? "\n" : ""); |
||
332 | } |
||
333 | } |
||
334 | |||
335 | int ff_request_frame(AVFilterLink *link) |
||
336 | { |
||
337 | int ret = -1; |
||
338 | FF_TPRINTF_START(NULL, request_frame); ff_tlog_link(NULL, link, 1); |
||
339 | |||
340 | if (link->closed) |
||
341 | return AVERROR_EOF; |
||
342 | av_assert0(!link->frame_requested); |
||
343 | link->frame_requested = 1; |
||
344 | while (link->frame_requested) { |
||
345 | if (link->srcpad->request_frame) |
||
346 | ret = link->srcpad->request_frame(link); |
||
347 | else if (link->src->inputs[0]) |
||
348 | ret = ff_request_frame(link->src->inputs[0]); |
||
349 | if (ret == AVERROR_EOF && link->partial_buf) { |
||
350 | AVFrame *pbuf = link->partial_buf; |
||
351 | link->partial_buf = NULL; |
||
352 | ret = ff_filter_frame_framed(link, pbuf); |
||
353 | } |
||
354 | if (ret < 0) { |
||
355 | link->frame_requested = 0; |
||
356 | if (ret == AVERROR_EOF) |
||
357 | link->closed = 1; |
||
358 | } else { |
||
359 | av_assert0(!link->frame_requested || |
||
360 | link->flags & FF_LINK_FLAG_REQUEST_LOOP); |
||
361 | } |
||
362 | } |
||
363 | return ret; |
||
364 | } |
||
365 | |||
366 | int ff_poll_frame(AVFilterLink *link) |
||
367 | { |
||
368 | int i, min = INT_MAX; |
||
369 | |||
370 | if (link->srcpad->poll_frame) |
||
371 | return link->srcpad->poll_frame(link); |
||
372 | |||
373 | for (i = 0; i < link->src->nb_inputs; i++) { |
||
374 | int val; |
||
375 | if (!link->src->inputs[i]) |
||
376 | return -1; |
||
377 | val = ff_poll_frame(link->src->inputs[i]); |
||
378 | min = FFMIN(min, val); |
||
379 | } |
||
380 | |||
381 | return min; |
||
382 | } |
||
383 | |||
384 | static const char *const var_names[] = { "t", "n", "pos", NULL }; |
||
385 | enum { VAR_T, VAR_N, VAR_POS, VAR_VARS_NB }; |
||
386 | |||
387 | static int set_enable_expr(AVFilterContext *ctx, const char *expr) |
||
388 | { |
||
389 | int ret; |
||
390 | char *expr_dup; |
||
391 | AVExpr *old = ctx->enable; |
||
392 | |||
393 | if (!(ctx->filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE)) { |
||
394 | av_log(ctx, AV_LOG_ERROR, "Timeline ('enable' option) not supported " |
||
395 | "with filter '%s'\n", ctx->filter->name); |
||
396 | return AVERROR_PATCHWELCOME; |
||
397 | } |
||
398 | |||
399 | expr_dup = av_strdup(expr); |
||
400 | if (!expr_dup) |
||
401 | return AVERROR(ENOMEM); |
||
402 | |||
403 | if (!ctx->var_values) { |
||
404 | ctx->var_values = av_calloc(VAR_VARS_NB, sizeof(*ctx->var_values)); |
||
405 | if (!ctx->var_values) { |
||
406 | av_free(expr_dup); |
||
407 | return AVERROR(ENOMEM); |
||
408 | } |
||
409 | } |
||
410 | |||
411 | ret = av_expr_parse((AVExpr**)&ctx->enable, expr_dup, var_names, |
||
412 | NULL, NULL, NULL, NULL, 0, ctx->priv); |
||
413 | if (ret < 0) { |
||
414 | av_log(ctx->priv, AV_LOG_ERROR, |
||
415 | "Error when evaluating the expression '%s' for enable\n", |
||
416 | expr_dup); |
||
417 | av_free(expr_dup); |
||
418 | return ret; |
||
419 | } |
||
420 | |||
421 | av_expr_free(old); |
||
422 | av_free(ctx->enable_str); |
||
423 | ctx->enable_str = expr_dup; |
||
424 | return 0; |
||
425 | } |
||
426 | |||
427 | void ff_update_link_current_pts(AVFilterLink *link, int64_t pts) |
||
428 | { |
||
429 | if (pts == AV_NOPTS_VALUE) |
||
430 | return; |
||
431 | link->current_pts = av_rescale_q(pts, link->time_base, AV_TIME_BASE_Q); |
||
432 | /* TODO use duration */ |
||
433 | if (link->graph && link->age_index >= 0) |
||
434 | ff_avfilter_graph_update_heap(link->graph, link); |
||
435 | } |
||
436 | |||
437 | int avfilter_process_command(AVFilterContext *filter, const char *cmd, const char *arg, char *res, int res_len, int flags) |
||
438 | { |
||
439 | if(!strcmp(cmd, "ping")){ |
||
440 | char local_res[256] = {0}; |
||
441 | |||
442 | if (!res) { |
||
443 | res = local_res; |
||
444 | res_len = sizeof(local_res); |
||
445 | } |
||
446 | av_strlcatf(res, res_len, "pong from:%s %s\n", filter->filter->name, filter->name); |
||
447 | if (res == local_res) |
||
448 | av_log(filter, AV_LOG_INFO, "%s", res); |
||
449 | return 0; |
||
450 | }else if(!strcmp(cmd, "enable")) { |
||
451 | return set_enable_expr(filter, arg); |
||
452 | }else if(filter->filter->process_command) { |
||
453 | return filter->filter->process_command(filter, cmd, arg, res, res_len, flags); |
||
454 | } |
||
455 | return AVERROR(ENOSYS); |
||
456 | } |
||
457 | |||
458 | static AVFilter *first_filter; |
||
459 | |||
460 | AVFilter *avfilter_get_by_name(const char *name) |
||
461 | { |
||
462 | const AVFilter *f = NULL; |
||
463 | |||
464 | if (!name) |
||
465 | return NULL; |
||
466 | |||
467 | while ((f = avfilter_next(f))) |
||
468 | if (!strcmp(f->name, name)) |
||
469 | return (AVFilter *)f; |
||
470 | |||
471 | return NULL; |
||
472 | } |
||
473 | |||
474 | int avfilter_register(AVFilter *filter) |
||
475 | { |
||
476 | AVFilter **f = &first_filter; |
||
477 | int i; |
||
478 | |||
479 | /* the filter must select generic or internal exclusively */ |
||
480 | av_assert0((filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE) != AVFILTER_FLAG_SUPPORT_TIMELINE); |
||
481 | |||
482 | for(i=0; filter->inputs && filter->inputs[i].name; i++) { |
||
483 | const AVFilterPad *input = &filter->inputs[i]; |
||
484 | av_assert0( !input->filter_frame |
||
485 | || (!input->start_frame && !input->end_frame)); |
||
486 | } |
||
487 | |||
488 | filter->next = NULL; |
||
489 | |||
490 | while(avpriv_atomic_ptr_cas((void * volatile *)f, NULL, filter)) |
||
491 | f = &(*f)->next; |
||
492 | |||
493 | return 0; |
||
494 | } |
||
495 | |||
496 | const AVFilter *avfilter_next(const AVFilter *prev) |
||
497 | { |
||
498 | return prev ? prev->next : first_filter; |
||
499 | } |
||
500 | |||
501 | #if FF_API_OLD_FILTER_REGISTER |
||
502 | AVFilter **av_filter_next(AVFilter **filter) |
||
503 | { |
||
504 | return filter ? &(*filter)->next : &first_filter; |
||
505 | } |
||
506 | |||
507 | void avfilter_uninit(void) |
||
508 | { |
||
509 | } |
||
510 | #endif |
||
511 | |||
512 | int avfilter_pad_count(const AVFilterPad *pads) |
||
513 | { |
||
514 | int count; |
||
515 | |||
516 | if (!pads) |
||
517 | return 0; |
||
518 | |||
519 | for (count = 0; pads->name; count++) |
||
520 | pads++; |
||
521 | return count; |
||
522 | } |
||
523 | |||
524 | static const char *default_filter_name(void *filter_ctx) |
||
525 | { |
||
526 | AVFilterContext *ctx = filter_ctx; |
||
527 | return ctx->name ? ctx->name : ctx->filter->name; |
||
528 | } |
||
529 | |||
530 | static void *filter_child_next(void *obj, void *prev) |
||
531 | { |
||
532 | AVFilterContext *ctx = obj; |
||
533 | if (!prev && ctx->filter && ctx->filter->priv_class && ctx->priv) |
||
534 | return ctx->priv; |
||
535 | return NULL; |
||
536 | } |
||
537 | |||
538 | static const AVClass *filter_child_class_next(const AVClass *prev) |
||
539 | { |
||
540 | const AVFilter *f = NULL; |
||
541 | |||
542 | /* find the filter that corresponds to prev */ |
||
543 | while (prev && (f = avfilter_next(f))) |
||
544 | if (f->priv_class == prev) |
||
545 | break; |
||
546 | |||
547 | /* could not find filter corresponding to prev */ |
||
548 | if (prev && !f) |
||
549 | return NULL; |
||
550 | |||
551 | /* find next filter with specific options */ |
||
552 | while ((f = avfilter_next(f))) |
||
553 | if (f->priv_class) |
||
554 | return f->priv_class; |
||
555 | |||
556 | return NULL; |
||
557 | } |
||
558 | |||
559 | #define OFFSET(x) offsetof(AVFilterContext, x) |
||
560 | #define FLAGS AV_OPT_FLAG_FILTERING_PARAM |
||
561 | static const AVOption avfilter_options[] = { |
||
562 | { "thread_type", "Allowed thread types", OFFSET(thread_type), AV_OPT_TYPE_FLAGS, |
||
563 | { .i64 = AVFILTER_THREAD_SLICE }, 0, INT_MAX, FLAGS, "thread_type" }, |
||
564 | { "slice", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVFILTER_THREAD_SLICE }, .unit = "thread_type" }, |
||
565 | { "enable", "set enable expression", OFFSET(enable_str), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, |
||
566 | { NULL }, |
||
567 | }; |
||
568 | |||
569 | static const AVClass avfilter_class = { |
||
570 | .class_name = "AVFilter", |
||
571 | .item_name = default_filter_name, |
||
572 | .version = LIBAVUTIL_VERSION_INT, |
||
573 | .category = AV_CLASS_CATEGORY_FILTER, |
||
574 | .child_next = filter_child_next, |
||
575 | .child_class_next = filter_child_class_next, |
||
576 | .option = avfilter_options, |
||
577 | }; |
||
578 | |||
579 | static int default_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, |
||
580 | int *ret, int nb_jobs) |
||
581 | { |
||
582 | int i; |
||
583 | |||
584 | for (i = 0; i < nb_jobs; i++) { |
||
585 | int r = func(ctx, arg, i, nb_jobs); |
||
586 | if (ret) |
||
587 | ret[i] = r; |
||
588 | } |
||
589 | return 0; |
||
590 | } |
||
591 | |||
592 | AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name) |
||
593 | { |
||
594 | AVFilterContext *ret; |
||
595 | |||
596 | if (!filter) |
||
597 | return NULL; |
||
598 | |||
599 | ret = av_mallocz(sizeof(AVFilterContext)); |
||
600 | if (!ret) |
||
601 | return NULL; |
||
602 | |||
603 | ret->av_class = &avfilter_class; |
||
604 | ret->filter = filter; |
||
605 | ret->name = inst_name ? av_strdup(inst_name) : NULL; |
||
606 | if (filter->priv_size) { |
||
607 | ret->priv = av_mallocz(filter->priv_size); |
||
608 | if (!ret->priv) |
||
609 | goto err; |
||
610 | } |
||
611 | |||
612 | av_opt_set_defaults(ret); |
||
613 | if (filter->priv_class) { |
||
614 | *(const AVClass**)ret->priv = filter->priv_class; |
||
615 | av_opt_set_defaults(ret->priv); |
||
616 | } |
||
617 | |||
618 | ret->internal = av_mallocz(sizeof(*ret->internal)); |
||
619 | if (!ret->internal) |
||
620 | goto err; |
||
621 | ret->internal->execute = default_execute; |
||
622 | |||
623 | ret->nb_inputs = avfilter_pad_count(filter->inputs); |
||
624 | if (ret->nb_inputs ) { |
||
625 | ret->input_pads = av_malloc(sizeof(AVFilterPad) * ret->nb_inputs); |
||
626 | if (!ret->input_pads) |
||
627 | goto err; |
||
628 | memcpy(ret->input_pads, filter->inputs, sizeof(AVFilterPad) * ret->nb_inputs); |
||
629 | ret->inputs = av_mallocz(sizeof(AVFilterLink*) * ret->nb_inputs); |
||
630 | if (!ret->inputs) |
||
631 | goto err; |
||
632 | } |
||
633 | |||
634 | ret->nb_outputs = avfilter_pad_count(filter->outputs); |
||
635 | if (ret->nb_outputs) { |
||
636 | ret->output_pads = av_malloc(sizeof(AVFilterPad) * ret->nb_outputs); |
||
637 | if (!ret->output_pads) |
||
638 | goto err; |
||
639 | memcpy(ret->output_pads, filter->outputs, sizeof(AVFilterPad) * ret->nb_outputs); |
||
640 | ret->outputs = av_mallocz(sizeof(AVFilterLink*) * ret->nb_outputs); |
||
641 | if (!ret->outputs) |
||
642 | goto err; |
||
643 | } |
||
644 | #if FF_API_FOO_COUNT |
||
645 | FF_DISABLE_DEPRECATION_WARNINGS |
||
646 | ret->output_count = ret->nb_outputs; |
||
647 | ret->input_count = ret->nb_inputs; |
||
648 | FF_ENABLE_DEPRECATION_WARNINGS |
||
649 | #endif |
||
650 | |||
651 | return ret; |
||
652 | |||
653 | err: |
||
654 | av_freep(&ret->inputs); |
||
655 | av_freep(&ret->input_pads); |
||
656 | ret->nb_inputs = 0; |
||
657 | av_freep(&ret->outputs); |
||
658 | av_freep(&ret->output_pads); |
||
659 | ret->nb_outputs = 0; |
||
660 | av_freep(&ret->priv); |
||
661 | av_freep(&ret->internal); |
||
662 | av_free(ret); |
||
663 | return NULL; |
||
664 | } |
||
665 | |||
666 | #if FF_API_AVFILTER_OPEN |
||
667 | int avfilter_open(AVFilterContext **filter_ctx, AVFilter *filter, const char *inst_name) |
||
668 | { |
||
669 | *filter_ctx = ff_filter_alloc(filter, inst_name); |
||
670 | return *filter_ctx ? 0 : AVERROR(ENOMEM); |
||
671 | } |
||
672 | #endif |
||
673 | |||
674 | static void free_link(AVFilterLink *link) |
||
675 | { |
||
676 | if (!link) |
||
677 | return; |
||
678 | |||
679 | if (link->src) |
||
680 | link->src->outputs[link->srcpad - link->src->output_pads] = NULL; |
||
681 | if (link->dst) |
||
682 | link->dst->inputs[link->dstpad - link->dst->input_pads] = NULL; |
||
683 | |||
684 | ff_formats_unref(&link->in_formats); |
||
685 | ff_formats_unref(&link->out_formats); |
||
686 | ff_formats_unref(&link->in_samplerates); |
||
687 | ff_formats_unref(&link->out_samplerates); |
||
688 | ff_channel_layouts_unref(&link->in_channel_layouts); |
||
689 | ff_channel_layouts_unref(&link->out_channel_layouts); |
||
690 | avfilter_link_free(&link); |
||
691 | } |
||
692 | |||
693 | void avfilter_free(AVFilterContext *filter) |
||
694 | { |
||
695 | int i; |
||
696 | |||
697 | if (!filter) |
||
698 | return; |
||
699 | |||
700 | if (filter->graph) |
||
701 | ff_filter_graph_remove_filter(filter->graph, filter); |
||
702 | |||
703 | if (filter->filter->uninit) |
||
704 | filter->filter->uninit(filter); |
||
705 | |||
706 | for (i = 0; i < filter->nb_inputs; i++) { |
||
707 | free_link(filter->inputs[i]); |
||
708 | } |
||
709 | for (i = 0; i < filter->nb_outputs; i++) { |
||
710 | free_link(filter->outputs[i]); |
||
711 | } |
||
712 | |||
713 | if (filter->filter->priv_class) |
||
714 | av_opt_free(filter->priv); |
||
715 | |||
716 | av_freep(&filter->name); |
||
717 | av_freep(&filter->input_pads); |
||
718 | av_freep(&filter->output_pads); |
||
719 | av_freep(&filter->inputs); |
||
720 | av_freep(&filter->outputs); |
||
721 | av_freep(&filter->priv); |
||
722 | while(filter->command_queue){ |
||
723 | ff_command_queue_pop(filter); |
||
724 | } |
||
725 | av_opt_free(filter); |
||
726 | av_expr_free(filter->enable); |
||
727 | filter->enable = NULL; |
||
728 | av_freep(&filter->var_values); |
||
729 | av_freep(&filter->internal); |
||
730 | av_free(filter); |
||
731 | } |
||
732 | |||
733 | static int process_options(AVFilterContext *ctx, AVDictionary **options, |
||
734 | const char *args) |
||
735 | { |
||
736 | const AVOption *o = NULL; |
||
737 | int ret, count = 0; |
||
738 | char *av_uninit(parsed_key), *av_uninit(value); |
||
739 | const char *key; |
||
740 | int offset= -1; |
||
741 | |||
742 | if (!args) |
||
743 | return 0; |
||
744 | |||
745 | while (*args) { |
||
746 | const char *shorthand = NULL; |
||
747 | |||
748 | o = av_opt_next(ctx->priv, o); |
||
749 | if (o) { |
||
750 | if (o->type == AV_OPT_TYPE_CONST || o->offset == offset) |
||
751 | continue; |
||
752 | offset = o->offset; |
||
753 | shorthand = o->name; |
||
754 | } |
||
755 | |||
756 | ret = av_opt_get_key_value(&args, "=", ":", |
||
757 | shorthand ? AV_OPT_FLAG_IMPLICIT_KEY : 0, |
||
758 | &parsed_key, &value); |
||
759 | if (ret < 0) { |
||
760 | if (ret == AVERROR(EINVAL)) |
||
761 | av_log(ctx, AV_LOG_ERROR, "No option name near '%s'\n", args); |
||
762 | else |
||
763 | av_log(ctx, AV_LOG_ERROR, "Unable to parse '%s': %s\n", args, |
||
764 | av_err2str(ret)); |
||
765 | return ret; |
||
766 | } |
||
767 | if (*args) |
||
768 | args++; |
||
769 | if (parsed_key) { |
||
770 | key = parsed_key; |
||
771 | while ((o = av_opt_next(ctx->priv, o))); /* discard all remaining shorthand */ |
||
772 | } else { |
||
773 | key = shorthand; |
||
774 | } |
||
775 | |||
776 | av_log(ctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value); |
||
777 | |||
778 | if (av_opt_find(ctx, key, NULL, 0, 0)) { |
||
779 | ret = av_opt_set(ctx, key, value, 0); |
||
780 | if (ret < 0) { |
||
781 | av_free(value); |
||
782 | av_free(parsed_key); |
||
783 | return ret; |
||
784 | } |
||
785 | } else { |
||
786 | av_dict_set(options, key, value, 0); |
||
787 | if ((ret = av_opt_set(ctx->priv, key, value, 0)) < 0) { |
||
788 | if (!av_opt_find(ctx->priv, key, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)) { |
||
789 | if (ret == AVERROR_OPTION_NOT_FOUND) |
||
790 | av_log(ctx, AV_LOG_ERROR, "Option '%s' not found\n", key); |
||
791 | av_free(value); |
||
792 | av_free(parsed_key); |
||
793 | return ret; |
||
794 | } |
||
795 | } |
||
796 | } |
||
797 | |||
798 | av_free(value); |
||
799 | av_free(parsed_key); |
||
800 | count++; |
||
801 | } |
||
802 | |||
803 | if (ctx->enable_str) { |
||
804 | ret = set_enable_expr(ctx, ctx->enable_str); |
||
805 | if (ret < 0) |
||
806 | return ret; |
||
807 | } |
||
808 | return count; |
||
809 | } |
||
810 | |||
811 | #if FF_API_AVFILTER_INIT_FILTER |
||
812 | int avfilter_init_filter(AVFilterContext *filter, const char *args, void *opaque) |
||
813 | { |
||
814 | return avfilter_init_str(filter, args); |
||
815 | } |
||
816 | #endif |
||
817 | |||
818 | int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options) |
||
819 | { |
||
820 | int ret = 0; |
||
821 | |||
822 | ret = av_opt_set_dict(ctx, options); |
||
823 | if (ret < 0) { |
||
824 | av_log(ctx, AV_LOG_ERROR, "Error applying generic filter options.\n"); |
||
825 | return ret; |
||
826 | } |
||
827 | |||
828 | if (ctx->filter->flags & AVFILTER_FLAG_SLICE_THREADS && |
||
829 | ctx->thread_type & ctx->graph->thread_type & AVFILTER_THREAD_SLICE && |
||
830 | ctx->graph->internal->thread_execute) { |
||
831 | ctx->thread_type = AVFILTER_THREAD_SLICE; |
||
832 | ctx->internal->execute = ctx->graph->internal->thread_execute; |
||
833 | } else { |
||
834 | ctx->thread_type = 0; |
||
835 | } |
||
836 | |||
837 | if (ctx->filter->priv_class) { |
||
838 | ret = av_opt_set_dict(ctx->priv, options); |
||
839 | if (ret < 0) { |
||
840 | av_log(ctx, AV_LOG_ERROR, "Error applying options to the filter.\n"); |
||
841 | return ret; |
||
842 | } |
||
843 | } |
||
844 | |||
845 | if (ctx->filter->init_opaque) |
||
846 | ret = ctx->filter->init_opaque(ctx, NULL); |
||
847 | else if (ctx->filter->init) |
||
848 | ret = ctx->filter->init(ctx); |
||
849 | else if (ctx->filter->init_dict) |
||
850 | ret = ctx->filter->init_dict(ctx, options); |
||
851 | |||
852 | return ret; |
||
853 | } |
||
854 | |||
855 | int avfilter_init_str(AVFilterContext *filter, const char *args) |
||
856 | { |
||
857 | AVDictionary *options = NULL; |
||
858 | AVDictionaryEntry *e; |
||
859 | int ret = 0; |
||
860 | |||
861 | if (args && *args) { |
||
862 | if (!filter->filter->priv_class) { |
||
863 | av_log(filter, AV_LOG_ERROR, "This filter does not take any " |
||
864 | "options, but options were provided: %s.\n", args); |
||
865 | return AVERROR(EINVAL); |
||
866 | } |
||
867 | |||
868 | #if FF_API_OLD_FILTER_OPTS |
||
869 | if ( !strcmp(filter->filter->name, "format") || |
||
870 | !strcmp(filter->filter->name, "noformat") || |
||
871 | !strcmp(filter->filter->name, "frei0r") || |
||
872 | !strcmp(filter->filter->name, "frei0r_src") || |
||
873 | !strcmp(filter->filter->name, "ocv") || |
||
874 | !strcmp(filter->filter->name, "pan") || |
||
875 | !strcmp(filter->filter->name, "pp") || |
||
876 | !strcmp(filter->filter->name, "aevalsrc")) { |
||
877 | /* a hack for compatibility with the old syntax |
||
878 | * replace colons with |s */ |
||
879 | char *copy = av_strdup(args); |
||
880 | char *p = copy; |
||
881 | int nb_leading = 0; // number of leading colons to skip |
||
882 | int deprecated = 0; |
||
883 | |||
884 | if (!copy) { |
||
885 | ret = AVERROR(ENOMEM); |
||
886 | goto fail; |
||
887 | } |
||
888 | |||
889 | if (!strcmp(filter->filter->name, "frei0r") || |
||
890 | !strcmp(filter->filter->name, "ocv")) |
||
891 | nb_leading = 1; |
||
892 | else if (!strcmp(filter->filter->name, "frei0r_src")) |
||
893 | nb_leading = 3; |
||
894 | |||
895 | while (nb_leading--) { |
||
896 | p = strchr(p, ':'); |
||
897 | if (!p) { |
||
898 | p = copy + strlen(copy); |
||
899 | break; |
||
900 | } |
||
901 | p++; |
||
902 | } |
||
903 | |||
904 | deprecated = strchr(p, ':') != NULL; |
||
905 | |||
906 | if (!strcmp(filter->filter->name, "aevalsrc")) { |
||
907 | deprecated = 0; |
||
908 | while ((p = strchr(p, ':')) && p[1] != ':') { |
||
909 | const char *epos = strchr(p + 1, '='); |
||
910 | const char *spos = strchr(p + 1, ':'); |
||
911 | const int next_token_is_opt = epos && (!spos || epos < spos); |
||
912 | if (next_token_is_opt) { |
||
913 | p++; |
||
914 | break; |
||
915 | } |
||
916 | /* next token does not contain a '=', assume a channel expression */ |
||
917 | deprecated = 1; |
||
918 | *p++ = '|'; |
||
919 | } |
||
920 | if (p && *p == ':') { // double sep '::' found |
||
921 | deprecated = 1; |
||
922 | memmove(p, p + 1, strlen(p)); |
||
923 | } |
||
924 | } else |
||
925 | while ((p = strchr(p, ':'))) |
||
926 | *p++ = '|'; |
||
927 | |||
928 | if (deprecated) |
||
929 | av_log(filter, AV_LOG_WARNING, "This syntax is deprecated. Use " |
||
930 | "'|' to separate the list items.\n"); |
||
931 | |||
932 | av_log(filter, AV_LOG_DEBUG, "compat: called with args=[%s]\n", copy); |
||
933 | ret = process_options(filter, &options, copy); |
||
934 | av_freep(©); |
||
935 | |||
936 | if (ret < 0) |
||
937 | goto fail; |
||
938 | #endif |
||
939 | } else { |
||
940 | #if CONFIG_MP_FILTER |
||
941 | if (!strcmp(filter->filter->name, "mp")) { |
||
942 | char *escaped; |
||
943 | |||
944 | if (!strncmp(args, "filter=", 7)) |
||
945 | args += 7; |
||
946 | ret = av_escape(&escaped, args, ":=", AV_ESCAPE_MODE_BACKSLASH, 0); |
||
947 | if (ret < 0) { |
||
948 | av_log(filter, AV_LOG_ERROR, "Unable to escape MPlayer filters arg '%s'\n", args); |
||
949 | goto fail; |
||
950 | } |
||
951 | ret = process_options(filter, &options, escaped); |
||
952 | av_free(escaped); |
||
953 | } else |
||
954 | #endif |
||
955 | ret = process_options(filter, &options, args); |
||
956 | if (ret < 0) |
||
957 | goto fail; |
||
958 | } |
||
959 | } |
||
960 | |||
961 | ret = avfilter_init_dict(filter, &options); |
||
962 | if (ret < 0) |
||
963 | goto fail; |
||
964 | |||
965 | if ((e = av_dict_get(options, "", NULL, AV_DICT_IGNORE_SUFFIX))) { |
||
966 | av_log(filter, AV_LOG_ERROR, "No such option: %s.\n", e->key); |
||
967 | ret = AVERROR_OPTION_NOT_FOUND; |
||
968 | goto fail; |
||
969 | } |
||
970 | |||
971 | fail: |
||
972 | av_dict_free(&options); |
||
973 | |||
974 | return ret; |
||
975 | } |
||
976 | |||
977 | const char *avfilter_pad_get_name(const AVFilterPad *pads, int pad_idx) |
||
978 | { |
||
979 | return pads[pad_idx].name; |
||
980 | } |
||
981 | |||
982 | enum AVMediaType avfilter_pad_get_type(const AVFilterPad *pads, int pad_idx) |
||
983 | { |
||
984 | return pads[pad_idx].type; |
||
985 | } |
||
986 | |||
987 | static int default_filter_frame(AVFilterLink *link, AVFrame *frame) |
||
988 | { |
||
989 | return ff_filter_frame(link->dst->outputs[0], frame); |
||
990 | } |
||
991 | |||
992 | static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame) |
||
993 | { |
||
994 | int (*filter_frame)(AVFilterLink *, AVFrame *); |
||
995 | AVFilterContext *dstctx = link->dst; |
||
996 | AVFilterPad *dst = link->dstpad; |
||
997 | AVFrame *out; |
||
998 | int ret; |
||
999 | AVFilterCommand *cmd= link->dst->command_queue; |
||
1000 | int64_t pts; |
||
1001 | |||
1002 | if (link->closed) { |
||
1003 | av_frame_free(&frame); |
||
1004 | return AVERROR_EOF; |
||
1005 | } |
||
1006 | |||
1007 | if (!(filter_frame = dst->filter_frame)) |
||
1008 | filter_frame = default_filter_frame; |
||
1009 | |||
1010 | /* copy the frame if needed */ |
||
1011 | if (dst->needs_writable && !av_frame_is_writable(frame)) { |
||
1012 | av_log(link->dst, AV_LOG_DEBUG, "Copying data in avfilter.\n"); |
||
1013 | |||
1014 | /* Maybe use ff_copy_buffer_ref instead? */ |
||
1015 | switch (link->type) { |
||
1016 | case AVMEDIA_TYPE_VIDEO: |
||
1017 | out = ff_get_video_buffer(link, link->w, link->h); |
||
1018 | break; |
||
1019 | case AVMEDIA_TYPE_AUDIO: |
||
1020 | out = ff_get_audio_buffer(link, frame->nb_samples); |
||
1021 | break; |
||
1022 | default: return AVERROR(EINVAL); |
||
1023 | } |
||
1024 | if (!out) { |
||
1025 | av_frame_free(&frame); |
||
1026 | return AVERROR(ENOMEM); |
||
1027 | } |
||
1028 | av_frame_copy_props(out, frame); |
||
1029 | |||
1030 | switch (link->type) { |
||
1031 | case AVMEDIA_TYPE_VIDEO: |
||
1032 | av_image_copy(out->data, out->linesize, (const uint8_t **)frame->data, frame->linesize, |
||
1033 | frame->format, frame->width, frame->height); |
||
1034 | break; |
||
1035 | case AVMEDIA_TYPE_AUDIO: |
||
1036 | av_samples_copy(out->extended_data, frame->extended_data, |
||
1037 | 0, 0, frame->nb_samples, |
||
1038 | av_get_channel_layout_nb_channels(frame->channel_layout), |
||
1039 | frame->format); |
||
1040 | break; |
||
1041 | default: return AVERROR(EINVAL); |
||
1042 | } |
||
1043 | |||
1044 | av_frame_free(&frame); |
||
1045 | } else |
||
1046 | out = frame; |
||
1047 | |||
1048 | while(cmd && cmd->time <= out->pts * av_q2d(link->time_base)){ |
||
1049 | av_log(link->dst, AV_LOG_DEBUG, |
||
1050 | "Processing command time:%f command:%s arg:%s\n", |
||
1051 | cmd->time, cmd->command, cmd->arg); |
||
1052 | avfilter_process_command(link->dst, cmd->command, cmd->arg, 0, 0, cmd->flags); |
||
1053 | ff_command_queue_pop(link->dst); |
||
1054 | cmd= link->dst->command_queue; |
||
1055 | } |
||
1056 | |||
1057 | pts = out->pts; |
||
1058 | if (dstctx->enable_str) { |
||
1059 | int64_t pos = av_frame_get_pkt_pos(out); |
||
1060 | dstctx->var_values[VAR_N] = link->frame_count; |
||
1061 | dstctx->var_values[VAR_T] = pts == AV_NOPTS_VALUE ? NAN : pts * av_q2d(link->time_base); |
||
1062 | dstctx->var_values[VAR_POS] = pos == -1 ? NAN : pos; |
||
1063 | |||
1064 | dstctx->is_disabled = fabs(av_expr_eval(dstctx->enable, dstctx->var_values, NULL)) < 0.5; |
||
1065 | if (dstctx->is_disabled && |
||
1066 | (dstctx->filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC)) |
||
1067 | filter_frame = default_filter_frame; |
||
1068 | } |
||
1069 | ret = filter_frame(link, out); |
||
1070 | link->frame_count++; |
||
1071 | link->frame_requested = 0; |
||
1072 | ff_update_link_current_pts(link, pts); |
||
1073 | return ret; |
||
1074 | } |
||
1075 | |||
1076 | static int ff_filter_frame_needs_framing(AVFilterLink *link, AVFrame *frame) |
||
1077 | { |
||
1078 | int insamples = frame->nb_samples, inpos = 0, nb_samples; |
||
1079 | AVFrame *pbuf = link->partial_buf; |
||
1080 | int nb_channels = av_frame_get_channels(frame); |
||
1081 | int ret = 0; |
||
1082 | |||
1083 | link->flags |= FF_LINK_FLAG_REQUEST_LOOP; |
||
1084 | /* Handle framing (min_samples, max_samples) */ |
||
1085 | while (insamples) { |
||
1086 | if (!pbuf) { |
||
1087 | AVRational samples_tb = { 1, link->sample_rate }; |
||
1088 | pbuf = ff_get_audio_buffer(link, link->partial_buf_size); |
||
1089 | if (!pbuf) { |
||
1090 | av_log(link->dst, AV_LOG_WARNING, |
||
1091 | "Samples dropped due to memory allocation failure.\n"); |
||
1092 | return 0; |
||
1093 | } |
||
1094 | av_frame_copy_props(pbuf, frame); |
||
1095 | pbuf->pts = frame->pts; |
||
1096 | if (pbuf->pts != AV_NOPTS_VALUE) |
||
1097 | pbuf->pts += av_rescale_q(inpos, samples_tb, link->time_base); |
||
1098 | pbuf->nb_samples = 0; |
||
1099 | } |
||
1100 | nb_samples = FFMIN(insamples, |
||
1101 | link->partial_buf_size - pbuf->nb_samples); |
||
1102 | av_samples_copy(pbuf->extended_data, frame->extended_data, |
||
1103 | pbuf->nb_samples, inpos, |
||
1104 | nb_samples, nb_channels, link->format); |
||
1105 | inpos += nb_samples; |
||
1106 | insamples -= nb_samples; |
||
1107 | pbuf->nb_samples += nb_samples; |
||
1108 | if (pbuf->nb_samples >= link->min_samples) { |
||
1109 | ret = ff_filter_frame_framed(link, pbuf); |
||
1110 | pbuf = NULL; |
||
1111 | } |
||
1112 | } |
||
1113 | av_frame_free(&frame); |
||
1114 | link->partial_buf = pbuf; |
||
1115 | return ret; |
||
1116 | } |
||
1117 | |||
1118 | int ff_filter_frame(AVFilterLink *link, AVFrame *frame) |
||
1119 | { |
||
1120 | FF_TPRINTF_START(NULL, filter_frame); ff_tlog_link(NULL, link, 1); ff_tlog(NULL, " "); ff_tlog_ref(NULL, frame, 1); |
||
1121 | |||
1122 | /* Consistency checks */ |
||
1123 | if (link->type == AVMEDIA_TYPE_VIDEO) { |
||
1124 | if (strcmp(link->dst->filter->name, "scale")) { |
||
1125 | av_assert1(frame->format == link->format); |
||
1126 | av_assert1(frame->width == link->w); |
||
1127 | av_assert1(frame->height == link->h); |
||
1128 | } |
||
1129 | } else { |
||
1130 | av_assert1(frame->format == link->format); |
||
1131 | av_assert1(av_frame_get_channels(frame) == link->channels); |
||
1132 | av_assert1(frame->channel_layout == link->channel_layout); |
||
1133 | av_assert1(frame->sample_rate == link->sample_rate); |
||
1134 | } |
||
1135 | |||
1136 | /* Go directly to actual filtering if possible */ |
||
1137 | if (link->type == AVMEDIA_TYPE_AUDIO && |
||
1138 | link->min_samples && |
||
1139 | (link->partial_buf || |
||
1140 | frame->nb_samples < link->min_samples || |
||
1141 | frame->nb_samples > link->max_samples)) { |
||
1142 | return ff_filter_frame_needs_framing(link, frame); |
||
1143 | } else { |
||
1144 | return ff_filter_frame_framed(link, frame); |
||
1145 | } |
||
1146 | } |
||
1147 | |||
1148 | const AVClass *avfilter_get_class(void) |
||
1149 | { |
||
1150 | return &avfilter_class; |
||
1151 | }>>=>>>>>>>>>>>>>>>>>>>>>>>=>=>> |