[FFmpeg-soc] [soc]: r5841 - libavfilter/vf_overlay.c
stefano
subversion at mplayerhq.hu
Mon Jun 21 01:27:14 CEST 2010
Author: stefano
Date: Mon Jun 21 01:27:14 2010
New Revision: 5841
Log:
Revert commit:
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.
Fix movie in movie and ffplay overlaying with static images, ffplay
movie in movie filtering is still borken.
Modified:
libavfilter/vf_overlay.c
Modified: libavfilter/vf_overlay.c
==============================================================================
--- libavfilter/vf_overlay.c Sat Jun 19 23:51:15 2010 (r5840)
+++ libavfilter/vf_overlay.c Mon Jun 21 01:27:14 2010 (r5841)
@@ -1,6 +1,5 @@
/*
* copyright (c) 2007 Bobby Bingham
- * copyright (c) 2010 Baptiste Coudurier
*
* This file is part of FFmpeg.
*
@@ -27,7 +26,6 @@
#include "avfilter.h"
#include "libavutil/eval.h"
#include "libavutil/avstring.h"
-#include "libavutil/pixdesc.h"
static const char *var_names[] = {
"main_w", ///< width of the main video
@@ -46,9 +44,13 @@ enum var_name {
};
typedef struct {
- unsigned x, y; //< position of subpicture
+ int x, y; //< position of subpicture
- AVFilterPicRef *overlay;
+ /** 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];
int bpp; //< bytes per pixel
int hsub, vsub; //< chroma subsampling
@@ -72,15 +74,18 @@ static av_cold int init(AVFilterContext
static av_cold void uninit(AVFilterContext *ctx)
{
OverlayContext *over = ctx->priv;
+ int i, j;
- if (over->overlay)
- avfilter_unref_pic(over->overlay);
+ for(i = 0; i < 2; i ++)
+ for(j = 0; j < 2; j ++)
+ if(over->pics[i][j])
+ avfilter_unref_pic(over->pics[i][j]);
}
static int query_formats(AVFilterContext *ctx)
{
- //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_BGR24, 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);
@@ -118,8 +123,7 @@ static int config_input_main(AVFilterLin
over->bpp = 1;
}
- over->hsub = av_pix_fmt_descriptors[link->format].log2_chroma_w;
- over->vsub = av_pix_fmt_descriptors[link->format].log2_chroma_h;
+ avcodec_get_chroma_sub_sample(link->format, &over->hsub, &over->vsub);
return 0;
}
@@ -128,7 +132,7 @@ static int config_input_overlay(AVFilter
{
AVFilterContext *ctx = link->dst;
OverlayContext *over = link->dst->priv;
- const char *expr;
+ char *expr;
double var_values[VARS_NB], res;
int ret;
@@ -139,27 +143,14 @@ static int config_input_overlay(AVFilter
var_values[OVERLAY_W] = ctx->inputs[1]->w;
var_values[OVERLAY_H] = ctx->inputs[1]->h;
- 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 ((ret = av_parse_and_eval_expr(&res, (expr = over->x_expr),
- var_names, var_values,
- NULL, NULL, NULL, NULL,
- NULL, 0, ctx)) < 0)
+ if ((ret = av_parse_and_eval_expr(&res, (expr = over->x_expr), var_names, var_values,
+ NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
goto fail;
over->x = res;
- if ((ret = av_parse_and_eval_expr(&res, (expr = over->y_expr),
- var_names, var_values,
- NULL, NULL, NULL, NULL,
- NULL, 0, ctx)) < 0)
+ if ((ret = av_parse_and_eval_expr(&res, (expr = over->y_expr), var_names, var_values,
+ NULL, NULL, NULL, NULL, NULL, 0, ctx)))
goto fail;
over->y = res;
-
- 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;
fail:
@@ -168,147 +159,209 @@ fail:
return ret;
}
-static AVFilterPicRef *get_video_buffer(AVFilterLink *link, int perms, int w, int h)
+static void shift_input(OverlayContext *over, int idx)
{
- AVFilterPicRef *picref = avfilter_get_video_buffer(link->dst->outputs[0],
- perms, w, h);
- return picref;
+ 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;
}
static void start_frame(AVFilterLink *link, AVFilterPicRef *picref)
{
- AVFilterPicRef *outpicref = avfilter_ref_pic(picref, ~0);
+ 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;
+ }
+}
- link->dst->outputs[0]->outpic = outpicref;
+static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
+{
+}
- avfilter_start_frame(link->dst->outputs[0], outpicref);
+static void end_frame(AVFilterLink *link)
+{
}
-static void start_frame_overlay(AVFilterLink *link, AVFilterPicRef *picref)
+static int lower_timestamp(OverlayContext *over)
{
- AVFilterContext *ctx = link->dst;
- OverlayContext *over = ctx->priv;
+ 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;
- over->overlay = picref;
+ if(over->pics[0][1]->pts == over->pics[1][1]->pts) return 2;
+ return (over->pics[0][1]->pts > over->pics[1][1]->pts);
}
-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)
+static void copy_image_rgb(AVFilterPicRef *dst, int x, int y,
+ AVFilterPicRef *src, int w, int h, int bpp)
{
- 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;
+ AVPicture pic;
- 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;
+ memcpy(&pic, &dst->data, sizeof(AVPicture));
+ pic.data[0] += x * bpp;
+ pic.data[0] += y * pic.linesize[0];
- 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;
+ 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;
}
- dp += dst->linesize[0];
- sp += src->linesize[0];
}
} else {
- 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];
- }
+ 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;
}
}
}
-static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
+static void copy_image_yuv(AVFilterPicRef *dst, int x, int y,
+ AVFilterPicRef *src, int w, int h,
+ int bpp, int hsub, int vsub)
{
- AVFilterContext *ctx = link->dst;
- AVFilterPicRef *pic = ctx->outputs[0]->outpic;
- OverlayContext *over = ctx->priv;
+ AVPicture pic;
+ int 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;
+ 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->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);
+
+ 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);
}
- out:
- avfilter_draw_slice(ctx->outputs[0], y, h, slice_dir);
}
-static void end_frame(AVFilterLink *link)
+static void copy_image(AVFilterPicRef *dst, int x, int y,
+ AVFilterPicRef *src, int w, int h,
+ int bpp, int hsub, int vsub)
{
- avfilter_end_frame(link->dst->outputs[0]);
- avfilter_unref_pic(link->cur_pic);
+ 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);
}
-static void null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
+static int request_frame(AVFilterLink *link)
{
-}
+ AVFilterPicRef *pic;
+ OverlayContext *over = link->src->priv;
+ int idx;
+ int x, y, w, h;
-static void null_end_frame(AVFilterLink *link)
-{
+ 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;
}
AVFilter avfilter_vf_overlay =
@@ -326,18 +379,23 @@ 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 },
+ .end_frame = end_frame,
+ .min_perms = AV_PERM_READ,
+ .rej_perms = AV_PERM_REUSE2, },
{ .name = "sub",
.type = AVMEDIA_TYPE_VIDEO,
- .start_frame = start_frame_overlay,
+ .start_frame = start_frame,
.config_props = config_input_overlay,
- .draw_slice = null_draw_slice,
- .end_frame = null_end_frame },
+ .draw_slice = draw_slice,
+ .end_frame = end_frame,
+ .min_perms = AV_PERM_READ,
+ .rej_perms = AV_PERM_REUSE2, },
{ .name = NULL}},
.outputs = (AVFilterPad[]) {{ .name = "default",
- .type = AVMEDIA_TYPE_VIDEO },
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame, },
{ .name = NULL}},
};
+
More information about the FFmpeg-soc
mailing list