[FFmpeg-soc] [PATCH] new avfilter vf_logo.c to overlay a (alpha-pathed) logo onto a video stream

Stefano Sabatini stefano.sabatini-lala at poste.it
Sun Apr 26 14:36:35 CEST 2009


On date Sunday 2009-04-26 13:42:04 +0200, Jürgen Meissner encoded:
> vf_logo.c implements avfilters "logo" and "logo_without_alpha"
>
> logo=10:20:logo.jpg overlays the video at x=10 y=20 with the logo (is  
> respecting the alpha-path of the logo)
> logo=-1:1:logo.png   overlays the video at 1 pixel from the right and 1  
> pixel from the top border
> logo_without_alpha=10:20:logo.gif overlays the video at 10,20 for all  
> pixels of the logo, doesn't look for an alpha-path in the logo
> logo=0:0:0:10:20:logo.gif overlays video at 10,20 and assumes black  
> RGB=(0,0,0) is the transparent color in the logo
>
> vf_logo.c is relying on the new pixdesc.c rather than the old pix-fmt.c  
> and therefor needs pixdesc.o to be included into the libavcodec.a 
> archive.
>
> 03_libavcodec_Makefile.diff adds the pixdesc.o to the OBS list in the  
> libavcodec/Makefile
>
> mfG J.Meissner
>
>
>

> Index: allfilters.c
> ===================================================================
> --- allfilters.c	(revision 4238)
> +++ allfilters.c	(working copy)
> @@ -40,6 +40,7 @@
>      REGISTER_FILTER(FORMAT,format,vf);
>      REGISTER_FILTER(FPS,fps,vf);
>      REGISTER_FILTER(HFLIP,hflip,vf);
> +    REGISTER_FILTER(LOGO,logo,vf);
>      REGISTER_FILTER(NEGATE,negate,vf);
>      REGISTER_FILTER(NOFORMAT,noformat,vf);
>      REGISTER_FILTER(NULL,null,vf);
> Index: diffs/03_libavcodec_Makefile.diff
> ===================================================================
> --- diffs/03_libavcodec_Makefile.diff	(revision 0)
> +++ diffs/03_libavcodec_Makefile.diff	(revision 0)
> @@ -0,0 +1,12 @@
> +Index: libavcodec/Makefile
> +===================================================================
> +--- libavcodec/Makefile	(revision 18682)
> ++++ libavcodec/Makefile	(working copy)
> +@@ -18,6 +18,7 @@
> +        opt.o                                                            \
> +        options.o                                                        \
> +        parser.o                                                         \
> ++       pixdesc.o                                                        \
> +        raw.o                                                            \
> +        resample.o                                                       \
> +        resample2.o                                                      \
> Index: doc/vfilters.texi
> ===================================================================
> --- doc/vfilters.texi	(revision 4238)
> +++ doc/vfilters.texi	(working copy)
> @@ -117,6 +117,47 @@
>  
>  Flip the video horizontally.
>  
> + at section logo
> +
> + at example
> +./ffmpeg -i inputvideofile -vfilters logo=10:20:logofile.png -y outputvideofile
> + at end example
> +
> + image of logofile.png is overlayed onto every frame of inputvideofile 
> + at offset x=10 y=20 giving outputvideofile
> +
> + x <INT>
> +
> +   Defines a logo (left border) offset from the left side of the video.
> +   A negative value offsets (logo right border) from
> +   the right side of the video.
> +
> + y <INT>
> +
> +   Defines a logo (top border) offset from the top of the video.
> +   A negative value offsets (logo bottom border) from
> +   the bottom of the video.
> +
> + if logofile has no alpha-path You can prefix another 3 fields R,G,B
> + to select a RGB-color to be the transparent one
> +
> + 
> + REMARKS: there is a lot of gymnastics with the single logo frame, we do 
> + this to avoid any transformation for ALL the many 
> + video frames

Strange formatting.

