Mercurial > mplayer.hg
annotate divx4_vbr.c @ 13922:3464287970af
sync 1.803
author | wight |
---|---|
date | Thu, 11 Nov 2004 20:33:29 +0000 |
parents | 11b249ef87b0 |
children | f580a7755ac5 |
rev | line source |
---|---|
2641 | 1 /* |
2 * divx4_vbr.c | |
3 * | |
7491 | 4 * This file is subject to the terms and conditions of the GNU General Public |
5 * License. See the file COPYING in the main directory of the Linux | |
6 * distribution for more details. | |
2641 | 7 * |
8 * 2-pass code OpenDivX port: | |
9 * Copyright (C) 2001 Christoph Lampert <gruel@gmx.de> | |
10 * | |
7491 | 11 * Large parts of this code were taken from VbrControl() from the OpenDivX |
12 * project, (C) divxnetworks, written by Eugene Kuznetsov <ekuznetsov@divxnetworks.com> | |
13 * with the permission of Darrius "Junto" Thompson, Director DivX | |
2641 | 14 */ |
15 | |
16 #include <stdio.h> | |
17 #include <stdlib.h> | |
2642 | 18 #include <string.h> |
2641 | 19 #include <unistd.h> |
20 #include <fcntl.h> | |
21 #include <math.h> | |
4003
92c59012249d
stdint.h replaced by inttypes.h (used more frequently in the sources)
pl
parents:
3919
diff
changeset
|
22 #include <inttypes.h> |
2642 | 23 |
24 #include "divx4_vbr.h" | |
25 | |
13699
11b249ef87b0
printf --> mp_msg by the Wanderer <inverseparadox at comcast dot net>
diego
parents:
8254
diff
changeset
|
26 #include "mp_msg.h" |
11b249ef87b0
printf --> mp_msg by the Wanderer <inverseparadox at comcast dot net>
diego
parents:
8254
diff
changeset
|
27 #include "help_mp.h" |
11b249ef87b0
printf --> mp_msg by the Wanderer <inverseparadox at comcast dot net>
diego
parents:
8254
diff
changeset
|
28 |
2642 | 29 //#include "transcode.h" |
2641 | 30 |
31 #define FALSE 0 | |
32 #define TRUE 1 | |
33 | |
34 /* Absolute maximum and minimum quantizers used in VBR modes */ | |
35 static const int min_quantizer=1; | |
36 static const int max_quantizer=31; | |
37 | |
38 /* Limits on frame-level deviation of quantizer ( higher values | |
39 correspond to frames with more changes and vice versa ) */ | |
40 static const float min_quant_delta=-10.f; | |
41 static const float max_quant_delta=5.f; | |
42 /* Limits on stream-level deviation of quantizer ( used to make | |
43 overall bitrate of stream close to requested value ) */ | |
44 static const float min_rc_quant_delta=.6f; | |
45 static const float max_rc_quant_delta=1.5f; | |
46 | |
47 /* Crispness parameter controls threshold for decision whether | |
48 to skip the frame or to code it. */ | |
49 //static const float max_crispness=100.f; | |
50 /* Maximum allowed number of skipped frames in a line. */ | |
51 //static const int max_drops_line=0; // CHL We don't drop frames at the moment! | |
52 | |
53 | |
54 typedef struct entry_s | |
55 /* max 28 bytes/frame or 5 Mb for 2-hour movie */ | |
56 { | |
57 int quant; | |
58 int text_bits; | |
59 int motion_bits; | |
60 int total_bits; | |
61 float mult; | |
62 short is_key_frame; | |
63 short drop; | |
64 } entry; | |
65 | |
2642 | 66 static int m_iCount; |
67 static int m_iQuant; | |
8254
772d6d27fd66
warning patch by (Dominik Mierzejewski <dominik at rangers dot eu dot org>)
michael
parents:
7491
diff
changeset
|
68 /*static int m_iCrispness;*/ |
2642 | 69 static short m_bDrop; |
70 static float m_fQuant; | |
2641 | 71 |
2642 | 72 static int64_t m_lEncodedBits; |
73 static int64_t m_lExpectedBits; | |
2641 | 74 |
2642 | 75 static FILE *m_pFile; |
2641 | 76 |
2642 | 77 static entry vFrame; |
78 static entry *m_vFrames; | |
79 static long lFrameStart; | |
2641 | 80 |
2642 | 81 static int iNumFrames; |
82 static int dummy; | |
2641 | 83 |
84 | |
85 void VbrControl_init_1pass_vbr(int quality, int crispness) | |
86 { | |
87 m_fQuant=min_quantizer+((max_quantizer-min_quantizer)/6.)*(6-quality); | |
88 m_iCount=0; | |
89 m_bDrop=FALSE; | |
90 VbrControl_update_1pass_vbr(); | |
91 } | |
92 | |
93 int VbrControl_init_2pass_vbr_analysis(const char *filename, int quality) | |
94 { | |
95 m_pFile=fopen(filename, "wb"); | |
96 if(m_pFile==0) | |
97 return -1; | |
98 m_iCount=0; | |
99 m_bDrop=FALSE; | |
100 fprintf(m_pFile, "##version 1\n"); | |
101 fprintf(m_pFile, "quality %d\n", quality); | |
102 return 0; | |
103 } | |
104 | |
105 int VbrControl_init_2pass_vbr_encoding(const char *filename, int bitrate, double framerate, int crispness, int quality) | |
106 { | |
107 int i; | |
108 | |
109 int64_t text_bits=0; | |
110 int64_t total_bits=0; | |
111 int64_t complexity=0; | |
112 int64_t new_complexity=0; | |
113 int64_t motion_bits=0; | |
114 int64_t denominator=0; | |
115 float qual_multiplier=1.; | |
116 char head[20]; | |
117 | |
118 int64_t desired_bits; | |
119 int64_t non_text_bits; | |
120 | |
121 float average_complexity; | |
122 | |
123 m_pFile=fopen(filename, "rb"); | |
124 if(m_pFile==0) | |
125 return -1; | |
126 m_bDrop=FALSE; | |
127 m_iCount=0; | |
128 | |
129 fread(head, 10, 1, m_pFile); | |
130 if(!strncmp("##version ", head, 10)) | |
131 { | |
132 int version; | |
133 int iOldQual; | |
134 float old_qual, new_qual; | |
135 fscanf(m_pFile, "%d\n", &version); | |
136 fscanf(m_pFile, "quality %d\n", &iOldQual); | |
137 switch(iOldQual) | |
138 { | |
139 case 5: | |
140 old_qual=1.f; | |
141 break; | |
142 case 4: | |
143 old_qual=1.1f; | |
144 break; | |
145 case 3: | |
146 old_qual=1.25f; | |
147 break; | |
148 case 2: | |
149 old_qual=1.4f; | |
150 break; | |
151 case 1: | |
152 old_qual=2.f; | |
153 break; | |
154 } | |
155 switch(quality) | |
156 { | |
157 case 5: | |
158 new_qual=1.f; | |
159 break; | |
160 case 4: | |
161 new_qual=1.1f; | |
162 break; | |
163 case 3: | |
164 new_qual=1.25f; | |
165 break; | |
166 case 2: | |
167 new_qual=1.4f; | |
168 break; | |
169 case 1: | |
170 new_qual=2.f; | |
171 break; | |
172 } | |
173 qual_multiplier=new_qual/old_qual; | |
174 } | |
175 else | |
176 fseek(m_pFile, 0, SEEK_SET); | |
177 | |
178 lFrameStart=ftell(m_pFile); // save current position | |
179 | |
180 /* removed C++ dependencies, now read file twice :-( */ | |
181 | |
182 | |
183 while(!feof(m_pFile)) | |
8254
772d6d27fd66
warning patch by (Dominik Mierzejewski <dominik at rangers dot eu dot org>)
michael
parents:
7491
diff
changeset
|
184 { fscanf(m_pFile, "Frame %d: intra %hd, quant %d, texture %d, motion %d, total %d\n", |
2641 | 185 &iNumFrames, &(vFrame.is_key_frame), &(vFrame.quant), &(vFrame.text_bits), &(vFrame.motion_bits), &(vFrame.total_bits)); |
186 | |
187 vFrame.total_bits+=vFrame.text_bits*(qual_multiplier-1); | |
188 vFrame.text_bits*=qual_multiplier; | |
189 text_bits +=(int64_t)vFrame.text_bits; | |
190 motion_bits += (int64_t)vFrame.motion_bits; | |
191 total_bits +=(int64_t)vFrame.total_bits; | |
192 complexity +=(int64_t)vFrame.text_bits*vFrame.quant; | |
193 | |
194 // printf("Frames %d, texture %d, motion %d, quant %d total %d ", | |
195 // iNumFrames, vFrame.text_bits, vFrame.motion_bits, vFrame.quant, vFrame.total_bits); | |
196 // printf("texture %d, total %d, complexity %lld \n",vFrame.text_bits,vFrame.total_bits, complexity); | |
197 } | |
198 iNumFrames++; | |
199 average_complexity=complexity/iNumFrames; | |
200 | |
2642 | 201 // if (verbose & TC_DEBUG) { |
202 // fprintf(stderr, "(%s) frames %d, texture %lld, motion %lld, total %lld, complexity %lld\n", __FILE__, iNumFrames, text_bits, motion_bits, total_bits, complexity); | |
203 // } | |
2641 | 204 |
205 m_vFrames = (entry*)malloc(iNumFrames*sizeof(entry)); | |
206 if (!m_vFrames) | |
13699
11b249ef87b0
printf --> mp_msg by the Wanderer <inverseparadox at comcast dot net>
diego
parents:
8254
diff
changeset
|
207 { mp_msg(MSGT_FIXME, MSGL_FIXME,MSGTR_OutOfMemory); |
2642 | 208 return -2; //TC_EXPORT_ERROR; |
2641 | 209 } |
210 | |
211 fseek(m_pFile, lFrameStart, SEEK_SET); // start again | |
212 | |
213 for (i=0;i<iNumFrames;i++) | |
8254
772d6d27fd66
warning patch by (Dominik Mierzejewski <dominik at rangers dot eu dot org>)
michael
parents:
7491
diff
changeset
|
214 { fscanf(m_pFile, "Frame %d: intra %hd, quant %d, texture %d, motion %d, total %d\n", |
2641 | 215 &dummy, &(m_vFrames[i].is_key_frame), &(m_vFrames[i].quant), |
216 &(m_vFrames[i].text_bits), &(m_vFrames[i].motion_bits), | |
217 &(m_vFrames[i].total_bits)); | |
218 | |
219 m_vFrames[i].total_bits += m_vFrames[i].text_bits*(qual_multiplier-1); | |
220 m_vFrames[i].text_bits *= qual_multiplier; | |
221 } | |
222 | |
223 if (m_pFile) | |
224 { fclose(m_pFile); | |
225 m_pFile=NULL; | |
226 } | |
227 | |
228 desired_bits=(int64_t)bitrate*(int64_t)iNumFrames/framerate; | |
229 non_text_bits=total_bits-text_bits; | |
230 | |
231 if(desired_bits<=non_text_bits) | |
232 { | |
8254
772d6d27fd66
warning patch by (Dominik Mierzejewski <dominik at rangers dot eu dot org>)
michael
parents:
7491
diff
changeset
|
233 /* char s[200];*/ |
13699
11b249ef87b0
printf --> mp_msg by the Wanderer <inverseparadox at comcast dot net>
diego
parents:
8254
diff
changeset
|
234 mp_msg(MSGT_FIXME, MSGL_FIXME, MSGTR_OverridingTooLowBitrate, |
2641 | 235 (float)(non_text_bits*framerate/(int64_t)iNumFrames)); |
236 | |
237 desired_bits=non_text_bits*3/2; | |
238 /* | |
239 m_fQuant=max_quantizer; | |
240 for(int i=0; i<iNumFrames; i++) | |
241 { | |
242 m_vFrames[i].drop=0; | |
243 m_vFrames[i].mult=1; | |
244 } | |
245 VbrControl_set_quant(m_fQuant); | |
246 return 0; | |
247 */ | |
248 } | |
249 | |
250 desired_bits -= non_text_bits; | |
251 /** | |
252 BRIEF EXPLANATION OF WHAT'S GOING ON HERE. | |
253 We assume that | |
254 text_bits=complexity / quantizer | |
255 total_bits-text_bits = const(complexity) | |
256 where 'complexity' is a characteristic of the frame | |
257 and does not depend much on quantizer dynamics. | |
258 Using this equation, we calculate 'average' quantizer | |
259 to be used for encoding ( 1st order effect ). | |
260 Having constant quantizer for the entire stream is not | |
261 very convenient - reconstruction errors are | |
262 more noticeable in low-motion scenes. To compensate | |
263 this effect, we multiply quantizer for each frame by | |
264 (complexity/average_complexity)^k, | |
265 ( k - parameter of adjustment ). k=0 means 'no compensation' | |
266 and k=1 is 'constant bitrate mode'. We choose something in | |
267 between, like 0.5 ( 2nd order effect ). | |
268 **/ | |
269 | |
270 average_complexity=complexity/iNumFrames; | |
271 | |
272 for(i=0; i<iNumFrames; i++) | |
273 { | |
274 float mult; | |
275 if(m_vFrames[i].is_key_frame) | |
276 { | |
277 if((i+1<iNumFrames) && (m_vFrames[i+1].is_key_frame)) | |
278 mult=1.25; | |
279 else | |
280 mult=.75; | |
281 } | |
282 else | |
283 { | |
284 mult=m_vFrames[i].text_bits*m_vFrames[i].quant; | |
285 mult=(float)sqrt(mult/average_complexity); | |
286 | |
287 // if(i && m_vFrames[i-1].is_key_frame) | |
288 // mult *= 0.75; | |
289 if(mult<0.5) | |
290 mult=0.5; | |
291 if(mult>1.5) | |
292 mult=1.5; | |
293 } | |
294 | |
295 m_vFrames[i].mult=mult; | |
296 m_vFrames[i].drop=FALSE; | |
297 new_complexity+=m_vFrames[i].text_bits*m_vFrames[i].quant; | |
298 | |
299 denominator+=desired_bits*m_vFrames[i].mult/iNumFrames; | |
300 } | |
301 | |
302 m_fQuant=((double)new_complexity)/(double)denominator; | |
303 | |
304 if(m_fQuant<min_quantizer) m_fQuant=min_quantizer; | |
305 if(m_fQuant>max_quantizer) m_fQuant=max_quantizer; | |
306 m_pFile=fopen("analyse.log", "wb"); | |
307 if(m_pFile) | |
308 { | |
309 fprintf(m_pFile, "Total frames: %d Avg quantizer: %f\n", | |
310 iNumFrames, m_fQuant); | |
311 fprintf(m_pFile, "Expecting %12lld bits\n", desired_bits+non_text_bits); | |
312 fflush(m_pFile); | |
313 } | |
314 VbrControl_set_quant(m_fQuant*m_vFrames[0].mult); | |
315 m_lEncodedBits=m_lExpectedBits=0; | |
316 return 0; | |
317 } | |
318 | |
319 int VbrControl_get_intra() | |
320 { | |
321 return m_vFrames[m_iCount].is_key_frame; | |
322 } | |
323 | |
324 short VbrControl_get_drop() | |
325 { | |
326 return m_bDrop; | |
327 } | |
328 | |
329 int VbrControl_get_quant() | |
330 { | |
331 return m_iQuant; | |
332 } | |
333 | |
334 void VbrControl_set_quant(float quant) | |
335 { | |
336 m_iQuant=quant; | |
337 if((rand() % 10)<((quant-m_iQuant) * 10)) | |
338 m_iQuant++; | |
339 if(m_iQuant<min_quantizer) m_iQuant=min_quantizer; | |
340 if(m_iQuant>max_quantizer) m_iQuant=max_quantizer; | |
341 } | |
342 | |
343 void VbrControl_update_1pass_vbr() | |
344 { | |
345 VbrControl_set_quant(m_fQuant); | |
346 m_iCount++; | |
347 } | |
348 | |
349 void VbrControl_update_2pass_vbr_analysis(int is_key_frame, int motion_bits, int texture_bits, int total_bits, int quant) | |
350 { | |
351 if(!m_pFile) | |
352 return; | |
353 fprintf(m_pFile, "Frame %d: intra %d, quant %d, texture %d, motion %d, total %d\n", | |
354 m_iCount, is_key_frame, quant, texture_bits, motion_bits, total_bits); | |
355 m_iCount++; | |
356 } | |
357 | |
358 void VbrControl_update_2pass_vbr_encoding(int motion_bits, int texture_bits, int total_bits) | |
359 { | |
360 double q; | |
361 double dq; | |
362 | |
363 if(m_iCount>=iNumFrames) | |
364 return; | |
365 | |
366 m_lExpectedBits+=(m_vFrames[m_iCount].total_bits-m_vFrames[m_iCount].text_bits) | |
367 + m_vFrames[m_iCount].text_bits*m_vFrames[m_iCount].quant/m_fQuant; | |
368 m_lEncodedBits+=(int64_t)total_bits; | |
369 | |
370 if(m_pFile) | |
371 fprintf(m_pFile, "Frame %d: PRESENT, complexity %d, quant multiplier %f, texture %d, total %d ", | |
372 m_iCount, m_vFrames[m_iCount].text_bits*m_vFrames[m_iCount].quant, | |
373 m_vFrames[m_iCount].mult, texture_bits, total_bits); | |
374 | |
375 m_iCount++; | |
376 | |
377 q = m_fQuant * m_vFrames[m_iCount].mult; | |
378 if(q<m_fQuant+min_quant_delta) q=m_fQuant+min_quant_delta; | |
379 if(q>m_fQuant+max_quant_delta) q=m_fQuant+max_quant_delta; | |
380 | |
381 dq = (double)m_lEncodedBits/(double)m_lExpectedBits; | |
382 dq*=dq; | |
383 if(dq<min_rc_quant_delta) | |
384 dq=min_rc_quant_delta; | |
385 if(dq>max_rc_quant_delta) | |
386 dq=max_rc_quant_delta; | |
387 if(m_iCount<20) // no framerate corrections in first frames | |
388 dq=1; | |
389 if(m_pFile) | |
390 fprintf(m_pFile, "Progress: expected %12lld, achieved %12lld, dq %f", | |
391 m_lExpectedBits, m_lEncodedBits, dq); | |
392 q *= dq; | |
393 VbrControl_set_quant(q); | |
394 if(m_pFile) | |
395 fprintf(m_pFile, ", new quant %d\n", m_iQuant); | |
396 } | |
397 | |
398 void VbrControl_close() | |
399 { | |
400 if(m_pFile) | |
401 { | |
402 fclose(m_pFile); | |
403 m_pFile=NULL; | |
404 } | |
405 free(m_vFrames); | |
406 } |