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