summaryrefslogtreecommitdiffstats
path: root/filters/f_utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'filters/f_utils.c')
-rw-r--r--filters/f_utils.c175
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;
+}