Mercurial > mplayer.hg
comparison divx4_vbr.c @ 2641:41b67e5e5d38
initial import from transcode
author | arpi |
---|---|
date | Fri, 02 Nov 2001 23:53:44 +0000 |
parents | |
children | 0e6e13261d79 |
comparison
equal
deleted
inserted
replaced
2640:a6c378d5ed3a | 2641:41b67e5e5d38 |
---|---|
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> | |
39 #include <sys/stat.h> | |
40 #include <unistd.h> | |
41 #include <fcntl.h> | |
42 #include <dlfcn.h> | |
43 #include <math.h> | |
44 | |
45 #include <stdint.h> | |
46 | |
47 #include "config.h" | |
48 #include "transcode.h" | |
49 | |
50 #define FALSE 0 | |
51 #define TRUE 1 | |
52 | |
53 /* Absolute maximum and minimum quantizers used in VBR modes */ | |
54 static const int min_quantizer=1; | |
55 static const int max_quantizer=31; | |
56 | |
57 /* Limits on frame-level deviation of quantizer ( higher values | |
58 correspond to frames with more changes and vice versa ) */ | |
59 static const float min_quant_delta=-10.f; | |
60 static const float max_quant_delta=5.f; | |
61 /* Limits on stream-level deviation of quantizer ( used to make | |
62 overall bitrate of stream close to requested value ) */ | |
63 static const float min_rc_quant_delta=.6f; | |
64 static const float max_rc_quant_delta=1.5f; | |
65 | |
66 /* Crispness parameter controls threshold for decision whether | |
67 to skip the frame or to code it. */ | |
68 //static const float max_crispness=100.f; | |
69 /* Maximum allowed number of skipped frames in a line. */ | |
70 //static const int max_drops_line=0; // CHL We don't drop frames at the moment! | |
71 | |
72 | |
73 typedef struct entry_s | |
74 /* max 28 bytes/frame or 5 Mb for 2-hour movie */ | |
75 { | |
76 int quant; | |
77 int text_bits; | |
78 int motion_bits; | |
79 int total_bits; | |
80 float mult; | |
81 short is_key_frame; | |
82 short drop; | |
83 } entry; | |
84 | |
85 int m_iCount; | |
86 int m_iQuant; | |
87 int m_iCrispness; | |
88 short m_bDrop; | |
89 float m_fQuant; | |
90 | |
91 int64_t m_lEncodedBits; | |
92 int64_t m_lExpectedBits; | |
93 | |
94 FILE *m_pFile; | |
95 | |
96 entry vFrame; | |
97 entry *m_vFrames; | |
98 long lFrameStart; | |
99 | |
100 int iNumFrames; | |
101 int dummy; | |
102 | |
103 // methods from class VbrControl | |
104 | |
105 void VbrControl_init_1pass_vbr(int quality, int crispness); | |
106 int VbrControl_init_2pass_vbr_encoding(const char* filename, int bitrate, double framerate, int crispness, int quality); | |
107 int VbrControl_init_2pass_vbr_analysis(const char* filename, int quality); | |
108 | |
109 void VbrControl_update_1pass_vbr(); | |
110 void VbrControl_update_2pass_vbr_encoding(int motion_bits, int texture_bits, int total_bits); | |
111 void VbrControl_update_2pass_vbr_analysis(int is_key_frame, int motion_bits, int texture_bits, int total_bits, int quant); | |
112 | |
113 int VbrControl_get_quant(); | |
114 void VbrControl_set_quant(float q); | |
115 int VbrControl_get_intra(); | |
116 short VbrControl_get_drop(); | |
117 void VbrControl_close(); | |
118 | |
119 | |
120 void VbrControl_init_1pass_vbr(int quality, int crispness) | |
121 { | |
122 m_fQuant=min_quantizer+((max_quantizer-min_quantizer)/6.)*(6-quality); | |
123 m_iCount=0; | |
124 m_bDrop=FALSE; | |
125 VbrControl_update_1pass_vbr(); | |
126 } | |
127 | |
128 int VbrControl_init_2pass_vbr_analysis(const char *filename, int quality) | |
129 { | |
130 m_pFile=fopen(filename, "wb"); | |
131 if(m_pFile==0) | |
132 return -1; | |
133 m_iCount=0; | |
134 m_bDrop=FALSE; | |
135 fprintf(m_pFile, "##version 1\n"); | |
136 fprintf(m_pFile, "quality %d\n", quality); | |
137 return 0; | |
138 } | |
139 | |
140 int VbrControl_init_2pass_vbr_encoding(const char *filename, int bitrate, double framerate, int crispness, int quality) | |
141 { | |
142 int i; | |
143 | |
144 int64_t text_bits=0; | |
145 int64_t total_bits=0; | |
146 int64_t complexity=0; | |
147 int64_t new_complexity=0; | |
148 int64_t motion_bits=0; | |
149 int64_t denominator=0; | |
150 float qual_multiplier=1.; | |
151 char head[20]; | |
152 | |
153 int64_t desired_bits; | |
154 int64_t non_text_bits; | |
155 | |
156 float average_complexity; | |
157 | |
158 m_pFile=fopen(filename, "rb"); | |
159 if(m_pFile==0) | |
160 return -1; | |
161 m_bDrop=FALSE; | |
162 m_iCount=0; | |
163 | |
164 fread(head, 10, 1, m_pFile); | |
165 if(!strncmp("##version ", head, 10)) | |
166 { | |
167 int version; | |
168 int iOldQual; | |
169 float old_qual, new_qual; | |
170 fscanf(m_pFile, "%d\n", &version); | |
171 fscanf(m_pFile, "quality %d\n", &iOldQual); | |
172 switch(iOldQual) | |
173 { | |
174 case 5: | |
175 old_qual=1.f; | |
176 break; | |
177 case 4: | |
178 old_qual=1.1f; | |
179 break; | |
180 case 3: | |
181 old_qual=1.25f; | |
182 break; | |
183 case 2: | |
184 old_qual=1.4f; | |
185 break; | |
186 case 1: | |
187 old_qual=2.f; | |
188 break; | |
189 } | |
190 switch(quality) | |
191 { | |
192 case 5: | |
193 new_qual=1.f; | |
194 break; | |
195 case 4: | |
196 new_qual=1.1f; | |
197 break; | |
198 case 3: | |
199 new_qual=1.25f; | |
200 break; | |
201 case 2: | |
202 new_qual=1.4f; | |
203 break; | |
204 case 1: | |
205 new_qual=2.f; | |
206 break; | |
207 } | |
208 qual_multiplier=new_qual/old_qual; | |
209 } | |
210 else | |
211 fseek(m_pFile, 0, SEEK_SET); | |
212 | |
213 lFrameStart=ftell(m_pFile); // save current position | |
214 | |
215 /* removed C++ dependencies, now read file twice :-( */ | |
216 | |
217 | |
218 while(!feof(m_pFile)) | |
219 { fscanf(m_pFile, "Frame %d: intra %d, quant %d, texture %d, motion %d, total %d\n", | |
220 &iNumFrames, &(vFrame.is_key_frame), &(vFrame.quant), &(vFrame.text_bits), &(vFrame.motion_bits), &(vFrame.total_bits)); | |
221 | |
222 vFrame.total_bits+=vFrame.text_bits*(qual_multiplier-1); | |
223 vFrame.text_bits*=qual_multiplier; | |
224 text_bits +=(int64_t)vFrame.text_bits; | |
225 motion_bits += (int64_t)vFrame.motion_bits; | |
226 total_bits +=(int64_t)vFrame.total_bits; | |
227 complexity +=(int64_t)vFrame.text_bits*vFrame.quant; | |
228 | |
229 // printf("Frames %d, texture %d, motion %d, quant %d total %d ", | |
230 // iNumFrames, vFrame.text_bits, vFrame.motion_bits, vFrame.quant, vFrame.total_bits); | |
231 // printf("texture %d, total %d, complexity %lld \n",vFrame.text_bits,vFrame.total_bits, complexity); | |
232 } | |
233 iNumFrames++; | |
234 average_complexity=complexity/iNumFrames; | |
235 | |
236 if (verbose & TC_DEBUG) { | |
237 fprintf(stderr, "(%s) frames %d, texture %lld, motion %lld, total %lld, complexity %lld\n", __FILE__, iNumFrames, text_bits, motion_bits, total_bits, complexity); | |
238 } | |
239 | |
240 m_vFrames = (entry*)malloc(iNumFrames*sizeof(entry)); | |
241 if (!m_vFrames) | |
242 { printf("out of memory"); | |
243 return TC_EXPORT_ERROR; | |
244 } | |
245 | |
246 fseek(m_pFile, lFrameStart, SEEK_SET); // start again | |
247 | |
248 for (i=0;i<iNumFrames;i++) | |
249 { fscanf(m_pFile, "Frame %d: intra %d, quant %d, texture %d, motion %d, total %d\n", | |
250 &dummy, &(m_vFrames[i].is_key_frame), &(m_vFrames[i].quant), | |
251 &(m_vFrames[i].text_bits), &(m_vFrames[i].motion_bits), | |
252 &(m_vFrames[i].total_bits)); | |
253 | |
254 m_vFrames[i].total_bits += m_vFrames[i].text_bits*(qual_multiplier-1); | |
255 m_vFrames[i].text_bits *= qual_multiplier; | |
256 } | |
257 | |
258 if (m_pFile) | |
259 { fclose(m_pFile); | |
260 m_pFile=NULL; | |
261 } | |
262 | |
263 desired_bits=(int64_t)bitrate*(int64_t)iNumFrames/framerate; | |
264 non_text_bits=total_bits-text_bits; | |
265 | |
266 if(desired_bits<=non_text_bits) | |
267 { | |
268 char s[200]; | |
269 printf("Specified bitrate is too low for this clip.\n" | |
270 "Minimum possible bitrate for the clip is %.0f kbps. Overriding\n" | |
271 "user-specified value.\n", | |
272 (float)(non_text_bits*framerate/(int64_t)iNumFrames)); | |
273 | |
274 desired_bits=non_text_bits*3/2; | |
275 /* | |
276 m_fQuant=max_quantizer; | |
277 for(int i=0; i<iNumFrames; i++) | |
278 { | |
279 m_vFrames[i].drop=0; | |
280 m_vFrames[i].mult=1; | |
281 } | |
282 VbrControl_set_quant(m_fQuant); | |
283 return 0; | |
284 */ | |
285 } | |
286 | |
287 desired_bits -= non_text_bits; | |
288 /** | |
289 BRIEF EXPLANATION OF WHAT'S GOING ON HERE. | |
290 We assume that | |
291 text_bits=complexity / quantizer | |
292 total_bits-text_bits = const(complexity) | |
293 where 'complexity' is a characteristic of the frame | |
294 and does not depend much on quantizer dynamics. | |
295 Using this equation, we calculate 'average' quantizer | |
296 to be used for encoding ( 1st order effect ). | |
297 Having constant quantizer for the entire stream is not | |
298 very convenient - reconstruction errors are | |
299 more noticeable in low-motion scenes. To compensate | |
300 this effect, we multiply quantizer for each frame by | |
301 (complexity/average_complexity)^k, | |
302 ( k - parameter of adjustment ). k=0 means 'no compensation' | |
303 and k=1 is 'constant bitrate mode'. We choose something in | |
304 between, like 0.5 ( 2nd order effect ). | |
305 **/ | |
306 | |
307 average_complexity=complexity/iNumFrames; | |
308 | |
309 for(i=0; i<iNumFrames; i++) | |
310 { | |
311 float mult; | |
312 if(m_vFrames[i].is_key_frame) | |
313 { | |
314 if((i+1<iNumFrames) && (m_vFrames[i+1].is_key_frame)) | |
315 mult=1.25; | |
316 else | |
317 mult=.75; | |
318 } | |
319 else | |
320 { | |
321 mult=m_vFrames[i].text_bits*m_vFrames[i].quant; | |
322 mult=(float)sqrt(mult/average_complexity); | |
323 | |
324 // if(i && m_vFrames[i-1].is_key_frame) | |
325 // mult *= 0.75; | |
326 if(mult<0.5) | |
327 mult=0.5; | |
328 if(mult>1.5) | |
329 mult=1.5; | |
330 } | |
331 | |
332 m_vFrames[i].mult=mult; | |
333 m_vFrames[i].drop=FALSE; | |
334 new_complexity+=m_vFrames[i].text_bits*m_vFrames[i].quant; | |
335 | |
336 denominator+=desired_bits*m_vFrames[i].mult/iNumFrames; | |
337 } | |
338 | |
339 m_fQuant=((double)new_complexity)/(double)denominator; | |
340 | |
341 if(m_fQuant<min_quantizer) m_fQuant=min_quantizer; | |
342 if(m_fQuant>max_quantizer) m_fQuant=max_quantizer; | |
343 m_pFile=fopen("analyse.log", "wb"); | |
344 if(m_pFile) | |
345 { | |
346 fprintf(m_pFile, "Total frames: %d Avg quantizer: %f\n", | |
347 iNumFrames, m_fQuant); | |
348 fprintf(m_pFile, "Expecting %12lld bits\n", desired_bits+non_text_bits); | |
349 fflush(m_pFile); | |
350 } | |
351 VbrControl_set_quant(m_fQuant*m_vFrames[0].mult); | |
352 m_lEncodedBits=m_lExpectedBits=0; | |
353 return 0; | |
354 } | |
355 | |
356 int VbrControl_get_intra() | |
357 { | |
358 return m_vFrames[m_iCount].is_key_frame; | |
359 } | |
360 | |
361 short VbrControl_get_drop() | |
362 { | |
363 return m_bDrop; | |
364 } | |
365 | |
366 int VbrControl_get_quant() | |
367 { | |
368 return m_iQuant; | |
369 } | |
370 | |
371 void VbrControl_set_quant(float quant) | |
372 { | |
373 m_iQuant=quant; | |
374 if((rand() % 10)<((quant-m_iQuant) * 10)) | |
375 m_iQuant++; | |
376 if(m_iQuant<min_quantizer) m_iQuant=min_quantizer; | |
377 if(m_iQuant>max_quantizer) m_iQuant=max_quantizer; | |
378 } | |
379 | |
380 void VbrControl_update_1pass_vbr() | |
381 { | |
382 VbrControl_set_quant(m_fQuant); | |
383 m_iCount++; | |
384 } | |
385 | |
386 void VbrControl_update_2pass_vbr_analysis(int is_key_frame, int motion_bits, int texture_bits, int total_bits, int quant) | |
387 { | |
388 if(!m_pFile) | |
389 return; | |
390 fprintf(m_pFile, "Frame %d: intra %d, quant %d, texture %d, motion %d, total %d\n", | |
391 m_iCount, is_key_frame, quant, texture_bits, motion_bits, total_bits); | |
392 m_iCount++; | |
393 } | |
394 | |
395 void VbrControl_update_2pass_vbr_encoding(int motion_bits, int texture_bits, int total_bits) | |
396 { | |
397 double q; | |
398 double dq; | |
399 | |
400 if(m_iCount>=iNumFrames) | |
401 return; | |
402 | |
403 m_lExpectedBits+=(m_vFrames[m_iCount].total_bits-m_vFrames[m_iCount].text_bits) | |
404 + m_vFrames[m_iCount].text_bits*m_vFrames[m_iCount].quant/m_fQuant; | |
405 m_lEncodedBits+=(int64_t)total_bits; | |
406 | |
407 if(m_pFile) | |
408 fprintf(m_pFile, "Frame %d: PRESENT, complexity %d, quant multiplier %f, texture %d, total %d ", | |
409 m_iCount, m_vFrames[m_iCount].text_bits*m_vFrames[m_iCount].quant, | |
410 m_vFrames[m_iCount].mult, texture_bits, total_bits); | |
411 | |
412 m_iCount++; | |
413 | |
414 q = m_fQuant * m_vFrames[m_iCount].mult; | |
415 if(q<m_fQuant+min_quant_delta) q=m_fQuant+min_quant_delta; | |
416 if(q>m_fQuant+max_quant_delta) q=m_fQuant+max_quant_delta; | |
417 | |
418 dq = (double)m_lEncodedBits/(double)m_lExpectedBits; | |
419 dq*=dq; | |
420 if(dq<min_rc_quant_delta) | |
421 dq=min_rc_quant_delta; | |
422 if(dq>max_rc_quant_delta) | |
423 dq=max_rc_quant_delta; | |
424 if(m_iCount<20) // no framerate corrections in first frames | |
425 dq=1; | |
426 if(m_pFile) | |
427 fprintf(m_pFile, "Progress: expected %12lld, achieved %12lld, dq %f", | |
428 m_lExpectedBits, m_lEncodedBits, dq); | |
429 q *= dq; | |
430 VbrControl_set_quant(q); | |
431 if(m_pFile) | |
432 fprintf(m_pFile, ", new quant %d\n", m_iQuant); | |
433 } | |
434 | |
435 void VbrControl_close() | |
436 { | |
437 if(m_pFile) | |
438 { | |
439 fclose(m_pFile); | |
440 m_pFile=NULL; | |
441 } | |
442 free(m_vFrames); | |
443 } |