blob: 9600e5f3f128895f55ae2b6c720cabdbf34faf8d [file] [log] [blame]
Sauw Ming93ba7fe2012-04-18 02:38:42 +00001//------------------------------------------------------------------------------
2// File: ArithUtil.cpp
3//
4// Desc: DirectShow base classes - implements helper classes for building
5// multimedia filters.
6//
7// Copyright (c) 1992-2004 Microsoft Corporation. All rights reserved.
8//------------------------------------------------------------------------------
9
Nanang Izzuddinc46d1152012-04-24 07:07:39 +000010#include <pjmedia-videodev/config.h>
11
12#if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0
13
Sauw Ming93ba7fe2012-04-18 02:38:42 +000014#include <streams.h>
15
16//
17// Declare function from largeint.h we need so that PPC can build
18//
19
20//
21// Enlarged integer divide - 64-bits / 32-bits > 32-bits
22//
23
24#ifndef _X86_
25
26#define LLtoU64(x) (*(unsigned __int64*)(void*)(&(x)))
27
28__inline
29ULONG
30WINAPI
31EnlargedUnsignedDivide (
32 IN ULARGE_INTEGER Dividend,
33 IN ULONG Divisor,
34 IN PULONG Remainder
35 )
36{
37 // return remainder if necessary
38 if (Remainder != NULL)
39 *Remainder = (ULONG)(LLtoU64(Dividend) % Divisor);
40 return (ULONG)(LLtoU64(Dividend) / Divisor);
41}
42
43#else
44__inline
45ULONG
46WINAPI
47EnlargedUnsignedDivide (
48 IN ULARGE_INTEGER Dividend,
49 IN ULONG Divisor,
50 IN PULONG Remainder
51 )
52{
53 ULONG ulResult;
54 _asm {
55 mov eax,Dividend.LowPart
56 mov edx,Dividend.HighPart
57 mov ecx,Remainder
58 div Divisor
59 or ecx,ecx
60 jz short label
61 mov [ecx],edx
62label:
63 mov ulResult,eax
64 }
65 return ulResult;
66}
67#endif
68
69
70/* Arithmetic functions to help with time format conversions
71*/
72
73#ifdef _M_ALPHA
74// work around bug in version 12.00.8385 of the alpha compiler where
75// UInt32x32To64 sign-extends its arguments (?)
76#undef UInt32x32To64
77#define UInt32x32To64(a, b) (((ULONGLONG)((ULONG)(a)) & 0xffffffff) * ((ULONGLONG)((ULONG)(b)) & 0xffffffff))
78#endif
79
80/* Compute (a * b + d) / c */
81LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG d)
82{
83 /* Compute the absolute values to avoid signed arithmetic problems */
84 ULARGE_INTEGER ua, ub;
85 DWORDLONG uc;
86
87 ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a);
88 ub.QuadPart = (DWORDLONG)(b >= 0 ? b : -b);
89 uc = (DWORDLONG)(c >= 0 ? c : -c);
90 BOOL bSign = (a < 0) ^ (b < 0);
91
92 /* Do long multiplication */
93 ULARGE_INTEGER p[2];
94 p[0].QuadPart = UInt32x32To64(ua.LowPart, ub.LowPart);
95
96 /* This next computation cannot overflow into p[1].HighPart because
97 the max number we can compute here is:
98
99 (2 ** 32 - 1) * (2 ** 32 - 1) + // ua.LowPart * ub.LowPart
100 (2 ** 32) * (2 ** 31) * (2 ** 32 - 1) * 2 // x.LowPart * y.HighPart * 2
101
102 == 2 ** 96 - 2 ** 64 + (2 ** 64 - 2 ** 33 + 1)
103 == 2 ** 96 - 2 ** 33 + 1
104 < 2 ** 96
105 */
106
107 ULARGE_INTEGER x;
108 x.QuadPart = UInt32x32To64(ua.LowPart, ub.HighPart) +
109 UInt32x32To64(ua.HighPart, ub.LowPart) +
110 p[0].HighPart;
111 p[0].HighPart = x.LowPart;
112 p[1].QuadPart = UInt32x32To64(ua.HighPart, ub.HighPart) + x.HighPart;
113
114 if (d != 0) {
115 ULARGE_INTEGER ud[2];
116 if (bSign) {
117 ud[0].QuadPart = (DWORDLONG)(-d);
118 if (d > 0) {
119 /* -d < 0 */
120 ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1;
121 } else {
122 ud[1].QuadPart = (DWORDLONG)0;
123 }
124 } else {
125 ud[0].QuadPart = (DWORDLONG)d;
126 if (d < 0) {
127 ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1;
128 } else {
129 ud[1].QuadPart = (DWORDLONG)0;
130 }
131 }
132 /* Now do extended addition */
133 ULARGE_INTEGER uliTotal;
134
135 /* Add ls DWORDs */
136 uliTotal.QuadPart = (DWORDLONG)ud[0].LowPart + p[0].LowPart;
137 p[0].LowPart = uliTotal.LowPart;
138
139 /* Propagate carry */
140 uliTotal.LowPart = uliTotal.HighPart;
141 uliTotal.HighPart = 0;
142
143 /* Add 2nd most ls DWORDs */
144 uliTotal.QuadPart += (DWORDLONG)ud[0].HighPart + p[0].HighPart;
145 p[0].HighPart = uliTotal.LowPart;
146
147 /* Propagate carry */
148 uliTotal.LowPart = uliTotal.HighPart;
149 uliTotal.HighPart = 0;
150
151 /* Add MS DWORDLONGs - no carry expected */
152 p[1].QuadPart += ud[1].QuadPart + uliTotal.QuadPart;
153
154 /* Now see if we got a sign change from the addition */
155 if ((LONG)p[1].HighPart < 0) {
156 bSign = !bSign;
157
158 /* Negate the current value (ugh!) */
159 p[0].QuadPart = ~p[0].QuadPart;
160 p[1].QuadPart = ~p[1].QuadPart;
161 p[0].QuadPart += 1;
162 p[1].QuadPart += (p[0].QuadPart == 0);
163 }
164 }
165
166 /* Now for the division */
167 if (c < 0) {
168 bSign = !bSign;
169 }
170
171
172 /* This will catch c == 0 and overflow */
173 if (uc <= p[1].QuadPart) {
174 return bSign ? (LONGLONG)0x8000000000000000 :
175 (LONGLONG)0x7FFFFFFFFFFFFFFF;
176 }
177
178 DWORDLONG ullResult;
179
180 /* Do the division */
181 /* If the dividend is a DWORD_LONG use the compiler */
182 if (p[1].QuadPart == 0) {
183 ullResult = p[0].QuadPart / uc;
184 return bSign ? -(LONGLONG)ullResult : (LONGLONG)ullResult;
185 }
186
187 /* If the divisor is a DWORD then its simpler */
188 ULARGE_INTEGER ulic;
189 ulic.QuadPart = uc;
190 if (ulic.HighPart == 0) {
191 ULARGE_INTEGER uliDividend;
192 ULARGE_INTEGER uliResult;
193 DWORD dwDivisor = (DWORD)uc;
194 // ASSERT(p[1].HighPart == 0 && p[1].LowPart < dwDivisor);
195 uliDividend.HighPart = p[1].LowPart;
196 uliDividend.LowPart = p[0].HighPart;
197#ifndef USE_LARGEINT
198 uliResult.HighPart = (DWORD)(uliDividend.QuadPart / dwDivisor);
199 p[0].HighPart = (DWORD)(uliDividend.QuadPart % dwDivisor);
200 uliResult.LowPart = 0;
201 uliResult.QuadPart = p[0].QuadPart / dwDivisor + uliResult.QuadPart;
202#else
203 /* NOTE - this routine will take exceptions if
204 the result does not fit in a DWORD
205 */
206 if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) {
207 uliResult.HighPart = EnlargedUnsignedDivide(
208 uliDividend,
209 dwDivisor,
210 &p[0].HighPart);
211 } else {
212 uliResult.HighPart = 0;
213 }
214 uliResult.LowPart = EnlargedUnsignedDivide(
215 p[0],
216 dwDivisor,
217 NULL);
218#endif
219 return bSign ? -(LONGLONG)uliResult.QuadPart :
220 (LONGLONG)uliResult.QuadPart;
221 }
222
223
224 ullResult = 0;
225
226 /* OK - do long division */
227 for (int i = 0; i < 64; i++) {
228 ullResult <<= 1;
229
230 /* Shift 128 bit p left 1 */
231 p[1].QuadPart <<= 1;
232 if ((p[0].HighPart & 0x80000000) != 0) {
233 p[1].LowPart++;
234 }
235 p[0].QuadPart <<= 1;
236
237 /* Compare */
238 if (uc <= p[1].QuadPart) {
239 p[1].QuadPart -= uc;
240 ullResult += 1;
241 }
242 }
243
244 return bSign ? - (LONGLONG)ullResult : (LONGLONG)ullResult;
245}
246
247LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG d)
248{
249 ULARGE_INTEGER ua;
250 DWORD ub;
251 DWORD uc;
252
253 /* Compute the absolute values to avoid signed arithmetic problems */
254 ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a);
255 ub = (DWORD)(b >= 0 ? b : -b);
256 uc = (DWORD)(c >= 0 ? c : -c);
257 BOOL bSign = (a < 0) ^ (b < 0);
258
259 /* Do long multiplication */
260 ULARGE_INTEGER p0;
261 DWORD p1;
262 p0.QuadPart = UInt32x32To64(ua.LowPart, ub);
263
264 if (ua.HighPart != 0) {
265 ULARGE_INTEGER x;
266 x.QuadPart = UInt32x32To64(ua.HighPart, ub) + p0.HighPart;
267 p0.HighPart = x.LowPart;
268 p1 = x.HighPart;
269 } else {
270 p1 = 0;
271 }
272
273 if (d != 0) {
274 ULARGE_INTEGER ud0;
275 DWORD ud1;
276
277 if (bSign) {
278 //
279 // Cast d to LONGLONG first otherwise -0x80000000 sign extends
280 // incorrectly
281 //
282 ud0.QuadPart = (DWORDLONG)(-(LONGLONG)d);
283 if (d > 0) {
284 /* -d < 0 */
285 ud1 = (DWORD)-1;
286 } else {
287 ud1 = (DWORD)0;
288 }
289 } else {
290 ud0.QuadPart = (DWORDLONG)d;
291 if (d < 0) {
292 ud1 = (DWORD)-1;
293 } else {
294 ud1 = (DWORD)0;
295 }
296 }
297 /* Now do extended addition */
298 ULARGE_INTEGER uliTotal;
299
300 /* Add ls DWORDs */
301 uliTotal.QuadPart = (DWORDLONG)ud0.LowPart + p0.LowPart;
302 p0.LowPart = uliTotal.LowPart;
303
304 /* Propagate carry */
305 uliTotal.LowPart = uliTotal.HighPart;
306 uliTotal.HighPart = 0;
307
308 /* Add 2nd most ls DWORDs */
309 uliTotal.QuadPart += (DWORDLONG)ud0.HighPart + p0.HighPart;
310 p0.HighPart = uliTotal.LowPart;
311
312 /* Add MS DWORDLONGs - no carry expected */
313 p1 += ud1 + uliTotal.HighPart;
314
315 /* Now see if we got a sign change from the addition */
316 if ((LONG)p1 < 0) {
317 bSign = !bSign;
318
319 /* Negate the current value (ugh!) */
320 p0.QuadPart = ~p0.QuadPart;
321 p1 = ~p1;
322 p0.QuadPart += 1;
323 p1 += (p0.QuadPart == 0);
324 }
325 }
326
327 /* Now for the division */
328 if (c < 0) {
329 bSign = !bSign;
330 }
331
332
333 /* This will catch c == 0 and overflow */
334 if (uc <= p1) {
335 return bSign ? (LONGLONG)0x8000000000000000 :
336 (LONGLONG)0x7FFFFFFFFFFFFFFF;
337 }
338
339 /* Do the division */
340
341 /* If the divisor is a DWORD then its simpler */
342 ULARGE_INTEGER uliDividend;
343 ULARGE_INTEGER uliResult;
344 DWORD dwDivisor = uc;
345 uliDividend.HighPart = p1;
346 uliDividend.LowPart = p0.HighPart;
347 /* NOTE - this routine will take exceptions if
348 the result does not fit in a DWORD
349 */
350 if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) {
351 uliResult.HighPart = EnlargedUnsignedDivide(
352 uliDividend,
353 dwDivisor,
354 &p0.HighPart);
355 } else {
356 uliResult.HighPart = 0;
357 }
358 uliResult.LowPart = EnlargedUnsignedDivide(
359 p0,
360 dwDivisor,
361 NULL);
362 return bSign ? -(LONGLONG)uliResult.QuadPart :
363 (LONGLONG)uliResult.QuadPart;
364}
Nanang Izzuddinc46d1152012-04-24 07:07:39 +0000365
366#endif /* PJMEDIA_VIDEO_DEV_HAS_DSHOW */