avfilter/vf_alphamerge: use framesync

pull/350/head
Paul B Mahol 4 years ago
parent abc884bcc0
commit 88db1745fc
  1. 6
      doc/filters.texi
  2. 2
      libavfilter/Makefile
  3. 136
      libavfilter/vf_alphamerge.c

@ -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

@ -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

@ -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;
return ff_framesync_configure(&s->fs);
}
static void draw_frame(AVFilterContext *ctx,
AVFrame *main_buf,
AVFrame *alpha_buf)
static int activate(AVFilterContext *ctx)
{
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_activate(&s->fs);
}
static int activate(AVFilterContext *ctx)
static av_cold void uninit(AVFilterContext *ctx)
{
AVFilterLink *outlink = ctx->outputs[0];
AlphaMergeContext *s = ctx->priv;
int ret;
FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx);
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,
};

Loading…
Cancel
Save