> + at example
> +./ffmpeg -i inputvideofile -vfilters logo=0:0:0:10:20:logofile.png -y outputvideofile
> + at end example

Maybe you should use a non-positional system, for example that
implemented by the patches I posted on ffmpeg-devel
(av_set_options_set), but wait for this since they still have to be
discussed. Also it should avoid the "_without_alpha" thing.

> +
> + black is the color to be understood as transparent

Maybe this should be configurable.

> +
> + at example
> +./ffmpeg -i inputvideofile -vfilters logo_without_alpha=10:20:logofile.png -y outputvideofile
> + at end example
> +
> + force overlaying all pixels (even if no alpha-path)
> +
>  @section negate
>  
>  @example
> Index: vf_logo.c
> ===================================================================
> --- vf_logo.c	(revision 0)
> +++ vf_logo.c	(revision 0)
> @@ -0,0 +1,859 @@
> +#define VF_LOGO_VERSION "0.9.8 26.4.2009"

No need for version.

> +/**
> + * libavfilter/vf_logo.c
> + * filter to overlay (with or without alpha) logo on top of video
> + * Copyright (c) 2009 Juergen Meissner (using parts of previous code)
> + * Copyright (c) 2008 Victor Paesa     (libavfilter/vsrc_movie.c)
> + * Copyright (c) 2007 Bobby Bingham    (libavfilter/vf_overlay.c)
> + * Copyright (c) 2007 Juergen Meissner (vhook/overlay.c)
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +
> +/**
> + *
> + * example of using libavfilter/vf_logo:
> + *
> + * ffmpeg -i inputvideofile -vfilters logo=10:20:logofile.png -y outputvideofile
> + *
> + * image of logofile.png is overlayed onto every frame of inputvideofile 
> + * at offset x=10 y=20 giving outputvideofile
> + *
> + * x <INT>
> + *
> + *   Defines a logo (left border) offset from the left side of the video.
> + *   A negative value offsets (logo right border) from
> + *   the right side of the video.
> + *
> + * y <INT>
> + *
> + *   Defines a logo (top border) offset from the top of the video.
> + *   A negative value offsets (logo bottom border) from
> + *   the bottom of the video.
> + *
> + * if logofile has no alpha-path You can prefix another 3 fields R,G,B
> + * to select a RGB-color to be the transparent one
> + *
> + *
> + * ffmpeg -i inputvideofile -vfilters logo=0:0:0:10:20:logofile.png -y outputvideofile
> + *
> + *   black is the color to be understood as transparent
> + *
> + *
> + * ffmpeg -i inputvideofile -vfilters logo_without_alpha=10:20:logofile.png -y outputvideofile
> + *
> + *   force overlaying all pixels (even if no alpha-path)
> + *
> + *
> + *   REMARKS: there is a lot of gymnastics with the single logo frame, we do 
> + *   this to avoid any transformation for ALL the many 
> + *   video frames
> + *
> + */

Duplicated, keep the docs in vfilters.texi.

> +
> +/* TODO:
> + *
> + *
> + */

Please remove this.

