diff options
authorwm4 <wm4@nowhere>2018-02-12 19:07:57 +0100
committerKevin Mitchell <>2018-02-13 17:45:29 -0800
commit3ffa70e2da121b1924f3fb74b0de0787184de237 (patch)
parent251f4e5d77af12672e058effd6e3047e9e50e8ac (diff)
filter: extend documentation comments
Add more explanations, and also fix some blatantly wrong things.
1 files changed, 43 insertions, 6 deletions
diff --git a/filters/filter.h b/filters/filter.h
index b618a9c637..e63b812a79 100644
--- a/filters/filter.h
+++ b/filters/filter.h
@@ -36,6 +36,7 @@ bool mp_pin_in_needs_data(struct mp_pin *p);
// (does not normally happen, as long as mp_pin_in_needs_data() returned true).
// The callee owns the reference to the frame data, even on failure.
// Writing a MP_FRAME_NONE has no effect (and returns false).
+// If you did not call mp_pin_in_needs_data() before this, it's likely a bug.
bool mp_pin_in_write(struct mp_pin *p, struct mp_frame frame);
// True if a frame is actually available for reading right now, and
@@ -119,8 +120,8 @@ bool mp_pin_can_transfer_data(struct mp_pin *dst, struct mp_pin *src);
// mp_pin_can_transfer_data(). Returns whether a transfer happened.
bool mp_pin_transfer_data(struct mp_pin *dst, struct mp_pin *src);
-// Connect src and dst, for automatic data flow. pin a will reflect the request
-// state of pin src, and accept and pass down frames to dst when appropriate.
+// Connect src and dst, for automatic data flow. Pin src will reflect the request
+// state of pin dst, and accept and pass down frames to dst when appropriate.
// src must be MP_PIN_OUT, dst must be MP_PIN_IN.
// Previous connections are always removed. If the pins were already connected,
// no action is taken.
@@ -144,8 +145,7 @@ void mp_pin_set_manual_connection_for(struct mp_pin *p, struct mp_filter *f);
// Return the manual connection for this pin, or NULL if none.
struct mp_filter *mp_pin_get_manual_connection(struct mp_pin *p);
-// If not connected, this will produce EOF for MP_PIN_IN, and never request
-// data for MP_PIN_OUT.
+// Disconnect the pin, possibly breaking connections.
void mp_pin_disconnect(struct mp_pin *p);
// Return whether a connection was set on this pin. Note that this is not
@@ -173,10 +173,42 @@ const char *mp_pin_get_name(struct mp_pin *p);
* things that require readahead). But in general, a filter should not request
* input before output is needed.
- * The general goal is to reduce the amount of data buffered. If buffering is
+ * The general goal is to reduce the amount of data buffered. This is why
+ * mp_pins buffer at most 1 frame, and the API is designed such that queued
+ * data in pins will be immediately passed to the next filter. If buffering is
* actually desired, explicit filters for buffering have to be introduced into
* the filter chain.
+ * Typically a filter will do something like this:
+ *
+ * process(struct mp_filter *f) {
+ * if (!mp_pin_in_needs_data(f->ppins[1]))
+ * return; // reader needs no output yet, so stop filtering
+ * if (!have_enough_data_for_output) {
+ * // Could check mp_pin_out_request_data(), but often just trying to
+ * // read is enough, as a failed read will request more data.
+ * struct mp_frame fr = mp_pin_out_read_data(f->ppins[0]);
+ * if (!fr.type)
+ * return; // no frame was returned - data was requested, and will
+ * // be queued when available, and invoke process() again
+ * ... do something with fr here ...
+ * }
+ * ... produce output frame (i.e. actual filtering) ...
+ * mp_pin_in_write(f->ppins[1], output_frame);
+ * }
+ *
+ * Simpler filters can use utility functions like mp_pin_can_transfer_data(),
+ * which reduce the boilerplate. Such filters also may not need to buffer data
+ * as internal state.
+ *
+ * --- Driving filters:
+ *
+ * The filter root (created by mp_filter_create_root()) will internally create
+ * a graph runner, that can be entered with mp_filter_run(). This will check if
+ * any filter/pin has unhandled requests, and call filter process() functions
+ * accordingly. Outside of the filter, this can be triggered implicitly via the
+ * mp_pin_* functions.
+ *
* Multiple filters are driven by letting mp_pin flag filters which need
* process() to be called. The process starts by requesting output from the
* last filter. The requests will "bubble up" by iteratively calling process()
@@ -184,7 +216,12 @@ const char *mp_pin_get_name(struct mp_pin *p);
* filter's input pin is requested. The API user feeds it a frame, which will
* call the first filter's process() function, which will filter and output
* the frame, and the frame is iteratively filtered until it reaches the output.
- * (Depending on implementation, some if this wil be recursive not iterative.)
+ *
+ * (The mp_pin_* calls can recursively start filtering, but this is only the
+ * case if you access a separate graph with a different filter root. Most
+ * importantly, calling them from outside the filter's process() function (e.g.
+ * an outside filter user) will enter filtering. Within the filter, mp_pin_*
+ * will usually only set or query flags.)
* --- General rules for thread safety: