[FFmpeg-soc] [soc]: r5617 - in libavfilter: diffs/03_libavfilter_doc.diff vf_overlay.c

stefano subversion at mplayerhq.hu
Thu Feb 4 01:55:07 CET 2010


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@$foo.st>, and
adapted by Artur Bodera <a$surname at gmail.com> 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:
++ at example
++movie=0:png:logo.png [logo]; [in][logo] overlay=10:mainH-overlayH-10:1 [out]
++ at 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):
++ at 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]
++ at end example
++
++You could chain and add more overlays this way but the efficiency of
++such approach is yet to be tested.
++
 + at section rotate
 +
 + at 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,


More information about the FFmpeg-soc mailing list