[xiph-commits] r15824 - in branches/theora-thusnelda: examples lib lib/enc tests
tterribe at svn.xiph.org
tterribe at svn.xiph.org
Sat Mar 21 14:09:30 PDT 2009
Author: tterribe
Date: 2009-03-21 14:09:30 -0700 (Sat, 21 Mar 2009)
New Revision: 15824
Modified:
branches/theora-thusnelda/examples/Makefile.am
branches/theora-thusnelda/examples/dump_psnr.c
branches/theora-thusnelda/lib/Makefile.am
branches/theora-thusnelda/lib/enc/encoder_toplevel.c
branches/theora-thusnelda/tests/Makefile.am
Log:
Convert rate control code to fixed point.
Also add an option to dump_psnr to show frame type/quantizer for Theora files.
Modified: branches/theora-thusnelda/examples/Makefile.am
===================================================================
--- branches/theora-thusnelda/examples/Makefile.am 2009-03-21 20:22:37 UTC (rev 15823)
+++ branches/theora-thusnelda/examples/Makefile.am 2009-03-21 21:09:30 UTC (rev 15824)
@@ -10,7 +10,7 @@
AM_CFLAGS = $(OGG_CFLAGS)
LDADD = ../lib/libtheora.la $(OGG_LIBS)
LDADDDEC = ../lib/libtheoradec.la $(OGG_LIBS)
-LDADDENC = ../lib/libtheoraenc.la ../lib/libtheoradec.la $(OGG_LIBS) -lm
+LDADDENC = ../lib/libtheoraenc.la ../lib/libtheoradec.la $(OGG_LIBS)
dump_video_SOURCES = dump_video.c
EXTRA_dump_video_SOURCES = getopt.c getopt1.c getopt.h
@@ -34,7 +34,7 @@
png2theora_SOURCES = png2theora.c
png2theora_CFLAGS = $(OGG_CFLAGS) $(PNG_CFLAGS)
-png2theora_LDADD = $(GETOPT_OBJS) $(LDADD) $(PNG_LIBS) -lm
+png2theora_LDADD = $(GETOPT_OBJS) $(LDADD) $(PNG_LIBS)
png2theora_DEPENDENCIES = $(GETOPT_OBJS)
debug:
Modified: branches/theora-thusnelda/examples/dump_psnr.c
===================================================================
--- branches/theora-thusnelda/examples/dump_psnr.c 2009-03-21 20:22:37 UTC (rev 15823)
+++ branches/theora-thusnelda/examples/dump_psnr.c 2009-03-21 21:09:30 UTC (rev 15824)
@@ -49,13 +49,18 @@
#include <signal.h>
#include "theora/theoradec.h"
-const char *optstring = "ys";
+const char *optstring = "fsy";
struct option options [] = {
+ {"frame-type",no_argument,NULL,'f'},
+ {"summary",no_argument,NULL,'s'},
{"luma-only",no_argument,NULL,'y'},
- {"summary",no_argument,NULL,'s'},
{NULL,0,NULL,0}
};
+static int show_frame_type;
+static int summary_only;
+static int luma_only;
+
typedef struct y4m_input y4m_input;
/*The function used to perform chroma conversion.*/
@@ -945,6 +950,11 @@
if(ogg_stream_packetout(&_th->to,&op)>0){
if(th_decode_packetin(_th->td,&op,NULL)>=0){
th_decode_ycbcr_out(_th->td,_ycbcr);
+ if(!summary_only&&show_frame_type){
+ printf("%c",th_packet_iskeyframe(&op)?'K':'D');
+ if(op.bytes>0)printf("%02i ",op.packet[0]&0x3F);
+ else printf("-- ");
+ }
return 1;
}
else return -1;
@@ -1026,8 +1036,9 @@
fprintf(stderr,"Usage: %s [options] <video1> <video2>\n"
" <video1> and <video1> may be either YUV4MPEG or Ogg Theora files.\n\n"
" Options:\n\n"
- " -y --luma-only Only output values for the luma channel.\n"
- " -s --summary Only output the summary line.\n",_argv[0]);
+ " -f --frame-type Show frame type and QI value for each Theora frame.\n"
+ " -s --summary Only output the summary line.\n"
+ " -y --luma-only Only output values for the luma channel.\n",_argv[0]);
}
int main(int _argc,char *_argv[]){
@@ -1039,8 +1050,6 @@
ogg_int64_t gnpixels;
ogg_int64_t gplsqerr[3];
ogg_int64_t gplnpixels[3];
- int luma_only;
- int summary_only;
int frameno;
FILE *fin;
int long_option_index;
@@ -1052,13 +1061,12 @@
Don't add any more, you'll probably go to hell if you do.*/
_setmode(_fileno(stdin),_O_BINARY);
#endif
- luma_only=0;
- summary_only=0;
/*Process option arguments.*/
while((c=getopt_long(_argc,_argv,optstring,options,&long_option_index))!=EOF){
switch(c){
+ case 'f':show_frame_type=1;break;
+ case 's':summary_only=1;break;
case 'y':luma_only=1;break;
- case 's':summary_only=1;break;
default:usage(_argv);break;
}
}
Modified: branches/theora-thusnelda/lib/Makefile.am
===================================================================
--- branches/theora-thusnelda/lib/Makefile.am 2009-03-21 20:22:37 UTC (rev 15823)
+++ branches/theora-thusnelda/lib/Makefile.am 2009-03-21 21:09:30 UTC (rev 15824)
@@ -37,6 +37,7 @@
enc/encoder_quant.c \
enc/frarray.c \
enc/frinit.c \
+ enc/mathops.c \
enc/mcenc.c \
enc/mode.c \
enc/reconstruct.c
@@ -98,6 +99,7 @@
enc/encoder_lookup.h \
enc/enquant.h \
enc/hufftables.h \
+ enc/mathops.h \
enc/mode_select.h \
enc/quant_lookup.h \
enc/toplevel_lookup.h \
@@ -127,7 +129,7 @@
Version_script-enc
libtheoraenc_la_LDFLAGS = \
-version-info @THENC_LIB_CURRENT@:@THENC_LIB_REVISION@:@THENC_LIB_AGE@ \
- @THEORAENC_LDFLAGS@ $(OGG_LIBS) -lm
+ @THEORAENC_LDFLAGS@ $(OGG_LIBS)
libtheora_la_SOURCES = \
$(decoder_arch_sources) \
@@ -137,7 +139,7 @@
Version_script
libtheora_la_LDFLAGS = \
-version-info @TH_LIB_CURRENT@:@TH_LIB_REVISION@:@TH_LIB_AGE@ \
- @THEORA_LDFLAGS@ @CAIRO_LIBS@ $(OGG_LIBS) -lm
+ @THEORA_LDFLAGS@ @CAIRO_LIBS@ $(OGG_LIBS)
debug:
$(MAKE) all CFLAGS="@DEBUG@"
Modified: branches/theora-thusnelda/lib/enc/encoder_toplevel.c
===================================================================
--- branches/theora-thusnelda/lib/enc/encoder_toplevel.c 2009-03-21 20:22:37 UTC (rev 15823)
+++ branches/theora-thusnelda/lib/enc/encoder_toplevel.c 2009-03-21 21:09:30 UTC (rev 15824)
@@ -25,55 +25,24 @@
#include "../internal.h"
#include "dsp.h"
#include "codec_internal.h"
+#include "mathops.h"
-static int _ilog(unsigned int v){
- int ret=0;
- while(v){
- ret++;
- v>>=1;
- }
- return(ret);
-}
-static int oc_log2frac(ogg_uint32_t _val,int _frac_bits){
- int l;
- l=_ilog(_val);
- if(l>16)_val>>=l-16;
- else _val<<=16-l;
- l--;
- while(_frac_bits-->0){
- int b;
- _val=_val*_val>>15;
- b=(int)(_val>>16);
- l=l<<1|b;
- _val>>=b;
- }
- return l;
-}
-static ogg_uint16_t oc_exp2(int _log){
- int ipart;
- ogg_uint32_t fpart;
- ipart=_log>>12;
- if(ipart>15)return 0xFFFF;
- else if(ipart<0)return 0;
- fpart=_log-(ipart<<12)<<3;
- /*3rd order polynomial approximation in Q15:
- (((3*log(2)-2)*f+3-4*log(2))*f+log(2))*f+1*/
- fpart=(fpart*((fpart*((fpart*2603>>15)+7452)>>15)+22713)>>15)+32768;
- if(ipart<15)fpart+=1<<14-ipart;
- return fpart>>15-ipart;
-}
-
static void oc_enc_calc_lambda(CP_INSTANCE *cpi){
- int l;
+ ogg_int64_t l;
/*For now, lambda is fixed depending on the qi value and frame type:
lambda=1.125*(qavg[qti][qi]**1.5)
A more adaptive scheme might perform better, but Theora's behavior does not
seem to conform to existing models in the literature.*/
- l=oc_log2frac(cpi->qavg[cpi->FrameType!=KEY_FRAME][cpi->BaseQ],12)-(3<<12);
- l=oc_exp2(l+(l>>1));
- cpi->lambda=l+(l>>3);
+ l=oc_blog64(cpi->qavg[cpi->FrameType!=KEY_FRAME][cpi->BaseQ]);
+ l-=(ogg_int64_t)3<<57;
+ /*Raise to the 1.5 power.*/
+ l+=(l>>1);
+ /*Multiply by 1.125.*/
+ l+=0x00570068E7EF5A1ELL;
+ /*The upper bound here is 0x48000.*/
+ cpi->lambda=(int)oc_bexp64(l);
}
@@ -136,12 +105,18 @@
static void oc_enc_update_rc_state(CP_INSTANCE *cpi,
long _bits,int _qti,int _qi,int _trial){
- unsigned scale;
- unsigned long npixels;
+ ogg_int64_t log_scale;
+ ogg_int64_t log_npixels;
+ ogg_int64_t log_bits;
+ ogg_int64_t log_qexp;
+ ogg_uint32_t scale;
/*Compute the estimated scale factor for this frame type.*/
- npixels=cpi->info.width*(unsigned long)cpi->info.height;
- scale=(int)(256.0*_bits/(npixels*
- pow(cpi->qavg[_qti][_qi]/32.0,cpi->rc.exp[_qti]/-64.0))+0.5);
+ log_bits=oc_blog64(_bits);
+ log_npixels=oc_blog64(cpi->info.width*(ogg_int64_t)cpi->info.height);
+ log_qexp=oc_blog64(cpi->qavg[_qti][_qi])-((ogg_int64_t)5<<57);
+ log_qexp=(log_qexp>>6)*(cpi->rc.exp[_qti]);
+ log_scale=((ogg_int64_t)8<<57)+log_bits-log_npixels+log_qexp;
+ scale=(ogg_uint32_t)oc_bexp64(OC_MINI(log_scale,(ogg_int64_t)16<<57));
/*Use it to set that factor directly if this was a trial.*/
if(_trial)cpi->rc.scale[_qti]=scale;
/*Otherwise update an exponential moving average.*/
@@ -150,7 +125,11 @@
+(cpi->rc.scale[_qti]-scale)*OC_RATE_SMOOTHING[_qti]>>16;
}
/*Update the buffer fullness level.*/
- if(!_trial)cpi->rc.fullness+=cpi->rc.bits_per_frame-_bits;
+ if(!_trial){
+ cpi->rc.fullness+=cpi->rc.bits_per_frame-_bits;
+ /*If we're too quick filling the buffer, that rate is lost forever.*/
+ if(cpi->rc.fullness>cpi->rc.max)cpi->rc.fullness=cpi->rc.max;
+ }
}
static int oc_enc_select_qi(CP_INSTANCE *cpi,int _qti,int _trial){
@@ -158,6 +137,10 @@
ogg_uint32_t next_key_frame;
int nframes[2];
int buf_delay;
+ int qtarget;
+ int best_qi;
+ int best_qdiff;
+ int qi;
/*Figure out how to re-distribute bits so that we hit our fullness target
before the last keyframe in our current buffer window (after the current
frame), or the end of the buffer window, whichever comes first.*/
@@ -174,62 +157,78 @@
+buf_delay*cpi->rc.bits_per_frame;
/*If there aren't enough bits to achieve our desired fullness level, use the
minimum quality permitted.*/
- if(rate_total<=0)return cpi->info.quality;
+ if(rate_total<=0)qtarget=OC_QUANT_MAX<<3;
else{
- static const double KEY_RATIO[2]={0.53125,1.0};
- unsigned long npixels;
- double prevr;
- double curr;
- int qtarget;
- int best_qi;
- int best_qdiff;
- int qi;
+ static const unsigned char KEY_RATIO[2]={29,32};
+ ogg_int64_t log_npixels;
+ ogg_int64_t log_scale0;
+ ogg_int64_t log_scale1;
+ ogg_int64_t prevr;
+ ogg_int64_t curr;
+ ogg_int64_t realr;
+ ogg_int64_t log_qtarget;
int i;
- npixels=cpi->info.width*(unsigned long)cpi->info.height;
- curr=rate_total/(double)buf_delay;
+ log_npixels=oc_blog64(cpi->info.width*(ogg_int64_t)cpi->info.height);
+ log_scale0=oc_blog64(cpi->rc.scale[_qti])-((ogg_int64_t)8<<57)+log_npixels;
+ log_scale1=oc_blog64(cpi->rc.scale[1-_qti])-((ogg_int64_t)8<<57)
+ +log_npixels;
+ curr=(rate_total+(buf_delay>>1))/buf_delay;
+ realr=curr*KEY_RATIO[_qti]+16>>5;
for(i=0;i<10;i++){
- double rdiff;
- double rderiv;
- double exp;
- double rpow;
+ ogg_int64_t rdiff;
+ ogg_int64_t rderiv;
+ ogg_int64_t log_rpow;
+ ogg_int64_t rscale;
+ ogg_int64_t drscale;
+ ogg_int64_t mask;
+ ogg_int64_t bias;
prevr=curr;
- exp=cpi->rc.exp[1-_qti]/(double)cpi->rc.exp[_qti];
- rpow=pow(prevr*256.0/(npixels*(double)cpi->rc.scale[_qti]),exp);
- rdiff=(nframes[_qti]*KEY_RATIO[_qti])*prevr
- +nframes[1-_qti]*KEY_RATIO[1-_qti]*cpi->rc.scale[1-_qti]/256.0*npixels*
- rpow-rate_total;
- rderiv=nframes[_qti]*KEY_RATIO[_qti]+
- (nframes[1-_qti]*KEY_RATIO[1-_qti]*cpi->rc.scale[1-_qti]/256.0*npixels*
- rpow)*(exp/prevr);
- curr=prevr-rdiff/rderiv;
- if(curr<=0||KEY_RATIO[_qti]*curr>rate_total||fabs(prevr-curr)<1)break;
+ log_rpow=oc_blog64(prevr)-log_scale0;
+ log_rpow=(log_rpow+(cpi->rc.exp[_qti]>>1))/cpi->rc.exp[_qti]*
+ cpi->rc.exp[1-_qti];
+ rscale=nframes[1-_qti]*KEY_RATIO[1-_qti]*
+ oc_bexp64(log_scale1+log_rpow);
+ rdiff=nframes[_qti]*KEY_RATIO[_qti]*prevr+rscale-(rate_total<<5);
+ drscale=(rscale+(cpi->rc.exp[_qti]>>1))/cpi->rc.exp[_qti]*
+ cpi->rc.exp[1-_qti]/prevr;
+ rderiv=nframes[_qti]*KEY_RATIO[_qti]+drscale;
+ if(rderiv==0)break;
+ mask=OC_SIGNMASK(rdiff)^OC_SIGNMASK(rderiv);
+ bias=rderiv+mask^mask;
+ curr=prevr-((rdiff<<1)+bias)/(rderiv<<1);
+ realr=curr*KEY_RATIO[_qti]+16>>5;
+ if(curr<=0||realr>rate_total||prevr==curr)break;
}
- qtarget=(int)(32*pow(KEY_RATIO[_qti]*curr*256/
- (npixels*(double)cpi->rc.scale[_qti]),-64.0/cpi->rc.exp[_qti])+0.5);
- /*If this was not one of the initial frames, limit a change in quality.*/
- if(!_trial){
- int qmin;
- int qmax;
- qmin=cpi->qavg[_qti][cpi->BaseQ]*13>>4;
- qmax=cpi->qavg[_qti][cpi->BaseQ]*5>>2;
- qtarget=OC_CLAMPI(qmin,qtarget,qmax);
+ log_qtarget=((ogg_int64_t)5<<57)-
+ ((oc_blog64(realr)-log_scale0+(cpi->rc.exp[_qti]>>1))/
+ cpi->rc.exp[_qti]<<6);
+ qtarget=(int)oc_bexp64(OC_MINI(log_qtarget,(ogg_int64_t)15<<57));
+ }
+ /*If this was not one of the initial frames, limit a change in quality.*/
+ if(!_trial){
+ int qmin;
+ int qmax;
+ /*TODO: With user-specified quant matrices, we need to enlarge these limits
+ if they don't actually let us change qi values.*/
+ qmin=cpi->qavg[_qti][cpi->BaseQ]*13>>4;
+ qmax=cpi->qavg[_qti][cpi->BaseQ]*5>>2;
+ qtarget=OC_CLAMPI(qmin,qtarget,qmax);
+ }
+ /*Search for the quantizer that matches the target most closely.
+ We don't assume a linear ordering, but when there are ties we do pick the
+ quantizer closest to the current one.*/
+ best_qi=cpi->info.quality;
+ best_qdiff=abs(cpi->qavg[_qti][best_qi]-qtarget);
+ for(qi=cpi->info.quality+1;qi<64;qi++){
+ int qdiff;
+ qdiff=abs(cpi->qavg[_qti][qi]-qtarget);
+ if(qdiff<best_qdiff||
+ qdiff==best_qdiff&&abs(qi-cpi->BaseQ)<abs(best_qi-cpi->BaseQ)){
+ best_qi=qi;
+ best_qdiff=qdiff;
}
- /*Search for the quantizer that matches the target most closely.
- We don't assume a linear ordering, but when there are ties we do pick the
- quantizer closest to the current one.*/
- best_qi=cpi->info.quality;
- best_qdiff=abs(cpi->qavg[_qti][best_qi]-qtarget);
- for(qi=cpi->info.quality+1;qi<64;qi++){
- int qdiff;
- qdiff=abs(cpi->qavg[_qti][qi]-qtarget);
- if(qdiff<best_qdiff||
- qdiff==best_qdiff&&abs(qi-cpi->BaseQ)<abs(best_qi-cpi->BaseQ)){
- best_qi=qi;
- best_qdiff=qdiff;
- }
- }
- return best_qi;
}
+ return best_qi;
}
@@ -344,7 +343,7 @@
if(c->keyframe_mindistance>32768)c->keyframe_mindistance=32768;
if(c->keyframe_mindistance>c->keyframe_frequency_force)
c->keyframe_mindistance=c->keyframe_frequency_force;
- cpi->keyframe_granule_shift=_ilog(c->keyframe_frequency_force-1);
+ cpi->keyframe_granule_shift=OC_ILOG_32(c->keyframe_frequency_force-1);
/* clamp the target_bitrate to a maximum of 24 bits so we get a
more meaningful value when we write this out in the header. */
Modified: branches/theora-thusnelda/tests/Makefile.am
===================================================================
--- branches/theora-thusnelda/tests/Makefile.am 2009-03-21 20:22:37 UTC (rev 15823)
+++ branches/theora-thusnelda/tests/Makefile.am 2009-03-21 21:09:30 UTC (rev 15824)
@@ -5,7 +5,7 @@
AM_CFLAGS = $(OGG_CFLAGS)
THEORADIR = ../lib
-THEORA_LIBS = $(THEORADIR)/libtheora.la $(OGG_LIBS) -lm
+THEORA_LIBS = $(THEORADIR)/libtheora.la $(OGG_LIBS)
test: check
More information about the commits
mailing list