summaryrefslogtreecommitdiffstats
path: root/filters/f_utils.h
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2018-01-16 11:53:44 +0100
committerKevin Mitchell <kevmitch@gmail.com>2018-01-30 03:10:27 -0800
commit76276c92104c31ee936ba5c76a76072f09978c5f (patch)
tree5f514978ef0326ed76adc9e82ac276daac9e257f /filters/f_utils.h
parentedb4970ca8b9bee8e54222a1e119af9d355d451a (diff)
downloadmpv-76276c92104c31ee936ba5c76a76072f09978c5f.tar.bz2
mpv-76276c92104c31ee936ba5c76a76072f09978c5f.tar.xz
video: rewrite filtering glue code
Get rid of the old vf.c code. Replace it with a generic filtering framework, which can potentially handle more than just --vf. At least reimplementing --af with this code is planned. This changes some --vf semantics (including runtime behavior and the "vf" command). The most important ones are listed in interface-changes. vf_convert.c is renamed to f_swscale.c. It is now an internal filter that can not be inserted by the user manually. f_lavfi.c is a refactor of player/lavfi.c. The latter will be removed once --lavfi-complex is reimplemented on top of f_lavfi.c. (which is conceptually easy, but a big mess due to the data flow changes). The existing filters are all changed heavily. The data flow of the new filter framework is different. Especially EOF handling changes - EOF is now a "frame" rather than a state, and must be passed through exactly once. Another major thing is that all filters must support dynamic format changes. The filter reconfig() function goes away. (This sounds complex, but since all filters need to handle EOF draining anyway, they can use the same code, and it removes the mess with reconfig() having to predict the output format, which completely breaks with libavfilter anyway.) In addition, there is no automatic format negotiation or conversion. libavfilter's primitive and insufficient API simply doesn't allow us to do this in a reasonable way. Instead, filters can use f_autoconvert as sub-filter, and tell it which formats they support. This filter will in turn add actual conversion filters, such as f_swscale, to perform necessary format changes. vf_vapoursynth.c uses the same basic principle of operation as before, but with worryingly different details in data flow. Still appears to work. The hardware deint filters (vf_vavpp.c, vf_d3d11vpp.c, vf_vdpaupp.c) are heavily changed. Fortunately, they all used refqueue.c, which is for sharing the data flow logic (especially for managing future/past surfaces and such). It turns out it can be used to factor out most of the data flow. Some of these filters accepted software input. Instead of having ad-hoc upload code in each filter, surface upload is now delegated to f_autoconvert, which can use f_hwupload to perform this. Exporting VO capabilities is still a big mess (mp_stream_info stuff). The D3D11 code drops the redundant image formats, and all code uses the hw_subfmt (sw_format in FFmpeg) instead. Although that too seems to be a big mess for now. f_async_queue is unused.
Diffstat (limited to 'filters/f_utils.h')
-rw-r--r--filters/f_utils.h72
1 files changed, 72 insertions, 0 deletions
diff --git a/filters/f_utils.h b/filters/f_utils.h
new file mode 100644
index 0000000000..a59ac1601d
--- /dev/null
+++ b/filters/f_utils.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#include "filter.h"
+
+// Filter that computes the exact duration of video frames by buffering 1 frame,
+// and taking the PTS difference. This supports video frames only, and stores
+// the duration in mp_image.pkt_duration. All other frame types are passed
+// through.
+struct mp_filter *mp_compute_frame_duration_create(struct mp_filter *parent);
+
+// Given the filters[0..num_filters] array, connect in with the input of the
+// first filter, connect the output of the first filter to the input to the
+// second filter, etc., until out. All filters are assumed to be bidrectional,
+// with input on pin 0 and output on pin 1. NULL entries are skipped.
+void mp_chain_filters(struct mp_pin *in, struct mp_pin *out,
+ struct mp_filter **filters, int num_filters);
+
+// Helper for maintaining a sub-filter that is created or destroyed on demand,
+// because it might depend on frame input formats or is otherwise dynamically
+// changing. (This is overkill for more static sub filters, or entirely manual
+// filtering.)
+// To initialize this, zero-init all fields, and set the in/out fields.
+struct mp_subfilter {
+ // These two fields must be set on init. The pins must have a manual
+ // connection to the filter whose process() function calls the
+ // mp_subfilter_*() functions.
+ struct mp_pin *in, *out;
+ // Temporary buffered frame, as triggered by mp_subfilter_read(). You can
+ // not mutate this (unless you didn't create or destroy sub->filter).
+ struct mp_frame frame;
+ // The sub-filter, set by the user. Can be NULL if disabled. If set, this
+ // must be a bidirectional filter, with manual connections same as
+ // mp_sub_filter.in/out (to get the correct process() function called).
+ // Set this only if it's NULL. You should not overwrite this if it's set.
+ // Use either mp_subfilter_drain_destroy(), mp_subfilter_destroy(), or
+ // mp_subfilter_reset() to unset and destroy the filter gracefully.
+ struct mp_filter *filter;
+ // Internal state.
+ bool draining;
+};
+
+// Make requests for a new frame.
+// Returns whether sub->frame is set to anything. If true is returned, you
+// must either call mp_subfilter_continue() or mp_subfilter_drain_destroy()
+// once to continue data flow normally (otherwise it will stall). If you call
+// mp_subfilter_drain_destroy(), and it returns true, or you call
+// mp_subfilter_destroy(), you can call mp_subfilter_continue() once after it.
+// If this returns true, sub->frame is never unset (MP_FRAME_NONE).
+bool mp_subfilter_read(struct mp_subfilter *sub);
+
+// Clear internal state (usually to be called by parent filter's reset(), or
+// destroy()). This usually does not free sub->filter.
+void mp_subfilter_reset(struct mp_subfilter *sub);
+
+// Continue filtering sub->frame. This can happen after setting a new filter
+// too.
+void mp_subfilter_continue(struct mp_subfilter *sub);
+
+// Destroy the filter immediately (if it's set). You must call
+// mp_subfilter_continue() after this to propagate sub->frame.
+void mp_subfilter_destroy(struct mp_subfilter *sub);
+
+// Make sure the filter is destroyed. Returns true if the filter was destroyed.
+// If this returns false, exit your process() function, so dataflow can
+// continue normally. (process() is repeated until this function returns true,
+// which can take a while if sub->filter has many frames buffered).
+// If this returns true, call mp_subfilter_continue() to propagate sub->frame.
+// The filter is destroyed with talloc_free(sub->filter).
+bool mp_subfilter_drain_destroy(struct mp_subfilter *sub);
+
+// A bidrectional filter which passes through all data.
+struct mp_filter *mp_bidir_nop_filter_create(struct mp_filter *parent);