mfplat: Add MFllMulDiv().
Implementation is based on similar gstreamer utility code, adjusted for signed arguments, and with platform optimizations removed. Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
0ac619ae7a
commit
3e3490be39
|
@ -19,6 +19,7 @@
|
|||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define COBJMACROS
|
||||
#define NONAMELESSUNION
|
||||
|
@ -8928,3 +8929,183 @@ HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **man
|
|||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* MFllMulDiv implementation is derived from gstreamer utility functions code (gstutils.c),
|
||||
* released under LGPL2. Full authors list follows.
|
||||
* ===================================================================================
|
||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* 2000 Wim Taymans <wtay@chello.be>
|
||||
* 2002 Thomas Vander Stichele <thomas@apestaart.org>
|
||||
* 2004 Wim Taymans <wim@fluendo.com>
|
||||
* 2015 Jan Schmidt <jan@centricular.com>
|
||||
* ===================================================================================
|
||||
*/
|
||||
|
||||
static void llmult128(ULARGE_INTEGER *c1, ULARGE_INTEGER *c0, LONGLONG val, LONGLONG num)
|
||||
{
|
||||
ULARGE_INTEGER a1, b0, v, n;
|
||||
|
||||
v.QuadPart = llabs(val);
|
||||
n.QuadPart = llabs(num);
|
||||
|
||||
/* do 128 bits multiply
|
||||
* nh nl
|
||||
* * vh vl
|
||||
* ----------
|
||||
* a0 = vl * nl
|
||||
* a1 = vl * nh
|
||||
* b0 = vh * nl
|
||||
* b1 = + vh * nh
|
||||
* -------------------
|
||||
* c1h c1l c0h c0l
|
||||
*
|
||||
* "a0" is optimized away, result is stored directly in c0. "b1" is
|
||||
* optimized away, result is stored directly in c1.
|
||||
*/
|
||||
c0->QuadPart = (ULONGLONG)v.LowPart * n.LowPart;
|
||||
a1.QuadPart = (ULONGLONG)v.LowPart * n.HighPart;
|
||||
b0.QuadPart = (ULONGLONG)v.HighPart * n.LowPart;
|
||||
|
||||
/* add the high word of a0 to the low words of a1 and b0 using c1 as
|
||||
* scrach space to capture the carry. the low word of the result becomes
|
||||
* the final high word of c0 */
|
||||
c1->QuadPart = (ULONGLONG)c0->HighPart + a1.LowPart + b0.LowPart;
|
||||
c0->HighPart = c1->LowPart;
|
||||
|
||||
/* add the carry from the result above (found in the high word of c1) and
|
||||
* the high words of a1 and b0 to b1, the result is c1. */
|
||||
c1->QuadPart = (ULONGLONG)v.HighPart * n.HighPart + c1->HighPart + a1.HighPart + b0.HighPart;
|
||||
}
|
||||
|
||||
static ULONGLONG lldiv128(ULARGE_INTEGER c1, ULARGE_INTEGER c0, LONGLONG denom)
|
||||
{
|
||||
ULARGE_INTEGER q1, q0, rhat;
|
||||
ULARGE_INTEGER v, cmp1, cmp2;
|
||||
unsigned int s = 0;
|
||||
|
||||
v.QuadPart = llabs(denom);
|
||||
|
||||
/* 64bit numerator */
|
||||
if (c1.QuadPart == 0)
|
||||
return c0.QuadPart / v.QuadPart;
|
||||
|
||||
/* 96bit numerator, 32bit denominator */
|
||||
if (v.HighPart == 0 && c1.HighPart == 0)
|
||||
{
|
||||
ULONGLONG low = c0.LowPart, high = c0.HighPart + ((ULONGLONG)c1.LowPart << 32);
|
||||
low += (high % v.LowPart) << 32;
|
||||
return ((high / v.LowPart) << 32) + (low / v.LowPart);
|
||||
}
|
||||
|
||||
/* 128bit numerator, 32bit denominator */
|
||||
if (v.HighPart == 0)
|
||||
return UI64_MAX;
|
||||
|
||||
/* count number of leading zeroes */
|
||||
BitScanReverse(&s, v.HighPart);
|
||||
s = 31 - s;
|
||||
|
||||
if (s)
|
||||
{
|
||||
/* normalize divisor and dividend */
|
||||
v.QuadPart <<= s;
|
||||
c1.QuadPart = (c1.QuadPart << s) | (c0.HighPart >> (32 - s));
|
||||
c0.QuadPart <<= s;
|
||||
}
|
||||
|
||||
q1.QuadPart = c1.QuadPart / v.HighPart;
|
||||
rhat.QuadPart = c1.QuadPart - q1.QuadPart * v.HighPart;
|
||||
|
||||
cmp1.HighPart = rhat.LowPart;
|
||||
cmp1.LowPart = c0.HighPart;
|
||||
cmp2.QuadPart = q1.QuadPart * v.LowPart;
|
||||
|
||||
while (q1.HighPart || cmp2.QuadPart > cmp1.QuadPart)
|
||||
{
|
||||
q1.QuadPart--;
|
||||
rhat.QuadPart += v.HighPart;
|
||||
if (rhat.HighPart)
|
||||
break;
|
||||
cmp1.HighPart = rhat.LowPart;
|
||||
cmp2.QuadPart -= v.LowPart;
|
||||
}
|
||||
c1.HighPart = c1.LowPart;
|
||||
c1.LowPart = c0.HighPart;
|
||||
c1.QuadPart -= q1.QuadPart * v.QuadPart;
|
||||
q0.QuadPart = c1.QuadPart / v.HighPart;
|
||||
rhat.QuadPart = c1.QuadPart - q0.QuadPart * v.HighPart;
|
||||
|
||||
cmp1.HighPart = rhat.LowPart;
|
||||
cmp1.LowPart = c0.LowPart;
|
||||
cmp2.QuadPart = q0.QuadPart * v.LowPart;
|
||||
|
||||
while (q0.HighPart || cmp2.QuadPart > cmp1.QuadPart)
|
||||
{
|
||||
q0.QuadPart--;
|
||||
rhat.QuadPart += v.HighPart;
|
||||
if (rhat.HighPart)
|
||||
break;
|
||||
cmp1.HighPart = rhat.LowPart;
|
||||
cmp2.QuadPart -= v.LowPart;
|
||||
}
|
||||
q0.HighPart += q1.LowPart;
|
||||
|
||||
return q0.QuadPart;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MFllMulDiv (mfplat.@)
|
||||
*/
|
||||
LONGLONG WINAPI MFllMulDiv(LONGLONG val, LONGLONG num, LONGLONG denom, LONGLONG factor)
|
||||
{
|
||||
#define LLOVERFLOW (sign ? I64_MIN : I64_MAX)
|
||||
unsigned int sign, factor_sign, denom_sign;
|
||||
ULARGE_INTEGER c1, c0;
|
||||
ULONGLONG ret;
|
||||
|
||||
TRACE("%s, %s, %s, %s.\n", wine_dbgstr_longlong(val), wine_dbgstr_longlong(num),
|
||||
wine_dbgstr_longlong(denom), wine_dbgstr_longlong(factor));
|
||||
|
||||
/* compute 128-bit numerator product */
|
||||
llmult128(&c1, &c0, val, num);
|
||||
|
||||
sign = (val < 0) ^ (num < 0);
|
||||
factor_sign = factor < 0;
|
||||
denom_sign = denom < 0;
|
||||
|
||||
factor = llabs(factor);
|
||||
if (sign == factor_sign)
|
||||
{
|
||||
if (UI64_MAX - c0.QuadPart < factor)
|
||||
{
|
||||
if (c1.QuadPart == UI64_MAX) return LLOVERFLOW;
|
||||
c1.QuadPart++;
|
||||
}
|
||||
c0.QuadPart += factor;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c0.QuadPart >= factor)
|
||||
c0.QuadPart -= factor;
|
||||
else
|
||||
{
|
||||
if (c1.QuadPart)
|
||||
c1.QuadPart--;
|
||||
else
|
||||
sign = !sign;
|
||||
|
||||
c0.QuadPart = factor - c0.QuadPart;
|
||||
}
|
||||
}
|
||||
|
||||
if (c1.QuadPart >= denom) return LLOVERFLOW;
|
||||
|
||||
/* compute quotient, fits in 64 bits */
|
||||
ret = lldiv128(c1, c0, denom);
|
||||
sign ^= denom_sign;
|
||||
if (ret >= I64_MAX) return LLOVERFLOW;
|
||||
return sign ? -(LONGLONG)ret : ret;
|
||||
#undef LLOVERFLOW
|
||||
}
|
||||
|
|
|
@ -176,6 +176,6 @@
|
|||
@ stdcall MFUnwrapMediaType(ptr ptr)
|
||||
@ stub MFValidateMediaTypeSize
|
||||
@ stdcall MFWrapMediaType(ptr ptr ptr ptr)
|
||||
@ stub MFllMulDiv
|
||||
@ stdcall -ret64 MFllMulDiv(int64 int64 int64 int64)
|
||||
@ stub PropVariantFromStream
|
||||
@ stub PropVariantToStream
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define COBJMACROS
|
||||
|
||||
|
@ -7130,6 +7131,43 @@ static void test_MFLockSharedWorkQueue(void)
|
|||
ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
|
||||
}
|
||||
|
||||
static void test_MFllMulDiv(void)
|
||||
{
|
||||
/* (a * b + d) / c */
|
||||
static const struct muldivtest
|
||||
{
|
||||
LONGLONG a;
|
||||
LONGLONG b;
|
||||
LONGLONG c;
|
||||
LONGLONG d;
|
||||
LONGLONG result;
|
||||
}
|
||||
muldivtests[] =
|
||||
{
|
||||
{ 0, 0, 0, 0, _I64_MAX },
|
||||
{ 1000000, 1000000, 2, 0, 500000000000 },
|
||||
{ _I64_MAX, 3, _I64_MAX, 0, 3 },
|
||||
{ _I64_MAX, 3, _I64_MAX, 1, 3 },
|
||||
{ -10000, 3, 100, 0, -300 },
|
||||
{ 2, 0, 3, 5, 1 },
|
||||
{ 2, 1, 1, -3, -1 },
|
||||
/* a * b product does not fit in uint64_t */
|
||||
{ _I64_MAX, 4, 8, 0, _I64_MAX / 2 },
|
||||
/* Large a * b product, large denominator */
|
||||
{ _I64_MAX, 4, 0x100000000, 0, 0x1ffffffff },
|
||||
};
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(muldivtests); ++i)
|
||||
{
|
||||
LONGLONG result;
|
||||
|
||||
result = MFllMulDiv(muldivtests[i].a, muldivtests[i].b, muldivtests[i].c, muldivtests[i].d);
|
||||
ok(result == muldivtests[i].result, "%u: unexpected result %s, expected %s.\n", i,
|
||||
wine_dbgstr_longlong(result), wine_dbgstr_longlong(muldivtests[i].result));
|
||||
}
|
||||
}
|
||||
|
||||
START_TEST(mfplat)
|
||||
{
|
||||
char **argv;
|
||||
|
@ -7194,6 +7232,7 @@ START_TEST(mfplat)
|
|||
test_dxgi_surface_buffer();
|
||||
test_sample_allocator();
|
||||
test_MFMapDX9FormatToDXGIFormat();
|
||||
test_MFllMulDiv();
|
||||
|
||||
CoUninitialize();
|
||||
}
|
||||
|
|
|
@ -552,6 +552,7 @@ HRESULT WINAPI MFTEnumEx(GUID category, UINT32 flags, const MFT_REGISTER_TYPE_IN
|
|||
HRESULT WINAPI MFInitAttributesFromBlob(IMFAttributes *attributes, const UINT8 *buffer, UINT size);
|
||||
HRESULT WINAPI MFInitMediaTypeFromWaveFormatEx(IMFMediaType *mediatype, const WAVEFORMATEX *format, UINT32 size);
|
||||
HRESULT WINAPI MFInvokeCallback(IMFAsyncResult *result);
|
||||
LONGLONG WINAPI MFllMulDiv(LONGLONG val, LONGLONG num, LONGLONG denom, LONGLONG factor);
|
||||
HRESULT WINAPI MFLockPlatform(void);
|
||||
HRESULT WINAPI MFLockSharedWorkQueue(const WCHAR *name, LONG base_priority, DWORD *taskid, DWORD *queue);
|
||||
DXGI_FORMAT WINAPI MFMapDX9FormatToDXGIFormat(DWORD format);
|
||||
|
|
Loading…
Reference in New Issue