summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-12-07 19:32:44 +0100
committerwm4 <wm4@nowhere>2013-12-07 19:32:44 +0100
commitbb6165342db0ba60fefa97afe770b393fd6cb463 (patch)
treee97e2a9ab048dd339ff6bfd7112ab9e23bb6e7e6
parent75d3bf4711f88a79af5fd3246a9503dbd6e01586 (diff)
downloadmpv-bb6165342db0ba60fefa97afe770b393fd6cb463.tar.bz2
mpv-bb6165342db0ba60fefa97afe770b393fd6cb463.tar.xz
video: create a separate context for video filter chain
This adds vf_chain, which unlike vf_instance refers to the filter chain as a whole. This makes the filter API less awkward, and will allow handling format negotiation better.
-rw-r--r--mpvcore/player/command.c12
-rw-r--r--mpvcore/player/playloop.c3
-rw-r--r--mpvcore/player/screenshot.c6
-rw-r--r--mpvcore/player/video.c24
-rw-r--r--video/decode/dec_video.c56
-rw-r--r--video/decode/dec_video.h3
-rw-r--r--video/decode/vd_lavc.c4
-rw-r--r--video/filter/vf.c189
-rw-r--r--video/filter/vf.h52
-rw-r--r--video/filter/vf_vavpp.c6
-rw-r--r--video/filter/vf_vo.c2
11 files changed, 197 insertions, 160 deletions
diff --git a/mpvcore/player/command.c b/mpvcore/player/command.c
index 05742e0da6..728e01c636 100644
--- a/mpvcore/player/command.c
+++ b/mpvcore/player/command.c
@@ -1189,13 +1189,13 @@ static int probe_deint_filters(struct MPContext *mpctx, const char *cmd)
static int get_deinterlacing(struct MPContext *mpctx)
{
- vf_instance_t *vf = mpctx->d_video->vfilter;
+ struct vf_chain *c = mpctx->d_video->vfilter;
int enabled = 0;
- if (vf->control(vf, VFCTRL_GET_DEINTERLACE, &enabled) != CONTROL_OK)
+ if (vf_control_any(c, VFCTRL_GET_DEINTERLACE, &enabled) != CONTROL_OK)
enabled = -1;
if (enabled < 0) {
// vf_lavfi doesn't support VFCTRL_GET_DEINTERLACE
- if (vf_find_by_label(vf, VF_DEINTERLACE_LABEL))
+ if (vf_find_by_label(c, VF_DEINTERLACE_LABEL))
enabled = 1;
}
return enabled;
@@ -1203,14 +1203,14 @@ static int get_deinterlacing(struct MPContext *mpctx)
static void set_deinterlacing(struct MPContext *mpctx, bool enable)
{
- vf_instance_t *vf = mpctx->d_video->vfilter;
- if (vf_find_by_label(vf, VF_DEINTERLACE_LABEL)) {
+ struct vf_chain *c = mpctx->d_video->vfilter;
+ if (vf_find_by_label(c, VF_DEINTERLACE_LABEL)) {
if (!enable)
edit_filters(mpctx, STREAM_VIDEO, "del", "@" VF_DEINTERLACE_LABEL);
} else {
if ((get_deinterlacing(mpctx) > 0) != enable) {
int arg = enable;
- if (vf->control(vf, VFCTRL_SET_DEINTERLACE, &arg) != CONTROL_OK)
+ if (vf_control_any(c, VFCTRL_SET_DEINTERLACE, &arg) != CONTROL_OK)
probe_deint_filters(mpctx, "pre");
}
}
diff --git a/mpvcore/player/playloop.c b/mpvcore/player/playloop.c
index b069e5c3f7..b87231c709 100644
--- a/mpvcore/player/playloop.c
+++ b/mpvcore/player/playloop.c
@@ -994,7 +994,8 @@ void run_playloop(struct MPContext *mpctx)
if (!vo->frame_loaded && (!mpctx->paused || mpctx->restart_playback)) {
double frame_time = update_video(mpctx, endpts);
mp_dbg(MSGT_AVSYNC, MSGL_DBG2, "*** ftime=%5.3f ***\n", frame_time);
- if (mpctx->d_video->vf_initialized < 0) {
+ if (mpctx->d_video->vfilter && mpctx->d_video->vfilter->initialized < 0)
+ {
MP_FATAL(mpctx, "\nFATAL: Could not initialize video filters "
"(-vf) or video output (-vo).\n");
int uninit = INITIALIZED_VCODEC;
diff --git a/mpvcore/player/screenshot.c b/mpvcore/player/screenshot.c
index 6a3c258094..bf7a0ce9ee 100644
--- a/mpvcore/player/screenshot.c
+++ b/mpvcore/player/screenshot.c
@@ -314,10 +314,8 @@ static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode)
struct voctrl_screenshot_args args =
{ .full_window = (mode == MODE_FULL_WINDOW) };
- if (mpctx->d_video && mpctx->d_video->vfilter) {
- struct vf_instance *vfilter = mpctx->d_video->vfilter;
- vfilter->control(vfilter, VFCTRL_SCREENSHOT, &args);
- }
+ if (mpctx->d_video && mpctx->d_video->vfilter)
+ vf_control_any(mpctx->d_video->vfilter, VFCTRL_SCREENSHOT, &args);
if (!args.out_image)
vo_control(mpctx->video_out, VOCTRL_SCREENSHOT, &args);
diff --git a/mpvcore/player/video.c b/mpvcore/player/video.c
index 6560192fb4..1b88422593 100644
--- a/mpvcore/player/video.c
+++ b/mpvcore/player/video.c
@@ -58,18 +58,19 @@ static void recreate_video_filters(struct MPContext *mpctx)
struct dec_video *d_video = mpctx->d_video;
assert(d_video);
- vf_uninit_filter_chain(d_video->vfilter);
+ vf_destroy(d_video->vfilter);
+ d_video->vfilter = vf_new(opts);
+ d_video->vfilter->hwdec = &d_video->hwdec_info;
- d_video->vfilter = vf_open_filter(opts, NULL, "vo", NULL);
- if (!d_video->vfilter)
- abort();
- d_video->vfilter->control(d_video->vfilter, VFCTRL_SET_VO, mpctx->video_out);
+ vf_append_filter(d_video->vfilter, "vo", NULL);
+ vf_control_any(d_video->vfilter, VFCTRL_SET_VO, mpctx->video_out);
- d_video->vfilter = append_filters(d_video->vfilter, opts->vf_settings);
+ vf_append_filter_list(d_video->vfilter, opts->vf_settings);
- struct vf_instance *vf = d_video->vfilter;
+ // for vf_sub
+ vf_control_any(d_video->vfilter, VFCTRL_SET_OSD_OBJ, mpctx->osd);
mpctx->osd->render_subs_in_filter
- = vf->control(vf, VFCTRL_INIT_OSD, NULL) == VO_TRUE;
+ = vf_control_any(d_video->vfilter, VFCTRL_INIT_OSD, NULL) == CONTROL_OK;
}
int reinit_video_filters(struct MPContext *mpctx)
@@ -82,7 +83,7 @@ int reinit_video_filters(struct MPContext *mpctx)
recreate_video_filters(mpctx);
video_reinit_vo(d_video);
- return d_video->vf_initialized > 0 ? 0 : -1;
+ return d_video->vfilter && d_video->vfilter->initialized > 0 ? 0 : -1;
}
int reinit_video_chain(struct MPContext *mpctx)
@@ -189,7 +190,7 @@ static bool filter_output_queued_frame(struct MPContext *mpctx)
struct dec_video *d_video = mpctx->d_video;
struct vo *video_out = mpctx->video_out;
- struct mp_image *img = vf_chain_output_queued_frame(d_video->vfilter);
+ struct mp_image *img = vf_output_queued_frame(d_video->vfilter);
if (img)
vo_queue_image(video_out, img);
talloc_free(img);
@@ -215,7 +216,7 @@ static void init_filter_params(struct MPContext *mpctx)
// might recreate the chain a second time, which is not very elegant, but
// allows us to test whether enabling deinterlacing works with the current
// video format and other filters.
- if (d_video->vf_initialized != 1)
+ if (!d_video->vfilter || d_video->vfilter->initialized != 1)
return;
if (d_video->vf_reconfig_count <= mpctx->last_vf_reconfig_count) {
@@ -286,7 +287,6 @@ double update_video(struct MPContext *mpctx, double endpts)
{
struct dec_video *d_video = mpctx->d_video;
struct vo *video_out = mpctx->video_out;
- vf_control(d_video->vfilter, VFCTRL_SET_OSD_OBJ, mpctx->osd); // for vf_sub
if (d_video->header->attached_picture)
return update_video_attached_pic(mpctx);
diff --git a/video/decode/dec_video.c b/video/decode/dec_video.c
index 7b7f7f73fc..9a43ada4c4 100644
--- a/video/decode/dec_video.c
+++ b/video/decode/dec_video.c
@@ -59,8 +59,8 @@ const vd_functions_t * const mpcodecs_vd_drivers[] = {
void video_reset_decoding(struct dec_video *d_video)
{
video_vd_control(d_video, VDCTRL_RESET, NULL);
- if (d_video->vf_initialized == 1)
- vf_chain_seek_reset(d_video->vfilter);
+ if (d_video->vfilter && d_video->vfilter->initialized == 1)
+ vf_seek_reset(d_video->vfilter);
d_video->num_buffered_pts = 0;
d_video->last_pts = MP_NOPTS_VALUE;
d_video->last_packet_pdts = MP_NOPTS_VALUE;
@@ -81,15 +81,14 @@ int video_vd_control(struct dec_video *d_video, int cmd, void *arg)
int video_set_colors(struct dec_video *d_video, const char *item, int value)
{
- vf_instance_t *vf = d_video->vfilter;
vf_equalizer_t data;
data.item = item;
data.value = value;
mp_dbg(MSGT_DECVIDEO, MSGL_V, "set video colors %s=%d \n", item, value);
- if (vf) {
- int ret = vf_control(vf, VFCTRL_SET_EQUALIZER, &data);
+ if (d_video->vfilter) {
+ int ret = vf_control_any(d_video->vfilter, VFCTRL_SET_EQUALIZER, &data);
if (ret == CONTROL_TRUE)
return 1;
}
@@ -100,14 +99,13 @@ int video_set_colors(struct dec_video *d_video, const char *item, int value)
int video_get_colors(struct dec_video *d_video, const char *item, int *value)
{
- vf_instance_t *vf = d_video->vfilter;
vf_equalizer_t data;
data.item = item;
mp_dbg(MSGT_DECVIDEO, MSGL_V, "get video colors %s \n", item);
- if (vf) {
- int ret = vf_control(vf, VFCTRL_GET_EQUALIZER, &data);
+ if (d_video->vfilter) {
+ int ret = vf_control_any(d_video->vfilter, VFCTRL_GET_EQUALIZER, &data);
if (ret == CONTROL_TRUE) {
*value = data.value;
return 1;
@@ -128,7 +126,7 @@ void video_uninit(struct dec_video *d_video)
d_video->vd_driver->uninit(d_video);
}
talloc_free(d_video->priv);
- vf_uninit_filter_chain(d_video->vfilter);
+ vf_destroy(d_video->vfilter);
talloc_free(d_video);
}
@@ -383,7 +381,6 @@ int mpcodecs_reconfig_vo(struct dec_video *d_video,
const struct mp_image_params *params)
{
struct MPOpts *opts = d_video->opts;
- vf_instance_t *vf = d_video->vfilter;
struct mp_image_params p = *params;
struct sh_video *sh = d_video->header->video;
@@ -397,37 +394,6 @@ int mpcodecs_reconfig_vo(struct dec_video *d_video,
mp_msg(MSGT_DECVIDEO, MSGL_V, "VDec: vo config request - %d x %d (%s)\n",
p.w, p.h, vo_format_name(p.imgfmt));
- // check if libvo and codec has common outfmt (no conversion):
- int flags = 0;
- for (;;) {
- mp_msg(MSGT_VFILTER, MSGL_V, "Trying filter chain:\n");
- vf_print_filter_chain(MSGL_V, vf);
-
- flags = vf->query_format(vf, p.imgfmt);
- mp_msg(MSGT_CPLAYER, MSGL_DBG2, "vo_debug: query(%s) returned 0x%X \n",
- vo_format_name(p.imgfmt), flags);
- if ((flags & VFCAP_CSP_SUPPORTED_BY_HW)
- || (flags & VFCAP_CSP_SUPPORTED))
- {
- break;
- }
- // TODO: no match - we should use conversion...
- if (strcmp(vf->info->name, "scale")) {
- mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "Could not find matching colorspace - retrying with -vf scale...\n");
- vf = vf_open_filter(opts, vf, "scale", NULL);
- continue;
- }
- mp_tmsg(MSGT_CPLAYER, MSGL_WARN,
- "The selected video_out device is incompatible with this codec.\n"\
- "Try appending the scale filter to your filter list,\n"\
- "e.g. -vf filter,scale instead of -vf filter.\n");
- mp_tmsg(MSGT_VFILTER, MSGL_WARN, "Attempted filter chain:\n");
- vf_print_filter_chain(MSGL_WARN, vf);
- d_video->vf_initialized = -1;
- return -1; // failed
- }
- d_video->vfilter = vf;
-
float decoder_aspect = p.d_w / (float)p.d_h;
if (d_video->initial_decoder_aspect == 0)
d_video->initial_decoder_aspect = decoder_aspect;
@@ -473,17 +439,11 @@ int mpcodecs_reconfig_vo(struct dec_video *d_video,
mp_msg(MSGT_CPLAYER, MSGL_V, "VO Config (%dx%d->%dx%d,0x%X)\n",
p.w, p.h, p.d_w, p.d_h, p.imgfmt);
- if (vf_reconfig_wrapper(vf, &p, 0) < 0) {
+ if (vf_reconfig(d_video->vfilter, &p) < 0) {
mp_tmsg(MSGT_CPLAYER, MSGL_WARN, "FATAL: Cannot initialize video driver.\n");
- d_video->vf_initialized = -1;
return -1;
}
- mp_tmsg(MSGT_VFILTER, MSGL_V, "Video filter chain:\n");
- vf_print_filter_chain(MSGL_V, vf);
-
- d_video->vf_initialized = 1;
-
d_video->vf_input = p;
if (opts->gamma_gamma != 1000)
diff --git a/video/decode/dec_video.h b/video/decode/dec_video.h
index 090b60bc1c..29e23ff322 100644
--- a/video/decode/dec_video.h
+++ b/video/decode/dec_video.h
@@ -30,9 +30,8 @@ struct mp_decoder_list;
struct dec_video {
struct MPOpts *opts;
- struct vf_instance *vfilter; // video filter chain
+ struct vf_chain *vfilter; // video filter chain
const struct vd_functions *vd_driver;
- int vf_initialized; // -1 failed, 0 not done, 1 done
long vf_reconfig_count; // incremented each mpcodecs_reconfig_vo() call
struct mp_image_params vf_input; // video filter input params
struct mp_hwdec_info hwdec_info; // video output hwdec handles
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c
index 10e46b78b1..7683f6c6de 100644
--- a/video/decode/vd_lavc.c
+++ b/video/decode/vd_lavc.c
@@ -791,8 +791,8 @@ static struct mp_image *decode_with_fallback(struct dec_video *vd,
init_avctx(vd, decoder, NULL);
if (ctx->avctx) {
mpi = NULL;
- if (vd->vf_initialized < 0)
- vd->vf_initialized = 0;
+ if (vd->vfilter && vd->vfilter->initialized < 0)
+ vd->vfilter->initialized = 0;
decode(vd, packet, flags, &mpi);
return mpi;
}
diff --git a/video/filter/vf.c b/video/filter/vf.c
index 03044906f9..21f89e5386 100644
--- a/video/filter/vf.c
+++ b/video/filter/vf.c
@@ -116,6 +116,10 @@ static const vf_info_t *const filter_list[] = {
NULL
};
+static void vf_uninit_filter(vf_instance_t *vf);
+static int vf_reconfig_wrapper(struct vf_instance *vf,
+ const struct mp_image_params *params, int flags);
+
static bool get_desc(struct m_obj_desc *dst, int index)
{
if (index >= MP_ARRAY_SIZE(filter_list) - 1)
@@ -139,9 +143,11 @@ const struct m_obj_list vf_obj_list = {
.description = "video filters",
};
-int vf_control(struct vf_instance *vf, int cmd, void *arg)
+int vf_control_any(struct vf_chain *c, int cmd, void *arg)
{
- return vf->control(vf, cmd, arg);
+ if (c->first)
+ return c->first->control(c->first, cmd, arg);
+ return CONTROL_UNKNOWN;
}
static void vf_fix_img_params(struct mp_image *img, struct mp_image_params *p)
@@ -210,12 +216,12 @@ static void print_fmt(int msglevel, struct vf_format *fmt)
}
}
-void vf_print_filter_chain(int msglevel, struct vf_instance *vf)
+void vf_print_filter_chain(struct vf_chain *c, int msglevel)
{
if (!mp_msg_test(MSGT_VFILTER, msglevel))
return;
- for (vf_instance_t *f = vf; f; f = f->next) {
+ for (vf_instance_t *f = c->first; f; f = f->next) {
mp_msg(MSGT_VFILTER, msglevel, " [%s] ", f->info->name);
print_fmt(msglevel, &f->fmt_in);
if (f->next) {
@@ -226,8 +232,8 @@ void vf_print_filter_chain(int msglevel, struct vf_instance *vf)
}
}
-static struct vf_instance *vf_open(struct MPOpts *opts, vf_instance_t *next,
- const char *name, char **args)
+static struct vf_instance *vf_open(struct vf_chain *c, const char *name,
+ char **args)
{
struct m_obj_desc desc;
if (!m_obj_list_find(&desc, &vf_obj_list, bstr0(name))) {
@@ -238,16 +244,17 @@ static struct vf_instance *vf_open(struct MPOpts *opts, vf_instance_t *next,
vf_instance_t *vf = talloc_zero(NULL, struct vf_instance);
*vf = (vf_instance_t) {
.info = desc.p,
- .opts = opts,
- .next = next,
+ .opts = c->opts,
+ .hwdec = c->hwdec,
.config = vf_next_config,
.control = vf_next_control,
.query_format = vf_default_query_format,
.filter = vf_default_filter,
.out_pool = talloc_steal(vf, mp_image_pool_new(16)),
+ .chain = c,
};
struct m_config *config = m_config_from_obj_desc(vf, &desc);
- if (m_config_apply_defaults(config, name, opts->vf_defs) < 0)
+ if (m_config_apply_defaults(config, name, c->opts->vf_defs) < 0)
goto error;
if (m_config_set_obj_params(config, args) < 0)
goto error;
@@ -263,8 +270,8 @@ error:
return NULL;
}
-vf_instance_t *vf_open_filter(struct MPOpts *opts, vf_instance_t *next,
- const char *name, char **args)
+static vf_instance_t *vf_open_filter(struct vf_chain *c, const char *name,
+ char **args)
{
if (strcmp(name, "vo") != 0) {
int i, l = 0;
@@ -279,7 +286,35 @@ vf_instance_t *vf_open_filter(struct MPOpts *opts, vf_instance_t *next,
mp_msg(MSGT_VFILTER, MSGL_INFO, "%s[%s]\n",
"Opening video filter: ", str);
}
- return vf_open(opts, next, name, args);
+ return vf_open(c, name, args);
+}
+
+struct vf_instance *vf_append_filter(struct vf_chain *c, const char *name,
+ char **args)
+{
+ struct vf_instance *vf = vf_open_filter(c, name, args);
+ if (vf) {
+ // Insert it before the last filter, which is the "vo" filter
+ struct vf_instance **pprev = &c->first;
+ while (*pprev && (*pprev)->next)
+ pprev = &(*pprev)->next;
+ vf->next = *pprev ? *pprev : NULL;
+ *pprev = vf;
+ }
+ return vf;
+}
+
+int vf_append_filter_list(struct vf_chain *c, struct m_obj_settings *list)
+{
+ for (int n = 0; list && list[n].name; n++) {
+ struct vf_instance *vf =
+ vf_append_filter(c, list[n].name, list[n].attribs);
+ if (vf) {
+ if (list[n].label)
+ vf->label = talloc_strdup(vf, list[n].label);
+ }
+ }
+ return 0;
}
// Used by filters to add a filtered frame to the output queue.
@@ -304,9 +339,7 @@ static struct mp_image *vf_dequeue_output_frame(struct vf_instance *vf)
return res;
}
-// Input a frame into the filter chain.
-// Return >= 0 on success, < 0 on failure (even if output frames were produced)
-int vf_filter_frame(struct vf_instance *vf, struct mp_image *img)
+static int vf_do_filter(struct vf_instance *vf, struct mp_image *img)
{
assert(vf->fmt_in.configured);
vf_fix_img_params(img, &vf->fmt_in.params);
@@ -319,12 +352,24 @@ int vf_filter_frame(struct vf_instance *vf, struct mp_image *img)
}
}
+// Input a frame into the filter chain. Ownership of img is transferred.
+// Return >= 0 on success, < 0 on failure (even if output frames were produced)
+int vf_filter_frame(struct vf_chain *c, struct mp_image *img)
+{
+ if (c->first) {
+ return vf_do_filter(c->first, img);
+ } else {
+ talloc_free(img);
+ return 0;
+ }
+}
+
// Output the next queued image (if any) from the full filter chain.
-struct mp_image *vf_chain_output_queued_frame(struct vf_instance *vf)
+struct mp_image *vf_output_queued_frame(struct vf_chain *c)
{
while (1) {
struct vf_instance *last = NULL;
- for (struct vf_instance * cur = vf; cur; cur = cur->next) {
+ for (struct vf_instance * cur = c->first; cur; cur = cur->next) {
if (cur->num_out_queued)
last = cur;
}
@@ -333,7 +378,7 @@ struct mp_image *vf_chain_output_queued_frame(struct vf_instance *vf)
struct mp_image *img = vf_dequeue_output_frame(last);
if (!last->next)
return img;
- vf_filter_frame(last->next, img);
+ vf_do_filter(last->next, img);
}
}
@@ -344,15 +389,17 @@ static void vf_forget_frames(struct vf_instance *vf)
vf->num_out_queued = 0;
}
-void vf_chain_seek_reset(struct vf_instance *vf)
+void vf_seek_reset(struct vf_chain *c)
{
- vf->control(vf, VFCTRL_SEEK_RESET, NULL);
- for (struct vf_instance *cur = vf; cur; cur = cur->next)
+ if (!c->first)
+ return;
+ c->first->control(c->first, VFCTRL_SEEK_RESET, NULL);
+ for (struct vf_instance *cur = c->first; cur; cur = cur->next)
vf_forget_frames(cur);
}
-int vf_reconfig_wrapper(struct vf_instance *vf, const struct mp_image_params *p,
- int flags)
+static int vf_reconfig_wrapper(struct vf_instance *vf, const struct mp_image_params *p,
+ int flags)
{
vf_forget_frames(vf);
mp_image_pool_clear(vf->out_pool);
@@ -382,7 +429,6 @@ int vf_reconfig_wrapper(struct vf_instance *vf, const struct mp_image_params *p,
int vf_next_reconfig(struct vf_instance *vf, struct mp_image_params *p,
int outflags)
{
- struct MPOpts *opts = vf->opts;
int flags = vf->next->query_format(vf->next, p->imgfmt);
if (!flags) {
// hmm. colorspace mismatch!!!
@@ -390,9 +436,10 @@ int vf_next_reconfig(struct vf_instance *vf, struct mp_image_params *p,
vf_instance_t *vf2;
if (vf->next->info == &vf_info_scale)
return -1; // scale->scale
- vf2 = vf_open_filter(opts, vf->next, "scale", NULL);
+ vf2 = vf_open_filter(vf->chain, "scale", NULL);
if (!vf2)
return -1; // shouldn't happen!
+ vf2->next = vf->next;
vf->next = vf2;
flags = vf->next->query_format(vf->next, p->imgfmt);
if (!flags) {
@@ -437,43 +484,59 @@ int vf_next_query_format(struct vf_instance *vf, unsigned int fmt)
//============================================================================
-vf_instance_t *append_filters(vf_instance_t *last,
- struct m_obj_settings *vf_settings)
-{
- struct MPOpts *opts = last->opts;
- vf_instance_t *vf;
- int i;
-
- if (vf_settings) {
- // We want to add them in the 'right order'
- for (i = 0; vf_settings[i].name; i++)
- /* NOP */;
- for (i--; i >= 0; i--) {
- //printf("Open filter %s\n",vf_settings[i].name);
- vf = vf_open_filter(opts, last, vf_settings[i].name,
- vf_settings[i].attribs);
- if (vf) {
- if (vf_settings[i].label)
- vf->label = talloc_strdup(vf, vf_settings[i].label);
- last = vf;
- }
+int vf_reconfig(struct vf_chain *c, const struct mp_image_params *params)
+{
+ // check if libvo and codec has common outfmt (no conversion):
+ struct vf_instance *vf = c->first;
+ int flags = 0;
+ for (;;) {
+ mp_msg(MSGT_VFILTER, MSGL_V, "Trying filter chain:\n");
+ vf_print_filter_chain(c, MSGL_V);
+
+ flags = vf->query_format(vf, params->imgfmt);
+ mp_msg(MSGT_CPLAYER, MSGL_DBG2, "vo_debug: query(%s) returned 0x%X \n",
+ vo_format_name(params->imgfmt), flags);
+ if ((flags & VFCAP_CSP_SUPPORTED_BY_HW)
+ || (flags & VFCAP_CSP_SUPPORTED))
+ {
+ break;
+ }
+ // TODO: no match - we should use conversion...
+ if (strcmp(vf->info->name, "scale")) {
+ mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "Could not find matching colorspace - retrying with -vf scale...\n");
+ vf = vf_open_filter(c, "scale", NULL);
+ vf->next = c->first;
+ c->first = vf;
+ continue;
}
+ mp_tmsg(MSGT_CPLAYER, MSGL_WARN,
+ "The selected video_out device is incompatible with this codec.\n"\
+ "Try appending the scale filter to your filter list,\n"\
+ "e.g. -vf filter,scale instead of -vf filter.\n");
+ mp_tmsg(MSGT_VFILTER, MSGL_WARN, "Attempted filter chain:\n");
+ vf_print_filter_chain(c, MSGL_WARN);
+ c->initialized = -1;
+ return -1; // failed
}
- return last;
+
+ int r = vf_reconfig_wrapper(c->first, params, 0);
+ c->initialized = r >= 0 ? 1 : -1;
+ mp_tmsg(MSGT_VFILTER, MSGL_V, "Video filter chain:\n");
+ vf_print_filter_chain(c, MSGL_V);
+ return r;
}
-vf_instance_t *vf_find_by_label(vf_instance_t *chain, const char *label)
+struct vf_instance *vf_find_by_label(struct vf_chain *c, const char *label)
{
- while (chain) {
- if (chain->label && label && strcmp(chain->label, label) == 0)
- return chain;
- chain = chain->next;
+ struct vf_instance *vf = c->first;
+ while (vf) {
+ if (vf->label && label && strcmp(vf->label, label) == 0)
+ return vf;
+ vf = vf->next;
}
return NULL;
}
-//============================================================================
-
void vf_uninit_filter(vf_instance_t *vf)
{
if (vf->uninit)
@@ -482,13 +545,25 @@ void vf_uninit_filter(vf_instance_t *vf)
talloc_free(vf);
}
-void vf_uninit_filter_chain(vf_instance_t *vf)
+struct vf_chain *vf_new(struct MPOpts *opts)
{
- while (vf) {
- vf_instance_t *next = vf->next;
+ struct vf_chain *c = talloc_ptrtype(NULL, c);
+ *c = (struct vf_chain){
+ .opts = opts,
+ };
+ return c;
+}
+
+void vf_destroy(struct vf_chain *c)
+{
+ if (!c)
+ return;
+ while (c->first) {
+ vf_instance_t *vf = c->first;
+ c->first = vf->next;
vf_uninit_filter(vf);
- vf = next;
}
+ talloc_free(c);
}
// When changing the size of an image that had old_w/old_h with
diff --git a/video/filter/vf.h b/video/filter/vf.h
index d47ac2beb8..21031de3ac 100644
--- a/video/filter/vf.h
+++ b/video/filter/vf.h
@@ -29,6 +29,7 @@
struct MPOpts;
struct vf_instance;
struct vf_priv_s;
+struct m_obj_settings;
typedef struct vf_info {
const char *description;
@@ -82,11 +83,25 @@ typedef struct vf_instance {
struct mp_image_pool *out_pool;
struct vf_priv_s *priv;
struct MPOpts *opts;
+ struct mp_hwdec_info *hwdec;
struct mp_image **out_queued;
int num_out_queued;
+
+ // Temporary
+ struct vf_chain *chain;
} vf_instance_t;
+// A chain of video filters
+struct vf_chain {
+ int initialized; // 0: no, 1: yes, -1: attempted to, but failed
+
+ struct vf_instance *first;
+
+ struct MPOpts *opts;
+ struct mp_hwdec_info *hwdec;
+};
+
typedef struct vf_seteq {
const char *item;
int value;
@@ -104,22 +119,26 @@ enum vf_ctrl {
* access OSD/subtitle state outside of normal OSD draw time. */
VFCTRL_SET_OSD_OBJ,
VFCTRL_SET_VO,
- VFCTRL_GET_HWDEC_INFO, // for hwdec filters
};
-int vf_control(struct vf_instance *vf, int cmd, void *arg);
-
+struct vf_chain *vf_new(struct MPOpts *opts);
+void vf_destroy(struct vf_chain *c);
+int vf_reconfig(struct vf_chain *c, const struct mp_image_params *params);
+int vf_control_any(struct vf_chain *c, int cmd, void *arg);
+int vf_filter_frame(struct vf_chain *c, struct mp_image *img);
+struct mp_image *vf_output_queued_frame(struct vf_chain *c);
+void vf_seek_reset(struct vf_chain *c);
+struct vf_instance *vf_append_filter(struct vf_chain *c, const char *name,
+ char **args);
+int vf_append_filter_list(struct vf_chain *c, struct m_obj_settings *list);
+struct vf_instance *vf_find_by_label(struct vf_chain *c, const char *label);
+void vf_print_filter_chain(struct vf_chain *c, int msglevel);
+
+// Filter internal API
struct mp_image *vf_alloc_out_image(struct vf_instance *vf);
void vf_make_out_image_writeable(struct vf_instance *vf, struct mp_image *img);
void vf_add_output_frame(struct vf_instance *vf, struct mp_image *img);
-int vf_filter_frame(struct vf_instance *vf, struct mp_image *img);
-struct mp_image *vf_chain_output_queued_frame(struct vf_instance *vf);
-void vf_chain_seek_reset(struct vf_instance *vf);
-
-vf_instance_t *vf_open_filter(struct MPOpts *opts, vf_instance_t *next,
- const char *name, char **args);
-
// default wrappers:
int vf_next_config(struct vf_instance *vf,
int width, int height, int d_width, int d_height,
@@ -130,18 +149,7 @@ int vf_next_query_format(struct vf_instance *vf, unsigned int fmt);
int vf_next_reconfig(struct vf_instance *vf, struct mp_image_params *params,
int flags);
-struct m_obj_settings;
-vf_instance_t *append_filters(vf_instance_t *last,
- struct m_obj_settings *vf_settings);
-
-vf_instance_t *vf_find_by_label(vf_instance_t *chain, const char *label);
-
-void vf_uninit_filter(vf_instance_t *vf);
-void vf_uninit_filter_chain(vf_instance_t *vf);
-
-int vf_reconfig_wrapper(struct vf_instance *vf,
- const struct mp_image_params *params, int flags);
-void vf_print_filter_chain(int msglevel, struct vf_instance *vf);
+// Helpers
void vf_rescale_dsize(int *d_width, int *d_height, int old_w, int old_h,
int new_w, int new_h);
diff --git a/video/filter/vf_vavpp.c b/video/filter/vf_vavpp.c
index 352f2a586c..1a8a974e11 100644
--- a/video/filter/vf_vavpp.c
+++ b/video/filter/vf_vavpp.c
@@ -372,10 +372,8 @@ static int vf_open(vf_instance_t *vf)
vf->control = control;
struct vf_priv_s *p = vf->priv;
- struct mp_hwdec_info hwdec = {0};
- vf_control(vf->next, VFCTRL_GET_HWDEC_INFO, &hwdec);
- hwdec_request_api(&hwdec, "vaapi");
- p->va = hwdec.vaapi_ctx;
+ hwdec_request_api(vf->hwdec, "vaapi");
+ p->va = vf->hwdec ? vf->hwdec->vaapi_ctx : NULL;
if (!p->va || !p->va->display)
return false;
p->display = p->va->display;
diff --git a/video/filter/vf_vo.c b/video/filter/vf_vo.c
index 3ba0a60fe8..87cdb781f7 100644
--- a/video/filter/vf_vo.c
+++ b/video/filter/vf_vo.c
@@ -88,8 +88,6 @@ static int control(struct vf_instance *vf, int request, void *data)
};
return vo_control(video_out, VOCTRL_GET_EQUALIZER, &param) == VO_TRUE;
}
- case VFCTRL_GET_HWDEC_INFO:
- return vo_control(video_out, VOCTRL_GET_HWDEC_INFO, data) == VO_TRUE;
}
return CONTROL_UNKNOWN;
}