avfilter/vf_alphamerge: use framesync

This commit is contained in:
Paul B Mahol 2020-08-30 23:07:17 +02:00
parent abc884bcc0
commit 88db1745fc
3 changed files with 65 additions and 81 deletions

View File

@ -6470,12 +6470,6 @@ and a separate video created with @var{alphaextract}, you might use:
movie=in_alpha.mkv [alpha]; [in][alpha] alphamerge [out]
@end example
Since this filter is designed for reconstruction, it operates on frame
sequences without considering timestamps, and terminates when either
input reaches end of stream. This will cause problems if your encoding
pipeline drops frames. If you're trying to apply an image as an
overlay to a video stream, consider the @var{overlay} filter instead.
@section amplify
Amplify differences between current pixel and pixels of adjacent frames in

View File

@ -158,7 +158,7 @@ OBJS-$(CONFIG_ANULLSINK_FILTER) += asink_anullsink.o
# video filters
OBJS-$(CONFIG_ADDROI_FILTER) += vf_addroi.o
OBJS-$(CONFIG_ALPHAEXTRACT_FILTER) += vf_extractplanes.o
OBJS-$(CONFIG_ALPHAMERGE_FILTER) += vf_alphamerge.o
OBJS-$(CONFIG_ALPHAMERGE_FILTER) += vf_alphamerge.o framesync.o
OBJS-$(CONFIG_AMPLIFY_FILTER) += vf_amplify.o
OBJS-$(CONFIG_ASS_FILTER) += vf_subtitles.o
OBJS-$(CONFIG_ATADENOISE_FILTER) += vf_atadenoise.o

View File

