Author: stefano Date: Thu Feb 4 01:55:07 2010 New Revision: 5617 Log: Implement option for supporting alpha-blending in the overlay filter.
Based on a patch by Martin Storsjö $foo=martin <$...@$foo.st>, and adapted by Artur Bodera <[email protected]> and me. Modified: libavfilter/diffs/03_libavfilter_doc.diff libavfilter/vf_overlay.c Modified: libavfilter/diffs/03_libavfilter_doc.diff ============================================================================== --- libavfilter/diffs/03_libavfilter_doc.diff Mon Feb 1 23:45:01 2010 (r5616) +++ libavfilter/diffs/03_libavfilter_doc.diff Thu Feb 4 01:55:07 2010 (r5617) @@ -54,7 +54,7 @@ Index: doc/libavfilter.texi @section noformat Force libavfilter not to use any of the specified pixel formats for the -@@ -149,6 +187,37 @@ +@@ -149,6 +187,64 @@ Pass the source unchanged to the output. @@ -81,6 +81,33 @@ Index: doc/libavfilter.texi +can be used to draw the overlay at 10 pixels from the bottom right +corner of the main video. + ++The filter accepts a third optional parameter, if set to a value ++different than 0, it will alpha-blend the overlayed video on top of ++the first one. ++ ++This can be used in particular for performing watermarking effects, or ++for adding a logo on top of the input video. ++ ++For example, the following command will insert a transparent PNG ++logo in the bottom left corner of the input video: +...@example ++movie=0:png:logo.png [logo]; [in][logo] overlay=10:mainH-overlayH-10:1 [out] +...@end example ++ ++Notice the last parameter to overlay ":1" - this enables alpha blending. ++ ++The following example will insert 2 different transparent PNG ++logos (second logo on bottom right corner): +...@example ++movie=0:png:logo1.png [logo1]; ++movie=0:png:logo2.png [logo2]; ++[in][logo1] overlay=10:mainH-overlayH-10:1 [in+logo1]; ++[in+logo1][logo2] overlay=mainW-overlayW-10:mainH-overlayH-10:1 [out] +...@end example ++ ++You could chain and add more overlays this way but the efficiency of ++such approach is yet to be tested. ++ +...@section rotate + +...@example @@ -92,7 +119,7 @@ Index: doc/libavfilter.texi @section scale Scale the input video to width:height and/or convert the image format. -@@ -174,6 +243,24 @@ +@@ -174,6 +270,24 @@ The default value of ``width'' and ``height'' is 0. @@ -117,7 +144,7 @@ Index: doc/libavfilter.texi @section slicify Pass the images of input video on to next video filter as multiple -@@ -189,6 +276,19 @@ +@@ -189,6 +303,19 @@ Adding this in the beginning of filter chains should make filtering faster due to better use of the memory cache. @@ -137,7 +164,7 @@ Index: doc/libavfilter.texi @section vflip Flip the input video vertically. -@@ -201,6 +301,32 @@ +@@ -201,6 +328,32 @@ Below is a description of the currently available video sources. Modified: libavfilter/vf_overlay.c ============================================================================== --- libavfilter/vf_overlay.c Mon Feb 1 23:45:01 2010 (r5616) +++ libavfilter/vf_overlay.c Thu Feb 4 01:55:07 2010 (r5617) @@ -54,6 +54,8 @@ typedef struct { int hsub, vsub; //< chroma subsampling char x_expr[256], y_expr[256]; + + int blend; } OverlayContext; static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) @@ -64,7 +66,7 @@ static av_cold int init(AVFilterContext av_strlcpy(over->y_expr, "0", sizeof(over->y_expr)); if (args) - sscanf(args, "%255[^:]:%255[^:]", over->x_expr, over->y_expr); + sscanf(args, "%255[^:]:%255[^:]:%d", over->x_expr, over->y_expr, &over->blend); return 0; } @@ -80,6 +82,24 @@ static av_cold void uninit(AVFilterConte avfilter_unref_pic(over->pics[i][j]); } +static int query_formats(AVFilterContext *ctx) +{ + OverlayContext *over = ctx->priv; + if (over->blend) { + enum PixelFormat inout_pix_fmts[] = { PIX_FMT_YUV420P, PIX_FMT_NONE }; + enum PixelFormat blend_pix_fmts[] = { PIX_FMT_YUVA420P, PIX_FMT_NONE }; + AVFilterFormats *inout_formats = avfilter_make_format_list(inout_pix_fmts); + AVFilterFormats *blend_formats = avfilter_make_format_list(blend_pix_fmts); + + avfilter_formats_ref(inout_formats, &ctx->inputs [0]->out_formats); + avfilter_formats_ref(blend_formats, &ctx->inputs [1]->out_formats); + avfilter_formats_ref(inout_formats, &ctx->outputs[0]->in_formats ); + } else { + avfilter_default_query_formats(ctx); + } + return 0; +} + static int config_input_main(AVFilterLink *link) { OverlayContext *over = link->dst->priv; @@ -179,9 +199,30 @@ static int lower_timestamp(OverlayContex return (over->pics[0][1]->pts > over->pics[1][1]->pts); } +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) >> 8; + optr++; + iptr++; + aptr += 1 << hsub; + } + } +} + static void copy_image(AVFilterPicRef *dst, int x, int y, AVFilterPicRef *src, int w, int h, - int bpp, int hsub, int vsub) + int bpp, int hsub, int vsub, int blend) { AVPicture pic; int i; @@ -200,7 +241,17 @@ static void copy_image(AVFilterPicRef *d } } + if (blend) { + int chroma_w = w>>hsub; + int chroma_h = h>>vsub; + assert(dst->pic->format == PIX_FMT_YUV420P); + assert(src->pic->format == PIX_FMT_YUVA420P); + 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); + } } static int request_frame(AVFilterLink *link) @@ -253,7 +304,7 @@ static int request_frame(AVFilterLink *l 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); + over->bpp, over->hsub, over->vsub, 0); } x = FFMIN(over->x, link->w-1); y = FFMIN(over->y, link->h-1); @@ -261,7 +312,7 @@ static int request_frame(AVFilterLink *l 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); + over->bpp, over->hsub, over->vsub, over->blend); /* 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); @@ -284,6 +335,8 @@ AVFilter avfilter_vf_overlay = .priv_size = sizeof(OverlayContext), + .query_formats = query_formats, + .inputs = (AVFilterPad[]) {{ .name = "default", .type = CODEC_TYPE_VIDEO, .start_frame = start_frame, _______________________________________________ FFmpeg-soc mailing list [email protected] https://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-soc