> +
> +#include <stdio.h>
> +#include "avfilter.h"
> +#include "libavcodec/pixdesc.h"
> +#include "libavformat/avformat.h"
> +#include "libswscale/swscale.h"
> +
> +
> +typedef struct {
> +
> +    // pointer back to AVFilterContext
> +    AVFilterContext *filter_ctx;
> +
> +    // video parameters
> +    int hsub, vsub;             //< chroma subsampling
> +    int bpp[4];                 //< bytes per pixel within plane
> +    int video_w, video_h, video_format;
> +
> +    // logo parameters
> +    int x, y;                   //< requested offsets of logo on video
> +    int w, h, format;           //< width, height, pix-format
> +    int app_x, app_y, app_w, app_h;     // corrected to be applied
> +    char file_name[512];
> +    int alpha_R, alpha_G, alpha_B;
> +
> +    // Needed to load logo
> +    AVFormatContext *pFormatCtx;

Please avoid pThisIsAPointer style, this_is_a_pointer is preferred and
consistent with the rest of FFmpeg.

> +    int videoStream;
> +    AVCodecContext *pCodecCtx;
> +    AVCodec *pCodec;
> +    AVFrame *plogo_frame;
> +    AVFrame *plogo_frame_rgba32;
> +    AVFrame *plogo_frame_video_format;
> +    uint8_t *buffer_logo_frame;
> +    uint8_t *buffer_logo_frame_rgba32;
> +    uint8_t *buffer_logo_frame_video_format;
> +    AVPacket packet;
> +    struct SwsContext *sws;
> +
> +    // Needed to overlay logo onto video frame
> +    uint8_t *pRuler_0;
> +    uint8_t *pRuler_1_2;
> +
> +} LogoContext;
> +
> +/**
> + * RGBA pixel.
> + */
> +typedef struct {
> +    uint8_t R;                  ///< Red.
> +    uint8_t G;                  ///< Green.
> +    uint8_t B;                  ///< Blue.
> +    uint8_t A;                  ///< Alpha.
> +} RGBA;
> +
> +static const char *pixdesc_name(int pix_fmt)
> +{
> +    return av_pix_fmt_descriptors[pix_fmt].name;
> +}

Useless wrapper, I'd say to directly use
av_pix_fmt_descriptors[pix_fmt].name.

