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