Mercurial > mplayer.hg
annotate divx4_vbr.c @ 18385:4cdb4082d899
French Fixes by Pierre Lombard, (and 10l to me for not checking they were
conflicts on my tree before committing, so previous version was probably
not even building cleanly).
author | gpoirier |
---|---|
date | Thu, 04 May 2006 12:36:34 +0000 |
parents | f580a7755ac5 |
children | 682a16136d6c |
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 | |
17566
f580a7755ac5
Patch by Stefan Huehner / stefan % huehner ! org \
rathann
parents:
13699
diff
changeset
|
319 int VbrControl_get_intra(void) |
2641 | 320 { |
321 return m_vFrames[m_iCount].is_key_frame; | |
322 } | |
323 | |
17566
f580a7755ac5
Patch by Stefan Huehner / stefan % huehner ! org \
rathann
parents:
13699
diff
changeset
|
324 short VbrControl_get_drop(void) |
2641 | 325 { |
326 return m_bDrop; | |
327 } | |
328 | |
17566
f580a7755ac5
Patch by Stefan Huehner / stefan % huehner ! org \
rathann
parents:
13699
diff
changeset
|
329 int VbrControl_get_quant(void) |
2641 | 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 | |
17566
f580a7755ac5
Patch by Stefan Huehner / stefan % huehner ! org \
rathann
parents:
13699
diff
changeset
|
343 void VbrControl_update_1pass_vbr(void) |
2641 | 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 | |
17566
f580a7755ac5
Patch by Stefan Huehner / stefan % huehner ! org \
rathann
parents:
13699
diff
changeset
|
398 void VbrControl_close(void) |
2641 | 399 { |
400 if(m_pFile) | |
401 { | |
402 fclose(m_pFile); | |
403 m_pFile=NULL; | |
404 } | |
405 free(m_vFrames); | |
406 } |