[FFmpeg-devel] [PATCH] libavfilter: created a new filter that obtains the average peak signal-to-noise ratio (PSNR) of two input video files in YUV format.

Michael Niedermayer michaelni at gmx.at
Mon Jul 18 11:36:07 CEST 2011


On Mon, Jul 04, 2011 at 07:22:26PM +0200, Stefano Sabatini wrote:
> On date Thursday 2011-06-23 14:57:59 +0200, Stefano Sabatini encoded:
> > On date Thursday 2011-06-23 14:07:51 +0200, Roger Pau Monné encoded:
> > > 2011/6/23 Stefano Sabatini <stefano.sabatini-lala at poste.it>:
> > > > On date Tuesday 2011-06-21 16:01:36 +0200, Stefano Sabatini encoded:
> > > >> On date Tuesday 2011-06-21 14:44:50 +0200, Roger Pau Monné encoded:
> > > >> > Hello,
> > > >> >
[..]
> +static inline int pow2(int base)
> +{
> +    return base*base;
> +}
> +
> +static inline double get_psnr(double mse, int nb_frames, int max)
> +{
> +    return 10.0*log((pow2(max))/(mse/nb_frames))/log(10.0);
> +}
> +
> +static inline
> +void compute_images_mse(const uint8_t *ref_data[4],
> +                        const uint8_t *data[4], const int linesizes[4],
> +                        int w, int h, const AVPixFmtDescriptor *desc,
> +                        double mse[4], uint16_t *line1, uint16_t *line2)
> +{
> +    int i, c, j = w;
> +
> +    memset(mse, 0, sizeof(*mse)*4);
> +
> +    for (c = 0; c < desc->nb_components; c++) {
> +        int w1 = c == 1 || c == 2 ? w>>desc->log2_chroma_w : w;
> +        int h1 = c == 1 || c == 2 ? h>>desc->log2_chroma_h : h;
> +
> +        for (i = 0; i < h1; i++) {
> +            av_read_image_line(line1, ref_data, linesizes, desc, 0, i, c, w1, 0);
> +            av_read_image_line(line2, data,     linesizes, desc, 0, i, c, w1, 0);
> +            for (j = 0; j < w1; j++)
> +                mse[c] += pow2(line1[j] - line2[j]);
> +        }
> +        mse[c] /= w1*h1;
> +    }
> +}

This is a bit slow, i think there should be specific optimized code
for planar yuv as its most common.
also id avoid the int->double per sample and sum all samples of a
line (or each 100 samples) in 32bit int and only after that change to
a type with more range


[...]
> +static int config_input_ref(AVFilterLink *inlink)
> +{
> +    AVFilterContext *ctx  = inlink->dst;
> +    PSNRContext *psnr = ctx->priv;
> +
> +    if (ctx->inputs[0]->w != ctx->inputs[1]->w ||
> +        ctx->inputs[0]->h != ctx->inputs[1]->h) {
> +        av_log(ctx, AV_LOG_ERROR,
> +               "Width and/or heigth of input videos are different, could not calculate PSNR\n");
> +        return AVERROR(EINVAL);
> +    }
> +    if (ctx->inputs[0]->format != ctx->inputs[1]->format) {
> +        av_log(ctx, AV_LOG_ERROR,
> +               "Input filters have different pixel formats, could not calculate PSNR\n");
> +        return AVERROR(EINVAL);
> +    }
> +
> +    if (!(psnr->line1 = av_malloc(sizeof(*psnr->line1) * inlink->w)) ||
> +        !(psnr->line2 = av_malloc(sizeof(*psnr->line2) * inlink->w)))
> +        return AVERROR(ENOMEM);
> +
> +    switch (inlink->format) {
> +    case PIX_FMT_YUV410P:
> +    case PIX_FMT_YUV411P:
> +    case PIX_FMT_YUV420P:
> +    case PIX_FMT_YUV422P:
> +    case PIX_FMT_YUV440P:
> +    case PIX_FMT_YUV444P:
> +    case PIX_FMT_YUVA420P:
> +        psnr->max[0] = 235;
> +        psnr->max[3] = 255;
> +        psnr->max[1] = psnr->max[2] = 240;
> +        break;
> +    default:
> +        psnr->max[0] = psnr->max[1] = psnr->max[2] = psnr->max[3] = 255;
> +    }
> +
> +    if      (ff_fmt_is_in(inlink->format, yuv_pix_fmts)) psnr->is_yuv = 1;
> +    else if (ff_fmt_is_in(inlink->format, rgb_pix_fmts)) psnr->is_rgb = 1;
> +
> +    if (psnr->is_rgb) {
> +        switch (inlink->format) {
> +        case PIX_FMT_ARGB:  psnr->rgba_map[A] = 0; psnr->rgba_map[R] = 1; psnr->rgba_map[G] = 2; psnr->rgba_map[B] = 3; break;
> +        case PIX_FMT_ABGR:  psnr->rgba_map[A] = 0; psnr->rgba_map[B] = 1; psnr->rgba_map[G] = 2; psnr->rgba_map[R] = 3; break;
> +        case PIX_FMT_RGBA:
> +        case PIX_FMT_RGB24: psnr->rgba_map[R] = 0; psnr->rgba_map[G] = 1; psnr->rgba_map[B] = 2; psnr->rgba_map[A] = 3; break;
> +        case PIX_FMT_BGRA:
> +        case PIX_FMT_BGR24: psnr->rgba_map[B] = 0; psnr->rgba_map[G] = 1; psnr->rgba_map[R] = 2; psnr->rgba_map[A] = 3; break;
> +        }
> +    }
> +
> +    for(int j = 0; j < av_pix_fmt_descriptors[inlink->format].nb_components; j++)
> +        psnr->average_max += psnr->max[j];
> +    psnr->average_max /= av_pix_fmt_descriptors[inlink->format].nb_components;

the 3 planes mse should be rescaled before adding them together

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

If you think the mosad wants you dead since a long time then you are either
wrong or dead since a long time.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20110718/6b21468f/attachment.asc>


More information about the ffmpeg-devel mailing list