Browse Source

avfilter/vf_alphamerge: use framesync

tags/n4.4
Paul B Mahol 5 years ago
parent
commit
88db1745fc
3 changed files with 64 additions and 80 deletions
  1. +0
    -6
      doc/filters.texi
  2. +1
    -1
      libavfilter/Makefile
  3. +63
    -73
      libavfilter/vf_alphamerge.c

+ 0
- 6
doc/filters.texi 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


+ 1
- 1
libavfilter/Makefile 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


+ 63
- 73
libavfilter/vf_alphamerge.c 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;

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