> +static int load_logo_create_frames(AVFilterContext * ctx)
> +{
> +    LogoContext *logo;
> +    int i, j, err, numBytes, frameFinished;
> +    uint8_t *pLOADfrom_sol;
> +    RGBA *pLOADfrom;
> +
> +    logo = ctx->priv;
> +
> +    /*
> +     * The last three parameters specify the file format, buffer size and format
> +     * parameters; by simply specifying NULL or 0 we ask libavformat to
> +     * auto-detect the format and use a default buffer size.
> +     */
> +    if ((err =
> +         av_open_input_file(&logo->pFormatCtx, logo->file_name, NULL, 0,
> +                            NULL)) != 0) {
> +        av_log(ctx, AV_LOG_ERROR,
> +               " cannot open logo file %s error is %d\n", logo->file_name,

"Cannot open", no space at the begin, same below.

[...]
> +static av_cold int init(AVFilterContext * ctx, const char *args,
> +                        void *opaque)
> +{
> +    LogoContext *logo;
> +    int num_fields;
> +    int arg_R, arg_G, arg_B;
> +
> +    logo = ctx->priv;
> +
> +    av_log(ctx, AV_LOG_DEBUG, " version %s\n", VF_LOGO_VERSION);
> 
> +    logo->filter_ctx = ctx;     // remember ptr to AVFilterContext in LogoContext
> +
> +    logo->alpha_R = -1;         // you can pick a color to be the transparent one
> +    logo->alpha_G = -1;
> +    logo->alpha_B = -1;
> +
> +    if (!args || strlen(args) > 1024) {
> +        av_log(ctx, AV_LOG_ERROR, " Invalid arguments!\n");
> +        return -1;
> +    }
> +
> +    num_fields = sscanf(args, "%d:%d:%d:%d:%d:%512[^:]",
> +                        &arg_R, &arg_G, &arg_B,
> +                        &logo->x, &logo->y, logo->file_name);
> +    if (num_fields == 6) {
> +        logo->alpha_R = arg_R;
> +        logo->alpha_G = arg_G;
> +        logo->alpha_B = arg_B;
> +        av_log(ctx, AV_LOG_INFO,
> +               " RGB=(%d,%d,%d) x=%d y=%d file=%s\n",
> +               logo->alpha_R, logo->alpha_G, logo->alpha_B,
> +               logo->x, logo->y, logo->file_name);
> +        if (logo->alpha_R < 0 || logo->alpha_R > 255 ||
> +            logo->alpha_G < 0 || logo->alpha_G > 255 ||
> +            logo->alpha_B < 0 || logo->alpha_B > 255) {
> +            av_log(ctx, AV_LOG_ERROR,
> +                   " Invalid RGB values! (must be 0-255)\n");
> +            return -1;
> +        }
> +    } else {
> +        num_fields = sscanf(args, "%d:%d:%512[^:]",
> +                            &logo->x, &logo->y, logo->file_name);
> +        if (num_fields == 3) {
> +            av_log(ctx, AV_LOG_INFO,
> +                   " x=%d y=%d file=%s\n",
> +                   logo->x, logo->y, logo->file_name);
> +            av_log(ctx, AV_LOG_DEBUG,
> +                   " RGB=(%d,%d,%d) x=%d y=%d file=%s\n",
> +                   logo->alpha_R, logo->alpha_G, logo->alpha_B,
> +                   logo->x, logo->y, logo->file_name);
> +        } else {
> +            av_log(ctx, AV_LOG_ERROR,
> +                   " expected 3 or 6 arguments\n\t\t\tlogo={R:G:B:}x:y:filename\n\t\t\toptional R,G,B selects a color to be the transparent one\n\t\t\tlogo_without_alpha=x:y:filename forces overlay of all pixels\n\t\t\tbut wrong args are given: '%s'\n",
> +                   args);
> +            return -1;
> +        }
> +    }
> +    if (!strcmp(ctx->filter->name, "logo_without_alpha")) {
> +        logo->alpha_R = logo->alpha_G = logo->alpha_B = 999;
> +        av_log(ctx, AV_LOG_INFO, " processing logofile without alpha\n");
> +    }

Much of this can be simplified using something like
av_set_options_string (not yet discussed on ffmpeg-devel though).

> +
> +    if (!
> +        (logo->sws =
> +         sws_getContext(16, 16, 0, 16, 16, 0, SWS_BICUBIC, NULL, NULL,
> +                        NULL))) {
> +        av_log(ctx, AV_LOG_ERROR, " cannot get SwsContext for swscale\n");
> +        return -1;
> +    }
> +    // load logo image and create rgba32 and video_format frames of logo
> +    return load_logo_create_frames(ctx);
> +}
> +
> +static void uninit(AVFilterContext * ctx)
> +{
> +
> +    LogoContext *logo;
> +
> +    logo = ctx->priv;
> +
> +    if (logo->sws != NULL)
> +        sws_freeContext(logo->sws);
> +    av_free(&logo->plogo_frame);
> +    av_free(&logo->plogo_frame_rgba32);
> +    av_free(&logo->plogo_frame_video_format);
> +    av_free(&logo->buffer_logo_frame);
> +    av_free(&logo->buffer_logo_frame_rgba32);
> +    av_free(&logo->buffer_logo_frame_video_format);
> +    av_free(&logo->pRuler_0);
> +    av_free(&logo->pRuler_1_2);
> +}
> +
> +static AVFilterFormats *make_format_list(LogoContext * logo)
> +{
> +    AVFilterFormats *ret;
> +    int i;
> +
> +    ret = av_mallocz(sizeof(AVFilterFormats));
> +    ret->formats = av_malloc(sizeof(int) * PIX_FMT_NB);
> +
> +    for (i = 0; i < PIX_FMT_NB; i++) {
> +        switch (i) {
> +            /* don't support these */
> +        case PIX_FMT_YUYV422:
> +        case PIX_FMT_MONOBLACK:
> +        case PIX_FMT_UYVY422:
> +            break;
> +            /* support everything else (if named) */
> +        default:
> +            if (av_pix_fmt_descriptors[i].name)
> +                ret->formats[ret->format_count++] = i;
> +        }

Ugh, this is hackish, but for now we can't do anything better.

[...]
 
> Property changes on: vf_logo.c
> ___________________________________________________________________
> Added: svn:executable
>    + *

This looks spurious.

[...]

Regards.


More information about the FFmpeg-soc mailing list