Line data Source code
1 : /********************************************************************
2 : * *
3 : * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
4 : * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 : * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 : * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 : * *
8 : * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
9 : * by the Xiph.Org Foundation http://www.xiph.org/ *
10 : * *
11 : ********************************************************************
12 :
13 : function: bitrate tracking and management
14 : last mod: $Id$
15 :
16 : ********************************************************************/
17 :
18 : #include <stdlib.h>
19 : #include <string.h>
20 : #include <math.h>
21 : #include <ogg/ogg.h>
22 : #include "vorbis/codec.h"
23 : #include "codec_internal.h"
24 : #include "os.h"
25 : #include "misc.h"
26 : #include "bitrate.h"
27 :
28 : /* compute bitrate tracking setup */
29 0 : void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bm){
30 0 : codec_setup_info *ci=vi->codec_setup;
31 0 : bitrate_manager_info *bi=&ci->bi;
32 :
33 0 : memset(bm,0,sizeof(*bm));
34 :
35 0 : if(bi && (bi->reservoir_bits>0)){
36 0 : long ratesamples=vi->rate;
37 0 : int halfsamples=ci->blocksizes[0]>>1;
38 :
39 0 : bm->short_per_long=ci->blocksizes[1]/ci->blocksizes[0];
40 0 : bm->managed=1;
41 :
42 0 : bm->avg_bitsper= rint(1.*bi->avg_rate*halfsamples/ratesamples);
43 0 : bm->min_bitsper= rint(1.*bi->min_rate*halfsamples/ratesamples);
44 0 : bm->max_bitsper= rint(1.*bi->max_rate*halfsamples/ratesamples);
45 :
46 0 : bm->avgfloat=PACKETBLOBS/2;
47 :
48 : /* not a necessary fix, but one that leads to a more balanced
49 : typical initialization */
50 : {
51 0 : long desired_fill=bi->reservoir_bits*bi->reservoir_bias;
52 0 : bm->minmax_reservoir=desired_fill;
53 0 : bm->avg_reservoir=desired_fill;
54 : }
55 :
56 : }
57 0 : }
58 :
59 0 : void vorbis_bitrate_clear(bitrate_manager_state *bm){
60 0 : memset(bm,0,sizeof(*bm));
61 0 : return;
62 : }
63 :
64 0 : int vorbis_bitrate_managed(vorbis_block *vb){
65 0 : vorbis_dsp_state *vd=vb->vd;
66 0 : private_state *b=vd->backend_state;
67 0 : bitrate_manager_state *bm=&b->bms;
68 :
69 0 : if(bm && bm->managed)return(1);
70 0 : return(0);
71 : }
72 :
73 : /* finish taking in the block we just processed */
74 0 : int vorbis_bitrate_addblock(vorbis_block *vb){
75 0 : vorbis_block_internal *vbi=vb->internal;
76 0 : vorbis_dsp_state *vd=vb->vd;
77 0 : private_state *b=vd->backend_state;
78 0 : bitrate_manager_state *bm=&b->bms;
79 0 : vorbis_info *vi=vd->vi;
80 0 : codec_setup_info *ci=vi->codec_setup;
81 0 : bitrate_manager_info *bi=&ci->bi;
82 :
83 0 : int choice=rint(bm->avgfloat);
84 0 : long this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
85 0 : long min_target_bits=(vb->W?bm->min_bitsper*bm->short_per_long:bm->min_bitsper);
86 0 : long max_target_bits=(vb->W?bm->max_bitsper*bm->short_per_long:bm->max_bitsper);
87 0 : int samples=ci->blocksizes[vb->W]>>1;
88 0 : long desired_fill=bi->reservoir_bits*bi->reservoir_bias;
89 0 : if(!bm->managed){
90 : /* not a bitrate managed stream, but for API simplicity, we'll
91 : buffer the packet to keep the code path clean */
92 :
93 0 : if(bm->vb)return(-1); /* one has been submitted without
94 : being claimed */
95 0 : bm->vb=vb;
96 0 : return(0);
97 : }
98 :
99 0 : bm->vb=vb;
100 :
101 : /* look ahead for avg floater */
102 0 : if(bm->avg_bitsper>0){
103 0 : double slew=0.;
104 0 : long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper);
105 0 : double slewlimit= 15./bi->slew_damp;
106 :
107 : /* choosing a new floater:
108 : if we're over target, we slew down
109 : if we're under target, we slew up
110 :
111 : choose slew as follows: look through packetblobs of this frame
112 : and set slew as the first in the appropriate direction that
113 : gives us the slew we want. This may mean no slew if delta is
114 : already favorable.
115 :
116 : Then limit slew to slew max */
117 :
118 0 : if(bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){
119 0 : while(choice>0 && this_bits>avg_target_bits &&
120 0 : bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){
121 0 : choice--;
122 0 : this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
123 : }
124 0 : }else if(bm->avg_reservoir+(this_bits-avg_target_bits)<desired_fill){
125 0 : while(choice+1<PACKETBLOBS && this_bits<avg_target_bits &&
126 0 : bm->avg_reservoir+(this_bits-avg_target_bits)<desired_fill){
127 0 : choice++;
128 0 : this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
129 : }
130 : }
131 :
132 0 : slew=rint(choice-bm->avgfloat)/samples*vi->rate;
133 0 : if(slew<-slewlimit)slew=-slewlimit;
134 0 : if(slew>slewlimit)slew=slewlimit;
135 0 : choice=rint(bm->avgfloat+= slew/vi->rate*samples);
136 0 : this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
137 : }
138 :
139 :
140 :
141 : /* enforce min(if used) on the current floater (if used) */
142 0 : if(bm->min_bitsper>0){
143 : /* do we need to force the bitrate up? */
144 0 : if(this_bits<min_target_bits){
145 0 : while(bm->minmax_reservoir-(min_target_bits-this_bits)<0){
146 0 : choice++;
147 0 : if(choice>=PACKETBLOBS)break;
148 0 : this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
149 : }
150 : }
151 : }
152 :
153 : /* enforce max (if used) on the current floater (if used) */
154 0 : if(bm->max_bitsper>0){
155 : /* do we need to force the bitrate down? */
156 0 : if(this_bits>max_target_bits){
157 0 : while(bm->minmax_reservoir+(this_bits-max_target_bits)>bi->reservoir_bits){
158 0 : choice--;
159 0 : if(choice<0)break;
160 0 : this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
161 : }
162 : }
163 : }
164 :
165 : /* Choice of packetblobs now made based on floater, and min/max
166 : requirements. Now boundary check extreme choices */
167 :
168 0 : if(choice<0){
169 : /* choosing a smaller packetblob is insufficient to trim bitrate.
170 : frame will need to be truncated */
171 0 : long maxsize=(max_target_bits+(bi->reservoir_bits-bm->minmax_reservoir))/8;
172 0 : bm->choice=choice=0;
173 :
174 0 : if(oggpack_bytes(vbi->packetblob[choice])>maxsize){
175 :
176 0 : oggpack_writetrunc(vbi->packetblob[choice],maxsize*8);
177 0 : this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
178 : }
179 : }else{
180 0 : long minsize=(min_target_bits-bm->minmax_reservoir+7)/8;
181 0 : if(choice>=PACKETBLOBS)
182 0 : choice=PACKETBLOBS-1;
183 :
184 0 : bm->choice=choice;
185 :
186 : /* prop up bitrate according to demand. pad this frame out with zeroes */
187 0 : minsize-=oggpack_bytes(vbi->packetblob[choice]);
188 0 : while(minsize-->0)oggpack_write(vbi->packetblob[choice],0,8);
189 0 : this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
190 :
191 : }
192 :
193 : /* now we have the final packet and the final packet size. Update statistics */
194 : /* min and max reservoir */
195 0 : if(bm->min_bitsper>0 || bm->max_bitsper>0){
196 :
197 0 : if(max_target_bits>0 && this_bits>max_target_bits){
198 0 : bm->minmax_reservoir+=(this_bits-max_target_bits);
199 0 : }else if(min_target_bits>0 && this_bits<min_target_bits){
200 0 : bm->minmax_reservoir+=(this_bits-min_target_bits);
201 : }else{
202 : /* inbetween; we want to take reservoir toward but not past desired_fill */
203 0 : if(bm->minmax_reservoir>desired_fill){
204 0 : if(max_target_bits>0){ /* logical bulletproofing against initialization state */
205 0 : bm->minmax_reservoir+=(this_bits-max_target_bits);
206 0 : if(bm->minmax_reservoir<desired_fill)bm->minmax_reservoir=desired_fill;
207 : }else{
208 0 : bm->minmax_reservoir=desired_fill;
209 : }
210 : }else{
211 0 : if(min_target_bits>0){ /* logical bulletproofing against initialization state */
212 0 : bm->minmax_reservoir+=(this_bits-min_target_bits);
213 0 : if(bm->minmax_reservoir>desired_fill)bm->minmax_reservoir=desired_fill;
214 : }else{
215 0 : bm->minmax_reservoir=desired_fill;
216 : }
217 : }
218 : }
219 : }
220 :
221 : /* avg reservoir */
222 0 : if(bm->avg_bitsper>0){
223 0 : long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper);
224 0 : bm->avg_reservoir+=this_bits-avg_target_bits;
225 : }
226 :
227 0 : return(0);
228 : }
229 :
230 0 : int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd,ogg_packet *op){
231 0 : private_state *b=vd->backend_state;
232 0 : bitrate_manager_state *bm=&b->bms;
233 0 : vorbis_block *vb=bm->vb;
234 0 : int choice=PACKETBLOBS/2;
235 0 : if(!vb)return 0;
236 :
237 0 : if(op){
238 0 : vorbis_block_internal *vbi=vb->internal;
239 :
240 0 : if(vorbis_bitrate_managed(vb))
241 0 : choice=bm->choice;
242 :
243 0 : op->packet=oggpack_get_buffer(vbi->packetblob[choice]);
244 0 : op->bytes=oggpack_bytes(vbi->packetblob[choice]);
245 0 : op->b_o_s=0;
246 0 : op->e_o_s=vb->eofflag;
247 0 : op->granulepos=vb->granulepos;
248 0 : op->packetno=vb->sequence; /* for sake of completeness */
249 : }
250 :
251 0 : bm->vb=0;
252 0 : return(1);
253 : }
|