Skip to content

Commit ed5a365

Browse files
committed
vo_gpu_next: use shader deinterlacer instead of software bwdif
1 parent 5e7f9b0 commit ed5a365

4 files changed

Lines changed: 75 additions & 5 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
add `--deinterlace-algorithm` option

DOCS/man/options.rst

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1808,9 +1808,11 @@ Video
18081808
``--deinterlace=<yes|no|auto>``
18091809
Enable or disable deinterlacing (default: no).
18101810
Interlaced video shows ugly comb-like artifacts, which are visible on
1811-
fast movement. Enabling this typically inserts the bwdif video filter in
1812-
order to deinterlace the video, or lets the video output apply deinterlacing
1813-
if supported.
1811+
fast movement. Enabling this inserts the hardware deinterlacing filter if
1812+
``--hwdec`` is used, otherwise the video output applies deinterlacing. If
1813+
neither is possible, a software bwdif filter is used instead. The
1814+
``--deinterlace-algorithm`` option can be used to select the deinterlacing
1815+
algorithm used by the video output (``gpu-next`` only).
18141816

18151817
When using ``auto``, mpv will insert a deinterlacing filter if ffmpeg
18161818
detects that the video frame is interlaced. Be aware that there can be false
@@ -6248,6 +6250,12 @@ them.
62486250
Among these kernels, ``burkes`` achieves a good balance between performance
62496251
and quality, and probably is the one you want to try first.
62506252

6253+
``--deinterlace-algorithm=<weave|bob|yadif|bwdif>``
6254+
Sets the deinterlacing algorithm to use when the VO is doing deinterlacing.
6255+
Currently only ``gpu-next`` supports this.
6256+
6257+
Default: ``bwdif``.
6258+
62516259
``--gpu-debug``
62526260
Enables GPU debugging. What this means depends on the API type. For OpenGL,
62536261
it calls ``glGetError()``, and requests a debug context. For Vulkan, it

filters/f_auto_filters.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ static void deint_process(struct mp_filter *f)
9595
field_parity = "auto";
9696
}
9797

98+
struct mp_stream_info *info = mp_filter_find_stream_info(f);
9899
bool has_filter = true;
99100
if (img->imgfmt == IMGFMT_VDPAU) {
100101
char *args[] = {"deint", "yes",
@@ -126,6 +127,11 @@ static void deint_process(struct mp_filter *f)
126127
"parity", field_parity, NULL};
127128
p->sub.filter =
128129
mp_create_user_filter(f, MP_OUTPUT_CHAIN_VIDEO, "vavpp", args);
130+
} else if (info && info->deinterlace && !IMGFMT_IS_HWACCEL(img->imgfmt)) {
131+
char *args[] = {"interlaced-only", opts->deinterlace == 1 ? "no" : "yes",
132+
"parity", field_parity, NULL};
133+
p->sub.filter = mp_create_user_filter(f, MP_OUTPUT_CHAIN_VIDEO,
134+
"fieldrate", args);
129135
} else {
130136
has_filter = false;
131137
}

