diff options
Diffstat (limited to 'thirdparty/libtheora/rate.c')
-rw-r--r-- | thirdparty/libtheora/rate.c | 1137 |
1 files changed, 1137 insertions, 0 deletions
diff --git a/thirdparty/libtheora/rate.c b/thirdparty/libtheora/rate.c new file mode 100644 index 0000000000..4f43bb2e5f --- /dev/null +++ b/thirdparty/libtheora/rate.c @@ -0,0 +1,1137 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: rate.c 16503 2009-08-22 18:14:02Z giles $ + + ********************************************************************/ +#include <stdlib.h> +#include <string.h> +#include "encint.h" + +/*A rough lookup table for tan(x), 0<=x<pi/2. + The values are Q12 fixed-point and spaced at 5 degree intervals. + These decisions are somewhat arbitrary, but sufficient for the 2nd order + Bessel follower below. + Values of x larger than 85 degrees are extrapolated from the last inteval, + which is way off, but "good enough".*/ +static unsigned short OC_ROUGH_TAN_LOOKUP[18]={ + 0, 358, 722, 1098, 1491, 1910, + 2365, 2868, 3437, 4096, 4881, 5850, + 7094, 8784,11254,15286,23230,46817 +}; + +/*_alpha is Q24 in the range [0,0.5). + The return values is 5.12.*/ +static int oc_warp_alpha(int _alpha){ + int i; + int d; + int t0; + int t1; + i=_alpha*36>>24; + if(i>=17)i=16; + t0=OC_ROUGH_TAN_LOOKUP[i]; + t1=OC_ROUGH_TAN_LOOKUP[i+1]; + d=_alpha*36-(i<<24); + return (int)(((ogg_int64_t)t0<<32)+(t1-t0<<8)*(ogg_int64_t)d>>32); +} + +/*Re-initialize the Bessel filter coefficients with the specified delay. + This does not alter the x/y state, but changes the reaction time of the + filter. + Altering the time constant of a reactive filter without alterning internal + state is something that has to be done carefuly, but our design operates at + high enough delays and with small enough time constant changes to make it + safe.*/ +static void oc_iir_filter_reinit(oc_iir_filter *_f,int _delay){ + int alpha; + ogg_int64_t one48; + ogg_int64_t warp; + ogg_int64_t k1; + ogg_int64_t k2; + ogg_int64_t d; + ogg_int64_t a; + ogg_int64_t ik2; + ogg_int64_t b1; + ogg_int64_t b2; + /*This borrows some code from an unreleased version of Postfish. + See the recipe at http://unicorn.us.com/alex/2polefilters.html for details + on deriving the filter coefficients.*/ + /*alpha is Q24*/ + alpha=(1<<24)/_delay; + one48=(ogg_int64_t)1<<48; + /*warp is 7.12*/ + warp=OC_MAXI(oc_warp_alpha(alpha),1); + /*k1 is 9.12*/ + k1=3*warp; + /*k2 is 16.24.*/ + k2=k1*warp; + /*d is 16.15.*/ + d=((1<<12)+k1<<12)+k2+256>>9; + /*a is 0.32, since d is larger than both 1.0 and k2.*/ + a=(k2<<23)/d; + /*ik2 is 25.24.*/ + ik2=one48/k2; + /*b1 is Q56; in practice, the integer ranges between -2 and 2.*/ + b1=2*a*(ik2-(1<<24)); + /*b2 is Q56; in practice, the integer ranges between -2 and 2.*/ + b2=(one48<<8)-(4*a<<24)-b1; + /*All of the filter parameters are Q24.*/ + _f->c[0]=(ogg_int32_t)(b1+((ogg_int64_t)1<<31)>>32); + _f->c[1]=(ogg_int32_t)(b2+((ogg_int64_t)1<<31)>>32); + _f->g=(ogg_int32_t)(a+128>>8); +} + +/*Initialize a 2nd order low-pass Bessel filter with the corresponding delay + and initial value. + _value is Q24.*/ +static void oc_iir_filter_init(oc_iir_filter *_f,int _delay,ogg_int32_t _value){ + oc_iir_filter_reinit(_f,_delay); + _f->y[1]=_f->y[0]=_f->x[1]=_f->x[0]=_value; +} + +static ogg_int64_t oc_iir_filter_update(oc_iir_filter *_f,ogg_int32_t _x){ + ogg_int64_t c0; + ogg_int64_t c1; + ogg_int64_t g; + ogg_int64_t x0; + ogg_int64_t x1; + ogg_int64_t y0; + ogg_int64_t y1; + ogg_int64_t ya; + c0=_f->c[0]; + c1=_f->c[1]; + g=_f->g; + x0=_f->x[0]; + x1=_f->x[1]; + y0=_f->y[0]; + y1=_f->y[1]; + ya=(_x+x0*2+x1)*g+y0*c0+y1*c1+(1<<23)>>24; + _f->x[1]=(ogg_int32_t)x0; + _f->x[0]=_x; + _f->y[1]=(ogg_int32_t)y0; + _f->y[0]=(ogg_int32_t)ya; + return ya; +} + + + +/*Search for the quantizer that matches the target most closely. + We don't assume a linear ordering, but when there are ties we pick the + quantizer closest to the old one.*/ +static int oc_enc_find_qi_for_target(oc_enc_ctx *_enc,int _qti,int _qi_old, + int _qi_min,ogg_int64_t _log_qtarget){ + ogg_int64_t best_qdiff; + int best_qi; + int qi; + best_qi=_qi_min; + best_qdiff=_enc->log_qavg[_qti][best_qi]-_log_qtarget; + best_qdiff=best_qdiff+OC_SIGNMASK(best_qdiff)^OC_SIGNMASK(best_qdiff); + for(qi=_qi_min+1;qi<64;qi++){ + ogg_int64_t qdiff; + qdiff=_enc->log_qavg[_qti][qi]-_log_qtarget; + qdiff=qdiff+OC_SIGNMASK(qdiff)^OC_SIGNMASK(qdiff); + if(qdiff<best_qdiff|| + qdiff==best_qdiff&&abs(qi-_qi_old)<abs(best_qi-_qi_old)){ + best_qi=qi; + best_qdiff=qdiff; + } + } + return best_qi; +} + +void oc_enc_calc_lambda(oc_enc_ctx *_enc,int _qti){ + ogg_int64_t lq; + int qi; + int qi1; + int nqis; + /*For now, lambda is fixed depending on the qi value and frame type: + lambda=qscale*(qavg[qti][qi]**2), + where qscale=0.2125. + This was derived by exhaustively searching for the optimal quantizer for + the AC coefficients in each block from a number of test sequences for a + number of fixed lambda values and fitting the peaks of the resulting + histograms (on the log(qavg) scale). + The same model applies to both inter and intra frames. + A more adaptive scheme might perform better.*/ + qi=_enc->state.qis[0]; + /*If rate control is active, use the lambda for the _target_ quantizer. + This allows us to scale to rates slightly lower than we'd normally be able + to reach, and give the rate control a semblance of "fractional qi" + precision. + TODO: Add API for changing QI, and allow extra precision.*/ + if(_enc->state.info.target_bitrate>0)lq=_enc->rc.log_qtarget; + else lq=_enc->log_qavg[_qti][qi]; + /*The resulting lambda value is less than 0x500000.*/ + _enc->lambda=(int)oc_bexp64(2*lq-0x4780BD468D6B62BLL); + /*Select additional quantizers. + The R-D optimal block AC quantizer statistics suggest that the distribution + is roughly Gaussian-like with a slight positive skew. + K-means clustering on log_qavg to select 3 quantizers produces cluster + centers of {log_qavg-0.6,log_qavg,log_qavg+0.7}. + Experiments confirm these are relatively good choices. + + Although we do greedy R-D optimization of the qii flags to avoid switching + too frequently, this becomes ineffective at low rates, either because we + do a poor job of predicting the actual R-D cost, or the greedy + optimization is not sufficient. + Therefore adaptive quantization is disabled above an (experimentally + suggested) threshold of log_qavg=7.00 (e.g., below INTRA qi=12 or + INTER qi=20 with current matrices). + This may need to be revised if the R-D cost estimation or qii flag + optimization strategies change.*/ + nqis=1; + if(lq<(OC_Q57(56)>>3)&&!_enc->vp3_compatible){ + qi1=oc_enc_find_qi_for_target(_enc,_qti,OC_MAXI(qi-1,0),0, + lq+(OC_Q57(7)+5)/10); + if(qi1!=qi)_enc->state.qis[nqis++]=qi1; + qi1=oc_enc_find_qi_for_target(_enc,_qti,OC_MINI(qi+1,63),0, + lq-(OC_Q57(6)+5)/10); + if(qi1!=qi&&qi1!=_enc->state.qis[nqis-1])_enc->state.qis[nqis++]=qi1; + } + _enc->state.nqis=nqis; +} + +/*Binary exponential of _log_scale with 24-bit fractional precision and + saturation. + _log_scale: A binary logarithm in Q24 format. + Return: The binary exponential in Q24 format, saturated to 2**47-1 if + _log_scale was too large.*/ +static ogg_int64_t oc_bexp_q24(ogg_int32_t _log_scale){ + if(_log_scale<(ogg_int32_t)23<<24){ + ogg_int64_t ret; + ret=oc_bexp64(((ogg_int64_t)_log_scale<<33)+OC_Q57(24)); + return ret<0x7FFFFFFFFFFFLL?ret:0x7FFFFFFFFFFFLL; + } + return 0x7FFFFFFFFFFFLL; +} + +/*Convenience function converts Q57 value to a clamped 32-bit Q24 value + _in: input in Q57 format. + Return: same number in Q24 */ +static ogg_int32_t oc_q57_to_q24(ogg_int64_t _in){ + ogg_int64_t ret; + ret=_in+((ogg_int64_t)1<<32)>>33; + /*0x80000000 is automatically converted to unsigned on 32-bit systems. + -0x7FFFFFFF-1 is needed to avoid "promoting" the whole expression to + unsigned.*/ + return (ogg_int32_t)OC_CLAMPI(-0x7FFFFFFF-1,ret,0x7FFFFFFF); +} + +/*Binary exponential of _log_scale with 24-bit fractional precision and + saturation. + _log_scale: A binary logarithm in Q57 format. + Return: The binary exponential in Q24 format, saturated to 2**31-1 if + _log_scale was too large.*/ +static ogg_int32_t oc_bexp64_q24(ogg_int64_t _log_scale){ + if(_log_scale<OC_Q57(8)){ + ogg_int64_t ret; + ret=oc_bexp64(_log_scale+OC_Q57(24)); + return ret<0x7FFFFFFF?(ogg_int32_t)ret:0x7FFFFFFF; + } + return 0x7FFFFFFF; +} + + +static void oc_enc_rc_reset(oc_enc_ctx *_enc){ + ogg_int64_t npixels; + ogg_int64_t ibpp; + int inter_delay; + /*TODO: These parameters should be exposed in a th_encode_ctl() API.*/ + _enc->rc.bits_per_frame=(_enc->state.info.target_bitrate* + (ogg_int64_t)_enc->state.info.fps_denominator)/ + _enc->state.info.fps_numerator; + /*Insane framerates or frame sizes mean insane bitrates. + Let's not get carried away.*/ + if(_enc->rc.bits_per_frame>0x400000000000LL){ + _enc->rc.bits_per_frame=(ogg_int64_t)0x400000000000LL; + } + else if(_enc->rc.bits_per_frame<32)_enc->rc.bits_per_frame=32; + _enc->rc.buf_delay=OC_MAXI(_enc->rc.buf_delay,12); + _enc->rc.max=_enc->rc.bits_per_frame*_enc->rc.buf_delay; + /*Start with a buffer fullness of 50% plus 25% of the amount we plan to spend + on a single keyframe interval. + We can require fully half the bits in an interval for a keyframe, so this + initial level gives us maximum flexibility for over/under-shooting in + subsequent frames.*/ + _enc->rc.target=(_enc->rc.max+1>>1)+(_enc->rc.bits_per_frame+2>>2)* + OC_MINI(_enc->keyframe_frequency_force,_enc->rc.buf_delay); + _enc->rc.fullness=_enc->rc.target; + /*Pick exponents and initial scales for quantizer selection.*/ + npixels=_enc->state.info.frame_width* + (ogg_int64_t)_enc->state.info.frame_height; + _enc->rc.log_npixels=oc_blog64(npixels); + ibpp=npixels/_enc->rc.bits_per_frame; + if(ibpp<1){ + _enc->rc.exp[0]=59; + _enc->rc.log_scale[0]=oc_blog64(1997)-OC_Q57(8); + } + else if(ibpp<2){ + _enc->rc.exp[0]=55; + _enc->rc.log_scale[0]=oc_blog64(1604)-OC_Q57(8); + } + else{ + _enc->rc.exp[0]=48; + _enc->rc.log_scale[0]=oc_blog64(834)-OC_Q57(8); + } + if(ibpp<4){ + _enc->rc.exp[1]=100; + _enc->rc.log_scale[1]=oc_blog64(2249)-OC_Q57(8); + } + else if(ibpp<8){ + _enc->rc.exp[1]=95; + _enc->rc.log_scale[1]=oc_blog64(1751)-OC_Q57(8); + } + else{ + _enc->rc.exp[1]=73; + _enc->rc.log_scale[1]=oc_blog64(1260)-OC_Q57(8); + } + _enc->rc.prev_drop_count=0; + _enc->rc.log_drop_scale=OC_Q57(0); + /*Set up second order followers, initialized according to corresponding + time constants.*/ + oc_iir_filter_init(&_enc->rc.scalefilter[0],4, + oc_q57_to_q24(_enc->rc.log_scale[0])); + inter_delay=(_enc->rc.twopass? + OC_MAXI(_enc->keyframe_frequency_force,12):_enc->rc.buf_delay)>>1; + _enc->rc.inter_count=0; + /*We clamp the actual inter_delay to a minimum of 10 to work within the range + of values where later incrementing the delay works as designed. + 10 is not an exact choice, but rather a good working trade-off.*/ + _enc->rc.inter_delay=10; + _enc->rc.inter_delay_target=inter_delay; + oc_iir_filter_init(&_enc->rc.scalefilter[1],_enc->rc.inter_delay, + oc_q57_to_q24(_enc->rc.log_scale[1])); + oc_iir_filter_init(&_enc->rc.vfrfilter,4, + oc_bexp64_q24(_enc->rc.log_drop_scale)); +} + +void oc_rc_state_init(oc_rc_state *_rc,oc_enc_ctx *_enc){ + _rc->twopass=0; + _rc->twopass_buffer_bytes=0; + _rc->twopass_force_kf=0; + _rc->frame_metrics=NULL; + _rc->rate_bias=0; + if(_enc->state.info.target_bitrate>0){ + /*The buffer size is set equal to the keyframe interval, clamped to the + range [12,256] frames. + The 12 frame minimum gives us some chance to distribute bit estimation + errors. + The 256 frame maximum means we'll require 8-10 seconds of pre-buffering + at 24-30 fps, which is not unreasonable.*/ + _rc->buf_delay=_enc->keyframe_frequency_force>256? + 256:_enc->keyframe_frequency_force; + /*By default, enforce all buffer constraints.*/ + _rc->drop_frames=1; + _rc->cap_overflow=1; + _rc->cap_underflow=0; + oc_enc_rc_reset(_enc); + } +} + +void oc_rc_state_clear(oc_rc_state *_rc){ + _ogg_free(_rc->frame_metrics); +} + +void oc_enc_rc_resize(oc_enc_ctx *_enc){ + /*If encoding has not yet begun, reset the buffer state.*/ + if(_enc->state.curframe_num<0)oc_enc_rc_reset(_enc); + else{ + int idt; + /*Otherwise, update the bounds on the buffer, but not the current + fullness.*/ + _enc->rc.bits_per_frame=(_enc->state.info.target_bitrate* + (ogg_int64_t)_enc->state.info.fps_denominator)/ + _enc->state.info.fps_numerator; + /*Insane framerates or frame sizes mean insane bitrates. + Let's not get carried away.*/ + if(_enc->rc.bits_per_frame>0x400000000000LL){ + _enc->rc.bits_per_frame=(ogg_int64_t)0x400000000000LL; + } + else if(_enc->rc.bits_per_frame<32)_enc->rc.bits_per_frame=32; + _enc->rc.buf_delay=OC_MAXI(_enc->rc.buf_delay,12); + _enc->rc.max=_enc->rc.bits_per_frame*_enc->rc.buf_delay; + _enc->rc.target=(_enc->rc.max+1>>1)+(_enc->rc.bits_per_frame+2>>2)* + OC_MINI(_enc->keyframe_frequency_force,_enc->rc.buf_delay); + /*Update the INTER-frame scale filter delay. + We jump to it immediately if we've already seen enough frames; otherwise + it is simply set as the new target.*/ + _enc->rc.inter_delay_target=idt=OC_MAXI(_enc->rc.buf_delay>>1,10); + if(idt<OC_MINI(_enc->rc.inter_delay,_enc->rc.inter_count)){ + oc_iir_filter_init(&_enc->rc.scalefilter[1],idt, + _enc->rc.scalefilter[1].y[0]); + _enc->rc.inter_delay=idt; + } + } + /*If we're in pass-2 mode, make sure the frame metrics array is big enough + to hold frame statistics for the full buffer.*/ + if(_enc->rc.twopass==2){ + int cfm; + int buf_delay; + int reset_window; + buf_delay=_enc->rc.buf_delay; + reset_window=_enc->rc.frame_metrics==NULL&&(_enc->rc.frames_total[0]==0|| + buf_delay<_enc->rc.frames_total[0]+_enc->rc.frames_total[1] + +_enc->rc.frames_total[2]); + cfm=_enc->rc.cframe_metrics; + /*Only try to resize the frame metrics buffer if a) it's too small and + b) we were using a finite buffer, or are about to start.*/ + if(cfm<buf_delay&&(_enc->rc.frame_metrics!=NULL||reset_window)){ + oc_frame_metrics *fm; + int nfm; + int fmh; + fm=(oc_frame_metrics *)_ogg_realloc(_enc->rc.frame_metrics, + buf_delay*sizeof(*_enc->rc.frame_metrics)); + if(fm==NULL){ + /*We failed to allocate a finite buffer.*/ + /*If we don't have a valid 2-pass header yet, just return; we'll reset + the buffer size when we read the header.*/ + if(_enc->rc.frames_total[0]==0)return; + /*Otherwise revert to the largest finite buffer previously set, or to + whole-file buffering if we were still using that.*/ + _enc->rc.buf_delay=_enc->rc.frame_metrics!=NULL? + cfm:_enc->rc.frames_total[0]+_enc->rc.frames_total[1] + +_enc->rc.frames_total[2]; + oc_enc_rc_resize(_enc); + return; + } + _enc->rc.frame_metrics=fm; + _enc->rc.cframe_metrics=buf_delay; + /*Re-organize the circular buffer.*/ + fmh=_enc->rc.frame_metrics_head; + nfm=_enc->rc.nframe_metrics; + if(fmh+nfm>cfm){ + int shift; + shift=OC_MINI(fmh+nfm-cfm,buf_delay-cfm); + memcpy(fm+cfm,fm,OC_MINI(fmh+nfm-cfm,buf_delay-cfm)*sizeof(*fm)); + if(fmh+nfm>buf_delay)memmove(fm,fm+shift,fmh+nfm-buf_delay); + } + } + /*We were using whole-file buffering; now we're not.*/ + if(reset_window){ + _enc->rc.nframes[0]=_enc->rc.nframes[1]=_enc->rc.nframes[2]=0; + _enc->rc.scale_sum[0]=_enc->rc.scale_sum[1]=0; + _enc->rc.scale_window_end=_enc->rc.scale_window0= + _enc->state.curframe_num+_enc->prev_dup_count+1; + if(_enc->rc.twopass_buffer_bytes){ + int qti; + /*We already read the metrics for the first frame in the window.*/ + *(_enc->rc.frame_metrics)=*&_enc->rc.cur_metrics; + _enc->rc.nframe_metrics++; + qti=_enc->rc.cur_metrics.frame_type; + _enc->rc.nframes[qti]++; + _enc->rc.nframes[2]+=_enc->rc.cur_metrics.dup_count; + _enc->rc.scale_sum[qti]+=oc_bexp_q24(_enc->rc.cur_metrics.log_scale); + _enc->rc.scale_window_end+=_enc->rc.cur_metrics.dup_count+1; + if(_enc->rc.scale_window_end-_enc->rc.scale_window0<buf_delay){ + /*We need more frame data.*/ + _enc->rc.twopass_buffer_bytes=0; + } + } + } + /*Otherwise, we could shrink the size of the current window, if necessary, + but leaving it like it is lets us adapt to the new buffer size more + gracefully.*/ + } +} + +/*Scale the number of frames by the number of expected drops/duplicates.*/ +static int oc_rc_scale_drop(oc_rc_state *_rc,int _nframes){ + if(_rc->prev_drop_count>0||_rc->log_drop_scale>OC_Q57(0)){ + ogg_int64_t dup_scale; + dup_scale=oc_bexp64((_rc->log_drop_scale + +oc_blog64(_rc->prev_drop_count+1)>>1)+OC_Q57(8)); + if(dup_scale<_nframes<<8){ + int dup_scalei; + dup_scalei=(int)dup_scale; + if(dup_scalei>0)_nframes=((_nframes<<8)+dup_scalei-1)/dup_scalei; + } + else _nframes=!!_nframes; + } + return _nframes; +} + +int oc_enc_select_qi(oc_enc_ctx *_enc,int _qti,int _clamp){ + ogg_int64_t rate_total; + ogg_int64_t rate_bias; + int nframes[2]; + int buf_delay; + int buf_pad; + ogg_int64_t log_qtarget; + ogg_int64_t log_scale0; + ogg_int64_t log_cur_scale; + ogg_int64_t log_qexp; + int exp0; + int old_qi; + 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.*/ + log_cur_scale=(ogg_int64_t)_enc->rc.scalefilter[_qti].y[0]<<33; + buf_pad=0; + switch(_enc->rc.twopass){ + default:{ + ogg_uint32_t next_key_frame; + /*Single pass mode: assume only forced keyframes and attempt to estimate + the drop count for VFR content.*/ + next_key_frame=_qti?_enc->keyframe_frequency_force + -(_enc->state.curframe_num-_enc->state.keyframe_num):0; + nframes[0]=(_enc->rc.buf_delay-OC_MINI(next_key_frame,_enc->rc.buf_delay) + +_enc->keyframe_frequency_force-1)/_enc->keyframe_frequency_force; + if(nframes[0]+_qti>1){ + nframes[0]--; + buf_delay=next_key_frame+nframes[0]*_enc->keyframe_frequency_force; + } + else buf_delay=_enc->rc.buf_delay; + nframes[1]=buf_delay-nframes[0]; + /*Downgrade the delta frame rate to correspond to the recent drop count + history.*/ + nframes[1]=oc_rc_scale_drop(&_enc->rc,nframes[1]); + }break; + case 1:{ + /*Pass 1 mode: use a fixed qi value.*/ + qi=_enc->state.qis[0]; + _enc->rc.log_qtarget=_enc->log_qavg[_qti][qi]; + return qi; + }break; + case 2:{ + ogg_int64_t scale_sum[2]; + int qti; + /*Pass 2 mode: we know exactly how much of each frame type there is in + the current buffer window, and have estimates for the scales.*/ + nframes[0]=_enc->rc.nframes[0]; + nframes[1]=_enc->rc.nframes[1]; + scale_sum[0]=_enc->rc.scale_sum[0]; + scale_sum[1]=_enc->rc.scale_sum[1]; + /*The window size can be slightly larger than the buffer window for VFR + content; clamp it down, if appropriate (the excess will all be dup + frames).*/ + buf_delay=OC_MINI(_enc->rc.scale_window_end-_enc->rc.scale_window0, + _enc->rc.buf_delay); + /*If we're approaching the end of the file, add some slack to keep us + from slamming into a rail. + Our rate accuracy goes down, but it keeps the result sensible. + We position the target where the first forced keyframe beyond the end + of the file would be (for consistency with 1-pass mode).*/ + buf_pad=OC_MINI(_enc->rc.buf_delay,_enc->state.keyframe_num + +_enc->keyframe_frequency_force-_enc->rc.scale_window0); + if(buf_delay<buf_pad)buf_pad-=buf_delay; + else{ + /*Otherwise, search for the last keyframe in the buffer window and + target that.*/ + buf_pad=0; + /*TODO: Currently we only do this when using a finite buffer; we could + save the position of the last keyframe in the summary data and do it + with a whole-file buffer as well, but it isn't likely to make a + difference.*/ + if(_enc->rc.frame_metrics!=NULL){ + int fmi; + int fm_tail; + fm_tail=_enc->rc.frame_metrics_head+_enc->rc.nframe_metrics; + if(fm_tail>=_enc->rc.cframe_metrics)fm_tail-=_enc->rc.cframe_metrics; + for(fmi=fm_tail;;){ + oc_frame_metrics *m; + fmi--; + if(fmi<0)fmi+=_enc->rc.cframe_metrics; + /*Stop before we remove the first frame.*/ + if(fmi==_enc->rc.frame_metrics_head)break; + m=_enc->rc.frame_metrics+fmi; + /*If we find a keyframe, remove it and everything past it.*/ + if(m->frame_type==OC_INTRA_FRAME){ + do{ + qti=m->frame_type; + nframes[qti]--; + scale_sum[qti]-=oc_bexp_q24(m->log_scale); + buf_delay-=m->dup_count+1; + fmi++; + if(fmi>=_enc->rc.cframe_metrics)fmi=0; + m=_enc->rc.frame_metrics+fmi; + } + while(fmi!=fm_tail); + /*And stop scanning backwards.*/ + break; + } + } + } + } + /*If we're not using the same frame type as in pass 1 (because someone + changed the keyframe interval), remove that scale estimate. + We'll add in a replacement for the correct frame type below.*/ + qti=_enc->rc.cur_metrics.frame_type; + if(qti!=_qti){ + nframes[qti]--; + scale_sum[qti]-=oc_bexp_q24(_enc->rc.cur_metrics.log_scale); + } + /*Compute log_scale estimates for each frame type from the pass-1 scales + we measured in the current window.*/ + for(qti=0;qti<2;qti++){ + _enc->rc.log_scale[qti]=nframes[qti]>0? + oc_blog64(scale_sum[qti])-oc_blog64(nframes[qti])-OC_Q57(24): + -_enc->rc.log_npixels; + } + /*If we're not using the same frame type as in pass 1, add a scale + estimate for the corresponding frame using the current low-pass + filter value. + This is mostly to ensure we have a valid estimate even when pass 1 had + no frames of this type in the buffer window. + TODO: We could also plan ahead and figure out how many keyframes we'll + be forced to add in the current buffer window.*/ + qti=_enc->rc.cur_metrics.frame_type; + if(qti!=_qti){ + ogg_int64_t scale; + scale=_enc->rc.log_scale[_qti]<OC_Q57(23)? + oc_bexp64(_enc->rc.log_scale[_qti]+OC_Q57(24)):0x7FFFFFFFFFFFLL; + scale*=nframes[_qti]; + nframes[_qti]++; + scale+=oc_bexp_q24(log_cur_scale>>33); + _enc->rc.log_scale[_qti]=oc_blog64(scale) + -oc_blog64(nframes[qti])-OC_Q57(24); + } + else log_cur_scale=(ogg_int64_t)_enc->rc.cur_metrics.log_scale<<33; + /*Add the padding from above. + This basically reverts to 1-pass estimations in the last keyframe + interval.*/ + if(buf_pad>0){ + ogg_int64_t scale; + int nextra_frames; + /*Extend the buffer.*/ + buf_delay+=buf_pad; + /*Add virtual delta frames according to the estimated drop count.*/ + nextra_frames=oc_rc_scale_drop(&_enc->rc,buf_pad); + /*And blend in the low-pass filtered scale according to how many frames + we added.*/ + scale= + oc_bexp64(_enc->rc.log_scale[1]+OC_Q57(24))*(ogg_int64_t)nframes[1] + +oc_bexp_q24(_enc->rc.scalefilter[1].y[0])*(ogg_int64_t)nextra_frames; + nframes[1]+=nextra_frames; + _enc->rc.log_scale[1]=oc_blog64(scale)-oc_blog64(nframes[1])-OC_Q57(24); + } + }break; + } + /*If we've been missing our target, add a penalty term.*/ + rate_bias=(_enc->rc.rate_bias/(_enc->state.curframe_num+1000))* + (buf_delay-buf_pad); + /*rate_total is the total bits available over the next buf_delay frames.*/ + rate_total=_enc->rc.fullness-_enc->rc.target+rate_bias + +buf_delay*_enc->rc.bits_per_frame; + log_scale0=_enc->rc.log_scale[_qti]+_enc->rc.log_npixels; + /*If there aren't enough bits to achieve our desired fullness level, use the + minimum quality permitted.*/ + if(rate_total<=buf_delay)log_qtarget=OC_QUANT_MAX_LOG; + else{ + static const ogg_int64_t LOG_KEY_RATIO=0x0137222BB70747BALL; + ogg_int64_t log_scale1; + ogg_int64_t rlo; + ogg_int64_t rhi; + log_scale1=_enc->rc.log_scale[1-_qti]+_enc->rc.log_npixels; + rlo=0; + rhi=(rate_total+nframes[_qti]-1)/nframes[_qti]; + while(rlo<rhi){ + ogg_int64_t curr; + ogg_int64_t rdiff; + ogg_int64_t log_rpow; + ogg_int64_t rscale; + curr=rlo+rhi>>1; + log_rpow=oc_blog64(curr)-log_scale0; + log_rpow=(log_rpow+(_enc->rc.exp[_qti]>>1))/_enc->rc.exp[_qti]; + if(_qti)log_rpow+=LOG_KEY_RATIO>>6; + else log_rpow-=LOG_KEY_RATIO>>6; + log_rpow*=_enc->rc.exp[1-_qti]; + rscale=nframes[1-_qti]*oc_bexp64(log_scale1+log_rpow); + rdiff=nframes[_qti]*curr+rscale-rate_total; + if(rdiff<0)rlo=curr+1; + else if(rdiff>0)rhi=curr-1; + else break; + } + log_qtarget=OC_Q57(2)-((oc_blog64(rlo)-log_scale0+(_enc->rc.exp[_qti]>>1))/ + _enc->rc.exp[_qti]<<6); + log_qtarget=OC_MINI(log_qtarget,OC_QUANT_MAX_LOG); + } + /*The above allocation looks only at the total rate we'll accumulate in the + next buf_delay frames. + However, we could overflow the buffer on the very next frame, so check for + that here, if we're not using a soft target.*/ + exp0=_enc->rc.exp[_qti]; + if(_enc->rc.cap_overflow){ + ogg_int64_t margin; + ogg_int64_t soft_limit; + ogg_int64_t log_soft_limit; + /*Allow 3% of the buffer for prediction error. + This should be plenty, and we don't mind if we go a bit over; we only + want to keep these bits from being completely wasted.*/ + margin=_enc->rc.max+31>>5; + /*We want to use at least this many bits next frame.*/ + soft_limit=_enc->rc.fullness+_enc->rc.bits_per_frame-(_enc->rc.max-margin); + log_soft_limit=oc_blog64(soft_limit); + /*If we're predicting we won't use that many...*/ + log_qexp=(log_qtarget-OC_Q57(2)>>6)*exp0; + if(log_scale0-log_qexp<log_soft_limit){ + /*Scale the adjustment based on how far into the margin we are.*/ + log_qexp+=(log_scale0-log_soft_limit-log_qexp>>32)* + ((OC_MINI(margin,soft_limit)<<32)/margin); + log_qtarget=((log_qexp+(exp0>>1))/exp0<<6)+OC_Q57(2); + } + } + /*If this was not one of the initial frames, limit the change in quality.*/ + old_qi=_enc->state.qis[0]; + if(_clamp){ + ogg_int64_t log_qmin; + ogg_int64_t log_qmax; + /*Clamp the target quantizer to within [0.8*Q,1.2*Q], where Q is the + current quantizer. + TODO: With user-specified quant matrices, we need to enlarge these limits + if they don't actually let us change qi values.*/ + log_qmin=_enc->log_qavg[_qti][old_qi]-0x00A4D3C25E68DC58LL; + log_qmax=_enc->log_qavg[_qti][old_qi]+0x00A4D3C25E68DC58LL; + log_qtarget=OC_CLAMPI(log_qmin,log_qtarget,log_qmax); + } + /*The above allocation looks only at the total rate we'll accumulate in the + next buf_delay frames. + However, we could bust the budget on the very next frame, so check for that + here, if we're not using a soft target.*/ + /* Disabled when our minimum qi > 0; if we saturate log_qtarget to + to the maximum possible size when we have a minimum qi, the + resulting lambda will interact very strangely with SKIP. The + resulting artifacts look like waterfalls. */ + if(_enc->state.info.quality==0){ + ogg_int64_t log_hard_limit; + /*Compute the maximum number of bits we can use in the next frame. + Allow 50% of the rate for a single frame for prediction error. + This may not be enough for keyframes or sudden changes in complexity.*/ + log_hard_limit=oc_blog64(_enc->rc.fullness+(_enc->rc.bits_per_frame>>1)); + /*If we're predicting we'll use more than this...*/ + log_qexp=(log_qtarget-OC_Q57(2)>>6)*exp0; + if(log_scale0-log_qexp>log_hard_limit){ + /*Force the target to hit our limit exactly.*/ + log_qexp=log_scale0-log_hard_limit; + log_qtarget=((log_qexp+(exp0>>1))/exp0<<6)+OC_Q57(2); + /*If that target is unreasonable, oh well; we'll have to drop.*/ + log_qtarget=OC_MINI(log_qtarget,OC_QUANT_MAX_LOG); + } + } + /*Compute a final estimate of the number of bits we plan to use.*/ + log_qexp=(log_qtarget-OC_Q57(2)>>6)*_enc->rc.exp[_qti]; + _enc->rc.rate_bias+=oc_bexp64(log_cur_scale+_enc->rc.log_npixels-log_qexp); + qi=oc_enc_find_qi_for_target(_enc,_qti,old_qi, + _enc->state.info.quality,log_qtarget); + /*Save the quantizer target for lambda calculations.*/ + _enc->rc.log_qtarget=log_qtarget; + return qi; +} + +int oc_enc_update_rc_state(oc_enc_ctx *_enc, + long _bits,int _qti,int _qi,int _trial,int _droppable){ + ogg_int64_t buf_delta; + ogg_int64_t log_scale; + int dropped; + dropped=0; + /* Drop frames also disabled for now in the case of infinite-buffer + two-pass mode */ + if(!_enc->rc.drop_frames||_enc->rc.twopass&&_enc->rc.frame_metrics==NULL){ + _droppable=0; + } + buf_delta=_enc->rc.bits_per_frame*(1+_enc->dup_count); + if(_bits<=0){ + /*We didn't code any blocks in this frame.*/ + log_scale=OC_Q57(-64); + _bits=0; + } + else{ + ogg_int64_t log_bits; + ogg_int64_t log_qexp; + /*Compute the estimated scale factor for this frame type.*/ + log_bits=oc_blog64(_bits); + log_qexp=_enc->rc.log_qtarget-OC_Q57(2); + log_qexp=(log_qexp>>6)*(_enc->rc.exp[_qti]); + log_scale=OC_MINI(log_bits-_enc->rc.log_npixels+log_qexp,OC_Q57(16)); + } + /*Special two-pass processing.*/ + switch(_enc->rc.twopass){ + case 1:{ + /*Pass 1 mode: save the metrics for this frame.*/ + _enc->rc.cur_metrics.log_scale=oc_q57_to_q24(log_scale); + _enc->rc.cur_metrics.dup_count=_enc->dup_count; + _enc->rc.cur_metrics.frame_type=_enc->state.frame_type; + _enc->rc.twopass_buffer_bytes=0; + }break; + case 2:{ + /*Pass 2 mode:*/ + if(!_trial){ + ogg_int64_t next_frame_num; + int qti; + /*Move the current metrics back one frame.*/ + *&_enc->rc.prev_metrics=*&_enc->rc.cur_metrics; + next_frame_num=_enc->state.curframe_num+_enc->dup_count+1; + /*Back out the last frame's statistics from the sliding window.*/ + qti=_enc->rc.prev_metrics.frame_type; + _enc->rc.frames_left[qti]--; + _enc->rc.frames_left[2]-=_enc->rc.prev_metrics.dup_count; + _enc->rc.nframes[qti]--; + _enc->rc.nframes[2]-=_enc->rc.prev_metrics.dup_count; + _enc->rc.scale_sum[qti]-=oc_bexp_q24(_enc->rc.prev_metrics.log_scale); + _enc->rc.scale_window0=(int)next_frame_num; + /*Free the corresponding entry in the circular buffer.*/ + if(_enc->rc.frame_metrics!=NULL){ + _enc->rc.nframe_metrics--; + _enc->rc.frame_metrics_head++; + if(_enc->rc.frame_metrics_head>=_enc->rc.cframe_metrics){ + _enc->rc.frame_metrics_head=0; + } + } + /*Mark us ready for the next 2-pass packet.*/ + _enc->rc.twopass_buffer_bytes=0; + /*Update state, so the user doesn't have to keep calling 2pass_in after + they've fed in all the data when we're using a finite buffer.*/ + _enc->prev_dup_count=_enc->dup_count; + oc_enc_rc_2pass_in(_enc,NULL,0); + } + }break; + } + /*Common to all passes:*/ + if(_bits>0){ + if(_trial){ + oc_iir_filter *f; + /*Use the estimated scale factor directly if this was a trial.*/ + f=_enc->rc.scalefilter+_qti; + f->y[1]=f->y[0]=f->x[1]=f->x[0]=oc_q57_to_q24(log_scale); + _enc->rc.log_scale[_qti]=log_scale; + } + else{ + /*Lengthen the time constant for the INTER filter as we collect more + frame statistics, until we reach our target.*/ + if(_enc->rc.inter_delay<_enc->rc.inter_delay_target&& + _enc->rc.inter_count>=_enc->rc.inter_delay&&_qti==OC_INTER_FRAME){ + oc_iir_filter_reinit(&_enc->rc.scalefilter[1],++_enc->rc.inter_delay); + } + /*Otherwise update the low-pass scale filter for this frame type, + regardless of whether or not we dropped this frame.*/ + _enc->rc.log_scale[_qti]=oc_iir_filter_update( + _enc->rc.scalefilter+_qti,oc_q57_to_q24(log_scale))<<33; + /*If this frame busts our budget, it must be dropped.*/ + if(_droppable&&_enc->rc.fullness+buf_delta<_bits){ + _enc->rc.prev_drop_count+=1+_enc->dup_count; + _bits=0; + dropped=1; + } + else{ + ogg_uint32_t drop_count; + /*Update a low-pass filter to estimate the "real" frame rate taking + drops and duplicates into account. + This is only done if the frame is coded, as it needs the final + count of dropped frames.*/ + drop_count=_enc->rc.prev_drop_count+1; + if(drop_count>0x7F)drop_count=0x7FFFFFFF; + else drop_count<<=24; + _enc->rc.log_drop_scale=oc_blog64(oc_iir_filter_update( + &_enc->rc.vfrfilter,drop_count))-OC_Q57(24); + /*Initialize the drop count for this frame to the user-requested dup + count. + It will be increased if we drop more frames.*/ + _enc->rc.prev_drop_count=_enc->dup_count; + } + } + /*Increment the INTER frame count, for filter adaptation purposes.*/ + if(_enc->rc.inter_count<INT_MAX)_enc->rc.inter_count+=_qti; + } + /*Increase the drop count.*/ + else _enc->rc.prev_drop_count+=1+_enc->dup_count; + /*And update the buffer fullness level.*/ + if(!_trial){ + _enc->rc.fullness+=buf_delta-_bits; + /*If we're too quick filling the buffer and overflow is capped, + that rate is lost forever.*/ + if(_enc->rc.cap_overflow&&_enc->rc.fullness>_enc->rc.max){ + _enc->rc.fullness=_enc->rc.max; + } + /*If we're too quick draining the buffer and underflow is capped, + don't try to make up that rate later.*/ + if(_enc->rc.cap_underflow&&_enc->rc.fullness<0){ + _enc->rc.fullness=0; + } + /*Adjust the bias for the real bits we've used.*/ + _enc->rc.rate_bias-=_bits; + } + return dropped; +} + +#define OC_RC_2PASS_VERSION (1) +#define OC_RC_2PASS_HDR_SZ (38) +#define OC_RC_2PASS_PACKET_SZ (8) + +static void oc_rc_buffer_val(oc_rc_state *_rc,ogg_int64_t _val,int _bytes){ + while(_bytes-->0){ + _rc->twopass_buffer[_rc->twopass_buffer_bytes++]=(unsigned char)(_val&0xFF); + _val>>=8; + } +} + +int oc_enc_rc_2pass_out(oc_enc_ctx *_enc,unsigned char **_buf){ + if(_enc->rc.twopass_buffer_bytes==0){ + if(_enc->rc.twopass==0){ + int qi; + /*Pick first-pass qi for scale calculations.*/ + qi=oc_enc_select_qi(_enc,0,0); + _enc->state.nqis=1; + _enc->state.qis[0]=qi; + _enc->rc.twopass=1; + _enc->rc.frames_total[0]=_enc->rc.frames_total[1]= + _enc->rc.frames_total[2]=0; + _enc->rc.scale_sum[0]=_enc->rc.scale_sum[1]=0; + /*Fill in dummy summary values.*/ + oc_rc_buffer_val(&_enc->rc,0x5032544F,4); + oc_rc_buffer_val(&_enc->rc,OC_RC_2PASS_VERSION,4); + oc_rc_buffer_val(&_enc->rc,0,OC_RC_2PASS_HDR_SZ-8); + } + else{ + int qti; + qti=_enc->rc.cur_metrics.frame_type; + _enc->rc.scale_sum[qti]+=oc_bexp_q24(_enc->rc.cur_metrics.log_scale); + _enc->rc.frames_total[qti]++; + _enc->rc.frames_total[2]+=_enc->rc.cur_metrics.dup_count; + oc_rc_buffer_val(&_enc->rc, + _enc->rc.cur_metrics.dup_count|_enc->rc.cur_metrics.frame_type<<31,4); + oc_rc_buffer_val(&_enc->rc,_enc->rc.cur_metrics.log_scale,4); + } + } + else if(_enc->packet_state==OC_PACKET_DONE&& + _enc->rc.twopass_buffer_bytes!=OC_RC_2PASS_HDR_SZ){ + _enc->rc.twopass_buffer_bytes=0; + oc_rc_buffer_val(&_enc->rc,0x5032544F,4); + oc_rc_buffer_val(&_enc->rc,OC_RC_2PASS_VERSION,4); + oc_rc_buffer_val(&_enc->rc,_enc->rc.frames_total[0],4); + oc_rc_buffer_val(&_enc->rc,_enc->rc.frames_total[1],4); + oc_rc_buffer_val(&_enc->rc,_enc->rc.frames_total[2],4); + oc_rc_buffer_val(&_enc->rc,_enc->rc.exp[0],1); + oc_rc_buffer_val(&_enc->rc,_enc->rc.exp[1],1); + oc_rc_buffer_val(&_enc->rc,_enc->rc.scale_sum[0],8); + oc_rc_buffer_val(&_enc->rc,_enc->rc.scale_sum[1],8); + } + else{ + /*The data for this frame has already been retrieved.*/ + *_buf=NULL; + return 0; + } + *_buf=_enc->rc.twopass_buffer; + return _enc->rc.twopass_buffer_bytes; +} + +static size_t oc_rc_buffer_fill(oc_rc_state *_rc, + unsigned char *_buf,size_t _bytes,size_t _consumed,size_t _goal){ + while(_rc->twopass_buffer_fill<_goal&&_consumed<_bytes){ + _rc->twopass_buffer[_rc->twopass_buffer_fill++]=_buf[_consumed++]; + } + return _consumed; +} + +static ogg_int64_t oc_rc_unbuffer_val(oc_rc_state *_rc,int _bytes){ + ogg_int64_t ret; + int shift; + ret=0; + shift=0; + while(_bytes-->0){ + ret|=((ogg_int64_t)_rc->twopass_buffer[_rc->twopass_buffer_bytes++])<<shift; + shift+=8; + } + return ret; +} + +int oc_enc_rc_2pass_in(oc_enc_ctx *_enc,unsigned char *_buf,size_t _bytes){ + size_t consumed; + consumed=0; + /*Enable pass 2 mode if this is the first call.*/ + if(_enc->rc.twopass==0){ + _enc->rc.twopass=2; + _enc->rc.twopass_buffer_fill=0; + _enc->rc.frames_total[0]=0; + _enc->rc.nframe_metrics=0; + _enc->rc.cframe_metrics=0; + _enc->rc.frame_metrics_head=0; + _enc->rc.scale_window0=0; + _enc->rc.scale_window_end=0; + } + /*If we haven't got a valid summary header yet, try to parse one.*/ + if(_enc->rc.frames_total[0]==0){ + if(!_buf){ + int frames_needed; + /*If we're using a whole-file buffer, we just need the first frame. + Otherwise, we may need as many as one per buffer slot.*/ + frames_needed=_enc->rc.frame_metrics==NULL?1:_enc->rc.buf_delay; + return OC_RC_2PASS_HDR_SZ+frames_needed*OC_RC_2PASS_PACKET_SZ + -_enc->rc.twopass_buffer_fill; + } + consumed=oc_rc_buffer_fill(&_enc->rc, + _buf,_bytes,consumed,OC_RC_2PASS_HDR_SZ); + if(_enc->rc.twopass_buffer_fill>=OC_RC_2PASS_HDR_SZ){ + ogg_int64_t scale_sum[2]; + int exp[2]; + int buf_delay; + /*Read the summary header data.*/ + /*Check the magic value and version number.*/ + if(oc_rc_unbuffer_val(&_enc->rc,4)!=0x5032544F|| + oc_rc_unbuffer_val(&_enc->rc,4)!=OC_RC_2PASS_VERSION){ + _enc->rc.twopass_buffer_bytes=0; + return TH_ENOTFORMAT; + } + _enc->rc.frames_total[0]=(ogg_uint32_t)oc_rc_unbuffer_val(&_enc->rc,4); + _enc->rc.frames_total[1]=(ogg_uint32_t)oc_rc_unbuffer_val(&_enc->rc,4); + _enc->rc.frames_total[2]=(ogg_uint32_t)oc_rc_unbuffer_val(&_enc->rc,4); + exp[0]=(int)oc_rc_unbuffer_val(&_enc->rc,1); + exp[1]=(int)oc_rc_unbuffer_val(&_enc->rc,1); + scale_sum[0]=oc_rc_unbuffer_val(&_enc->rc,8); + scale_sum[1]=oc_rc_unbuffer_val(&_enc->rc,8); + /*Make sure the file claims to have at least one frame. + Otherwise we probably got the placeholder data from an aborted pass 1. + Also make sure the total frame count doesn't overflow an integer.*/ + buf_delay=_enc->rc.frames_total[0]+_enc->rc.frames_total[1] + +_enc->rc.frames_total[2]; + if(_enc->rc.frames_total[0]==0||buf_delay<0|| + (ogg_uint32_t)buf_delay<_enc->rc.frames_total[0]|| + (ogg_uint32_t)buf_delay<_enc->rc.frames_total[1]){ + _enc->rc.frames_total[0]=0; + _enc->rc.twopass_buffer_bytes=0; + return TH_EBADHEADER; + } + /*Got a valid header; set up pass 2.*/ + _enc->rc.frames_left[0]=_enc->rc.frames_total[0]; + _enc->rc.frames_left[1]=_enc->rc.frames_total[1]; + _enc->rc.frames_left[2]=_enc->rc.frames_total[2]; + /*If the user hasn't specified a buffer size, use the whole file.*/ + if(_enc->rc.frame_metrics==NULL){ + _enc->rc.buf_delay=buf_delay; + _enc->rc.nframes[0]=_enc->rc.frames_total[0]; + _enc->rc.nframes[1]=_enc->rc.frames_total[1]; + _enc->rc.nframes[2]=_enc->rc.frames_total[2]; + _enc->rc.scale_sum[0]=scale_sum[0]; + _enc->rc.scale_sum[1]=scale_sum[1]; + _enc->rc.scale_window_end=buf_delay; + oc_enc_rc_reset(_enc); + } + _enc->rc.exp[0]=exp[0]; + _enc->rc.exp[1]=exp[1]; + /*Clear the header data from the buffer to make room for packet data.*/ + _enc->rc.twopass_buffer_fill=0; + _enc->rc.twopass_buffer_bytes=0; + } + } + if(_enc->rc.frames_total[0]!=0){ + ogg_int64_t curframe_num; + int nframes_total; + curframe_num=_enc->state.curframe_num; + if(curframe_num>=0){ + /*We just encoded a frame; make sure things matched.*/ + if(_enc->rc.prev_metrics.dup_count!=_enc->prev_dup_count){ + _enc->rc.twopass_buffer_bytes=0; + return TH_EINVAL; + } + } + curframe_num+=_enc->prev_dup_count+1; + nframes_total=_enc->rc.frames_total[0]+_enc->rc.frames_total[1] + +_enc->rc.frames_total[2]; + if(curframe_num>=nframes_total){ + /*We don't want any more data after the last frame, and we don't want to + allow any more frames to be encoded.*/ + _enc->rc.twopass_buffer_bytes=0; + } + else if(_enc->rc.twopass_buffer_bytes==0){ + if(_enc->rc.frame_metrics==NULL){ + /*We're using a whole-file buffer:*/ + if(!_buf)return OC_RC_2PASS_PACKET_SZ-_enc->rc.twopass_buffer_fill; + consumed=oc_rc_buffer_fill(&_enc->rc, + _buf,_bytes,consumed,OC_RC_2PASS_PACKET_SZ); + if(_enc->rc.twopass_buffer_fill>=OC_RC_2PASS_PACKET_SZ){ + ogg_uint32_t dup_count; + ogg_int32_t log_scale; + int qti; + int arg; + /*Read the metrics for the next frame.*/ + dup_count=oc_rc_unbuffer_val(&_enc->rc,4); + log_scale=oc_rc_unbuffer_val(&_enc->rc,4); + _enc->rc.cur_metrics.log_scale=log_scale; + qti=(dup_count&0x80000000)>>31; + _enc->rc.cur_metrics.dup_count=dup_count&0x7FFFFFFF; + _enc->rc.cur_metrics.frame_type=qti; + _enc->rc.twopass_force_kf=qti==OC_INTRA_FRAME; + /*"Helpfully" set the dup count back to what it was in pass 1.*/ + arg=_enc->rc.cur_metrics.dup_count; + th_encode_ctl(_enc,TH_ENCCTL_SET_DUP_COUNT,&arg,sizeof(arg)); + /*Clear the buffer for the next frame.*/ + _enc->rc.twopass_buffer_fill=0; + } + } + else{ + int frames_needed; + /*We're using a finite buffer:*/ + frames_needed=OC_CLAMPI(0,_enc->rc.buf_delay + -(_enc->rc.scale_window_end-_enc->rc.scale_window0), + _enc->rc.frames_left[0]+_enc->rc.frames_left[1] + -_enc->rc.nframes[0]-_enc->rc.nframes[1]); + while(frames_needed>0){ + if(!_buf){ + return OC_RC_2PASS_PACKET_SZ*frames_needed + -_enc->rc.twopass_buffer_fill; + } + consumed=oc_rc_buffer_fill(&_enc->rc, + _buf,_bytes,consumed,OC_RC_2PASS_PACKET_SZ); + if(_enc->rc.twopass_buffer_fill>=OC_RC_2PASS_PACKET_SZ){ + oc_frame_metrics *m; + int fmi; + ogg_uint32_t dup_count; + ogg_int32_t log_scale; + int qti; + /*Read the metrics for the next frame.*/ + dup_count=oc_rc_unbuffer_val(&_enc->rc,4); + log_scale=oc_rc_unbuffer_val(&_enc->rc,4); + /*Add the to the circular buffer.*/ + fmi=_enc->rc.frame_metrics_head+_enc->rc.nframe_metrics++; + if(fmi>=_enc->rc.cframe_metrics)fmi-=_enc->rc.cframe_metrics; + m=_enc->rc.frame_metrics+fmi; + m->log_scale=log_scale; + qti=(dup_count&0x80000000)>>31; + m->dup_count=dup_count&0x7FFFFFFF; + m->frame_type=qti; + /*And accumulate the statistics over the window.*/ + _enc->rc.nframes[qti]++; + _enc->rc.nframes[2]+=m->dup_count; + _enc->rc.scale_sum[qti]+=oc_bexp_q24(m->log_scale); + _enc->rc.scale_window_end+=m->dup_count+1; + /*Compute an upper bound on the number of remaining packets needed + for the current window.*/ + frames_needed=OC_CLAMPI(0,_enc->rc.buf_delay + -(_enc->rc.scale_window_end-_enc->rc.scale_window0), + _enc->rc.frames_left[0]+_enc->rc.frames_left[1] + -_enc->rc.nframes[0]-_enc->rc.nframes[1]); + /*Clear the buffer for the next frame.*/ + _enc->rc.twopass_buffer_fill=0; + _enc->rc.twopass_buffer_bytes=0; + } + /*Go back for more data.*/ + else break; + } + /*If we've got all the frames we need, fill in the current metrics. + We're ready to go.*/ + if(frames_needed<=0){ + int arg; + *&_enc->rc.cur_metrics= + *(_enc->rc.frame_metrics+_enc->rc.frame_metrics_head); + _enc->rc.twopass_force_kf= + _enc->rc.cur_metrics.frame_type==OC_INTRA_FRAME; + /*"Helpfully" set the dup count back to what it was in pass 1.*/ + arg=_enc->rc.cur_metrics.dup_count; + th_encode_ctl(_enc,TH_ENCCTL_SET_DUP_COUNT,&arg,sizeof(arg)); + /*Mark us ready for the next frame.*/ + _enc->rc.twopass_buffer_bytes=1; + } + } + } + } + return (int)consumed; +} |