Index: libmpcodecs/vf_deflicker.c =================================================================== --- libmpcodecs/vf_deflicker.c (révision 0) +++ libmpcodecs/vf_deflicker.c (révision 0) @@ -0,0 +1,161 @@ +/* + * vf_deflicker.c + * Histogram-matching based deflicker. + * Copyright(c) 2010 Alexandre Janon + * + */ + +#include +#include +#include +#include + +#include "mp_msg.h" +#include "mp_image.h" +#include "vf.h" + +#include "m_option.h" +#include "m_struct.h" + +struct vf_priv_s +{ + int nFrames; // current frame number + int h, w; // height and width of the picture + int state; // state of the buffers: -1 notAllocated ; 0 notFilled ; 1 filled + int wSz; // window size (in frames) + unsigned char *buffer; // previous Y data : buffer[x+y*mpi->w+t*mpi->w*mpi->h] contains frame #t, pixel (x,y) + int *means; // moving temporal averages : means[x+y*mpi->w] is the mean of the Y plane, @(x,y), of the wSz last frames +} vf_priv_s; + +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) { + mp_image_t *dmpi; + int n; + int x, y, k, t; + double val; + double h1[256]; // current frame histogram + double h2[256]; // target histogram + double F1[256]; // current frame CDF + double F2[256]; // target CDF + double L[256]; // lookup-table + int doMatch=1; + + dmpi = vf_get_image(vf->next,mpi->imgfmt, MP_IMGTYPE_TEMP, + MP_IMGFLAG_ACCEPT_STRIDE, mpi->w, mpi->h); + + if(vf->priv->state == -1) { // buffer allocation + vf->priv->buffer=malloc(sizeof(unsigned char)*mpi->h*mpi->w*vf->priv->wSz); + vf->priv->means=malloc(sizeof(int)*mpi->h*mpi->w); + vf->priv->state=0; + } + + if(vf->priv->nFrames == vf->priv->wSz) vf->priv->state=1; + + if(vf->priv->state==0) { // buffer fill-in + memcpy(vf->priv->buffer+vf->priv->nFrames*mpi->h*mpi->w, mpi->planes[0], mpi->h*mpi->w); + } + + if(vf->priv->state==1) { + // computation of the moving averages + for(y=0 ; yh ; y++) { + for(x=0 ; xw ; x++) { + vf->priv->means[x+y*mpi->w]=0; + for(t=1 ; tpriv->wSz ; t++) { // todo: be more cache-friendly ? + vf->priv->means[x+y*mpi->w] += vf->priv->buffer[x+y*mpi->w+t*mpi->w*mpi->h]; + vf->priv->buffer[x+y*mpi->w+(t-1)*mpi->w*mpi->h]=vf->priv->buffer[x+y*mpi->w+t*mpi->w*mpi->h]; + } + vf->priv->buffer[x+y*mpi->w+(t-1)*mpi->w*mpi->h]=mpi->planes[0][x+y*mpi->stride[0]]; + vf->priv->means[x+y*mpi->w] += mpi->planes[0][x+y*mpi->stride[0]]; + + vf->priv->means[x+y*mpi->w] = vf->priv->means[x+y*mpi->w]/vf->priv->wSz; + } + } + + if(doMatch) { + // current frame histogram + for(n=0 ; n<256 ; n++) + h1[n]=0; + + for(y=0;yh;y++) { + for(x=0;xw;x++) { + h1[mpi->planes[0][x+mpi->stride[0]*y]] += 1./(mpi->h*mpi->w); + } + } + + val=0; + for(n=0;n<256;n++) { + val += h1[n]; + F1[n]=val; + } + + // moving average histogram + for(n=0 ; n<256 ; n++) + h2[n]=0; + + for(y=0;yh;y++) { + for(x=0;xw;x++) { + h2[vf->priv->means[x+y*mpi->w]] += 1./(mpi->h*mpi->w); + } + } + + val=0; + for(n=0;n<256;n++) { + val += h2[n]; + F2[n]=val; + } + + // histogram matching + for(n=0;n<256;n++) { + for(k=(n==0 ? 0 : F1[n-1]);k<256 && F1[n] > F2[k];k++) ; + L[n]=(k<255 ? k : 255); + } + + // change Y plane + for(y=0;yh;y++) { + for(x=0;xw;x++) { + dmpi->planes[0][x+dmpi->stride[0]*y]=L[mpi->planes[0][x+mpi->stride[0]*y]] ; + } + } + } else { + // don't change Y plane + for(y=0;yh;y++) { + for(x=0;xw;x++) { + dmpi->planes[0][x+dmpi->stride[0]*y]=mpi->planes[0][x+mpi->stride[0]*y] ; + } + } + } + } else { // buffer still not filled-in + memcpy(dmpi->planes[0], mpi->planes[0], mpi->h*mpi->w); + } + + // copy UV plane + for(y=0;yh;y++) { + for(x=0;xw;x++) { + dmpi->planes[2][x+dmpi->stride[2]*y]=mpi->planes[2][x+mpi->stride[2]*y]; + } + } + + vf->priv->nFrames++; + + return vf_next_put_image(vf,dmpi,pts); +} + +static int open(vf_instance_t *vf, char *args) +{ + vf->put_image = put_image; + vf->priv=malloc(sizeof(struct vf_priv_s)); + vf->priv->nFrames=0; + if(!args || !sscanf(args,"%d",&vf->priv->wSz)) + vf->priv->wSz=10; + vf->priv->state=-1; + return 1; +} + +const vf_info_t vf_info_deflicker = { + "Deflickering filter.", + "deflicker", + "Alexandre Janon", + "", + open, + NULL +}; + Index: libmpcodecs/vf.c =================================================================== --- libmpcodecs/vf.c (révision 31179) +++ libmpcodecs/vf.c (copie de travail) @@ -119,6 +119,7 @@ extern const vf_info_t vf_info_geq; extern const vf_info_t vf_info_ow; extern const vf_info_t vf_info_fixpts; +extern const vf_info_t vf_info_deflicker; // list of available filters: static const vf_info_t* const filter_list[]={ @@ -212,6 +213,7 @@ &vf_info_blackframe, &vf_info_ow, &vf_info_fixpts, + &vf_info_deflicker, NULL }; Index: Makefile =================================================================== --- Makefile (révision 31179) +++ Makefile (copie de travail) @@ -445,6 +445,7 @@ libmpcodecs/vf_pullup.c \ libmpcodecs/vf_rectangle.c \ libmpcodecs/vf_remove_logo.c \ + libmpcodecs/vf_deflicker.c \ libmpcodecs/vf_rgb2bgr.c \ libmpcodecs/vf_rgbtest.c \ libmpcodecs/vf_rotate.c \ Index: DOCS/man/en/mplayer.1 =================================================================== --- DOCS/man/en/mplayer.1 (révision 31179) +++ DOCS/man/en/mplayer.1 (copie de travail) @@ -6474,6 +6474,16 @@ .PD 1 . .TP +.B deflicker[=10] +Histogram-matching based deflicker. For each video frame, it builds +a target histogram, based on the average of the previous frames. Then +it matches histogram of the current frame with the target histogram. +The optional argument is the number of frames averaged during target +histogram creation; the correct setting depends on the frequency of +the flicker you want to remove. +.RE +. +.TP .B eq[=brightness:contrast] (OBSOLETE) Software equalizer with interactive controls just like the hardware equalizer, for cards/\:drivers that do not support brightness and