367 lines
11 KiB
C++
367 lines
11 KiB
C++
//------------------------------------------------------------------------------
|
|
// File: ArithUtil.cpp
|
|
//
|
|
// Desc: DirectShow base classes - implements helper classes for building
|
|
// multimedia filters.
|
|
//
|
|
// Copyright (c) 1992-2004 Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------------------------
|
|
|
|
#include <pjmedia-videodev/config.h>
|
|
|
|
#if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0
|
|
|
|
#include <streams.h>
|
|
|
|
//
|
|
// Declare function from largeint.h we need so that PPC can build
|
|
//
|
|
|
|
//
|
|
// Enlarged integer divide - 64-bits / 32-bits > 32-bits
|
|
//
|
|
|
|
#if !defined(_X86_) || !defined(_MSC_VER)
|
|
|
|
#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 */
|