[FFmpeg-soc] [soc]: r5821 - libavfilter/vf_overlay.c
bcoudurier
subversion at mplayerhq.hu
Fri Jun 4 22:15:35 CEST 2010
Author: bcoudurier
Date: Fri Jun 4 22:15:35 2010
New Revision: 5821
Log:
Direct rendering in overlay filter.
RGB24 support.
Doesn't work with movie in movie yet, needs loop input feature for logos
either in movie filter or here.
Modified:
libavfilter/vf_overlay.c
Modified: libavfilter/vf_overlay.c
==============================================================================
--- libavfilter/vf_overlay.c Fri Jun 4 22:10:23 2010 (r5820)
+++ libavfilter/vf_overlay.c Fri Jun 4 22:15:35 2010 (r5821)
@@ -1,5 +1,6 @@
/*
* copyright (c) 2007 Bobby Bingham
+ * copyright (c) 2010 Baptiste Coudurier
*
* This file is part of FFmpeg.
*
@@ -44,13 +45,9 @@ enum var_name {
};
typedef struct {
- int x, y; //< position of subpicture
+ unsigned x, y; //< position of subpicture
- /** pics[0][0..1] are pictures for the main image.
- * pics[1][0..1] are pictures for the sub image.
- * pics[x][0] are previously outputted images.
- * pics[x][1] are queued, yet unused frames for each input. */
- AVFilterPicRef *pics[2][2];
+ AVFilterPicRef *overlay;
int bpp; //< bytes per pixel
int hsub, vsub; //< chroma subsampling
@@ -74,18 +71,15 @@ static av_cold int init(AVFilterContext
static av_cold void uninit(AVFilterContext *ctx)
{
OverlayContext *over = ctx->priv;
- int i, j;
- for(i = 0; i < 2; i ++)
- for(j = 0; j < 2; j ++)
- if(over->pics[i][j])
- avfilter_unref_pic(over->pics[i][j]);
+ if (over->overlay)
+ avfilter_unref_pic(over->overlay);
}
static int query_formats(AVFilterContext *ctx)
{
- //const enum PixelFormat inout_pix_fmts[] = { PIX_FMT_BGR24, PIX_FMT_NONE };
- //const enum PixelFormat blend_pix_fmts[] = { PIX_FMT_BGRA, PIX_FMT_NONE };
+ //const enum PixelFormat inout_pix_fmts[] = { PIX_FMT_BGR24, PIX_FMT_RGB24, PIX_FMT_NONE };
+ //const enum PixelFormat blend_pix_fmts[] = { PIX_FMT_BGRA, PIX_FMT_NONE };
const enum PixelFormat inout_pix_fmts[] = { PIX_FMT_YUV420P, PIX_FMT_NONE };
const enum PixelFormat blend_pix_fmts[] = { PIX_FMT_YUVA420P, PIX_FMT_NONE };
AVFilterFormats *inout_formats = avfilter_make_format_list(inout_pix_fmts);
@@ -133,7 +127,7 @@ static int config_input_overlay(AVFilter
AVFilterContext *ctx = link->dst;
OverlayContext *over = link->dst->priv;
const char *error = NULL, *expr;
- double var_values[VARS_NB];
+ double var_values[VARS_NB], ret;
/* Finish the configuration by evaluating the expressions
now when both inputs are configured. */
@@ -142,14 +136,26 @@ static int config_input_overlay(AVFilter
var_values[OVERLAY_W] = ctx->inputs[1]->w;
var_values[OVERLAY_H] = ctx->inputs[1]->h;
- over->x = ff_parse_and_eval_expr((expr = over->x_expr), var_values, var_names,
- NULL, NULL, NULL, NULL, NULL, &error);
- if (error)
+ av_log(ctx, AV_LOG_INFO, "main %dx%d overlay %dx%d\n", ctx->inputs[0]->w, ctx->inputs[0]->h,
+ ctx->inputs[1]->w, ctx->inputs[1]->h);
+
+ if (ff_parse_and_eval_expr(&ret, (expr = over->x_expr),
+ var_names, var_values,
+ NULL, NULL, NULL, NULL,
+ NULL, 0, ctx) < 0)
goto fail;
- over->y = ff_parse_and_eval_expr((expr = over->y_expr), var_values, var_names,
- NULL, NULL, NULL, NULL, NULL, &error);
- if (error)
+ over->x = ret;
+ if (ff_parse_and_eval_expr(&ret, (expr = over->y_expr),
+ var_names, var_values,
+ NULL, NULL, NULL, NULL,
+ NULL, 0, ctx) < 0)
goto fail;
+ over->y = ret;
+
+ over->x &= ~((1 << over->hsub) - 1);
+ over->y &= ~((1 << over->vsub) - 1);
+
+ av_log(ctx, AV_LOG_INFO, "overlaying at %d,%d\n", over->x, over->y);
return 0;
@@ -159,209 +165,147 @@ fail:
return -1;
}
-static void shift_input(OverlayContext *over, int idx)
+static AVFilterPicRef *get_video_buffer(AVFilterLink *link, int perms, int w, int h)
{
- assert(over->pics[idx][0]);
- assert(over->pics[idx][1]);
- avfilter_unref_pic(over->pics[idx][0]);
- over->pics[idx][0] = over->pics[idx][1];
- over->pics[idx][1] = NULL;
+ AVFilterPicRef *picref = avfilter_get_video_buffer(link->dst->outputs[0],
+ perms, w, h);
+ return picref;
}
static void start_frame(AVFilterLink *link, AVFilterPicRef *picref)
{
- OverlayContext *over = link->dst->priv;
- /* There shouldn't be any previous queued frame in this queue */
- assert(!over->pics[link->dstpad][1]);
- if (over->pics[link->dstpad][0]) {
- /* Queue the new frame */
- over->pics[link->dstpad][1] = picref;
- } else {
- /* No previous unused frame, take this one into use directly */
- over->pics[link->dstpad][0] = picref;
- }
-}
+ AVFilterPicRef *outpicref = avfilter_ref_pic(picref, ~0);
-static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
-{
-}
+ link->dst->outputs[0]->outpic = outpicref;
-static void end_frame(AVFilterLink *link)
-{
+ avfilter_start_frame(link->dst->outputs[0], outpicref);
}
-static int lower_timestamp(OverlayContext *over)
+static void start_frame_overlay(AVFilterLink *link, AVFilterPicRef *picref)
{
- if(!over->pics[0][0] &&
- !over->pics[1][0]) return 2;
- if(!over->pics[0][1]) return 0;
- if(!over->pics[1][1]) return 1;
+ AVFilterContext *ctx = link->dst;
+ OverlayContext *over = ctx->priv;
- if(over->pics[0][1]->pts == over->pics[1][1]->pts) return 2;
- return (over->pics[0][1]->pts > over->pics[1][1]->pts);
+ over->overlay = picref;
}
-static void copy_image_rgb(AVFilterPicRef *dst, int x, int y,
- AVFilterPicRef *src, int w, int h, int bpp)
+static void blend_slice(AVFilterContext *ctx,
+ AVFilterPicRef *dst, AVFilterPicRef *src,
+ int x, int y, int w, int h,
+ int slice_y, int slice_w, int slice_h)
{
- AVPicture pic;
+ OverlayContext *over = ctx->priv;
+ int i, j, k;
+ int width, height;
+ int overlay_end_y = y+h;
+ int slice_end_y = slice_y+slice_h;
+ int end_y, start_y;
- memcpy(&pic, &dst->data, sizeof(AVPicture));
- pic.data[0] += x * bpp;
- pic.data[0] += y * pic.linesize[0];
+ width = FFMIN(slice_w - x, w);
+ end_y = FFMIN(slice_end_y, overlay_end_y);
+ start_y = FFMAX(y, slice_y);
+ height = end_y - start_y;
- if (src->pic->format == PIX_FMT_BGRA) {
- for (y = 0; y < h; y++) {
- uint8_t *optr = pic.data[0] + y * pic.linesize[0];
- const uint8_t *iptr = src->data[0] + y * src->linesize[0];
- for (x = 0; x < w; x++) {
- uint8_t a = iptr[3];
- optr[0] = (optr[0] * (0xff - a) + iptr[0] * a + 128) >> 8;
- optr[1] = (optr[1] * (0xff - a) + iptr[1] * a + 128) >> 8;
- optr[2] = (optr[2] * (0xff - a) + iptr[2] * a + 128) >> 8;
- iptr += bpp+1;
- optr += bpp;
+ if (dst->pic->format == PIX_FMT_BGR24 || dst->pic->format == PIX_FMT_RGB24) {
+ uint8_t *dp = dst->data[0] + x * 3 + start_y * dst->linesize[0];
+ uint8_t *sp = src->data[0];
+ int b = dst->pic->format == PIX_FMT_BGR24 ? 2 : 0;
+ int r = dst->pic->format == PIX_FMT_BGR24 ? 0 : 2;
+ if (slice_y > y)
+ sp += (slice_y - y) * src->linesize[0];
+ for (i = 0; i < height; i++) {
+ uint8_t *d = dp, *s = sp;
+ for (j = 0; j < width; j++) {
+ d[r] = (d[r] * (0xff - s[3]) + s[0] * s[3] + 128) >> 8;
+ d[1] = (d[1] * (0xff - s[3]) + s[1] * s[3] + 128) >> 8;
+ d[b] = (d[b] * (0xff - s[3]) + s[2] * s[3] + 128) >> 8;
+ d += 3;
+ s += 4;
}
+ dp += dst->linesize[0];
+ sp += src->linesize[0];
}
} else {
- av_picture_copy(&pic, (AVPicture *)src->data, dst->pic->format, w, h);
- }
-}
-
-static void copy_blended(uint8_t* out, int out_linesize,
- const uint8_t* in, int in_linesize,
- const uint8_t* alpha, int alpha_linesize,
- int w, int h, int hsub, int vsub)
-{
- int y;
- for (y = 0; y < h; y++) {
- int x;
- uint8_t *optr = out + y * out_linesize;
- const uint8_t *iptr = in + y * in_linesize;
- const uint8_t *aptr = alpha + (y<<vsub) * alpha_linesize;
- for (x = 0; x < w; x++) {
- uint8_t a = *aptr;
- *optr = (*optr * (0xff - a) + *iptr * a + 128) >> 8;
- optr++;
- iptr++;
- aptr += 1 << hsub;
+ for (i = 0; i < 3; i++) {
+ int hsub = i ? over->hsub : 0;
+ int vsub = i ? over->vsub : 0;
+ uint8_t *dp = dst->data[i] + (x >> hsub) +
+ (start_y >> vsub) * dst->linesize[i];
+ uint8_t *sp = src->data[i];
+ uint8_t *ap = src->data[3];
+ int wp = FFALIGN(width, 1<<hsub) >> hsub;
+ int hp = FFALIGN(height, 1<<vsub) >> vsub;
+ if (slice_y > y) {
+ sp += ((slice_y - y) >> vsub) * src->linesize[i];
+ ap += (slice_y - y) * src->linesize[3];
+ }
+ for (j = 0; j < hp; j++) {
+ uint8_t *d = dp, *s = sp, *a = ap;
+ for (k = 0; k < wp; k++) {
+ // average alpha for color components, improve quality
+ int alpha_v, alpha_h, alpha;
+ if (hsub && vsub && j+1 < hp && k+1 < wp) {
+ alpha = (a[0] + a[src->linesize[3]] +
+ a[1] + a[src->linesize[3]+1]) >> 2;
+ } else if (hsub || vsub) {
+ alpha_h = hsub && k+1 < wp ?
+ (a[0] + a[1]) >> 1 : a[0];
+ alpha_v = vsub && j+1 < hp ?
+ (a[0] + a[src->linesize[3]]) >> 1 : a[0];
+ alpha = (alpha_v + alpha_h) >> 1;
+ } else
+ alpha = a[0];
+ *d = (*d * (0xff - alpha) + *s++ * alpha + 128) >> 8;
+ d++;
+ a += 1 << hsub;
+ }
+ dp += dst->linesize[i];
+ sp += src->linesize[i];
+ ap += (1 << vsub) * src->linesize[3];
+ }
}
}
}
-static void copy_image_yuv(AVFilterPicRef *dst, int x, int y,
- AVFilterPicRef *src, int w, int h,
- int bpp, int hsub, int vsub)
+static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
{
- AVPicture pic;
- int i;
+ AVFilterContext *ctx = link->dst;
+ AVFilterPicRef *pic = ctx->outputs[0]->outpic;
+ OverlayContext *over = ctx->priv;
- memcpy(&pic, &dst->data, sizeof(AVPicture));
- for(i = 0; i < 4; i ++) {
- if(pic.data[i]) {
- int x_off = x;
- int y_off = y;
- if (i == 1 || i == 2) {
- x_off >>= hsub;
- y_off >>= vsub;
- }
- pic.data[i] += x_off * bpp;
- pic.data[i] += y_off * pic.linesize[i];
+ if (!over->overlay) {// || over->overlay->pts < pic->pts) {
+ if (over->overlay) {
+ avfilter_unref_pic(over->overlay);
+ over->overlay = NULL;
+ }
+ if (avfilter_request_frame(ctx->inputs[1]))
+ goto out;
+ if (!over->overlay) {
+ av_log(ctx, AV_LOG_ERROR, "error getting overlay frame\n");
+ goto out;
}
}
-
- if (src->pic->format == PIX_FMT_YUVA420P) {
- int chroma_w = w>>hsub;
- int chroma_h = h>>vsub;
- assert(dst->pic->format == PIX_FMT_YUV420P);
- copy_blended(pic.data[0], pic.linesize[0], src->data[0], src->linesize[0], src->data[3], src->linesize[3], w, h, 0, 0);
- copy_blended(pic.data[1], pic.linesize[1], src->data[1], src->linesize[1], src->data[3], src->linesize[3], chroma_w, chroma_h, hsub, vsub);
- copy_blended(pic.data[2], pic.linesize[2], src->data[2], src->linesize[2], src->data[3], src->linesize[3], chroma_w, chroma_h, hsub, vsub);
- } else {
- av_picture_copy(&pic, (AVPicture *)src->data, dst->pic->format, w, h);
+ if (!(over->x >= pic->w || over->y >= pic->h ||
+ y+h < over->y || y >= over->y+over->overlay->h)) {
+ blend_slice(ctx, pic, over->overlay, over->x, over->y,
+ over->overlay->w, over->overlay->h, y, pic->w, h);
}
+ out:
+ avfilter_draw_slice(ctx->outputs[0], y, h, slice_dir);
}
-static void copy_image(AVFilterPicRef *dst, int x, int y,
- AVFilterPicRef *src, int w, int h,
- int bpp, int hsub, int vsub)
+static void end_frame(AVFilterLink *link)
{
- if (dst->pic->format == PIX_FMT_YUV420P)
- return copy_image_yuv(dst, x, y, src, w, h, bpp, hsub, vsub);
- else
- return copy_image_rgb(dst, x, y, src, w, h, bpp);
+ avfilter_end_frame(link->dst->outputs[0]);
+ avfilter_unref_pic(link->cur_pic);
}
-static int request_frame(AVFilterLink *link)
+static void null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
{
- AVFilterPicRef *pic;
- OverlayContext *over = link->src->priv;
- int idx;
- int x, y, w, h;
-
- if (!over->pics[0][0] || !over->pics[1][0]) {
- /* No frame output yet, we need one frame from each input */
- if (!over->pics[0][0] && avfilter_request_frame(link->src->inputs[0]))
- return AVERROR_EOF;
- if (!over->pics[1][0] && avfilter_request_frame(link->src->inputs[1]))
- return AVERROR_EOF;
- } else {
- int eof = 0;
-
- /* Try pulling a new candidate from each input unless we already
- have one */
- for (idx = 0; idx < 2; idx++) {
- if (!over->pics[idx][1] &&
- avfilter_request_frame(link->src->inputs[idx]))
- eof++;
- }
- if (eof == 2)
- return AVERROR_EOF; /* No new candidates in any input; EOF */
-
- /* At least one new frame */
- assert(over->pics[0][1] || over->pics[1][1]);
-
- if (over->pics[0][1] && over->pics[1][1]) {
- /* Neither one of the inputs has finished */
- if ((idx = lower_timestamp(over)) == 2) {
- shift_input(over, 0);
- shift_input(over, 1);
- } else
- shift_input(over, idx);
- } else if (over->pics[0][1]) {
- /* Use the single new input frame */
- shift_input(over, 0);
- } else {
- assert(over->pics[1][1]);
- shift_input(over, 1);
- }
- }
-
- /* we draw the output frame */
- pic = avfilter_get_video_buffer(link, AV_PERM_WRITE, link->w, link->h);
- if(over->pics[0][0]) {
- pic->pixel_aspect = over->pics[0][0]->pixel_aspect;
- copy_image(pic, 0, 0, over->pics[0][0], link->w, link->h,
- over->bpp, over->hsub, over->vsub);
- }
- x = FFMIN(over->x, link->w-1);
- y = FFMIN(over->y, link->h-1);
- w = FFMIN(link->w-x, over->pics[1][0]->w);
- h = FFMIN(link->h-y, over->pics[1][0]->h);
- if(over->pics[1][0])
- copy_image(pic, x, y, over->pics[1][0], w, h,
- over->bpp, over->hsub, over->vsub);
-
- /* we give the output frame the higher of the two current pts values */
- pic->pts = FFMAX(over->pics[0][0]->pts, over->pics[1][0]->pts);
-
- /* and send it to the next filter */
- avfilter_start_frame(link, avfilter_ref_pic(pic, ~0));
- avfilter_draw_slice (link, 0, pic->h, 1);
- avfilter_end_frame (link);
- avfilter_unref_pic(pic);
+}
- return 0;
+static void null_end_frame(AVFilterLink *link)
+{
}
AVFilter avfilter_vf_overlay =
@@ -379,23 +323,18 @@ AVFilter avfilter_vf_overlay =
.inputs = (AVFilterPad[]) {{ .name = "default",
.type = AVMEDIA_TYPE_VIDEO,
.start_frame = start_frame,
+ .get_video_buffer= get_video_buffer,
.config_props = config_input_main,
.draw_slice = draw_slice,
- .end_frame = end_frame,
- .min_perms = AV_PERM_READ,
- .rej_perms = AV_PERM_REUSE2, },
+ .end_frame = end_frame },
{ .name = "sub",
.type = AVMEDIA_TYPE_VIDEO,
- .start_frame = start_frame,
+ .start_frame = start_frame_overlay,
.config_props = config_input_overlay,
- .draw_slice = draw_slice,
- .end_frame = end_frame,
- .min_perms = AV_PERM_READ,
- .rej_perms = AV_PERM_REUSE2, },
+ .draw_slice = null_draw_slice,
+ .end_frame = null_end_frame },
{ .name = NULL}},
.outputs = (AVFilterPad[]) {{ .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .request_frame = request_frame, },
+ .type = AVMEDIA_TYPE_VIDEO },
{ .name = NULL}},
};
-
More information about the FFmpeg-soc
mailing list