|
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: bitrate.c 16227 2009-07-08 06:58:46Z xiphmont $ |
|
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 void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bm){ |
|
30 codec_setup_info *ci=vi->codec_setup; |
|
31 bitrate_manager_info *bi=&ci->bi; |
|
32 |
|
33 memset(bm,0,sizeof(*bm)); |
|
34 |
|
35 if(bi && (bi->reservoir_bits>0)){ |
|
36 long ratesamples=vi->rate; |
|
37 int halfsamples=ci->blocksizes[0]>>1; |
|
38 |
|
39 bm->short_per_long=ci->blocksizes[1]/ci->blocksizes[0]; |
|
40 bm->managed=1; |
|
41 |
|
42 bm->avg_bitsper= rint(1.*bi->avg_rate*halfsamples/ratesamples); |
|
43 bm->min_bitsper= rint(1.*bi->min_rate*halfsamples/ratesamples); |
|
44 bm->max_bitsper= rint(1.*bi->max_rate*halfsamples/ratesamples); |
|
45 |
|
46 bm->avgfloat=PACKETBLOBS/2; |
|
47 |
|
48 /* not a necessary fix, but one that leads to a more balanced |
|
49 typical initialization */ |
|
50 { |
|
51 long desired_fill=bi->reservoir_bits*bi->reservoir_bias; |
|
52 bm->minmax_reservoir=desired_fill; |
|
53 bm->avg_reservoir=desired_fill; |
|
54 } |
|
55 |
|
56 } |
|
57 } |
|
58 |
|
59 void vorbis_bitrate_clear(bitrate_manager_state *bm){ |
|
60 memset(bm,0,sizeof(*bm)); |
|
61 return; |
|
62 } |
|
63 |
|
64 int vorbis_bitrate_managed(vorbis_block *vb){ |
|
65 vorbis_dsp_state *vd=vb->vd; |
|
66 private_state *b=vd->backend_state; |
|
67 bitrate_manager_state *bm=&b->bms; |
|
68 |
|
69 if(bm && bm->managed)return(1); |
|
70 return(0); |
|
71 } |
|
72 |
|
73 /* finish taking in the block we just processed */ |
|
74 int vorbis_bitrate_addblock(vorbis_block *vb){ |
|
75 vorbis_block_internal *vbi=vb->internal; |
|
76 vorbis_dsp_state *vd=vb->vd; |
|
77 private_state *b=vd->backend_state; |
|
78 bitrate_manager_state *bm=&b->bms; |
|
79 vorbis_info *vi=vd->vi; |
|
80 codec_setup_info *ci=vi->codec_setup; |
|
81 bitrate_manager_info *bi=&ci->bi; |
|
82 |
|
83 int choice=rint(bm->avgfloat); |
|
84 long this_bits=oggpack_bytes(vbi->packetblob[choice])*8; |
|
85 long min_target_bits=(vb->W?bm->min_bitsper*bm->short_per_long:bm->min_bitsper); |
|
86 long max_target_bits=(vb->W?bm->max_bitsper*bm->short_per_long:bm->max_bitsper); |
|
87 int samples=ci->blocksizes[vb->W]>>1; |
|
88 long desired_fill=bi->reservoir_bits*bi->reservoir_bias; |
|
89 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 if(bm->vb)return(-1); /* one has been submitted without |
|
94 being claimed */ |
|
95 bm->vb=vb; |
|
96 return(0); |
|
97 } |
|
98 |
|
99 bm->vb=vb; |
|
100 |
|
101 /* look ahead for avg floater */ |
|
102 if(bm->avg_bitsper>0){ |
|
103 double slew=0.; |
|
104 long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper); |
|
105 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 if(bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){ |
|
119 while(choice>0 && this_bits>avg_target_bits && |
|
120 bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){ |
|
121 choice--; |
|
122 this_bits=oggpack_bytes(vbi->packetblob[choice])*8; |
|
123 } |
|
124 }else if(bm->avg_reservoir+(this_bits-avg_target_bits)<desired_fill){ |
|
125 while(choice+1<PACKETBLOBS && this_bits<avg_target_bits && |
|
126 bm->avg_reservoir+(this_bits-avg_target_bits)<desired_fill){ |
|
127 choice++; |
|
128 this_bits=oggpack_bytes(vbi->packetblob[choice])*8; |
|
129 } |
|
130 } |
|
131 |
|
132 slew=rint(choice-bm->avgfloat)/samples*vi->rate; |
|
133 if(slew<-slewlimit)slew=-slewlimit; |
|
134 if(slew>slewlimit)slew=slewlimit; |
|
135 choice=rint(bm->avgfloat+= slew/vi->rate*samples); |
|
136 this_bits=oggpack_bytes(vbi->packetblob[choice])*8; |
|
137 } |
|
138 |
|
139 |
|
140 |
|
141 /* enforce min(if used) on the current floater (if used) */ |
|
142 if(bm->min_bitsper>0){ |
|
143 /* do we need to force the bitrate up? */ |
|
144 if(this_bits<min_target_bits){ |
|
145 while(bm->minmax_reservoir-(min_target_bits-this_bits)<0){ |
|
146 choice++; |
|
147 if(choice>=PACKETBLOBS)break; |
|
148 this_bits=oggpack_bytes(vbi->packetblob[choice])*8; |
|
149 } |
|
150 } |
|
151 } |
|
152 |
|
153 /* enforce max (if used) on the current floater (if used) */ |
|
154 if(bm->max_bitsper>0){ |
|
155 /* do we need to force the bitrate down? */ |
|
156 if(this_bits>max_target_bits){ |
|
157 while(bm->minmax_reservoir+(this_bits-max_target_bits)>bi->reservoir_bits){ |
|
158 choice--; |
|
159 if(choice<0)break; |
|
160 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 if(choice<0){ |
|
169 /* choosing a smaller packetblob is insufficient to trim bitrate. |
|
170 frame will need to be truncated */ |
|
171 long maxsize=(max_target_bits+(bi->reservoir_bits-bm->minmax_reservoir))/8; |
|
172 bm->choice=choice=0; |
|
173 |
|
174 if(oggpack_bytes(vbi->packetblob[choice])>maxsize){ |
|
175 |
|
176 oggpack_writetrunc(vbi->packetblob[choice],maxsize*8); |
|
177 this_bits=oggpack_bytes(vbi->packetblob[choice])*8; |
|
178 } |
|
179 }else{ |
|
180 long minsize=(min_target_bits-bm->minmax_reservoir+7)/8; |
|
181 if(choice>=PACKETBLOBS) |
|
182 choice=PACKETBLOBS-1; |
|
183 |
|
184 bm->choice=choice; |
|
185 |
|
186 /* prop up bitrate according to demand. pad this frame out with zeroes */ |
|
187 minsize-=oggpack_bytes(vbi->packetblob[choice]); |
|
188 while(minsize-->0)oggpack_write(vbi->packetblob[choice],0,8); |
|
189 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 if(bm->min_bitsper>0 || bm->max_bitsper>0){ |
|
196 |
|
197 if(max_target_bits>0 && this_bits>max_target_bits){ |
|
198 bm->minmax_reservoir+=(this_bits-max_target_bits); |
|
199 }else if(min_target_bits>0 && this_bits<min_target_bits){ |
|
200 bm->minmax_reservoir+=(this_bits-min_target_bits); |
|
201 }else{ |
|
202 /* inbetween; we want to take reservoir toward but not past desired_fill */ |
|
203 if(bm->minmax_reservoir>desired_fill){ |
|
204 if(max_target_bits>0){ /* logical bulletproofing against initialization state */ |
|
205 bm->minmax_reservoir+=(this_bits-max_target_bits); |
|
206 if(bm->minmax_reservoir<desired_fill)bm->minmax_reservoir=desired_fill; |
|
207 }else{ |
|
208 bm->minmax_reservoir=desired_fill; |
|
209 } |
|
210 }else{ |
|
211 if(min_target_bits>0){ /* logical bulletproofing against initialization state */ |
|
212 bm->minmax_reservoir+=(this_bits-min_target_bits); |
|
213 if(bm->minmax_reservoir>desired_fill)bm->minmax_reservoir=desired_fill; |
|
214 }else{ |
|
215 bm->minmax_reservoir=desired_fill; |
|
216 } |
|
217 } |
|
218 } |
|
219 } |
|
220 |
|
221 /* avg reservoir */ |
|
222 if(bm->avg_bitsper>0){ |
|
223 long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper); |
|
224 bm->avg_reservoir+=this_bits-avg_target_bits; |
|
225 } |
|
226 |
|
227 return(0); |
|
228 } |
|
229 |
|
230 int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd,ogg_packet *op){ |
|
231 private_state *b=vd->backend_state; |
|
232 bitrate_manager_state *bm=&b->bms; |
|
233 vorbis_block *vb=bm->vb; |
|
234 int choice=PACKETBLOBS/2; |
|
235 if(!vb)return 0; |
|
236 |
|
237 if(op){ |
|
238 vorbis_block_internal *vbi=vb->internal; |
|
239 |
|
240 if(vorbis_bitrate_managed(vb)) |
|
241 choice=bm->choice; |
|
242 |
|
243 op->packet=oggpack_get_buffer(vbi->packetblob[choice]); |
|
244 op->bytes=oggpack_bytes(vbi->packetblob[choice]); |
|
245 op->b_o_s=0; |
|
246 op->e_o_s=vb->eofflag; |
|
247 op->granulepos=vb->granulepos; |
|
248 op->packetno=vb->sequence; /* for sake of completeness */ |
|
249 } |
|
250 |
|
251 bm->vb=0; |
|
252 return(1); |
|
253 } |