2010-01-30 16:57:40 +00:00
|
|
|
/*
|
2015-04-13 07:36:54 +00:00
|
|
|
* This file is part of mpv.
|
2010-01-30 16:57:40 +00:00
|
|
|
*
|
2015-04-13 07:36:54 +00:00
|
|
|
* mpv is free software; you can redistribute it and/or modify
|
2010-01-30 16:57:40 +00:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
2015-04-13 07:36:54 +00:00
|
|
|
* mpv is distributed in the hope that it will be useful,
|
2010-01-30 16:57:40 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
2015-04-13 07:36:54 +00:00
|
|
|
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
2010-01-30 16:57:40 +00:00
|
|
|
*/
|
|
|
|
|
2002-04-06 22:05:01 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2011-07-30 16:03:20 +00:00
|
|
|
#include <assert.h>
|
2012-07-31 21:37:56 +00:00
|
|
|
#include <sys/types.h>
|
2012-08-15 20:23:02 +00:00
|
|
|
#include <libavutil/common.h>
|
|
|
|
#include <libavutil/mem.h>
|
2002-04-06 22:05:01 +00:00
|
|
|
|
2005-11-18 14:39:25 +00:00
|
|
|
#include "config.h"
|
2002-05-25 13:22:28 +00:00
|
|
|
|
2014-07-13 18:12:13 +00:00
|
|
|
#include "common/common.h"
|
2013-12-21 16:43:25 +00:00
|
|
|
#include "common/global.h"
|
2013-12-17 01:39:45 +00:00
|
|
|
#include "common/msg.h"
|
2013-12-17 01:02:25 +00:00
|
|
|
#include "options/m_option.h"
|
|
|
|
#include "options/m_config.h"
|
2002-08-13 23:32:05 +00:00
|
|
|
|
2013-12-17 01:02:25 +00:00
|
|
|
#include "options/options.h"
|
2002-04-06 22:05:01 +00:00
|
|
|
|
2012-11-09 00:06:43 +00:00
|
|
|
#include "video/img_format.h"
|
|
|
|
#include "video/mp_image.h"
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
#include "video/mp_image_pool.h"
|
2002-04-06 22:05:01 +00:00
|
|
|
#include "vf.h"
|
|
|
|
|
2007-11-09 06:57:24 +00:00
|
|
|
extern const vf_info_t vf_info_crop;
|
|
|
|
extern const vf_info_t vf_info_expand;
|
|
|
|
extern const vf_info_t vf_info_scale;
|
|
|
|
extern const vf_info_t vf_info_format;
|
|
|
|
extern const vf_info_t vf_info_noformat;
|
|
|
|
extern const vf_info_t vf_info_flip;
|
|
|
|
extern const vf_info_t vf_info_rotate;
|
|
|
|
extern const vf_info_t vf_info_mirror;
|
|
|
|
extern const vf_info_t vf_info_noise;
|
2012-11-15 14:16:12 +00:00
|
|
|
extern const vf_info_t vf_info_eq;
|
2009-07-07 02:01:36 +00:00
|
|
|
extern const vf_info_t vf_info_gradfun;
|
2007-11-09 06:57:24 +00:00
|
|
|
extern const vf_info_t vf_info_unsharp;
|
|
|
|
extern const vf_info_t vf_info_hqdn3d;
|
|
|
|
extern const vf_info_t vf_info_dsize;
|
|
|
|
extern const vf_info_t vf_info_pullup;
|
|
|
|
extern const vf_info_t vf_info_delogo;
|
2012-10-21 16:31:34 +00:00
|
|
|
extern const vf_info_t vf_info_sub;
|
2007-11-09 06:57:24 +00:00
|
|
|
extern const vf_info_t vf_info_yadif;
|
2010-10-22 17:46:12 +00:00
|
|
|
extern const vf_info_t vf_info_stereo3d;
|
2012-08-23 10:32:13 +00:00
|
|
|
extern const vf_info_t vf_info_dlopen;
|
2013-03-10 23:16:34 +00:00
|
|
|
extern const vf_info_t vf_info_lavfi;
|
2013-09-20 13:55:13 +00:00
|
|
|
extern const vf_info_t vf_info_vaapi;
|
2014-04-12 15:51:19 +00:00
|
|
|
extern const vf_info_t vf_info_vapoursynth;
|
2014-10-11 23:31:20 +00:00
|
|
|
extern const vf_info_t vf_info_vapoursynth_lazy;
|
2014-04-29 13:07:21 +00:00
|
|
|
extern const vf_info_t vf_info_vdpaupp;
|
2014-07-30 20:44:35 +00:00
|
|
|
extern const vf_info_t vf_info_buffer;
|
2002-04-06 22:05:01 +00:00
|
|
|
|
|
|
|
// list of available filters:
|
2011-11-03 13:21:53 +00:00
|
|
|
static const vf_info_t *const filter_list[] = {
|
2002-04-06 22:05:01 +00:00
|
|
|
&vf_info_crop,
|
|
|
|
&vf_info_expand,
|
2002-04-07 20:21:37 +00:00
|
|
|
&vf_info_scale,
|
2002-04-09 14:01:53 +00:00
|
|
|
&vf_info_format,
|
2004-02-06 20:31:57 +00:00
|
|
|
&vf_info_noformat,
|
2002-04-11 03:17:14 +00:00
|
|
|
&vf_info_flip,
|
2011-12-11 05:48:26 +00:00
|
|
|
|
2014-03-16 09:25:05 +00:00
|
|
|
#if HAVE_LIBAVFILTER
|
2015-04-20 15:00:00 +00:00
|
|
|
&vf_info_mirror,
|
2013-03-10 23:16:34 +00:00
|
|
|
&vf_info_lavfi,
|
2015-02-11 16:32:41 +00:00
|
|
|
&vf_info_rotate,
|
2002-06-14 01:14:56 +00:00
|
|
|
&vf_info_noise,
|
2009-07-07 02:01:36 +00:00
|
|
|
&vf_info_gradfun,
|
2002-10-29 22:37:11 +00:00
|
|
|
&vf_info_unsharp,
|
2003-02-15 22:24:32 +00:00
|
|
|
&vf_info_hqdn3d,
|
2003-08-18 15:24:08 +00:00
|
|
|
&vf_info_pullup,
|
2003-09-03 22:44:28 +00:00
|
|
|
&vf_info_delogo,
|
2006-06-06 23:30:23 +00:00
|
|
|
&vf_info_yadif,
|
2015-02-11 16:32:41 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
&vf_info_eq,
|
|
|
|
&vf_info_dsize,
|
|
|
|
&vf_info_sub,
|
2010-10-22 17:46:12 +00:00
|
|
|
&vf_info_stereo3d,
|
2014-07-30 20:44:35 +00:00
|
|
|
&vf_info_buffer,
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_DLOPEN
|
2012-08-23 10:32:13 +00:00
|
|
|
&vf_info_dlopen,
|
2013-09-20 13:55:13 +00:00
|
|
|
#endif
|
2014-10-11 23:31:20 +00:00
|
|
|
#if HAVE_VAPOURSYNTH_CORE && HAVE_VAPOURSYNTH
|
2014-04-12 15:51:19 +00:00
|
|
|
&vf_info_vapoursynth,
|
|
|
|
#endif
|
2014-10-11 23:31:20 +00:00
|
|
|
#if HAVE_VAPOURSYNTH_CORE && HAVE_VAPOURSYNTH_LAZY
|
|
|
|
&vf_info_vapoursynth_lazy,
|
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_VAAPI_VPP
|
2013-09-20 13:55:13 +00:00
|
|
|
&vf_info_vaapi,
|
2014-04-29 13:07:21 +00:00
|
|
|
#endif
|
|
|
|
#if HAVE_VDPAU
|
|
|
|
&vf_info_vdpaupp,
|
2013-07-09 07:28:05 +00:00
|
|
|
#endif
|
2002-04-06 22:05:01 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2014-04-20 21:53:59 +00:00
|
|
|
static void vf_uninit_filter(vf_instance_t *vf);
|
|
|
|
|
options: use m_config for options instead of m_struct
For some reason, both m_config and m_struct are somewhat similar, except
that m_config is much more powerful. m_config is used for VOs and some
other things, so to unify them. We plan to kick out m_struct and use
m_config for everything. (Unfortunately, m_config is also a bit more
bloated, so this commit isn't all that great, but it will allow to
reduce the option parser mess somewhat.)
This commit also switches all video filters to use the option macros.
One reason is that m_struct and m_config, even though they both use
m_option, store the offsets of the option fields differently (sigh...),
meaning the options defined for either are incompatible. It's easier to
switch everything in one go.
This commit will allow using the -vf option parser for other things,
like VOs and AOs.
2013-07-21 17:33:08 +00:00
|
|
|
static bool get_desc(struct m_obj_desc *dst, int index)
|
|
|
|
{
|
|
|
|
if (index >= MP_ARRAY_SIZE(filter_list) - 1)
|
|
|
|
return false;
|
|
|
|
const vf_info_t *vf = filter_list[index];
|
|
|
|
*dst = (struct m_obj_desc) {
|
|
|
|
.name = vf->name,
|
2013-10-23 17:06:42 +00:00
|
|
|
.description = vf->description,
|
options: use m_config for options instead of m_struct
For some reason, both m_config and m_struct are somewhat similar, except
that m_config is much more powerful. m_config is used for VOs and some
other things, so to unify them. We plan to kick out m_struct and use
m_config for everything. (Unfortunately, m_config is also a bit more
bloated, so this commit isn't all that great, but it will allow to
reduce the option parser mess somewhat.)
This commit also switches all video filters to use the option macros.
One reason is that m_struct and m_config, even though they both use
m_option, store the offsets of the option fields differently (sigh...),
meaning the options defined for either are incompatible. It's easier to
switch everything in one go.
This commit will allow using the -vf option parser for other things,
like VOs and AOs.
2013-07-21 17:33:08 +00:00
|
|
|
.priv_size = vf->priv_size,
|
|
|
|
.priv_defaults = vf->priv_defaults,
|
|
|
|
.options = vf->options,
|
|
|
|
.p = vf,
|
2013-11-23 20:34:24 +00:00
|
|
|
.print_help = vf->print_help,
|
options: use m_config for options instead of m_struct
For some reason, both m_config and m_struct are somewhat similar, except
that m_config is much more powerful. m_config is used for VOs and some
other things, so to unify them. We plan to kick out m_struct and use
m_config for everything. (Unfortunately, m_config is also a bit more
bloated, so this commit isn't all that great, but it will allow to
reduce the option parser mess somewhat.)
This commit also switches all video filters to use the option macros.
One reason is that m_struct and m_config, even though they both use
m_option, store the offsets of the option fields differently (sigh...),
meaning the options defined for either are incompatible. It's easier to
switch everything in one go.
This commit will allow using the -vf option parser for other things,
like VOs and AOs.
2013-07-21 17:33:08 +00:00
|
|
|
};
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2003-03-15 18:01:02 +00:00
|
|
|
// For the vf option
|
options: use m_config for options instead of m_struct
For some reason, both m_config and m_struct are somewhat similar, except
that m_config is much more powerful. m_config is used for VOs and some
other things, so to unify them. We plan to kick out m_struct and use
m_config for everything. (Unfortunately, m_config is also a bit more
bloated, so this commit isn't all that great, but it will allow to
reduce the option parser mess somewhat.)
This commit also switches all video filters to use the option macros.
One reason is that m_struct and m_config, even though they both use
m_option, store the offsets of the option fields differently (sigh...),
meaning the options defined for either are incompatible. It's easier to
switch everything in one go.
This commit will allow using the -vf option parser for other things,
like VOs and AOs.
2013-07-21 17:33:08 +00:00
|
|
|
const struct m_obj_list vf_obj_list = {
|
|
|
|
.get_desc = get_desc,
|
|
|
|
.description = "video filters",
|
2003-03-15 18:01:02 +00:00
|
|
|
};
|
|
|
|
|
2013-12-07 18:33:38 +00:00
|
|
|
// Try the cmd on each filter (starting with the first), and stop at the first
|
|
|
|
// filter which does not return CONTROL_UNKNOWN for it.
|
2013-12-07 18:32:44 +00:00
|
|
|
int vf_control_any(struct vf_chain *c, int cmd, void *arg)
|
2013-07-14 22:57:04 +00:00
|
|
|
{
|
2013-12-07 18:33:38 +00:00
|
|
|
for (struct vf_instance *cur = c->first; cur; cur = cur->next) {
|
|
|
|
if (cur->control) {
|
|
|
|
int r = cur->control(cur, cmd, arg);
|
|
|
|
if (r != CONTROL_UNKNOWN)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
2013-12-07 18:32:44 +00:00
|
|
|
return CONTROL_UNKNOWN;
|
2013-07-14 22:57:04 +00:00
|
|
|
}
|
|
|
|
|
2014-04-13 14:00:11 +00:00
|
|
|
int vf_control_by_label(struct vf_chain *c,int cmd, void *arg, bstr label)
|
|
|
|
{
|
|
|
|
char *label_str = bstrdup0(NULL, label);
|
|
|
|
struct vf_instance *cur = vf_find_by_label(c, label_str);
|
|
|
|
talloc_free(label_str);
|
2014-12-30 13:04:53 +00:00
|
|
|
if (cur) {
|
|
|
|
return cur->control ? cur->control(cur, cmd, arg) : CONTROL_NA;
|
|
|
|
} else {
|
2014-04-13 14:00:11 +00:00
|
|
|
return CONTROL_UNKNOWN;
|
2014-12-30 13:04:53 +00:00
|
|
|
}
|
2014-04-13 14:00:11 +00:00
|
|
|
}
|
|
|
|
|
2014-05-01 17:29:17 +00:00
|
|
|
static void vf_control_all(struct vf_chain *c, int cmd, void *arg)
|
|
|
|
{
|
|
|
|
for (struct vf_instance *cur = c->first; cur; cur = cur->next) {
|
|
|
|
if (cur->control)
|
|
|
|
cur->control(cur, cmd, arg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-18 11:37:24 +00:00
|
|
|
static void vf_fix_img_params(struct mp_image *img, struct mp_image_params *p)
|
|
|
|
{
|
|
|
|
// Filters must absolutely set these correctly.
|
|
|
|
assert(img->w == p->w && img->h == p->h);
|
|
|
|
assert(img->imgfmt == p->imgfmt);
|
|
|
|
// Too many things don't set this correctly.
|
|
|
|
// If --colormatrix is used, decoder and filter chain disagree too.
|
|
|
|
// In general, it's probably more convenient to force these here,
|
|
|
|
// instead of requiring filters to set these correctly.
|
2014-04-20 19:27:45 +00:00
|
|
|
img->params = *p;
|
2013-07-18 11:37:24 +00:00
|
|
|
}
|
|
|
|
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
// Get a new image for filter output, with size and pixel format according to
|
|
|
|
// the last vf_config call.
|
|
|
|
struct mp_image *vf_alloc_out_image(struct vf_instance *vf)
|
2011-11-03 13:21:53 +00:00
|
|
|
{
|
2013-12-07 18:33:11 +00:00
|
|
|
struct mp_image_params *p = &vf->fmt_out;
|
|
|
|
assert(p->imgfmt);
|
2013-07-18 11:37:24 +00:00
|
|
|
struct mp_image *img = mp_image_pool_get(vf->out_pool, p->imgfmt, p->w, p->h);
|
video: introduce failure path for image allocations
Until now, failure to allocate image data resulted in a crash (i.e.
abort() was called). This was intentional, because it's pretty silly to
degrade playback, and in almost all situations, the OOM will probably
kill you anyway. (And then there's the standard Linux overcommit
behavior, which also will kill you at some point.)
But I changed my opinion, so here we go. This change does not affect
_all_ memory allocations, just image data. Now in most failure cases,
the output will just be skipped. For video filters, this coincidentally
means that failure is treated as EOF (because the playback core assumes
EOF if nothing comes out of the video filter chain). In other
situations, output might be in some way degraded, like skipping frames,
not scaling OSD, and such.
Functions whose return values changed semantics:
mp_image_alloc
mp_image_new_copy
mp_image_new_ref
mp_image_make_writeable
mp_image_setrefp
mp_image_to_av_frame_and_unref
mp_image_from_av_frame
mp_image_new_external_ref
mp_image_new_custom_ref
mp_image_pool_make_writeable
mp_image_pool_get
mp_image_pool_new_copy
mp_vdpau_mixed_frame_create
vf_alloc_out_image
vf_make_out_image_writeable
glGetWindowScreenshot
2014-06-17 20:43:43 +00:00
|
|
|
if (img)
|
|
|
|
vf_fix_img_params(img, p);
|
2013-07-18 11:37:24 +00:00
|
|
|
return img;
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
}
|
2011-11-03 13:21:53 +00:00
|
|
|
|
video: introduce failure path for image allocations
Until now, failure to allocate image data resulted in a crash (i.e.
abort() was called). This was intentional, because it's pretty silly to
degrade playback, and in almost all situations, the OOM will probably
kill you anyway. (And then there's the standard Linux overcommit
behavior, which also will kill you at some point.)
But I changed my opinion, so here we go. This change does not affect
_all_ memory allocations, just image data. Now in most failure cases,
the output will just be skipped. For video filters, this coincidentally
means that failure is treated as EOF (because the playback core assumes
EOF if nothing comes out of the video filter chain). In other
situations, output might be in some way degraded, like skipping frames,
not scaling OSD, and such.
Functions whose return values changed semantics:
mp_image_alloc
mp_image_new_copy
mp_image_new_ref
mp_image_make_writeable
mp_image_setrefp
mp_image_to_av_frame_and_unref
mp_image_from_av_frame
mp_image_new_external_ref
mp_image_new_custom_ref
mp_image_pool_make_writeable
mp_image_pool_get
mp_image_pool_new_copy
mp_vdpau_mixed_frame_create
vf_alloc_out_image
vf_make_out_image_writeable
glGetWindowScreenshot
2014-06-17 20:43:43 +00:00
|
|
|
// Returns false on failure; then the image can't be written to.
|
|
|
|
bool vf_make_out_image_writeable(struct vf_instance *vf, struct mp_image *img)
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
{
|
2013-12-07 18:33:11 +00:00
|
|
|
struct mp_image_params *p = &vf->fmt_out;
|
|
|
|
assert(p->imgfmt);
|
2013-06-07 23:35:44 +00:00
|
|
|
assert(p->imgfmt == img->imgfmt);
|
|
|
|
assert(p->w == img->w && p->h == img->h);
|
video: introduce failure path for image allocations
Until now, failure to allocate image data resulted in a crash (i.e.
abort() was called). This was intentional, because it's pretty silly to
degrade playback, and in almost all situations, the OOM will probably
kill you anyway. (And then there's the standard Linux overcommit
behavior, which also will kill you at some point.)
But I changed my opinion, so here we go. This change does not affect
_all_ memory allocations, just image data. Now in most failure cases,
the output will just be skipped. For video filters, this coincidentally
means that failure is treated as EOF (because the playback core assumes
EOF if nothing comes out of the video filter chain). In other
situations, output might be in some way degraded, like skipping frames,
not scaling OSD, and such.
Functions whose return values changed semantics:
mp_image_alloc
mp_image_new_copy
mp_image_new_ref
mp_image_make_writeable
mp_image_setrefp
mp_image_to_av_frame_and_unref
mp_image_from_av_frame
mp_image_new_external_ref
mp_image_new_custom_ref
mp_image_pool_make_writeable
mp_image_pool_get
mp_image_pool_new_copy
mp_vdpau_mixed_frame_create
vf_alloc_out_image
vf_make_out_image_writeable
glGetWindowScreenshot
2014-06-17 20:43:43 +00:00
|
|
|
return mp_image_pool_make_writeable(vf->out_pool, img);
|
2002-04-06 22:05:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
|
2013-12-07 18:35:55 +00:00
|
|
|
// The default callback assumes all formats are passed through.
|
2011-11-03 13:21:53 +00:00
|
|
|
static int vf_default_query_format(struct vf_instance *vf, unsigned int fmt)
|
|
|
|
{
|
|
|
|
return vf_next_query_format(vf, fmt);
|
2002-10-30 17:48:39 +00:00
|
|
|
}
|
|
|
|
|
2014-05-04 14:07:43 +00:00
|
|
|
void vf_print_filter_chain(struct vf_chain *c, int msglevel,
|
|
|
|
struct vf_instance *vf)
|
2013-01-14 18:19:23 +00:00
|
|
|
{
|
2013-12-21 20:49:13 +00:00
|
|
|
if (!mp_msg_test(c->log, msglevel))
|
2013-01-14 18:19:23 +00:00
|
|
|
return;
|
|
|
|
|
2014-07-13 18:12:13 +00:00
|
|
|
char b[128] = {0};
|
|
|
|
|
2014-11-12 18:19:16 +00:00
|
|
|
mp_snprintf_cat(b, sizeof(b), "%s", mp_image_params_to_str(&c->input_params));
|
2015-02-23 15:12:03 +00:00
|
|
|
mp_msg(c->log, msglevel, " [vd] %s\n", b);
|
2014-07-13 18:12:13 +00:00
|
|
|
|
2013-12-07 18:32:44 +00:00
|
|
|
for (vf_instance_t *f = c->first; f; f = f->next) {
|
2014-07-13 18:12:13 +00:00
|
|
|
b[0] = '\0';
|
2015-02-23 15:12:03 +00:00
|
|
|
mp_snprintf_cat(b, sizeof(b), " [%s] ", f->info->name);
|
2014-11-12 18:19:16 +00:00
|
|
|
mp_snprintf_cat(b, sizeof(b), "%s", mp_image_params_to_str(&f->fmt_out));
|
2014-05-01 16:45:02 +00:00
|
|
|
if (f->autoinserted)
|
2014-07-13 18:12:13 +00:00
|
|
|
mp_snprintf_cat(b, sizeof(b), " [a]");
|
2014-05-04 14:07:43 +00:00
|
|
|
if (f == vf)
|
2014-07-13 18:12:13 +00:00
|
|
|
mp_snprintf_cat(b, sizeof(b), " <---");
|
|
|
|
mp_msg(c->log, msglevel, "%s\n", b);
|
2013-01-14 18:19:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-07 18:32:44 +00:00
|
|
|
static struct vf_instance *vf_open(struct vf_chain *c, const char *name,
|
|
|
|
char **args)
|
2010-01-16 18:37:13 +00:00
|
|
|
{
|
options: use m_config for options instead of m_struct
For some reason, both m_config and m_struct are somewhat similar, except
that m_config is much more powerful. m_config is used for VOs and some
other things, so to unify them. We plan to kick out m_struct and use
m_config for everything. (Unfortunately, m_config is also a bit more
bloated, so this commit isn't all that great, but it will allow to
reduce the option parser mess somewhat.)
This commit also switches all video filters to use the option macros.
One reason is that m_struct and m_config, even though they both use
m_option, store the offsets of the option fields differently (sigh...),
meaning the options defined for either are incompatible. It's easier to
switch everything in one go.
This commit will allow using the -vf option parser for other things,
like VOs and AOs.
2013-07-21 17:33:08 +00:00
|
|
|
struct m_obj_desc desc;
|
|
|
|
if (!m_obj_list_find(&desc, &vf_obj_list, bstr0(name))) {
|
2013-12-21 16:43:25 +00:00
|
|
|
MP_ERR(c, "Couldn't find video filter '%s'.\n", name);
|
options: use m_config for options instead of m_struct
For some reason, both m_config and m_struct are somewhat similar, except
that m_config is much more powerful. m_config is used for VOs and some
other things, so to unify them. We plan to kick out m_struct and use
m_config for everything. (Unfortunately, m_config is also a bit more
bloated, so this commit isn't all that great, but it will allow to
reduce the option parser mess somewhat.)
This commit also switches all video filters to use the option macros.
One reason is that m_struct and m_config, even though they both use
m_option, store the offsets of the option fields differently (sigh...),
meaning the options defined for either are incompatible. It's easier to
switch everything in one go.
This commit will allow using the -vf option parser for other things,
like VOs and AOs.
2013-07-21 17:33:08 +00:00
|
|
|
return NULL;
|
2002-04-06 22:05:01 +00:00
|
|
|
}
|
options: use m_config for options instead of m_struct
For some reason, both m_config and m_struct are somewhat similar, except
that m_config is much more powerful. m_config is used for VOs and some
other things, so to unify them. We plan to kick out m_struct and use
m_config for everything. (Unfortunately, m_config is also a bit more
bloated, so this commit isn't all that great, but it will allow to
reduce the option parser mess somewhat.)
This commit also switches all video filters to use the option macros.
One reason is that m_struct and m_config, even though they both use
m_option, store the offsets of the option fields differently (sigh...),
meaning the options defined for either are incompatible. It's easier to
switch everything in one go.
This commit will allow using the -vf option parser for other things,
like VOs and AOs.
2013-07-21 17:33:08 +00:00
|
|
|
vf_instance_t *vf = talloc_zero(NULL, struct vf_instance);
|
|
|
|
*vf = (vf_instance_t) {
|
|
|
|
.info = desc.p,
|
2013-12-21 16:43:25 +00:00
|
|
|
.log = mp_log_new(vf, c->log, name),
|
2013-12-07 18:32:44 +00:00
|
|
|
.hwdec = c->hwdec,
|
options: use m_config for options instead of m_struct
For some reason, both m_config and m_struct are somewhat similar, except
that m_config is much more powerful. m_config is used for VOs and some
other things, so to unify them. We plan to kick out m_struct and use
m_config for everything. (Unfortunately, m_config is also a bit more
bloated, so this commit isn't all that great, but it will allow to
reduce the option parser mess somewhat.)
This commit also switches all video filters to use the option macros.
One reason is that m_struct and m_config, even though they both use
m_option, store the offsets of the option fields differently (sigh...),
meaning the options defined for either are incompatible. It's easier to
switch everything in one go.
This commit will allow using the -vf option parser for other things,
like VOs and AOs.
2013-07-21 17:33:08 +00:00
|
|
|
.query_format = vf_default_query_format,
|
|
|
|
.out_pool = talloc_steal(vf, mp_image_pool_new(16)),
|
2014-06-10 20:41:14 +00:00
|
|
|
.chain = c,
|
options: use m_config for options instead of m_struct
For some reason, both m_config and m_struct are somewhat similar, except
that m_config is much more powerful. m_config is used for VOs and some
other things, so to unify them. We plan to kick out m_struct and use
m_config for everything. (Unfortunately, m_config is also a bit more
bloated, so this commit isn't all that great, but it will allow to
reduce the option parser mess somewhat.)
This commit also switches all video filters to use the option macros.
One reason is that m_struct and m_config, even though they both use
m_option, store the offsets of the option fields differently (sigh...),
meaning the options defined for either are incompatible. It's easier to
switch everything in one go.
This commit will allow using the -vf option parser for other things,
like VOs and AOs.
2013-07-21 17:33:08 +00:00
|
|
|
};
|
2013-12-21 18:45:42 +00:00
|
|
|
struct m_config *config = m_config_from_obj_desc(vf, vf->log, &desc);
|
2013-12-07 18:32:44 +00:00
|
|
|
if (m_config_apply_defaults(config, name, c->opts->vf_defs) < 0)
|
2013-11-30 23:12:10 +00:00
|
|
|
goto error;
|
2013-12-03 23:01:38 +00:00
|
|
|
if (m_config_set_obj_params(config, args) < 0)
|
options: use m_config for options instead of m_struct
For some reason, both m_config and m_struct are somewhat similar, except
that m_config is much more powerful. m_config is used for VOs and some
other things, so to unify them. We plan to kick out m_struct and use
m_config for everything. (Unfortunately, m_config is also a bit more
bloated, so this commit isn't all that great, but it will allow to
reduce the option parser mess somewhat.)
This commit also switches all video filters to use the option macros.
One reason is that m_struct and m_config, even though they both use
m_option, store the offsets of the option fields differently (sigh...),
meaning the options defined for either are incompatible. It's easier to
switch everything in one go.
This commit will allow using the -vf option parser for other things,
like VOs and AOs.
2013-07-21 17:33:08 +00:00
|
|
|
goto error;
|
2013-12-03 23:01:38 +00:00
|
|
|
vf->priv = config->optstruct;
|
|
|
|
int retcode = vf->info->open(vf);
|
2013-09-20 12:00:19 +00:00
|
|
|
if (retcode < 1)
|
options: use m_config for options instead of m_struct
For some reason, both m_config and m_struct are somewhat similar, except
that m_config is much more powerful. m_config is used for VOs and some
other things, so to unify them. We plan to kick out m_struct and use
m_config for everything. (Unfortunately, m_config is also a bit more
bloated, so this commit isn't all that great, but it will allow to
reduce the option parser mess somewhat.)
This commit also switches all video filters to use the option macros.
One reason is that m_struct and m_config, even though they both use
m_option, store the offsets of the option fields differently (sigh...),
meaning the options defined for either are incompatible. It's easier to
switch everything in one go.
This commit will allow using the -vf option parser for other things,
like VOs and AOs.
2013-07-21 17:33:08 +00:00
|
|
|
goto error;
|
|
|
|
return vf;
|
|
|
|
|
|
|
|
error:
|
2013-12-21 16:43:25 +00:00
|
|
|
MP_ERR(c, "Creating filter '%s' failed.\n", name);
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
talloc_free(vf);
|
2002-04-06 22:05:01 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-12-07 18:32:44 +00:00
|
|
|
static vf_instance_t *vf_open_filter(struct vf_chain *c, const char *name,
|
|
|
|
char **args)
|
2011-11-03 13:21:53 +00:00
|
|
|
{
|
2013-12-10 18:24:58 +00:00
|
|
|
int i, l = 0;
|
|
|
|
for (i = 0; args && args[2 * i]; i++)
|
|
|
|
l += 1 + strlen(args[2 * i]) + 1 + strlen(args[2 * i + 1]);
|
|
|
|
l += strlen(name);
|
|
|
|
char str[l + 1];
|
|
|
|
char *p = str;
|
|
|
|
p += sprintf(str, "%s", name);
|
|
|
|
for (i = 0; args && args[2 * i]; i++)
|
|
|
|
p += sprintf(p, " %s=%s", args[2 * i], args[2 * i + 1]);
|
2013-12-21 16:43:25 +00:00
|
|
|
MP_INFO(c, "Opening video filter: [%s]\n", str);
|
2013-12-07 18:32:44 +00:00
|
|
|
return vf_open(c, name, args);
|
|
|
|
}
|
|
|
|
|
2014-04-20 21:53:59 +00:00
|
|
|
void vf_remove_filter(struct vf_chain *c, struct vf_instance *vf)
|
|
|
|
{
|
|
|
|
assert(vf != c->first && vf != c->last); // these are sentinels
|
|
|
|
struct vf_instance *prev = c->first;
|
|
|
|
while (prev && prev->next != vf)
|
|
|
|
prev = prev->next;
|
|
|
|
assert(prev); // not inserted
|
|
|
|
prev->next = vf->next;
|
|
|
|
vf_uninit_filter(vf);
|
|
|
|
}
|
|
|
|
|
2013-12-07 18:32:44 +00:00
|
|
|
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) {
|
2013-12-10 18:24:58 +00:00
|
|
|
// Insert it before the last filter, which is the "out" pseudo-filter
|
2013-12-07 18:35:55 +00:00
|
|
|
// (But after the "in" pseudo-filter)
|
|
|
|
struct vf_instance **pprev = &c->first->next;
|
2013-12-07 18:32:44 +00:00
|
|
|
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) {
|
2014-04-13 14:52:58 +00:00
|
|
|
if (list[n].label) {
|
2013-12-07 18:32:44 +00:00
|
|
|
vf->label = talloc_strdup(vf, list[n].label);
|
2014-04-13 14:52:58 +00:00
|
|
|
} else {
|
|
|
|
for (int i = 0; i < 100; i++) {
|
|
|
|
char* label = talloc_asprintf(vf, "%s.%02d", list[n].name, i);
|
|
|
|
if (vf_find_by_label(c, label)) {
|
|
|
|
talloc_free(label);
|
|
|
|
} else {
|
|
|
|
vf->label = label;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-12-07 18:32:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
2002-04-10 23:23:36 +00:00
|
|
|
}
|
|
|
|
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
// Used by filters to add a filtered frame to the output queue.
|
|
|
|
// Ownership of img is transferred from caller to the filter chain.
|
|
|
|
void vf_add_output_frame(struct vf_instance *vf, struct mp_image *img)
|
2006-07-06 06:58:17 +00:00
|
|
|
{
|
2013-07-16 21:22:55 +00:00
|
|
|
if (img) {
|
2013-12-10 18:24:58 +00:00
|
|
|
vf_fix_img_params(img, &vf->fmt_out);
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
MP_TARRAY_APPEND(vf, vf->out_queued, vf->num_out_queued, img);
|
2013-07-16 21:22:55 +00:00
|
|
|
}
|
2006-07-06 06:58:17 +00:00
|
|
|
}
|
|
|
|
|
2014-09-18 17:25:46 +00:00
|
|
|
static bool vf_has_output_frame(struct vf_instance *vf)
|
|
|
|
{
|
|
|
|
if (!vf->num_out_queued && vf->filter_out) {
|
|
|
|
if (vf->filter_out(vf) < 0)
|
|
|
|
MP_ERR(vf, "Error filtering frame.\n");
|
|
|
|
}
|
|
|
|
return vf->num_out_queued > 0;
|
|
|
|
}
|
|
|
|
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
static struct mp_image *vf_dequeue_output_frame(struct vf_instance *vf)
|
|
|
|
{
|
|
|
|
struct mp_image *res = NULL;
|
2014-09-18 17:25:46 +00:00
|
|
|
if (vf_has_output_frame(vf)) {
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
res = vf->out_queued[0];
|
|
|
|
MP_TARRAY_REMOVE_AT(vf->out_queued, vf->num_out_queued, 0);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2013-12-07 18:32:44 +00:00
|
|
|
static int vf_do_filter(struct vf_instance *vf, struct mp_image *img)
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
{
|
2013-12-07 18:33:11 +00:00
|
|
|
assert(vf->fmt_in.imgfmt);
|
video: don't drop last frame when deinterlacing with yadif
Or in other words, add support for properly draining remaining frames
from video filters. vf_yadif is buffering at least one frame, and the
buffered frame was not retrieved on EOF.
For most filters, ignore this for now, and just adjust them to the
changed semantics of filter_ext. But for vf_lavfi (used by vf_yadif),
real support is implemented. libavfilter handles this simply by passing
a NULL frame to av_buffersrc_add_frame(), so we just have to make
mp_to_av() handle NULL arguments.
In load_next_vo_frame(), we first try to output a frame buffered in the
VO, then the filter, and then (if EOF is reached and there's still no
new frame) the VO again, with draining enabled. I guess this was
implemented slightly incorrectly before, because the filter chain still
could have had remaining output frames.
2014-04-28 17:44:35 +00:00
|
|
|
if (img)
|
2014-06-17 21:30:16 +00:00
|
|
|
assert(mp_image_params_equal(&img->params, &vf->fmt_in));
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
|
|
|
|
if (vf->filter_ext) {
|
2014-04-30 20:19:38 +00:00
|
|
|
int r = vf->filter_ext(vf, img);
|
|
|
|
if (r < 0)
|
|
|
|
MP_ERR(vf, "Error filtering frame.\n");
|
|
|
|
return r;
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
} else {
|
video: don't drop last frame when deinterlacing with yadif
Or in other words, add support for properly draining remaining frames
from video filters. vf_yadif is buffering at least one frame, and the
buffered frame was not retrieved on EOF.
For most filters, ignore this for now, and just adjust them to the
changed semantics of filter_ext. But for vf_lavfi (used by vf_yadif),
real support is implemented. libavfilter handles this simply by passing
a NULL frame to av_buffersrc_add_frame(), so we just have to make
mp_to_av() handle NULL arguments.
In load_next_vo_frame(), we first try to output a frame buffered in the
VO, then the filter, and then (if EOF is reached and there's still no
new frame) the VO again, with draining enabled. I guess this was
implemented slightly incorrectly before, because the filter chain still
could have had remaining output frames.
2014-04-28 17:44:35 +00:00
|
|
|
if (img) {
|
|
|
|
if (vf->filter)
|
|
|
|
img = vf->filter(vf, img);
|
|
|
|
vf_add_output_frame(vf, img);
|
|
|
|
}
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2006-07-06 06:58:17 +00:00
|
|
|
|
2013-12-07 18:32:44 +00:00
|
|
|
// 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)
|
|
|
|
{
|
video: don't drop last frame when deinterlacing with yadif
Or in other words, add support for properly draining remaining frames
from video filters. vf_yadif is buffering at least one frame, and the
buffered frame was not retrieved on EOF.
For most filters, ignore this for now, and just adjust them to the
changed semantics of filter_ext. But for vf_lavfi (used by vf_yadif),
real support is implemented. libavfilter handles this simply by passing
a NULL frame to av_buffersrc_add_frame(), so we just have to make
mp_to_av() handle NULL arguments.
In load_next_vo_frame(), we first try to output a frame buffered in the
VO, then the filter, and then (if EOF is reached and there's still no
new frame) the VO again, with draining enabled. I guess this was
implemented slightly incorrectly before, because the filter chain still
could have had remaining output frames.
2014-04-28 17:44:35 +00:00
|
|
|
assert(img);
|
2013-12-07 18:35:55 +00:00
|
|
|
if (c->initialized < 1) {
|
2013-12-07 18:32:44 +00:00
|
|
|
talloc_free(img);
|
2013-12-07 18:35:55 +00:00
|
|
|
return -1;
|
2013-12-07 18:32:44 +00:00
|
|
|
}
|
2014-06-17 21:30:16 +00:00
|
|
|
assert(mp_image_params_equal(&img->params, &c->input_params));
|
2014-05-01 21:15:50 +00:00
|
|
|
vf_fix_img_params(img, &c->override_params);
|
2013-12-07 18:35:55 +00:00
|
|
|
return vf_do_filter(c->first, img);
|
2013-12-07 18:32:44 +00:00
|
|
|
}
|
|
|
|
|
2015-01-03 02:01:58 +00:00
|
|
|
// Similar to vf_output_frame(), but only ensure that the filter "until" has
|
|
|
|
// output, instead of the end of the filter chain.
|
|
|
|
static int vf_output_frame_until(struct vf_chain *c, struct vf_instance *until,
|
|
|
|
bool eof)
|
2006-07-06 06:58:17 +00:00
|
|
|
{
|
2015-01-03 02:01:58 +00:00
|
|
|
if (until->num_out_queued)
|
2014-05-01 17:29:17 +00:00
|
|
|
return 1;
|
2013-12-07 18:35:55 +00:00
|
|
|
if (c->initialized < 1)
|
2014-05-01 17:29:17 +00:00
|
|
|
return -1;
|
2006-07-06 06:58:17 +00:00
|
|
|
while (1) {
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
struct vf_instance *last = NULL;
|
2013-12-07 18:32:44 +00:00
|
|
|
for (struct vf_instance * cur = c->first; cur; cur = cur->next) {
|
video: don't drop last frame when deinterlacing with yadif
Or in other words, add support for properly draining remaining frames
from video filters. vf_yadif is buffering at least one frame, and the
buffered frame was not retrieved on EOF.
For most filters, ignore this for now, and just adjust them to the
changed semantics of filter_ext. But for vf_lavfi (used by vf_yadif),
real support is implemented. libavfilter handles this simply by passing
a NULL frame to av_buffersrc_add_frame(), so we just have to make
mp_to_av() handle NULL arguments.
In load_next_vo_frame(), we first try to output a frame buffered in the
VO, then the filter, and then (if EOF is reached and there's still no
new frame) the VO again, with draining enabled. I guess this was
implemented slightly incorrectly before, because the filter chain still
could have had remaining output frames.
2014-04-28 17:44:35 +00:00
|
|
|
// Flush remaining frames on EOF, but do that only if the previous
|
|
|
|
// filters have been flushed (i.e. they have no more output).
|
2014-05-01 17:29:17 +00:00
|
|
|
if (eof && !last) {
|
|
|
|
int r = vf_do_filter(cur, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
2014-09-18 17:25:46 +00:00
|
|
|
if (vf_has_output_frame(cur))
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
last = cur;
|
2015-01-03 02:01:58 +00:00
|
|
|
if (cur == until)
|
|
|
|
break;
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
}
|
2011-11-03 13:21:53 +00:00
|
|
|
if (!last)
|
2014-05-01 17:29:17 +00:00
|
|
|
return 0;
|
2015-01-03 02:01:58 +00:00
|
|
|
if (last == until)
|
2014-11-12 17:51:05 +00:00
|
|
|
return 1;
|
|
|
|
int r = vf_do_filter(last->next, vf_dequeue_output_frame(last));
|
2014-05-01 17:29:17 +00:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2006-07-06 06:58:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-03 02:01:58 +00:00
|
|
|
// Output the next queued image (if any) from the full filter chain.
|
|
|
|
// The frame can be retrieved with vf_read_output_frame().
|
|
|
|
// eof: if set, assume there's no more input i.e. vf_filter_frame() will
|
|
|
|
// not be called (until reset) - flush all internally delayed frames
|
|
|
|
// returns: -1: error, 0: no output, 1: output available
|
|
|
|
int vf_output_frame(struct vf_chain *c, bool eof)
|
|
|
|
{
|
|
|
|
return vf_output_frame_until(c, c->last, eof);
|
|
|
|
}
|
|
|
|
|
2014-05-01 17:29:17 +00:00
|
|
|
struct mp_image *vf_read_output_frame(struct vf_chain *c)
|
|
|
|
{
|
2014-11-12 17:51:05 +00:00
|
|
|
if (!c->last->num_out_queued)
|
2014-05-01 17:29:17 +00:00
|
|
|
vf_output_frame(c, false);
|
2014-11-12 17:51:05 +00:00
|
|
|
return vf_dequeue_output_frame(c->last);
|
2014-05-01 17:29:17 +00:00
|
|
|
}
|
|
|
|
|
2015-01-03 02:01:58 +00:00
|
|
|
// Some filters (vf_vapoursynth) filter on separate threads, and may need new
|
|
|
|
// input from the decoder, even though the core does not need a new output image
|
|
|
|
// yet (this is required to get proper pipelining in the filter). If the filter
|
|
|
|
// needs new data, it will call c->wakeup_callback, which in turn causes the
|
|
|
|
// core to recheck the filter chain, calling this function. Each filter is asked
|
|
|
|
// whether it needs a frame (with vf->needs_input), and if so, it will try to
|
|
|
|
// feed it a new frame. If this fails, it will request a new frame from the
|
|
|
|
// core by returning 1.
|
|
|
|
// returns -1: error, 0: nothing needed, 1: add new frame with vf_filter_frame()
|
|
|
|
int vf_needs_input(struct vf_chain *c)
|
|
|
|
{
|
|
|
|
struct vf_instance *prev = c->first;
|
|
|
|
for (struct vf_instance *cur = c->first; cur; cur = cur->next) {
|
|
|
|
while (cur->needs_input && cur->needs_input(cur)) {
|
|
|
|
// Get frames from preceding filters, or if there are none,
|
|
|
|
// request new frames from decoder.
|
|
|
|
int r = vf_output_frame_until(c, prev, false);
|
|
|
|
if (r < 1)
|
|
|
|
return r < 0 ? -1 : 1;
|
|
|
|
r = vf_do_filter(cur, vf_dequeue_output_frame(prev));
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
prev = cur;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
static void vf_forget_frames(struct vf_instance *vf)
|
|
|
|
{
|
|
|
|
for (int n = 0; n < vf->num_out_queued; n++)
|
|
|
|
talloc_free(vf->out_queued[n]);
|
|
|
|
vf->num_out_queued = 0;
|
|
|
|
}
|
2006-07-06 06:58:17 +00:00
|
|
|
|
2014-05-01 17:29:17 +00:00
|
|
|
static void vf_chain_forget_frames(struct vf_chain *c)
|
2013-01-20 02:03:40 +00:00
|
|
|
{
|
2014-05-01 17:29:17 +00:00
|
|
|
for (struct vf_instance *cur = c->first; cur; cur = cur->next)
|
2013-01-20 02:03:40 +00:00
|
|
|
vf_forget_frames(cur);
|
2014-05-01 17:29:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void vf_seek_reset(struct vf_chain *c)
|
|
|
|
{
|
|
|
|
vf_control_all(c, VFCTRL_SEEK_RESET, NULL);
|
|
|
|
vf_chain_forget_frames(c);
|
2013-01-20 02:03:40 +00:00
|
|
|
}
|
|
|
|
|
2013-06-07 23:35:44 +00:00
|
|
|
int vf_next_config(struct vf_instance *vf,
|
|
|
|
int width, int height, int d_width, int d_height,
|
|
|
|
unsigned int voflags, unsigned int outfmt)
|
|
|
|
{
|
2014-04-20 19:27:45 +00:00
|
|
|
vf->fmt_out = vf->fmt_in;
|
|
|
|
vf->fmt_out.imgfmt = outfmt;
|
|
|
|
vf->fmt_out.w = width;
|
|
|
|
vf->fmt_out.h = height;
|
|
|
|
vf->fmt_out.d_w = d_width;
|
|
|
|
vf->fmt_out.d_h = d_height;
|
2013-12-07 18:35:55 +00:00
|
|
|
return 1;
|
2002-04-06 22:05:01 +00:00
|
|
|
}
|
|
|
|
|
2011-11-03 13:21:53 +00:00
|
|
|
int vf_next_query_format(struct vf_instance *vf, unsigned int fmt)
|
|
|
|
{
|
2013-12-07 18:35:55 +00:00
|
|
|
return fmt >= IMGFMT_START && fmt < IMGFMT_END
|
|
|
|
? vf->last_outfmts[fmt - IMGFMT_START] : 0;
|
2002-04-06 22:05:01 +00:00
|
|
|
}
|
|
|
|
|
2013-12-07 18:35:55 +00:00
|
|
|
// Mark accepted input formats in fmts[]. Note that ->query_format will
|
|
|
|
// typically (but not always) call vf_next_query_format() to check whether
|
|
|
|
// an output format is supported.
|
|
|
|
static void query_formats(uint8_t *fmts, struct vf_instance *vf)
|
|
|
|
{
|
|
|
|
for (int n = IMGFMT_START; n < IMGFMT_END; n++)
|
|
|
|
fmts[n - IMGFMT_START] = vf->query_format(vf, n);
|
|
|
|
}
|
2002-04-06 22:05:01 +00:00
|
|
|
|
2013-12-07 18:35:55 +00:00
|
|
|
static bool is_conv_filter(struct vf_instance *vf)
|
2013-12-07 18:32:44 +00:00
|
|
|
{
|
2013-12-07 18:35:55 +00:00
|
|
|
return vf && strcmp(vf->info->name, "scale") == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void update_formats(struct vf_chain *c, struct vf_instance *vf,
|
|
|
|
uint8_t *fmts)
|
|
|
|
{
|
|
|
|
if (vf->next)
|
|
|
|
update_formats(c, vf->next, vf->last_outfmts);
|
|
|
|
query_formats(fmts, vf);
|
|
|
|
bool has_in = false, has_out = false;
|
|
|
|
for (int n = IMGFMT_START; n < IMGFMT_END; n++) {
|
|
|
|
has_in |= !!fmts[n - IMGFMT_START];
|
|
|
|
has_out |= !!vf->last_outfmts[n - IMGFMT_START];
|
|
|
|
}
|
|
|
|
if (has_out && !has_in && !is_conv_filter(vf) &&
|
|
|
|
!is_conv_filter(vf->next))
|
|
|
|
{
|
|
|
|
// If there are output formats, but no input formats (meaning the
|
|
|
|
// filters after vf work, but vf can't output any format the filters
|
|
|
|
// after it accept), try to insert a conversion filter.
|
2013-12-21 16:43:25 +00:00
|
|
|
MP_INFO(c, "Using conversion filter.\n");
|
2013-12-07 18:35:55 +00:00
|
|
|
struct vf_instance *conv = vf_open(c, "scale", NULL);
|
|
|
|
if (conv) {
|
2014-04-20 23:26:56 +00:00
|
|
|
conv->autoinserted = true;
|
2013-12-07 18:35:55 +00:00
|
|
|
conv->next = vf->next;
|
|
|
|
vf->next = conv;
|
|
|
|
update_formats(c, conv, vf->last_outfmts);
|
|
|
|
query_formats(fmts, vf);
|
2011-11-03 13:21:53 +00:00
|
|
|
}
|
2002-04-06 22:05:01 +00:00
|
|
|
}
|
2013-12-07 18:35:55 +00:00
|
|
|
for (int n = IMGFMT_START; n < IMGFMT_END; n++)
|
|
|
|
has_in |= !!fmts[n - IMGFMT_START];
|
|
|
|
if (!has_in) {
|
|
|
|
// Pretend all out formats work. All this does it getting better
|
|
|
|
// error messages in some cases, so we can configure all filter
|
|
|
|
// until it fails, which will be visible in vf_print_filter_chain().
|
|
|
|
for (int n = IMGFMT_START; n < IMGFMT_END; n++)
|
2015-01-21 21:08:24 +00:00
|
|
|
vf->last_outfmts[n - IMGFMT_START] = 1;
|
2013-12-07 18:35:55 +00:00
|
|
|
query_formats(fmts, vf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vf_reconfig_wrapper(struct vf_instance *vf,
|
|
|
|
const struct mp_image_params *p)
|
|
|
|
{
|
|
|
|
vf_forget_frames(vf);
|
|
|
|
if (vf->out_pool)
|
|
|
|
mp_image_pool_clear(vf->out_pool);
|
|
|
|
|
|
|
|
if (!vf->query_format(vf, p->imgfmt))
|
|
|
|
return -2;
|
|
|
|
|
|
|
|
vf->fmt_out = vf->fmt_in = *p;
|
|
|
|
|
2014-06-17 20:44:13 +00:00
|
|
|
if (!mp_image_params_valid(&vf->fmt_in))
|
|
|
|
return -2;
|
|
|
|
|
2013-12-07 18:35:55 +00:00
|
|
|
int r;
|
|
|
|
if (vf->reconfig) {
|
|
|
|
r = vf->reconfig(vf, &vf->fmt_in, &vf->fmt_out);
|
|
|
|
} else if (vf->config) {
|
|
|
|
r = vf->config(vf, p->w, p->h, p->d_w, p->d_h, 0, p->imgfmt) ? 0 : -1;
|
|
|
|
} else {
|
|
|
|
r = 0;
|
|
|
|
}
|
|
|
|
|
2014-06-17 21:30:16 +00:00
|
|
|
if (!mp_image_params_equal(&vf->fmt_in, p))
|
2013-12-07 18:35:55 +00:00
|
|
|
r = -2;
|
|
|
|
|
2014-06-17 20:44:13 +00:00
|
|
|
if (!mp_image_params_valid(&vf->fmt_out))
|
|
|
|
r = -2;
|
|
|
|
|
2013-12-07 18:35:55 +00:00
|
|
|
// Fix csp in case of pixel format change
|
|
|
|
if (r >= 0)
|
|
|
|
mp_image_params_guess_csp(&vf->fmt_out);
|
2013-12-07 18:32:44 +00:00
|
|
|
|
2013-12-07 18:35:55 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-05-01 21:15:50 +00:00
|
|
|
// override_params is used to forcibly change the parameters of input images,
|
|
|
|
// while params has to match the input images exactly.
|
|
|
|
int vf_reconfig(struct vf_chain *c, const struct mp_image_params *params,
|
|
|
|
const struct mp_image_params *override_params)
|
2013-12-07 18:35:55 +00:00
|
|
|
{
|
|
|
|
int r = 0;
|
2014-05-01 17:29:17 +00:00
|
|
|
vf_chain_forget_frames(c);
|
2014-04-20 23:26:56 +00:00
|
|
|
for (struct vf_instance *vf = c->first; vf; ) {
|
|
|
|
struct vf_instance *next = vf->next;
|
|
|
|
if (vf->autoinserted)
|
|
|
|
vf_remove_filter(c, vf);
|
|
|
|
vf = next;
|
|
|
|
}
|
2014-05-01 21:15:50 +00:00
|
|
|
c->input_params = *params;
|
|
|
|
c->first->fmt_in = *override_params;
|
|
|
|
c->override_params = *override_params;
|
|
|
|
struct mp_image_params cur = c->override_params;
|
|
|
|
|
2013-12-07 18:35:55 +00:00
|
|
|
uint8_t unused[IMGFMT_END - IMGFMT_START];
|
|
|
|
update_formats(c, c->first, unused);
|
2014-05-04 14:07:43 +00:00
|
|
|
struct vf_instance *failing = NULL;
|
2013-12-07 18:35:55 +00:00
|
|
|
for (struct vf_instance *vf = c->first; vf; vf = vf->next) {
|
|
|
|
r = vf_reconfig_wrapper(vf, &cur);
|
2014-05-04 14:07:43 +00:00
|
|
|
if (r < 0) {
|
|
|
|
failing = vf;
|
2013-12-07 18:35:55 +00:00
|
|
|
break;
|
2014-05-04 14:07:43 +00:00
|
|
|
}
|
2013-12-07 18:35:55 +00:00
|
|
|
cur = vf->fmt_out;
|
|
|
|
}
|
2014-05-01 21:15:50 +00:00
|
|
|
c->output_params = cur;
|
2013-12-07 18:35:55 +00:00
|
|
|
c->initialized = r < 0 ? -1 : 1;
|
|
|
|
int loglevel = r < 0 ? MSGL_WARN : MSGL_V;
|
|
|
|
if (r == -2)
|
2015-01-13 13:40:37 +00:00
|
|
|
MP_ERR(c, "Image formats incompatible or invalid.\n");
|
2013-12-21 20:49:13 +00:00
|
|
|
mp_msg(c->log, loglevel, "Video filter chain:\n");
|
2014-05-04 14:07:43 +00:00
|
|
|
vf_print_filter_chain(c, loglevel, failing);
|
2014-05-01 21:15:50 +00:00
|
|
|
if (r < 0) {
|
|
|
|
c->input_params = c->override_params = c->output_params =
|
|
|
|
(struct mp_image_params){0};
|
|
|
|
}
|
2013-12-07 18:32:44 +00:00
|
|
|
return r;
|
2002-04-06 22:05:01 +00:00
|
|
|
}
|
|
|
|
|
2013-12-07 18:32:44 +00:00
|
|
|
struct vf_instance *vf_find_by_label(struct vf_chain *c, const char *label)
|
2013-05-22 21:19:57 +00:00
|
|
|
{
|
2013-12-07 18:32:44 +00:00
|
|
|
struct vf_instance *vf = c->first;
|
|
|
|
while (vf) {
|
|
|
|
if (vf->label && label && strcmp(vf->label, label) == 0)
|
|
|
|
return vf;
|
|
|
|
vf = vf->next;
|
2013-05-22 21:19:57 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-12-07 18:35:55 +00:00
|
|
|
static void vf_uninit_filter(vf_instance_t *vf)
|
2011-11-03 13:21:53 +00:00
|
|
|
{
|
|
|
|
if (vf->uninit)
|
|
|
|
vf->uninit(vf);
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
vf_forget_frames(vf);
|
|
|
|
talloc_free(vf);
|
2002-04-20 22:24:19 +00:00
|
|
|
}
|
|
|
|
|
2013-12-07 18:35:55 +00:00
|
|
|
static int input_query_format(struct vf_instance *vf, unsigned int fmt)
|
|
|
|
{
|
|
|
|
// Setting fmt_in is guaranteed by vf_reconfig().
|
|
|
|
if (fmt == vf->fmt_in.imgfmt)
|
|
|
|
return vf_next_query_format(vf, fmt);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-12-10 18:24:58 +00:00
|
|
|
static int output_query_format(struct vf_instance *vf, unsigned int fmt)
|
|
|
|
{
|
|
|
|
struct vf_chain *c = (void *)vf->priv;
|
|
|
|
if (fmt >= IMGFMT_START && fmt < IMGFMT_END)
|
|
|
|
return c->allowed_output_formats[fmt - IMGFMT_START];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-12-21 16:43:25 +00:00
|
|
|
struct vf_chain *vf_new(struct mpv_global *global)
|
2011-11-03 13:21:53 +00:00
|
|
|
{
|
2013-12-07 18:32:44 +00:00
|
|
|
struct vf_chain *c = talloc_ptrtype(NULL, c);
|
|
|
|
*c = (struct vf_chain){
|
2013-12-21 16:43:25 +00:00
|
|
|
.opts = global->opts,
|
|
|
|
.log = mp_log_new(c, global->log, "!vf"),
|
|
|
|
.global = global,
|
2013-12-07 18:32:44 +00:00
|
|
|
};
|
2013-12-07 18:35:55 +00:00
|
|
|
static const struct vf_info in = { .name = "in" };
|
|
|
|
c->first = talloc(c, struct vf_instance);
|
|
|
|
*c->first = (struct vf_instance) {
|
|
|
|
.info = &in,
|
|
|
|
.query_format = input_query_format,
|
|
|
|
};
|
2013-12-10 18:24:58 +00:00
|
|
|
static const struct vf_info out = { .name = "out" };
|
2014-11-12 17:51:05 +00:00
|
|
|
c->last = talloc(c, struct vf_instance);
|
|
|
|
*c->last = (struct vf_instance) {
|
2013-12-10 18:24:58 +00:00
|
|
|
.info = &out,
|
|
|
|
.query_format = output_query_format,
|
|
|
|
.priv = (void *)c,
|
|
|
|
};
|
2014-11-12 17:51:05 +00:00
|
|
|
c->first->next = c->last;
|
2013-12-07 18:32:44 +00:00
|
|
|
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;
|
2011-11-03 13:21:53 +00:00
|
|
|
vf_uninit_filter(vf);
|
2002-04-20 22:24:19 +00:00
|
|
|
}
|
2014-05-01 17:29:17 +00:00
|
|
|
vf_chain_forget_frames(c);
|
2013-12-07 18:32:44 +00:00
|
|
|
talloc_free(c);
|
2002-04-20 22:24:19 +00:00
|
|
|
}
|
vf_*: fix pts values passed to the next filter
Many video filters failed to calculate or even just pass through pts
values for their output frames. Fix this, and also make the two
remaining filters that called vf_next_put_image() twice for the same
input frame (vf_softpulldown, vf_telecine) use vf_queue_frame() so
that e.g. framestepping properly sees both frames.
Changed filters: vf_bmovl, vf_detc, vf_divtc, vf_filmdint, vf_ivtc,
vf_lavc, vf_phase, vf_pullup, vf_softpulldown, vf_telecine, vf_tile,
vf_tinterlace.
2011-04-23 16:56:47 +00:00
|
|
|
|
2013-01-22 12:28:31 +00:00
|
|
|
// When changing the size of an image that had old_w/old_h with
|
|
|
|
// DAR *d_width/*d_height to the new size new_w/new_h, adjust
|
|
|
|
// *d_width/*d_height such that the new image has the same pixel aspect ratio.
|
|
|
|
void vf_rescale_dsize(int *d_width, int *d_height, int old_w, int old_h,
|
|
|
|
int new_w, int new_h)
|
2012-12-26 20:08:54 +00:00
|
|
|
{
|
|
|
|
*d_width = *d_width * new_w / old_w;
|
|
|
|
*d_height = *d_height * new_h / old_h;
|
|
|
|
}
|
|
|
|
|
2013-09-26 14:05:46 +00:00
|
|
|
// Set *d_width/*d_height to display aspect ratio with the givem source size
|
|
|
|
void vf_set_dar(int *d_w, int *d_h, int w, int h, double dar)
|
|
|
|
{
|
|
|
|
*d_w = w;
|
|
|
|
*d_h = h;
|
|
|
|
if (dar > 0.01) {
|
2014-02-19 14:37:47 +00:00
|
|
|
*d_w = h * dar + 0.5;
|
2013-09-26 14:05:46 +00:00
|
|
|
// we don't like horizontal downscale
|
|
|
|
if (*d_w < w) {
|
|
|
|
*d_w = w;
|
2014-02-19 14:37:47 +00:00
|
|
|
*d_h = w / dar + 0.5;
|
2013-09-26 14:05:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|