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