[MPlayer-dev-eng] [CFTWWI] VF logodetect/logoremove

Gaetan SEMET gsem01 at freescale.com
Thu Aug 11 11:45:15 CEST 2005


Hello

Logo removals would be so nice in mplayer...
Do you know this project :
http://www-sop.inria.fr/odyssee/research/tschumperle-deriche:02d/appliu/
It's a powerful image reconstruction library.
I don't think it is usable for "live" processing, but it may be interesting
to look at it.

My 2 cents

Gaetan

Ivo wrote:

>Hi,
>
>A while ago, several logo removal video filters where posted. By that time, 
>I wrote a detection filter and an improved alpha-deblend filter. It was 
>never really finished and I completely lost interest. In fact, I find 
>deblended or blurred logo's even more annoying than the original logo's. 
>For a decent deblend, the logo has to be transparent enough (which most of 
>them aren't), otherwise you get a lot of noise in the non-dark/light 
>scenes. And all blur algorithms I have seen so far make the logo look like 
>it's behind a +10 dioptre lens. 
>
>So, why do I post this code here? Well, I got bugged to release it several 
>times (you know who you are :) ) and maybe others have use for it. In no 
>case will I commit this code (or lobby for it) and maintain it, but if 
>others want to, go ahead.
>
>* logodetect can take two suboption, thres and (no)output. The latter speaks 
>for itself and thres defines a lower threshold. All pixels that never reach 
>a value below thres are considered to make up the logo.
>
>TODO (if anyone wants to): support for totally opaque logo's. those are 
>better detected by determining which pixels hardly change color at all 
>(+-10 or something). As a bonus, it'll also detect (partly) black logo's.
>
>If output is specified (default), it writes a logo and alpha pnm file to 
>disk when you abort MPlayer by control-c. Be sure to keep it running for 
>long enough to detect all the pixels that make up the logo (thousands of 
>frames, depending on the content) and be sure the logo is always visible in 
>every frame you feed it (be aware of pre-commercial break fading of the 
>logo, like for exaple The WB does). Also, experiment with the threshold. 
>They might vary between files you try it on (even if it's the same show 
>from the same ripper or network sometimes) and it takes some time to find 
>the best value. For example, if the correct value is 30 and you use 32, see 
>what happend when you deblend/remove it :) Offcourse, this filter works 
>best on clean signals (DVB feeds, etc.)
>
>* logoremove reads the pnm files and applies a deblend or plain remove 
>filter to the video it's playing. suboptions are logo=<file>, alpha=<file> 
>and (no)deblend.
>
>TODO: implement nodeblend (read: remove/blur). The framework is there, just 
>right now it paints all logo pixels black.
>
>I was thinking of an algorithm that computes the weighted average (weight 
>based on distance) of surrounding non-logo pixels for every logo-pixel. 
>
>To compile, copy both files to libmpcodecs/. , add hooks in vf.c and 
>Makefile there, run make and have fun :)
>
>CFTWWI, Code For Those Who Want It :)
>
>--Ivo
>
>
>
>  
>
>------------------------------------------------------------------------
>
>
>/* --------------------------------------------------------------------------*/
>
>/*
> * Written by Ivo van Poorten <ivop at euronet.nl>
> * Copyright (C) 2005
> *
> * This program is free software; you can redistribute it and/or
> * modify it under the terms of the GNU General Public License
> * as published by the Free Software Foundation; either version 2
> * of the License, or (at your option) any later version.
> *
> * This program 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 General Public License for more details.
> *
> * You should have received a copy of the GNU General Public License
> * along with this program; if not, write to the Free Software
> * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
> *
> */
>
>/* --------------------------------------------------------------------------*/
>
>/* Global Includes */
>
>#include <stdio.h>
>#include <stdlib.h>
>#include <string.h>
>#include <inttypes.h>
>
>/* --------------------------------------------------------------------------*/
>
>/* Local Includes */
>
>#include "../config.h"
>#include "../mp_msg.h"
>#include "img_format.h"
>#include "mp_image.h"
>#include "vf.h"
>#include "../libvo/fastmemcpy.h"
>#include "../subopt-helper.h"
>#include "../postproc/swscale.h"
>
>/* --------------------------------------------------------------------------*/
>
>/* Defines */
>
>#define setw(x, y, b) x[0] = b? y : y*3; x[1] = b? y/2 : 0; x[2] = b? y/2: 0;
>#define seth(x, y, b) x[0] = b? y : y; x[1] = b? y/2 : 0; x[2] = b? y/2: 0;
>#define setwh(wh, w, h) wh[0]=w[0]*h[0]; wh[1]=w[1]*h[1]; wh[2]=w[2]*h[2];
>#define malloctriple(x, wh, s) x[0] = malloc( (wh[0] + wh[1] + wh[2]) * s); \
>                               x[1] = &x[0][ wh[0] ]; \
>                               x[2] = &x[0][ wh[0] + wh[1] ]
>#define copyof(x) { x[0], x[1], x[2] }
>#define copyvals(x,y) x[0]=y[0]; x[1]=y[1]; x[2]=y[2]
>
>/* --------------------------------------------------------------------------*/
>
>struct vf_priv_s {
>    int gmin[3], gmax[3];
>    unsigned char *min[3], *max[3];
>    int width[3], height[3], thres[3];
>    
>    int fno, yuv, output;
>};
>
>/* --------------------------------------------------------------------------*/
>
>static int query_format(struct vf_instance_s *vf, unsigned int fmt)
>{
>    switch(fmt) {
>        case IMGFMT_YV12:
>            vf->priv->yuv = 1;
>            return vf_next_query_format(vf, fmt);
>        case IMGFMT_RGB24:
>            vf->priv->yuv = 0;
>            return vf_next_query_format(vf, fmt);
>    }
>    return 0;
>}
>
>/* --------------------------------------------------------------------------*/
>
>static int config(struct vf_instance_s *vf, int width, int height, int d_width,
>                  int d_height, unsigned int flags, unsigned int outfmt)
>{
>    struct vf_priv_s *priv = vf->priv;
>    int yuv = priv->yuv;
>    int wh[3];
>
>    setw(priv->width, width, yuv);
>    seth(priv->height, height, yuv);
>    setwh(wh, priv->width, priv->height);
>
>    malloctriple(priv->min, wh, sizeof(unsigned char));
>    malloctriple(priv->max, wh, sizeof(unsigned char));
>
>    memset(priv->min[0], 128, wh[0] + wh[1] + wh[2]);
>    memset(priv->max[0], 128, wh[0] + wh[1] + wh[2]);
>
>    priv->gmin[0] = priv->gmin[1] = priv->gmin[2] =
>    priv->gmax[0] = priv->gmax[1] = priv->gmax[2] = 128;
>
>    priv->thres[1] = yuv ? 0 : priv->thres[0];
>    priv->thres[2] = yuv ? 0 : priv->thres[0];
>
>    return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
>}
>
>/* --------------------------------------------------------------------------*/
>
>static int put_image(struct vf_instance_s *vf, mp_image_t *mpi)
>{
>    struct vf_priv_s *priv = vf->priv;
>    mp_image_t *dmpi;
>    const int *w = priv->width, *h = priv->height;
>    unsigned char *max[3]   = copyof(priv->max);
>    unsigned char *min[3]   = copyof(priv->min);
>    unsigned char *plane[3] = copyof(mpi->planes);
>             int  stride[3] = copyof(mpi->stride);
>    register int x, y, p;
>    register unsigned char v;
>
>    // filter has to export mpi
>
>    dmpi = vf_get_image(vf->next, mpi->imgfmt,MP_IMGTYPE_EXPORT, 0, w[0], h[0]);
>
>    copyvals(dmpi->planes, mpi->planes);
>    copyvals(dmpi->stride, mpi->stride);
>    dmpi->width = mpi->width;
>    dmpi->height = mpi->height;
>
>    // ignore first two frames
>
>    if (priv->fno < 2) {
>        priv->fno++;
>        return vf_next_put_image(vf,dmpi);
>    }
>
>    // process 3rd frame and onwards
>
>    for (p=0; p<3; p++) {
>        for (y=0; y<h[p]; y++) {
>            for (x=0; x<w[p]; x++) {
>                v = plane[p][x];
>                if ( v > max[p][x] )    max[p][x] = v;
>                if ( v < min[p][x] )    min[p][x] = v;
>                if ( v > priv->gmax[p]) priv->gmax[p] = v;
>                if ( v < priv->gmin[p]) priv->gmin[p] = v;
>            }
>            plane[p] += stride[p];
>            max[p] += w[p];
>            min[p] += w[p];
>        }
>    }
>
>    return vf_next_put_image(vf,dmpi);
>}
>
>/* --------------------------------------------------------------------------*/
>
>/* per pixel formulas are:
> *
> * alpha = 1-(max-min)/(globalmax-globalmin)      range: [0.0-1.0]
> * logoimage = (min-(1-alpha)*globalmin)/alpha    range: [globalmin-globalmax]
> *
> * thanks to Richard for helping me with these formulas, instead of only
> * doing alpha detection based on luminance
> */
>
>static void calc_alpha_and_image(int w, int h,
>                                 unsigned char *min, unsigned char *max,
>                                 float *falphas, unsigned char *alphas,
>                                 unsigned char *logo,
>                                 int gmin, int gmax, int t)
>{
>    int x, y;
>
>    for (y=0; y<h; y++) {
>        for (x=0; x<w; x++) {
>            if (min[y*w+x] < gmin + t) {
>                max[y*w+x] = gmax;
>                min[y*w+x] = gmin;
>            }
>            falphas[y*w+x] = (1.0 - ( (float)(max[y*w+x] - min[y*w+x]) /
>                                      (float)(gmax-gmin)                 ) );
>            alphas[y*w+x] = falphas[y*w+x] * 255;
>            if (alphas[y*w+x] != 0)
>                logo[y*w+x] = ( (float)min[y*w+x] -
>                                (1.0-falphas[y*w+x])*(float)gmin) /
>                                                            falphas[y*w+x];
>            else
>                logo[y*w+x] = 0;
>        }
>    }
>
>}
>
>/* --------------------------------------------------------------------------*/
>
>static void write_pgmyuv(char *filename, unsigned char **buffer,
>                                                    const int *w, const int *h)
>{
>    FILE *outfile;
>    int y;
>
>    outfile = fopen(filename, "wb");
>    fprintf(outfile, "P5\n%i %i\n255\n", w[0], h[0]*3/2);
>    fwrite(buffer[0], w[0], h[0], outfile);
>    for (y=0; y<h[1]; y++) {
>        fwrite(buffer[1]+y*w[1], w[1], 1, outfile);
>        fwrite(buffer[2]+y*w[2], w[2], 1, outfile);
>    }
>    fclose(outfile);
>}
>
>/* --------------------------------------------------------------------------*/
>
>static void write_ppm(char *filename, unsigned char **buffer,
>                                                    const int *w, const int *h)
>{
>    FILE *outfile;
>
>    outfile = fopen(filename, "wb");
>    fprintf(outfile, "P6\n%i %i\n 255\n", w[0]/3, h[0]);
>    fwrite(buffer[0], w[0], h[0], outfile);
>    fclose(outfile);
>}
>
>/* --------------------------------------------------------------------------*/
>
>static void uninit(struct vf_instance_s *vf)
>{
>    struct vf_priv_s *priv = vf->priv;
>    int x, y;
>    const int *w = priv->width, *h = priv->height, *t = priv->thres;
>    int *gmax = priv->gmax, *gmin = priv-> gmin;
>    unsigned char **max = priv->max, **min = priv->min;
>    unsigned char *alphas[3], *logo[3];
>    float *falphas[3];
>    int wh[3], p;
>
>    setwh(wh, w, h);
>
>    malloctriple(alphas, wh, sizeof(unsigned char*));
>    malloctriple(falphas, wh, sizeof(float));
>    malloctriple(logo, wh, sizeof(unsigned char*));
>
>    // set right global min/max values (either [0-255] or [16-240])
>    // not sure about this; seems to increase noise
>
>    /* if ( (gminY<16) || (gmaxY>240) ) {
>        gminY = 0;   gminU = 0;   gminV = 0;
>        gmaxY = 255; gmaxU = 255; gmaxV = 255;
>    } else {
>        gminY = 16;  gminU = 16;  gminV = 16;
>        gmaxY = 240; gmaxU = 240; gmaxV = 240;
>    } */
>
>    for (p=0; p<3; p++) {
>        calc_alpha_and_image(w[p], h[p], min[p], max[p], falphas[p], alphas[p],
>                                            logo[p], gmin[p], gmax[p], t[p]);
>    }
>
>    // set chroma channels logo and alpha to 0 where there's no logo detected
>    // offcourse, this is doe YV12 only
>
>    if (vf->priv->yuv) {
>        for (p=1; p<3; p++) {
>            for (y=0; y<h[1]; y++) {
>                for (x=0; x<w[1]; x++) {
>                    if ( ( alphas[0][2*y*w[0]+2*x] +
>                           alphas[0][2*y*w[0]+2*x+1] +
>                           alphas[0][2*y*w[0]+w[0]+2*x] +
>                           alphas[0][2*y*w[0]+w[0]+2*x+1] ) != 0 )
>                        continue;
>                    alphas[p][y*w[p]+x] = 0;
>                    logo[p][y*w[p]+x] = 128;
>                }
>            }
>        }
>    }
>
>    // write alpha channels and logo to files
>
>    if (vf->priv->output && vf->priv->yuv) {
>        write_pgmyuv("logodetect.alpha.pgmyuv", alphas, w, h);
>        write_pgmyuv("logodetect.logo.pgmyuv",  logo,   w, h);
>    } else if (vf->priv->output) {
>        write_ppm("logodetect.alpha.ppm", alphas, w, h);
>        write_ppm("logodetect.logo.ppm",  logo,   w, h);
>    }
>
>/*    fprintf(stderr, "DEBUG: global min/max Y: %d %d  U: %d %d  V: %d %d\n",
>            vf->priv->gmin[0], vf->priv->gmax[0],
>            vf->priv->gmin[1], vf->priv->gmax[1],
>            vf->priv->gmin[2], vf->priv->gmax[2]); */
>
>    // free memory
>
>    free(alphas[0]);
>    free(falphas[0]);
>    free(logo[0]);
>    free(vf->priv->min[0]);
>    free(vf->priv->max[0]);
>    free(vf->priv);
>    vf->priv = NULL;
>}
>
>/* --------------------------------------------------------------------------*/
>
>static int int_0_255(int *val)
>{
>    if ( (*val < 0) || (*val > 255) )return 0;
>    return 1;
>}
>
>static int parse_command_line (vf_instance_t *vf, char *args)
>{
>    opt_t subopts[] = {
>        {"thres",       OPT_ARG_INT,    &vf->priv->thres,
>                                                    (opt_test_f) int_0_255, 0},
>        {"output",      OPT_ARG_BOOL,   &vf->priv->output, NULL, 0},
>        {NULL, 0, NULL, NULL, 0}
>    };
>
>    /* set defaults */
>
>    vf->priv->thres[0]  = 20;
>    vf->priv->yuv       = 1;
>    vf->priv->output    = 1;
>
>    if (subopt_parse(args, subopts) != 0) return -1;
>
>    return 1;
>}
>
>/* --------------------------------------------------------------------------*/
>
>static int open (vf_instance_t *vf, char *args)
>{
>    vf->config = config;
>    vf->query_format = query_format;
>    vf->put_image = put_image;
>    vf->uninit = uninit;
>    vf->priv = calloc(1, sizeof(struct vf_priv_s));
>
>    vf->priv->fno = 0;
>
>    return parse_command_line(vf, args);
>}
>
>/* --------------------------------------------------------------------------*/
>
>vf_info_t vf_info_logodetect = {
>    "Autodetect logo",
>    "logodetect",
>    "Ivo van Poorten",
>    "",
>    open,
>    NULL
>};
>
>/* --------------------------------------------------------------------------*/
>
>  
>
>------------------------------------------------------------------------
>
>
>/* --------------------------------------------------------------------------*/
>
>/*
> * Written by Ivo van Poorten <ivop at euronet.nl>
> * Copyright (C) 2005
> *
> * This program is free software; you can redistribute it and/or
> * modify it under the terms of the GNU General Public License
> * as published by the Free Software Foundation; either version 2
> * of the License, or (at your option) any later version.
> *
> * This program 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 General Public License for more details.
> *
> * You should have received a copy of the GNU General Public License
> * along with this program; if not, write to the Free Software
> * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
> *
> */
>
>/* --------------------------------------------------------------------------*/
>
>/* Global Includes */
>
>#include <stdio.h>
>#include <stdlib.h>
>#include <string.h>
>#include <inttypes.h>
>#include <ctype.h>
>#include <limits.h>
>
>/* --------------------------------------------------------------------------*/
>
>/* Local Includes */
>
>#include "../config.h"
>#include "../mp_msg.h"
>#include "img_format.h"
>#include "mp_image.h"
>#include "vf.h"
>#include "../libvo/fastmemcpy.h"
>#include "../subopt-helper.h"
>
>/* --------------------------------------------------------------------------*/
>
>/* Defines */
>
>#define setw(x, y, b) x[0] = b? y : y*3; x[1] = b? y/2 : 0; x[2] = b? y/2: 0;
>#define seth(x, y, b) x[0] = b? y : y; x[1] = b? y/2 : 0; x[2] = b? y/2: 0;
>#define setwh(wh, w, h) wh[0]=w[0]*h[0]; wh[1]=w[1]*h[1]; wh[2]=w[2]*h[2];
>#define malloctriple(x, wh, s) x[0] = malloc( (wh[0] + wh[1] + wh[2]) * s); \
>                               x[1] = &x[0][ wh[0] ]; \
>                               x[2] = &x[0][ wh[0] + wh[1] ]
>#define CLAMP(a) (a>255) ? 255 : ( (a<0) ? 0 : a )
>
>#define LOGOFILENAMEDEFAULT     "logodetect.logo"
>#define ALPHAFILENAMEDEFAULT    "logodetect.alpha"
>
>/* --------------------------------------------------------------------------*/
>
>struct vf_priv_s {
>    char *logofilename, *alphafilename;
>    unsigned char *logo[3], *alpha[3];
>    int width[3], height[3], ystart[3], yend[3], xstart[3], xend[3];
>    int config, yuv, deblend;
>};
>
>/* --------------------------------------------------------------------------*/
>
>static int query_format(struct vf_instance_s *vf, unsigned int fmt)
>{
>    struct vf_priv_s *priv = vf->priv;
>
>    switch(fmt) {
>        case IMGFMT_YV12:
>            priv->yuv = 1;
>            break;
>        case IMGFMT_RGB24:
>            priv->yuv = 0;
>            break;
>        default:
>            return 0;
>    }
>
>    if (!priv->logofilename) priv->logofilename = strdup (priv->yuv ?
>                LOGOFILENAMEDEFAULT ".pgmyuv" : LOGOFILENAMEDEFAULT ".ppm");
>    if (!priv->alphafilename) priv->alphafilename = strdup (priv->yuv ?
>                ALPHAFILENAMEDEFAULT ".pgmyuv" : ALPHAFILENAMEDEFAULT ".ppm");
>
>    return vf_next_query_format(vf, fmt);
>}
>
>/* --------------------------------------------------------------------------*/
>
>static int skip(FILE *f)
>{
>    int c, comment = 0;
>    do {
>        c = fgetc(f);
>        if (c == '#')  comment = 1;
>        if (c == '\n') comment = 0;
>    } while (c != EOF && (isspace(c) || comment));
>    ungetc(c, f);
>    return 1;
>}
>
>// ----------
>
>static int load_pnm(char *filename, unsigned char *buf, int w, int h, int yuv)
>{
>    FILE *f = fopen(filename, "rb");
>    int width, height, maxval, y;
>    unsigned char a, b;
>
>    if (!f) {
>       fprintf(stderr, "Can't open %s\n", filename);
>       return 0;
>    }
>    skip(f);
>    a = fgetc(f);
>    b = fgetc(f);
>    if ( yuv && (a != 'P' || b != '5') ) {
>        fprintf(stderr, "%s is not a PGMYUV file\n", filename);
>        return 0;
>    }
>    if ( !yuv && (a != 'P' || b != '6') ) {
>        fprintf(stderr, "%s is not a PPM file\n", filename);
>        return 0;
>    }
>    if ( ( skip(f) && fscanf(f, "%i", &width) &&
>           skip(f) && fscanf(f, "%i", &height) &&
>           skip(f) && fscanf(f, "%i", &maxval) && isspace(fgetc(f)) ) < 1) {
>        fprintf(stderr, "%s has an invalid header\n", filename);
>        return 0;
>    }
>
>    if ( yuv ? (w != width) : (w != width*3) ) {
>       fprintf(stderr, "width of %s doesn't match input video\n", filename);
>       return 0;
>    }
>    if ( yuv ? (h != (height<<1)/3) : (h != height) ) {
>       fprintf(stderr, "height of %s doesn't match input video\n", filename);
>       return 0;
>    }
>    if (maxval != 255) return 0;
>
>    if (fread(buf, w, h, f) != (unsigned) h) {
>        fprintf(stderr, "read error while reading %s\n", filename);
>        return 0;
>    }
>    if (yuv) {
>        for (y=0; y<h/2; y++) {
>            fread(buf+w*h+y*w/2, w/2, 1, f);
>            fread(buf+w*h+w*h/4+y*w/2, w/2, 1, f);
>        }
>    }
>    fclose(f);
>
>    return 1;
>}
>
>/* --------------------------------------------------------------------------*/
>
>static void detect_bounding_box(unsigned char *buf, int w, int h,
>                            int *ystart, int *yend, int *xstart, int *xend)
>{
>    int x, y;
>
>    *ystart = *xstart = INT_MAX;
>    *yend = *xend = 0;
>    for (y=0; y<h; y++) for (x=0; x<w; x++) if (buf[y*w+x]) {
>        *xstart = (x < *xstart) ? x : (*xstart);
>        *xend   = (x > *xend  ) ? x : (*xend);
>        *ystart = (y < *ystart) ? y : (*ystart);
>        *yend   = (y > *yend  ) ? y : (*yend);
>    }
>}
>
>/* --------------------------------------------------------------------------*/
>
>static int config(struct vf_instance_s *vf, int width, int height, int d_width,
>                  int d_height, unsigned int flags, unsigned int outfmt)
>{
>    struct vf_priv_s *priv = vf->priv;
>    int yuv = priv->yuv, wh[3], p;
>
>    setw(priv->width, width, yuv);
>    seth(priv->height, height, yuv);
>    setwh(wh, priv->width, priv->height);
>
>    malloctriple(priv->logo, wh, sizeof(unsigned char));
>    malloctriple(priv->alpha, wh, sizeof(unsigned char));
>
>    priv->config = 1;
>
>    if (load_pnm(priv->logofilename, priv->logo[0], priv->width[0],
>                                                    priv->height[0], yuv) != 1)
>        priv->config = 0;
>    if (load_pnm(priv->alphafilename, priv->alpha[0], priv->width[0],
>                                                    priv->height[0], yuv) != 1)
>        priv->config = 0;
>
>    for (p=0; p<3; p++)
>        detect_bounding_box(priv->alpha[p], priv->width[p], priv->height[p],
>                                        &priv->ystart[p], &priv->yend[p],
>                                        &priv->xstart[p], &priv->xend[p] );
>
>    return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
>}
>
>/* --------------------------------------------------------------------------*/
>
>static void logodeblend(unsigned char *srcplane, unsigned char *dstplane, int w,
>                        int h, int stride, unsigned char *alpha,
>                        unsigned char *logo, int xstart, int xend,
>                        int ystart, int yend)
>{
>    static short int lut[256];
>    static int n = 0;
>    int x, y, v, a, l;
>
>    if (n==0) { for(n=0; n<256; n++) { lut[n] = 32768/(n+1); } }
>
>    srcplane += ystart*stride;
>    dstplane += ystart*stride;
>    alpha += ystart*stride;
>    logo  += ystart*stride;
>    for (y=ystart; y<=yend; y++) {
>        for (x=xstart; x<=xend; x++) {
>            a = alpha[x];
>            if (a == 0 || a == 255) continue;
>            v = srcplane[x];
>            l = logo[x];
>            v = ( (long long) (((v<<8)-(l*a))<<15) * lut[255-a] )>>30;
>            dstplane[x] = CLAMP((int)v);
>        }
>        srcplane += stride;
>        dstplane += stride;
>        alpha += stride;
>        logo  += stride;
>    }
>}
>
>/* --------------------------------------------------------------------------*/
>
>static void logoremove(unsigned char *srcplane, unsigned char *dstplane, int w,
>                       int h, int stride, unsigned char *alpha,
>                       unsigned char *logo, int xstart, int xend,
>                       int ystart, int yend, int black)
>{
>    int x, y, v, a, l;
>
>    srcplane += ystart*stride;
>    dstplane += ystart*stride;
>    alpha += ystart*stride;
>    logo  += ystart*stride;
>    for (y=ystart; y<=yend; y++) {
>        for (x=xstart; x<=xend; x++) {
>            a = alpha[x];
>            if (a == 0) continue;
>            v = srcplane[x];
>            v = black;
>            dstplane[x] = CLAMP((int)v);
>        }
>        srcplane += stride;
>        dstplane += stride;
>        alpha += stride;
>        logo  += stride;
>    }
>}
>
>/* --------------------------------------------------------------------------*/
>
>static int put_image(struct vf_instance_s *vf, mp_image_t *mpi)
>{
>    struct vf_priv_s *priv = vf->priv;
>    unsigned char **logo = priv->logo, **alpha = priv->alpha;
>    int yuv = priv->yuv;
>    mp_image_t *dmpi;
>    int *width = priv->width, *height = priv->height, p;
>    int *xstart = priv->xstart, *xend = priv->xend;
>    int *ystart = priv->ystart, *yend = priv->yend;
>
>    if (!priv->config) return vf_next_put_image(vf,mpi);
>
>    dmpi = vf_get_image(vf->next, IMGFMT_YV12, MP_IMGTYPE_TEMP, 0,
>                                                        width[0], height[0]);
>
>    for (p=0; p<3; p++) {
>        memcpy_pic(dmpi->planes[p], mpi->planes[p], width[p], height[p],
>                                            mpi->stride[p], mpi->stride[p]);
>        if (priv->deblend)
>            logodeblend(mpi->planes[p], dmpi->planes[p], width[p], height[p],
>                    dmpi->stride[p], alpha[p], logo[p], xstart[p], xend[p],
>                                                        ystart[p], yend[p]);
>        else
>            logoremove(mpi->planes[p], dmpi->planes[p], width[p], height[p],
>                    dmpi->stride[p], alpha[p], logo[p], xstart[p], xend[p],
>                    ystart[p], yend[p], (yuv && (p!=0)) ? 128 : 0 );
>
>    }
>
>    return vf_next_put_image(vf,dmpi);
>}
>
>/* --------------------------------------------------------------------------*/
>
>static void uninit(struct vf_instance_s *vf)
>{
>    struct vf_priv_s *priv = vf->priv;
>
>    // free memory
>
>    free(priv->logo[0]);
>    free(priv->alpha[0]);
>    free(priv);
>    vf->priv = NULL;
>}
>
>/* --------------------------------------------------------------------------*/
>
>static int parse_command_line (vf_instance_t *vf, char *args)
>{
>    struct vf_priv_s *priv = vf->priv;
>
>    opt_t subopts[] = {
>        {"logo",    OPT_ARG_MSTRZ, &priv->logofilename, NULL, 0},
>        {"alpha",   OPT_ARG_MSTRZ, &priv->alphafilename, NULL, 0},
>        {"deblend", OPT_ARG_BOOL,  &priv->deblend, NULL, 0},
>        {NULL, 0, NULL, NULL, 0}
>    };
>
>    /* set defaults */
>
>    priv->logofilename = priv->alphafilename = NULL;
>    priv->deblend = 0; /* default is remove */
>
>    if (subopt_parse(args, subopts) != 0) return -1;
>
>    return 1;
>}
>
>/* --------------------------------------------------------------------------*/
>
>static int open (vf_instance_t *vf, char *args)
>{
>    vf->config = config;
>    vf->query_format = query_format;
>    vf->put_image = put_image;
>    vf->uninit = uninit;
>    vf->priv = calloc(1, sizeof(struct vf_priv_s));
>
>    return parse_command_line(vf, args);
>}
>
>/* --------------------------------------------------------------------------*/
>
>vf_info_t vf_info_logoremove = {
>    "Remove/deblend logo",
>    "logoremove",
>    "Ivo van Poorten",
>    "",
>    open,
>    NULL
>};
>
>/* --------------------------------------------------------------------------*/
>
>  
>
>------------------------------------------------------------------------
>
>_______________________________________________
>MPlayer-dev-eng mailing list
>MPlayer-dev-eng at mplayerhq.hu
>http://mplayerhq.hu/mailman/listinfo/mplayer-dev-eng
>  
>




More information about the MPlayer-dev-eng mailing list