avfilter/libplacebo: add option for outputting separate fields

cf. the other deinterlacing-aware filters.
This commit is contained in:
Niklas Haas
2025-02-16 16:56:18 +01:00
parent 83c1b34964
commit 27814dc3b6
2 changed files with 25 additions and 3 deletions

View File

@ -16632,6 +16632,11 @@ Yet another deinterlacing filter. See the @ref{yadif} filter for more details.
@item skip_spatial_check
Skip the spatial deinterlacing check when using @code{yadif} deinterlacing.
@item send_fields
Output a frame for each field, rather than for each frame. Note that this will
always double the tagged output frame rate, even if the input does not contain
any interlaced frames. Disabled by default.
@end table
@subsubsection Debanding

View File

@ -215,6 +215,7 @@ typedef struct LibplaceboContext {
/* pl_deinterlace_params */
int deinterlace;
int skip_spatial_check;
int send_fields;
/* pl_deband_params */
int deband;
@ -967,8 +968,7 @@ static int handle_input(AVFilterContext *ctx, LibplaceboInput *input)
int64_t pts;
while ((ret = ff_inlink_consume_frame(inlink, &in)) > 0) {
in->opaque = s;
pl_queue_push(input->queue, &(struct pl_source_frame) {
struct pl_source_frame src = {
.pts = in->pts * av_q2d(inlink->time_base),
.duration = in->duration * av_q2d(inlink->time_base),
.first_field = s->deinterlace ? pl_field_from_avframe(in) : PL_FIELD_NONE,
@ -976,12 +976,21 @@ static int handle_input(AVFilterContext *ctx, LibplaceboInput *input)
.map = map_frame,
.unmap = unmap_frame,
.discard = discard_frame,
});
};
in->opaque = s;
pl_queue_push(input->queue, &src);
if (!s->fps.num) {
/* Internally queue an output frame for the same PTS */
pts = av_rescale_q(in->pts, inlink->time_base, outlink->time_base);
av_fifo_write(input->out_pts, &pts, 1);
if (s->send_fields && src.first_field != PL_FIELD_NONE) {
/* Queue the second field for interlaced content */
pts += av_rescale_q(in->duration, inlink->time_base, outlink->time_base) / 2;
av_fifo_write(input->out_pts, &pts, 1);
}
}
}
@ -1239,6 +1248,13 @@ static int libplacebo_config_output(AVFilterLink *outlink)
avctx->inputs[i]->time_base,
AV_TIME_BASE / 2, AV_TIME_BASE_Q);
}
if (s->deinterlace && s->send_fields) {
const AVRational q2 = { 2, 1 };
ol->frame_rate = av_mul_q(ol->frame_rate, q2);
/* Ensure output frame timestamps are divisible by two */
outlink->time_base = av_div_q(outlink->time_base, q2);
}
}
/* Static variables */
@ -1373,6 +1389,7 @@ static const AVOption libplacebo_options[] = {
{ "bob", "Naive bob deinterlacing", 0, AV_OPT_TYPE_CONST, {.i64 = PL_DEINTERLACE_BOB}, 0, 0, STATIC, .unit = "deinterlace" },
{ "yadif", "Yet another deinterlacing filter", 0, AV_OPT_TYPE_CONST, {.i64 = PL_DEINTERLACE_YADIF}, 0, 0, STATIC, .unit = "deinterlace" },
{ "skip_spatial_check", "Skip yadif spatial check", OFFSET(skip_spatial_check), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC },
{ "send_fields", "Output a frame for each field", OFFSET(send_fields), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC },
{ "deband", "Enable debanding", OFFSET(deband), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC },
{ "deband_iterations", "Deband iterations", OFFSET(deband_iterations), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 16, DYNAMIC },