[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