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/trunktags/v0.5
| @@ -98,6 +98,7 @@ static char *str_comment = NULL; | |||||
| static int do_benchmark = 0; | static int do_benchmark = 0; | ||||
| static int do_hex_dump = 0; | static int do_hex_dump = 0; | ||||
| static int do_play = 0; | static int do_play = 0; | ||||
| static int do_psnr = 0; | |||||
| typedef struct AVOutputStream { | typedef struct AVOutputStream { | ||||
| int file_index; /* file index */ | int file_index; /* file index */ | ||||
| @@ -958,6 +959,8 @@ static int av_encode(AVFormatContext **output_files, | |||||
| frame_number = ist->frame_number; | frame_number = ist->frame_number; | ||||
| sprintf(buf + strlen(buf), "frame=%5d q=%2d ", | sprintf(buf + strlen(buf), "frame=%5d q=%2d ", | ||||
| frame_number, enc->quality); | frame_number, enc->quality); | ||||
| if (do_psnr) | |||||
| sprintf(buf + strlen(buf), "PSNR=%6.2f ", enc->psnr_y); | |||||
| vid = 1; | vid = 1; | ||||
| } | } | ||||
| /* compute min pts value */ | /* compute min pts value */ | ||||
| @@ -1006,6 +1009,8 @@ static int av_encode(AVFormatContext **output_files, | |||||
| frame_number = ist->frame_number; | frame_number = ist->frame_number; | ||||
| sprintf(buf + strlen(buf), "frame=%5d q=%2d ", | sprintf(buf + strlen(buf), "frame=%5d q=%2d ", | ||||
| frame_number, enc->quality); | frame_number, enc->quality); | ||||
| if (do_psnr) | |||||
| sprintf(buf + strlen(buf), "PSNR=%6.2f ", enc->psnr_y); | |||||
| vid = 1; | vid = 1; | ||||
| } | } | ||||
| /* compute min pts value */ | /* compute min pts value */ | ||||
| @@ -1618,6 +1623,10 @@ void opt_output_file(const char *filename) | |||||
| video_enc->flags |= CODEC_FLAG_QSCALE; | video_enc->flags |= CODEC_FLAG_QSCALE; | ||||
| video_enc->quality = video_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 */ | /* XXX: need to find a way to set codec parameters */ | ||||
| if (oc->format == &ppm_format || | if (oc->format == &ppm_format || | ||||
| oc->format == &ppmpipe_format) { | oc->format == &ppmpipe_format) { | ||||
| @@ -1960,6 +1969,7 @@ const OptionDef options[] = { | |||||
| "add timings for benchmarking" }, | "add timings for benchmarking" }, | ||||
| { "hex", OPT_BOOL | OPT_EXPERT, {(void*)&do_hex_dump}, | { "hex", OPT_BOOL | OPT_EXPERT, {(void*)&do_hex_dump}, | ||||
| "dump each input packet" }, | "dump each input packet" }, | ||||
| { "psnr", OPT_BOOL | OPT_EXPERT, {(void*)&do_psnr}, "calculate PSNR of compressed frames" }, | |||||
| { NULL, }, | { NULL, }, | ||||
| }; | }; | ||||
| @@ -16,6 +16,11 @@ OBJS+= ac3dec.o \ | |||||
| libac3/imdct.o libac3/parse.o | libac3/imdct.o libac3/parse.o | ||||
| endif | endif | ||||
| ifeq ($(TARGET_GPROF),yes) | |||||
| CFLAGS+=-p | |||||
| LDFLAGS+=-p | |||||
| endif | |||||
| # i386 mmx specific stuff | # i386 mmx specific stuff | ||||
| ifeq ($(TARGET_MMX),yes) | ifeq ($(TARGET_MMX),yes) | ||||
| OBJS += i386/fdct_mmx.o i386/cputest.o \ | OBJS += i386/fdct_mmx.o i386/cputest.o \ | ||||
| @@ -123,6 +123,12 @@ typedef struct AVCodecContext { | |||||
| /* with a Start Code (it should) H.263 does */ | /* with a Start Code (it should) H.263 does */ | ||||
| void (*rtp_callback)(void *data, int size, int packet_number); | 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 */ | /* the following fields are ignored */ | ||||
| void *opaque; /* can be used to carry app specific stuff */ | void *opaque; /* can be used to carry app specific stuff */ | ||||
| @@ -18,6 +18,7 @@ | |||||
| */ | */ | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <math.h> | |||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "dsputil.h" | #include "dsputil.h" | ||||
| #include "simple_idct.h" | #include "simple_idct.h" | ||||
| @@ -576,3 +577,37 @@ void dsputil_init(void) | |||||
| build_zigzag_end(); | 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;y<avctx->height;y++) { | |||||
| for (x=0;x<avctx->width;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; | |||||
| } | |||||
| @@ -2,6 +2,7 @@ | |||||
| #define DSPUTIL_H | #define DSPUTIL_H | ||||
| #include "common.h" | #include "common.h" | ||||
| #include "avcodec.h" | |||||
| /* dct code */ | /* dct code */ | ||||
| typedef short DCTELEM; | typedef short DCTELEM; | ||||
| @@ -138,4 +139,9 @@ void dsputil_init_alpha(void); | |||||
| #endif | #endif | ||||
| /* PSNR */ | |||||
| void get_psnr(UINT8 *orig_image[3], UINT8 *coded_image[3], | |||||
| int orig_linesize[3], int coded_linesize, | |||||
| AVCodecContext *avctx); | |||||
| #endif | #endif | ||||
| @@ -96,14 +96,14 @@ static void dct_unquantize_h263_mmx(MpegEncContext *s, | |||||
| block[0] = block[0] * s->c_dc_scale; | block[0] = block[0] * s->c_dc_scale; | ||||
| } | } | ||||
| for(i=1; i<8; i++) { | 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; | nCoeffs=64; | ||||
| @@ -522,6 +522,12 @@ int MPV_encode_picture(AVCodecContext *avctx, | |||||
| s->total_bits += (pbBufPtr(&s->pb) - s->pb.buf) * 8; | s->total_bits += (pbBufPtr(&s->pb) - s->pb.buf) * 8; | ||||
| avctx->quality = s->qscale; | 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; | return pbBufPtr(&s->pb) - s->pb.buf; | ||||
| } | } | ||||