mirror of
https://github.com/mpv-player/mpv
synced 2024-12-27 17:42:17 +00:00
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.
This commit is contained in:
parent
75d3bf4711
commit
bb6165342d
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
int vf_reconfig(struct vf_chain *c, const struct mp_image_params *params)
|
||||
{
|
||||
struct MPOpts *opts = last->opts;
|
||||
vf_instance_t *vf;
|
||||
int i;
|
||||
// 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);
|
||||
|
||||
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;
|
||||
}
|
||||
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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -88,8 +88,6 @@ static int control(struct vf_instance *vf, int request, void *data)
|
||||
};
|
||||
return vo_control(video_out, VOCTRL_GET_EQUALIZER, ¶m) == VO_TRUE;
|
||||
}
|
||||
case VFCTRL_GET_HWDEC_INFO:
|
||||
return vo_control(video_out, VOCTRL_GET_HWDEC_INFO, data) == VO_TRUE;
|
||||
}
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user