mirror of
https://github.com/mpv-player/mpv
synced 2025-03-30 07:18:17 +00:00
video/filter: add field order support for built in deinterlacers
refqueue gets the field of the frame from mp_image which almost always(if not always) assumes bottom field order first. By default this behavior should not change but specifying the field order should bypass this.
This commit is contained in:
parent
5b52d44972
commit
03bfd797f6
@ -88,12 +88,14 @@ static void deint_process(struct mp_filter *f)
|
||||
|
||||
bool has_filter = true;
|
||||
if (img->imgfmt == IMGFMT_VDPAU) {
|
||||
char *args[] = {"deint", "yes", NULL};
|
||||
char *args[] = {"deint", "yes",
|
||||
"parity", field_parity, NULL};
|
||||
p->sub.filter =
|
||||
mp_create_user_filter(f, MP_OUTPUT_CHAIN_VIDEO, "vdpaupp", args);
|
||||
} else if (img->imgfmt == IMGFMT_D3D11) {
|
||||
char *args[] = {"parity", field_parity, NULL};
|
||||
p->sub.filter =
|
||||
mp_create_user_filter(f, MP_OUTPUT_CHAIN_VIDEO, "d3d11vpp", NULL);
|
||||
mp_create_user_filter(f, MP_OUTPUT_CHAIN_VIDEO, "d3d11vpp", args);
|
||||
} else if (img->imgfmt == IMGFMT_CUDA) {
|
||||
char *args[] = {"mode", "send_field",
|
||||
"parity", field_parity, NULL};
|
||||
@ -106,7 +108,8 @@ static void deint_process(struct mp_filter *f)
|
||||
mp_create_user_filter(f, MP_OUTPUT_CHAIN_VIDEO, "bwdif_vulkan", args);
|
||||
} else if (img->imgfmt == IMGFMT_VAAPI) {
|
||||
char *args[] = {"deint", "motion-adaptive",
|
||||
"interlaced-only", "yes", NULL};
|
||||
"interlaced-only", "yes",
|
||||
"parity", field_parity, NULL};
|
||||
p->sub.filter =
|
||||
mp_create_user_filter(f, MP_OUTPUT_CHAIN_VIDEO, "vavpp", args);
|
||||
} else {
|
||||
|
@ -39,6 +39,7 @@ struct mp_refqueue {
|
||||
int needed_past_frames;
|
||||
int needed_future_frames;
|
||||
int flags;
|
||||
int field_parity;
|
||||
|
||||
bool second_field; // current frame has to output a second field yet
|
||||
bool eof;
|
||||
@ -97,6 +98,11 @@ void mp_refqueue_set_mode(struct mp_refqueue *q, int flags)
|
||||
q->flags = flags;
|
||||
}
|
||||
|
||||
void mp_refqueue_set_parity(struct mp_refqueue *q, int parity)
|
||||
{
|
||||
q->field_parity = parity;
|
||||
}
|
||||
|
||||
// Whether the current frame should be deinterlaced.
|
||||
bool mp_refqueue_should_deint(struct mp_refqueue *q)
|
||||
{
|
||||
@ -113,8 +119,14 @@ bool mp_refqueue_is_top_field(struct mp_refqueue *q)
|
||||
{
|
||||
if (!mp_refqueue_has_output(q))
|
||||
return false;
|
||||
|
||||
return !!(q->queue[q->pos]->fields & MP_IMGFIELD_TOP_FIRST) ^ q->second_field;
|
||||
|
||||
bool tff = q->field_parity == MP_FIELD_PARITY_TFF;
|
||||
bool bff = q->field_parity == MP_FIELD_PARITY_BFF;
|
||||
bool ret = (!!(q->queue[q->pos]->fields & MP_IMGFIELD_TOP_FIRST) ^ q->second_field
|
||||
&& !tff && !bff); // Default parity
|
||||
ret = ret || (tff && !q->second_field); // Check if top field is forced
|
||||
ret = ret || (bff && q->second_field); // Check if bottom field is forced
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Whether top-field-first mode is enabled.
|
||||
@ -123,7 +135,9 @@ bool mp_refqueue_top_field_first(struct mp_refqueue *q)
|
||||
if (!mp_refqueue_has_output(q))
|
||||
return false;
|
||||
|
||||
return q->queue[q->pos]->fields & MP_IMGFIELD_TOP_FIRST;
|
||||
bool tff = q->field_parity == MP_FIELD_PARITY_TFF;
|
||||
bool bff = q->field_parity == MP_FIELD_PARITY_BFF;
|
||||
return ((q->queue[q->pos]->fields & MP_IMGFIELD_TOP_FIRST) || tff) && !bff;
|
||||
}
|
||||
|
||||
// Discard all state.
|
||||
|
@ -34,6 +34,7 @@ enum {
|
||||
#define MP_FIELD_PARITY_BFF 1
|
||||
|
||||
void mp_refqueue_set_mode(struct mp_refqueue *q, int flags);
|
||||
void mp_refqueue_set_parity(struct mp_refqueue *q, int parity);
|
||||
bool mp_refqueue_should_deint(struct mp_refqueue *q);
|
||||
bool mp_refqueue_is_top_field(struct mp_refqueue *q);
|
||||
bool mp_refqueue_top_field_first(struct mp_refqueue *q);
|
||||
|
@ -46,6 +46,7 @@ struct opts {
|
||||
bool deint_enabled;
|
||||
bool interlaced_only;
|
||||
int mode;
|
||||
int field_parity;
|
||||
};
|
||||
|
||||
struct priv {
|
||||
@ -469,6 +470,7 @@ static struct mp_filter *vf_d3d11vpp_create(struct mp_filter *parent,
|
||||
(p->opts->deint_enabled ? MP_MODE_DEINT : 0) |
|
||||
MP_MODE_OUTPUT_FIELDS |
|
||||
(p->opts->interlaced_only ? MP_MODE_INTERLACED_ONLY : 0));
|
||||
mp_refqueue_set_parity(p->queue, p->opts->field_parity);
|
||||
|
||||
return f;
|
||||
|
||||
@ -488,6 +490,10 @@ static const m_option_t vf_opts_fields[] = {
|
||||
{"mocomp", D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_MOTION_COMPENSATION},
|
||||
{"ivctc", D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_INVERSE_TELECINE},
|
||||
{"none", 0})},
|
||||
{"parity", OPT_CHOICE(field_parity,
|
||||
{"tff", MP_FIELD_PARITY_TFF},
|
||||
{"bff", MP_FIELD_PARITY_BFF},
|
||||
{"auto", MP_FIELD_PARITY_AUTO})},
|
||||
{0}
|
||||
};
|
||||
|
||||
@ -499,6 +505,7 @@ const struct mp_user_filter_entry vf_d3d11vpp = {
|
||||
.priv_defaults = &(const OPT_BASE_STRUCT) {
|
||||
.deint_enabled = true,
|
||||
.mode = D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BOB,
|
||||
.field_parity = MP_FIELD_PARITY_AUTO,
|
||||
},
|
||||
.options = vf_opts_fields,
|
||||
},
|
||||
|
@ -51,6 +51,7 @@ struct pipeline {
|
||||
|
||||
struct opts {
|
||||
int deint_type;
|
||||
int field_parity;
|
||||
bool interlaced_only;
|
||||
bool reversal_bug;
|
||||
};
|
||||
@ -143,11 +144,13 @@ static void update_pipeline(struct mp_filter *vf)
|
||||
(p->do_deint ? MP_MODE_DEINT : 0) |
|
||||
(p->opts->deint_type >= 2 ? MP_MODE_OUTPUT_FIELDS : 0) |
|
||||
(p->opts->interlaced_only ? MP_MODE_INTERLACED_ONLY : 0));
|
||||
mp_refqueue_set_parity(p->queue, p->opts->field_parity);
|
||||
return;
|
||||
|
||||
nodeint:
|
||||
mp_refqueue_set_refs(p->queue, 0, 0);
|
||||
mp_refqueue_set_mode(p->queue, 0);
|
||||
mp_refqueue_set_parity(p->queue, p->opts->field_parity);
|
||||
}
|
||||
|
||||
static struct mp_image *alloc_out(struct mp_filter *vf)
|
||||
@ -485,6 +488,10 @@ static const m_option_t vf_opts_fields[] = {
|
||||
{"motion-compensated", 5})},
|
||||
{"interlaced-only", OPT_BOOL(interlaced_only)},
|
||||
{"reversal-bug", OPT_BOOL(reversal_bug)},
|
||||
{"parity", OPT_CHOICE(field_parity,
|
||||
{"tff", MP_FIELD_PARITY_TFF},
|
||||
{"bff", MP_FIELD_PARITY_BFF},
|
||||
{"auto", MP_FIELD_PARITY_AUTO})},
|
||||
{0}
|
||||
};
|
||||
|
||||
@ -496,6 +503,7 @@ const struct mp_user_filter_entry vf_vavpp = {
|
||||
.priv_defaults = &(const OPT_BASE_STRUCT){
|
||||
.deint_type = -1,
|
||||
.reversal_bug = true,
|
||||
.field_parity = MP_FIELD_PARITY_AUTO,
|
||||
},
|
||||
.options = vf_opts_fields,
|
||||
},
|
||||
|
@ -43,6 +43,7 @@
|
||||
struct opts {
|
||||
bool deint_enabled;
|
||||
bool interlaced_only;
|
||||
int field_parity;
|
||||
struct mp_vdpau_mixer_opts opts;
|
||||
};
|
||||
|
||||
@ -156,6 +157,8 @@ static struct mp_filter *vf_vdpaupp_create(struct mp_filter *parent, void *optio
|
||||
(p->opts->interlaced_only ? MP_MODE_INTERLACED_ONLY : 0) |
|
||||
(p->opts->opts.deint >= 2 ? MP_MODE_OUTPUT_FIELDS : 0));
|
||||
|
||||
mp_refqueue_set_parity(p->queue, p->opts->field_parity);
|
||||
|
||||
mp_refqueue_add_in_format(p->queue, IMGFMT_VDPAU, 0);
|
||||
|
||||
return f;
|
||||
@ -180,6 +183,10 @@ static const m_option_t vf_opts_fields[] = {
|
||||
{"sharpen", OPT_FLOAT(opts.sharpen), M_RANGE(-1, 1)},
|
||||
{"hqscaling", OPT_INT(opts.hqscaling), M_RANGE(0, 9)},
|
||||
{"interlaced-only", OPT_BOOL(interlaced_only)},
|
||||
{"parity", OPT_CHOICE(field_parity,
|
||||
{"tff", MP_FIELD_PARITY_TFF},
|
||||
{"bff", MP_FIELD_PARITY_BFF},
|
||||
{"auto", MP_FIELD_PARITY_AUTO})},
|
||||
{0}
|
||||
};
|
||||
|
||||
@ -188,6 +195,9 @@ const struct mp_user_filter_entry vf_vdpaupp = {
|
||||
.description = "vdpau postprocessing",
|
||||
.name = "vdpaupp",
|
||||
.priv_size = sizeof(OPT_BASE_STRUCT),
|
||||
.priv_defaults = &(const OPT_BASE_STRUCT){
|
||||
.field_parity = MP_FIELD_PARITY_AUTO,
|
||||
},
|
||||
.options = vf_opts_fields,
|
||||
},
|
||||
.create = vf_vdpaupp_create,
|
||||
|
Loading…
Reference in New Issue
Block a user