diff options
Diffstat (limited to 'filters/f_utils.c')
-rw-r--r-- | filters/f_utils.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/filters/f_utils.c b/filters/f_utils.c new file mode 100644 index 0000000000..f984a3b33a --- /dev/null +++ b/filters/f_utils.c @@ -0,0 +1,175 @@ +#include "video/mp_image.h" + +#include "f_utils.h" +#include "filter_internal.h" + +struct frame_duration_priv { + struct mp_image *buffered; +}; + +static void frame_duration_process(struct mp_filter *f) +{ + struct frame_duration_priv *p = f->priv; + + if (!mp_pin_can_transfer_data(f->ppins[1], f->ppins[0])) + return; + + struct mp_frame frame = mp_pin_out_read(f->ppins[0]); + + if (frame.type == MP_FRAME_EOF && p->buffered) { + mp_pin_in_write(f->ppins[1], MAKE_FRAME(MP_FRAME_VIDEO, p->buffered)); + p->buffered = NULL; + // Pass through the actual EOF in the next iteration. + mp_pin_out_repeat_eof(f->ppins[0]); + } else if (frame.type == MP_FRAME_VIDEO) { + struct mp_image *next = frame.data; + if (p->buffered) { + if (p->buffered->pts != MP_NOPTS_VALUE && + next->pts != MP_NOPTS_VALUE && + next->pts >= p->buffered->pts) + p->buffered->pkt_duration = next->pts - p->buffered->pts; + mp_pin_in_write(f->ppins[1], MAKE_FRAME(MP_FRAME_VIDEO, p->buffered)); + } else { + mp_pin_out_request_data(f->ppins[0]); + } + p->buffered = next; + } else { + mp_pin_in_write(f->ppins[1], frame); + } +} + +static void frame_duration_reset(struct mp_filter *f) +{ + struct frame_duration_priv *p = f->priv; + + mp_image_unrefp(&p->buffered); +} + +static const struct mp_filter_info frame_duration_filter = { + .name = "frame_duration", + .priv_size = sizeof(struct frame_duration_priv), + .process = frame_duration_process, + .reset = frame_duration_reset, +}; + +struct mp_filter *mp_compute_frame_duration_create(struct mp_filter *parent) +{ + struct mp_filter *f = mp_filter_create(parent, &frame_duration_filter); + if (!f) + return NULL; + + mp_filter_add_pin(f, MP_PIN_IN, "in"); + mp_filter_add_pin(f, MP_PIN_OUT, "out"); + + return f; +} + +void mp_chain_filters(struct mp_pin *in, struct mp_pin *out, + struct mp_filter **filters, int num_filters) +{ + for (int n = 0; n < num_filters; n++) { + if (!filters[n]) + continue; + assert(filters[n]->num_pins == 2); + mp_pin_connect(filters[n]->pins[0], in); + in = filters[n]->pins[1]; + } + mp_pin_connect(out, in); +} + +// Make it repeat process(). +static void mark_progress(struct mp_subfilter *sub) +{ + // f == NULL is not really allowed, but at least don't crash. + struct mp_filter *f = mp_pin_get_manual_connection(sub->in); + if (f) + mp_filter_internal_mark_progress(f); +} + +bool mp_subfilter_read(struct mp_subfilter *sub) +{ + if (sub->filter) { + if (mp_pin_can_transfer_data(sub->out, sub->filter->pins[1])) { + struct mp_frame frame = mp_pin_out_read(sub->filter->pins[1]); + if (sub->draining && frame.type == MP_FRAME_EOF) { + sub->draining = false; + TA_FREEP(&sub->filter); + mark_progress(sub); + return false; + } + mp_pin_in_write(sub->out, frame); + return false; + } + if (sub->draining) + return false; + } + + struct mp_pin *out = sub->filter ? sub->filter->pins[0] : sub->out; + + if (sub->frame.type) + return mp_pin_in_needs_data(out); + + if (!mp_pin_can_transfer_data(out, sub->in)) + return false; + + sub->frame = mp_pin_out_read(sub->in); + return true; +} + +void mp_subfilter_reset(struct mp_subfilter *sub) +{ + if (sub->filter && sub->draining) + TA_FREEP(&sub->filter); + sub->draining = false; + mp_frame_unref(&sub->frame); +} + +void mp_subfilter_continue(struct mp_subfilter *sub) +{ + struct mp_pin *out = sub->filter ? sub->filter->pins[0] : sub->out; + // It was made sure earlier that the pin is writable, unless the filter + // was newly created, or a previously existing filter (which was going to + // accept input) was destroyed. In those cases, essentially restart + // data flow. + if (!mp_pin_in_needs_data(out)) { + mark_progress(sub); + return; + } + mp_pin_in_write(out, sub->frame); + sub->frame = MP_NO_FRAME; +} + +void mp_subfilter_destroy(struct mp_subfilter *sub) +{ + TA_FREEP(&sub->filter); + sub->draining = false; +} + +bool mp_subfilter_drain_destroy(struct mp_subfilter *sub) +{ + if (!sub->draining && sub->filter) { + // We know the filter is writable (unless the user created a new filter + // and immediately called this function, which is invalid). + mp_pin_in_write(sub->filter->pins[0], MP_EOF_FRAME); + sub->draining = true; + } + return !sub->filter; +} + +static const struct mp_filter_info bidir_nop_filter = { + .name = "nop", +}; + +struct mp_filter *mp_bidir_nop_filter_create(struct mp_filter *parent) +{ + struct mp_filter *f = mp_filter_create(parent, &bidir_nop_filter); + if (!f) + return NULL; + + mp_filter_add_pin(f, MP_PIN_IN, "in"); + mp_filter_add_pin(f, MP_PIN_OUT, "out"); + + mp_pin_connect(f->ppins[1], f->ppins[0]); + + return f; +} |