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.
2018-01-16 11:53:44 +01:00
|
|
|
#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);
|
2018-01-18 14:44:20 +01:00
|
|
|
|
2019-10-02 21:09:30 +02:00
|
|
|
// A bidrectional filter which does not connect its pins. Instead, the user is,
|
|
|
|
// by convention, allowed to access the filter's private pins, and use them
|
|
|
|
// freely. (This is sometimes convenient, such as when you need to pass a single
|
|
|
|
// filter instance to other code, and you don't need a full "proper" filter.)
|
|
|
|
struct mp_filter *mp_bidir_dummy_filter_create(struct mp_filter *parent);
|
|
|
|
|
2018-01-18 14:44:20 +01:00
|
|
|
// A filter which repacks audio frame to fixed frame sizes with the given
|
|
|
|
// number of samples. On hard format changes (sample format/channels/srate),
|
|
|
|
// the frame can be shorter, unless pad_silence is true. Fails on non-aframes.
|
|
|
|
struct mp_filter *mp_fixed_aframe_size_create(struct mp_filter *parent,
|
|
|
|
int samples, bool pad_silence);
|