From 43f1708f8bb400790b226993ab1e6c3d12564d3b Mon Sep 17 00:00:00 2001 From: Juanjo Date: Tue, 26 Feb 2002 22:14:27 +0000 Subject: [PATCH] - Added PSNR feature to libavcodec and ffmpeg. By now just Y PSNR until I'm sure it works ok. Also it's slow, so use it only when you _really_ need to measure quality. - Fix libavcodec Makefile to enable profiling. Originally committed as revision 314 to svn://svn.ffmpeg.org/ffmpeg/trunk --- ffmpeg.c | 10 ++++++++++ libavcodec/Makefile | 5 +++++ libavcodec/avcodec.h | 6 ++++++ libavcodec/dsputil.c | 35 +++++++++++++++++++++++++++++++++ libavcodec/dsputil.h | 6 ++++++ libavcodec/i386/mpegvideo_mmx.c | 16 +++++++-------- libavcodec/mpegvideo.c | 6 ++++++ 7 files changed, 76 insertions(+), 8 deletions(-) diff --git a/ffmpeg.c b/ffmpeg.c index 80b1127d7b..5d5431cf26 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -98,6 +98,7 @@ static char *str_comment = NULL; static int do_benchmark = 0; static int do_hex_dump = 0; static int do_play = 0; +static int do_psnr = 0; typedef struct AVOutputStream { int file_index; /* file index */ @@ -958,6 +959,8 @@ static int av_encode(AVFormatContext **output_files, frame_number = ist->frame_number; sprintf(buf + strlen(buf), "frame=%5d q=%2d ", frame_number, enc->quality); + if (do_psnr) + sprintf(buf + strlen(buf), "PSNR=%6.2f ", enc->psnr_y); vid = 1; } /* compute min pts value */ @@ -1006,6 +1009,8 @@ static int av_encode(AVFormatContext **output_files, frame_number = ist->frame_number; sprintf(buf + strlen(buf), "frame=%5d q=%2d ", frame_number, enc->quality); + if (do_psnr) + sprintf(buf + strlen(buf), "PSNR=%6.2f ", enc->psnr_y); vid = 1; } /* compute min pts value */ @@ -1618,6 +1623,10 @@ void opt_output_file(const char *filename) video_enc->flags |= CODEC_FLAG_QSCALE; video_enc->quality = video_qscale; } + if (do_psnr) + video_enc->get_psnr = 1; + else + video_enc->get_psnr = 0; /* XXX: need to find a way to set codec parameters */ if (oc->format == &ppm_format || oc->format == &ppmpipe_format) { @@ -1960,6 +1969,7 @@ const OptionDef options[] = { "add timings for benchmarking" }, { "hex", OPT_BOOL | OPT_EXPERT, {(void*)&do_hex_dump}, "dump each input packet" }, + { "psnr", OPT_BOOL | OPT_EXPERT, {(void*)&do_psnr}, "calculate PSNR of compressed frames" }, { NULL, }, }; diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 4898e86a55..fe124a4a1c 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -16,6 +16,11 @@ OBJS+= ac3dec.o \ libac3/imdct.o libac3/parse.o endif +ifeq ($(TARGET_GPROF),yes) +CFLAGS+=-p +LDFLAGS+=-p +endif + # i386 mmx specific stuff ifeq ($(TARGET_MMX),yes) OBJS += i386/fdct_mmx.o i386/cputest.o \ diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index cc374c1cab..d8abfded9b 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -123,6 +123,12 @@ typedef struct AVCodecContext { /* with a Start Code (it should) H.263 does */ void (*rtp_callback)(void *data, int size, int packet_number); + /* These are for PSNR calculation, if you set get_psnr to 1 */ + /* after encoding you will have the PSNR on psnr_y/cb/cr */ + int get_psnr; + float psnr_y; + float psnr_cb; + float psnr_cr; /* the following fields are ignored */ void *opaque; /* can be used to carry app specific stuff */ diff --git a/libavcodec/dsputil.c b/libavcodec/dsputil.c index 701cb9969a..09c4c231fe 100644 --- a/libavcodec/dsputil.c +++ b/libavcodec/dsputil.c @@ -18,6 +18,7 @@ */ #include #include +#include #include "avcodec.h" #include "dsputil.h" #include "simple_idct.h" @@ -576,3 +577,37 @@ void dsputil_init(void) build_zigzag_end(); } + +void get_psnr(UINT8 *orig_image[3], UINT8 *coded_image[3], + int orig_linesize[3], int coded_linesize, + AVCodecContext *avctx) +{ + int quad, diff, x, y; + UINT8 *orig, *coded; + UINT32 *sq = squareTbl + 256; + + quad = 0; + diff = 0; + + /* Luminance */ + orig = orig_image[0]; + coded = coded_image[0]; + + for (y=0;yheight;y++) { + for (x=0;xwidth;x++) { + diff = *(orig + x) - *(coded + x); + quad += sq[diff]; + } + orig += orig_linesize[0]; + coded += coded_linesize; + } + + avctx->psnr_y = (float) quad / (float) (avctx->width * avctx->height); + + if (avctx->psnr_y) { + avctx->psnr_y = (float) (255 * 255) / avctx->psnr_y; + avctx->psnr_y = 10 * (float) log10 (avctx->psnr_y); + } else + avctx->psnr_y = 99.99; +} + diff --git a/libavcodec/dsputil.h b/libavcodec/dsputil.h index bb57b09433..ed264c83b7 100644 --- a/libavcodec/dsputil.h +++ b/libavcodec/dsputil.h @@ -2,6 +2,7 @@ #define DSPUTIL_H #include "common.h" +#include "avcodec.h" /* dct code */ typedef short DCTELEM; @@ -138,4 +139,9 @@ void dsputil_init_alpha(void); #endif +/* PSNR */ +void get_psnr(UINT8 *orig_image[3], UINT8 *coded_image[3], + int orig_linesize[3], int coded_linesize, + AVCodecContext *avctx); + #endif diff --git a/libavcodec/i386/mpegvideo_mmx.c b/libavcodec/i386/mpegvideo_mmx.c index 017e3d4881..f23bdd827a 100644 --- a/libavcodec/i386/mpegvideo_mmx.c +++ b/libavcodec/i386/mpegvideo_mmx.c @@ -96,14 +96,14 @@ static void dct_unquantize_h263_mmx(MpegEncContext *s, block[0] = block[0] * s->c_dc_scale; } for(i=1; i<8; i++) { - level = block[i]; - if (level) { - if (level < 0) { - level = level * qmul - qadd; - } else { - level = level * qmul + qadd; - } - block[i] = level; + level = block[i]; + if (level) { + if (level < 0) { + level = level * qmul - qadd; + } else { + level = level * qmul + qadd; + } + block[i] = level; } } nCoeffs=64; diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index 7c866b794d..6c4e372e1a 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -522,6 +522,12 @@ int MPV_encode_picture(AVCodecContext *avctx, s->total_bits += (pbBufPtr(&s->pb) - s->pb.buf) * 8; avctx->quality = s->qscale; + if (avctx->get_psnr) { + /* At this point pict->data should have the original frame */ + /* an s->current_picture should have the coded/decoded frame */ + get_psnr(pict->data, s->current_picture, + pict->linesize, s->linesize, avctx); + } return pbBufPtr(&s->pb) - s->pb.buf; }