@ -32,6 +32,7 @@
#include "drawutils.h"
#include "formats.h"
#include "filters.h"
#include "framesync.h"
#include "internal.h"
#include "video.h"
@ -42,10 +43,54 @@ typedef struct AlphaMergeContext {
int is_packed_rgb;
uint8_t rgba_map[4];
AVFrame *main_frame;
AVFrame *alpha_frame;
FFFrameSync fs;
} AlphaMergeContext;
static int do_alphamerge(FFFrameSync *fs)
{
AVFilterContext *ctx = fs->parent;
AlphaMergeContext *s = ctx->priv;
AVFrame *main_buf, *alpha_buf;
int ret;
ret = ff_framesync_dualinput_get_writable(fs, &main_buf, &alpha_buf);
if (ret < 0)
return ret;
if (!alpha_buf)
return ff_filter_frame(ctx->outputs[0], main_buf);
if (s->is_packed_rgb) {
int x, y;
uint8_t *pin, *pout;
for (y = 0; y < main_buf->height; y++) {
pin = alpha_buf->data[0] + y * alpha_buf->linesize[0];
pout = main_buf->data[0] + y * main_buf->linesize[0] + s->rgba_map[A];
for (x = 0; x < main_buf->width; x++) {
*pout = *pin;
pin += 1;
pout += 4;
}
}
} else {
const int main_linesize = main_buf->linesize[A];
const int alpha_linesize = alpha_buf->linesize[Y];
av_image_copy_plane(main_buf->data[A], main_linesize,
alpha_buf->data[Y], alpha_linesize,
FFMIN(main_linesize, alpha_linesize), alpha_buf->height);
}
return ff_filter_frame(ctx->outputs[0], main_buf);
}
static av_cold int init(AVFilterContext *ctx)
{
AlphaMergeContext *s = ctx->priv;
s->fs.on_event = do_alphamerge;
return 0;
}
static int query_formats(AVFilterContext *ctx)
{
static const enum AVPixelFormat main_fmts[] = {
@ -78,8 +123,11 @@ static int config_input_main(AVFilterLink *inlink)
static int config_output(AVFilterLink *outlink)
{
AVFilterContext *ctx = outlink->src;
AlphaMergeContext *s = ctx->priv;
AVFilterLink *mainlink = ctx->inputs[0];
AVFilterLink *alphalink = ctx->inputs[1];
int ret;
if (mainlink->w != alphalink->w || mainlink->h != alphalink->h) {
av_log(ctx, AV_LOG_ERROR,
"Input frame sizes do not match (%dx%d vs %dx%d).\n",
@ -88,89 +136,29 @@ static int config_output(AVFilterLink *outlink)
return AVERROR(EINVAL);
}
if ((ret = ff_framesync_init_dualinput(&s->fs, ctx)) < 0)
return ret;
outlink->w = mainlink->w;
outlink->h = mainlink->h;
outlink->time_base = mainlink->time_base;
outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
outlink->frame_rate = mainlink->frame_rate;
return 0;
}
static void draw_frame(AVFilterContext *ctx,
AVFrame *main_buf,
AVFrame *alpha_buf)
{
AlphaMergeContext *s = ctx->priv;
int h = main_buf->height;
if (s->is_packed_rgb) {
int x, y;
uint8_t *pin, *pout;
for (y = 0; y < h; y++) {
pin = alpha_buf->data[0] + y * alpha_buf->linesize[0];
pout = main_buf->data[0] + y * main_buf->linesize[0] + s->rgba_map[A];
for (x = 0; x < main_buf->width; x++) {
*pout = *pin;
pin += 1;
pout += 4;
}
}
} else {
const int main_linesize = main_buf->linesize[A];
const int alpha_linesize = alpha_buf->linesize[Y];
av_image_copy_plane(main_buf->data[A], main_linesize,
alpha_buf->data[Y], alpha_linesize,
FFMIN(main_linesize, alpha_linesize), alpha_buf->height);
}
return ff_framesync_configure(&s->fs);
}
static int activate(AVFilterContext *ctx)
{
AVFilterLink *outlink = ctx->outputs[0];
AlphaMergeContext *s = ctx->priv;
int ret;
return ff_framesync_activate(&s->fs);
}
FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx);
static av_cold void uninit(AVFilterContext *ctx)
{
AlphaMergeContext *s = ctx->priv;
if (!s->main_frame) {
ret = ff_inlink_consume_frame(ctx->inputs[0], &s->main_frame);
if (ret < 0)
return ret;
}
if (!s->alpha_frame) {
ret = ff_inlink_consume_frame(ctx->inputs[1], &s->alpha_frame);
if (ret < 0)
return ret;
}
if (s->main_frame && s->alpha_frame) {
if (!ctx->is_disabled)
draw_frame(ctx, s->main_frame, s->alpha_frame);
ret = ff_filter_frame(outlink, s->main_frame);
av_frame_free(&s->alpha_frame);
s->main_frame = NULL;
return ret;
}
FF_FILTER_FORWARD_STATUS(ctx->inputs[0], outlink);
FF_FILTER_FORWARD_STATUS(ctx->inputs[1], outlink);
if (ff_outlink_frame_wanted(ctx->outputs[0]) &&
!ff_outlink_get_status(ctx->inputs[0]) &&
!s->main_frame) {
ff_inlink_request_frame(ctx->inputs[0]);
return 0;
}
if (ff_outlink_frame_wanted(ctx->outputs[0]) &&
!ff_outlink_get_status(ctx->inputs[1]) &&
!s->alpha_frame) {
ff_inlink_request_frame(ctx->inputs[1]);
return 0;
}
return FFERROR_NOT_READY;
ff_framesync_uninit(&s->fs);
}
static const AVFilterPad alphamerge_inputs[] = {
@ -178,7 +166,6 @@ static const AVFilterPad alphamerge_inputs[] = {
.name = "main",
.type = AVMEDIA_TYPE_VIDEO,
.config_props = config_input_main,
.needs_writable = 1,
},{
.name = "alpha",
.type = AVMEDIA_TYPE_VIDEO,
@ -199,17 +186,20 @@ static const AVOption alphamerge_options[] = {
{ NULL }
};
AVFILTER_DEFINE_CLASS(alphamerge);
FRAMESYNC_DEFINE_CLASS(alphamerge, AlphaMergeContext, fs);
AVFilter ff_vf_alphamerge = {
.name = "alphamerge",
.description = NULL_IF_CONFIG_SMALL("Copy the luma value of the second "
"input into the alpha channel of the first input."),
.preinit = alphamerge_framesync_preinit,
.priv_size = sizeof(AlphaMergeContext),
.priv_class = &alphamerge_class,
.init = init,
.query_formats = query_formats,
.inputs = alphamerge_inputs,
.outputs = alphamerge_outputs,
.uninit = uninit,
.activate = activate,
.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
};