//------------------------------------------------------------------------------ // File: ArithUtil.cpp // // Desc: DirectShow base classes - implements helper classes for building // multimedia filters. // // Copyright (c) 1992-2004 Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ #include #if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0 #include // // Declare function from largeint.h we need so that PPC can build // // // Enlarged integer divide - 64-bits / 32-bits > 32-bits // #ifndef _X86_ #define LLtoU64(x) (*(unsigned __int64*)(void*)(&(x))) __inline ULONG WINAPI EnlargedUnsignedDivide ( IN ULARGE_INTEGER Dividend, IN ULONG Divisor, IN PULONG Remainder ) { // return remainder if necessary if (Remainder != NULL) *Remainder = (ULONG)(LLtoU64(Dividend) % Divisor); return (ULONG)(LLtoU64(Dividend) / Divisor); } #else __inline ULONG WINAPI EnlargedUnsignedDivide ( IN ULARGE_INTEGER Dividend, IN ULONG Divisor, IN PULONG Remainder ) { ULONG ulResult; _asm { mov eax,Dividend.LowPart mov edx,Dividend.HighPart mov ecx,Remainder div Divisor or ecx,ecx jz short label mov [ecx],edx label: mov ulResult,eax } return ulResult; } #endif /* Arithmetic functions to help with time format conversions */ #ifdef _M_ALPHA // work around bug in version 12.00.8385 of the alpha compiler where // UInt32x32To64 sign-extends its arguments (?) #undef UInt32x32To64 #define UInt32x32To64(a, b) (((ULONGLONG)((ULONG)(a)) & 0xffffffff) * ((ULONGLONG)((ULONG)(b)) & 0xffffffff)) #endif /* Compute (a * b + d) / c */ LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG d) { /* Compute the absolute values to avoid signed arithmetic problems */ ULARGE_INTEGER ua, ub; DWORDLONG uc; ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a); ub.QuadPart = (DWORDLONG)(b >= 0 ? b : -b); uc = (DWORDLONG)(c >= 0 ? c : -c); BOOL bSign = (a < 0) ^ (b < 0); /* Do long multiplication */ ULARGE_INTEGER p[2]; p[0].QuadPart = UInt32x32To64(ua.LowPart, ub.LowPart); /* This next computation cannot overflow into p[1].HighPart because the max number we can compute here is: (2 ** 32 - 1) * (2 ** 32 - 1) + // ua.LowPart * ub.LowPart (2 ** 32) * (2 ** 31) * (2 ** 32 - 1) * 2 // x.LowPart * y.HighPart * 2 == 2 ** 96 - 2 ** 64 + (2 ** 64 - 2 ** 33 + 1) == 2 ** 96 - 2 ** 33 + 1 < 2 ** 96 */ ULARGE_INTEGER x; x.QuadPart = UInt32x32To64(ua.LowPart, ub.HighPart) + UInt32x32To64(ua.HighPart, ub.LowPart) + p[0].HighPart; p[0].HighPart = x.LowPart; p[1].QuadPart = UInt32x32To64(ua.HighPart, ub.HighPart) + x.HighPart; if (d != 0) { ULARGE_INTEGER ud[2]; if (bSign) { ud[0].QuadPart = (DWORDLONG)(-d); if (d > 0) { /* -d < 0 */ ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1; } else { ud[1].QuadPart = (DWORDLONG)0; } } else { ud[0].QuadPart = (DWORDLONG)d; if (d < 0) { ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1; } else { ud[1].QuadPart = (DWORDLONG)0; } } /* Now do extended addition */ ULARGE_INTEGER uliTotal; /* Add ls DWORDs */ uliTotal.QuadPart = (DWORDLONG)ud[0].LowPart + p[0].LowPart; p[0].LowPart = uliTotal.LowPart; /* Propagate carry */ uliTotal.LowPart = uliTotal.HighPart; uliTotal.HighPart = 0; /* Add 2nd most ls DWORDs */ uliTotal.QuadPart += (DWORDLONG)ud[0].HighPart + p[0].HighPart; p[0].HighPart = uliTotal.LowPart; /* Propagate carry */ uliTotal.LowPart = uliTotal.HighPart; uliTotal.HighPart = 0; /* Add MS DWORDLONGs - no carry expected */ p[1].QuadPart += ud[1].QuadPart + uliTotal.QuadPart; /* Now see if we got a sign change from the addition */ if ((LONG)p[1].HighPart < 0) { bSign = !bSign; /* Negate the current value (ugh!) */ p[0].QuadPart = ~p[0].QuadPart; p[1].QuadPart = ~p[1].QuadPart; p[0].QuadPart += 1; p[1].QuadPart += (p[0].QuadPart == 0); } } /* Now for the division */ if (c < 0) { bSign = !bSign; } /* This will catch c == 0 and overflow */ if (uc <= p[1].QuadPart) { return bSign ? (LONGLONG)0x8000000000000000 : (LONGLONG)0x7FFFFFFFFFFFFFFF; } DWORDLONG ullResult; /* Do the division */ /* If the dividend is a DWORD_LONG use the compiler */ if (p[1].QuadPart == 0) { ullResult = p[0].QuadPart / uc; return bSign ? -(LONGLONG)ullResult : (LONGLONG)ullResult; } /* If the divisor is a DWORD then its simpler */ ULARGE_INTEGER ulic; ulic.QuadPart = uc; if (ulic.HighPart == 0) { ULARGE_INTEGER uliDividend; ULARGE_INTEGER uliResult; DWORD dwDivisor = (DWORD)uc; // ASSERT(p[1].HighPart == 0 && p[1].LowPart < dwDivisor); uliDividend.HighPart = p[1].LowPart; uliDividend.LowPart = p[0].HighPart; #ifndef USE_LARGEINT uliResult.HighPart = (DWORD)(uliDividend.QuadPart / dwDivisor); p[0].HighPart = (DWORD)(uliDividend.QuadPart % dwDivisor); uliResult.LowPart = 0; uliResult.QuadPart = p[0].QuadPart / dwDivisor + uliResult.QuadPart; #else /* NOTE - this routine will take exceptions if the result does not fit in a DWORD */ if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) { uliResult.HighPart = EnlargedUnsignedDivide( uliDividend, dwDivisor, &p[0].HighPart); } else { uliResult.HighPart = 0; } uliResult.LowPart = EnlargedUnsignedDivide( p[0], dwDivisor, NULL); #endif return bSign ? -(LONGLONG)uliResult.QuadPart : (LONGLONG)uliResult.QuadPart; } ullResult = 0; /* OK - do long division */ for (int i = 0; i < 64; i++) { ullResult <<= 1; /* Shift 128 bit p left 1 */ p[1].QuadPart <<= 1; if ((p[0].HighPart & 0x80000000) != 0) { p[1].LowPart++; } p[0].QuadPart <<= 1; /* Compare */ if (uc <= p[1].QuadPart) { p[1].QuadPart -= uc; ullResult += 1; } } return bSign ? - (LONGLONG)ullResult : (LONGLONG)ullResult; } LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG d) { ULARGE_INTEGER ua; DWORD ub; DWORD uc; /* Compute the absolute values to avoid signed arithmetic problems */ ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a); ub = (DWORD)(b >= 0 ? b : -b); uc = (DWORD)(c >= 0 ? c : -c); BOOL bSign = (a < 0) ^ (b < 0); /* Do long multiplication */ ULARGE_INTEGER p0; DWORD p1; p0.QuadPart = UInt32x32To64(ua.LowPart, ub); if (ua.HighPart != 0) { ULARGE_INTEGER x; x.QuadPart = UInt32x32To64(ua.HighPart, ub) + p0.HighPart; p0.HighPart = x.LowPart; p1 = x.HighPart; } else { p1 = 0; } if (d != 0) { ULARGE_INTEGER ud0; DWORD ud1; if (bSign) { // // Cast d to LONGLONG first otherwise -0x80000000 sign extends // incorrectly // ud0.QuadPart = (DWORDLONG)(-(LONGLONG)d); if (d > 0) { /* -d < 0 */ ud1 = (DWORD)-1; } else { ud1 = (DWORD)0; } } else { ud0.QuadPart = (DWORDLONG)d; if (d < 0) { ud1 = (DWORD)-1; } else { ud1 = (DWORD)0; } } /* Now do extended addition */ ULARGE_INTEGER uliTotal; /* Add ls DWORDs */ uliTotal.QuadPart = (DWORDLONG)ud0.LowPart + p0.LowPart; p0.LowPart = uliTotal.LowPart; /* Propagate carry */ uliTotal.LowPart = uliTotal.HighPart; uliTotal.HighPart = 0; /* Add 2nd most ls DWORDs */ uliTotal.QuadPart += (DWORDLONG)ud0.HighPart + p0.HighPart; p0.HighPart = uliTotal.LowPart; /* Add MS DWORDLONGs - no carry expected */ p1 += ud1 + uliTotal.HighPart; /* Now see if we got a sign change from the addition */ if ((LONG)p1 < 0) { bSign = !bSign; /* Negate the current value (ugh!) */ p0.QuadPart = ~p0.QuadPart; p1 = ~p1; p0.QuadPart += 1; p1 += (p0.QuadPart == 0); } } /* Now for the division */ if (c < 0) { bSign = !bSign; } /* This will catch c == 0 and overflow */ if (uc <= p1) { return bSign ? (LONGLONG)0x8000000000000000 : (LONGLONG)0x7FFFFFFFFFFFFFFF; } /* Do the division */ /* If the divisor is a DWORD then its simpler */ ULARGE_INTEGER uliDividend; ULARGE_INTEGER uliResult; DWORD dwDivisor = uc; uliDividend.HighPart = p1; uliDividend.LowPart = p0.HighPart; /* NOTE - this routine will take exceptions if the result does not fit in a DWORD */ if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) { uliResult.HighPart = EnlargedUnsignedDivide( uliDividend, dwDivisor, &p0.HighPart); } else { uliResult.HighPart = 0; } uliResult.LowPart = EnlargedUnsignedDivide( p0, dwDivisor, NULL); return bSign ? -(LONGLONG)uliResult.QuadPart : (LONGLONG)uliResult.QuadPart; } #endif /* PJMEDIA_VIDEO_DEV_HAS_DSHOW */