video/out/vo_gpu_next.c

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ struct priv {
149149
pl_options pars;
150150
struct m_config_cache *opts_cache;
151151
struct m_config_cache *next_opts_cache;
152+
struct m_config_cache *filter_opts_cache;
152153
struct gl_next_opts *next_opts;
153154
struct cache shader_cache, icc_cache;
154155
struct mp_csp_equalizer_state *video_eq;
@@ -182,6 +183,7 @@ struct gl_next_opts {
182183
float background_blur_radius;
183184
float corner_rounding;
184185
bool inter_preserve;
186+
int deint_algo;
185187
struct user_lut lut;
186188
struct user_lut image_lut;
187189
struct user_lut target_lut;
@@ -215,6 +217,11 @@ const struct m_sub_options gl_next_conf = {
215217
{"background-blur-radius", OPT_FLOAT(background_blur_radius)},
216218
{"corner-rounding", OPT_FLOAT(corner_rounding), M_RANGE(0, 1)},
217219
{"interpolation-preserve", OPT_BOOL(inter_preserve)},
220+
{"deinterlace-algorithm", OPT_CHOICE(deint_algo,
221+
{"weave", PL_DEINTERLACE_WEAVE},
222+
{"bob", PL_DEINTERLACE_BOB},
223+
{"yadif", PL_DEINTERLACE_YADIF},
224+
{"bwdif", PL_DEINTERLACE_BWDIF})},
218225
{"lut", OPT_STRING(lut.opt), .flags = M_OPT_FILE},
219226
{"lut-type", OPT_CHOICE_C(lut.type, lut_types)},
220227
{"image-lut", OPT_STRING(image_lut.opt), .flags = M_OPT_FILE},
@@ -230,6 +237,7 @@ const struct m_sub_options gl_next_conf = {
230237
.defaults = &(struct gl_next_opts) {
231238
.border_background = BACKGROUND_COLOR,
232239
.background_blur_radius = 16.0f,
240+
.deint_algo = PL_DEINTERLACE_BWDIF,
233241
.inter_preserve = true,
234242
.image_subs_hdr_peak = 1000,
235243
.target_hint = -1,
@@ -1036,6 +1044,7 @@ static void update_options(struct vo *vo)
10361044
pl_options pars = p->pars;
10371045
bool changed = m_config_cache_update(p->opts_cache);
10381046
changed = m_config_cache_update(p->next_opts_cache) || changed;
1047+
changed = m_config_cache_update(p->filter_opts_cache) || changed;
10391048
if (changed)
10401049
update_render_options(vo);
10411050

@@ -1290,13 +1299,50 @@ static bool draw_frame(struct vo *vo, struct vo_frame *frame)
12901299
mpi->priv = fp;
12911300
fp->vo = vo;
12921301

1302+
bool is_deinterlacing = params.deinterlace_params &&
1303+
mpi->fields & MP_IMGFIELD_INTERLACED;
1304+
1305+
// vf_fieldrate emits a frame for each field only to make mpv render
1306+
// at the second field PTS. But don't actually push it to pl_queue,
1307+
// because it already derives it internally from first_field.
1308+
bool second_tick = is_deinterlacing && (mpi->fields & MP_IMGFIELD_TICK_SECOND);
1309+
if (second_tick && p->last_id) {
1310+
talloc_free(mpi);
1311+
p->last_id = id;
1312+
continue;
1313+
}
1314+
int first_field = !is_deinterlacing ? PL_FIELD_NONE :
1315+
(mpi->fields & MP_IMGFIELD_TOP_FIRST) ? PL_FIELD_TOP : PL_FIELD_BOTTOM;
1316+
1317+
if (!p->last_id && !second_tick && mpi->deint_prev) {
1318+
struct mp_image *prev = mp_image_new_ref(mpi->deint_prev);
1319+
mp_image_unrefp(&prev->deint_prev);
1320+
struct frame_priv *prev_fp = talloc_zero(prev, struct frame_priv);
1321+
prev->priv = prev_fp;
1322+
prev_fp->vo = vo;
1323+
mp_assert(prev->fields & MP_IMGFIELD_TICK_SECOND);
1324+
pl_queue_push(p->queue, &(struct pl_source_frame) {
1325+
.pts = prev->pts - prev->pkt_duration / 2,
1326+
.duration = prev->pkt_duration,
1327+
.frame_data = prev,
1328+
.map = map_frame,
1329+
.unmap = unmap_frame,
1330+
.discard = discard_frame,
1331+
.first_field = (prev->fields & MP_IMGFIELD_TOP_FIRST) ?
1332+
PL_FIELD_TOP : PL_FIELD_BOTTOM,
1333+
});
1334+
}
1335+
mp_image_unrefp(&mpi->deint_prev);
1336+
12931337
pl_queue_push(p->queue, &(struct pl_source_frame) {
1294-
.pts = mpi->pts,
1295-
.duration = can_interpolate ? frame->approx_duration : 0,
1338+
.pts = second_tick ? mpi->pts - mpi->pkt_duration / 2 : mpi->pts,
1339+
.duration = can_interpolate ? frame->approx_duration :
1340+
is_deinterlacing ? mpi->pkt_duration : 0,
12961341
.frame_data = mpi,
12971342
.map = map_frame,
12981343
.unmap = unmap_frame,
12991344
.discard = discard_frame,
1345+
.first_field = first_field,
13001346
});
13011347

13021348
p->last_id = id;
@@ -2388,6 +2434,7 @@ static int preinit(struct vo *vo)
23882434
{
23892435
struct priv *p = vo->priv;
23902436
p->opts_cache = m_config_cache_alloc(p, vo->global, &gl_video_conf);
2437+
p->filter_opts_cache = m_config_cache_alloc(p, vo->global, &filter_conf);
23912438
p->next_opts_cache = m_config_cache_alloc(p, vo->global, &gl_next_conf);
23922439
p->next_opts = p->next_opts_cache->opts;
23932440
p->video_eq = mp_csp_equalizer_create(p, vo->global);
@@ -2715,6 +2762,7 @@ static void update_render_options(struct vo *vo)
27152762
struct priv *p = vo->priv;
27162763
pl_options pars = p->pars;
27172764
const struct gl_video_opts *opts = p->opts_cache->opts;
2765+
const struct filter_opts *fopts = p->filter_opts_cache->opts;
27182766
pars->params.background_color[0] = opts->background_color.r / 255.0;
27192767
pars->params.background_color[1] = opts->background_color.g / 255.0;
27202768
pars->params.background_color[2] = opts->background_color.b / 255.0;
@@ -2748,6 +2796,9 @@ static void update_render_options(struct vo *vo)
27482796
pars->params.plane_upscaler = map_scaler(p, SCALER_CSCALE);
27492797
pars->params.frame_mixer = opts->interpolation ? map_scaler(p, SCALER_TSCALE) : NULL;
27502798

2799+
pars->params.deinterlace_params = fopts->deinterlace != 0 ? &pars->deinterlace_params : NULL;
2800+
pars->deinterlace_params.algo = p->next_opts->deint_algo;
2801+
27512802
// Request as many frames as required from the decoder, depending on the
27522803
// speed VPS/FPS ratio libplacebo may need more frames. Request frames up to
27532804
// ratio of 1/2, but only if anti aliasing is enabled.
@@ -2756,6 +2807,9 @@ static void update_render_options(struct vo *vo)
27562807
req_frames += ceilf(pars->params.frame_mixer->kernel->radius) *
27572808
(pars->params.skip_anti_aliasing ? 1 : 2);
27582809
}
2810+
2811+
if (pars->params.deinterlace_params)
2812+
req_frames++;
27592813
vo_set_queue_params(vo, 0, MPMIN(VO_MAX_REQ_FRAMES, req_frames));
27602814

27612815
pars->params.deband_params = opts->deband ? &pars->deband_params : NULL;
@@ -2865,6 +2919,7 @@ const struct vo_driver video_out_gpu_next = {
28652919
.caps = VO_CAP_ROTATE90 |
28662920
VO_CAP_FILM_GRAIN |
28672921
VO_CAP_VFLIP |
2922+
VO_CAP_DEINTERLACE |
28682923
0x0,
28692924
.preinit = preinit,
28702925
.query_format = query_format,

0 commit comments

Comments
 (0)