#include <stdlib.h>
#include <string.h>
#include "encint.h"
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
};
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);
}
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;
alpha=(1<<24)/_delay;
one48=(ogg_int64_t)1<<48;
warp=OC_MAXI(oc_warp_alpha(alpha),1);
k1=3*warp;
k2=k1*warp;
d=((1<<12)+k1<<12)+k2+256>>9;
a=(k2<<23)/d;
ik2=one48/k2;
b1=2*a*(ik2-(1<<24));
b2=(one48<<8)-(4*a<<24)-b1;
_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);
}
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;
}
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;
qi=_enc->state.qis[0];
if(_enc->state.info.target_bitrate>0)lq=_enc->rc.log_qtarget;
else lq=_enc->log_qavg[_qti][qi];
_enc->lambda=(int)oc_bexp64(2*lq-0x4780BD468D6B62BLL);
nqis=1;
if(lq<(OC_Q57(56)>>3)&&!_enc->vp3_compatible&&
_enc->sp_level<OC_SP_LEVEL_FAST_ANALYSIS){
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;
}
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;
}
static ogg_int32_t oc_q57_to_q24(ogg_int64_t _in){
ogg_int64_t ret;
ret=_in+((ogg_int64_t)1<<32)>>33;
return (ogg_int32_t)OC_CLAMPI(-0x7FFFFFFF-1,ret,0x7FFFFFFF);
}
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;
_enc->rc.bits_per_frame=(_enc->state.info.target_bitrate*
(ogg_int64_t)_enc->state.info.fps_denominator)/
_enc->state.info.fps_numerator;
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);
_enc->rc.fullness=_enc->rc.target;
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);
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;
_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){
_rc->buf_delay=_enc->keyframe_frequency_force>256?
256:_enc->keyframe_frequency_force;
_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(_enc->state.curframe_num<0)oc_enc_rc_reset(_enc);
else{
int idt;
_enc->rc.bits_per_frame=(_enc->state.info.target_bitrate*
(ogg_int64_t)_enc->state.info.fps_denominator)/
_enc->state.info.fps_numerator;
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);
_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(_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;
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){
if(_enc->rc.frames_total[0]==0)return;
_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;
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);
}
}
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;
*(_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){
_enc->rc.twopass_buffer_bytes=0;
}
}
}
}
}
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;
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;
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];
nframes[1]=oc_rc_scale_drop(&_enc->rc,nframes[1]);
}break;
case 1:{
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;
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];
buf_delay=OC_MINI(_enc->rc.scale_window_end-_enc->rc.scale_window0,
_enc->rc.buf_delay);
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{
buf_pad=0;
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;
if(fmi==_enc->rc.frame_metrics_head)break;
m=_enc->rc.frame_metrics+fmi;
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);
break;
}
}
}
}
qti=_enc->rc.cur_metrics.frame_type;
if(qti!=_qti){
nframes[qti]--;
scale_sum[qti]-=oc_bexp_q24(_enc->rc.cur_metrics.log_scale);
}
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;
}
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;
if(buf_pad>0){
ogg_int64_t scale;
int nextra_frames;
buf_delay+=buf_pad;
nextra_frames=oc_rc_scale_drop(&_enc->rc,buf_pad);
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;
}
rate_bias=(_enc->rc.rate_bias/(_enc->state.curframe_num+1000))*
(buf_delay-buf_pad);
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(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);
}
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;
margin=_enc->rc.max+31>>5;
soft_limit=_enc->rc.fullness+_enc->rc.bits_per_frame-(_enc->rc.max-margin);
log_soft_limit=oc_blog64(soft_limit);
log_qexp=(log_qtarget-OC_Q57(2)>>6)*exp0;
if(log_scale0-log_qexp<log_soft_limit){
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);
}
}
old_qi=_enc->state.qis[0];
if(_clamp){
ogg_int64_t log_qmin;
ogg_int64_t log_qmax;
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);
}
if(_enc->state.info.quality==0){
ogg_int64_t log_hard_limit;
log_hard_limit=oc_blog64(_enc->rc.fullness+(_enc->rc.bits_per_frame>>1));
log_qexp=(log_qtarget-OC_Q57(2)>>6)*exp0;
if(log_scale0-log_qexp>log_hard_limit){
log_qexp=log_scale0-log_hard_limit;
log_qtarget=((log_qexp+(exp0>>1))/exp0<<6)+OC_Q57(2);
log_qtarget=OC_MINI(log_qtarget,OC_QUANT_MAX_LOG);
}
}
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);
_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;
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){
log_scale=OC_Q57(-64);
_bits=0;
}
else{
ogg_int64_t log_bits;
ogg_int64_t log_qexp;
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));
}
switch(_enc->rc.twopass){
case 1:{
_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.cur_metrics.activity_avg=_enc->activity_avg;
_enc->rc.twopass_buffer_bytes=0;
}break;
case 2:{
if(!_trial){
ogg_int64_t next_frame_num;
int qti;
*&_enc->rc.prev_metrics=*&_enc->rc.cur_metrics;
next_frame_num=_enc->state.curframe_num+_enc->dup_count+1;
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;
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;
}
}
_enc->rc.twopass_buffer_bytes=0;
_enc->prev_dup_count=_enc->dup_count;
oc_enc_rc_2pass_in(_enc,NULL,0);
}
}break;
}
if(_bits>0){
if(_trial){
oc_iir_filter *f;
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{
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);
}
_enc->rc.log_scale[_qti]=oc_iir_filter_update(
_enc->rc.scalefilter+_qti,oc_q57_to_q24(log_scale))<<33;
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;
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);
_enc->rc.prev_drop_count=_enc->dup_count;
}
}
if(_enc->rc.inter_count<INT_MAX)_enc->rc.inter_count+=_qti;
}
else _enc->rc.prev_drop_count+=1+_enc->dup_count;
if(!_trial){
_enc->rc.fullness+=buf_delta-_bits;
if(_enc->rc.cap_overflow&&_enc->rc.fullness>_enc->rc.max){
_enc->rc.fullness=_enc->rc.max;
}
if(_enc->rc.cap_underflow&&_enc->rc.fullness<0){
_enc->rc.fullness=0;
}
_enc->rc.rate_bias-=_bits;
}
return dropped;
}
#define OC_RC_2PASS_VERSION (2)
#define OC_RC_2PASS_HDR_SZ (38)
#define OC_RC_2PASS_PACKET_SZ (12)
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;
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;
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);
oc_rc_buffer_val(&_enc->rc,_enc->rc.cur_metrics.activity_avg,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{
*_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;
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(_enc->rc.frames_total[0]==0){
if(!_buf){
int frames_needed;
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;
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);
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;
}
_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(_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];
_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){
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){
_enc->rc.twopass_buffer_bytes=0;
}
else if(_enc->rc.twopass_buffer_bytes==0){
if(_enc->rc.frame_metrics==NULL){
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;
unsigned activity;
int qti;
int arg;
dup_count=oc_rc_unbuffer_val(&_enc->rc,4);
log_scale=oc_rc_unbuffer_val(&_enc->rc,4);
activity=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;
_enc->activity_avg=_enc->rc.cur_metrics.activity_avg=activity;
arg=_enc->rc.cur_metrics.dup_count;
th_encode_ctl(_enc,TH_ENCCTL_SET_DUP_COUNT,&arg,sizeof(arg));
_enc->rc.twopass_buffer_fill=0;
}
}
else{
int frames_needed;
frames_needed=OC_MINI(_enc->rc.buf_delay-OC_MINI(_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;
unsigned activity;
dup_count=oc_rc_unbuffer_val(&_enc->rc,4);
log_scale=oc_rc_unbuffer_val(&_enc->rc,4);
activity=oc_rc_unbuffer_val(&_enc->rc,4);
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;
m->activity_avg=activity;
_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;
frames_needed=OC_MINI(_enc->rc.buf_delay-OC_MINI(_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]);
_enc->rc.twopass_buffer_fill=0;
_enc->rc.twopass_buffer_bytes=0;
}
else break;
}
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;
_enc->activity_avg=_enc->rc.cur_metrics.activity_avg;
arg=_enc->rc.cur_metrics.dup_count;
th_encode_ctl(_enc,TH_ENCCTL_SET_DUP_COUNT,&arg,sizeof(arg));
_enc->rc.twopass_buffer_bytes=1;
}
}
}
}
return (int)consumed;
}