mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-28 20:53:54 +02:00
lavfi/vf_libplacebo: allow fps conversion
This exposes libplacebo's frame mixing functionality to vf_libplacebo, by allowing users to specify a desired target fps to output at. Incoming frames will be smoothly resampled (in a manner determined by the `frame_mixer` option, to be added in the next commit). To generate a consistently timed output stream, we directly use the desired framerate as the timebase, and simply output frames in sequential order (tracked by the number of frames output so far).
This commit is contained in:
parent
83b1f3f54e
commit
02f3b9312a
@ -16044,6 +16044,13 @@ and @code{(oh-ph)/2}.
|
||||
Set the output placement width/height expressions, default values are @code{ow}
|
||||
and @code{oh}.
|
||||
|
||||
@item fps
|
||||
Set the output frame rate. This can be rational, e.g. @code{60000/1001}. If
|
||||
set to the special string @code{none} (the default), input timestamps will
|
||||
instead be passed through to the output unmodified. Otherwise, the input video
|
||||
frames will be interpolated as necessary to rescale the video to the specified
|
||||
target framerate, in a manner as determined by the @option{frame_mixer} option.
|
||||
|
||||
@item format
|
||||
Set the output format override. If unset (the default), frames will be output
|
||||
in the same format as the respective input frames. Otherwise, format conversion
|
||||
|
@ -139,6 +139,8 @@ typedef struct LibplaceboContext {
|
||||
double var_values[VAR_VARS_NB];
|
||||
char *w_expr;
|
||||
char *h_expr;
|
||||
char *fps_string;
|
||||
AVRational fps; ///< parsed FPS, or 0/0 for "none"
|
||||
char *crop_x_expr, *crop_y_expr;
|
||||
char *crop_w_expr, *crop_h_expr;
|
||||
char *pos_x_expr, *pos_y_expr;
|
||||
@ -166,6 +168,7 @@ typedef struct LibplaceboContext {
|
||||
float antiringing;
|
||||
int sigmoid;
|
||||
int skip_aa;
|
||||
int skip_cache;
|
||||
float polar_cutoff;
|
||||
int disable_linear;
|
||||
int disable_builtin;
|
||||
@ -400,7 +403,7 @@ static int update_settings(AVFilterContext *ctx)
|
||||
.num_hooks = s->num_hooks,
|
||||
|
||||
.skip_anti_aliasing = s->skip_aa,
|
||||
.skip_caching_single_frame = true,
|
||||
.skip_caching_single_frame = s->skip_cache,
|
||||
.polar_cutoff = s->polar_cutoff,
|
||||
.disable_linear_scaling = s->disable_linear,
|
||||
.disable_builtin_scalers = s->disable_builtin,
|
||||
@ -465,6 +468,8 @@ static int libplacebo_init(AVFilterContext *avctx)
|
||||
|
||||
/* Initialize dynamic filter state */
|
||||
s->out_pts = av_fifo_alloc2(1, sizeof(int64_t), AV_FIFO_FLAG_AUTO_GROW);
|
||||
if (strcmp(s->fps_string, "none") != 0)
|
||||
RET(av_parse_video_rate(&s->fps, s->fps_string));
|
||||
|
||||
/* Note: s->vulkan etc. are initialized later, when hwctx is available */
|
||||
return 0;
|
||||
@ -663,6 +668,8 @@ static int output_frame_mix(AVFilterContext *ctx,
|
||||
out->pts = pts;
|
||||
out->width = outlink->w;
|
||||
out->height = outlink->h;
|
||||
if (s->fps.num)
|
||||
out->duration = 1;
|
||||
|
||||
if (s->apply_dovi && av_frame_get_side_data(ref, AV_FRAME_DATA_DOVI_METADATA)) {
|
||||
/* Output of dovi reshaping is always BT.2020+PQ, so infer the correct
|
||||
@ -784,9 +791,11 @@ static int libplacebo_activate(AVFilterContext *ctx)
|
||||
.discard = discard_frame,
|
||||
});
|
||||
|
||||
/* Internally queue an output frame for the same PTS */
|
||||
av_assert1(!av_cmp_q(link->time_base, outlink->time_base));
|
||||
av_fifo_write(s->out_pts, &in->pts, 1);
|
||||
if (!s->fps.num) {
|
||||
/* Internally queue an output frame for the same PTS */
|
||||
av_assert1(!av_cmp_q(link->time_base, outlink->time_base));
|
||||
av_fifo_write(s->out_pts, &in->pts, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
@ -799,7 +808,8 @@ static int libplacebo_activate(AVFilterContext *ctx)
|
||||
/* Signal EOF to pl_queue, and enqueue this output frame to
|
||||
* make sure we see PL_QUEUE_EOF returned eventually */
|
||||
pl_queue_push(s->queue, NULL);
|
||||
av_fifo_write(s->out_pts, &pts, 1);
|
||||
if (!s->fps.num)
|
||||
av_fifo_write(s->out_pts, &pts, 1);
|
||||
} else {
|
||||
ff_outlink_set_status(outlink, status, pts);
|
||||
return 0;
|
||||
@ -810,7 +820,9 @@ static int libplacebo_activate(AVFilterContext *ctx)
|
||||
struct pl_frame_mix mix;
|
||||
enum pl_queue_status ret;
|
||||
|
||||
if (av_fifo_peek(s->out_pts, &pts, 1, 0) < 0) {
|
||||
if (s->fps.num) {
|
||||
pts = outlink->frame_count_out;
|
||||
} else if (av_fifo_peek(s->out_pts, &pts, 1, 0) < 0) {
|
||||
ff_inlink_request_frame(inlink);
|
||||
return 0;
|
||||
}
|
||||
@ -826,7 +838,8 @@ static int libplacebo_activate(AVFilterContext *ctx)
|
||||
ff_inlink_request_frame(inlink);
|
||||
return 0;
|
||||
case PL_QUEUE_OK:
|
||||
av_fifo_drain2(s->out_pts, 1);
|
||||
if (!s->fps.num)
|
||||
av_fifo_drain2(s->out_pts, 1);
|
||||
return output_frame_mix(ctx, &mix, pts);
|
||||
case PL_QUEUE_EOF:
|
||||
ff_outlink_set_status(outlink, AVERROR_EOF, pts);
|
||||
@ -942,6 +955,7 @@ static int libplacebo_config_output(AVFilterLink *outlink)
|
||||
AVVulkanFramesContext *vkfc;
|
||||
AVRational scale_sar;
|
||||
|
||||
/* Frame dimensions */
|
||||
RET(ff_scale_eval_dimensions(s, s->w_expr, s->h_expr, inlink, outlink,
|
||||
&outlink->w, &outlink->h));
|
||||
|
||||
@ -965,6 +979,15 @@ static int libplacebo_config_output(AVFilterLink *outlink)
|
||||
outlink->sample_aspect_ratio = scale_sar;
|
||||
}
|
||||
|
||||
/* Frame rate */
|
||||
if (s->fps.num) {
|
||||
outlink->frame_rate = s->fps;
|
||||
outlink->time_base = av_inv_q(s->fps);
|
||||
s->skip_cache = av_cmp_q(inlink->frame_rate, s->fps) > 0;
|
||||
} else {
|
||||
s->skip_cache = true;
|
||||
}
|
||||
|
||||
/* Static variables */
|
||||
s->var_values[VAR_IN_W] = s->var_values[VAR_IW] = inlink->w;
|
||||
s->var_values[VAR_IN_H] = s->var_values[VAR_IH] = inlink->h;
|
||||
@ -1009,6 +1032,7 @@ fail:
|
||||
static const AVOption libplacebo_options[] = {
|
||||
{ "w", "Output video frame width", OFFSET(w_expr), AV_OPT_TYPE_STRING, {.str = "iw"}, .flags = STATIC },
|
||||
{ "h", "Output video frame height", OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = "ih"}, .flags = STATIC },
|
||||
{ "fps", "Output video frame rate", OFFSET(fps_string), AV_OPT_TYPE_STRING, {.str = "none"}, .flags = STATIC },
|
||||
{ "crop_x", "Input video crop x", OFFSET(crop_x_expr), AV_OPT_TYPE_STRING, {.str = "(iw-cw)/2"}, .flags = DYNAMIC },
|
||||
{ "crop_y", "Input video crop y", OFFSET(crop_y_expr), AV_OPT_TYPE_STRING, {.str = "(ih-ch)/2"}, .flags = DYNAMIC },
|
||||
{ "crop_w", "Input video crop w", OFFSET(crop_w_expr), AV_OPT_TYPE_STRING, {.str = "iw"}, .flags = DYNAMIC },
|
||||
|
Loading…
Reference in New Issue
Block a user