Index: libmpcodecs/vf_deflicker.c =================================================================== --- libmpcodecs/vf_deflicker.c (révision 0) +++ libmpcodecs/vf_deflicker.c (révision 0) @@ -0,0 +1,193 @@ +/* + * Histogram-matching based deflicker + * Copyright(C) 2010 Alexandre Janon + * + * This file is part of MPlayer. + * + * MPlayer 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. + * + * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#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; y < mpi->h; y++) { + for (x = 0; x < mpi->w; x++) { + vf->priv->means[x + y * mpi->w] = 0; + for (t = 1; t < vf->priv->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; y < mpi->h; y++) { + for (x = 0; x < mpi->w; 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; y < mpi->h; y++) { + for (x = 0; x < mpi->w; 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; y < mpi->h; y++) { + for (x = 0; x < mpi->w; 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; y < mpi->h; y++) { + for (x = 0; x < mpi->w; 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; y < mpi->h; y++) { + for (x = 0; x < mpi->w; 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,19 @@ .PD 1 . .TP +.B deflicker[=10] +Histogram-matching based deflicker. +.br +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. +.br +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