diff options
Diffstat (limited to 'filters/f_auto_filters.c')
-rw-r--r-- | filters/f_auto_filters.c | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/filters/f_auto_filters.c b/filters/f_auto_filters.c new file mode 100644 index 0000000000..eac6f745ca --- /dev/null +++ b/filters/f_auto_filters.c @@ -0,0 +1,244 @@ +#include <math.h> + +#include "common/common.h" +#include "common/msg.h" +#include "options/m_config.h" +#include "options/options.h" +#include "video/mp_image.h" + +#include "f_auto_filters.h" +#include "f_swscale.h" +#include "f_utils.h" +#include "filter.h" +#include "filter_internal.h" +#include "user_filters.h" + +struct deint_priv { + struct mp_subfilter sub; + int prev_imgfmt; + int prev_setting; + struct m_config_cache *opts; +}; + +static void deint_process(struct mp_filter *f) +{ + struct deint_priv *p = f->priv; + + if (!mp_subfilter_read(&p->sub)) + return; + + struct mp_frame frame = p->sub.frame; + + if (mp_frame_is_signaling(frame)) { + mp_subfilter_continue(&p->sub); + return; + } + + if (frame.type != MP_FRAME_VIDEO) { + MP_ERR(f, "video input required!\n"); + mp_filter_internal_mark_failed(f); + return; + } + + m_config_cache_update(p->opts); + struct filter_opts *opts = p->opts->opts; + + if (!opts->deinterlace) + mp_subfilter_destroy(&p->sub); + + struct mp_image *img = frame.data; + + if (img->imgfmt == p->prev_imgfmt && p->prev_setting == opts->deinterlace) { + mp_subfilter_continue(&p->sub); + return; + } + + if (!mp_subfilter_drain_destroy(&p->sub)) + return; + + assert(!p->sub.filter); + + p->prev_imgfmt = img->imgfmt; + p->prev_setting = opts->deinterlace; + if (!p->prev_setting) { + mp_subfilter_continue(&p->sub); + return; + } + + if (img->imgfmt == IMGFMT_VDPAU) { + char *args[] = {"deint", "yes", NULL}; + p->sub.filter = + mp_create_user_filter(f, MP_OUTPUT_CHAIN_VIDEO, "vdpaupp", args); + } else if (img->imgfmt == IMGFMT_VAAPI) { + p->sub.filter = + mp_create_user_filter(f, MP_OUTPUT_CHAIN_VIDEO, "vavpp", NULL); + } else if (img->imgfmt == IMGFMT_D3D11) { + p->sub.filter = + mp_create_user_filter(f, MP_OUTPUT_CHAIN_VIDEO, "d3d11vpp", NULL); + } else if (mp_sws_supports_input(img->imgfmt)) { + char *args[] = {"mode", "send_field", "deint", "interlaced", NULL}; + p->sub.filter = + mp_create_user_filter(f, MP_OUTPUT_CHAIN_VIDEO, "yadif", args); + } else { + MP_ERR(f, "no deinterlace filter available for this format\n"); + mp_subfilter_continue(&p->sub); + return; + } + + if (!p->sub.filter) + MP_ERR(f, "creating deinterlacer failed\n"); + + mp_subfilter_continue(&p->sub); +} + +static void deint_reset(struct mp_filter *f) +{ + struct deint_priv *p = f->priv; + + mp_subfilter_reset(&p->sub); +} + +static void deint_destroy(struct mp_filter *f) +{ + struct deint_priv *p = f->priv; + + mp_subfilter_reset(&p->sub); + TA_FREEP(&p->sub.filter); +} + +static const struct mp_filter_info deint_filter = { + .name = "deint", + .priv_size = sizeof(struct deint_priv), + .process = deint_process, + .reset = deint_reset, + .destroy = deint_destroy, +}; + +struct mp_filter *mp_deint_create(struct mp_filter *parent) +{ + struct mp_filter *f = mp_filter_create(parent, &deint_filter); + if (!f) + return NULL; + + struct deint_priv *p = f->priv; + + p->sub.in = mp_filter_add_pin(f, MP_PIN_IN, "in"); + p->sub.out = mp_filter_add_pin(f, MP_PIN_OUT, "out"); + + p->opts = m_config_cache_alloc(f, f->global, &filter_conf); + + return f; +} + +struct rotate_priv { + struct mp_subfilter sub; + int prev_rotate; + int prev_imgfmt; + int target_rotate; +}; + +static void rotate_process(struct mp_filter *f) +{ + struct rotate_priv *p = f->priv; + + if (!mp_subfilter_read(&p->sub)) + return; + + struct mp_frame frame = p->sub.frame; + + if (mp_frame_is_signaling(frame)) { + mp_subfilter_continue(&p->sub); + return; + } + + if (frame.type != MP_FRAME_VIDEO) { + MP_ERR(f, "video input required!\n"); + return; + } + + struct mp_image *img = frame.data; + + if (img->params.rotate == p->prev_rotate && + img->imgfmt == p->prev_imgfmt) + { + img->params.rotate = p->target_rotate; + mp_subfilter_continue(&p->sub); + return; + } + + if (!mp_subfilter_drain_destroy(&p->sub)) + return; + + assert(!p->sub.filter); + + int rotate = p->prev_rotate = img->params.rotate; + p->target_rotate = rotate; + p->prev_imgfmt = img->imgfmt; + + struct mp_stream_info *info = mp_filter_find_stream_info(f); + if (rotate == 0 || (info && info->rotate90 && !(rotate % 90))) { + mp_subfilter_continue(&p->sub); + return; + } + + if (mp_sws_supports_input(img->imgfmt)) { + MP_ERR(f, "Video rotation with this format not supported\n"); + mp_subfilter_continue(&p->sub); + return; + } + + double angle = rotate / 360.0 * M_PI * 2; + char *args[] = {"angle", mp_tprintf(30, "%f", angle), + "ow", mp_tprintf(30, "rotw(%f)", angle), + "oh", mp_tprintf(30, "roth(%f)", angle), + NULL}; + p->sub.filter = + mp_create_user_filter(f, MP_OUTPUT_CHAIN_VIDEO, "rotate", args); + + if (p->sub.filter) { + MP_INFO(f, "Inserting rotation filter.\n"); + p->target_rotate = 0; + } else { + MP_ERR(f, "could not create rotation filter\n"); + } + + mp_subfilter_continue(&p->sub); +} + +static void rotate_reset(struct mp_filter *f) +{ + struct rotate_priv *p = f->priv; + + mp_subfilter_reset(&p->sub); +} + +static void rotate_destroy(struct mp_filter *f) +{ + struct rotate_priv *p = f->priv; + + mp_subfilter_reset(&p->sub); + TA_FREEP(&p->sub.filter); +} + +static const struct mp_filter_info rotate_filter = { + .name = "autorotate", + .priv_size = sizeof(struct rotate_priv), + .process = rotate_process, + .reset = rotate_reset, + .destroy = rotate_destroy, +}; + +struct mp_filter *mp_autorotate_create(struct mp_filter *parent) +{ + struct mp_filter *f = mp_filter_create(parent, &rotate_filter); + if (!f) + return NULL; + + struct rotate_priv *p = f->priv; + p->prev_rotate = -1; + + p->sub.in = mp_filter_add_pin(f, MP_PIN_IN, "in"); + p->sub.out = mp_filter_add_pin(f, MP_PIN_OUT, "out"); + + return f; +} |