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