8766 lines
366 KiB
C
8766 lines
366 KiB
C
/*
|
|
* Copyright 2017 Nikolay Sivov
|
|
* Copyright 2022 Rémi Bernon for CodeWeavers
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
|
|
#define COBJMACROS
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
|
|
#include "control.h"
|
|
#include "d3d9types.h"
|
|
#include "dmo.h"
|
|
#include "mferror.h"
|
|
#include "mfidl.h"
|
|
#include "mftransform.h"
|
|
#include "propvarutil.h"
|
|
#include "uuids.h"
|
|
#include "wmcodecdsp.h"
|
|
#include "mediaerr.h"
|
|
#include "amvideo.h"
|
|
#include "vfw.h"
|
|
#include "ks.h"
|
|
#include "ksmedia.h"
|
|
|
|
#include "mf_test.h"
|
|
|
|
#include "wine/test.h"
|
|
|
|
#include "initguid.h"
|
|
|
|
#include "codecapi.h"
|
|
|
|
#include "d3d11_4.h"
|
|
|
|
DEFINE_GUID(DMOVideoFormat_RGB24,D3DFMT_R8G8B8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
|
|
DEFINE_GUID(DMOVideoFormat_RGB32,D3DFMT_X8R8G8B8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
|
|
DEFINE_GUID(DMOVideoFormat_RGB555,D3DFMT_X1R5G5B5,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
|
|
DEFINE_GUID(DMOVideoFormat_RGB565,D3DFMT_R5G6B5,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
|
|
DEFINE_GUID(DMOVideoFormat_RGB8,D3DFMT_P8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
|
|
DEFINE_GUID(MFAudioFormat_RAW_AAC1,WAVE_FORMAT_RAW_AAC1,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
|
|
DEFINE_GUID(MFVideoFormat_ABGR32,0x00000020,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
|
|
DEFINE_GUID(MFVideoFormat_P208,0x38303250,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
|
|
DEFINE_GUID(MFVideoFormat_VC1S,0x53314356,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
|
|
DEFINE_GUID(MFVideoFormat_WMV_Unknown,0x7ce12ca9,0xbfbf,0x43d9,0x9d,0x00,0x82,0xb8,0xed,0x54,0x31,0x6b);
|
|
DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_IV50,MAKEFOURCC('I','V','5','0'));
|
|
|
|
DEFINE_GUID(mft_output_sample_incomplete,0xffffff,0xffff,0xffff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff);
|
|
|
|
struct media_buffer
|
|
{
|
|
IMediaBuffer IMediaBuffer_iface;
|
|
LONG refcount;
|
|
DWORD length;
|
|
DWORD max_length;
|
|
BYTE data[];
|
|
};
|
|
|
|
static inline struct media_buffer *impl_from_IMediaBuffer(IMediaBuffer *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct media_buffer, IMediaBuffer_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI media_buffer_QueryInterface(IMediaBuffer *iface, REFIID iid, void **obj)
|
|
{
|
|
if (IsEqualIID(iid, &IID_IMediaBuffer)
|
|
|| IsEqualIID(iid, &IID_IUnknown))
|
|
{
|
|
*obj = iface;
|
|
return S_OK;
|
|
}
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI media_buffer_AddRef(IMediaBuffer *iface)
|
|
{
|
|
struct media_buffer *buffer = impl_from_IMediaBuffer(iface);
|
|
return InterlockedIncrement(&buffer->refcount);
|
|
}
|
|
|
|
static ULONG WINAPI media_buffer_Release(IMediaBuffer *iface)
|
|
{
|
|
struct media_buffer *buffer = impl_from_IMediaBuffer(iface);
|
|
ULONG ref = InterlockedDecrement(&buffer->refcount);
|
|
if (!ref)
|
|
free(buffer);
|
|
return ref;
|
|
}
|
|
|
|
static HRESULT WINAPI media_buffer_SetLength(IMediaBuffer *iface, DWORD length)
|
|
{
|
|
struct media_buffer *buffer = impl_from_IMediaBuffer(iface);
|
|
if (length > buffer->max_length)
|
|
return E_INVALIDARG;
|
|
buffer->length = length;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI media_buffer_GetMaxLength(IMediaBuffer *iface, DWORD *max_length)
|
|
{
|
|
struct media_buffer *buffer = impl_from_IMediaBuffer(iface);
|
|
if (!max_length)
|
|
return E_POINTER;
|
|
*max_length = buffer->max_length;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI media_buffer_GetBufferAndLength(IMediaBuffer *iface, BYTE **data, DWORD *length)
|
|
{
|
|
struct media_buffer *buffer = impl_from_IMediaBuffer(iface);
|
|
if (!data || ! length)
|
|
return E_POINTER;
|
|
*data = buffer->data;
|
|
*length = buffer->length;
|
|
return S_OK;
|
|
}
|
|
|
|
static IMediaBufferVtbl media_buffer_vtbl = {
|
|
media_buffer_QueryInterface,
|
|
media_buffer_AddRef,
|
|
media_buffer_Release,
|
|
media_buffer_SetLength,
|
|
media_buffer_GetMaxLength,
|
|
media_buffer_GetBufferAndLength,
|
|
};
|
|
|
|
HRESULT media_buffer_create(DWORD max_length, struct media_buffer **ret)
|
|
{
|
|
struct media_buffer *buffer;
|
|
|
|
if (!(buffer = calloc(1, offsetof(struct media_buffer, data[max_length]))))
|
|
return E_OUTOFMEMORY;
|
|
buffer->IMediaBuffer_iface.lpVtbl = &media_buffer_vtbl;
|
|
buffer->refcount = 1;
|
|
buffer->length = 0;
|
|
buffer->max_length = max_length;
|
|
*ret = buffer;
|
|
return S_OK;
|
|
}
|
|
|
|
static BOOL is_compressed_subtype(const GUID *subtype)
|
|
{
|
|
if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMV1)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_WMV2)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_WMVA)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_WMVP)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_WVP2)
|
|
|| IsEqualGUID(subtype, &MFVideoFormat_WMV_Unknown)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_WVC1)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_WMV3)
|
|
|| IsEqualGUID(subtype, &MFVideoFormat_VC1S))
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
static DWORD subtype_to_tag(const GUID *subtype)
|
|
{
|
|
if (IsEqualGUID(subtype, &MEDIASUBTYPE_RGB32)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_RGB24)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_RGB555)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_RGB8))
|
|
return BI_RGB;
|
|
else if (IsEqualGUID(subtype, &MEDIASUBTYPE_RGB565))
|
|
return BI_BITFIELDS;
|
|
else if (IsEqualGUID(subtype, &MEDIASUBTYPE_PCM))
|
|
return WAVE_FORMAT_PCM;
|
|
else
|
|
return subtype->Data1;
|
|
}
|
|
|
|
static DWORD subtype_to_bpp(const GUID *subtype)
|
|
{
|
|
if (IsEqualGUID(subtype, &MEDIASUBTYPE_RGB8))
|
|
return 8;
|
|
else if (IsEqualGUID(subtype, &MEDIASUBTYPE_NV12)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_YV12)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_IYUV)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_I420)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_NV11))
|
|
return 12;
|
|
else if (IsEqualGUID(subtype, &MEDIASUBTYPE_YUY2)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_UYVY)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_YVYU)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_RGB565)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_RGB555))
|
|
return 16;
|
|
else if (IsEqualGUID(subtype, &MEDIASUBTYPE_RGB24))
|
|
return 24;
|
|
else if (IsEqualGUID(subtype, &MEDIASUBTYPE_RGB32))
|
|
return 32;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static DWORD subtype_to_extra_bytes(const GUID *subtype)
|
|
{
|
|
if (IsEqualGUID(subtype, &MEDIASUBTYPE_MSAUDIO1))
|
|
return MSAUDIO1_WFX_EXTRA_BYTES;
|
|
else if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMAUDIO2))
|
|
return WMAUDIO2_WFX_EXTRA_BYTES;
|
|
else if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMAUDIO3))
|
|
return WMAUDIO3_WFX_EXTRA_BYTES;
|
|
else if (IsEqualGUID(subtype, &MEDIASUBTYPE_RGB8))
|
|
return sizeof(RGBQUAD) * (1 << 8);
|
|
else if (IsEqualGUID(subtype, &MEDIASUBTYPE_RGB565))
|
|
return sizeof(DWORD) * 3;
|
|
else if (is_compressed_subtype(subtype))
|
|
return 4;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static void load_resource(const WCHAR *filename, const BYTE **data, DWORD *length)
|
|
{
|
|
HRSRC resource = FindResourceW(NULL, filename, (const WCHAR *)RT_RCDATA);
|
|
ok(resource != 0, "FindResourceW failed, error %lu\n", GetLastError());
|
|
*data = LockResource(LoadResource(GetModuleHandleW(NULL), resource));
|
|
*length = SizeofResource(GetModuleHandleW(NULL), resource);
|
|
}
|
|
|
|
#define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
|
|
static void _expect_ref(IUnknown* obj, ULONG expected_refcount, int line)
|
|
{
|
|
ULONG refcount;
|
|
IUnknown_AddRef(obj);
|
|
refcount = IUnknown_Release(obj);
|
|
ok_(__FILE__, line)(refcount == expected_refcount, "Unexpected refcount %ld, expected %ld.\n", refcount,
|
|
expected_refcount);
|
|
}
|
|
|
|
#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
|
|
static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported)
|
|
{
|
|
IUnknown *iface = iface_ptr;
|
|
HRESULT hr, expected_hr;
|
|
IUnknown *unk;
|
|
|
|
expected_hr = supported ? S_OK : E_NOINTERFACE;
|
|
|
|
hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
|
|
ok_(__FILE__, line)(hr == expected_hr, "Got hr %#lx, expected %#lx.\n", hr, expected_hr);
|
|
if (SUCCEEDED(hr))
|
|
IUnknown_Release(unk);
|
|
}
|
|
|
|
#define check_member_(file, line, val, exp, fmt, member) \
|
|
ok_ (file, line)((val).member == (exp).member, "Got " #member " " fmt ", expected " fmt ".\n", (val).member, (exp).member)
|
|
#define check_member(val, exp, fmt, member) check_member_(__FILE__, __LINE__, val, exp, fmt, member)
|
|
|
|
void check_attributes_(const char *file, int line, IMFAttributes *attributes,
|
|
const struct attribute_desc *desc, ULONG limit)
|
|
{
|
|
char buffer[1024], *buf = buffer;
|
|
PROPVARIANT value;
|
|
int i, j, ret;
|
|
HRESULT hr;
|
|
|
|
for (i = 0; i < limit && desc[i].key; ++i)
|
|
{
|
|
hr = IMFAttributes_GetItem(attributes, desc[i].key, &value);
|
|
todo_wine_if(desc[i].todo)
|
|
ok_(file, line)(hr == S_OK, "%s missing, hr %#lx\n", debugstr_a(desc[i].name), hr);
|
|
if (hr != S_OK) continue;
|
|
|
|
switch (value.vt)
|
|
{
|
|
default: sprintf(buffer, "??"); break;
|
|
case VT_CLSID: sprintf(buffer, "%s", debugstr_guid(value.puuid)); break;
|
|
case VT_UI4: sprintf(buffer, "%lu", value.ulVal); break;
|
|
case VT_UI8:
|
|
if (desc[i].ratio)
|
|
sprintf(buffer, "%lu:%lu", value.uhVal.HighPart, value.uhVal.LowPart);
|
|
else
|
|
sprintf(buffer, "%I64u", value.uhVal.QuadPart);
|
|
break;
|
|
case VT_VECTOR | VT_UI1:
|
|
buf += sprintf(buf, "size %lu, data {", value.caub.cElems);
|
|
for (j = 0; j < 128 && j < value.caub.cElems; ++j)
|
|
buf += sprintf(buf, "0x%02x,", value.caub.pElems[j]);
|
|
if (value.caub.cElems > 128)
|
|
buf += sprintf(buf, "...}");
|
|
else
|
|
buf += sprintf(buf - (j ? 1 : 0), "}");
|
|
break;
|
|
}
|
|
|
|
ret = PropVariantCompareEx(&value, &desc[i].value, 0, 0);
|
|
todo_wine_if(desc[i].todo_value)
|
|
ok_(file, line)(ret == 0, "%s mismatch, type %u, value %s\n",
|
|
debugstr_a(desc[i].name), value.vt, buffer);
|
|
PropVariantClear(&value);
|
|
}
|
|
}
|
|
|
|
struct transform_info
|
|
{
|
|
const WCHAR *name;
|
|
const GUID *major_type;
|
|
struct
|
|
{
|
|
const GUID *subtype;
|
|
BOOL broken;
|
|
} inputs[32], input_end, outputs[32], output_end;
|
|
};
|
|
|
|
static BOOL check_mft_enum(GUID category, MFT_REGISTER_TYPE_INFO *input_type,
|
|
MFT_REGISTER_TYPE_INFO *output_type, const GUID *expect_class_id)
|
|
{
|
|
GUID *class_ids = NULL;
|
|
UINT32 count = 0, i;
|
|
HRESULT hr;
|
|
|
|
hr = MFTEnum(category, 0, input_type, output_type, NULL, &class_ids, &count);
|
|
if (FAILED(hr) || count == 0)
|
|
{
|
|
todo_wine
|
|
win_skip("MFTEnum returned %#lx, count %u, skipping tests.\n", hr, count);
|
|
return FALSE;
|
|
}
|
|
|
|
ok(hr == S_OK, "MFTEnum returned %#lx\n", hr);
|
|
for (i = 0; i < count; ++i)
|
|
if (IsEqualGUID(expect_class_id, class_ids + i))
|
|
break;
|
|
ok(i < count, "Failed to find transform.\n");
|
|
CoTaskMemFree(class_ids);
|
|
|
|
return i < count;
|
|
}
|
|
|
|
static void check_mft_get_info(const GUID *class_id, const struct transform_info *expect)
|
|
{
|
|
MFT_REGISTER_TYPE_INFO *input_types = NULL, *output_types = NULL;
|
|
UINT32 input_count = 0, output_count = 0, i;
|
|
WCHAR *name;
|
|
HRESULT hr;
|
|
|
|
hr = MFTGetInfo(*class_id, &name, &input_types, &input_count, &output_types, &output_count, NULL);
|
|
ok(hr == S_OK, "MFTEnum returned %#lx\n", hr);
|
|
ok(!wcscmp(name, expect->name), "got name %s\n", debugstr_w(name));
|
|
|
|
for (i = 0; i < input_count && expect->inputs[i].subtype; ++i)
|
|
{
|
|
ok(IsEqualGUID(&input_types[i].guidMajorType, expect->major_type),
|
|
"got input[%u] major %s\n", i, debugstr_guid(&input_types[i].guidMajorType));
|
|
ok(IsEqualGUID(&input_types[i].guidSubtype, expect->inputs[i].subtype),
|
|
"got input[%u] subtype %s\n", i, debugstr_guid(&input_types[i].guidSubtype));
|
|
}
|
|
for (; expect->inputs[i].subtype; ++i)
|
|
ok(broken(expect->inputs[i].broken), "missing input[%u] subtype %s\n",
|
|
i, debugstr_guid(expect->inputs[i].subtype));
|
|
for (; i < input_count; ++i)
|
|
ok(0, "extra input[%u] subtype %s\n", i, debugstr_guid(&input_types[i].guidSubtype));
|
|
|
|
for (i = 0; expect->outputs[i].subtype; ++i)
|
|
{
|
|
ok(IsEqualGUID(&output_types[i].guidMajorType, expect->major_type),
|
|
"got output[%u] major %s\n", i, debugstr_guid(&output_types[i].guidMajorType));
|
|
ok(IsEqualGUID(&output_types[i].guidSubtype, expect->outputs[i].subtype),
|
|
"got output[%u] subtype %s\n", i, debugstr_guid(&output_types[i].guidSubtype));
|
|
}
|
|
for (; expect->outputs[i].subtype; ++i)
|
|
ok(0, "missing output[%u] subtype %s\n", i, debugstr_guid(expect->outputs[i].subtype));
|
|
for (; i < output_count; ++i)
|
|
ok(0, "extra output[%u] subtype %s\n", i, debugstr_guid(&output_types[i].guidSubtype));
|
|
|
|
CoTaskMemFree(output_types);
|
|
CoTaskMemFree(input_types);
|
|
CoTaskMemFree(name);
|
|
}
|
|
|
|
static void check_dmo_get_info(const GUID *class_id, const struct transform_info *expect)
|
|
{
|
|
DWORD input_count = 0, output_count = 0;
|
|
DMO_PARTIAL_MEDIATYPE output[32] = {{{0}}};
|
|
DMO_PARTIAL_MEDIATYPE input[32] = {{{0}}};
|
|
WCHAR name[80];
|
|
HRESULT hr;
|
|
int i;
|
|
|
|
hr = DMOGetName(class_id, name);
|
|
ok(hr == S_OK, "DMOGetName returned %#lx\n", hr);
|
|
ok(!wcscmp(name, expect->name), "got name %s\n", debugstr_w(name));
|
|
|
|
hr = DMOGetTypes(class_id, ARRAY_SIZE(input), &input_count, input,
|
|
ARRAY_SIZE(output), &output_count, output);
|
|
ok(hr == S_OK, "DMOGetTypes returned %#lx\n", hr);
|
|
|
|
for (i = 0; i < input_count && expect->inputs[i].subtype; ++i)
|
|
{
|
|
ok(IsEqualGUID(&input[i].type, expect->major_type),
|
|
"got input[%u] major %s\n", i, debugstr_guid(&input[i].type));
|
|
ok(IsEqualGUID(&input[i].subtype, expect->inputs[i].subtype),
|
|
"got input[%u] subtype %s\n", i, debugstr_guid(&input[i].subtype));
|
|
}
|
|
for (; expect->inputs[i].subtype; ++i)
|
|
ok(0, "missing input[%u] subtype %s\n", i, debugstr_guid(expect->inputs[i].subtype));
|
|
for (; i < input_count; ++i)
|
|
ok(0, "extra input[%u] subtype %s\n", i, debugstr_guid(&input[i].subtype));
|
|
|
|
for (i = 0; expect->outputs[i].subtype; ++i)
|
|
{
|
|
ok(IsEqualGUID(&output[i].type, expect->major_type),
|
|
"got output[%u] major %s\n", i, debugstr_guid(&output[i].type));
|
|
ok(IsEqualGUID(&output[i].subtype, expect->outputs[i].subtype),
|
|
"got output[%u] subtype %s\n", i, debugstr_guid(&output[i].subtype));
|
|
}
|
|
for (; expect->outputs[i].subtype; ++i)
|
|
ok(0, "missing output[%u] subtype %s\n", i, debugstr_guid(expect->outputs[i].subtype));
|
|
for (; i < output_count; ++i)
|
|
ok(0, "extra output[%u] subtype %s\n", i, debugstr_guid(&output[i].subtype));
|
|
}
|
|
|
|
void init_media_type(IMFMediaType *mediatype, const struct attribute_desc *desc, ULONG limit)
|
|
{
|
|
HRESULT hr;
|
|
ULONG i;
|
|
|
|
hr = IMFMediaType_DeleteAllItems(mediatype);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
|
|
for (i = 0; i < limit && desc[i].key; ++i)
|
|
{
|
|
hr = IMFMediaType_SetItem(mediatype, desc[i].key, &desc[i].value);
|
|
ok(hr == S_OK, "SetItem %s returned %#lx\n", debugstr_a(desc[i].name), hr);
|
|
}
|
|
}
|
|
|
|
static void init_dmo_media_type_video(DMO_MEDIA_TYPE *media_type,
|
|
const GUID *subtype, const LONG width, const LONG height)
|
|
{
|
|
UINT32 image_size = 0, extra_bytes = subtype_to_extra_bytes(subtype);
|
|
VIDEOINFOHEADER *header = (VIDEOINFOHEADER *)(media_type + 1);
|
|
BOOL compressed = is_compressed_subtype(subtype);
|
|
|
|
MFCalculateImageSize(subtype, width, height, &image_size);
|
|
memset(media_type, 0, sizeof(*media_type) + sizeof(*header) + extra_bytes);
|
|
|
|
header->rcSource.top = 0;
|
|
header->rcSource.left = 0;
|
|
header->rcSource.right = width;
|
|
header->rcSource.bottom = height;
|
|
header->rcTarget.top = 0;
|
|
header->rcTarget.left = 0;
|
|
header->rcTarget.right = width;
|
|
header->rcTarget.bottom = height;
|
|
header->bmiHeader.biSize = sizeof(header->bmiHeader);
|
|
header->bmiHeader.biWidth = width;
|
|
header->bmiHeader.biHeight = height;
|
|
header->bmiHeader.biPlanes = 1;
|
|
header->bmiHeader.biBitCount = subtype_to_bpp(subtype);
|
|
header->bmiHeader.biCompression = subtype_to_tag(subtype);
|
|
header->bmiHeader.biSizeImage = image_size;
|
|
if (IsEqualGUID(subtype, &MEDIASUBTYPE_RGB8))
|
|
{
|
|
header->bmiHeader.biClrUsed = 226;
|
|
header->bmiHeader.biClrImportant = header->bmiHeader.biClrUsed;
|
|
}
|
|
|
|
media_type->majortype = MEDIATYPE_Video;
|
|
media_type->subtype = *subtype;
|
|
media_type->bFixedSizeSamples = !compressed;
|
|
media_type->bTemporalCompression = compressed;
|
|
media_type->lSampleSize = image_size;
|
|
media_type->formattype = FORMAT_VideoInfo;
|
|
media_type->pUnk = NULL;
|
|
media_type->cbFormat = sizeof(*header) + extra_bytes;
|
|
media_type->pbFormat = (BYTE *)header;
|
|
}
|
|
|
|
static void init_dmo_media_type_audio(DMO_MEDIA_TYPE *media_type,
|
|
const GUID *subtype, UINT channel_count, UINT rate, UINT bits_per_sample)
|
|
{
|
|
WAVEFORMATEX *format = (WAVEFORMATEX *)(media_type + 1);
|
|
DWORD extra_bytes = subtype_to_extra_bytes(subtype);
|
|
|
|
memset(media_type, 0, sizeof(*media_type) + sizeof(*format) + extra_bytes);
|
|
|
|
media_type->majortype = MEDIATYPE_Audio;
|
|
media_type->subtype = *subtype;
|
|
media_type->bFixedSizeSamples = TRUE;
|
|
media_type->bTemporalCompression = FALSE;
|
|
media_type->lSampleSize = 0;
|
|
media_type->formattype = FORMAT_WaveFormatEx;
|
|
media_type->pUnk = NULL;
|
|
media_type->cbFormat = sizeof(*format) + extra_bytes;
|
|
media_type->pbFormat = (BYTE *)format;
|
|
|
|
format->wFormatTag = subtype_to_tag(subtype);
|
|
format->nChannels = channel_count;
|
|
format->nSamplesPerSec = rate;
|
|
format->wBitsPerSample = bits_per_sample;
|
|
format->nBlockAlign = channel_count * bits_per_sample / 8;
|
|
format->nAvgBytesPerSec = format->nBlockAlign * rate;
|
|
format->cbSize = extra_bytes;
|
|
}
|
|
|
|
static void check_mft_optional_methods(IMFTransform *transform, DWORD output_count)
|
|
{
|
|
DWORD in_id, out_id, in_count, out_count, in_min, in_max, out_min, out_max;
|
|
PROPVARIANT propvar = {.vt = VT_EMPTY};
|
|
IMFMediaEvent *event;
|
|
HRESULT hr;
|
|
|
|
in_min = in_max = out_min = out_max = 0xdeadbeef;
|
|
hr = IMFTransform_GetStreamLimits(transform, &in_min, &in_max, &out_min, &out_max);
|
|
ok(hr == S_OK, "GetStreamLimits returned %#lx\n", hr);
|
|
ok(in_min == 1, "got input_min %lu\n", in_min);
|
|
ok(in_max == 1, "got input_max %lu\n", in_max);
|
|
ok(out_min == output_count, "got output_min %lu\n", out_min);
|
|
ok(out_max == output_count, "got output_max %lu\n", out_max);
|
|
|
|
in_count = out_count = 0xdeadbeef;
|
|
hr = IMFTransform_GetStreamCount(transform, &in_count, &out_count);
|
|
ok(hr == S_OK, "GetStreamCount returned %#lx\n", hr);
|
|
ok(in_count == 1, "got input_count %lu\n", in_count);
|
|
ok(out_count == output_count, "got output_count %lu\n", out_count);
|
|
|
|
in_count = out_count = 1;
|
|
in_id = out_id = 0xdeadbeef;
|
|
hr = IMFTransform_GetStreamIDs(transform, in_count, &in_id, out_count, &out_id);
|
|
ok(hr == E_NOTIMPL, "GetStreamIDs returned %#lx\n", hr);
|
|
|
|
hr = IMFTransform_DeleteInputStream(transform, 0);
|
|
ok(hr == E_NOTIMPL, "DeleteInputStream returned %#lx\n", hr);
|
|
hr = IMFTransform_DeleteInputStream(transform, 1);
|
|
ok(hr == E_NOTIMPL, "DeleteInputStream returned %#lx\n", hr);
|
|
|
|
hr = IMFTransform_AddInputStreams(transform, 0, NULL);
|
|
ok(hr == E_NOTIMPL, "AddInputStreams returned %#lx\n", hr);
|
|
in_id = 0xdeadbeef;
|
|
hr = IMFTransform_AddInputStreams(transform, 1, &in_id);
|
|
ok(hr == E_NOTIMPL, "AddInputStreams returned %#lx\n", hr);
|
|
|
|
hr = IMFTransform_SetOutputBounds(transform, 0, 0);
|
|
ok(hr == E_NOTIMPL || hr == S_OK, "SetOutputBounds returned %#lx\n", hr);
|
|
|
|
hr = MFCreateMediaEvent(MEEndOfStream, &GUID_NULL, S_OK, &propvar, &event);
|
|
ok(hr == S_OK, "MFCreateMediaEvent returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessEvent(transform, 0, NULL);
|
|
ok(hr == E_NOTIMPL || hr == E_POINTER || hr == E_INVALIDARG, "ProcessEvent returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessEvent(transform, 1, event);
|
|
ok(hr == E_NOTIMPL, "ProcessEvent returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessEvent(transform, 0, event);
|
|
ok(hr == E_NOTIMPL, "ProcessEvent returned %#lx\n", hr);
|
|
IMFMediaEvent_Release(event);
|
|
}
|
|
|
|
static void check_mft_get_attributes(IMFTransform *transform, const struct attribute_desc *expect_transform_attributes,
|
|
BOOL expect_output_attributes)
|
|
{
|
|
IMFAttributes *attributes, *tmp_attributes;
|
|
UINT32 count;
|
|
HRESULT hr;
|
|
ULONG ref;
|
|
|
|
hr = IMFTransform_GetAttributes(transform, &attributes);
|
|
todo_wine_if(expect_transform_attributes && hr == E_NOTIMPL)
|
|
ok(hr == (expect_transform_attributes ? S_OK : E_NOTIMPL), "GetAttributes returned %#lx\n", hr);
|
|
if (hr == S_OK)
|
|
{
|
|
ok(hr == S_OK, "GetAttributes returned %#lx\n", hr);
|
|
check_attributes(attributes, expect_transform_attributes, -1);
|
|
|
|
hr = IMFTransform_GetAttributes(transform, &tmp_attributes);
|
|
ok(hr == S_OK, "GetAttributes returned %#lx\n", hr);
|
|
ok(attributes == tmp_attributes, "got attributes %p\n", tmp_attributes);
|
|
IMFAttributes_Release(tmp_attributes);
|
|
|
|
ref = IMFAttributes_Release(attributes);
|
|
ok(ref == 1, "Release returned %lu\n", ref);
|
|
}
|
|
|
|
hr = IMFTransform_GetOutputStreamAttributes(transform, 0, &attributes);
|
|
todo_wine_if(expect_output_attributes && hr == E_NOTIMPL)
|
|
ok(hr == (expect_output_attributes ? S_OK : E_NOTIMPL)
|
|
|| broken(hr == MF_E_UNSUPPORTED_REPRESENTATION) /* Win7 */,
|
|
"GetOutputStreamAttributes returned %#lx\n", hr);
|
|
if (hr == S_OK)
|
|
{
|
|
ok(hr == S_OK, "GetOutputStreamAttributes returned %#lx\n", hr);
|
|
|
|
count = 0xdeadbeef;
|
|
hr = IMFAttributes_GetCount(attributes, &count);
|
|
ok(hr == S_OK, "GetCount returned %#lx\n", hr);
|
|
ok(!count, "got %u attributes\n", count);
|
|
|
|
hr = IMFTransform_GetOutputStreamAttributes(transform, 0, &tmp_attributes);
|
|
ok(hr == S_OK, "GetAttributes returned %#lx\n", hr);
|
|
ok(attributes == tmp_attributes, "got attributes %p\n", tmp_attributes);
|
|
IMFAttributes_Release(tmp_attributes);
|
|
|
|
ref = IMFAttributes_Release(attributes);
|
|
ok(ref == 1, "Release returned %lu\n", ref);
|
|
|
|
hr = IMFTransform_GetOutputStreamAttributes(transform, 0, NULL);
|
|
ok(hr == E_NOTIMPL || hr == E_POINTER, "GetOutputStreamAttributes returned %#lx\n", hr);
|
|
hr = IMFTransform_GetOutputStreamAttributes(transform, 1, &attributes);
|
|
ok(hr == MF_E_INVALIDSTREAMNUMBER, "GetOutputStreamAttributes returned %#lx\n", hr);
|
|
}
|
|
|
|
hr = IMFTransform_GetInputStreamAttributes(transform, 0, &attributes);
|
|
ok(hr == E_NOTIMPL || broken(hr == MF_E_UNSUPPORTED_REPRESENTATION) /* Win7 */,
|
|
"GetInputStreamAttributes returned %#lx\n", hr);
|
|
}
|
|
|
|
#define check_mft_input_stream_info(a, b) check_mft_input_stream_info_(__LINE__, a, b)
|
|
static void check_mft_input_stream_info_(int line, MFT_INPUT_STREAM_INFO *value, const MFT_INPUT_STREAM_INFO *expect)
|
|
{
|
|
check_member_(__FILE__, line, *value, *expect, "%I64d", hnsMaxLatency);
|
|
check_member_(__FILE__, line, *value, *expect, "%#lx", dwFlags);
|
|
check_member_(__FILE__, line, *value, *expect, "%#lx", cbSize);
|
|
check_member_(__FILE__, line, *value, *expect, "%#lx", cbMaxLookahead);
|
|
check_member_(__FILE__, line, *value, *expect, "%#lx", cbAlignment);
|
|
}
|
|
|
|
#define check_mft_get_input_stream_info(a, b, c) check_mft_get_input_stream_info_(__LINE__, a, b, c)
|
|
static void check_mft_get_input_stream_info_(int line, IMFTransform *transform, HRESULT expect_hr, const MFT_INPUT_STREAM_INFO *expect)
|
|
{
|
|
MFT_INPUT_STREAM_INFO info, empty = {0};
|
|
HRESULT hr;
|
|
|
|
memset(&info, 0xcd, sizeof(info));
|
|
hr = IMFTransform_GetInputStreamInfo(transform, 0, &info);
|
|
ok_(__FILE__, line)(hr == expect_hr, "GetInputStreamInfo returned %#lx\n", hr);
|
|
check_mft_input_stream_info_(line, &info, expect ? expect : &empty);
|
|
}
|
|
|
|
#define check_mft_output_stream_info(a, b) check_mft_output_stream_info_(__LINE__, a, b)
|
|
static void check_mft_output_stream_info_(int line, MFT_OUTPUT_STREAM_INFO *value, const MFT_OUTPUT_STREAM_INFO *expect)
|
|
{
|
|
check_member_(__FILE__, line, *value, *expect, "%#lx", dwFlags);
|
|
check_member_(__FILE__, line, *value, *expect, "%#lx", cbSize);
|
|
check_member_(__FILE__, line, *value, *expect, "%#lx", cbAlignment);
|
|
}
|
|
|
|
#define check_mft_get_output_stream_info(a, b, c) check_mft_get_output_stream_info_(__LINE__, a, b, c)
|
|
static void check_mft_get_output_stream_info_(int line, IMFTransform *transform, HRESULT expect_hr, const MFT_OUTPUT_STREAM_INFO *expect)
|
|
{
|
|
MFT_OUTPUT_STREAM_INFO info, empty = {0};
|
|
HRESULT hr;
|
|
|
|
memset(&info, 0xcd, sizeof(info));
|
|
hr = IMFTransform_GetOutputStreamInfo(transform, 0, &info);
|
|
ok_(__FILE__, line)(hr == expect_hr, "GetOutputStreamInfo returned %#lx\n", hr);
|
|
check_mft_output_stream_info_(line, &info, expect ? expect : &empty);
|
|
}
|
|
|
|
#define check_mft_set_input_type_required(a, b) check_mft_set_input_type_required_(__LINE__, a, b)
|
|
static void check_mft_set_input_type_required_(int line, IMFTransform *transform, const struct attribute_desc *attributes)
|
|
{
|
|
const struct attribute_desc *attr;
|
|
IMFMediaType *media_type;
|
|
HRESULT hr;
|
|
ULONG ref;
|
|
|
|
hr = MFCreateMediaType(&media_type);
|
|
ok_(__FILE__, line)(hr == S_OK, "MFCreateMediaType returned hr %#lx.\n", hr);
|
|
init_media_type(media_type, attributes, -1);
|
|
|
|
for (attr = attributes; attr && attr->key; attr++)
|
|
{
|
|
winetest_push_context("%s", debugstr_a(attr->name));
|
|
hr = IMFMediaType_DeleteItem(media_type, attr->key);
|
|
ok_(__FILE__, line)(hr == S_OK, "DeleteItem returned %#lx\n", hr);
|
|
hr = IMFTransform_SetInputType(transform, 0, media_type, MFT_SET_TYPE_TEST_ONLY);
|
|
ok_(__FILE__, line)(FAILED(hr) == attr->required, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMFMediaType_SetItem(media_type, attr->key, &attr->value);
|
|
ok_(__FILE__, line)(hr == S_OK, "SetItem returned %#lx\n", hr);
|
|
winetest_pop_context();
|
|
}
|
|
|
|
hr = IMFTransform_SetInputType(transform, 0, media_type, MFT_SET_TYPE_TEST_ONLY);
|
|
ok_(__FILE__, line)(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
ref = IMFMediaType_Release(media_type);
|
|
ok_(__FILE__, line)(!ref, "Release returned %lu\n", ref);
|
|
}
|
|
|
|
static void check_mft_set_input_type(IMFTransform *transform, const struct attribute_desc *attributes)
|
|
{
|
|
IMFMediaType *media_type;
|
|
HRESULT hr;
|
|
|
|
hr = MFCreateMediaType(&media_type);
|
|
ok(hr == S_OK, "MFCreateMediaType returned hr %#lx.\n", hr);
|
|
init_media_type(media_type, attributes, -1);
|
|
|
|
hr = IMFTransform_SetInputType(transform, 0, media_type, MFT_SET_TYPE_TEST_ONLY);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMFTransform_SetInputType(transform, 0, media_type, 0);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
|
|
IMFMediaType_Release(media_type);
|
|
}
|
|
|
|
#define check_mft_get_input_current_type(a, b) check_mft_get_input_current_type_(a, b, FALSE, FALSE)
|
|
static void check_mft_get_input_current_type_(IMFTransform *transform, const struct attribute_desc *attributes,
|
|
BOOL todo_current, BOOL todo_compare)
|
|
{
|
|
HRESULT hr, expect_hr = attributes ? S_OK : MF_E_TRANSFORM_TYPE_NOT_SET;
|
|
IMFMediaType *media_type, *current_type;
|
|
BOOL result;
|
|
|
|
hr = IMFTransform_GetInputCurrentType(transform, 0, ¤t_type);
|
|
todo_wine_if(todo_current)
|
|
ok(hr == expect_hr, "GetInputCurrentType returned hr %#lx.\n", hr);
|
|
if (FAILED(hr))
|
|
return;
|
|
|
|
hr = MFCreateMediaType(&media_type);
|
|
ok(hr == S_OK, "MFCreateMediaType returned hr %#lx.\n", hr);
|
|
init_media_type(media_type, attributes, -1);
|
|
|
|
hr = IMFMediaType_Compare(current_type, (IMFAttributes *)media_type,
|
|
MF_ATTRIBUTES_MATCH_ALL_ITEMS, &result);
|
|
ok(hr == S_OK, "Compare returned hr %#lx.\n", hr);
|
|
todo_wine_if(todo_compare)
|
|
ok(result, "got result %u.\n", !!result);
|
|
|
|
IMFMediaType_Release(media_type);
|
|
IMFMediaType_Release(current_type);
|
|
}
|
|
|
|
#define check_mft_set_output_type_required(a, b) check_mft_set_output_type_required_(__LINE__, a, b)
|
|
static void check_mft_set_output_type_required_(int line, IMFTransform *transform, const struct attribute_desc *attributes)
|
|
{
|
|
const struct attribute_desc *attr;
|
|
IMFMediaType *media_type;
|
|
HRESULT hr;
|
|
ULONG ref;
|
|
|
|
hr = MFCreateMediaType(&media_type);
|
|
ok_(__FILE__, line)(hr == S_OK, "MFCreateMediaType returned hr %#lx.\n", hr);
|
|
init_media_type(media_type, attributes, -1);
|
|
|
|
for (attr = attributes; attr && attr->key; attr++)
|
|
{
|
|
winetest_push_context("%s", debugstr_a(attr->name));
|
|
hr = IMFMediaType_DeleteItem(media_type, attr->key);
|
|
ok_(__FILE__, line)(hr == S_OK, "DeleteItem returned %#lx\n", hr);
|
|
hr = IMFTransform_SetOutputType(transform, 0, media_type, MFT_SET_TYPE_TEST_ONLY);
|
|
ok_(__FILE__, line)(FAILED(hr) == attr->required, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMFMediaType_SetItem(media_type, attr->key, &attr->value);
|
|
ok_(__FILE__, line)(hr == S_OK, "SetItem returned %#lx\n", hr);
|
|
winetest_pop_context();
|
|
}
|
|
|
|
hr = IMFTransform_SetOutputType(transform, 0, media_type, MFT_SET_TYPE_TEST_ONLY);
|
|
ok_(__FILE__, line)(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
ref = IMFMediaType_Release(media_type);
|
|
ok_(__FILE__, line)(!ref, "Release returned %lu\n", ref);
|
|
}
|
|
|
|
static void check_mft_set_output_type(IMFTransform *transform, const struct attribute_desc *attributes,
|
|
HRESULT expect_hr)
|
|
{
|
|
IMFMediaType *media_type;
|
|
HRESULT hr;
|
|
|
|
hr = MFCreateMediaType(&media_type);
|
|
ok(hr == S_OK, "MFCreateMediaType returned hr %#lx.\n", hr);
|
|
init_media_type(media_type, attributes, -1);
|
|
|
|
hr = IMFTransform_SetOutputType(transform, 0, media_type, MFT_SET_TYPE_TEST_ONLY);
|
|
ok(hr == expect_hr, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMFTransform_SetOutputType(transform, 0, media_type, 0);
|
|
ok(hr == expect_hr, "SetOutputType returned %#lx.\n", hr);
|
|
|
|
IMFMediaType_Release(media_type);
|
|
}
|
|
|
|
#define check_mft_get_output_current_type(a, b) check_mft_get_output_current_type_(a, b, FALSE)
|
|
static void check_mft_get_output_current_type_(IMFTransform *transform, const struct attribute_desc *attributes,
|
|
BOOL todo_current)
|
|
{
|
|
HRESULT hr, expect_hr = attributes ? S_OK : MF_E_TRANSFORM_TYPE_NOT_SET;
|
|
IMFMediaType *media_type, *current_type;
|
|
|
|
hr = IMFTransform_GetOutputCurrentType(transform, 0, ¤t_type);
|
|
todo_wine_if(todo_current)
|
|
ok(hr == expect_hr, "GetOutputCurrentType returned hr %#lx.\n", hr);
|
|
if (FAILED(hr))
|
|
return;
|
|
|
|
hr = MFCreateMediaType(&media_type);
|
|
ok(hr == S_OK, "MFCreateMediaType returned hr %#lx.\n", hr);
|
|
init_media_type(media_type, attributes, -1);
|
|
|
|
check_attributes((IMFAttributes *)current_type, attributes, -1);
|
|
|
|
IMFMediaType_Release(media_type);
|
|
IMFMediaType_Release(current_type);
|
|
}
|
|
|
|
#define check_mft_process_output(a, b, c) check_mft_process_output_(__LINE__, a, b, c)
|
|
static HRESULT check_mft_process_output_(int line, IMFTransform *transform, IMFSample *output_sample, DWORD *output_status)
|
|
{
|
|
static const DWORD expect_flags = MFT_OUTPUT_DATA_BUFFER_INCOMPLETE | MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE
|
|
| MFT_OUTPUT_DATA_BUFFER_STREAM_END | MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE;
|
|
MFT_OUTPUT_DATA_BUFFER output[3];
|
|
HRESULT hr, ret;
|
|
DWORD status;
|
|
|
|
status = 0;
|
|
memset(&output, 0, sizeof(output));
|
|
output[0].pSample = output_sample;
|
|
output[0].dwStreamID = 0;
|
|
ret = IMFTransform_ProcessOutput(transform, 0, 1, output, &status);
|
|
ok_(__FILE__, line)(output[0].dwStreamID == 0, "got dwStreamID %#lx\n", output[0].dwStreamID);
|
|
ok_(__FILE__, line)(output[0].pEvents == NULL, "got pEvents %p\n", output[0].pEvents);
|
|
ok_(__FILE__, line)(output[0].pSample == output_sample, "got pSample %p\n", output[0].pSample);
|
|
ok_(__FILE__, line)((output[0].dwStatus & ~expect_flags) == 0
|
|
|| broken((output[0].dwStatus & ~expect_flags) == 6) /* Win7 */
|
|
|| broken((output[0].dwStatus & ~expect_flags) == 7) /* Win7 */,
|
|
"got dwStatus %#lx\n", output[0].dwStatus);
|
|
*output_status = output[0].dwStatus & expect_flags;
|
|
|
|
if (!output_sample)
|
|
ok_(__FILE__, line)(status == 0, "got status %#lx\n", status);
|
|
else if (ret == MF_E_TRANSFORM_STREAM_CHANGE)
|
|
ok_(__FILE__, line)(status == MFT_PROCESS_OUTPUT_STATUS_NEW_STREAMS,
|
|
"got status %#lx\n", status);
|
|
else
|
|
{
|
|
if (*output_status & MFT_OUTPUT_DATA_BUFFER_INCOMPLETE)
|
|
{
|
|
hr = IMFSample_SetUINT32(output_sample, &mft_output_sample_incomplete, 1);
|
|
ok_(__FILE__, line)(hr == S_OK, "SetUINT32 returned %#lx\n", hr);
|
|
}
|
|
else
|
|
{
|
|
hr = IMFSample_DeleteItem(output_sample, &mft_output_sample_incomplete);
|
|
ok_(__FILE__, line)(hr == S_OK, "DeleteItem returned %#lx\n", hr);
|
|
}
|
|
ok_(__FILE__, line)(status == 0, "got status %#lx\n", status);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
DWORD compare_nv12(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect)
|
|
{
|
|
DWORD x, y, size, diff = 0, width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf;
|
|
|
|
/* skip BMP header and RGB data from the dump */
|
|
size = *(DWORD *)(expect + 2);
|
|
*length = *length + size;
|
|
expect = expect + size;
|
|
|
|
for (y = 0; y < height; y++, data += width, expect += width)
|
|
{
|
|
if (y < rect->top || y >= rect->bottom) continue;
|
|
for (x = 0; x < width; x++)
|
|
{
|
|
if (x < rect->left || x >= rect->right) continue;
|
|
diff += abs((int)expect[x] - (int)data[x]);
|
|
}
|
|
}
|
|
|
|
for (y = 0; y < height; y += 2, data += width, expect += width)
|
|
{
|
|
if (y < rect->top || y >= rect->bottom) continue;
|
|
for (x = 0; x < width; x += 2)
|
|
{
|
|
if (x < rect->left || x >= rect->right) continue;
|
|
diff += abs((int)expect[x + 0] - (int)data[x + 0]);
|
|
diff += abs((int)expect[x + 1] - (int)data[x + 1]);
|
|
}
|
|
}
|
|
|
|
size = (rect->right - rect->left) * (rect->bottom - rect->top) * 3 / 2;
|
|
return diff * 100 / 256 / size;
|
|
}
|
|
|
|
DWORD compare_i420(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect)
|
|
{
|
|
DWORD i, x, y, size, diff = 0, width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf;
|
|
|
|
/* skip BMP header and RGB data from the dump */
|
|
size = *(DWORD *)(expect + 2);
|
|
*length = *length + size;
|
|
expect = expect + size;
|
|
|
|
for (y = 0; y < height; y++, data += width, expect += width)
|
|
{
|
|
if (y < rect->top || y >= rect->bottom) continue;
|
|
for (x = 0; x < width; x++)
|
|
{
|
|
if (x < rect->left || x >= rect->right) continue;
|
|
diff += abs((int)expect[x] - (int)data[x]);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < 2; ++i) for (y = 0; y < height; y += 2, data += width / 2, expect += width / 2)
|
|
{
|
|
if (y < rect->top || y >= rect->bottom) continue;
|
|
for (x = 0; x < width; x += 2)
|
|
{
|
|
if (x < rect->left || x >= rect->right) continue;
|
|
diff += abs((int)expect[x / 2] - (int)data[x / 2]);
|
|
}
|
|
}
|
|
|
|
size = (rect->right - rect->left) * (rect->bottom - rect->top) * 3 / 2;
|
|
return diff * 100 / 256 / size;
|
|
}
|
|
|
|
static DWORD compare_rgb(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect, UINT bits)
|
|
{
|
|
DWORD x, y, step = bits / 8, size, diff = 0, width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf;
|
|
|
|
/* skip BMP header from the dump */
|
|
size = *(DWORD *)(expect + 2 + 2 * sizeof(DWORD));
|
|
*length = *length + size;
|
|
expect = expect + size;
|
|
|
|
for (y = 0; y < height; y++, data += width * step, expect += width * step)
|
|
{
|
|
if (y < rect->top || y >= rect->bottom) continue;
|
|
for (x = 0; x < width; x++)
|
|
{
|
|
if (x < rect->left || x >= rect->right) continue;
|
|
diff += abs((int)expect[step * x + 0] - (int)data[step * x + 0]);
|
|
diff += abs((int)expect[step * x + 1] - (int)data[step * x + 1]);
|
|
if (step >= 3) diff += abs((int)expect[step * x + 2] - (int)data[step * x + 2]);
|
|
}
|
|
}
|
|
|
|
size = (rect->right - rect->left) * (rect->bottom - rect->top) * min(step, 3);
|
|
return diff * 100 / 256 / size;
|
|
}
|
|
|
|
DWORD compare_rgb32(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect)
|
|
{
|
|
return compare_rgb(data, length, rect, expect, 32);
|
|
}
|
|
|
|
DWORD compare_rgb24(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect)
|
|
{
|
|
return compare_rgb(data, length, rect, expect, 24);
|
|
}
|
|
|
|
DWORD compare_rgb16(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect)
|
|
{
|
|
return compare_rgb(data, length, rect, expect, 16);
|
|
}
|
|
|
|
DWORD compare_pcm16(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect)
|
|
{
|
|
const INT16 *data_pcm = (INT16 *)data, *expect_pcm = (INT16 *)expect;
|
|
DWORD i, size = *length / 2, diff = 0;
|
|
|
|
for (i = 0; i < size; i++)
|
|
diff += abs((int)*expect_pcm++ - (int)*data_pcm++);
|
|
|
|
return diff * 100 / 65536 / size;
|
|
}
|
|
|
|
static DWORD compare_bytes(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect)
|
|
{
|
|
DWORD i, size = *length, diff = 0;
|
|
|
|
for (i = 0; i < size; i++)
|
|
diff += abs((int)*expect++ - (int)*data++);
|
|
|
|
return diff * 100 / 256 / size;
|
|
}
|
|
|
|
static void dump_rgb(const BYTE *data, DWORD length, const RECT *rect, HANDLE output, UINT bits)
|
|
{
|
|
DWORD width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf;
|
|
static const char magic[2] = "BM";
|
|
struct
|
|
{
|
|
DWORD length;
|
|
DWORD reserved;
|
|
DWORD offset;
|
|
BITMAPINFOHEADER biHeader;
|
|
} header =
|
|
{
|
|
.length = length + sizeof(header) + 2, .offset = sizeof(header) + 2,
|
|
.biHeader =
|
|
{
|
|
.biSize = sizeof(BITMAPINFOHEADER), .biWidth = width, .biHeight = height, .biPlanes = 1,
|
|
.biBitCount = bits, .biCompression = BI_RGB, .biSizeImage = width * height * (bits / 8),
|
|
},
|
|
};
|
|
DWORD written;
|
|
BOOL ret;
|
|
|
|
ret = WriteFile(output, magic, sizeof(magic), &written, NULL);
|
|
ok(ret, "WriteFile failed, error %lu\n", GetLastError());
|
|
ok(written == sizeof(magic), "written %lu bytes\n", written);
|
|
ret = WriteFile(output, &header, sizeof(header), &written, NULL);
|
|
ok(ret, "WriteFile failed, error %lu\n", GetLastError());
|
|
ok(written == sizeof(header), "written %lu bytes\n", written);
|
|
ret = WriteFile(output, data, length, &written, NULL);
|
|
ok(ret, "WriteFile failed, error %lu\n", GetLastError());
|
|
ok(written == length, "written %lu bytes\n", written);
|
|
}
|
|
|
|
void dump_rgb32(const BYTE *data, DWORD length, const RECT *rect, HANDLE output)
|
|
{
|
|
return dump_rgb(data, length, rect, output, 32);
|
|
}
|
|
|
|
void dump_rgb24(const BYTE *data, DWORD length, const RECT *rect, HANDLE output)
|
|
{
|
|
return dump_rgb(data, length, rect, output, 24);
|
|
}
|
|
|
|
void dump_rgb16(const BYTE *data, DWORD length, const RECT *rect, HANDLE output)
|
|
{
|
|
return dump_rgb(data, length, rect, output, 16);
|
|
}
|
|
|
|
void dump_nv12(const BYTE *data, DWORD length, const RECT *rect, HANDLE output)
|
|
{
|
|
DWORD written, x, y, width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf;
|
|
BYTE *rgb32_data = malloc(width * height * 4), *rgb32 = rgb32_data;
|
|
BOOL ret;
|
|
|
|
for (y = 0; y < height; y++) for (x = 0; x < width; x++)
|
|
{
|
|
*rgb32++ = data[width * y + x];
|
|
*rgb32++ = data[width * height + width * (y / 2) + (x & ~1) + 0];
|
|
*rgb32++ = data[width * height + width * (y / 2) + (x & ~1) + 1];
|
|
*rgb32++ = 0xff;
|
|
}
|
|
|
|
dump_rgb32(rgb32_data, width * height * 4, rect, output);
|
|
free(rgb32_data);
|
|
|
|
ret = WriteFile(output, data, length, &written, NULL);
|
|
ok(ret, "WriteFile failed, error %lu\n", GetLastError());
|
|
ok(written == length, "written %lu bytes\n", written);
|
|
}
|
|
|
|
void dump_i420(const BYTE *data, DWORD length, const RECT *rect, HANDLE output)
|
|
{
|
|
DWORD written, x, y, width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf;
|
|
BYTE *rgb32_data = malloc(width * height * 4), *rgb32 = rgb32_data;
|
|
BOOL ret;
|
|
|
|
for (y = 0; y < height; y++) for (x = 0; x < width; x++)
|
|
{
|
|
*rgb32++ = data[width * y + x];
|
|
*rgb32++ = data[width * height + (width / 2) * (y / 2) + x / 2];
|
|
*rgb32++ = data[width * height + (width / 2) * (y / 2) + (width / 2) * (height / 2) + x / 2];
|
|
*rgb32++ = 0xff;
|
|
}
|
|
|
|
dump_rgb32(rgb32_data, width * height * 4, rect, output);
|
|
free(rgb32_data);
|
|
|
|
ret = WriteFile(output, data, length, &written, NULL);
|
|
ok(ret, "WriteFile failed, error %lu\n", GetLastError());
|
|
ok(written == length, "written %lu bytes\n", written);
|
|
}
|
|
|
|
typedef void (*enum_mf_media_buffers_cb)(IMFMediaBuffer *buffer, const struct buffer_desc *desc, void *context);
|
|
static void enum_mf_media_buffers(IMFSample *sample, const struct sample_desc *sample_desc,
|
|
enum_mf_media_buffers_cb callback, void *context)
|
|
{
|
|
IMFMediaBuffer *buffer;
|
|
HRESULT hr;
|
|
DWORD i;
|
|
|
|
for (i = 0; SUCCEEDED(hr = IMFSample_GetBufferByIndex(sample, i, &buffer)); i++)
|
|
{
|
|
winetest_push_context("buffer %lu", i);
|
|
ok(hr == S_OK, "GetBufferByIndex returned %#lx\n", hr);
|
|
ok(i < sample_desc->buffer_count, "got unexpected buffer\n");
|
|
|
|
callback(buffer, sample_desc->buffers + i, context);
|
|
|
|
IMFMediaBuffer_Release(buffer);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == E_INVALIDARG, "GetBufferByIndex returned %#lx\n", hr);
|
|
}
|
|
|
|
struct enum_mf_sample_state
|
|
{
|
|
const struct sample_desc *next_sample;
|
|
struct sample_desc sample;
|
|
};
|
|
|
|
typedef void (*enum_mf_sample_cb)(IMFSample *sample, const struct sample_desc *sample_desc, void *context);
|
|
static void enum_mf_samples(IMFCollection *samples, const struct sample_desc *collection_desc,
|
|
enum_mf_sample_cb callback, void *context)
|
|
{
|
|
struct enum_mf_sample_state state = {.next_sample = collection_desc};
|
|
IMFSample *sample;
|
|
HRESULT hr;
|
|
DWORD i;
|
|
|
|
for (i = 0; SUCCEEDED(hr = IMFCollection_GetElement(samples, i, (IUnknown **)&sample)); i++)
|
|
{
|
|
winetest_push_context("sample %lu", i);
|
|
ok(hr == S_OK, "GetElement returned %#lx\n", hr);
|
|
|
|
state.sample.sample_time += state.sample.sample_duration;
|
|
if (!state.sample.repeat_count--)
|
|
state.sample = *state.next_sample++;
|
|
|
|
callback(sample, &state.sample, context);
|
|
|
|
IMFSample_Release(sample);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == E_INVALIDARG, "GetElement returned %#lx\n", hr);
|
|
}
|
|
|
|
static void dump_mf_media_buffer(IMFMediaBuffer *buffer, const struct buffer_desc *buffer_desc, HANDLE output)
|
|
{
|
|
DWORD length, written;
|
|
HRESULT hr;
|
|
BYTE *data;
|
|
BOOL ret;
|
|
|
|
hr = IMFMediaBuffer_Lock(buffer, &data, NULL, &length);
|
|
ok(hr == S_OK, "Lock returned %#lx\n", hr);
|
|
|
|
if (buffer_desc->dump)
|
|
buffer_desc->dump(data, length, &buffer_desc->rect, output);
|
|
else
|
|
{
|
|
if (buffer_desc->length == -1)
|
|
{
|
|
ret = WriteFile(output, &length, sizeof(length), &written, NULL);
|
|
ok(ret, "WriteFile failed, error %lu\n", GetLastError());
|
|
ok(written == sizeof(length), "written %lu bytes\n", written);
|
|
}
|
|
|
|
ret = WriteFile(output, data, length, &written, NULL);
|
|
ok(ret, "WriteFile failed, error %lu\n", GetLastError());
|
|
ok(written == length, "written %lu bytes\n", written);
|
|
}
|
|
|
|
hr = IMFMediaBuffer_Unlock(buffer);
|
|
ok(hr == S_OK, "Unlock returned %#lx\n", hr);
|
|
}
|
|
|
|
static void dump_mf_sample(IMFSample *sample, const struct sample_desc *sample_desc, HANDLE output)
|
|
{
|
|
enum_mf_media_buffers(sample, sample_desc, dump_mf_media_buffer, output);
|
|
}
|
|
|
|
static void dump_mf_sample_collection(IMFCollection *samples, const struct sample_desc *collection_desc,
|
|
const WCHAR *output_filename)
|
|
{
|
|
WCHAR path[MAX_PATH];
|
|
HANDLE output;
|
|
|
|
GetTempPathW(ARRAY_SIZE(path), path);
|
|
lstrcatW(path, output_filename);
|
|
|
|
output = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
|
|
ok(output != INVALID_HANDLE_VALUE, "CreateFileW failed, error %lu\n", GetLastError());
|
|
|
|
enum_mf_samples(samples, collection_desc, dump_mf_sample, output);
|
|
|
|
trace("created %s\n", debugstr_w(path));
|
|
CloseHandle(output);
|
|
}
|
|
|
|
#define check_mf_media_buffer(a, b, c) check_mf_media_buffer_(__FILE__, __LINE__, a, b, c)
|
|
static DWORD check_mf_media_buffer_(const char *file, int line, IMFMediaBuffer *buffer, const struct buffer_desc *expect,
|
|
const BYTE **expect_data, DWORD *expect_data_len)
|
|
{
|
|
DWORD length, diff = 0, expect_length = expect->length;
|
|
HRESULT hr;
|
|
BYTE *data;
|
|
|
|
if (expect_length == -1)
|
|
{
|
|
expect_length = *(DWORD *)*expect_data;
|
|
*expect_data = *expect_data + sizeof(DWORD);
|
|
*expect_data_len = *expect_data_len - sizeof(DWORD);
|
|
}
|
|
|
|
hr = IMFMediaBuffer_Lock(buffer, &data, NULL, &length);
|
|
ok_(file, line)(hr == S_OK, "Lock returned %#lx\n", hr);
|
|
todo_wine_if(expect->todo_length)
|
|
ok_(file, line)(length == expect_length, "got length %#lx\n", length);
|
|
|
|
if (*expect_data)
|
|
{
|
|
if (*expect_data_len < length)
|
|
todo_wine_if(expect->todo_length)
|
|
ok_(file, line)(0, "missing %#lx bytes\n", length - *expect_data_len);
|
|
else if (!expect->compare)
|
|
diff = compare_bytes(data, &length, NULL, *expect_data);
|
|
else
|
|
diff = expect->compare(data, &length, &expect->rect, *expect_data);
|
|
}
|
|
|
|
hr = IMFMediaBuffer_Unlock(buffer);
|
|
ok_(file, line)(hr == S_OK, "Unlock returned %#lx\n", hr);
|
|
|
|
*expect_data = *expect_data + min(length, *expect_data_len);
|
|
*expect_data_len = *expect_data_len - min(length, *expect_data_len);
|
|
|
|
return diff;
|
|
}
|
|
|
|
struct check_mf_sample_context
|
|
{
|
|
DWORD total_length;
|
|
const BYTE *data;
|
|
DWORD data_len;
|
|
DWORD diff;
|
|
const char *file;
|
|
int line;
|
|
};
|
|
|
|
static void check_mf_sample_buffer(IMFMediaBuffer *buffer, const struct buffer_desc *expect, void *context)
|
|
{
|
|
struct check_mf_sample_context *ctx = context;
|
|
DWORD expect_length = expect->length == -1 ? *(DWORD *)ctx->data : expect->length;
|
|
ctx->diff += check_mf_media_buffer_(ctx->file, ctx->line, buffer, expect, &ctx->data, &ctx->data_len);
|
|
ctx->total_length += expect_length;
|
|
}
|
|
|
|
#define check_mf_sample(a, b, c, d) check_mf_sample_(__FILE__, __LINE__, a, b, c, d)
|
|
static DWORD check_mf_sample_(const char *file, int line, IMFSample *sample, const struct sample_desc *expect,
|
|
const BYTE **expect_data, DWORD *expect_data_len)
|
|
{
|
|
struct check_mf_sample_context ctx = {.data = *expect_data, .data_len = *expect_data_len, .file = file, .line = line};
|
|
DWORD buffer_count, total_length, sample_flags;
|
|
LONGLONG timestamp;
|
|
HRESULT hr;
|
|
|
|
if (expect->attributes)
|
|
check_attributes_(file, line, (IMFAttributes *)sample, expect->attributes, -1);
|
|
|
|
buffer_count = 0xdeadbeef;
|
|
hr = IMFSample_GetBufferCount(sample, &buffer_count);
|
|
ok_(file, line)(hr == S_OK, "GetBufferCount returned %#lx\n", hr);
|
|
ok_(file, line)(buffer_count == expect->buffer_count,
|
|
"got %lu buffers\n", buffer_count);
|
|
|
|
sample_flags = 0xdeadbeef;
|
|
hr = IMFSample_GetSampleFlags(sample, &sample_flags);
|
|
ok_(file, line)(hr == S_OK, "GetSampleFlags returned %#lx\n", hr);
|
|
ok_(file, line)(sample_flags == 0,
|
|
"got sample flags %#lx\n", sample_flags);
|
|
|
|
timestamp = 0xdeadbeef;
|
|
hr = IMFSample_GetSampleTime(sample, ×tamp);
|
|
ok_(file, line)(hr == S_OK, "GetSampleTime returned %#lx\n", hr);
|
|
todo_wine_if(expect->todo_time)
|
|
ok_(file, line)(llabs(timestamp - expect->sample_time) <= 50,
|
|
"got sample time %I64d\n", timestamp);
|
|
|
|
timestamp = 0xdeadbeef;
|
|
hr = IMFSample_GetSampleDuration(sample, ×tamp);
|
|
ok_(file, line)(hr == S_OK, "GetSampleDuration returned %#lx\n", hr);
|
|
todo_wine_if(expect->todo_duration && expect->todo_duration == timestamp)
|
|
ok_(file, line)(llabs(timestamp - expect->sample_duration) <= 1,
|
|
"got sample duration %I64d\n", timestamp);
|
|
|
|
enum_mf_media_buffers(sample, expect, check_mf_sample_buffer, &ctx);
|
|
|
|
total_length = 0xdeadbeef;
|
|
hr = IMFSample_GetTotalLength(sample, &total_length);
|
|
ok_(file, line)(hr == S_OK, "GetTotalLength returned %#lx\n", hr);
|
|
todo_wine_if(expect->todo_length)
|
|
ok_(file, line)(total_length == ctx.total_length,
|
|
"got total length %#lx\n", total_length);
|
|
ok_(file, line)(!*expect_data || *expect_data_len >= ctx.total_length,
|
|
"missing %#lx data\n", ctx.total_length - *expect_data_len);
|
|
|
|
*expect_data = ctx.data;
|
|
*expect_data_len = ctx.data_len;
|
|
|
|
return ctx.diff / buffer_count;
|
|
}
|
|
|
|
static void check_mf_sample_collection_enum(IMFSample *sample, const struct sample_desc *expect, void *context)
|
|
{
|
|
struct check_mf_sample_context *ctx = context;
|
|
ctx->diff += check_mf_sample_(ctx->file, ctx->line, sample, expect, &ctx->data, &ctx->data_len);
|
|
}
|
|
|
|
DWORD check_mf_sample_collection_(const char *file, int line, IMFCollection *samples,
|
|
const struct sample_desc *expect_samples, const WCHAR *expect_data_filename)
|
|
{
|
|
struct check_mf_sample_context ctx = {.file = file, .line = line};
|
|
DWORD count;
|
|
HRESULT hr;
|
|
|
|
if (expect_data_filename) load_resource(expect_data_filename, &ctx.data, &ctx.data_len);
|
|
enum_mf_samples(samples, expect_samples, check_mf_sample_collection_enum, &ctx);
|
|
|
|
if (expect_data_filename) dump_mf_sample_collection(samples, expect_samples, expect_data_filename);
|
|
|
|
hr = IMFCollection_GetElementCount(samples, &count);
|
|
ok_(file, line)(hr == S_OK, "GetElementCount returned %#lx\n", hr);
|
|
|
|
return ctx.diff / count;
|
|
}
|
|
|
|
#define check_video_info_header(a, b) check_video_info_header_(__LINE__, a, b)
|
|
static void check_video_info_header_(int line, VIDEOINFOHEADER *info, const VIDEOINFOHEADER *expected)
|
|
{
|
|
ok_(__FILE__, line)(info->rcSource.left == expected->rcSource.left
|
|
&& info->rcSource.top == expected->rcSource.top
|
|
&& info->rcSource.right == expected->rcSource.right
|
|
&& info->rcSource.bottom == expected->rcSource.bottom,
|
|
"Got unexpected rcSource {%ld, %ld, %ld, %ld}, expected {%ld, %ld, %ld, %ld}.\n",
|
|
info->rcSource.left, info->rcSource.top, info->rcSource.right, info->rcSource.bottom,
|
|
expected->rcSource.left, expected->rcSource.top, expected->rcSource.right, expected->rcSource.bottom);
|
|
ok_(__FILE__, line)(info->rcTarget.left == expected->rcTarget.left
|
|
&& info->rcTarget.top == expected->rcTarget.top
|
|
&& info->rcTarget.right == expected->rcTarget.right
|
|
&& info->rcTarget.bottom == expected->rcTarget.bottom,
|
|
"Got unexpected rcTarget {%ld, %ld, %ld, %ld}, expected {%ld, %ld, %ld, %ld}.\n",
|
|
info->rcTarget.left, info->rcTarget.top, info->rcTarget.right, info->rcTarget.bottom,
|
|
expected->rcTarget.left, expected->rcTarget.top, expected->rcTarget.right, expected->rcTarget.bottom);
|
|
check_member_(__FILE__, line, *info, *expected, "%lu", dwBitRate);
|
|
check_member_(__FILE__, line, *info, *expected, "%lu", dwBitErrorRate);
|
|
check_member_(__FILE__, line, *info, *expected, "%I64d", AvgTimePerFrame);
|
|
check_member_(__FILE__, line, *info, *expected, "%lu", bmiHeader.biSize);
|
|
check_member_(__FILE__, line, *info, *expected, "%ld", bmiHeader.biWidth);
|
|
check_member_(__FILE__, line, *info, *expected, "%ld", bmiHeader.biHeight);
|
|
check_member_(__FILE__, line, *info, *expected, "%u", bmiHeader.biPlanes);
|
|
check_member_(__FILE__, line, *info, *expected, "%u", bmiHeader.biBitCount);
|
|
check_member_(__FILE__, line, *info, *expected, "%lx", bmiHeader.biCompression);
|
|
check_member_(__FILE__, line, *info, *expected, "%lu", bmiHeader.biSizeImage);
|
|
check_member_(__FILE__, line, *info, *expected, "%ld", bmiHeader.biXPelsPerMeter);
|
|
check_member_(__FILE__, line, *info, *expected, "%ld", bmiHeader.biYPelsPerMeter);
|
|
todo_wine_if(expected->bmiHeader.biClrUsed != 0)
|
|
check_member_(__FILE__, line, *info, *expected, "%lu", bmiHeader.biClrUsed);
|
|
todo_wine_if(expected->bmiHeader.biClrImportant != 0)
|
|
check_member_(__FILE__, line, *info, *expected, "%lu", bmiHeader.biClrImportant);
|
|
}
|
|
|
|
#define check_wave_format(a, b) check_wave_format_(__LINE__, a, b)
|
|
static void check_wave_format_(int line, WAVEFORMATEX *info, const WAVEFORMATEX *expected)
|
|
{
|
|
check_member_(__FILE__, line, *info, *expected, "%#x", wFormatTag);
|
|
check_member_(__FILE__, line, *info, *expected, "%u", nChannels);
|
|
check_member_(__FILE__, line, *info, *expected, "%lu", nSamplesPerSec);
|
|
check_member_(__FILE__, line, *info, *expected, "%lu", nAvgBytesPerSec);
|
|
check_member_(__FILE__, line, *info, *expected, "%u", nBlockAlign);
|
|
check_member_(__FILE__, line, *info, *expected, "%u", wBitsPerSample);
|
|
check_member_(__FILE__, line, *info, *expected, "%u", cbSize);
|
|
}
|
|
|
|
#define check_dmo_media_type(a, b) check_dmo_media_type_(__LINE__, a, b)
|
|
static void check_dmo_media_type_(int line, DMO_MEDIA_TYPE *media_type, const DMO_MEDIA_TYPE *expected)
|
|
{
|
|
ok_(__FILE__, line)(IsEqualGUID(&media_type->majortype, &expected->majortype),
|
|
"Got unexpected majortype %s, expected %s.\n",
|
|
debugstr_guid(&media_type->majortype), debugstr_guid(&expected->majortype));
|
|
ok_(__FILE__, line)(IsEqualGUID(&media_type->subtype, &expected->subtype),
|
|
"Got unexpected subtype %s, expected %s.\n",
|
|
debugstr_guid(&media_type->subtype), debugstr_guid(&expected->subtype));
|
|
if (IsEqualGUID(&expected->majortype, &MEDIATYPE_Video))
|
|
{
|
|
check_member_(__FILE__, line, *media_type, *expected, "%d", bFixedSizeSamples);
|
|
check_member_(__FILE__, line, *media_type, *expected, "%d", bTemporalCompression);
|
|
check_member_(__FILE__, line, *media_type, *expected, "%lu", lSampleSize);
|
|
}
|
|
ok_(__FILE__, line)(IsEqualGUID(&media_type->formattype, &expected->formattype),
|
|
"Got unexpected formattype %s.\n",
|
|
debugstr_guid(&media_type->formattype));
|
|
ok_(__FILE__, line)(media_type->pUnk == NULL, "Got unexpected pUnk %p.\n", media_type->pUnk);
|
|
todo_wine_if(expected->cbFormat
|
|
&& expected->cbFormat != sizeof(VIDEOINFOHEADER)
|
|
&& IsEqualGUID(&expected->majortype, &MEDIATYPE_Video))
|
|
check_member_(__FILE__, line, *media_type, *expected, "%lu", cbFormat);
|
|
|
|
if (expected->pbFormat)
|
|
{
|
|
ok_(__FILE__, line)(!!media_type->pbFormat, "Got NULL pbFormat.\n");
|
|
if (!media_type->pbFormat)
|
|
return;
|
|
|
|
if (IsEqualGUID(&media_type->formattype, &FORMAT_VideoInfo)
|
|
&& IsEqualGUID(&expected->formattype, &FORMAT_VideoInfo))
|
|
check_video_info_header((VIDEOINFOHEADER *)media_type->pbFormat, (VIDEOINFOHEADER *)expected->pbFormat);
|
|
else if (IsEqualGUID(&media_type->formattype, &FORMAT_WaveFormatEx)
|
|
&& IsEqualGUID(&expected->formattype, &FORMAT_WaveFormatEx))
|
|
check_wave_format((WAVEFORMATEX *)media_type->pbFormat, (WAVEFORMATEX *)expected->pbFormat);
|
|
}
|
|
}
|
|
|
|
#define check_dmo_output_data_buffer(a, b, c, d, e) check_dmo_output_data_buffer_(__LINE__, a, b, c, d, e)
|
|
static DWORD check_dmo_output_data_buffer_(int line, DMO_OUTPUT_DATA_BUFFER *output_data_buffer,
|
|
const struct buffer_desc *buffer_desc, const WCHAR *expect_data_filename,
|
|
REFERENCE_TIME time_stamp, REFERENCE_TIME time_length)
|
|
{
|
|
DWORD diff, data_length, buffer_length, expect_length;
|
|
BYTE *data, *buffer;
|
|
HRESULT hr;
|
|
|
|
if (output_data_buffer->dwStatus & DMO_OUTPUT_DATA_BUFFERF_TIME)
|
|
ok_(__FILE__, line)(output_data_buffer->rtTimestamp == time_stamp,
|
|
"Unexpected time stamp %I64d, expected %I64d.\n",
|
|
output_data_buffer->rtTimestamp, time_stamp);
|
|
if (output_data_buffer->dwStatus & DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH)
|
|
todo_wine
|
|
ok_(__FILE__, line)(output_data_buffer->rtTimelength == time_length,
|
|
"Unexpected time length %I64d, expected %I64d.\n",
|
|
output_data_buffer->rtTimelength, time_length);
|
|
|
|
load_resource(expect_data_filename, (const BYTE **)&data, &data_length);
|
|
|
|
expect_length = buffer_desc->length;
|
|
if (expect_length == -1)
|
|
{
|
|
expect_length = *(DWORD *)data;
|
|
data += sizeof(DWORD);
|
|
data_length = data_length - sizeof(DWORD);
|
|
}
|
|
|
|
hr = IMediaBuffer_GetBufferAndLength(output_data_buffer->pBuffer, &buffer, &buffer_length);
|
|
ok(hr == S_OK, "GetBufferAndLength returned %#lx.\n", hr);
|
|
ok_(__FILE__, line)(buffer_length == expect_length, "Unexpected length %#lx, expected %#lx\n", buffer_length, expect_length);
|
|
|
|
diff = 0;
|
|
if (data_length < buffer_length)
|
|
ok_(__FILE__, line)(0, "Missing %#lx bytes\n", buffer_length - data_length);
|
|
else if (!buffer_desc->compare)
|
|
diff = compare_bytes(buffer, &buffer_length, NULL, data);
|
|
else
|
|
diff = buffer_desc->compare(buffer, &buffer_length, &buffer_desc->rect, data);
|
|
|
|
return diff;
|
|
}
|
|
|
|
#define check_dmo_get_output_size_info_video(a, b, c, d, e) check_dmo_get_output_size_info_video_(__LINE__, a, b, c, d, e)
|
|
static void check_dmo_get_output_size_info_video_(int line, IMediaObject *dmo,
|
|
const GUID *input_subtype, const GUID *output_subtype, const LONG width, const LONG height)
|
|
{
|
|
DWORD size, alignment, expected_size;
|
|
DMO_MEDIA_TYPE *type;
|
|
char buffer[2048];
|
|
HRESULT hr;
|
|
|
|
type = (void *)buffer;
|
|
|
|
hr = IMediaObject_SetInputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR);
|
|
ok_(__FILE__, line)(hr == S_OK, "Failed to clear input type, hr %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR);
|
|
ok_(__FILE__, line)(hr == S_OK, "Failed to clear output type, hr %#lx.\n", hr);
|
|
|
|
init_dmo_media_type_video(type, input_subtype, width, height);
|
|
hr = IMediaObject_SetInputType(dmo, 0, type, 0);
|
|
ok_(__FILE__, line)(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
|
|
init_dmo_media_type_video(type, output_subtype, width, height);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, type, 0);
|
|
todo_wine_if(IsEqualGUID(output_subtype, &MEDIASUBTYPE_NV11)
|
|
|| IsEqualGUID(output_subtype, &MEDIASUBTYPE_IYUV))
|
|
ok_(__FILE__, line)(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
if (hr != S_OK)
|
|
return;
|
|
|
|
size = 0xdeadbeef;
|
|
alignment = 0xdeadbeef;
|
|
hr = MFCalculateImageSize(output_subtype, width, height, (UINT32 *)&expected_size);
|
|
ok_(__FILE__, line)(hr == S_OK, "MFCalculateImageSize returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_GetOutputSizeInfo(dmo, 0, &size, &alignment);
|
|
ok_(__FILE__, line)(hr == S_OK, "GetOutputSizeInfo returned %#lx.\n", hr);
|
|
ok_(__FILE__, line)(size == expected_size, "Unexpected size %lu, expected %lu.\n", size, expected_size);
|
|
ok_(__FILE__, line)(alignment == 1, "Unexpected alignment %lu.\n", alignment);
|
|
}
|
|
|
|
static HRESULT WINAPI test_unk_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
|
|
{
|
|
if (IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*obj = iface;
|
|
IUnknown_AddRef(iface);
|
|
return S_OK;
|
|
}
|
|
|
|
*obj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI test_unk_AddRef(IUnknown *iface)
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
static ULONG WINAPI test_unk_Release(IUnknown *iface)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static const IUnknownVtbl test_unk_vtbl =
|
|
{
|
|
test_unk_QueryInterface,
|
|
test_unk_AddRef,
|
|
test_unk_Release,
|
|
};
|
|
|
|
static BOOL is_supported_video_type(const GUID *guid)
|
|
{
|
|
return IsEqualGUID(guid, &MFVideoFormat_L8)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_L16)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_D16)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_IYUV)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_YV12)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_NV12)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_NV21)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_420O)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_P010)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_P016)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_UYVY)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_YUY2)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_P208)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_NV11)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_AYUV)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_ARGB32)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_RGB32)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_A2R10G10B10)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_A16B16G16R16F)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_RGB24)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_I420)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_YVYU)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_RGB555)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_RGB565)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_RGB8)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_Y216)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_v410)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_Y41P)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_Y41T)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_Y42T)
|
|
|| IsEqualGUID(guid, &MFVideoFormat_ABGR32);
|
|
}
|
|
|
|
static BOOL is_sample_copier_available_type(IMFMediaType *type)
|
|
{
|
|
GUID major = { 0 };
|
|
UINT32 count;
|
|
HRESULT hr;
|
|
|
|
hr = IMFMediaType_GetMajorType(type, &major);
|
|
ok(hr == S_OK, "Failed to get major type, hr %#lx.\n", hr);
|
|
|
|
hr = IMFMediaType_GetCount(type, &count);
|
|
ok(hr == S_OK, "Failed to get attribute count, hr %#lx.\n", hr);
|
|
ok(count == 1, "Unexpected attribute count %u.\n", count);
|
|
|
|
return IsEqualGUID(&major, &MFMediaType_Video) || IsEqualGUID(&major, &MFMediaType_Audio);
|
|
}
|
|
|
|
static void test_sample_copier(void)
|
|
{
|
|
static const struct attribute_desc expect_transform_attributes[] =
|
|
{
|
|
ATTR_UINT32(MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, 1),
|
|
{0},
|
|
};
|
|
const MFT_OUTPUT_STREAM_INFO initial_output_info = {0}, output_info = {.cbSize = 16 * 16};
|
|
const MFT_INPUT_STREAM_INFO initial_input_info = {0}, input_info = {.cbSize = 16 * 16};
|
|
IMFMediaType *mediatype, *mediatype2;
|
|
IMFSample *sample, *client_sample;
|
|
IMFMediaBuffer *media_buffer;
|
|
MFT_INPUT_STREAM_INFO info;
|
|
DWORD flags, output_status;
|
|
IMFTransform *copier;
|
|
HRESULT hr;
|
|
LONG ref;
|
|
|
|
if (!pMFCreateSampleCopierMFT)
|
|
{
|
|
win_skip("MFCreateSampleCopierMFT() is not available.\n");
|
|
return;
|
|
}
|
|
|
|
winetest_push_context("copier");
|
|
|
|
hr = pMFCreateSampleCopierMFT(&copier);
|
|
ok(hr == S_OK, "Failed to create sample copier, hr %#lx.\n", hr);
|
|
|
|
check_interface(copier, &IID_IMFTransform, TRUE);
|
|
check_interface(copier, &IID_IMediaObject, FALSE);
|
|
check_interface(copier, &IID_IPropertyStore, FALSE);
|
|
check_interface(copier, &IID_IPropertyBag, FALSE);
|
|
|
|
check_mft_optional_methods(copier, 1);
|
|
check_mft_get_attributes(copier, expect_transform_attributes, FALSE);
|
|
|
|
/* Available types. */
|
|
hr = IMFTransform_GetInputAvailableType(copier, 0, 0, &mediatype);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
ok(is_sample_copier_available_type(mediatype), "Unexpected type.\n");
|
|
IMFMediaType_Release(mediatype);
|
|
|
|
hr = IMFTransform_GetInputAvailableType(copier, 0, 1, &mediatype);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
ok(is_sample_copier_available_type(mediatype), "Unexpected type.\n");
|
|
IMFMediaType_Release(mediatype);
|
|
|
|
hr = IMFTransform_GetInputAvailableType(copier, 0, 2, &mediatype);
|
|
ok(hr == MF_E_NO_MORE_TYPES, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_GetInputAvailableType(copier, 1, 0, &mediatype);
|
|
ok(hr == MF_E_INVALIDSTREAMNUMBER, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_GetOutputAvailableType(copier, 0, 0, &mediatype);
|
|
ok(hr == MF_E_NO_MORE_TYPES, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_GetOutputAvailableType(copier, 1, 0, &mediatype);
|
|
ok(hr == MF_E_INVALIDSTREAMNUMBER, "Unexpected hr %#lx.\n", hr);
|
|
|
|
check_mft_get_input_current_type(copier, NULL);
|
|
check_mft_get_output_current_type(copier, NULL);
|
|
|
|
hr = MFCreateSample(&sample);
|
|
ok(hr == S_OK, "Failed to create a sample, hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_ProcessInput(copier, 0, sample, 0);
|
|
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = MFCreateMediaType(&mediatype);
|
|
ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_SetOutputType(copier, 0, mediatype, 0);
|
|
ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFMediaType_SetGUID(mediatype, &MF_MT_MAJOR_TYPE, &MFMediaType_Video);
|
|
ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr);
|
|
|
|
hr = IMFMediaType_SetGUID(mediatype, &MF_MT_SUBTYPE, &MFVideoFormat_RGB8);
|
|
ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr);
|
|
|
|
hr = IMFMediaType_SetUINT64(mediatype, &MF_MT_FRAME_SIZE, ((UINT64)16) << 32 | 16);
|
|
ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr);
|
|
|
|
check_mft_get_input_stream_info(copier, S_OK, &initial_input_info);
|
|
check_mft_get_output_stream_info(copier, S_OK, &initial_output_info);
|
|
|
|
hr = IMFTransform_SetOutputType(copier, 0, mediatype, 0);
|
|
ok(hr == S_OK, "Failed to set input type, hr %#lx.\n", hr);
|
|
|
|
memset(&info, 0xcd, sizeof(info));
|
|
hr = IMFTransform_GetInputStreamInfo(copier, 0, &info);
|
|
ok(hr == S_OK, "GetInputStreamInfo returned %#lx\n", hr);
|
|
check_member(info, initial_input_info, "%I64d", hnsMaxLatency);
|
|
check_member(info, initial_input_info, "%#lx", dwFlags);
|
|
todo_wine
|
|
check_member(info, initial_input_info, "%#lx", cbSize);
|
|
check_member(info, initial_input_info, "%#lx", cbMaxLookahead);
|
|
check_member(info, initial_input_info, "%#lx", cbAlignment);
|
|
check_mft_get_output_stream_info(copier, S_OK, &output_info);
|
|
|
|
hr = IMFTransform_GetOutputCurrentType(copier, 0, &mediatype2);
|
|
ok(hr == S_OK, "Failed to get current type, hr %#lx.\n", hr);
|
|
IMFMediaType_Release(mediatype2);
|
|
|
|
check_mft_get_input_current_type(copier, NULL);
|
|
|
|
hr = IMFTransform_GetInputStatus(copier, 0, &flags);
|
|
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#lx.\n", hr);
|
|
|
|
/* Setting input type resets output type. */
|
|
hr = IMFTransform_GetOutputCurrentType(copier, 0, &mediatype2);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
IMFMediaType_Release(mediatype2);
|
|
|
|
hr = IMFTransform_SetInputType(copier, 0, mediatype, 0);
|
|
ok(hr == S_OK, "Failed to set input type, hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_GetOutputCurrentType(copier, 0, &mediatype2);
|
|
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_GetInputAvailableType(copier, 0, 1, &mediatype2);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
ok(is_sample_copier_available_type(mediatype2), "Unexpected type.\n");
|
|
IMFMediaType_Release(mediatype2);
|
|
|
|
check_mft_get_input_stream_info(copier, S_OK, &input_info);
|
|
check_mft_get_output_stream_info(copier, S_OK, &output_info);
|
|
|
|
hr = IMFTransform_GetOutputAvailableType(copier, 0, 0, &mediatype2);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
hr = IMFMediaType_IsEqual(mediatype2, mediatype, &flags);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
IMFMediaType_Release(mediatype2);
|
|
|
|
hr = IMFTransform_GetInputStatus(copier, 0, &flags);
|
|
ok(hr == S_OK, "Failed to get input status, hr %#lx.\n", hr);
|
|
ok(flags == MFT_INPUT_STATUS_ACCEPT_DATA, "Unexpected flags %#lx.\n", flags);
|
|
|
|
hr = IMFTransform_GetInputCurrentType(copier, 0, &mediatype2);
|
|
ok(hr == S_OK, "Failed to get current type, hr %#lx.\n", hr);
|
|
IMFMediaType_Release(mediatype2);
|
|
|
|
hr = IMFTransform_GetOutputStatus(copier, &flags);
|
|
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_SetOutputType(copier, 0, mediatype, 0);
|
|
ok(hr == S_OK, "Failed to set output type, hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_GetOutputStatus(copier, &flags);
|
|
ok(hr == S_OK, "Failed to get output status, hr %#lx.\n", hr);
|
|
ok(!flags, "Unexpected flags %#lx.\n", flags);
|
|
|
|
/* Pushing samples. */
|
|
hr = MFCreateAlignedMemoryBuffer(output_info.cbSize, output_info.cbAlignment, &media_buffer);
|
|
ok(hr == S_OK, "Failed to create media buffer, hr %#lx.\n", hr);
|
|
|
|
hr = IMFSample_AddBuffer(sample, media_buffer);
|
|
ok(hr == S_OK, "Failed to add a buffer, hr %#lx.\n", hr);
|
|
IMFMediaBuffer_Release(media_buffer);
|
|
|
|
EXPECT_REF(sample, 1);
|
|
hr = IMFTransform_ProcessInput(copier, 0, sample, 0);
|
|
ok(hr == S_OK, "Failed to process input, hr %#lx.\n", hr);
|
|
EXPECT_REF(sample, 2);
|
|
|
|
hr = IMFTransform_GetInputStatus(copier, 0, &flags);
|
|
ok(hr == S_OK, "Failed to get input status, hr %#lx.\n", hr);
|
|
ok(!flags, "Unexpected flags %#lx.\n", flags);
|
|
|
|
hr = IMFTransform_GetOutputStatus(copier, &flags);
|
|
ok(hr == S_OK, "Failed to get output status, hr %#lx.\n", hr);
|
|
ok(flags == MFT_OUTPUT_STATUS_SAMPLE_READY, "Unexpected flags %#lx.\n", flags);
|
|
|
|
hr = IMFTransform_ProcessInput(copier, 0, sample, 0);
|
|
ok(hr == MF_E_NOTACCEPTING, "Unexpected hr %#lx.\n", hr);
|
|
|
|
check_mft_get_input_stream_info(copier, S_OK, &input_info);
|
|
check_mft_get_output_stream_info(copier, S_OK, &output_info);
|
|
|
|
hr = MFCreateAlignedMemoryBuffer(output_info.cbSize, output_info.cbAlignment, &media_buffer);
|
|
ok(hr == S_OK, "Failed to create media buffer, hr %#lx.\n", hr);
|
|
|
|
hr = MFCreateSample(&client_sample);
|
|
ok(hr == S_OK, "Failed to create a sample, hr %#lx.\n", hr);
|
|
|
|
hr = IMFSample_AddBuffer(client_sample, media_buffer);
|
|
ok(hr == S_OK, "Failed to add a buffer, hr %#lx.\n", hr);
|
|
IMFMediaBuffer_Release(media_buffer);
|
|
|
|
hr = check_mft_process_output(copier, client_sample, &output_status);
|
|
ok(hr == S_OK, "Failed to get output, hr %#lx.\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
EXPECT_REF(sample, 1);
|
|
|
|
hr = check_mft_process_output(copier, client_sample, &output_status);
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "Failed to get output, hr %#lx.\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
|
|
/* Flushing. */
|
|
hr = IMFTransform_ProcessInput(copier, 0, sample, 0);
|
|
ok(hr == S_OK, "Failed to process input, hr %#lx.\n", hr);
|
|
EXPECT_REF(sample, 2);
|
|
|
|
hr = IMFTransform_ProcessMessage(copier, MFT_MESSAGE_COMMAND_FLUSH, 0);
|
|
ok(hr == S_OK, "Failed to flush, hr %#lx.\n", hr);
|
|
|
|
ref = IMFSample_Release(sample);
|
|
ok(ref == 0, "Release returned %ld\n", ref);
|
|
ref = IMFSample_Release(client_sample);
|
|
ok(ref == 0, "Release returned %ld\n", ref);
|
|
|
|
ref = IMFTransform_Release(copier);
|
|
ok(ref == 0, "Release returned %ld\n", ref);
|
|
ref = IMFMediaType_Release(mediatype);
|
|
ok(ref == 0, "Release returned %ld\n", ref);
|
|
|
|
winetest_pop_context();
|
|
}
|
|
|
|
struct sample_metadata
|
|
{
|
|
unsigned int flags;
|
|
LONGLONG duration;
|
|
LONGLONG time;
|
|
};
|
|
|
|
static void sample_copier_process(IMFTransform *copier, IMFMediaBuffer *input_buffer,
|
|
IMFMediaBuffer *output_buffer, const struct sample_metadata *md)
|
|
{
|
|
static const struct sample_metadata zero_md = { 0, ~0u, ~0u };
|
|
IMFSample *input_sample, *output_sample;
|
|
DWORD flags, output_status;
|
|
LONGLONG time;
|
|
HRESULT hr;
|
|
LONG ref;
|
|
|
|
hr = MFCreateSample(&input_sample);
|
|
ok(hr == S_OK, "Failed to create a sample, hr %#lx.\n", hr);
|
|
|
|
if (md)
|
|
{
|
|
hr = IMFSample_SetSampleFlags(input_sample, md->flags);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFSample_SetSampleTime(input_sample, md->time);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFSample_SetSampleDuration(input_sample, md->duration);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
}
|
|
|
|
hr = MFCreateSample(&output_sample);
|
|
ok(hr == S_OK, "Failed to create a sample, hr %#lx.\n", hr);
|
|
|
|
hr = IMFSample_SetSampleFlags(output_sample, ~0u);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFSample_SetSampleTime(output_sample, ~0u);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFSample_SetSampleDuration(output_sample, ~0u);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFSample_AddBuffer(input_sample, input_buffer);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFSample_AddBuffer(output_sample, output_buffer);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_ProcessInput(copier, 0, input_sample, 0);
|
|
ok(hr == S_OK, "Failed to process input, hr %#lx.\n", hr);
|
|
|
|
hr = check_mft_process_output(copier, output_sample, &output_status);
|
|
ok(hr == S_OK, "Failed to get output, hr %#lx.\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
|
|
if (!md) md = &zero_md;
|
|
|
|
hr = IMFSample_GetSampleFlags(output_sample, &flags);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
ok(md->flags == flags, "Unexpected flags.\n");
|
|
hr = IMFSample_GetSampleTime(output_sample, &time);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
ok(md->time == time, "Unexpected time.\n");
|
|
hr = IMFSample_GetSampleDuration(output_sample, &time);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
ok(md->duration == time, "Unexpected duration.\n");
|
|
|
|
ref = IMFSample_Release(input_sample);
|
|
ok(ref == 0, "Release returned %ld\n", ref);
|
|
ref = IMFSample_Release(output_sample);
|
|
ok(ref == 0, "Release returned %ld\n", ref);
|
|
}
|
|
|
|
static void test_sample_copier_output_processing(void)
|
|
{
|
|
IMFMediaBuffer *input_buffer, *output_buffer;
|
|
MFT_OUTPUT_STREAM_INFO output_info;
|
|
struct sample_metadata md;
|
|
IMFMediaType *mediatype;
|
|
IMFTransform *copier;
|
|
DWORD max_length;
|
|
HRESULT hr;
|
|
BYTE *ptr;
|
|
LONG ref;
|
|
|
|
if (!pMFCreateSampleCopierMFT)
|
|
return;
|
|
|
|
hr = pMFCreateSampleCopierMFT(&copier);
|
|
ok(hr == S_OK, "Failed to create sample copier, hr %#lx.\n", hr);
|
|
|
|
/* Configure for 16 x 16 of D3DFMT_X8R8G8B8. */
|
|
hr = MFCreateMediaType(&mediatype);
|
|
ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr);
|
|
|
|
hr = IMFMediaType_SetGUID(mediatype, &MF_MT_MAJOR_TYPE, &MFMediaType_Video);
|
|
ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr);
|
|
|
|
hr = IMFMediaType_SetGUID(mediatype, &MF_MT_SUBTYPE, &MFVideoFormat_RGB32);
|
|
ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr);
|
|
|
|
hr = IMFMediaType_SetUINT64(mediatype, &MF_MT_FRAME_SIZE, ((UINT64)16) << 32 | 16);
|
|
ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_SetInputType(copier, 0, mediatype, 0);
|
|
ok(hr == S_OK, "Failed to set input type, hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_SetOutputType(copier, 0, mediatype, 0);
|
|
ok(hr == S_OK, "Failed to set input type, hr %#lx.\n", hr);
|
|
|
|
/* Source and destination are linear buffers, destination is twice as large. */
|
|
hr = IMFTransform_GetOutputStreamInfo(copier, 0, &output_info);
|
|
ok(hr == S_OK, "Failed to get output info, hr %#lx.\n", hr);
|
|
|
|
hr = MFCreateAlignedMemoryBuffer(output_info.cbSize, output_info.cbAlignment, &output_buffer);
|
|
ok(hr == S_OK, "Failed to create media buffer, hr %#lx.\n", hr);
|
|
|
|
hr = IMFMediaBuffer_Lock(output_buffer, &ptr, &max_length, NULL);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
memset(ptr, 0xcc, max_length);
|
|
hr = IMFMediaBuffer_Unlock(output_buffer);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = MFCreateAlignedMemoryBuffer(output_info.cbSize, output_info.cbAlignment, &input_buffer);
|
|
ok(hr == S_OK, "Failed to create media buffer, hr %#lx.\n", hr);
|
|
|
|
hr = IMFMediaBuffer_Lock(input_buffer, &ptr, &max_length, NULL);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
memset(ptr, 0xaa, max_length);
|
|
hr = IMFMediaBuffer_Unlock(input_buffer);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
hr = IMFMediaBuffer_SetCurrentLength(input_buffer, 4);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
|
|
sample_copier_process(copier, input_buffer, output_buffer, NULL);
|
|
|
|
hr = IMFMediaBuffer_Lock(output_buffer, &ptr, &max_length, NULL);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
ok(ptr[0] == 0xaa && ptr[4] == 0xcc, "Unexpected buffer contents.\n");
|
|
|
|
hr = IMFMediaBuffer_Unlock(output_buffer);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
|
|
md.flags = 123;
|
|
md.time = 10;
|
|
md.duration = 2;
|
|
sample_copier_process(copier, input_buffer, output_buffer, &md);
|
|
|
|
ref = IMFMediaBuffer_Release(input_buffer);
|
|
ok(ref == 0, "Release returned %ld\n", ref);
|
|
ref = IMFMediaBuffer_Release(output_buffer);
|
|
ok(ref == 0, "Release returned %ld\n", ref);
|
|
|
|
ref = IMFTransform_Release(copier);
|
|
ok(ref == 0, "Release returned %ld\n", ref);
|
|
ref = IMFMediaType_Release(mediatype);
|
|
ok(ref == 0, "Release returned %ld\n", ref);
|
|
}
|
|
|
|
static IMFSample *create_sample(const BYTE *data, ULONG size)
|
|
{
|
|
IMFMediaBuffer *media_buffer;
|
|
IMFSample *sample;
|
|
DWORD length;
|
|
BYTE *buffer;
|
|
HRESULT hr;
|
|
ULONG ret;
|
|
|
|
hr = MFCreateSample(&sample);
|
|
ok(hr == S_OK, "MFCreateSample returned %#lx\n", hr);
|
|
hr = MFCreateMemoryBuffer(size, &media_buffer);
|
|
ok(hr == S_OK, "MFCreateMemoryBuffer returned %#lx\n", hr);
|
|
hr = IMFMediaBuffer_Lock(media_buffer, &buffer, NULL, &length);
|
|
ok(hr == S_OK, "Lock returned %#lx\n", hr);
|
|
ok(length == 0, "got length %lu\n", length);
|
|
if (!data) memset(buffer, 0xcd, size);
|
|
else memcpy(buffer, data, size);
|
|
hr = IMFMediaBuffer_Unlock(media_buffer);
|
|
ok(hr == S_OK, "Unlock returned %#lx\n", hr);
|
|
hr = IMFMediaBuffer_SetCurrentLength(media_buffer, data ? size : 0);
|
|
ok(hr == S_OK, "SetCurrentLength returned %#lx\n", hr);
|
|
hr = IMFSample_AddBuffer(sample, media_buffer);
|
|
ok(hr == S_OK, "AddBuffer returned %#lx\n", hr);
|
|
ret = IMFMediaBuffer_Release(media_buffer);
|
|
ok(ret == 1, "Release returned %lu\n", ret);
|
|
|
|
return sample;
|
|
}
|
|
|
|
static void test_aac_encoder(void)
|
|
{
|
|
const GUID *const class_id = &CLSID_AACMFTEncoder;
|
|
const struct transform_info expect_mft_info =
|
|
{
|
|
.name = L"Microsoft AAC Audio Encoder MFT",
|
|
.major_type = &MFMediaType_Audio,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MFAudioFormat_PCM},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MFAudioFormat_AAC},
|
|
},
|
|
};
|
|
|
|
static const struct attribute_desc input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100, .required = TRUE),
|
|
{0},
|
|
};
|
|
const struct attribute_desc output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_AAC, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 12000, .required = TRUE),
|
|
{0},
|
|
};
|
|
|
|
static const struct attribute_desc expect_input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_AM_FORMAT_TYPE, FORMAT_WaveFormatEx),
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 2),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 44100 * 2),
|
|
ATTR_UINT32(MF_MT_AVG_BITRATE, 44100 * 2 * 8),
|
|
ATTR_UINT32(MF_MT_COMPRESSED, 0),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1),
|
|
{0},
|
|
};
|
|
const struct attribute_desc expect_output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_AM_FORMAT_TYPE, FORMAT_WaveFormatEx),
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_AAC),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 1),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 12000),
|
|
ATTR_UINT32(MF_MT_AVG_BITRATE, 96000),
|
|
ATTR_UINT32(MF_MT_COMPRESSED, 1),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 0),
|
|
ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1),
|
|
ATTR_UINT32(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 41),
|
|
ATTR_UINT32(MF_MT_AAC_PAYLOAD_TYPE, 0),
|
|
ATTR_BLOB(MF_MT_USER_DATA, test_aac_codec_data, sizeof(test_aac_codec_data)),
|
|
{0},
|
|
};
|
|
const MFT_OUTPUT_STREAM_INFO initial_output_info = {0}, output_info = {.cbSize = 0x600};
|
|
const MFT_INPUT_STREAM_INFO input_info = {0};
|
|
|
|
const struct buffer_desc output_buffer_desc[] =
|
|
{
|
|
{.length = -1 /* variable */},
|
|
};
|
|
const struct attribute_desc output_sample_attributes[] =
|
|
{
|
|
ATTR_UINT32(MFSampleExtension_CleanPoint, 1),
|
|
{0},
|
|
};
|
|
const struct sample_desc output_sample_desc[] =
|
|
{
|
|
{
|
|
.repeat_count = 88,
|
|
.attributes = output_sample_attributes,
|
|
.sample_time = 0, .sample_duration = 113823,
|
|
.buffer_count = 1, .buffers = output_buffer_desc,
|
|
},
|
|
};
|
|
|
|
MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Audio, MFAudioFormat_AAC};
|
|
MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Audio, MFAudioFormat_PCM};
|
|
IMFSample *input_sample, *output_sample;
|
|
IMFCollection *output_samples;
|
|
ULONG i, ret, audio_data_len;
|
|
DWORD length, output_status;
|
|
IMFTransform *transform;
|
|
const BYTE *audio_data;
|
|
HRESULT hr;
|
|
LONG ref;
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr);
|
|
|
|
winetest_push_context("aacenc");
|
|
|
|
if (!check_mft_enum(MFT_CATEGORY_AUDIO_ENCODER, &input_type, &output_type, class_id))
|
|
goto failed;
|
|
check_mft_get_info(class_id, &expect_mft_info);
|
|
|
|
if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER,
|
|
&IID_IMFTransform, (void **)&transform)))
|
|
goto failed;
|
|
|
|
check_interface(transform, &IID_IMFTransform, TRUE);
|
|
check_interface(transform, &IID_IMediaObject, FALSE);
|
|
check_interface(transform, &IID_IPropertyStore, FALSE);
|
|
check_interface(transform, &IID_IPropertyBag, FALSE);
|
|
|
|
check_mft_optional_methods(transform, 1);
|
|
check_mft_get_attributes(transform, NULL, FALSE);
|
|
check_mft_get_input_stream_info(transform, S_OK, &input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, &initial_output_info);
|
|
|
|
check_mft_set_output_type_required(transform, output_type_desc);
|
|
check_mft_set_output_type(transform, output_type_desc, S_OK);
|
|
check_mft_get_output_current_type(transform, expect_output_type_desc);
|
|
|
|
check_mft_set_input_type_required(transform, input_type_desc);
|
|
check_mft_set_input_type(transform, input_type_desc);
|
|
check_mft_get_input_current_type(transform, expect_input_type_desc);
|
|
|
|
check_mft_get_input_stream_info(transform, S_OK, &input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, &output_info);
|
|
|
|
if (!has_video_processor)
|
|
{
|
|
win_skip("Skipping AAC encoder tests on Win7\n");
|
|
goto done;
|
|
}
|
|
|
|
load_resource(L"audiodata.bin", &audio_data, &audio_data_len);
|
|
ok(audio_data_len == 179928, "got length %lu\n", audio_data_len);
|
|
|
|
input_sample = create_sample(audio_data, audio_data_len);
|
|
hr = IMFSample_SetSampleTime(input_sample, 0);
|
|
ok(hr == S_OK, "SetSampleTime returned %#lx\n", hr);
|
|
hr = IMFSample_SetSampleDuration(input_sample, 10000000);
|
|
ok(hr == S_OK, "SetSampleDuration returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0);
|
|
ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr);
|
|
ref = IMFSample_Release(input_sample);
|
|
ok(ref <= 1, "Release returned %ld\n", ref);
|
|
|
|
hr = MFCreateCollection(&output_samples);
|
|
ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr);
|
|
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
for (i = 0; SUCCEEDED(hr = check_mft_process_output(transform, output_sample, &output_status)); i++)
|
|
{
|
|
winetest_push_context("%lu", i);
|
|
ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr);
|
|
hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample);
|
|
ok(hr == S_OK, "AddElement returned %#lx\n", hr);
|
|
ref = IMFSample_Release(output_sample);
|
|
ok(ref == 1, "Release returned %ld\n", ref);
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
ok(i == 88, "got %lu output samples\n", i);
|
|
|
|
ret = check_mf_sample_collection(output_samples, output_sample_desc, L"aacencdata.bin");
|
|
ok(ret == 0, "got %lu%% diff\n", ret);
|
|
IMFCollection_Release(output_samples);
|
|
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
hr = IMFSample_GetTotalLength(output_sample, &length);
|
|
ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr);
|
|
ok(length == 0, "got length %lu\n", length);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
done:
|
|
ret = IMFTransform_Release(transform);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
failed:
|
|
winetest_pop_context();
|
|
CoUninitialize();
|
|
}
|
|
|
|
static void test_aac_decoder_subtype(const struct attribute_desc *input_type_desc)
|
|
{
|
|
const GUID *const class_id = &CLSID_MSAACDecMFT;
|
|
const struct transform_info expect_mft_info =
|
|
{
|
|
.name = L"Microsoft AAC Audio Decoder MFT",
|
|
.major_type = &MFMediaType_Audio,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MFAudioFormat_AAC},
|
|
{.subtype = &MFAudioFormat_RAW_AAC1},
|
|
{.subtype = &MFAudioFormat_ADTS, .broken = TRUE /* <= w8 */},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MFAudioFormat_Float},
|
|
{.subtype = &MFAudioFormat_PCM},
|
|
},
|
|
};
|
|
|
|
static const struct attribute_desc expect_input_attributes[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 32),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 6),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 24),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 48000),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 1152000),
|
|
{0},
|
|
};
|
|
static const media_type_desc expect_available_inputs[] =
|
|
{
|
|
{
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_AAC),
|
|
ATTR_UINT32(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 0),
|
|
ATTR_UINT32(MF_MT_AAC_PAYLOAD_TYPE, 0),
|
|
/* MF_MT_USER_DATA with some AAC codec data */
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_RAW_AAC1),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_AAC),
|
|
ATTR_UINT32(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 0),
|
|
ATTR_UINT32(MF_MT_AAC_PAYLOAD_TYPE, 1),
|
|
/* MF_MT_USER_DATA with some AAC codec data */
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_AAC),
|
|
ATTR_UINT32(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 0),
|
|
ATTR_UINT32(MF_MT_AAC_PAYLOAD_TYPE, 3),
|
|
/* MF_MT_USER_DATA with some AAC codec data */
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_ADTS),
|
|
},
|
|
};
|
|
static const struct attribute_desc expect_output_attributes[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
{0},
|
|
};
|
|
static const media_type_desc expect_available_outputs[] =
|
|
{
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 32),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 4 * 44100),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 2),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 2 * 44100),
|
|
},
|
|
};
|
|
const struct attribute_desc expect_transform_attributes[] =
|
|
{
|
|
ATTR_UINT32(MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, !has_video_processor /* 1 on W7 */, .todo = TRUE),
|
|
/* more AAC decoder specific attributes from CODECAPI */
|
|
{0},
|
|
};
|
|
static const struct attribute_desc output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100, .required = TRUE),
|
|
{0},
|
|
};
|
|
const MFT_OUTPUT_STREAM_INFO output_info =
|
|
{
|
|
.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES,
|
|
.cbSize = 0xc000,
|
|
};
|
|
const MFT_INPUT_STREAM_INFO input_info =
|
|
{
|
|
.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER |
|
|
MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE | MFT_INPUT_STREAM_HOLDS_BUFFERS,
|
|
};
|
|
|
|
const struct buffer_desc output_buffer_desc[] =
|
|
{
|
|
{.length = 0x800},
|
|
};
|
|
const struct attribute_desc output_sample_attributes[] =
|
|
{
|
|
ATTR_UINT32(MFSampleExtension_CleanPoint, 1),
|
|
{0},
|
|
};
|
|
const struct sample_desc output_sample_desc[] =
|
|
{
|
|
{
|
|
.attributes = output_sample_attributes + (has_video_processor ? 0 : 1) /* MFSampleExtension_CleanPoint missing on Win7 */,
|
|
.sample_time = 0, .sample_duration = 232200,
|
|
.buffer_count = 1, .buffers = output_buffer_desc,
|
|
},
|
|
};
|
|
|
|
MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Audio, MFAudioFormat_Float};
|
|
MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Audio, MFAudioFormat_AAC};
|
|
IMFSample *input_sample, *output_sample;
|
|
ULONG i, ret, ref, aacenc_data_len;
|
|
IMFCollection *output_samples;
|
|
DWORD length, output_status;
|
|
IMFMediaType *media_type;
|
|
IMFTransform *transform;
|
|
const BYTE *aacenc_data;
|
|
DWORD flags;
|
|
HRESULT hr;
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr);
|
|
|
|
winetest_push_context("aacdec");
|
|
|
|
if (!check_mft_enum(MFT_CATEGORY_AUDIO_DECODER, &input_type, &output_type, class_id))
|
|
goto failed;
|
|
check_mft_get_info(class_id, &expect_mft_info);
|
|
|
|
if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER,
|
|
&IID_IMFTransform, (void **)&transform)))
|
|
goto failed;
|
|
|
|
check_interface(transform, &IID_IMFTransform, TRUE);
|
|
check_interface(transform, &IID_IMediaObject, FALSE);
|
|
check_interface(transform, &IID_IPropertyStore, FALSE);
|
|
check_interface(transform, &IID_IPropertyBag, FALSE);
|
|
|
|
check_mft_optional_methods(transform, 1);
|
|
check_mft_get_attributes(transform, expect_transform_attributes, FALSE);
|
|
check_mft_get_input_stream_info(transform, S_OK, &input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, &output_info);
|
|
|
|
hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type);
|
|
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "GetOutputAvailableType returned %#lx\n", hr);
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetInputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("in %lu", i);
|
|
ok(hr == S_OK, "GetInputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, expect_input_attributes, -1);
|
|
check_media_type(media_type, expect_available_inputs[i], -1);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret <= 1, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetInputAvailableType returned %#lx\n", hr);
|
|
ok(i == ARRAY_SIZE(expect_available_inputs)
|
|
|| broken(i == 2) /* w7 */ || broken(i == 4) /* w8 */,
|
|
"%lu input media types\n", i);
|
|
|
|
/* setting output media type first doesn't work */
|
|
check_mft_set_output_type(transform, output_type_desc, MF_E_TRANSFORM_TYPE_NOT_SET);
|
|
check_mft_get_output_current_type(transform, NULL);
|
|
|
|
check_mft_set_input_type_required(transform, input_type_desc);
|
|
check_mft_set_input_type(transform, input_type_desc);
|
|
check_mft_get_input_current_type(transform, input_type_desc);
|
|
|
|
/* check new output media types */
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("out %lu", i);
|
|
ok(hr == S_OK, "GetOutputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, expect_output_attributes, -1);
|
|
check_media_type(media_type, expect_available_outputs[i], -1);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret <= 1, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx\n", hr);
|
|
ok(i == ARRAY_SIZE(expect_available_outputs), "%lu input media types\n", i);
|
|
|
|
check_mft_set_output_type_required(transform, output_type_desc);
|
|
check_mft_set_output_type(transform, output_type_desc, S_OK);
|
|
check_mft_get_output_current_type(transform, output_type_desc);
|
|
|
|
check_mft_get_input_stream_info(transform, S_OK, &input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, &output_info);
|
|
|
|
load_resource(L"aacencdata.bin", &aacenc_data, &aacenc_data_len);
|
|
ok(aacenc_data_len == 24861, "got length %lu\n", aacenc_data_len);
|
|
|
|
input_sample = create_sample(aacenc_data + sizeof(DWORD), *(DWORD *)aacenc_data);
|
|
|
|
flags = 0;
|
|
hr = IMFTransform_GetInputStatus(transform, 0, &flags);
|
|
ok(hr == S_OK, "Got %#lx\n", hr);
|
|
ok(flags == MFT_INPUT_STATUS_ACCEPT_DATA, "Got flags %#lx.\n", flags);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);
|
|
flags = 0xdeadbeef;
|
|
hr = IMFTransform_GetInputStatus(transform, 0, &flags);
|
|
ok(hr == S_OK, "Got %#lx\n", hr);
|
|
ok(!flags, "Got flags %#lx.\n", flags);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr);
|
|
flags = 0xdeadbeef;
|
|
hr = IMFTransform_GetInputStatus(transform, 0, &flags);
|
|
ok(hr == S_OK, "Got %#lx\n", hr);
|
|
ok(!flags, "Got flags %#lx.\n", flags);
|
|
|
|
/* As output_info.dwFlags doesn't have MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES
|
|
* IMFTransform_ProcessOutput needs a sample or returns MF_E_TRANSFORM_NEED_MORE_INPUT */
|
|
|
|
hr = check_mft_process_output(transform, NULL, &output_status);
|
|
ok(hr == E_INVALIDARG, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
flags = 0xdeadbeef;
|
|
hr = IMFTransform_GetInputStatus(transform, 0, &flags);
|
|
ok(hr == S_OK, "Got %#lx\n", hr);
|
|
ok(!flags, "Got flags %#lx.\n", flags);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr);
|
|
|
|
hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0);
|
|
ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr);
|
|
flags = 0xdeadbeef;
|
|
hr = IMFTransform_GetInputStatus(transform, 0, &flags);
|
|
ok(hr == S_OK, "Got %#lx\n", hr);
|
|
ok(!flags, "Got flags %#lx.\n", flags);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr);
|
|
|
|
hr = MFCreateCollection(&output_samples);
|
|
ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr);
|
|
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
for (i = 0; SUCCEEDED(hr = check_mft_process_output(transform, output_sample, &output_status)); i++)
|
|
{
|
|
winetest_push_context("%lu", i);
|
|
ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr);
|
|
hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample);
|
|
ok(hr == S_OK, "AddElement returned %#lx\n", hr);
|
|
ref = IMFSample_Release(output_sample);
|
|
ok(ref == 1, "Release returned %ld\n", ref);
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
|
|
flags = 0;
|
|
hr = IMFTransform_GetInputStatus(transform, 0, &flags);
|
|
ok(hr == S_OK, "Got %#lx\n", hr);
|
|
ok(flags == MFT_INPUT_STATUS_ACCEPT_DATA, "Got flags %#lx.\n", flags);
|
|
|
|
ok(output_status == MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE, "got output[0].dwStatus %#lx\n", output_status);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
ok(i == 1, "got %lu output samples\n", i);
|
|
|
|
ret = check_mf_sample_collection(output_samples, output_sample_desc, L"aacdecdata.bin");
|
|
todo_wine_if(ret <= 5)
|
|
ok(ret == 0, "got %lu%% diff\n", ret);
|
|
IMFCollection_Release(output_samples);
|
|
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE, "got output[0].dwStatus %#lx\n", output_status);
|
|
hr = IMFSample_GetTotalLength(output_sample, &length);
|
|
ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr);
|
|
ok(length == 0, "got length %lu\n", length);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
ret = IMFSample_Release(input_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
ret = IMFTransform_Release(transform);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
failed:
|
|
winetest_pop_context();
|
|
CoUninitialize();
|
|
}
|
|
|
|
static void test_aac_decoder_channels(const struct attribute_desc *input_type_desc)
|
|
{
|
|
static const struct attribute_desc expect_output_attributes[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
{0},
|
|
};
|
|
static const media_type_desc expect_available_outputs[] =
|
|
{
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 32),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16),
|
|
},
|
|
};
|
|
static const UINT32 expected_mask[7] =
|
|
{
|
|
0,
|
|
0,
|
|
0,
|
|
SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_CENTER,
|
|
KSAUDIO_SPEAKER_QUAD,
|
|
KSAUDIO_SPEAKER_QUAD | SPEAKER_FRONT_CENTER,
|
|
KSAUDIO_SPEAKER_5POINT1,
|
|
};
|
|
|
|
UINT32 value, num_channels, expected_chans, format_index, sample_size;
|
|
unsigned int num_channels_index = ~0u;
|
|
struct attribute_desc input_desc[64];
|
|
IMFTransform *transform;
|
|
IMFAttributes *attrs;
|
|
IMFMediaType *type;
|
|
BOOL many_channels;
|
|
ULONG i, ret;
|
|
HRESULT hr;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(input_desc); i++)
|
|
{
|
|
input_desc[i] = input_type_desc[i];
|
|
if (!input_desc[i].key)
|
|
break;
|
|
if (IsEqualGUID(input_desc[i].key, &MF_MT_AUDIO_NUM_CHANNELS))
|
|
num_channels_index = i;
|
|
}
|
|
|
|
ok(num_channels_index != ~0u, "Could not find MF_MT_AUDIO_NUM_CHANNELS.\n");
|
|
ok(i < ARRAY_SIZE(input_desc), "Too many attributes.\n");
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
winetest_push_context("aacdec channels");
|
|
|
|
if (FAILED(hr = CoCreateInstance(&CLSID_MSAACDecMFT, NULL, CLSCTX_INPROC_SERVER,
|
|
&IID_IMFTransform, (void **)&transform)))
|
|
{
|
|
win_skip("AAC decoder transform is not available.\n");
|
|
goto failed;
|
|
}
|
|
|
|
hr = MFCreateMediaType(&type);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
input_desc[num_channels_index].value.vt = VT_UI8;
|
|
input_desc[num_channels_index].value.ulVal = 1;
|
|
init_media_type(type, input_desc, -1);
|
|
hr = IMFTransform_SetInputType(transform, 0, type, 0);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
IMFMediaType_Release(type);
|
|
hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &type);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
hr = IMFAttributes_GetUINT32((IMFAttributes *)type, &MF_MT_AUDIO_NUM_CHANNELS, &value);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
ok(value == 2, "got %u.\n", value);
|
|
IMFMediaType_Release(type);
|
|
input_desc[num_channels_index].value.vt = VT_UI4;
|
|
|
|
for (num_channels = 0; num_channels < 16; ++num_channels)
|
|
{
|
|
many_channels = num_channels > 2;
|
|
winetest_push_context("chans %u", num_channels);
|
|
input_desc[num_channels_index].value.ulVal = num_channels;
|
|
|
|
hr = MFCreateMediaType(&type);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
init_media_type(type, input_desc, -1);
|
|
hr = IMFTransform_SetInputType(transform, 0, type, 0);
|
|
IMFMediaType_Release(type);
|
|
if (num_channels <= 6)
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
else
|
|
{
|
|
ok(hr == MF_E_INVALIDMEDIATYPE, "got %#lx.\n", hr);
|
|
winetest_pop_context();
|
|
continue;
|
|
}
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &type)))
|
|
{
|
|
winetest_push_context("out %lu", i);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
check_media_type(type, expect_output_attributes, -1);
|
|
format_index = i % 2;
|
|
sample_size = format_index ? 2 : 4;
|
|
check_media_type(type, expect_available_outputs[format_index], -1);
|
|
attrs = (IMFAttributes *)type;
|
|
|
|
hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_NUM_CHANNELS, &value);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
if (!num_channels || i >= ARRAY_SIZE(expect_available_outputs))
|
|
expected_chans = 2;
|
|
else
|
|
expected_chans = num_channels;
|
|
ok(value == expected_chans, "got %u, expected %u.\n", value, expected_chans);
|
|
|
|
hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &value);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
ok(value == sample_size * 44100 * expected_chans, "got %u, expected %u.\n",
|
|
value, sample_size * 44100 * expected_chans);
|
|
|
|
hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &value);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
ok(value == sample_size * expected_chans, "got %u, expected %u.\n", value, sample_size * expected_chans);
|
|
|
|
hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, &value);
|
|
if (many_channels && i < ARRAY_SIZE(expect_available_outputs))
|
|
{
|
|
ok(hr == MF_E_ATTRIBUTENOTFOUND, "got %#lx.\n", hr);
|
|
}
|
|
else
|
|
{
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
ok(value == 1, "got %u.\n", value);
|
|
}
|
|
|
|
value = 0xdeadbeef;
|
|
hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_CHANNEL_MASK, &value);
|
|
if (expected_chans <= 2)
|
|
{
|
|
ok(hr == MF_E_ATTRIBUTENOTFOUND, "got %#lx.\n", hr);
|
|
}
|
|
else
|
|
{
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
ok(value == expected_mask[expected_chans], "got %#x, expected %#x.\n",
|
|
value, expected_mask[expected_chans]);
|
|
}
|
|
|
|
ret = IMFMediaType_Release(type);
|
|
ok(ret <= 1, "got %lu.\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "got %#lx.\n", hr);
|
|
if (many_channels)
|
|
ok(i == ARRAY_SIZE(expect_available_outputs) * 2, "got %lu media types.\n", i);
|
|
else
|
|
ok(i == ARRAY_SIZE(expect_available_outputs), "got %lu media types.\n", i);
|
|
winetest_pop_context();
|
|
}
|
|
|
|
ret = IMFTransform_Release(transform);
|
|
ok(!ret, "got %lu.\n", ret);
|
|
|
|
failed:
|
|
winetest_pop_context();
|
|
CoUninitialize();
|
|
}
|
|
|
|
static void test_aac_decoder(void)
|
|
{
|
|
static const BYTE aac_raw_codec_data[] = {0x12, 0x08};
|
|
static const struct attribute_desc raw_aac_input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_RAW_AAC1, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1),
|
|
ATTR_BLOB(MF_MT_USER_DATA, aac_raw_codec_data, sizeof(aac_raw_codec_data), .required = TRUE),
|
|
{0},
|
|
};
|
|
static const struct attribute_desc aac_input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_AAC, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100, .required = TRUE),
|
|
ATTR_BLOB(MF_MT_USER_DATA, test_aac_codec_data, sizeof(test_aac_codec_data), .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 12000),
|
|
ATTR_UINT32(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 41),
|
|
ATTR_UINT32(MF_MT_AAC_PAYLOAD_TYPE, 0),
|
|
{0},
|
|
};
|
|
|
|
test_aac_decoder_subtype(aac_input_type_desc);
|
|
test_aac_decoder_subtype(raw_aac_input_type_desc);
|
|
|
|
test_aac_decoder_channels(aac_input_type_desc);
|
|
test_aac_decoder_channels(raw_aac_input_type_desc);
|
|
}
|
|
|
|
static const BYTE wma_codec_data[10] = {0, 0x44, 0, 0, 0x17, 0, 0, 0, 0, 0};
|
|
static const ULONG wmaenc_block_size = 1487;
|
|
static const ULONG wmadec_block_size = 0x2000;
|
|
|
|
static void test_wma_encoder(void)
|
|
{
|
|
const GUID *const class_id = &CLSID_CWMAEncMediaObject;
|
|
const struct transform_info expect_mft_info =
|
|
{
|
|
.name = L"WMAudio Encoder MFT",
|
|
.major_type = &MFMediaType_Audio,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MFAudioFormat_PCM},
|
|
{.subtype = &MFAudioFormat_Float},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MFAudioFormat_WMAudioV8},
|
|
{.subtype = &MFAudioFormat_WMAudioV9},
|
|
{.subtype = &MFAudioFormat_WMAudio_Lossless},
|
|
},
|
|
};
|
|
const struct transform_info expect_dmo_info =
|
|
{
|
|
.name = L"WMAudio Encoder DMO",
|
|
.major_type = &MEDIATYPE_Audio,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MEDIASUBTYPE_PCM},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MEDIASUBTYPE_WMAUDIO2},
|
|
{.subtype = &MEDIASUBTYPE_WMAUDIO3},
|
|
{.subtype = &MEDIASUBTYPE_WMAUDIO_LOSSLESS},
|
|
},
|
|
};
|
|
|
|
static const struct attribute_desc input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 32, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 2 * (32 / 8), .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 2 * (32 / 8) * 22050, .required = TRUE),
|
|
{0},
|
|
};
|
|
const struct attribute_desc output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_WMAudioV8, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 4003, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, wmaenc_block_size, .required = TRUE),
|
|
ATTR_BLOB(MF_MT_USER_DATA, wma_codec_data, sizeof(wma_codec_data), .required = TRUE),
|
|
{0},
|
|
};
|
|
static const struct attribute_desc expect_input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 32),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 8),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 22050 * 8),
|
|
ATTR_UINT32(MF_MT_AUDIO_CHANNEL_MASK, 3),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
{0},
|
|
};
|
|
const struct attribute_desc expect_output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_WMAudioV8),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 4003),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, wmaenc_block_size),
|
|
ATTR_BLOB(MF_MT_USER_DATA, wma_codec_data, sizeof(wma_codec_data)),
|
|
ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1),
|
|
{0},
|
|
};
|
|
const MFT_OUTPUT_STREAM_INFO output_info =
|
|
{
|
|
.cbSize = wmaenc_block_size,
|
|
.cbAlignment = 1,
|
|
};
|
|
const MFT_INPUT_STREAM_INFO input_info =
|
|
{
|
|
.hnsMaxLatency = 19969161,
|
|
.cbSize = 8,
|
|
.cbAlignment = 1,
|
|
};
|
|
|
|
const struct buffer_desc output_buffer_desc[] =
|
|
{
|
|
{.length = wmaenc_block_size},
|
|
};
|
|
const struct attribute_desc output_sample_attributes[] =
|
|
{
|
|
ATTR_UINT32(mft_output_sample_incomplete, 1),
|
|
ATTR_UINT32(MFSampleExtension_CleanPoint, 1),
|
|
{0},
|
|
};
|
|
const struct sample_desc output_sample_desc[] =
|
|
{
|
|
{
|
|
.attributes = output_sample_attributes,
|
|
.sample_time = 0, .sample_duration = 3250794,
|
|
.buffer_count = 1, .buffers = output_buffer_desc,
|
|
},
|
|
{
|
|
.attributes = output_sample_attributes,
|
|
.sample_time = 3250794, .sample_duration = 3715193,
|
|
.buffer_count = 1, .buffers = output_buffer_desc,
|
|
},
|
|
{
|
|
.attributes = output_sample_attributes,
|
|
.sample_time = 6965986, .sample_duration = 3366893,
|
|
.buffer_count = 1, .buffers = output_buffer_desc,
|
|
},
|
|
};
|
|
|
|
MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Audio, MFAudioFormat_WMAudioV8};
|
|
MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Audio, MFAudioFormat_Float};
|
|
IMFSample *input_sample, *output_sample;
|
|
IMFCollection *output_samples;
|
|
DWORD length, output_status;
|
|
IMFMediaType *media_type;
|
|
IMFTransform *transform;
|
|
const BYTE *audio_data;
|
|
ULONG audio_data_len;
|
|
ULONG i, ret;
|
|
HRESULT hr;
|
|
LONG ref;
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr);
|
|
|
|
winetest_push_context("wmaenc");
|
|
|
|
if (!check_mft_enum(MFT_CATEGORY_AUDIO_ENCODER, &input_type, &output_type, class_id))
|
|
goto failed;
|
|
check_mft_get_info(class_id, &expect_mft_info);
|
|
check_dmo_get_info(class_id, &expect_dmo_info);
|
|
|
|
if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER,
|
|
&IID_IMFTransform, (void **)&transform)))
|
|
goto failed;
|
|
|
|
check_interface(transform, &IID_IMFTransform, TRUE);
|
|
check_interface(transform, &IID_IMediaObject, TRUE);
|
|
check_interface(transform, &IID_IPropertyStore, TRUE);
|
|
check_interface(transform, &IID_IPropertyBag, TRUE);
|
|
|
|
check_mft_optional_methods(transform, 1);
|
|
check_mft_get_attributes(transform, NULL, FALSE);
|
|
check_mft_get_input_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
|
|
check_mft_get_output_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
|
|
|
|
check_mft_set_input_type_required(transform, input_type_desc);
|
|
|
|
hr = MFCreateMediaType(&media_type);
|
|
ok(hr == S_OK, "MFCreateMediaType returned %#lx\n", hr);
|
|
init_media_type(media_type, input_type_desc, -1);
|
|
hr = IMFTransform_SetInputType(transform, 0, media_type, 0);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
check_mft_set_output_type_required(transform, output_type_desc);
|
|
check_mft_set_output_type(transform, output_type_desc, S_OK);
|
|
check_mft_get_output_current_type(transform, expect_output_type_desc);
|
|
|
|
check_mft_set_input_type_required(transform, input_type_desc);
|
|
check_mft_set_input_type(transform, input_type_desc);
|
|
check_mft_get_input_current_type(transform, expect_input_type_desc);
|
|
|
|
check_mft_get_input_stream_info(transform, S_OK, &input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, &output_info);
|
|
|
|
load_resource(L"audiodata.bin", &audio_data, &audio_data_len);
|
|
ok(audio_data_len == 179928, "got length %lu\n", audio_data_len);
|
|
|
|
input_sample = create_sample(audio_data, audio_data_len);
|
|
hr = IMFSample_SetSampleTime(input_sample, 0);
|
|
ok(hr == S_OK, "SetSampleTime returned %#lx\n", hr);
|
|
hr = IMFSample_SetSampleDuration(input_sample, 10000000);
|
|
ok(hr == S_OK, "SetSampleDuration returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0);
|
|
ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr);
|
|
ref = IMFSample_Release(input_sample);
|
|
ok(ref <= 1, "Release returned %ld\n", ref);
|
|
|
|
hr = MFCreateCollection(&output_samples);
|
|
ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr);
|
|
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
for (i = 0; SUCCEEDED(hr = check_mft_process_output(transform, output_sample, &output_status)); i++)
|
|
{
|
|
winetest_push_context("%lu", i);
|
|
ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == MFT_OUTPUT_DATA_BUFFER_INCOMPLETE, "got output[0].dwStatus %#lx\n", output_status);
|
|
hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample);
|
|
ok(hr == S_OK, "AddElement returned %#lx\n", hr);
|
|
ref = IMFSample_Release(output_sample);
|
|
ok(ref == 1, "Release returned %ld\n", ref);
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
ok(i == 3, "got %lu output samples\n", i);
|
|
|
|
ret = check_mf_sample_collection(output_samples, output_sample_desc, L"wmaencdata.bin");
|
|
ok(ret == 0, "got %lu%% diff\n", ret);
|
|
IMFCollection_Release(output_samples);
|
|
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
hr = IMFSample_GetTotalLength(output_sample, &length);
|
|
ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr);
|
|
ok(length == 0, "got length %lu\n", length);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
ret = IMFTransform_Release(transform);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
failed:
|
|
winetest_pop_context();
|
|
CoUninitialize();
|
|
}
|
|
|
|
static void test_wma_decoder(void)
|
|
{
|
|
const GUID *const class_id = &CLSID_CWMADecMediaObject;
|
|
const struct transform_info expect_mft_info =
|
|
{
|
|
.name = L"WMAudio Decoder MFT",
|
|
.major_type = &MFMediaType_Audio,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MEDIASUBTYPE_MSAUDIO1},
|
|
{.subtype = &MFAudioFormat_WMAudioV8},
|
|
{.subtype = &MFAudioFormat_WMAudioV9},
|
|
{.subtype = &MFAudioFormat_WMAudio_Lossless},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MFAudioFormat_PCM},
|
|
{.subtype = &MFAudioFormat_Float},
|
|
},
|
|
};
|
|
const struct transform_info expect_dmo_info =
|
|
{
|
|
.name = L"WMAudio Decoder DMO",
|
|
.major_type = &MEDIATYPE_Audio,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MEDIASUBTYPE_MSAUDIO1},
|
|
{.subtype = &MEDIASUBTYPE_WMAUDIO2},
|
|
{.subtype = &MEDIASUBTYPE_WMAUDIO3},
|
|
{.subtype = &MEDIASUBTYPE_WMAUDIO_LOSSLESS},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MEDIASUBTYPE_PCM},
|
|
{.subtype = &MEDIASUBTYPE_IEEE_FLOAT},
|
|
},
|
|
};
|
|
|
|
static const media_type_desc expect_available_inputs[] =
|
|
{
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MEDIASUBTYPE_MSAUDIO1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_WMAudioV8),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_WMAudioV9),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_WMAudio_Lossless),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
},
|
|
};
|
|
static const media_type_desc expect_available_outputs[] =
|
|
{
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 32),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 176400),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 8),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 88200),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1),
|
|
},
|
|
};
|
|
|
|
const struct attribute_desc input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_WMAudioV8, .required = TRUE),
|
|
ATTR_BLOB(MF_MT_USER_DATA, wma_codec_data, sizeof(wma_codec_data), .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, wmaenc_block_size, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 4003), /* not required by SetInputType, but needed for the transform to work */
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16),
|
|
{0},
|
|
};
|
|
static const struct attribute_desc output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 2 * (16 / 8), .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 2 * (16 / 8) * 22050, .required = TRUE),
|
|
{0},
|
|
};
|
|
const struct attribute_desc expect_input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_WMAudioV8),
|
|
ATTR_BLOB(MF_MT_USER_DATA, wma_codec_data, sizeof(wma_codec_data)),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, wmaenc_block_size),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 4003),
|
|
ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16),
|
|
{0},
|
|
};
|
|
static const struct attribute_desc expect_output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 22050 * 4),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4),
|
|
ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
{0},
|
|
};
|
|
const MFT_INPUT_STREAM_INFO input_info =
|
|
{
|
|
.cbSize = wmaenc_block_size,
|
|
.cbAlignment = 1,
|
|
};
|
|
const MFT_OUTPUT_STREAM_INFO output_info =
|
|
{
|
|
.cbSize = wmadec_block_size,
|
|
.cbAlignment = 1,
|
|
};
|
|
|
|
const struct buffer_desc output_buffer_desc[] =
|
|
{
|
|
{.length = wmadec_block_size, .compare = compare_pcm16},
|
|
{.length = wmadec_block_size / 2, .compare = compare_pcm16, .todo_length = TRUE},
|
|
};
|
|
const struct attribute_desc output_sample_attributes[] =
|
|
{
|
|
ATTR_UINT32(mft_output_sample_incomplete, 1),
|
|
ATTR_UINT32(MFSampleExtension_CleanPoint, 1),
|
|
{0},
|
|
};
|
|
const struct attribute_desc output_sample_attributes_todo[] =
|
|
{
|
|
ATTR_UINT32(mft_output_sample_incomplete, 1, .todo = TRUE),
|
|
ATTR_UINT32(MFSampleExtension_CleanPoint, 1),
|
|
{0},
|
|
};
|
|
struct sample_desc output_sample_desc[] =
|
|
{
|
|
{
|
|
.attributes = output_sample_attributes + 0,
|
|
.sample_time = 0, .sample_duration = 928798,
|
|
.buffer_count = 1, .buffers = output_buffer_desc + 0, .repeat_count = 1,
|
|
},
|
|
{
|
|
.attributes = output_sample_attributes + 0,
|
|
.sample_time = 1857596, .sample_duration = 928798,
|
|
.buffer_count = 1, .buffers = output_buffer_desc + 0,
|
|
},
|
|
{
|
|
.attributes = output_sample_attributes + 1, /* not MFT_OUTPUT_DATA_BUFFER_INCOMPLETE */
|
|
.sample_time = 2786394, .sample_duration = 464399, .todo_duration = 928798,
|
|
.buffer_count = 1, .buffers = output_buffer_desc + 1, .todo_length = TRUE,
|
|
},
|
|
};
|
|
|
|
MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Audio, MFAudioFormat_WMAudioV8};
|
|
MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Audio, MFAudioFormat_Float};
|
|
IUnknown *unknown, *tmp_unknown, outer = {&test_unk_vtbl};
|
|
IMFSample *input_sample, *output_sample;
|
|
IMFCollection *output_samples;
|
|
DWORD length, output_status;
|
|
IMediaObject *media_object;
|
|
IPropertyBag *property_bag;
|
|
IMFMediaType *media_type;
|
|
IMFTransform *transform;
|
|
const BYTE *wmaenc_data;
|
|
ULONG wmaenc_data_len;
|
|
ULONG i, ret, ref;
|
|
HRESULT hr;
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr);
|
|
|
|
winetest_push_context("wmadec");
|
|
|
|
if (!check_mft_enum(MFT_CATEGORY_AUDIO_DECODER, &input_type, &output_type, class_id))
|
|
goto failed;
|
|
check_mft_get_info(class_id, &expect_mft_info);
|
|
check_dmo_get_info(class_id, &expect_dmo_info);
|
|
|
|
if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER,
|
|
&IID_IMFTransform, (void **)&transform)))
|
|
goto failed;
|
|
|
|
check_interface(transform, &IID_IMFTransform, TRUE);
|
|
check_interface(transform, &IID_IMediaObject, TRUE);
|
|
todo_wine
|
|
check_interface(transform, &IID_IPropertyStore, TRUE);
|
|
check_interface(transform, &IID_IPropertyBag, TRUE);
|
|
|
|
check_mft_optional_methods(transform, 1);
|
|
check_mft_get_attributes(transform, NULL, FALSE);
|
|
check_mft_get_input_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
|
|
check_mft_get_output_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
|
|
|
|
hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type);
|
|
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "GetOutputAvailableType returned %#lx\n", hr);
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetInputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("in %lu", i);
|
|
ok(hr == S_OK, "GetInputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, expect_available_inputs[i], -1);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
todo_wine
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetInputAvailableType returned %#lx\n", hr);
|
|
todo_wine
|
|
ok(i == 4, "%lu input media types\n", i);
|
|
|
|
/* setting output media type first doesn't work */
|
|
check_mft_set_output_type(transform, output_type_desc, MF_E_TRANSFORM_TYPE_NOT_SET);
|
|
check_mft_get_output_current_type_(transform, NULL, TRUE);
|
|
|
|
check_mft_set_input_type_required(transform, input_type_desc);
|
|
check_mft_set_input_type(transform, input_type_desc);
|
|
check_mft_get_input_current_type_(transform, expect_input_type_desc, TRUE, FALSE);
|
|
|
|
check_mft_get_input_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
|
|
check_mft_get_output_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
|
|
|
|
/* check new output media types */
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("out %lu", i);
|
|
ok(hr == S_OK, "GetOutputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, expect_available_outputs[i], -1);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx\n", hr);
|
|
ok(i == 2, "%lu output media types\n", i);
|
|
|
|
check_mft_set_output_type_required(transform, output_type_desc);
|
|
check_mft_set_output_type(transform, output_type_desc, S_OK);
|
|
check_mft_get_output_current_type_(transform, expect_output_type_desc, TRUE);
|
|
|
|
check_mft_get_input_stream_info(transform, S_OK, &input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, &output_info);
|
|
|
|
load_resource(L"wmaencdata.bin", &wmaenc_data, &wmaenc_data_len);
|
|
ok(wmaenc_data_len % wmaenc_block_size == 0, "got length %lu\n", wmaenc_data_len);
|
|
|
|
input_sample = create_sample(wmaenc_data, wmaenc_block_size / 2);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);
|
|
ret = IMFSample_Release(input_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
input_sample = create_sample(wmaenc_data, wmaenc_block_size + 1);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);
|
|
ret = IMFSample_Release(input_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
input_sample = create_sample(wmaenc_data, wmaenc_block_size);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr);
|
|
ret = IMFSample_Release(input_sample);
|
|
ok(ret == 1, "Release returned %lu\n", ret);
|
|
|
|
/* As output_info.dwFlags doesn't have MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES
|
|
* IMFTransform_ProcessOutput needs a sample or returns MF_E_TRANSFORM_NEED_MORE_INPUT */
|
|
|
|
hr = check_mft_process_output(transform, NULL, &output_status);
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE
|
|
|| broken(output_status == (MFT_OUTPUT_DATA_BUFFER_INCOMPLETE|MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE)) /* Win7 */,
|
|
"got output[0].dwStatus %#lx\n", output_status);
|
|
|
|
input_sample = create_sample(wmaenc_data, wmaenc_block_size);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr);
|
|
ret = IMFSample_Release(input_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
hr = check_mft_process_output(transform, NULL, &output_status);
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE
|
|
|| broken(output_status == (MFT_OUTPUT_DATA_BUFFER_INCOMPLETE|MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE)) /* Win7 */,
|
|
"got output[0].dwStatus %#lx\n", output_status);
|
|
|
|
hr = MFCreateCollection(&output_samples);
|
|
ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr);
|
|
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
for (i = 0; SUCCEEDED(hr = check_mft_process_output(transform, output_sample, &output_status)); i++)
|
|
{
|
|
winetest_push_context("%lu", i);
|
|
ok(!(output_status & ~MFT_OUTPUT_DATA_BUFFER_INCOMPLETE), "got output[0].dwStatus %#lx\n", output_status);
|
|
ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr);
|
|
hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample);
|
|
ok(hr == S_OK, "AddElement returned %#lx\n", hr);
|
|
ref = IMFSample_Release(output_sample);
|
|
ok(ref == 1, "Release returned %ld\n", ref);
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
todo_wine_if(i == 3) /* wmadec output depends on ffmpeg version used */
|
|
ok(i == 4, "got %lu output samples\n", i);
|
|
|
|
if (!strcmp(winetest_platform, "wine") && i == 3)
|
|
output_sample_desc[1].attributes = output_sample_attributes_todo;
|
|
|
|
ret = check_mf_sample_collection(output_samples, output_sample_desc, L"wmadecdata.bin");
|
|
todo_wine_if(ret > 0 && ret <= 10) /* ffmpeg sometimes offsets the decoded data */
|
|
ok(ret == 0, "got %lu%% diff\n", ret);
|
|
IMFCollection_Release(output_samples);
|
|
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
hr = IMFSample_GetTotalLength(output_sample, &length);
|
|
ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr);
|
|
ok(length == 0, "got length %lu\n", length);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
input_sample = create_sample(wmaenc_data, wmaenc_block_size);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);
|
|
|
|
ret = IMFTransform_Release(transform);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
ret = IMFSample_Release(input_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
hr = CoCreateInstance( &CLSID_CWMADecMediaObject, &outer, CLSCTX_INPROC_SERVER, &IID_IUnknown,
|
|
(void **)&unknown );
|
|
ok( hr == S_OK, "CoCreateInstance returned %#lx\n", hr );
|
|
hr = IUnknown_QueryInterface( unknown, &IID_IMFTransform, (void **)&transform );
|
|
ok( hr == S_OK, "QueryInterface returned %#lx\n", hr );
|
|
hr = IUnknown_QueryInterface( unknown, &IID_IMediaObject, (void **)&media_object );
|
|
ok( hr == S_OK, "QueryInterface returned %#lx\n", hr );
|
|
hr = IUnknown_QueryInterface( unknown, &IID_IPropertyBag, (void **)&property_bag );
|
|
ok( hr == S_OK, "QueryInterface returned %#lx\n", hr );
|
|
hr = IUnknown_QueryInterface( media_object, &IID_IUnknown, (void **)&tmp_unknown );
|
|
ok( hr == S_OK, "QueryInterface returned %#lx\n", hr );
|
|
|
|
ok( unknown != &outer, "got outer IUnknown\n" );
|
|
ok( transform != (void *)unknown, "got IUnknown == IMFTransform\n" );
|
|
ok( media_object != (void *)unknown, "got IUnknown == IMediaObject\n" );
|
|
ok( property_bag != (void *)unknown, "got IUnknown == IPropertyBag\n" );
|
|
ok( tmp_unknown != unknown, "got inner IUnknown\n" );
|
|
|
|
check_interface( unknown, &IID_IPersistPropertyBag, FALSE );
|
|
check_interface( unknown, &IID_IAMFilterMiscFlags, FALSE );
|
|
check_interface( unknown, &IID_IMediaSeeking, FALSE );
|
|
check_interface( unknown, &IID_IMediaPosition, FALSE );
|
|
check_interface( unknown, &IID_IReferenceClock, FALSE );
|
|
check_interface( unknown, &IID_IBasicAudio, FALSE );
|
|
|
|
ref = IUnknown_Release( tmp_unknown );
|
|
ok( ref == 1, "Release returned %lu\n", ref );
|
|
ref = IPropertyBag_Release( property_bag );
|
|
ok( ref == 1, "Release returned %lu\n", ref );
|
|
ref = IMediaObject_Release( media_object );
|
|
ok( ref == 1, "Release returned %lu\n", ref );
|
|
ref = IMFTransform_Release( transform );
|
|
ok( ref == 1, "Release returned %lu\n", ref );
|
|
ref = IUnknown_Release( unknown );
|
|
ok( ref == 0, "Release returned %lu\n", ref );
|
|
|
|
failed:
|
|
winetest_pop_context();
|
|
CoUninitialize();
|
|
}
|
|
|
|
static void test_wma_decoder_dmo_input_type(void)
|
|
{
|
|
const DMO_MEDIA_TYPE expected_input_types[] =
|
|
{
|
|
{MEDIATYPE_Audio, MEDIASUBTYPE_MSAUDIO1 },
|
|
{MEDIATYPE_Audio, MEDIASUBTYPE_WMAUDIO2 },
|
|
{MEDIATYPE_Audio, MEDIASUBTYPE_WMAUDIO3 },
|
|
{MEDIATYPE_Audio, MEDIASUBTYPE_WMAUDIO_LOSSLESS},
|
|
};
|
|
|
|
DMO_MEDIA_TYPE *good_input_type, *bad_input_type, type;
|
|
char buffer_good[1024], buffer_bad[1024];
|
|
DWORD count, i, ret;
|
|
IMediaObject *dmo;
|
|
HRESULT hr;
|
|
|
|
winetest_push_context("wmadec");
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "CoInitialize failed, hr %#lx.\n", hr);
|
|
|
|
if (FAILED(hr = CoCreateInstance(&CLSID_CWMADecMediaObject, NULL, CLSCTX_INPROC_SERVER, &IID_IMediaObject, (void **)&dmo)))
|
|
{
|
|
CoUninitialize();
|
|
winetest_pop_context();
|
|
return;
|
|
}
|
|
|
|
good_input_type = (void *)buffer_good;
|
|
bad_input_type = (void *)buffer_bad;
|
|
|
|
/* Test GetInputType. */
|
|
count = ARRAY_SIZE(expected_input_types);
|
|
hr = IMediaObject_GetInputType(dmo, 1, 0, NULL);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputType(dmo, 1, 0, &type);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputType(dmo, 1, count, &type);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputType(dmo, 0, count, &type);
|
|
ok(hr == DMO_E_NO_MORE_ITEMS, "GetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputType(dmo, 0, count, NULL);
|
|
ok(hr == DMO_E_NO_MORE_ITEMS, "GetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputType(dmo, 0, 0xdeadbeef, NULL);
|
|
ok(hr == DMO_E_NO_MORE_ITEMS, "GetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputType(dmo, 0, count - 1, NULL);
|
|
ok(hr == S_OK, "GetInputType returned %#lx.\n", hr);
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMediaObject_GetInputType(dmo, 0, ++i, &type)))
|
|
{
|
|
winetest_push_context("type %lu", i);
|
|
check_dmo_media_type(&type, &expected_input_types[i]);
|
|
MoFreeMediaType(&type);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == DMO_E_NO_MORE_ITEMS, "GetInputType returned %#lx.\n", hr);
|
|
ok(i == count, "%lu types.\n", i);
|
|
|
|
/* Test SetInputType. */
|
|
init_dmo_media_type_audio(good_input_type, &MEDIASUBTYPE_WMAUDIO2, 2, 22050, 32);
|
|
memset(bad_input_type, 0, sizeof(buffer_bad));
|
|
|
|
hr = IMediaObject_SetInputType(dmo, 1, NULL, 0);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, bad_input_type, 0);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, good_input_type, 0);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, NULL, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, bad_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, NULL, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, bad_input_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, good_input_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, NULL, 0x4);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, bad_input_type, 0x4);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, good_input_type, 0x4);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_SetInputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR | DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == E_INVALIDARG, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR | 0x4);
|
|
ok(hr == E_INVALIDARG, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, NULL, 0);
|
|
ok(hr == E_POINTER, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, NULL, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == E_POINTER, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, NULL, 0x4);
|
|
ok(hr == E_POINTER, "SetInputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_SetInputType(dmo, 0, bad_input_type, 0);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, bad_input_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, bad_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, bad_input_type, 0x4);
|
|
ok(hr == E_INVALIDARG, "SetInputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, 0);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, 0x4);
|
|
ok(hr == E_INVALIDARG, "SetInputType returned %#lx.\n", hr);
|
|
|
|
/* Test GetInputCurrentType. */
|
|
hr = IMediaObject_SetInputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputCurrentType(dmo, 1, NULL);
|
|
todo_wine
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputCurrentType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputCurrentType(dmo, 0, NULL);
|
|
todo_wine
|
|
ok(hr == DMO_E_TYPE_NOT_SET, "GetInputCurrentType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputCurrentType(dmo, 1, &type);
|
|
todo_wine
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputCurrentType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputCurrentType(dmo, 0, &type);
|
|
todo_wine
|
|
ok(hr == DMO_E_TYPE_NOT_SET, "GetInputCurrentType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, 0);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputCurrentType(dmo, 1, NULL);
|
|
todo_wine
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputCurrentType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputCurrentType(dmo, 0, NULL);
|
|
todo_wine
|
|
ok(hr == E_POINTER, "GetInputCurrentType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputCurrentType(dmo, 1, &type);
|
|
todo_wine
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputCurrentType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputCurrentType(dmo, 0, &type);
|
|
todo_wine
|
|
ok(hr == S_OK, "GetInputCurrentType returned %#lx.\n", hr);
|
|
if (hr == S_OK)
|
|
{
|
|
check_dmo_media_type(&type, good_input_type);
|
|
MoFreeMediaType(&type);
|
|
}
|
|
|
|
/* Cleanup. */
|
|
ret = IMediaObject_Release(dmo);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
CoUninitialize();
|
|
winetest_pop_context();
|
|
}
|
|
|
|
static void test_wma_decoder_dmo_output_type(void)
|
|
{
|
|
const UINT channel_count = 2, rate = 22050, bits_per_sample = WMAUDIO_BITS_PER_SAMPLE;
|
|
const GUID* input_subtype = &MEDIASUBTYPE_WMAUDIO2;
|
|
const WAVEFORMATEX expected_output_info =
|
|
{
|
|
WAVE_FORMAT_PCM, channel_count, rate, bits_per_sample * rate * channel_count / 8,
|
|
bits_per_sample * channel_count / 8, WMAUDIO_BITS_PER_SAMPLE, 0
|
|
};
|
|
const DMO_MEDIA_TYPE expected_output_type =
|
|
{
|
|
MEDIATYPE_Audio, MEDIASUBTYPE_PCM, TRUE, FALSE, 0, FORMAT_WaveFormatEx, NULL,
|
|
sizeof(expected_output_info), (BYTE *)&expected_output_info
|
|
};
|
|
|
|
char buffer_good_output[1024], buffer_bad_output[1024], buffer_input[1024];
|
|
DMO_MEDIA_TYPE *good_output_type, *bad_output_type, *input_type, type;
|
|
DWORD count, i, ret, size, alignment;
|
|
IMediaObject *dmo;
|
|
HRESULT hr;
|
|
|
|
winetest_push_context("wmadec");
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "CoInitialize failed, hr %#lx.\n", hr);
|
|
|
|
if (FAILED(hr = CoCreateInstance(&CLSID_CWMADecMediaObject, NULL, CLSCTX_INPROC_SERVER, &IID_IMediaObject, (void **)&dmo)))
|
|
{
|
|
CoUninitialize();
|
|
winetest_pop_context();
|
|
return;
|
|
}
|
|
|
|
/* Initialize media types. */
|
|
input_type = (void *)buffer_input;
|
|
good_output_type = (void *)buffer_good_output;
|
|
bad_output_type = (void *)buffer_bad_output;
|
|
init_dmo_media_type_audio(input_type, input_subtype, channel_count, rate, 16);
|
|
init_dmo_media_type_audio(good_output_type, &MEDIASUBTYPE_PCM, channel_count, rate, bits_per_sample);
|
|
memset(bad_output_type, 0, sizeof(buffer_bad_output));
|
|
|
|
/* Test GetOutputType. */
|
|
hr = IMediaObject_GetOutputType(dmo, 1, 0, NULL);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputType(dmo, 0, 0, NULL);
|
|
ok(hr == DMO_E_TYPE_NOT_SET, "GetOutputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_SetInputType(dmo, 0, input_type, 0);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
|
|
count = 1;
|
|
hr = IMediaObject_GetOutputType(dmo, 1, 0, NULL);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputType(dmo, 1, 0, &type);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputType(dmo, 1, count, &type);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputType(dmo, 0, count, &type);
|
|
ok(hr == DMO_E_NO_MORE_ITEMS, "GetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputType(dmo, 0, count, NULL);
|
|
ok(hr == DMO_E_NO_MORE_ITEMS, "GetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputType(dmo, 0, 0xdeadbeef, NULL);
|
|
ok(hr == DMO_E_NO_MORE_ITEMS, "GetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputType(dmo, 0, count - 1, NULL);
|
|
ok(hr == S_OK, "GetOutputType returned %#lx.\n", hr);
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMediaObject_GetOutputType(dmo, 0, ++i, &type)))
|
|
{
|
|
winetest_push_context("type %lu", i);
|
|
check_dmo_media_type(&type, &expected_output_type);
|
|
MoFreeMediaType(&type);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == DMO_E_NO_MORE_ITEMS, "GetInputType returned %#lx.\n", hr);
|
|
ok(i == count, "%lu types.\n", i);
|
|
|
|
/* Test SetOutputType. */
|
|
hr = IMediaObject_SetInputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, NULL, 0);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, good_output_type, 0);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, 0);
|
|
ok(hr == E_POINTER, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, bad_output_type, 0);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, bad_output_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, 0);
|
|
ok(hr == DMO_E_TYPE_NOT_SET, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_TYPE_NOT_SET, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, 0x4);
|
|
ok(hr == E_INVALIDARG, "SetOutputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_SetInputType(dmo, 0, input_type, 0);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_SetOutputType(dmo, 1, NULL, 0);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, bad_output_type, 0);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, good_output_type, 0);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, NULL, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, bad_output_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, good_output_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, NULL, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, bad_output_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, good_output_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, NULL, 0x4);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, bad_output_type, 0x4);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, good_output_type, 0x4);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR | DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == E_INVALIDARG, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR | 0x4);
|
|
ok(hr == E_INVALIDARG, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, 0);
|
|
ok(hr == E_POINTER, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == E_POINTER, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, 0x4);
|
|
ok(hr == E_POINTER, "SetOutputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_SetOutputType(dmo, 0, bad_output_type, 0);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, bad_output_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, bad_output_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, bad_output_type, 0x4);
|
|
ok(hr == E_INVALIDARG, "SetOutputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, 0);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, 0x4);
|
|
ok(hr == E_INVALIDARG, "SetOutputType returned %#lx.\n", hr);
|
|
|
|
/* Test GetOutputCurrentType. */
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
todo_wine
|
|
{
|
|
hr = IMediaObject_GetOutputCurrentType(dmo, 1, NULL);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputCurrentType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputCurrentType(dmo, 0, NULL);
|
|
ok(hr == DMO_E_TYPE_NOT_SET, "GetOutputCurrentType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputCurrentType(dmo, 1, &type);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputCurrentType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputCurrentType(dmo, 0, &type);
|
|
ok(hr == DMO_E_TYPE_NOT_SET, "GetOutputCurrentType returned %#lx.\n", hr);
|
|
}
|
|
|
|
hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, 0);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
todo_wine
|
|
{
|
|
hr = IMediaObject_GetOutputCurrentType(dmo, 1, NULL);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputCurrentType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputCurrentType(dmo, 0, NULL);
|
|
ok(hr == E_POINTER, "GetOutputCurrentType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputCurrentType(dmo, 1, &type);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputCurrentType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputCurrentType(dmo, 0, &type);
|
|
ok(hr == S_OK, "GetOutputCurrentType returned %#lx.\n", hr);
|
|
}
|
|
if (hr == S_OK)
|
|
{
|
|
check_dmo_media_type(&type, good_output_type);
|
|
MoFreeMediaType(&type);
|
|
}
|
|
|
|
/* Test GetOutputSizeInfo. */
|
|
hr = IMediaObject_GetOutputSizeInfo(dmo, 1, NULL, NULL);
|
|
ok(hr == E_POINTER, "GetOutputSizeInfo returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputSizeInfo(dmo, 0, NULL, NULL);
|
|
ok(hr == E_POINTER, "GetOutputSizeInfo returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputSizeInfo(dmo, 0, &size, NULL);
|
|
ok(hr == E_POINTER, "GetOutputSizeInfo returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputSizeInfo(dmo, 0, NULL, &alignment);
|
|
ok(hr == E_POINTER, "GetOutputSizeInfo returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputSizeInfo(dmo, 0, &size, &alignment);
|
|
ok(hr == S_OK, "GetOutputSizeInfo returned %#lx.\n", hr);
|
|
ok(size == 8192, "Unexpected size %lu.\n", size);
|
|
ok(alignment == 1, "Unexpected alignment %lu.\n", alignment);
|
|
|
|
hr = IMediaObject_GetInputCurrentType(dmo, 0, input_type);
|
|
todo_wine
|
|
ok(hr == S_OK, "GetInputCurrentType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, input_type, 0);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputCurrentType(dmo, 0, &type);
|
|
todo_wine
|
|
ok(hr == S_OK, "GetOutputCurrentType returned %#lx.\n", hr);
|
|
|
|
init_dmo_media_type_audio(input_type, input_subtype, channel_count, rate * 2, 32);
|
|
hr = IMediaObject_SetInputType(dmo, 0, input_type, 0);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputCurrentType(dmo, 0, &type);
|
|
todo_wine
|
|
ok(hr == DMO_E_TYPE_NOT_SET, "GetOutputCurrentType returned %#lx.\n", hr);
|
|
|
|
/* Cleanup. */
|
|
ret = IMediaObject_Release(dmo);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
CoUninitialize();
|
|
winetest_pop_context();
|
|
}
|
|
|
|
#define next_h264_sample(a, b) next_h264_sample_(__LINE__, a, b)
|
|
static IMFSample *next_h264_sample_(int line, const BYTE **h264_buf, ULONG *h264_len)
|
|
{
|
|
const BYTE *sample_data;
|
|
|
|
ok_(__FILE__, line)(*h264_len > 4, "invalid h264 length\n");
|
|
ok_(__FILE__, line)(*(UINT32 *)*h264_buf == 0x01000000, "invalid h264 buffer\n");
|
|
sample_data = *h264_buf;
|
|
|
|
(*h264_len) -= 4;
|
|
(*h264_buf) += 4;
|
|
|
|
while (*h264_len >= 4 && *(UINT32 *)*h264_buf != 0x01000000)
|
|
{
|
|
(*h264_len)--;
|
|
(*h264_buf)++;
|
|
}
|
|
|
|
return create_sample(sample_data, *h264_buf - sample_data);
|
|
}
|
|
|
|
static void test_h264_encoder(void)
|
|
{
|
|
static const DWORD actual_width = 96, actual_height = 96;
|
|
const GUID *const class_id = &CLSID_MSH264EncoderMFT;
|
|
const struct transform_info expect_mft_info =
|
|
{
|
|
.name = L"H264 Encoder MFT",
|
|
.major_type = &MFMediaType_Video,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MFVideoFormat_IYUV},
|
|
{.subtype = &MFVideoFormat_YV12},
|
|
{.subtype = &MFVideoFormat_NV12},
|
|
{.subtype = &MFVideoFormat_YUY2},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MFVideoFormat_H264},
|
|
},
|
|
};
|
|
static const struct attribute_desc expect_transform_attributes[] =
|
|
{
|
|
ATTR_UINT32(MFT_ENCODER_SUPPORTS_CONFIG_EVENT, 1),
|
|
{0},
|
|
};
|
|
const struct attribute_desc input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
{0},
|
|
};
|
|
const struct attribute_desc output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_H264, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001),
|
|
ATTR_UINT32(MF_MT_AVG_BITRATE, 193540),
|
|
ATTR_UINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive),
|
|
{0},
|
|
};
|
|
const struct attribute_desc expect_input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001),
|
|
{0},
|
|
};
|
|
const struct attribute_desc expect_output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_H264),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001),
|
|
ATTR_UINT32(MF_MT_AVG_BITRATE, 193540),
|
|
ATTR_BLOB(MF_MT_MPEG_SEQUENCE_HEADER, test_h264_sequence_header, sizeof(test_h264_sequence_header)),
|
|
{0},
|
|
};
|
|
static const MFT_OUTPUT_STREAM_INFO expect_output_info = {.cbSize = 0x8000};
|
|
MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Video, MFVideoFormat_H264};
|
|
MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Video, MFVideoFormat_NV12};
|
|
IMFTransform *transform;
|
|
HRESULT hr;
|
|
ULONG ret;
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr);
|
|
|
|
winetest_push_context("h264enc");
|
|
|
|
if (!has_video_processor)
|
|
{
|
|
win_skip("Skipping inconsistent h264 encoder tests on Win7.\n");
|
|
goto failed;
|
|
}
|
|
|
|
if (!check_mft_enum(MFT_CATEGORY_VIDEO_ENCODER, &input_type, &output_type, class_id))
|
|
goto failed;
|
|
check_mft_get_info(class_id, &expect_mft_info);
|
|
|
|
hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform);
|
|
ok(hr == S_OK, "CoCreateInstance returned %#lx.\n", hr);
|
|
|
|
check_interface(transform, &IID_IMFTransform, TRUE);
|
|
check_interface(transform, &IID_IMediaObject, FALSE);
|
|
check_interface(transform, &IID_IPropertyStore, FALSE);
|
|
check_interface(transform, &IID_IPropertyBag, FALSE);
|
|
|
|
check_mft_get_attributes(transform, expect_transform_attributes, FALSE);
|
|
check_mft_get_input_stream_info(transform, S_OK, NULL);
|
|
check_mft_get_output_stream_info(transform, S_OK, NULL);
|
|
|
|
check_mft_set_output_type_required(transform, output_type_desc);
|
|
check_mft_set_output_type(transform, output_type_desc, S_OK);
|
|
|
|
check_mft_set_input_type_required(transform, input_type_desc);
|
|
check_mft_set_input_type(transform, input_type_desc);
|
|
check_mft_get_input_current_type(transform, expect_input_type_desc);
|
|
|
|
check_mft_get_output_current_type(transform, expect_output_type_desc);
|
|
|
|
check_mft_get_input_stream_info(transform, S_OK, NULL);
|
|
check_mft_get_output_stream_info(transform, S_OK, &expect_output_info);
|
|
|
|
ret = IMFTransform_Release(transform);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
failed:
|
|
winetest_pop_context();
|
|
CoUninitialize();
|
|
}
|
|
|
|
static void test_h264_decoder(void)
|
|
{
|
|
const GUID *const class_id = &CLSID_MSH264DecoderMFT;
|
|
const struct transform_info expect_mft_info =
|
|
{
|
|
.name = L"Microsoft H264 Video Decoder MFT",
|
|
.major_type = &MFMediaType_Video,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MFVideoFormat_H264},
|
|
{.subtype = &MFVideoFormat_H264_ES},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MFVideoFormat_NV12},
|
|
{.subtype = &MFVideoFormat_YV12},
|
|
{.subtype = &MFVideoFormat_IYUV},
|
|
{.subtype = &MFVideoFormat_I420},
|
|
{.subtype = &MFVideoFormat_YUY2},
|
|
},
|
|
};
|
|
static const media_type_desc default_inputs[] =
|
|
{
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_H264),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_H264_ES),
|
|
},
|
|
};
|
|
static const struct attribute_desc expect_transform_attributes[] =
|
|
{
|
|
ATTR_UINT32(MF_LOW_LATENCY, 0),
|
|
ATTR_UINT32(MF_SA_D3D_AWARE, 1, .todo = TRUE),
|
|
ATTR_UINT32(MF_SA_D3D11_AWARE, 1),
|
|
ATTR_UINT32(MFT_DECODER_EXPOSE_OUTPUT_TYPES_IN_NATIVE_ORDER, 0, .todo = TRUE),
|
|
/* more H264 decoder specific attributes from CODECAPI */
|
|
ATTR_UINT32(AVDecVideoAcceleration_H264, 1),
|
|
{0},
|
|
};
|
|
static const DWORD input_width = 120, input_height = 248;
|
|
const media_type_desc default_outputs[] =
|
|
{
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, input_width),
|
|
ATTR_UINT32(MF_MT_INTERLACE_MODE, 7),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, input_width, input_height),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, input_width * input_height * 3 / 2),
|
|
/* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YV12),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, input_width),
|
|
ATTR_UINT32(MF_MT_INTERLACE_MODE, 7),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, input_width, input_height),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, input_width * input_height * 3 / 2),
|
|
/* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_IYUV),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, input_width),
|
|
ATTR_UINT32(MF_MT_INTERLACE_MODE, 7),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, input_width, input_height),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, input_width * input_height * 3 / 2),
|
|
/* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_I420),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, input_width),
|
|
ATTR_UINT32(MF_MT_INTERLACE_MODE, 7),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, input_width, input_height),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, input_width * input_height * 3 / 2),
|
|
/* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, input_width * 2),
|
|
ATTR_UINT32(MF_MT_INTERLACE_MODE, 7),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, input_width, input_height),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, input_width * input_height * 2),
|
|
/* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */
|
|
},
|
|
};
|
|
const struct attribute_desc input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_H264, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, input_width, input_height),
|
|
{0},
|
|
};
|
|
const struct attribute_desc output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, input_width, input_height, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 60000, 1000),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 2, 1),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 3840),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, 3840 * input_height * 3 / 2),
|
|
ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0),
|
|
{0},
|
|
};
|
|
const struct attribute_desc expect_input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_H264),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, input_width, input_height),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 0),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 0),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 0),
|
|
ATTR_UINT32(MF_MT_AVG_BIT_ERROR_RATE, 0),
|
|
ATTR_UINT32(MF_MT_COMPRESSED, 1),
|
|
{0},
|
|
};
|
|
const struct attribute_desc expect_output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, input_width, input_height),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 60000, 1000),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 2, 1),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 3840),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, 3840 * input_height * 3 / 2),
|
|
ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0),
|
|
ATTR_UINT32(MF_MT_AVG_BIT_ERROR_RATE, 0, .todo = TRUE),
|
|
ATTR_UINT32(MF_MT_COMPRESSED, 0, .todo = TRUE),
|
|
{0},
|
|
};
|
|
static const struct attribute_desc new_output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_I420),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 1, 1),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 2),
|
|
{0},
|
|
};
|
|
static const struct attribute_desc expect_new_output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_I420),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 1, 1),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 2),
|
|
ATTR_UINT32(MF_MT_COMPRESSED, 0, .todo = TRUE),
|
|
ATTR_UINT32(MF_MT_AVG_BIT_ERROR_RATE, 0, .todo = TRUE),
|
|
{0},
|
|
};
|
|
static const MFVideoArea actual_aperture = {.Area={82,84}};
|
|
static const DWORD actual_width = 96, actual_height = 96;
|
|
const media_type_desc actual_outputs[] =
|
|
{
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 60000, 1000),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width),
|
|
/* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */
|
|
ATTR_UINT32(MF_MT_INTERLACE_MODE, 7),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YV12),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 60000, 1000),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width),
|
|
/* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */
|
|
ATTR_UINT32(MF_MT_INTERLACE_MODE, 7),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_IYUV),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 60000, 1000),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width),
|
|
/* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */
|
|
ATTR_UINT32(MF_MT_INTERLACE_MODE, 7),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_I420),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 60000, 1000),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width),
|
|
/* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */
|
|
ATTR_UINT32(MF_MT_INTERLACE_MODE, 7),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 60000, 1000),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 2),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 2),
|
|
/* ATTR_UINT32(MF_MT_VIDEO_ROTATION, 0), missing on Win7 */
|
|
ATTR_UINT32(MF_MT_INTERLACE_MODE, 7),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16),
|
|
},
|
|
};
|
|
const MFT_OUTPUT_STREAM_INFO initial_output_info =
|
|
{
|
|
.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER |
|
|
MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE,
|
|
.cbSize = 1920 * 1088 * 2,
|
|
};
|
|
const MFT_OUTPUT_STREAM_INFO output_info =
|
|
{
|
|
.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER |
|
|
MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE,
|
|
.cbSize = input_width * input_height * 2,
|
|
};
|
|
const MFT_OUTPUT_STREAM_INFO actual_output_info =
|
|
{
|
|
.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER |
|
|
MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE,
|
|
.cbSize = actual_width * actual_height * 2,
|
|
};
|
|
const MFT_INPUT_STREAM_INFO input_info =
|
|
{
|
|
.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER |
|
|
MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE,
|
|
.cbSize = 0x1000,
|
|
};
|
|
|
|
const struct attribute_desc output_sample_attributes[] =
|
|
{
|
|
ATTR_UINT32(MFSampleExtension_CleanPoint, 1),
|
|
{0},
|
|
};
|
|
const struct buffer_desc output_buffer_desc_nv12 =
|
|
{
|
|
.length = actual_width * actual_height * 3 / 2,
|
|
.compare = compare_nv12, .dump = dump_nv12, .rect = {.right = 82, .bottom = 84},
|
|
};
|
|
const struct sample_desc output_sample_desc_nv12 =
|
|
{
|
|
.attributes = output_sample_attributes,
|
|
.sample_time = 0, .sample_duration = 333667,
|
|
.buffer_count = 1, .buffers = &output_buffer_desc_nv12,
|
|
};
|
|
const struct buffer_desc output_buffer_desc_i420 =
|
|
{
|
|
.length = actual_width * actual_height * 3 / 2,
|
|
.compare = compare_i420, .dump = dump_i420, .rect = {.right = 82, .bottom = 84},
|
|
};
|
|
const struct sample_desc expect_output_sample_i420 =
|
|
{
|
|
.attributes = output_sample_attributes,
|
|
.sample_time = 333667, .sample_duration = 333667,
|
|
.buffer_count = 1, .buffers = &output_buffer_desc_i420,
|
|
};
|
|
|
|
MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Video, MFVideoFormat_H264};
|
|
MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Video, MFVideoFormat_NV12};
|
|
IMFSample *input_sample, *output_sample;
|
|
const BYTE *h264_encoded_data;
|
|
IMFCollection *output_samples;
|
|
ULONG h264_encoded_data_len;
|
|
DWORD length, output_status;
|
|
IMFAttributes *attributes;
|
|
IMFMediaType *media_type;
|
|
IMFTransform *transform;
|
|
ULONG i, ret, ref;
|
|
DWORD flags;
|
|
HRESULT hr;
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr);
|
|
|
|
winetest_push_context("h264dec");
|
|
|
|
if (!check_mft_enum(MFT_CATEGORY_VIDEO_DECODER, &input_type, &output_type, class_id))
|
|
goto failed;
|
|
check_mft_get_info(class_id, &expect_mft_info);
|
|
|
|
if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER,
|
|
&IID_IMFTransform, (void **)&transform)))
|
|
goto failed;
|
|
|
|
check_interface(transform, &IID_IMFTransform, TRUE);
|
|
check_interface(transform, &IID_IMediaObject, FALSE);
|
|
check_interface(transform, &IID_IPropertyStore, FALSE);
|
|
check_interface(transform, &IID_IPropertyBag, FALSE);
|
|
|
|
check_mft_optional_methods(transform, 1);
|
|
check_mft_get_attributes(transform, expect_transform_attributes, TRUE);
|
|
check_mft_get_input_stream_info(transform, S_OK, &input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, &initial_output_info);
|
|
|
|
hr = IMFTransform_GetAttributes(transform, &attributes);
|
|
ok(hr == S_OK, "GetAttributes returned %#lx\n", hr);
|
|
hr = IMFAttributes_SetUINT32(attributes, &MF_LOW_LATENCY, 1);
|
|
ok(hr == S_OK, "SetUINT32 returned %#lx\n", hr);
|
|
IMFAttributes_Release(attributes);
|
|
|
|
/* no output type is available before an input type is set */
|
|
|
|
hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type);
|
|
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "GetOutputAvailableType returned %#lx\n", hr);
|
|
|
|
flags = 0xdeadbeef;
|
|
hr = IMFTransform_GetInputStatus(transform, 0, &flags);
|
|
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Got %#lx\n", hr);
|
|
ok(flags == 0xdeadbeef, "Got flags %#lx.\n", flags);
|
|
|
|
/* setting output media type first doesn't work */
|
|
check_mft_set_output_type(transform, output_type_desc, MF_E_TRANSFORM_TYPE_NOT_SET);
|
|
check_mft_get_output_current_type(transform, NULL);
|
|
|
|
/* check available input types */
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetInputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("in %lu", i);
|
|
ok(hr == S_OK, "GetInputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, default_inputs[i], -1);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetInputAvailableType returned %#lx\n", hr);
|
|
ok(i == 2 || broken(i == 1) /* Win7 */, "%lu input media types\n", i);
|
|
|
|
check_mft_set_input_type_required(transform, input_type_desc);
|
|
check_mft_set_input_type(transform, input_type_desc);
|
|
check_mft_get_input_current_type_(transform, expect_input_type_desc, TRUE, FALSE);
|
|
|
|
check_mft_get_input_stream_info(transform, S_OK, &input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, &output_info);
|
|
|
|
/* output types can now be enumerated (though they are actually the same for all input types) */
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("out %lu", i);
|
|
ok(hr == S_OK, "GetOutputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, default_outputs[i], -1);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx\n", hr);
|
|
ok(i == 5, "%lu output media types\n", i);
|
|
|
|
check_mft_set_output_type_required(transform, output_type_desc);
|
|
check_mft_set_output_type(transform, output_type_desc, S_OK);
|
|
check_mft_get_output_current_type_(transform, expect_output_type_desc, FALSE);
|
|
|
|
/* check that the output media type we've selected don't change the enumeration */
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("out %lu", i);
|
|
ok(hr == S_OK, "GetOutputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, default_outputs[i], -1);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx\n", hr);
|
|
ok(i == 5, "%lu output media types\n", i);
|
|
|
|
check_mft_get_input_stream_info(transform, S_OK, &input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, &output_info);
|
|
|
|
load_resource(L"h264data.bin", &h264_encoded_data, &h264_encoded_data_len);
|
|
|
|
/* As output_info.dwFlags doesn't have MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES
|
|
* IMFTransform_ProcessOutput needs a sample or returns an error */
|
|
|
|
hr = check_mft_process_output(transform, NULL, &output_status);
|
|
ok(hr == E_INVALIDARG || hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
|
|
i = 0;
|
|
input_sample = next_h264_sample(&h264_encoded_data, &h264_encoded_data_len);
|
|
while (1)
|
|
{
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
if (hr != MF_E_TRANSFORM_NEED_MORE_INPUT) break;
|
|
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
hr = IMFSample_GetTotalLength(output_sample, &length);
|
|
ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr);
|
|
ok(length == 0, "got length %lu\n", length);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
flags = 0;
|
|
hr = IMFTransform_GetInputStatus(transform, 0, &flags);
|
|
ok(hr == S_OK, "Got %#lx\n", hr);
|
|
ok(flags == MFT_INPUT_STATUS_ACCEPT_DATA, "Got flags %#lx.\n", flags);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);
|
|
ret = IMFSample_Release(input_sample);
|
|
ok(ret <= 1, "Release returned %lu\n", ret);
|
|
input_sample = next_h264_sample(&h264_encoded_data, &h264_encoded_data_len);
|
|
|
|
flags = 0;
|
|
hr = IMFTransform_GetInputStatus(transform, 0, &flags);
|
|
ok(hr == S_OK, "Got %#lx\n", hr);
|
|
ok(flags == MFT_INPUT_STATUS_ACCEPT_DATA, "Got flags %#lx.\n", flags);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);
|
|
ret = IMFSample_Release(input_sample);
|
|
ok(ret <= 1, "Release returned %lu\n", ret);
|
|
input_sample = next_h264_sample(&h264_encoded_data, &h264_encoded_data_len);
|
|
i++;
|
|
|
|
hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0);
|
|
ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0);
|
|
ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr);
|
|
}
|
|
ok(i == 2, "got %lu iterations\n", i);
|
|
ok(h264_encoded_data_len == 2425, "got h264_encoded_data_len %lu\n", h264_encoded_data_len);
|
|
ok(hr == MF_E_TRANSFORM_STREAM_CHANGE, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE, "got output[0].dwStatus %#lx\n", output_status);
|
|
hr = IMFSample_GetTotalLength(output_sample, &length);
|
|
ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr);
|
|
ok(length == 0, "got length %lu\n", length);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
check_mft_get_input_stream_info(transform, S_OK, &input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, &actual_output_info);
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("out %lu", i);
|
|
ok(hr == S_OK, "GetOutputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, actual_outputs[i], -1);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx\n", hr);
|
|
ok(i == 5, "%lu output media types\n", i);
|
|
|
|
/* current output type is still the one we selected */
|
|
check_mft_get_output_current_type_(transform, expect_output_type_desc, FALSE);
|
|
|
|
hr = MFCreateCollection(&output_samples);
|
|
ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr);
|
|
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample);
|
|
ok(hr == S_OK, "AddElement returned %#lx\n", hr);
|
|
ref = IMFSample_Release(output_sample);
|
|
ok(ref == 1, "Release returned %ld\n", ref);
|
|
|
|
ret = check_mf_sample_collection(output_samples, &output_sample_desc_nv12, L"nv12frame.bmp");
|
|
ok(ret == 0, "got %lu%% diff\n", ret);
|
|
IMFCollection_Release(output_samples);
|
|
|
|
/* we can change it, but only with the correct frame size */
|
|
hr = MFCreateMediaType(&media_type);
|
|
ok(hr == S_OK, "MFCreateMediaType returned %#lx\n", hr);
|
|
init_media_type(media_type, output_type_desc, -1);
|
|
hr = IMFTransform_SetOutputType(transform, 0, media_type, 0);
|
|
ok(hr == MF_E_INVALIDMEDIATYPE, "SetOutputType returned %#lx.\n", hr);
|
|
init_media_type(media_type, new_output_type_desc, -1);
|
|
hr = IMFTransform_SetOutputType(transform, 0, media_type, 0);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret == 1, "Release returned %lu\n", ret);
|
|
|
|
check_mft_get_output_current_type_(transform, expect_new_output_type_desc, FALSE);
|
|
|
|
output_sample = create_sample(NULL, actual_width * actual_height * 2);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
todo_wine
|
|
ok(hr == MF_E_TRANSFORM_STREAM_CHANGE, "ProcessOutput returned %#lx\n", hr);
|
|
todo_wine
|
|
ok(output_status == MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE, "got output[0].dwStatus %#lx\n", output_status);
|
|
|
|
while (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
|
|
{
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);
|
|
ret = IMFSample_Release(input_sample);
|
|
ok(ret <= 1, "Release returned %lu\n", ret);
|
|
input_sample = next_h264_sample(&h264_encoded_data, &h264_encoded_data_len);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
}
|
|
|
|
ok(hr == MF_E_TRANSFORM_STREAM_CHANGE, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE, "got output[0].dwStatus %#lx\n", output_status);
|
|
|
|
hr = IMFSample_GetTotalLength(output_sample, &length);
|
|
ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr);
|
|
ok(length == 0, "got length %lu\n", length);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
hr = MFCreateCollection(&output_samples);
|
|
ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr);
|
|
|
|
output_sample = create_sample(NULL, actual_width * actual_height * 2);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample);
|
|
ok(hr == S_OK, "AddElement returned %#lx\n", hr);
|
|
ref = IMFSample_Release(output_sample);
|
|
ok(ref == 1, "Release returned %ld\n", ref);
|
|
|
|
ret = check_mf_sample_collection(output_samples, &expect_output_sample_i420, L"i420frame.bmp");
|
|
todo_wine /* wg_transform_set_output_format() should convert already processed samples instead of dropping */
|
|
ok(ret == 0, "got %lu%% diff\n", ret);
|
|
IMFCollection_Release(output_samples);
|
|
|
|
output_sample = create_sample(NULL, actual_width * actual_height * 2);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
todo_wine_if(hr == S_OK) /* when VA-API plugin is used */
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
do
|
|
{
|
|
flags = 0;
|
|
hr = IMFTransform_GetInputStatus(transform, 0, &flags);
|
|
ok(hr == S_OK, "Got %#lx\n", hr);
|
|
ok(flags == MFT_INPUT_STATUS_ACCEPT_DATA, "Got flags %#lx.\n", flags);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == S_OK || hr == MF_E_NOTACCEPTING, "Got %#lx\n", hr);
|
|
input_sample = next_h264_sample(&h264_encoded_data, &h264_encoded_data_len);
|
|
} while (hr == S_OK);
|
|
|
|
ok(hr == MF_E_NOTACCEPTING, "Got %#lx\n", hr);
|
|
flags = 0;
|
|
hr = IMFTransform_GetInputStatus(transform, 0, &flags);
|
|
ok(hr == S_OK, "Got %#lx\n", hr);
|
|
ok(flags == MFT_INPUT_STATUS_ACCEPT_DATA, "Got flags %#lx.\n", flags);
|
|
|
|
ret = IMFTransform_Release(transform);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
ret = IMFSample_Release(input_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
failed:
|
|
winetest_pop_context();
|
|
CoUninitialize();
|
|
}
|
|
|
|
static void test_h264_decoder_concat_streams(void)
|
|
{
|
|
const struct buffer_desc output_buffer_desc[] =
|
|
{
|
|
{.length = 0x3600},
|
|
{.length = 0x4980},
|
|
};
|
|
const struct attribute_desc output_sample_attributes[] =
|
|
{
|
|
ATTR_UINT32(MFSampleExtension_CleanPoint, 1),
|
|
{0},
|
|
};
|
|
const struct sample_desc output_sample_desc[] =
|
|
{
|
|
{
|
|
.attributes = output_sample_attributes + 0,
|
|
.sample_time = 0, .sample_duration = 400000,
|
|
.buffer_count = 1, .buffers = output_buffer_desc + 0, .repeat_count = 29,
|
|
},
|
|
{
|
|
.attributes = output_sample_attributes + 0,
|
|
.sample_time = 12000000, .sample_duration = 400000,
|
|
.buffer_count = 1, .buffers = output_buffer_desc + 1, .repeat_count = 29,
|
|
},
|
|
{
|
|
.attributes = output_sample_attributes + 0,
|
|
.sample_time = 0, .sample_duration = 400000,
|
|
.buffer_count = 1, .buffers = output_buffer_desc + 0, .repeat_count = 29,
|
|
.todo_time = TRUE,
|
|
},
|
|
{
|
|
.attributes = output_sample_attributes + 0,
|
|
.sample_time = 12000000, .sample_duration = 400000,
|
|
.buffer_count = 1, .buffers = output_buffer_desc + 1, .repeat_count = 6,
|
|
.todo_time = TRUE,
|
|
},
|
|
{0},
|
|
};
|
|
const WCHAR *filenames[] =
|
|
{
|
|
L"h264data-1.bin",
|
|
L"h264data-2.bin",
|
|
L"h264data-1.bin",
|
|
L"h264data-2.bin",
|
|
NULL,
|
|
};
|
|
DWORD output_status, input_count, output_count;
|
|
const WCHAR **filename = filenames;
|
|
const BYTE *h264_encoded_data;
|
|
IMFCollection *output_samples;
|
|
ULONG h264_encoded_data_len;
|
|
IMFAttributes *attributes;
|
|
IMFMediaType *media_type;
|
|
IMFTransform *transform;
|
|
IMFSample *input_sample;
|
|
HRESULT hr;
|
|
LONG ret;
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr);
|
|
|
|
if (FAILED(hr = CoCreateInstance(&CLSID_MSH264DecoderMFT, NULL, CLSCTX_INPROC_SERVER,
|
|
&IID_IMFTransform, (void **)&transform)))
|
|
goto failed;
|
|
ok(hr == S_OK, "hr %#lx\n", hr);
|
|
|
|
hr = IMFTransform_GetAttributes(transform, &attributes);
|
|
ok(hr == S_OK, "GetAttributes returned %#lx\n", hr);
|
|
hr = IMFAttributes_SetUINT32(attributes, &MF_LOW_LATENCY, 1);
|
|
ok(hr == S_OK, "SetUINT32 returned %#lx\n", hr);
|
|
IMFAttributes_Release(attributes);
|
|
|
|
hr = IMFTransform_GetInputAvailableType(transform, 0, 0, &media_type);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, (UINT64)25000 << 32 | 1000);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
hr = IMFTransform_SetInputType(transform, 0, media_type, 0);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
IMFMediaType_Release(media_type);
|
|
|
|
hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, (UINT64)50000 << 32 | 1000);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
hr = IMFTransform_SetOutputType(transform, 0, media_type, 0);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
IMFMediaType_Release(media_type);
|
|
|
|
load_resource(*filename, &h264_encoded_data, &h264_encoded_data_len);
|
|
|
|
hr = MFCreateCollection(&output_samples);
|
|
ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr);
|
|
|
|
input_count = 0;
|
|
input_sample = next_h264_sample(&h264_encoded_data, &h264_encoded_data_len);
|
|
while (input_sample)
|
|
{
|
|
MFT_OUTPUT_STREAM_INFO info = {0};
|
|
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == S_OK || hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr);
|
|
|
|
if (hr == S_OK && input_count < 2)
|
|
{
|
|
MFT_OUTPUT_DATA_BUFFER data = {.pSample = create_sample(NULL, 1)};
|
|
hr = IMFTransform_ProcessOutput(transform, 0, 1, &data, &output_status);
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
IMFSample_Release(data.pSample);
|
|
hr = S_OK;
|
|
}
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
IMFSample_Release(input_sample);
|
|
|
|
hr = IMFCollection_GetElementCount(output_samples, &output_count);
|
|
ok(hr == S_OK, "GetElementCount returned %#lx\n", hr);
|
|
|
|
if (output_count == 96)
|
|
{
|
|
hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_FLUSH, 0);
|
|
ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr);
|
|
}
|
|
|
|
if (h264_encoded_data_len <= 4 && *++filename)
|
|
{
|
|
load_resource(*filename, &h264_encoded_data, &h264_encoded_data_len);
|
|
|
|
if (!wcscmp(*filename, L"h264data-1.bin"))
|
|
{
|
|
hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0);
|
|
ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr);
|
|
}
|
|
}
|
|
|
|
if (h264_encoded_data_len > 4)
|
|
{
|
|
input_count++;
|
|
input_sample = next_h264_sample(&h264_encoded_data, &h264_encoded_data_len);
|
|
}
|
|
else
|
|
{
|
|
hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0);
|
|
ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr);
|
|
input_sample = NULL;
|
|
}
|
|
}
|
|
|
|
hr = IMFTransform_GetOutputStreamInfo(transform, 0, &info);
|
|
ok(hr == S_OK, "GetOutputStreamInfo returned %#lx\n", hr);
|
|
|
|
while (hr != MF_E_TRANSFORM_NEED_MORE_INPUT)
|
|
{
|
|
MFT_OUTPUT_DATA_BUFFER data = {.pSample = create_sample(NULL, info.cbSize)};
|
|
|
|
hr = IMFTransform_ProcessOutput(transform, 0, 1, &data, &output_status);
|
|
todo_wine_if(hr == 0xd0000001)
|
|
ok(hr == S_OK || hr == MF_E_TRANSFORM_NEED_MORE_INPUT || hr == MF_E_TRANSFORM_STREAM_CHANGE,
|
|
"ProcessOutput returned %#lx\n", hr);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
hr = IMFCollection_AddElement(output_samples, (IUnknown *)data.pSample);
|
|
ok(hr == S_OK, "AddElement returned %#lx\n", hr);
|
|
}
|
|
if (hr == MF_E_TRANSFORM_STREAM_CHANGE)
|
|
{
|
|
hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, (UINT64)50000 << 32 | 1000);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
hr = IMFTransform_SetOutputType(transform, 0, media_type, 0);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
IMFMediaType_Release(media_type);
|
|
hr = IMFTransform_GetOutputStreamInfo(transform, 0, &info);
|
|
ok(hr == S_OK, "GetOutputStreamInfo returned %#lx\n", hr);
|
|
}
|
|
|
|
IMFSample_Release(data.pSample);
|
|
}
|
|
}
|
|
|
|
hr = IMFCollection_GetElementCount(output_samples, &output_count);
|
|
ok(hr == S_OK, "GetElementCount returned %#lx\n", hr);
|
|
ok(output_count == 96 || broken(output_count == 120) /* Win7 sometimes */, "GetElementCount returned %lu\n", output_count);
|
|
while (broken(output_count > 96)) /* Win7 sometimes */
|
|
{
|
|
IMFSample *sample;
|
|
hr = IMFCollection_RemoveElement(output_samples, --output_count, (IUnknown **)&sample);
|
|
ok(hr == S_OK, "GetElementCount returned %#lx\n", hr);
|
|
IMFSample_Release(sample);
|
|
}
|
|
|
|
ret = check_mf_sample_collection(output_samples, output_sample_desc, NULL);
|
|
ok(ret == 0, "got %lu%% diff\n", ret);
|
|
|
|
ret = IMFTransform_Release(transform);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
failed:
|
|
CoUninitialize();
|
|
}
|
|
|
|
static void test_audio_convert(void)
|
|
{
|
|
const GUID *const class_id = &CLSID_CResamplerMediaObject;
|
|
const struct transform_info expect_mft_info =
|
|
{
|
|
.name = L"Resampler MFT",
|
|
.major_type = &MFMediaType_Audio,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MFAudioFormat_PCM},
|
|
{.subtype = &MFAudioFormat_Float},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MFAudioFormat_PCM},
|
|
{.subtype = &MFAudioFormat_Float},
|
|
},
|
|
};
|
|
const struct transform_info expect_dmo_info =
|
|
{
|
|
.name = L"Resampler DMO",
|
|
.major_type = &MEDIATYPE_Audio,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MEDIASUBTYPE_PCM},
|
|
{.subtype = &MEDIASUBTYPE_IEEE_FLOAT},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MEDIASUBTYPE_PCM},
|
|
{.subtype = &MEDIASUBTYPE_IEEE_FLOAT},
|
|
},
|
|
};
|
|
|
|
static const media_type_desc expect_available_inputs[] =
|
|
{
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
},
|
|
};
|
|
static const media_type_desc expect_available_outputs[] =
|
|
{
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 32),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 48000),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 384000),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 8),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 48000),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 192000),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1),
|
|
},
|
|
};
|
|
|
|
static const struct attribute_desc input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 32, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 2 * (32 / 8), .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 2 * (32 / 8) * 22050, .required = TRUE),
|
|
{0},
|
|
};
|
|
const struct attribute_desc output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 2 * (16 / 8), .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 2 * (16 / 8) * 44100, .required = TRUE),
|
|
{0},
|
|
};
|
|
static const struct attribute_desc expect_input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 32),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 8),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 22050 * 8),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_AUDIO_CHANNEL_MASK, 3),
|
|
{0},
|
|
};
|
|
const struct attribute_desc expect_output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 44100 * 4),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1, .todo = TRUE),
|
|
{0},
|
|
};
|
|
const MFT_OUTPUT_STREAM_INFO output_info =
|
|
{
|
|
.cbSize = 4,
|
|
.cbAlignment = 1,
|
|
};
|
|
const MFT_INPUT_STREAM_INFO input_info =
|
|
{
|
|
.cbSize = 8,
|
|
.cbAlignment = 1,
|
|
};
|
|
|
|
static const ULONG audioconv_block_size = 0x4000;
|
|
const struct buffer_desc output_buffer_desc[] =
|
|
{
|
|
{.length = audioconv_block_size, .compare = compare_pcm16},
|
|
{.length = 0x3dd8, .compare = compare_pcm16, .todo_length = TRUE},
|
|
{.length = 0xfc, .compare = compare_pcm16},
|
|
};
|
|
const struct attribute_desc output_sample_attributes[] =
|
|
{
|
|
ATTR_UINT32(mft_output_sample_incomplete, 1),
|
|
ATTR_UINT32(MFSampleExtension_CleanPoint, has_video_processor /* 0 on Win7 */, .todo = TRUE),
|
|
{0},
|
|
};
|
|
const struct sample_desc output_sample_desc[] =
|
|
{
|
|
{
|
|
.attributes = output_sample_attributes + 0,
|
|
.sample_time = 0, .sample_duration = 928798,
|
|
.buffer_count = 1, .buffers = output_buffer_desc + 0, .repeat_count = 9,
|
|
},
|
|
{
|
|
.attributes = output_sample_attributes + 1, /* not MFT_OUTPUT_DATA_BUFFER_INCOMPLETE */
|
|
.sample_time = 9287980, .sample_duration = 897506, .todo_duration = 897280,
|
|
.buffer_count = 1, .buffers = output_buffer_desc + 1, .todo_length = TRUE,
|
|
},
|
|
{
|
|
.attributes = output_sample_attributes + 0,
|
|
.sample_time = 10185486, .sample_duration = 14286,
|
|
.buffer_count = 1, .buffers = output_buffer_desc + 2,
|
|
},
|
|
};
|
|
|
|
MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Audio, MFAudioFormat_PCM};
|
|
MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Audio, MFAudioFormat_Float};
|
|
IMFSample *input_sample, *output_sample;
|
|
IMFCollection *output_samples;
|
|
DWORD length, output_status;
|
|
IMFMediaType *media_type;
|
|
IMFTransform *transform;
|
|
const BYTE *audio_data;
|
|
ULONG audio_data_len;
|
|
ULONG i, ret, ref;
|
|
HRESULT hr;
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr);
|
|
|
|
winetest_push_context("resampler");
|
|
|
|
if (!check_mft_enum(MFT_CATEGORY_AUDIO_EFFECT, &input_type, &output_type, class_id))
|
|
goto failed;
|
|
check_mft_get_info(class_id, &expect_mft_info);
|
|
check_dmo_get_info(class_id, &expect_dmo_info);
|
|
|
|
if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER,
|
|
&IID_IMFTransform, (void **)&transform)))
|
|
goto failed;
|
|
|
|
check_interface(transform, &IID_IMFTransform, TRUE);
|
|
check_interface(transform, &IID_IMediaObject, TRUE);
|
|
check_interface(transform, &IID_IPropertyStore, TRUE);
|
|
check_interface(transform, &IID_IPropertyBag, TRUE);
|
|
/* check_interface(transform, &IID_IWMResamplerProps, TRUE); */
|
|
|
|
check_mft_optional_methods(transform, 1);
|
|
check_mft_get_attributes(transform, NULL, FALSE);
|
|
check_mft_get_input_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
|
|
check_mft_get_output_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("out %lu", i);
|
|
ok(hr == S_OK, "GetOutputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, expect_available_outputs[i], -1);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx\n", hr);
|
|
ok(i == 4, "%lu output media types\n", i);
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetInputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("in %lu", i);
|
|
ok(hr == S_OK, "GetInputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, expect_available_inputs[i], -1);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetInputAvailableType returned %#lx\n", hr);
|
|
ok(i == 2, "%lu input media types\n", i);
|
|
|
|
/* setting output media type first doesn't work */
|
|
check_mft_set_output_type(transform, output_type_desc, MF_E_TRANSFORM_TYPE_NOT_SET);
|
|
check_mft_get_output_current_type(transform, NULL);
|
|
|
|
check_mft_set_input_type_required(transform, input_type_desc);
|
|
check_mft_set_input_type(transform, input_type_desc);
|
|
check_mft_get_input_current_type_(transform, expect_input_type_desc, FALSE, TRUE);
|
|
|
|
check_mft_get_input_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
|
|
check_mft_get_output_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
|
|
|
|
/* check new output media types */
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("out %lu", i);
|
|
ok(hr == S_OK, "GetOutputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, expect_available_outputs[i], -1);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx\n", hr);
|
|
ok(i == 4, "%lu output media types\n", i);
|
|
|
|
check_mft_set_output_type_required(transform, output_type_desc);
|
|
check_mft_set_output_type(transform, output_type_desc, S_OK);
|
|
check_mft_get_output_current_type_(transform, expect_output_type_desc, FALSE);
|
|
|
|
check_mft_get_input_stream_info(transform, S_OK, &input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, &output_info);
|
|
|
|
load_resource(L"audiodata.bin", &audio_data, &audio_data_len);
|
|
ok(audio_data_len == 179928, "got length %lu\n", audio_data_len);
|
|
|
|
input_sample = create_sample(audio_data, audio_data_len);
|
|
hr = IMFSample_SetSampleTime(input_sample, 0);
|
|
ok(hr == S_OK, "SetSampleTime returned %#lx\n", hr);
|
|
hr = IMFSample_SetSampleDuration(input_sample, 10000000);
|
|
ok(hr == S_OK, "SetSampleDuration returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0);
|
|
ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr);
|
|
ret = IMFSample_Release(input_sample);
|
|
ok(ret <= 1, "Release returned %ld\n", ret);
|
|
|
|
hr = MFCreateCollection(&output_samples);
|
|
ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr);
|
|
|
|
output_sample = create_sample(NULL, audioconv_block_size);
|
|
for (i = 0; SUCCEEDED(hr = check_mft_process_output(transform, output_sample, &output_status)); i++)
|
|
{
|
|
winetest_push_context("%lu", i);
|
|
ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr);
|
|
ok(!(output_status & ~MFT_OUTPUT_DATA_BUFFER_INCOMPLETE), "got output[0].dwStatus %#lx\n", output_status);
|
|
hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample);
|
|
ok(hr == S_OK, "AddElement returned %#lx\n", hr);
|
|
ref = IMFSample_Release(output_sample);
|
|
ok(ref == 1, "Release returned %ld\n", ref);
|
|
output_sample = create_sample(NULL, audioconv_block_size);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
todo_wine
|
|
ok(i == 12 || broken(i == 11) /* Win7 */, "got %lu output samples\n", i);
|
|
|
|
ret = check_mf_sample_collection(output_samples, output_sample_desc, L"audioconvdata.bin");
|
|
ok(ret == 0, "got %lu%% diff\n", ret);
|
|
IMFCollection_Release(output_samples);
|
|
|
|
output_sample = create_sample(NULL, audioconv_block_size);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
hr = IMFSample_GetTotalLength(output_sample, &length);
|
|
ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr);
|
|
ok(length == 0, "got length %lu\n", length);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
ret = IMFTransform_Release(transform);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
failed:
|
|
winetest_pop_context();
|
|
CoUninitialize();
|
|
}
|
|
|
|
const GUID *wmv_decoder_output_subtypes[] =
|
|
{
|
|
&MEDIASUBTYPE_NV12,
|
|
&MEDIASUBTYPE_YV12,
|
|
&MEDIASUBTYPE_IYUV,
|
|
&MEDIASUBTYPE_I420,
|
|
&MEDIASUBTYPE_YUY2,
|
|
&MEDIASUBTYPE_UYVY,
|
|
&MEDIASUBTYPE_YVYU,
|
|
&MEDIASUBTYPE_NV11,
|
|
&MEDIASUBTYPE_RGB32,
|
|
&MEDIASUBTYPE_RGB24,
|
|
&MEDIASUBTYPE_RGB565,
|
|
&MEDIASUBTYPE_RGB555,
|
|
&MEDIASUBTYPE_RGB8,
|
|
};
|
|
|
|
static void test_wmv_encoder(void)
|
|
{
|
|
const GUID *const class_id = &CLSID_CWMVXEncMediaObject;
|
|
const struct transform_info expect_mft_info =
|
|
{
|
|
.name = L"WMVideo8 Encoder MFT",
|
|
.major_type = &MFMediaType_Video,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MFVideoFormat_IYUV},
|
|
{.subtype = &MFVideoFormat_I420},
|
|
{.subtype = &MFVideoFormat_YV12},
|
|
{.subtype = &MFVideoFormat_NV11},
|
|
{.subtype = &MFVideoFormat_NV12},
|
|
{.subtype = &MFVideoFormat_YUY2},
|
|
{.subtype = &MFVideoFormat_UYVY},
|
|
{.subtype = &MFVideoFormat_YVYU},
|
|
{.subtype = &MFVideoFormat_YVU9},
|
|
{.subtype = &DMOVideoFormat_RGB32},
|
|
{.subtype = &DMOVideoFormat_RGB24},
|
|
{.subtype = &DMOVideoFormat_RGB565},
|
|
{.subtype = &DMOVideoFormat_RGB555},
|
|
{.subtype = &DMOVideoFormat_RGB8},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MFVideoFormat_WMV1},
|
|
{.subtype = &MFVideoFormat_WMV2},
|
|
},
|
|
};
|
|
const struct transform_info expect_dmo_info =
|
|
{
|
|
.name = L"WMVideo8 Encoder DMO",
|
|
.major_type = &MEDIATYPE_Video,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MEDIASUBTYPE_IYUV},
|
|
{.subtype = &MEDIASUBTYPE_I420},
|
|
{.subtype = &MEDIASUBTYPE_YV12},
|
|
{.subtype = &MEDIASUBTYPE_NV11},
|
|
{.subtype = &MEDIASUBTYPE_NV12},
|
|
{.subtype = &MEDIASUBTYPE_YUY2},
|
|
{.subtype = &MEDIASUBTYPE_UYVY},
|
|
{.subtype = &MEDIASUBTYPE_YVYU},
|
|
{.subtype = &MEDIASUBTYPE_YVU9},
|
|
{.subtype = &MEDIASUBTYPE_RGB32},
|
|
{.subtype = &MEDIASUBTYPE_RGB24},
|
|
{.subtype = &MEDIASUBTYPE_RGB565},
|
|
{.subtype = &MEDIASUBTYPE_RGB555},
|
|
{.subtype = &MEDIASUBTYPE_RGB8},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MEDIASUBTYPE_WMV1},
|
|
{.subtype = &MEDIASUBTYPE_WMV2},
|
|
},
|
|
};
|
|
|
|
static const media_type_desc expect_available_inputs[] =
|
|
{
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_IYUV),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_TRANSFER_FUNCTION, 0),
|
|
ATTR_UINT32(MF_MT_VIDEO_PRIMARIES, 0),
|
|
ATTR_UINT32(MF_MT_YUV_MATRIX, 0),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_I420),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_TRANSFER_FUNCTION, 0),
|
|
ATTR_UINT32(MF_MT_VIDEO_PRIMARIES, 0),
|
|
ATTR_UINT32(MF_MT_YUV_MATRIX, 0),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YV12),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_TRANSFER_FUNCTION, 0),
|
|
ATTR_UINT32(MF_MT_VIDEO_PRIMARIES, 0),
|
|
ATTR_UINT32(MF_MT_YUV_MATRIX, 0),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV11),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_TRANSFER_FUNCTION, 0),
|
|
ATTR_UINT32(MF_MT_VIDEO_PRIMARIES, 0),
|
|
ATTR_UINT32(MF_MT_YUV_MATRIX, 0),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_TRANSFER_FUNCTION, 0),
|
|
ATTR_UINT32(MF_MT_VIDEO_PRIMARIES, 0),
|
|
ATTR_UINT32(MF_MT_YUV_MATRIX, 0),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_TRANSFER_FUNCTION, 0),
|
|
ATTR_UINT32(MF_MT_VIDEO_PRIMARIES, 0),
|
|
ATTR_UINT32(MF_MT_YUV_MATRIX, 0),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_UYVY),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_TRANSFER_FUNCTION, 0),
|
|
ATTR_UINT32(MF_MT_VIDEO_PRIMARIES, 0),
|
|
ATTR_UINT32(MF_MT_YUV_MATRIX, 0),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YVYU),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_TRANSFER_FUNCTION, 0),
|
|
ATTR_UINT32(MF_MT_VIDEO_PRIMARIES, 0),
|
|
ATTR_UINT32(MF_MT_YUV_MATRIX, 0),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_TRANSFER_FUNCTION, 0),
|
|
ATTR_UINT32(MF_MT_VIDEO_PRIMARIES, 0),
|
|
ATTR_UINT32(MF_MT_YUV_MATRIX, 0),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB24),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_TRANSFER_FUNCTION, 0),
|
|
ATTR_UINT32(MF_MT_VIDEO_PRIMARIES, 0),
|
|
ATTR_UINT32(MF_MT_YUV_MATRIX, 0),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB565),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_TRANSFER_FUNCTION, 0),
|
|
ATTR_UINT32(MF_MT_VIDEO_PRIMARIES, 0),
|
|
ATTR_UINT32(MF_MT_YUV_MATRIX, 0),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB555),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_TRANSFER_FUNCTION, 0),
|
|
ATTR_UINT32(MF_MT_VIDEO_PRIMARIES, 0),
|
|
ATTR_UINT32(MF_MT_YUV_MATRIX, 0),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MEDIASUBTYPE_RGB8),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_TRANSFER_FUNCTION, 0),
|
|
ATTR_UINT32(MF_MT_VIDEO_PRIMARIES, 0),
|
|
ATTR_UINT32(MF_MT_YUV_MATRIX, 0),
|
|
},
|
|
};
|
|
static const media_type_desc expect_available_outputs[] =
|
|
{
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV1),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_TRANSFER_FUNCTION, 0),
|
|
ATTR_UINT32(MF_MT_VIDEO_PRIMARIES, 0),
|
|
ATTR_UINT32(MF_MT_YUV_MATRIX, 0),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV2),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_TRANSFER_FUNCTION, 0),
|
|
ATTR_UINT32(MF_MT_VIDEO_PRIMARIES, 0),
|
|
ATTR_UINT32(MF_MT_YUV_MATRIX, 0),
|
|
},
|
|
};
|
|
|
|
static const DWORD actual_width = 96, actual_height = 96;
|
|
const struct attribute_desc input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height), /* required for SetOutputType */
|
|
{0},
|
|
};
|
|
const struct attribute_desc output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV1, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AVG_BITRATE, 193540, .required = TRUE),
|
|
{0},
|
|
};
|
|
|
|
const struct attribute_desc expect_input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
{0},
|
|
};
|
|
const struct attribute_desc expect_output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV1),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001),
|
|
ATTR_UINT32(MF_MT_AVG_BITRATE, 193540),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
{0},
|
|
};
|
|
static const MFT_OUTPUT_STREAM_INFO empty_output_info =
|
|
{
|
|
.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER,
|
|
};
|
|
static const MFT_INPUT_STREAM_INFO empty_input_info =
|
|
{
|
|
.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER,
|
|
};
|
|
static const MFT_OUTPUT_STREAM_INFO expect_output_info =
|
|
{
|
|
.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER,
|
|
.cbSize = 0x8000,
|
|
.cbAlignment = 1,
|
|
};
|
|
static const MFT_INPUT_STREAM_INFO expect_input_info =
|
|
{
|
|
.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER,
|
|
.cbSize = 0x3600,
|
|
.cbAlignment = 1,
|
|
};
|
|
|
|
const struct buffer_desc output_buffer_desc[] =
|
|
{
|
|
{.length = -1 /* variable */},
|
|
};
|
|
const struct attribute_desc output_sample_attributes_key[] =
|
|
{
|
|
ATTR_UINT32(MFSampleExtension_CleanPoint, 1),
|
|
{0},
|
|
};
|
|
const struct attribute_desc output_sample_attributes[] =
|
|
{
|
|
ATTR_UINT32(MFSampleExtension_CleanPoint, 0),
|
|
{0},
|
|
};
|
|
const struct sample_desc output_sample_desc[] =
|
|
{
|
|
{
|
|
.attributes = output_sample_attributes_key,
|
|
.sample_time = 0, .sample_duration = 333333,
|
|
.buffer_count = 1, .buffers = output_buffer_desc,
|
|
},
|
|
{
|
|
.attributes = output_sample_attributes,
|
|
.sample_time = 333333, .sample_duration = 333333,
|
|
.buffer_count = 1, .buffers = output_buffer_desc, .repeat_count = 4
|
|
},
|
|
};
|
|
|
|
MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Video, MFVideoFormat_WMV1};
|
|
MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Video, MFVideoFormat_NV12};
|
|
IMFSample *input_sample, *output_sample;
|
|
DWORD status, length, output_status;
|
|
MFT_OUTPUT_DATA_BUFFER output;
|
|
IMFCollection *output_samples;
|
|
const BYTE *nv12frame_data;
|
|
IMFMediaType *media_type;
|
|
ULONG nv12frame_data_len;
|
|
IMFTransform *transform;
|
|
ULONG i, ret;
|
|
HRESULT hr;
|
|
LONG ref;
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr);
|
|
|
|
winetest_push_context("wmvenc");
|
|
|
|
if (!check_mft_enum(MFT_CATEGORY_VIDEO_ENCODER, &input_type, &output_type, class_id))
|
|
goto failed;
|
|
check_mft_get_info(class_id, &expect_mft_info);
|
|
check_dmo_get_info(class_id, &expect_dmo_info);
|
|
|
|
if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER,
|
|
&IID_IMFTransform, (void **)&transform)))
|
|
goto failed;
|
|
|
|
check_interface(transform, &IID_IMFTransform, TRUE);
|
|
check_interface(transform, &IID_IMediaObject, TRUE);
|
|
check_interface(transform, &IID_IPropertyStore, TRUE);
|
|
check_interface(transform, &IID_IPropertyBag, TRUE);
|
|
|
|
check_mft_optional_methods(transform, 2);
|
|
check_mft_get_attributes(transform, NULL, FALSE);
|
|
check_mft_get_input_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, &empty_input_info);
|
|
check_mft_get_output_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, &empty_output_info);
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetInputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("in 0 %lu", i);
|
|
ok(hr == S_OK, "GetInputAvailableType returned %#lx\n", hr);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret <= 1, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetInputAvailableType returned %#lx\n", hr);
|
|
ok(i == ARRAY_SIZE(expect_available_inputs), "%lu input media types\n", i);
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("out %lu", i);
|
|
ok(hr == S_OK, "GetOutputAvailableType returned %#lx\n", hr);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret <= 1, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx\n", hr);
|
|
ok(i == ARRAY_SIZE(expect_available_outputs), "%lu output media types\n", i);
|
|
|
|
check_mft_set_output_type(transform, output_type_desc, MF_E_TRANSFORM_TYPE_NOT_SET);
|
|
check_mft_get_output_current_type(transform, NULL);
|
|
|
|
check_mft_set_input_type_required(transform, input_type_desc);
|
|
check_mft_set_input_type(transform, input_type_desc);
|
|
check_mft_get_input_current_type_(transform, expect_input_type_desc, FALSE, TRUE);
|
|
|
|
check_mft_set_output_type_required(transform, output_type_desc);
|
|
check_mft_set_output_type(transform, output_type_desc, S_OK);
|
|
check_mft_get_output_current_type_(transform, expect_output_type_desc, FALSE);
|
|
|
|
check_mft_get_input_stream_info(transform, S_OK, &expect_input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, &expect_output_info);
|
|
|
|
if (!has_video_processor)
|
|
{
|
|
win_skip("Skipping WMV encoder tests on Win7\n");
|
|
goto done;
|
|
}
|
|
|
|
load_resource(L"nv12frame.bmp", &nv12frame_data, &nv12frame_data_len);
|
|
/* skip BMP header and RGB data from the dump */
|
|
length = *(DWORD *)(nv12frame_data + 2);
|
|
nv12frame_data_len = nv12frame_data_len - length;
|
|
nv12frame_data = nv12frame_data + length;
|
|
ok(nv12frame_data_len == 13824, "got length %lu\n", nv12frame_data_len);
|
|
|
|
hr = MFCreateCollection(&output_samples);
|
|
ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr);
|
|
|
|
for (i = 0; i < 5; i++)
|
|
{
|
|
input_sample = create_sample(nv12frame_data, nv12frame_data_len);
|
|
hr = IMFSample_SetSampleTime(input_sample, i * 333333);
|
|
ok(hr == S_OK, "SetSampleTime returned %#lx\n", hr);
|
|
hr = IMFSample_SetSampleDuration(input_sample, 333333);
|
|
ok(hr == S_OK, "SetSampleDuration returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);
|
|
ref = IMFSample_Release(input_sample);
|
|
ok(ref <= 1, "Release returned %ld\n", ref);
|
|
|
|
output_sample = create_sample(NULL, expect_output_info.cbSize);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr);
|
|
hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample);
|
|
ok(hr == S_OK, "AddElement returned %#lx\n", hr);
|
|
ref = IMFSample_Release(output_sample);
|
|
ok(ref == 1, "Release returned %ld\n", ref);
|
|
}
|
|
|
|
ret = check_mf_sample_collection(output_samples, output_sample_desc, L"wmvencdata.bin");
|
|
ok(ret == 0, "got %lu%% diff\n", ret);
|
|
IMFCollection_Release(output_samples);
|
|
|
|
output_sample = create_sample(NULL, expect_output_info.cbSize);
|
|
status = 0xdeadbeef;
|
|
memset(&output, 0, sizeof(output));
|
|
output.pSample = output_sample;
|
|
hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status);
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output.pSample == output_sample, "got pSample %p\n", output.pSample);
|
|
ok(output.dwStatus == 0, "got dwStatus %#lx\n", output.dwStatus);
|
|
ok(status == 0, "got status %#lx\n", status);
|
|
hr = IMFSample_GetTotalLength(output.pSample, &length);
|
|
ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr);
|
|
ok(length == 0, "got length %lu\n", length);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
done:
|
|
ret = IMFTransform_Release(transform);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
failed:
|
|
winetest_pop_context();
|
|
CoUninitialize();
|
|
}
|
|
|
|
static void test_wmv_decoder(void)
|
|
{
|
|
const GUID *const class_id = &CLSID_CWMVDecMediaObject;
|
|
const struct transform_info expect_mft_info =
|
|
{
|
|
.name = L"WMVideo Decoder MFT",
|
|
.major_type = &MFMediaType_Video,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MFVideoFormat_WMV1},
|
|
{.subtype = &MFVideoFormat_WMV2},
|
|
{.subtype = &MFVideoFormat_WMV3},
|
|
{.subtype = &MEDIASUBTYPE_WMVP},
|
|
{.subtype = &MEDIASUBTYPE_WVP2},
|
|
{.subtype = &MEDIASUBTYPE_WMVR},
|
|
{.subtype = &MEDIASUBTYPE_WMVA},
|
|
{.subtype = &MFVideoFormat_WVC1},
|
|
{.subtype = &MFVideoFormat_VC1S},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MFVideoFormat_YV12},
|
|
{.subtype = &MFVideoFormat_YUY2},
|
|
{.subtype = &MFVideoFormat_UYVY},
|
|
{.subtype = &MFVideoFormat_YVYU},
|
|
{.subtype = &MFVideoFormat_NV11},
|
|
{.subtype = &MFVideoFormat_NV12},
|
|
{.subtype = &DMOVideoFormat_RGB32},
|
|
{.subtype = &DMOVideoFormat_RGB24},
|
|
{.subtype = &DMOVideoFormat_RGB565},
|
|
{.subtype = &DMOVideoFormat_RGB555},
|
|
{.subtype = &DMOVideoFormat_RGB8},
|
|
},
|
|
};
|
|
const struct transform_info expect_dmo_info =
|
|
{
|
|
.name = L"WMVideo Decoder DMO",
|
|
.major_type = &MEDIATYPE_Video,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MEDIASUBTYPE_WMV1},
|
|
{.subtype = &MEDIASUBTYPE_WMV2},
|
|
{.subtype = &MEDIASUBTYPE_WMV3},
|
|
{.subtype = &MEDIASUBTYPE_WMVA},
|
|
{.subtype = &MEDIASUBTYPE_WVC1},
|
|
{.subtype = &MEDIASUBTYPE_WMVP},
|
|
{.subtype = &MEDIASUBTYPE_WVP2},
|
|
{.subtype = &MFVideoFormat_VC1S},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MEDIASUBTYPE_YV12},
|
|
{.subtype = &MEDIASUBTYPE_YUY2},
|
|
{.subtype = &MEDIASUBTYPE_UYVY},
|
|
{.subtype = &MEDIASUBTYPE_YVYU},
|
|
{.subtype = &MEDIASUBTYPE_NV11},
|
|
{.subtype = &MEDIASUBTYPE_NV12},
|
|
{.subtype = &MEDIASUBTYPE_RGB32},
|
|
{.subtype = &MEDIASUBTYPE_RGB24},
|
|
{.subtype = &MEDIASUBTYPE_RGB565},
|
|
{.subtype = &MEDIASUBTYPE_RGB555},
|
|
{.subtype = &MEDIASUBTYPE_RGB8},
|
|
},
|
|
};
|
|
|
|
static const struct attribute_desc expect_common_attributes[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
{0},
|
|
};
|
|
static const media_type_desc expect_available_inputs[] =
|
|
{
|
|
{ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV1)},
|
|
{ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV2)},
|
|
{ATTR_GUID(MF_MT_SUBTYPE, MEDIASUBTYPE_WMVA)},
|
|
{ATTR_GUID(MF_MT_SUBTYPE, MEDIASUBTYPE_WMVP)},
|
|
{ATTR_GUID(MF_MT_SUBTYPE, MEDIASUBTYPE_WVP2)},
|
|
{ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV_Unknown)},
|
|
{ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WVC1)},
|
|
{ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV3)},
|
|
{ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_VC1S)},
|
|
};
|
|
static const MFVideoArea actual_aperture = {.Area={96,96}};
|
|
static const DWORD actual_width = 96, actual_height = 96;
|
|
const struct attribute_desc expect_output_attributes[] =
|
|
{
|
|
ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, sizeof(actual_aperture)),
|
|
ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, sizeof(actual_aperture)),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_INTERLACE_MODE, 2),
|
|
{0},
|
|
};
|
|
const media_type_desc expect_available_outputs[] =
|
|
{
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YV12),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_IYUV),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_I420),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 2),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 2),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_UYVY),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 2),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 2),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YVYU),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 2),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 2),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV11),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 4),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB24),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 3),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB565),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 2),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 2),
|
|
/* ATTR_BLOB(MF_MT_PALETTE, ... with 12 elements), */
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB555),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 2),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 2),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB8),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height),
|
|
/* ATTR_BLOB(MF_MT_PALETTE, ... with 904 elements), */
|
|
},
|
|
};
|
|
const struct attribute_desc expect_attributes[] =
|
|
{
|
|
ATTR_UINT32(MF_LOW_LATENCY, 0),
|
|
ATTR_UINT32(MF_SA_D3D11_AWARE, 1),
|
|
ATTR_UINT32(MF_SA_D3D_AWARE, 1),
|
|
ATTR_UINT32(MFT_DECODER_EXPOSE_OUTPUT_TYPES_IN_NATIVE_ORDER, 0),
|
|
/* more attributes from CODECAPI */
|
|
{0},
|
|
};
|
|
const struct attribute_desc input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV1, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
{0},
|
|
};
|
|
const struct attribute_desc output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
{0},
|
|
};
|
|
const struct attribute_desc output_type_desc_negative_stride[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, -actual_width),
|
|
{0},
|
|
};
|
|
const struct attribute_desc output_type_desc_rgb[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
{0},
|
|
};
|
|
const struct attribute_desc output_type_desc_rgb_negative_stride[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, -actual_width * 4),
|
|
{0},
|
|
};
|
|
const struct attribute_desc output_type_desc_rgb_positive_stride[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 4),
|
|
{0},
|
|
};
|
|
const struct attribute_desc expect_input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV1),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
{0},
|
|
};
|
|
const struct attribute_desc expect_output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_VIDEO_NOMINAL_RANGE, 2),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
{0},
|
|
};
|
|
const struct attribute_desc expect_output_type_desc_rgb[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 4),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_VIDEO_NOMINAL_RANGE, 2),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
{0},
|
|
};
|
|
const struct attribute_desc expect_output_type_desc_rgb_negative_stride[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, -actual_width * 4),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_VIDEO_NOMINAL_RANGE, 2),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
{0},
|
|
};
|
|
const MFT_OUTPUT_STREAM_INFO expect_output_info =
|
|
{
|
|
.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_DISCARDABLE,
|
|
.cbSize = 0x3600,
|
|
.cbAlignment = 1,
|
|
};
|
|
const MFT_OUTPUT_STREAM_INFO expect_output_info_rgb =
|
|
{
|
|
.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_DISCARDABLE,
|
|
.cbSize = 0x9000,
|
|
.cbAlignment = 1,
|
|
};
|
|
const MFT_OUTPUT_STREAM_INFO empty_output_info =
|
|
{
|
|
.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_DISCARDABLE,
|
|
};
|
|
const MFT_INPUT_STREAM_INFO expect_input_info =
|
|
{
|
|
.cbSize = 0x3600,
|
|
.cbAlignment = 1,
|
|
};
|
|
const MFT_INPUT_STREAM_INFO expect_input_info_rgb =
|
|
{
|
|
.cbSize = 0x9000,
|
|
.cbAlignment = 1,
|
|
};
|
|
|
|
const struct attribute_desc output_sample_attributes[] =
|
|
{
|
|
ATTR_UINT32(MFSampleExtension_CleanPoint, 1),
|
|
{0},
|
|
};
|
|
const struct buffer_desc output_buffer_desc_nv12 =
|
|
{
|
|
.length = actual_width * actual_height * 3 / 2,
|
|
.compare = compare_nv12, .dump = dump_nv12, .rect = {.right = 82, .bottom = 84},
|
|
};
|
|
const struct buffer_desc output_buffer_desc_rgb =
|
|
{
|
|
.length = actual_width * actual_height * 4,
|
|
.compare = compare_rgb32, .dump = dump_rgb32, .rect = {.right = 82, .bottom = 84},
|
|
};
|
|
const struct sample_desc output_sample_desc_nv12 =
|
|
{
|
|
.attributes = output_sample_attributes,
|
|
.sample_time = 0, .sample_duration = 333333,
|
|
.buffer_count = 1, .buffers = &output_buffer_desc_nv12,
|
|
};
|
|
const struct sample_desc output_sample_desc_rgb =
|
|
{
|
|
.attributes = output_sample_attributes,
|
|
.sample_time = 0, .sample_duration = 333333,
|
|
.buffer_count = 1, .buffers = &output_buffer_desc_rgb,
|
|
};
|
|
|
|
const struct transform_desc
|
|
{
|
|
const struct attribute_desc *output_type_desc;
|
|
const struct attribute_desc *expect_output_type_desc;
|
|
const MFT_INPUT_STREAM_INFO *expect_input_info;
|
|
const MFT_OUTPUT_STREAM_INFO *expect_output_info;
|
|
const struct sample_desc *output_sample_desc;
|
|
const WCHAR *result_bitmap;
|
|
ULONG delta;
|
|
}
|
|
transform_tests[] =
|
|
{
|
|
{
|
|
/* WMV1 -> YUV */
|
|
.output_type_desc = output_type_desc,
|
|
.expect_output_type_desc = expect_output_type_desc,
|
|
.expect_input_info = &expect_input_info,
|
|
.expect_output_info = &expect_output_info,
|
|
.output_sample_desc = &output_sample_desc_nv12,
|
|
.result_bitmap = L"nv12frame.bmp",
|
|
.delta = 0,
|
|
},
|
|
|
|
{
|
|
/* WMV1 -> YUV (negative stride) */
|
|
.output_type_desc = output_type_desc_negative_stride,
|
|
.expect_output_type_desc = expect_output_type_desc,
|
|
.expect_input_info = &expect_input_info,
|
|
.expect_output_info = &expect_output_info,
|
|
.output_sample_desc = &output_sample_desc_nv12,
|
|
.result_bitmap = L"nv12frame.bmp",
|
|
.delta = 0,
|
|
},
|
|
|
|
{
|
|
/* WMV1 -> RGB */
|
|
.output_type_desc = output_type_desc_rgb,
|
|
.expect_output_type_desc = expect_output_type_desc_rgb,
|
|
.expect_input_info = &expect_input_info_rgb,
|
|
.expect_output_info = &expect_output_info_rgb,
|
|
.output_sample_desc = &output_sample_desc_rgb,
|
|
.result_bitmap = L"rgb32frame-flip.bmp",
|
|
.delta = 5,
|
|
},
|
|
|
|
{
|
|
/* WMV1 -> RGB (negative stride) */
|
|
.output_type_desc = output_type_desc_rgb_negative_stride,
|
|
.expect_output_type_desc = expect_output_type_desc_rgb_negative_stride,
|
|
.expect_input_info = &expect_input_info_rgb,
|
|
.expect_output_info = &expect_output_info_rgb,
|
|
.output_sample_desc = &output_sample_desc_rgb,
|
|
.result_bitmap = L"rgb32frame-flip.bmp",
|
|
.delta = 5,
|
|
},
|
|
|
|
{
|
|
/* WMV1 -> RGB (positive stride */
|
|
.output_type_desc = output_type_desc_rgb_positive_stride,
|
|
.expect_output_type_desc = expect_output_type_desc_rgb,
|
|
.expect_input_info = &expect_input_info_rgb,
|
|
.expect_output_info = &expect_output_info_rgb,
|
|
.output_sample_desc = &output_sample_desc_rgb,
|
|
.result_bitmap = L"rgb32frame-flip.bmp",
|
|
.delta = 5,
|
|
},
|
|
|
|
};
|
|
|
|
MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Video, MFVideoFormat_NV12};
|
|
MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Video, MFVideoFormat_WMV1};
|
|
IMFSample *input_sample, *output_sample;
|
|
IMFCollection *output_samples;
|
|
IMFMediaType *media_type;
|
|
IMFTransform *transform;
|
|
const BYTE *wmvenc_data;
|
|
ULONG wmvenc_data_len;
|
|
DWORD output_status;
|
|
ULONG i, j, ret, ref;
|
|
HRESULT hr;
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr);
|
|
|
|
winetest_push_context("wmvdec");
|
|
|
|
if (!has_video_processor)
|
|
{
|
|
win_skip("Skipping inconsistent WMV decoder tests on Win7\n");
|
|
goto failed;
|
|
}
|
|
|
|
if (!check_mft_enum(MFT_CATEGORY_VIDEO_DECODER, &input_type, &output_type, class_id))
|
|
goto failed;
|
|
check_mft_get_info(class_id, &expect_mft_info);
|
|
check_dmo_get_info(class_id, &expect_dmo_info);
|
|
|
|
if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER,
|
|
&IID_IMFTransform, (void **)&transform)))
|
|
goto failed;
|
|
|
|
check_interface(transform, &IID_IMFTransform, TRUE);
|
|
check_interface(transform, &IID_IMediaObject, TRUE);
|
|
check_interface(transform, &IID_IPropertyStore, TRUE);
|
|
check_interface(transform, &IID_IPropertyBag, TRUE);
|
|
|
|
check_mft_optional_methods(transform, 1);
|
|
check_mft_get_attributes(transform, expect_attributes, TRUE);
|
|
todo_wine
|
|
check_mft_get_input_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
|
|
todo_wine
|
|
check_mft_get_output_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, &empty_output_info);
|
|
|
|
hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type);
|
|
todo_wine
|
|
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "GetOutputAvailableType returned %#lx\n", hr);
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetInputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("in %lu", i);
|
|
ok(hr == S_OK, "GetInputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, expect_common_attributes, -1);
|
|
check_media_type(media_type, expect_available_inputs[i], -1);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(!ret, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
todo_wine
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetInputAvailableType returned %#lx\n", hr);
|
|
todo_wine
|
|
ok(i == ARRAY_SIZE(expect_available_inputs), "%lu input media types\n", i);
|
|
|
|
if (hr == E_NOTIMPL)
|
|
goto skip_tests;
|
|
|
|
check_mft_set_output_type(transform, output_type_desc, MF_E_TRANSFORM_TYPE_NOT_SET);
|
|
check_mft_get_output_current_type(transform, NULL);
|
|
|
|
check_mft_set_input_type_required(transform, input_type_desc);
|
|
check_mft_set_input_type(transform, input_type_desc);
|
|
check_mft_get_input_current_type_(transform, expect_input_type_desc, FALSE, TRUE);
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("out %lu", i);
|
|
ok(hr == S_OK, "GetOutputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, expect_common_attributes, -1);
|
|
check_media_type(media_type, expect_output_attributes, -1);
|
|
check_media_type(media_type, expect_available_outputs[i], -1);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(!ret, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx\n", hr);
|
|
ok(i == ARRAY_SIZE(expect_available_outputs), "%lu input media types\n", i);
|
|
|
|
for (j = 0; j < ARRAY_SIZE(transform_tests); j++)
|
|
{
|
|
winetest_push_context("transform #%lu", j);
|
|
|
|
check_mft_set_output_type_required(transform, transform_tests[j].output_type_desc);
|
|
check_mft_set_output_type(transform, transform_tests[j].output_type_desc, S_OK);
|
|
check_mft_get_output_current_type_(transform, transform_tests[j].expect_output_type_desc, FALSE);
|
|
|
|
check_mft_get_input_stream_info(transform, S_OK, transform_tests[j].expect_input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, transform_tests[j].expect_output_info);
|
|
|
|
load_resource(L"wmvencdata.bin", &wmvenc_data, &wmvenc_data_len);
|
|
|
|
input_sample = create_sample(wmvenc_data + sizeof(DWORD), *(DWORD *)wmvenc_data);
|
|
wmvenc_data_len -= *(DWORD *)wmvenc_data + sizeof(DWORD);
|
|
wmvenc_data += *(DWORD *)wmvenc_data + sizeof(DWORD);
|
|
hr = IMFSample_SetSampleTime(input_sample, 0);
|
|
ok(hr == S_OK, "SetSampleTime returned %#lx\n", hr);
|
|
hr = IMFSample_SetSampleDuration(input_sample, 333333);
|
|
ok(hr == S_OK, "SetSampleDuration returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);
|
|
ret = IMFSample_Release(input_sample);
|
|
ok(ret <= 1, "Release returned %ld\n", ret);
|
|
|
|
hr = MFCreateCollection(&output_samples);
|
|
ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr);
|
|
|
|
output_sample = create_sample(NULL, transform_tests[j].expect_output_info->cbSize);
|
|
for (i = 0; SUCCEEDED(hr = check_mft_process_output(transform, output_sample, &output_status)); i++)
|
|
{
|
|
winetest_push_context("%lu", i);
|
|
ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr);
|
|
hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample);
|
|
ok(hr == S_OK, "AddElement returned %#lx\n", hr);
|
|
ref = IMFSample_Release(output_sample);
|
|
ok(ref == 1, "Release returned %ld\n", ref);
|
|
output_sample = create_sample(NULL, transform_tests[j].expect_output_info->cbSize);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
ok(i == 1, "got %lu output samples\n", i);
|
|
|
|
ret = check_mf_sample_collection(output_samples, transform_tests[j].output_sample_desc,
|
|
transform_tests[j].result_bitmap);
|
|
ok(ret <= transform_tests[j].delta, "got %lu%% diff\n", ret);
|
|
IMFCollection_Release(output_samples);
|
|
winetest_pop_context();
|
|
}
|
|
|
|
skip_tests:
|
|
ret = IMFTransform_Release(transform);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
failed:
|
|
winetest_pop_context();
|
|
CoUninitialize();
|
|
}
|
|
|
|
static void test_wmv_decoder_dmo_input_type(void)
|
|
{
|
|
const GUID *input_subtypes[] =
|
|
{
|
|
&MEDIASUBTYPE_WMV1,
|
|
&MEDIASUBTYPE_WMV2,
|
|
&MEDIASUBTYPE_WMVA,
|
|
&MEDIASUBTYPE_WMVP,
|
|
&MEDIASUBTYPE_WVP2,
|
|
&MFVideoFormat_WMV_Unknown,
|
|
&MEDIASUBTYPE_WVC1,
|
|
&MEDIASUBTYPE_WMV3,
|
|
&MFVideoFormat_VC1S,
|
|
};
|
|
|
|
DMO_MEDIA_TYPE *good_input_type, *bad_input_type, type;
|
|
char buffer_good_input[2048], buffer_bad_input[2048];
|
|
const GUID *input_subtype = input_subtypes[0];
|
|
LONG width = 16, height = 16;
|
|
VIDEOINFOHEADER *header;
|
|
DWORD count, i, ret;
|
|
IMediaObject *dmo;
|
|
HRESULT hr;
|
|
|
|
winetest_push_context("wmvdec");
|
|
|
|
if (!has_video_processor)
|
|
{
|
|
win_skip("Skipping WMV decoder DMO tests on Win7.\n");
|
|
winetest_pop_context();
|
|
return;
|
|
}
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "CoInitialize failed, hr %#lx.\n", hr);
|
|
|
|
if (FAILED(hr = CoCreateInstance(&CLSID_CWMVDecMediaObject, NULL, CLSCTX_INPROC_SERVER, &IID_IMediaObject, (void **)&dmo)))
|
|
{
|
|
CoUninitialize();
|
|
winetest_pop_context();
|
|
return;
|
|
}
|
|
|
|
good_input_type = (void *)buffer_good_input;
|
|
bad_input_type = (void *)buffer_bad_input;
|
|
init_dmo_media_type_video(good_input_type, input_subtype, width, height);
|
|
memset(bad_input_type, 0, sizeof(buffer_bad_input));
|
|
header = (void *)(good_input_type + 1);
|
|
|
|
/* Test GetInputType. */
|
|
count = ARRAY_SIZE(input_subtypes);
|
|
hr = IMediaObject_GetInputType(dmo, 1, 0, NULL);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputType(dmo, 1, 0, &type);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputType(dmo, 1, count, &type);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputType(dmo, 0, count, &type);
|
|
ok(hr == DMO_E_NO_MORE_ITEMS, "GetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputType(dmo, 0, count, NULL);
|
|
ok(hr == DMO_E_NO_MORE_ITEMS, "GetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputType(dmo, 0, 0xdeadbeef, NULL);
|
|
ok(hr == DMO_E_NO_MORE_ITEMS, "GetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputType(dmo, 0, count - 1, NULL);
|
|
ok(hr == S_OK, "GetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputType(dmo, 0, count - 1, &type);
|
|
ok(hr == S_OK, "GetInputType returned %#lx.\n", hr);
|
|
MoFreeMediaType(&type);
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMediaObject_GetInputType(dmo, 0, ++i, &type)))
|
|
{
|
|
winetest_push_context("in %lu", i);
|
|
|
|
memset(good_input_type, 0, sizeof(*good_input_type));
|
|
good_input_type->majortype = MEDIATYPE_Video;
|
|
good_input_type->subtype = *input_subtypes[i];
|
|
good_input_type->bTemporalCompression = TRUE;
|
|
check_dmo_media_type(&type, good_input_type);
|
|
|
|
MoFreeMediaType(&type);
|
|
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == DMO_E_NO_MORE_ITEMS, "GetInputType returned %#lx.\n", hr);
|
|
ok(i == count, "%lu types.\n", i);
|
|
|
|
/* Test SetInputType. */
|
|
hr = IMediaObject_SetInputType(dmo, 1, NULL, 0);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, bad_input_type, 0);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, good_input_type, 0);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, NULL, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, bad_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, NULL, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, bad_input_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, good_input_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, NULL, 0x4);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, bad_input_type, 0x4);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 1, good_input_type, 0x4);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_SetInputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR | DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR | 0x4);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, NULL, 0);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, NULL, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, NULL, 0x4);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_SetInputType(dmo, 0, bad_input_type, 0);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, bad_input_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, bad_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, bad_input_type, 0x4);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(input_subtypes); ++i)
|
|
{
|
|
const GUID *subtype = input_subtypes[i];
|
|
|
|
if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMV2)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_WMVA)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_WVP2)
|
|
|| IsEqualGUID(subtype, &MEDIASUBTYPE_WVC1)
|
|
|| IsEqualGUID(subtype, &MFVideoFormat_VC1S))
|
|
{
|
|
skip("Skipping SetInputType tests for video subtype %s.\n", debugstr_guid(subtype));
|
|
continue;
|
|
}
|
|
|
|
winetest_push_context("type %lu", i);
|
|
|
|
init_dmo_media_type_video(good_input_type, subtype, width, height);
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, 0);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, 0x4);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
|
|
winetest_pop_context();
|
|
}
|
|
|
|
init_dmo_media_type_video(good_input_type, input_subtype, width, height);
|
|
header->dwBitRate = 0xdeadbeef;
|
|
header->dwBitErrorRate = 0xdeadbeef;
|
|
header->AvgTimePerFrame = 0xdeadbeef;
|
|
header->bmiHeader.biPlanes = 0xdead;
|
|
header->bmiHeader.biBitCount = 0xdead;
|
|
header->bmiHeader.biSizeImage = 0xdeadbeef;
|
|
header->bmiHeader.biXPelsPerMeter = 0xdead;
|
|
header->bmiHeader.biYPelsPerMeter = 0xdead;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, 0);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
|
|
init_dmo_media_type_video(good_input_type, input_subtype, width, height);
|
|
good_input_type->majortype = MFMediaType_Default;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
|
|
init_dmo_media_type_video(good_input_type, &MEDIASUBTYPE_None, width, height);
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
|
|
init_dmo_media_type_video(good_input_type, input_subtype, width, height);
|
|
good_input_type->formattype = FORMAT_None;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
|
|
init_dmo_media_type_video(good_input_type, input_subtype, width, height);
|
|
good_input_type->cbFormat = 1;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
|
|
init_dmo_media_type_video(good_input_type, input_subtype, width, height);
|
|
good_input_type->pbFormat = NULL;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
|
|
init_dmo_media_type_video(good_input_type, input_subtype, width, height);
|
|
header->bmiHeader.biSize = 0;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
todo_wine
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
header->bmiHeader.biSize = 1;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
todo_wine
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
header->bmiHeader.biSize = 0xdeadbeef;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
todo_wine
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
|
|
init_dmo_media_type_video(good_input_type, input_subtype, width, height);
|
|
header->bmiHeader.biWidth = 0;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
todo_wine
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
header->bmiHeader.biWidth = -1;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
todo_wine
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
header->bmiHeader.biWidth = 4096 + 1;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
todo_wine
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
header->bmiHeader.biWidth = 4096;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
|
|
init_dmo_media_type_video(good_input_type, input_subtype, width, height);
|
|
header->bmiHeader.biHeight = 0;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
todo_wine
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
header->bmiHeader.biHeight = 4096 + 1;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
todo_wine
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
header->bmiHeader.biHeight = 4096;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
header->bmiHeader.biHeight = -4096;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
|
|
init_dmo_media_type_video(good_input_type, input_subtype, width, height);
|
|
header->bmiHeader.biCompression = 0;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
todo_wine
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetInputType returned %#lx.\n", hr);
|
|
header->bmiHeader.biCompression = 1;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
header->bmiHeader.biCompression = 2;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
header->bmiHeader.biCompression = 0xdeadbeef;
|
|
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
|
|
/* Release. */
|
|
ret = IMediaObject_Release(dmo);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
CoUninitialize();
|
|
winetest_pop_context();
|
|
}
|
|
|
|
static void test_wmv_decoder_dmo_output_type(void)
|
|
{
|
|
char buffer_good_output[2048], buffer_bad_output[2048], buffer_input[2048];
|
|
DMO_MEDIA_TYPE *good_output_type, *bad_output_type, *input_type, type;
|
|
const GUID* input_subtype = &MEDIASUBTYPE_WMV1;
|
|
LONG width = 16, height = 16;
|
|
DWORD count, i, ret;
|
|
IMediaObject *dmo;
|
|
HRESULT hr;
|
|
|
|
winetest_push_context("wmvdec");
|
|
|
|
if (!has_video_processor)
|
|
{
|
|
win_skip("Skipping WMV decoder DMO tests on Win7.\n");
|
|
winetest_pop_context();
|
|
return;
|
|
}
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "CoInitialize failed, hr %#lx.\n", hr);
|
|
|
|
if (FAILED(hr = CoCreateInstance(&CLSID_CWMVDecMediaObject, NULL, CLSCTX_INPROC_SERVER, &IID_IMediaObject, (void **)&dmo)))
|
|
{
|
|
CoUninitialize();
|
|
winetest_pop_context();
|
|
return;
|
|
}
|
|
|
|
/* Initialize media types. */
|
|
input_type = (void *)buffer_input;
|
|
good_output_type = (void *)buffer_good_output;
|
|
bad_output_type = (void *)buffer_bad_output;
|
|
init_dmo_media_type_video(input_type, input_subtype, width, height);
|
|
memset(bad_output_type, 0, sizeof(buffer_bad_output));
|
|
|
|
/* Test GetOutputType. */
|
|
hr = IMediaObject_GetOutputType(dmo, 1, 0, NULL);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputType(dmo, 0, 0, NULL);
|
|
ok(hr == S_OK, "GetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputType(dmo, 0, 0, &type);
|
|
ok(hr == DMO_E_TYPE_NOT_SET, "GetOutputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_SetInputType(dmo, 0, input_type, 0);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
|
|
count = ARRAY_SIZE(wmv_decoder_output_subtypes);
|
|
hr = IMediaObject_GetOutputType(dmo, 1, 0, NULL);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputType(dmo, 1, 0, &type);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputType(dmo, 1, count, &type);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputType(dmo, 0, count, &type);
|
|
ok(hr == DMO_E_NO_MORE_ITEMS, "GetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputType(dmo, 0, count, NULL);
|
|
todo_wine
|
|
ok(hr == S_OK, "GetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputType(dmo, 0, 0xdeadbeef, NULL);
|
|
todo_wine
|
|
ok(hr == S_OK, "GetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputType(dmo, 0, count - 1, NULL);
|
|
ok(hr == S_OK, "GetOutputType returned %#lx.\n", hr);
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMediaObject_GetOutputType(dmo, 0, ++i, &type)))
|
|
{
|
|
winetest_push_context("type %lu", i);
|
|
init_dmo_media_type_video(good_output_type, wmv_decoder_output_subtypes[i], width, height);
|
|
check_dmo_media_type(&type, good_output_type);
|
|
MoFreeMediaType(&type);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == DMO_E_NO_MORE_ITEMS, "GetInputType returned %#lx.\n", hr);
|
|
ok(i == count, "%lu types.\n", i);
|
|
|
|
/* Test SetOutputType. */
|
|
init_dmo_media_type_video(good_output_type, &MEDIASUBTYPE_RGB24, width, height);
|
|
hr = IMediaObject_SetInputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, NULL, 0);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, good_output_type, 0);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, 0);
|
|
ok(hr == E_POINTER, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, 0x4);
|
|
ok(hr == E_POINTER, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR | DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, bad_output_type, 0);
|
|
ok(hr == DMO_E_TYPE_NOT_SET, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, bad_output_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == DMO_E_TYPE_NOT_SET, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, 0);
|
|
ok(hr == DMO_E_TYPE_NOT_SET, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_TYPE_NOT_SET, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == DMO_E_TYPE_NOT_SET, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, 0x4);
|
|
ok(hr == DMO_E_TYPE_NOT_SET, "SetOutputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_SetInputType(dmo, 0, input_type, 0);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_SetOutputType(dmo, 1, NULL, 0);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, bad_output_type, 0);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, good_output_type, 0);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, NULL, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, bad_output_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, good_output_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, NULL, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, bad_output_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, good_output_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, NULL, 0x4);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, bad_output_type, 0x4);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 1, good_output_type, 0x4);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR | DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR | 0x4);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, 0);
|
|
ok(hr == E_POINTER, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == E_POINTER, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, NULL, 0x4);
|
|
ok(hr == E_POINTER, "SetOutputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_SetOutputType(dmo, 0, bad_output_type, 0);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, bad_output_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, bad_output_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, bad_output_type, 0x4);
|
|
ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "SetOutputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, 0);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, DMO_SET_TYPEF_CLEAR);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, DMO_SET_TYPEF_TEST_ONLY);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, 0x4);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
|
|
/* Release. */
|
|
ret = IMediaObject_Release(dmo);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
CoUninitialize();
|
|
winetest_pop_context();
|
|
}
|
|
|
|
static void test_wmv_decoder_dmo_get_size_info(void)
|
|
{
|
|
DWORD i, ret, size, alignment;
|
|
IMediaObject *dmo;
|
|
HRESULT hr;
|
|
|
|
winetest_push_context("wmvdec");
|
|
|
|
if (!has_video_processor)
|
|
{
|
|
win_skip("Skipping WMV decoder DMO tests on Win7.\n");
|
|
winetest_pop_context();
|
|
return;
|
|
}
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "CoInitialize failed, hr %#lx.\n", hr);
|
|
hr = CoCreateInstance(&CLSID_CWMVDecMediaObject, NULL, CLSCTX_INPROC_SERVER, &IID_IMediaObject, (void **)&dmo);
|
|
ok(hr == S_OK, "CoCreateInstance failed, hr %#lx.\n", hr);
|
|
|
|
/* Test GetOutputSizeInfo. */
|
|
hr = IMediaObject_GetOutputSizeInfo(dmo, 1, NULL, NULL);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputSizeInfo returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputSizeInfo(dmo, 0, NULL, NULL);
|
|
todo_wine
|
|
ok(hr == E_POINTER, "GetOutputSizeInfo returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputSizeInfo(dmo, 0, &size, NULL);
|
|
todo_wine
|
|
ok(hr == E_POINTER, "GetOutputSizeInfo returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputSizeInfo(dmo, 0, NULL, &alignment);
|
|
todo_wine
|
|
ok(hr == E_POINTER, "GetOutputSizeInfo returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetOutputSizeInfo(dmo, 0, &size, &alignment);
|
|
ok(hr == DMO_E_TYPE_NOT_SET, "GetOutputSizeInfo returned %#lx.\n", hr);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(wmv_decoder_output_subtypes); ++i)
|
|
{
|
|
const GUID *subtype = wmv_decoder_output_subtypes[i];
|
|
|
|
if (IsEqualGUID(subtype, &MEDIASUBTYPE_RGB565) || IsEqualGUID(subtype, &MEDIASUBTYPE_RGB8))
|
|
{
|
|
skip("Skipping GetOutputSizeInfo tests for output subtype %s.\n", debugstr_guid(subtype));
|
|
continue;
|
|
}
|
|
|
|
winetest_push_context("out %lu", i);
|
|
|
|
check_dmo_get_output_size_info_video(dmo, &MEDIASUBTYPE_WMV1, subtype, 16, 16);
|
|
check_dmo_get_output_size_info_video(dmo, &MEDIASUBTYPE_WMV1, subtype, 96, 96);
|
|
check_dmo_get_output_size_info_video(dmo, &MEDIASUBTYPE_WMV1, subtype, 320, 240);
|
|
|
|
winetest_pop_context();
|
|
}
|
|
|
|
ret = IMediaObject_Release(dmo);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
CoUninitialize();
|
|
winetest_pop_context();
|
|
}
|
|
|
|
static void test_wmv_decoder_media_object(void)
|
|
{
|
|
const GUID *const class_id = &CLSID_CWMVDecMediaObject;
|
|
|
|
const DWORD data_width = 96, data_height = 96;
|
|
const struct buffer_desc output_buffer_desc_nv12 =
|
|
{
|
|
.length = data_width * data_height * 3 / 2,
|
|
.compare = compare_nv12, .dump = dump_nv12, .rect = {.right = 82, .bottom = 84},
|
|
};
|
|
DWORD in_count, out_count, size, alignment, wmv_data_length, status, expected_status, diff;
|
|
struct media_buffer *input_media_buffer = NULL, *output_media_buffer = NULL;
|
|
DMO_OUTPUT_DATA_BUFFER output_data_buffer;
|
|
IMediaObject *media_object;
|
|
DMO_MEDIA_TYPE *type;
|
|
const BYTE *wmv_data;
|
|
char buffer[2048];
|
|
HRESULT hr;
|
|
ULONG ret;
|
|
|
|
winetest_push_context("wmvdec");
|
|
|
|
if (!has_video_processor)
|
|
{
|
|
win_skip("Skipping inconsistent WMV decoder media object tests on Win7.\n");
|
|
winetest_pop_context();
|
|
return;
|
|
}
|
|
|
|
type = (DMO_MEDIA_TYPE *)buffer;
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "CoInitialize failed, hr %#lx.\n", hr);
|
|
|
|
if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, &IID_IMediaObject, (void **)&media_object)))
|
|
{
|
|
CoUninitialize();
|
|
winetest_pop_context();
|
|
return;
|
|
}
|
|
|
|
/* Test GetStreamCount. */
|
|
in_count = out_count = 0xdeadbeef;
|
|
hr = IMediaObject_GetStreamCount(media_object, &in_count, &out_count);
|
|
ok(hr == S_OK, "GetStreamCount returned %#lx.\n", hr);
|
|
ok(in_count == 1, "Got unexpected in_count %lu.\n", in_count);
|
|
ok(out_count == 1, "Got unexpected in_count %lu.\n", out_count);
|
|
|
|
/* Test GetStreamCount with invalid arguments. */
|
|
in_count = out_count = 0xdeadbeef;
|
|
hr = IMediaObject_GetStreamCount(media_object, NULL, &out_count);
|
|
ok(hr == E_POINTER, "GetStreamCount returned %#lx.\n", hr);
|
|
ok(out_count == 0xdeadbeef, "Got unexpected out_count %lu.\n", out_count);
|
|
hr = IMediaObject_GetStreamCount(media_object, &in_count, NULL);
|
|
ok(hr == E_POINTER, "GetStreamCount returned %#lx.\n", hr);
|
|
ok(in_count == 0xdeadbeef, "Got unexpected in_count %lu.\n", in_count);
|
|
|
|
/* Test ProcessInput. */
|
|
load_resource(L"wmvencdata.bin", &wmv_data, &wmv_data_length);
|
|
wmv_data_length = *((DWORD *)wmv_data);
|
|
wmv_data += sizeof(DWORD);
|
|
hr = media_buffer_create(wmv_data_length, &input_media_buffer);
|
|
ok(hr == S_OK, "Failed to create input media buffer.\n");
|
|
memcpy(input_media_buffer->data, wmv_data, wmv_data_length);
|
|
input_media_buffer->length = wmv_data_length;
|
|
|
|
init_dmo_media_type_video(type, &MEDIASUBTYPE_WMV1, data_width, data_height);
|
|
hr = IMediaObject_SetInputType(media_object, 0, type, 0);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
init_dmo_media_type_video(type, &MEDIASUBTYPE_NV12, data_width, data_height);
|
|
hr = IMediaObject_SetOutputType(media_object, 0, type, 0);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_ProcessInput(media_object, 0, &input_media_buffer->IMediaBuffer_iface, 0, 0, 0);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx.\n", hr);
|
|
|
|
/* Test ProcessOutput. */
|
|
hr = IMediaObject_GetOutputSizeInfo(media_object, 0, &size, &alignment);
|
|
ok(hr == S_OK, "GetOutputSizeInfo returned %#lx.\n", hr);
|
|
hr = media_buffer_create(size, &output_media_buffer);
|
|
ok(hr == S_OK, "Failed to create output media buffer.\n");
|
|
output_data_buffer.pBuffer = &output_media_buffer->IMediaBuffer_iface;
|
|
output_data_buffer.dwStatus = 0xdeadbeef;
|
|
output_data_buffer.rtTimestamp = 0xdeadbeef;
|
|
output_data_buffer.rtTimelength = 0xdeadbeef;
|
|
hr = IMediaObject_ProcessOutput(media_object, 0, 1, &output_data_buffer, &status);
|
|
ok(hr == S_OK, "ProcessOutput returned %#lx.\n", hr);
|
|
expected_status = DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT | DMO_OUTPUT_DATA_BUFFERF_TIME | DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH;
|
|
ok(output_data_buffer.dwStatus == expected_status, "Got unexpected dwStatus %#lx.\n", output_data_buffer.dwStatus);
|
|
diff = check_dmo_output_data_buffer(&output_data_buffer, &output_buffer_desc_nv12, L"nv12frame.bmp", 0, 0);
|
|
ok(diff == 0, "Got %lu%% diff.\n", diff);
|
|
|
|
/* Test GetInputStatus. */
|
|
hr = IMediaObject_GetInputStatus(media_object, 0xdeadbeef, NULL);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputStatus returned %#lx.\n", hr);
|
|
|
|
status = 0xdeadbeef;
|
|
hr = IMediaObject_GetInputStatus(media_object, 0xdeadbeef, &status);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputStatus returned %#lx.\n", hr);
|
|
ok(status == 0xdeadbeef, "Unexpected status %#lx.\n", status);
|
|
|
|
hr = IMediaObject_GetInputStatus(media_object, 0, NULL);
|
|
ok(hr == E_POINTER, "GetInputStatus returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_GetInputStatus(media_object, 0, &status);
|
|
ok(hr == S_OK, "GetInputStatus returned %#lx.\n", hr);
|
|
ok(status == DMO_INPUT_STATUSF_ACCEPT_DATA, "Unexpected status %#lx.\n", status);
|
|
|
|
/* Test Discontinuity. */
|
|
hr = IMediaObject_Discontinuity(media_object, 0xdeadbeef);
|
|
ok(hr == DMO_E_INVALIDSTREAMINDEX, "Discontinuity returned %#lx.\n", hr);
|
|
hr = IMediaObject_Discontinuity(media_object, 0);
|
|
ok(hr == S_OK, "Discontinuity returned %#lx.\n", hr);
|
|
hr = IMediaObject_Discontinuity(media_object, 0);
|
|
ok(hr == S_OK, "Discontinuity returned %#lx.\n", hr);
|
|
hr = IMediaObject_GetInputStatus(media_object, 0, &status);
|
|
ok(hr == S_OK, "GetInputStatus returned %#lx.\n", hr);
|
|
ok(status == DMO_INPUT_STATUSF_ACCEPT_DATA, "Unexpected status %#lx.\n", status);
|
|
|
|
/* Test Flush. */
|
|
hr = IMediaObject_ProcessInput(media_object, 0, &input_media_buffer->IMediaBuffer_iface, 0, 0, 0);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx.\n", hr);
|
|
hr = IMediaObject_Flush(media_object);
|
|
ok(hr == S_OK, "Flush returned %#lx.\n", hr);
|
|
hr = IMediaObject_Flush(media_object);
|
|
ok(hr == S_OK, "Flush returned %#lx.\n", hr);
|
|
output_media_buffer->length = 0;
|
|
output_data_buffer.pBuffer = &output_media_buffer->IMediaBuffer_iface;
|
|
output_data_buffer.dwStatus = 0xdeadbeef;
|
|
output_data_buffer.rtTimestamp = 0xdeadbeef;
|
|
output_data_buffer.rtTimelength = 0xdeadbeef;
|
|
hr = IMediaObject_ProcessOutput(media_object, 0, 1, &output_data_buffer, &status);
|
|
todo_wine
|
|
ok(hr == S_FALSE, "ProcessOutput returned %#lx.\n", hr);
|
|
ok(output_media_buffer->length == 0, "Unexpected length %#lx.\n", output_media_buffer->length);
|
|
|
|
/* Test ProcessOutput with setting framerate. */
|
|
init_dmo_media_type_video(type, &MEDIASUBTYPE_WMV1, data_width, data_height);
|
|
((VIDEOINFOHEADER *)type->pbFormat)->AvgTimePerFrame = 100000;
|
|
hr = IMediaObject_SetInputType(media_object, 0, type, 0);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
init_dmo_media_type_video(type, &MEDIASUBTYPE_NV12, data_width, data_height);
|
|
((VIDEOINFOHEADER *)type->pbFormat)->AvgTimePerFrame = 200000;
|
|
hr = IMediaObject_SetOutputType(media_object, 0, type, 0);
|
|
ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr);
|
|
|
|
hr = IMediaObject_ProcessInput(media_object, 0, &input_media_buffer->IMediaBuffer_iface, 0, 0, 300000);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx.\n", hr);
|
|
|
|
output_media_buffer->length = 0;
|
|
output_data_buffer.pBuffer = &output_media_buffer->IMediaBuffer_iface;
|
|
output_data_buffer.dwStatus = 0xdeadbeef;
|
|
output_data_buffer.rtTimestamp = 0xdeadbeef;
|
|
output_data_buffer.rtTimelength = 0xdeadbeef;
|
|
hr = IMediaObject_ProcessOutput(media_object, 0, 1, &output_data_buffer, &status);
|
|
ok(hr == S_OK, "ProcessOutput returned %#lx.\n", hr);
|
|
expected_status = DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT | DMO_OUTPUT_DATA_BUFFERF_TIME | DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH;
|
|
ok(output_data_buffer.dwStatus == expected_status, "Got unexpected dwStatus %#lx.\n", output_data_buffer.dwStatus);
|
|
diff = check_dmo_output_data_buffer(&output_data_buffer, &output_buffer_desc_nv12, L"nv12frame.bmp", 0, 300000);
|
|
ok(diff == 0, "Got %lu%% diff.\n", diff);
|
|
|
|
ret = IMediaBuffer_Release(&output_media_buffer->IMediaBuffer_iface);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
ret = IMediaBuffer_Release(&input_media_buffer->IMediaBuffer_iface);
|
|
todo_wine
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
ret = IMediaObject_Release(media_object);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
CoUninitialize();
|
|
winetest_pop_context();
|
|
}
|
|
|
|
static void test_color_convert(void)
|
|
{
|
|
const GUID *const class_id = &CLSID_CColorConvertDMO;
|
|
const struct transform_info expect_mft_info =
|
|
{
|
|
.name = L"Color Converter MFT",
|
|
.major_type = &MFMediaType_Video,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MFVideoFormat_YV12},
|
|
{.subtype = &MFVideoFormat_YUY2},
|
|
{.subtype = &MFVideoFormat_UYVY},
|
|
{.subtype = &MFVideoFormat_AYUV},
|
|
{.subtype = &MFVideoFormat_NV12},
|
|
{.subtype = &DMOVideoFormat_RGB32},
|
|
{.subtype = &DMOVideoFormat_RGB565},
|
|
{.subtype = &MFVideoFormat_I420},
|
|
{.subtype = &MFVideoFormat_IYUV},
|
|
{.subtype = &MFVideoFormat_YVYU},
|
|
{.subtype = &DMOVideoFormat_RGB24},
|
|
{.subtype = &DMOVideoFormat_RGB555},
|
|
{.subtype = &DMOVideoFormat_RGB8},
|
|
{.subtype = &MEDIASUBTYPE_V216},
|
|
{.subtype = &MEDIASUBTYPE_V410},
|
|
{.subtype = &MFVideoFormat_NV11},
|
|
{.subtype = &MFVideoFormat_Y41P},
|
|
{.subtype = &MFVideoFormat_Y41T},
|
|
{.subtype = &MFVideoFormat_Y42T},
|
|
{.subtype = &MFVideoFormat_YVU9},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MFVideoFormat_YV12},
|
|
{.subtype = &MFVideoFormat_YUY2},
|
|
{.subtype = &MFVideoFormat_UYVY},
|
|
{.subtype = &MFVideoFormat_AYUV},
|
|
{.subtype = &MFVideoFormat_NV12},
|
|
{.subtype = &DMOVideoFormat_RGB32},
|
|
{.subtype = &DMOVideoFormat_RGB565},
|
|
{.subtype = &MFVideoFormat_I420},
|
|
{.subtype = &MFVideoFormat_IYUV},
|
|
{.subtype = &MFVideoFormat_YVYU},
|
|
{.subtype = &DMOVideoFormat_RGB24},
|
|
{.subtype = &DMOVideoFormat_RGB555},
|
|
{.subtype = &DMOVideoFormat_RGB8},
|
|
{.subtype = &MEDIASUBTYPE_V216},
|
|
{.subtype = &MEDIASUBTYPE_V410},
|
|
{.subtype = &MFVideoFormat_NV11},
|
|
},
|
|
};
|
|
const struct transform_info expect_dmo_info =
|
|
{
|
|
.name = L"Color Converter DMO",
|
|
.major_type = &MEDIATYPE_Video,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MEDIASUBTYPE_YV12},
|
|
{.subtype = &MEDIASUBTYPE_YUY2},
|
|
{.subtype = &MEDIASUBTYPE_UYVY},
|
|
{.subtype = &MEDIASUBTYPE_AYUV},
|
|
{.subtype = &MEDIASUBTYPE_NV12},
|
|
{.subtype = &MEDIASUBTYPE_RGB32},
|
|
{.subtype = &MEDIASUBTYPE_RGB565},
|
|
{.subtype = &MEDIASUBTYPE_I420},
|
|
{.subtype = &MEDIASUBTYPE_IYUV},
|
|
{.subtype = &MEDIASUBTYPE_YVYU},
|
|
{.subtype = &MEDIASUBTYPE_RGB24},
|
|
{.subtype = &MEDIASUBTYPE_RGB555},
|
|
{.subtype = &MEDIASUBTYPE_RGB8},
|
|
{.subtype = &MEDIASUBTYPE_V216},
|
|
{.subtype = &MEDIASUBTYPE_V410},
|
|
{.subtype = &MEDIASUBTYPE_NV11},
|
|
{.subtype = &MEDIASUBTYPE_Y41P},
|
|
{.subtype = &MEDIASUBTYPE_Y41T},
|
|
{.subtype = &MEDIASUBTYPE_Y42T},
|
|
{.subtype = &MEDIASUBTYPE_YVU9},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MEDIASUBTYPE_YV12},
|
|
{.subtype = &MEDIASUBTYPE_YUY2},
|
|
{.subtype = &MEDIASUBTYPE_UYVY},
|
|
{.subtype = &MEDIASUBTYPE_AYUV},
|
|
{.subtype = &MEDIASUBTYPE_NV12},
|
|
{.subtype = &MEDIASUBTYPE_RGB32},
|
|
{.subtype = &MEDIASUBTYPE_RGB565},
|
|
{.subtype = &MEDIASUBTYPE_I420},
|
|
{.subtype = &MEDIASUBTYPE_IYUV},
|
|
{.subtype = &MEDIASUBTYPE_YVYU},
|
|
{.subtype = &MEDIASUBTYPE_RGB24},
|
|
{.subtype = &MEDIASUBTYPE_RGB555},
|
|
{.subtype = &MEDIASUBTYPE_RGB8},
|
|
{.subtype = &MEDIASUBTYPE_V216},
|
|
{.subtype = &MEDIASUBTYPE_V410},
|
|
{.subtype = &MEDIASUBTYPE_NV11},
|
|
},
|
|
};
|
|
|
|
static const media_type_desc expect_available_inputs[20] =
|
|
{
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YV12), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_UYVY), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_AYUV), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB565), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_I420), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_IYUV), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YVYU), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB24), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB555), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MEDIASUBTYPE_RGB8), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MEDIASUBTYPE_V216), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MEDIASUBTYPE_V410), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV11), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_Y41P), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_Y41T), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_Y42T), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YVU9), },
|
|
};
|
|
static const media_type_desc expect_available_outputs[16] =
|
|
{
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YV12), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_UYVY), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_AYUV), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB565), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_I420), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_IYUV), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YVYU), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB24), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB555), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MEDIASUBTYPE_RGB8), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MEDIASUBTYPE_V216), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MEDIASUBTYPE_V410), },
|
|
{ ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV11), },
|
|
};
|
|
static const media_type_desc expect_available_common =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
};
|
|
|
|
static const MFVideoArea actual_aperture = {.Area={82,84}};
|
|
static const DWORD actual_width = 96, actual_height = 96;
|
|
const struct attribute_desc input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16),
|
|
{0},
|
|
};
|
|
const struct attribute_desc output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
{0},
|
|
};
|
|
const struct attribute_desc output_type_desc_negative_stride[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, -actual_width * 4),
|
|
{0},
|
|
};
|
|
const struct attribute_desc output_type_desc_positive_stride[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 4),
|
|
{0},
|
|
};
|
|
const struct attribute_desc expect_input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12),
|
|
ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
|
|
{0},
|
|
};
|
|
const struct attribute_desc expect_output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 4),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4, .todo = TRUE),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1, .todo = TRUE),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1, .todo = TRUE),
|
|
{0},
|
|
};
|
|
const struct attribute_desc expect_output_type_desc_negative_stride[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, -actual_width * 4),
|
|
ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4, .todo = TRUE),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE),
|
|
ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1, .todo = TRUE),
|
|
ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1, .todo = TRUE),
|
|
{0},
|
|
};
|
|
const MFT_OUTPUT_STREAM_INFO output_info =
|
|
{
|
|
.cbSize = actual_width * actual_height * 4,
|
|
.cbAlignment = 1,
|
|
};
|
|
const MFT_INPUT_STREAM_INFO input_info =
|
|
{
|
|
.cbSize = actual_width * actual_height * 3 / 2,
|
|
.cbAlignment = 1,
|
|
};
|
|
|
|
const struct buffer_desc output_buffer_desc =
|
|
{
|
|
.length = actual_width * actual_height * 4,
|
|
.compare = compare_rgb32, .dump = dump_rgb32, .rect = {.right = 82, .bottom = 84},
|
|
};
|
|
const struct attribute_desc output_sample_attributes[] =
|
|
{
|
|
ATTR_UINT32(MFSampleExtension_CleanPoint, 0, .todo = TRUE),
|
|
{0},
|
|
};
|
|
const struct sample_desc output_sample_desc =
|
|
{
|
|
.attributes = output_sample_attributes,
|
|
.sample_time = 0, .sample_duration = 10000000,
|
|
.buffer_count = 1, .buffers = &output_buffer_desc,
|
|
};
|
|
const struct transform_desc
|
|
{
|
|
const struct attribute_desc *output_type_desc;
|
|
const struct attribute_desc *expect_output_type_desc;
|
|
const WCHAR *result_bitmap;
|
|
ULONG delta;
|
|
}
|
|
color_conversion_tests[] =
|
|
{
|
|
|
|
{
|
|
/* YUV -> RGB */
|
|
.output_type_desc = output_type_desc,
|
|
.expect_output_type_desc = expect_output_type_desc,
|
|
.result_bitmap = L"rgb32frame.bmp",
|
|
.delta = 4, /* Windows return 0, Wine needs 4 */
|
|
},
|
|
|
|
{
|
|
/* YUV -> RGB (negative stride) */
|
|
.output_type_desc = output_type_desc_negative_stride,
|
|
.expect_output_type_desc = expect_output_type_desc_negative_stride,
|
|
.result_bitmap = L"rgb32frame-flip.bmp",
|
|
.delta = 6,
|
|
},
|
|
|
|
{
|
|
/* YUV -> RGB (positive stride) */
|
|
.output_type_desc = output_type_desc_positive_stride,
|
|
.expect_output_type_desc = expect_output_type_desc,
|
|
.result_bitmap = L"rgb32frame.bmp",
|
|
.delta = 4, /* Windows return 0, Wine needs 4 */
|
|
},
|
|
|
|
};
|
|
|
|
MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Video, MFVideoFormat_NV12};
|
|
MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Video, MFVideoFormat_I420};
|
|
IMFSample *input_sample, *output_sample;
|
|
IMFCollection *output_samples;
|
|
DWORD length, output_status;
|
|
const BYTE *nv12frame_data;
|
|
ULONG nv12frame_data_len;
|
|
IMFMediaType *media_type;
|
|
IMFTransform *transform;
|
|
ULONG i, ret, ref;
|
|
HRESULT hr;
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr);
|
|
|
|
winetest_push_context("colorconv");
|
|
|
|
if (!check_mft_enum(MFT_CATEGORY_VIDEO_EFFECT, &input_type, &output_type, class_id))
|
|
goto failed;
|
|
check_mft_get_info(class_id, &expect_mft_info);
|
|
check_dmo_get_info(class_id, &expect_dmo_info);
|
|
|
|
if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER,
|
|
&IID_IMFTransform, (void **)&transform)))
|
|
goto failed;
|
|
|
|
check_interface(transform, &IID_IMFTransform, TRUE);
|
|
check_interface(transform, &IID_IMediaObject, TRUE);
|
|
check_interface(transform, &IID_IPropertyStore, TRUE);
|
|
todo_wine
|
|
check_interface(transform, &IID_IPropertyBag, FALSE);
|
|
todo_wine
|
|
check_interface(transform, &IID_IMFRealTimeClient, TRUE);
|
|
/* check_interface(transform, &IID_IWMColorConvProps, TRUE); */
|
|
|
|
check_mft_optional_methods(transform, 1);
|
|
check_mft_get_attributes(transform, NULL, FALSE);
|
|
check_mft_get_input_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
|
|
check_mft_get_output_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("out %lu", i);
|
|
ok(hr == S_OK, "GetOutputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, expect_available_common, -1);
|
|
check_media_type(media_type, expect_available_outputs[i], -1);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx\n", hr);
|
|
ok(i == 16, "%lu output media types\n", i);
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetInputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("in %lu", i);
|
|
ok(hr == S_OK, "GetInputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, expect_available_common, -1);
|
|
check_media_type(media_type, expect_available_inputs[i], -1);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetInputAvailableType returned %#lx\n", hr);
|
|
ok(i == 20, "%lu input media types\n", i);
|
|
|
|
check_mft_set_input_type_required(transform, input_type_desc);
|
|
check_mft_set_input_type(transform, input_type_desc);
|
|
check_mft_get_input_current_type_(transform, expect_input_type_desc, FALSE, TRUE);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(color_conversion_tests); i++)
|
|
{
|
|
winetest_push_context("color conversion #%lu", i);
|
|
check_mft_set_output_type_required(transform, color_conversion_tests[i].output_type_desc);
|
|
check_mft_set_output_type(transform, color_conversion_tests[i].output_type_desc, S_OK);
|
|
check_mft_get_output_current_type_(transform, color_conversion_tests[i].expect_output_type_desc, FALSE);
|
|
|
|
check_mft_get_input_stream_info(transform, S_OK, &input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, &output_info);
|
|
|
|
load_resource(L"nv12frame.bmp", &nv12frame_data, &nv12frame_data_len);
|
|
/* skip BMP header and RGB data from the dump */
|
|
length = *(DWORD *)(nv12frame_data + 2);
|
|
nv12frame_data_len = nv12frame_data_len - length;
|
|
nv12frame_data = nv12frame_data + length;
|
|
ok(nv12frame_data_len == 13824, "got length %lu\n", nv12frame_data_len);
|
|
|
|
input_sample = create_sample(nv12frame_data, nv12frame_data_len);
|
|
hr = IMFSample_SetSampleTime(input_sample, 0);
|
|
ok(hr == S_OK, "SetSampleTime returned %#lx\n", hr);
|
|
hr = IMFSample_SetSampleDuration(input_sample, 10000000);
|
|
ok(hr == S_OK, "SetSampleDuration returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0);
|
|
ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr);
|
|
ret = IMFSample_Release(input_sample);
|
|
ok(ret <= 1, "Release returned %ld\n", ret);
|
|
|
|
hr = MFCreateCollection(&output_samples);
|
|
ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr);
|
|
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample);
|
|
ok(hr == S_OK, "AddElement returned %#lx\n", hr);
|
|
ref = IMFSample_Release(output_sample);
|
|
ok(ref == 1, "Release returned %ld\n", ref);
|
|
|
|
ret = check_mf_sample_collection(output_samples, &output_sample_desc, color_conversion_tests[i].result_bitmap);
|
|
ok(ret <= color_conversion_tests[i].delta, "got %lu%% diff\n", ret);
|
|
IMFCollection_Release(output_samples);
|
|
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
hr = IMFSample_GetTotalLength(output_sample, &length);
|
|
ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr);
|
|
ok(length == 0, "got length %lu\n", length);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
|
|
ret = IMFTransform_Release(transform);
|
|
ok(ret == 0, "Release returned %ld\n", ret);
|
|
|
|
failed:
|
|
winetest_pop_context();
|
|
CoUninitialize();
|
|
}
|
|
|
|
static void test_video_processor(void)
|
|
{
|
|
const GUID *const class_id = &CLSID_VideoProcessorMFT;
|
|
const struct transform_info expect_mft_info =
|
|
{
|
|
.name = L"Microsoft Video Processor MFT",
|
|
.major_type = &MFMediaType_Video,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MFVideoFormat_IYUV},
|
|
{.subtype = &MFVideoFormat_YV12},
|
|
{.subtype = &MFVideoFormat_NV12},
|
|
{.subtype = &MFVideoFormat_YUY2},
|
|
{.subtype = &MFVideoFormat_ARGB32},
|
|
{.subtype = &MFVideoFormat_RGB32},
|
|
{.subtype = &MFVideoFormat_NV11},
|
|
{.subtype = &MFVideoFormat_AYUV},
|
|
{.subtype = &MFVideoFormat_UYVY},
|
|
{.subtype = &MEDIASUBTYPE_P208},
|
|
{.subtype = &MFVideoFormat_RGB24},
|
|
{.subtype = &MFVideoFormat_RGB555},
|
|
{.subtype = &MFVideoFormat_RGB565},
|
|
{.subtype = &MFVideoFormat_RGB8},
|
|
{.subtype = &MFVideoFormat_I420},
|
|
{.subtype = &MFVideoFormat_Y216},
|
|
{.subtype = &MFVideoFormat_v410},
|
|
{.subtype = &MFVideoFormat_Y41P},
|
|
{.subtype = &MFVideoFormat_Y41T},
|
|
{.subtype = &MFVideoFormat_Y42T},
|
|
{.subtype = &MFVideoFormat_YVYU},
|
|
{.subtype = &MFVideoFormat_420O},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MFVideoFormat_IYUV},
|
|
{.subtype = &MFVideoFormat_YV12},
|
|
{.subtype = &MFVideoFormat_NV12},
|
|
{.subtype = &MFVideoFormat_YUY2},
|
|
{.subtype = &MFVideoFormat_ARGB32},
|
|
{.subtype = &MFVideoFormat_RGB32},
|
|
{.subtype = &MFVideoFormat_NV11},
|
|
{.subtype = &MFVideoFormat_AYUV},
|
|
{.subtype = &MFVideoFormat_UYVY},
|
|
{.subtype = &MEDIASUBTYPE_P208},
|
|
{.subtype = &MFVideoFormat_RGB24},
|
|
{.subtype = &MFVideoFormat_RGB555},
|
|
{.subtype = &MFVideoFormat_RGB565},
|
|
{.subtype = &MFVideoFormat_RGB8},
|
|
{.subtype = &MFVideoFormat_I420},
|
|
{.subtype = &MFVideoFormat_Y216},
|
|
{.subtype = &MFVideoFormat_v410},
|
|
{.subtype = &MFVideoFormat_Y41P},
|
|
{.subtype = &MFVideoFormat_Y41T},
|
|
{.subtype = &MFVideoFormat_Y42T},
|
|
{.subtype = &MFVideoFormat_YVYU},
|
|
},
|
|
};
|
|
const struct input_type_desc
|
|
{
|
|
GUID guid;
|
|
BOOL optional;
|
|
}
|
|
expect_available_inputs[] =
|
|
{
|
|
{MFVideoFormat_L8, .optional = TRUE /* >= W10 */},
|
|
{MFVideoFormat_L16, .optional = TRUE /* >= W10 */},
|
|
{MFAudioFormat_MPEG, .optional = TRUE /* >= W10 */},
|
|
{MFVideoFormat_IYUV},
|
|
{MFVideoFormat_YV12},
|
|
{MFVideoFormat_NV12},
|
|
{MFVideoFormat_NV21, .optional = TRUE /* >= W11 */},
|
|
{MFVideoFormat_420O},
|
|
{MFVideoFormat_P010, .optional = TRUE /* >= W10 */},
|
|
{MFVideoFormat_P016, .optional = TRUE /* >= W10 */},
|
|
{MFVideoFormat_UYVY},
|
|
{MFVideoFormat_YUY2},
|
|
{MFVideoFormat_P208},
|
|
{MFVideoFormat_NV11},
|
|
{MFVideoFormat_AYUV},
|
|
{MFVideoFormat_ARGB32},
|
|
{MFVideoFormat_ABGR32, .optional = TRUE /* >= W10 */},
|
|
{MFVideoFormat_RGB32},
|
|
{MFVideoFormat_A2R10G10B10, .optional = TRUE /* >= W10 */},
|
|
{MFVideoFormat_A16B16G16R16F, .optional = TRUE /* >= W10 */},
|
|
{MFVideoFormat_RGB24},
|
|
{MFVideoFormat_I420},
|
|
{MFVideoFormat_YVYU},
|
|
{MFVideoFormat_RGB555},
|
|
{MFVideoFormat_RGB565},
|
|
{MFVideoFormat_RGB8},
|
|
{MFVideoFormat_Y216},
|
|
{MFVideoFormat_v410},
|
|
{MFVideoFormat_Y41P},
|
|
{MFVideoFormat_Y41T},
|
|
{MFVideoFormat_Y42T},
|
|
};
|
|
const GUID expect_available_outputs[] =
|
|
{
|
|
MFVideoFormat_A2R10G10B10, /* enumerated with MFVideoFormat_P010 input */
|
|
MFVideoFormat_P010, /* enumerated with MFVideoFormat_A2R10G10B10 input */
|
|
MFVideoFormat_YUY2,
|
|
MFVideoFormat_IYUV,
|
|
MFVideoFormat_I420,
|
|
MFVideoFormat_NV12,
|
|
MFVideoFormat_RGB24,
|
|
MFVideoFormat_ARGB32,
|
|
MFVideoFormat_RGB32,
|
|
MFVideoFormat_YV12,
|
|
MFVideoFormat_Y216, /* enumerated with some input formats */
|
|
MFVideoFormat_UYVY, /* enumerated with some input formats */
|
|
MFVideoFormat_YVYU, /* enumerated with some input formats */
|
|
MFVideoFormat_AYUV,
|
|
MFVideoFormat_RGB555,
|
|
MFVideoFormat_RGB565,
|
|
MFVideoFormat_AYUV, /* some inputs enumerate MFVideoFormat_AYUV after RGB565 */
|
|
MFVideoFormat_NV12, /* P010 enumerates NV12 after (A)RGB32 formats */
|
|
MFVideoFormat_A16B16G16R16F, /* enumerated with MFVideoFormat_P010 input */
|
|
MFVideoFormat_NV21, /* enumerated with some input formats */
|
|
};
|
|
static const media_type_desc expect_available_common =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
|
};
|
|
static const struct attribute_desc expect_transform_attributes[] =
|
|
{
|
|
ATTR_UINT32(MFT_SUPPORT_3DVIDEO, 1, .todo = TRUE),
|
|
/* ATTR_UINT32(MF_SA_D3D_AWARE, 1), only on W7 */
|
|
{0},
|
|
};
|
|
|
|
static const MFVideoArea actual_aperture = {.Area={82,84}};
|
|
static const DWORD actual_width = 96, actual_height = 96;
|
|
const struct attribute_desc rgb32_with_aperture[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16),
|
|
{0},
|
|
};
|
|
const struct attribute_desc nv12_default_stride[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
{0},
|
|
};
|
|
const struct attribute_desc rgb32_default_stride[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
{0},
|
|
};
|
|
const struct attribute_desc rgb32_negative_stride[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, -actual_width * 4),
|
|
{0},
|
|
};
|
|
const struct attribute_desc rgb32_positive_stride[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 4),
|
|
{0},
|
|
};
|
|
const struct attribute_desc rgb555_default_stride[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB555, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
{0},
|
|
};
|
|
const struct attribute_desc rgb555_negative_stride[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB555, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, -actual_width * 2),
|
|
{0},
|
|
};
|
|
const struct attribute_desc rgb555_positive_stride[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB555, .required = TRUE),
|
|
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 2),
|
|
{0},
|
|
};
|
|
const MFT_OUTPUT_STREAM_INFO initial_output_info = {0};
|
|
const MFT_INPUT_STREAM_INFO initial_input_info = {0};
|
|
MFT_OUTPUT_STREAM_INFO output_info = {0};
|
|
MFT_INPUT_STREAM_INFO input_info = {0};
|
|
|
|
const struct attribute_desc output_sample_attributes[] =
|
|
{
|
|
ATTR_UINT32(MFSampleExtension_CleanPoint, 1, .todo = TRUE),
|
|
{0},
|
|
};
|
|
const struct buffer_desc rgb32_buffer_desc =
|
|
{
|
|
.length = actual_width * actual_height * 4,
|
|
.compare = compare_rgb32, .dump = dump_rgb32, .rect = {.top = 12, .right = 82, .bottom = 96},
|
|
};
|
|
const struct sample_desc rgb32_sample_desc =
|
|
{
|
|
.attributes = output_sample_attributes,
|
|
.sample_time = 0, .sample_duration = 10000000,
|
|
.buffer_count = 1, .buffers = &rgb32_buffer_desc,
|
|
};
|
|
|
|
const struct buffer_desc rgb555_buffer_desc =
|
|
{
|
|
.length = actual_width * actual_height * 2,
|
|
.compare = compare_rgb16, .dump = dump_rgb16, .rect = {.top = 12, .right = 82, .bottom = 96},
|
|
};
|
|
const struct sample_desc rgb555_sample_desc =
|
|
{
|
|
.attributes = output_sample_attributes,
|
|
.sample_time = 0, .sample_duration = 10000000,
|
|
.buffer_count = 1, .buffers = &rgb555_buffer_desc,
|
|
};
|
|
|
|
const struct buffer_desc nv12_buffer_desc =
|
|
{
|
|
.length = actual_width * actual_height * 3 / 2,
|
|
.compare = compare_nv12, .dump = dump_nv12, .rect = {.top = 12, .right = 82, .bottom = 96},
|
|
};
|
|
const struct sample_desc nv12_sample_desc =
|
|
{
|
|
.attributes = output_sample_attributes,
|
|
.sample_time = 0, .sample_duration = 10000000,
|
|
.buffer_count = 1, .buffers = &nv12_buffer_desc,
|
|
};
|
|
|
|
const struct transform_desc
|
|
{
|
|
const struct attribute_desc *input_type_desc;
|
|
const struct attribute_desc *output_type_desc;
|
|
const struct sample_desc *output_sample_desc;
|
|
const WCHAR *result_bitmap;
|
|
ULONG delta;
|
|
BOOL broken;
|
|
}
|
|
video_processor_tests[] =
|
|
{
|
|
{
|
|
.input_type_desc = nv12_default_stride, .output_type_desc = rgb32_default_stride,
|
|
.output_sample_desc = &rgb32_sample_desc, .result_bitmap = L"rgb32frame-flip.bmp",
|
|
.delta = 2, /* Windows returns 0, Wine needs 2 */
|
|
},
|
|
{
|
|
.input_type_desc = nv12_default_stride, .output_type_desc = rgb32_negative_stride,
|
|
.output_sample_desc = &rgb32_sample_desc, .result_bitmap = L"rgb32frame-flip.bmp",
|
|
.delta = 2, /* Windows returns 0, Wine needs 2 */
|
|
},
|
|
{
|
|
.input_type_desc = nv12_default_stride, .output_type_desc = rgb32_positive_stride,
|
|
.output_sample_desc = &rgb32_sample_desc, .result_bitmap = L"rgb32frame.bmp",
|
|
.delta = 6,
|
|
},
|
|
{
|
|
.input_type_desc = rgb32_default_stride, .output_type_desc = nv12_default_stride,
|
|
.output_sample_desc = &nv12_sample_desc, .result_bitmap = L"nv12frame-flip.bmp",
|
|
.delta = 2, /* Windows returns 0, Wine needs 2 */
|
|
},
|
|
{
|
|
.input_type_desc = rgb32_negative_stride, .output_type_desc = nv12_default_stride,
|
|
.output_sample_desc = &nv12_sample_desc, .result_bitmap = L"nv12frame-flip.bmp",
|
|
.delta = 2, /* Windows returns 0, Wine needs 2 */
|
|
},
|
|
{
|
|
.input_type_desc = rgb32_positive_stride, .output_type_desc = nv12_default_stride,
|
|
.output_sample_desc = &nv12_sample_desc, .result_bitmap = L"nv12frame.bmp",
|
|
.delta = 2, /* Windows returns 1, Wine needs 2 */
|
|
},
|
|
{
|
|
.input_type_desc = rgb32_negative_stride, .output_type_desc = rgb32_negative_stride,
|
|
.output_sample_desc = &rgb32_sample_desc, .result_bitmap = L"rgb32frame.bmp",
|
|
},
|
|
{
|
|
.input_type_desc = rgb32_negative_stride, .output_type_desc = rgb32_positive_stride,
|
|
.output_sample_desc = &rgb32_sample_desc, .result_bitmap = L"rgb32frame-flip.bmp",
|
|
.delta = 3, /* Windows returns 3 */
|
|
},
|
|
{
|
|
.input_type_desc = rgb32_positive_stride, .output_type_desc = rgb32_negative_stride,
|
|
.output_sample_desc = &rgb32_sample_desc, .result_bitmap = L"rgb32frame-flip.bmp",
|
|
.delta = 3, /* Windows returns 3 */
|
|
},
|
|
{
|
|
.input_type_desc = rgb32_positive_stride, .output_type_desc = rgb32_positive_stride,
|
|
.output_sample_desc = &rgb32_sample_desc, .result_bitmap = L"rgb32frame.bmp",
|
|
},
|
|
{
|
|
.input_type_desc = rgb32_with_aperture, .output_type_desc = rgb32_with_aperture,
|
|
.output_sample_desc = &rgb32_sample_desc, .result_bitmap = L"rgb32frame.bmp",
|
|
.broken = TRUE /* old Windows version incorrectly rescale */
|
|
},
|
|
{
|
|
.input_type_desc = rgb32_default_stride, .output_type_desc = rgb555_default_stride,
|
|
.output_sample_desc = &rgb555_sample_desc, .result_bitmap = L"rgb555frame.bmp",
|
|
},
|
|
{
|
|
.input_type_desc = rgb32_default_stride, .output_type_desc = rgb555_negative_stride,
|
|
.output_sample_desc = &rgb555_sample_desc, .result_bitmap = L"rgb555frame.bmp",
|
|
},
|
|
{
|
|
.input_type_desc = rgb32_default_stride, .output_type_desc = rgb555_positive_stride,
|
|
.output_sample_desc = &rgb555_sample_desc, .result_bitmap = L"rgb555frame-flip.bmp",
|
|
.delta = 3, /* Windows returns 0, Wine needs 3 */
|
|
},
|
|
{
|
|
.input_type_desc = rgb555_default_stride, .output_type_desc = rgb555_positive_stride,
|
|
.output_sample_desc = &rgb555_sample_desc, .result_bitmap = L"rgb555frame-flip.bmp",
|
|
.delta = 4, /* Windows returns 0, Wine needs 4 */
|
|
},
|
|
};
|
|
|
|
MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Video, MFVideoFormat_NV12};
|
|
MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Video, MFVideoFormat_I420};
|
|
const struct input_type_desc *expect_input = expect_available_inputs;
|
|
DWORD i, j, k, flags, length, output_status;
|
|
IMFSample *input_sample, *output_sample;
|
|
IMFMediaType *media_type, *media_type2;
|
|
IMFCollection *output_samples;
|
|
IMFTransform *transform;
|
|
IMFMediaBuffer *buffer;
|
|
const BYTE *input_data;
|
|
ULONG input_data_len;
|
|
UINT32 count;
|
|
HRESULT hr;
|
|
ULONG ret;
|
|
GUID guid;
|
|
LONG ref;
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr);
|
|
|
|
winetest_push_context("videoproc");
|
|
|
|
if (!check_mft_enum(MFT_CATEGORY_VIDEO_PROCESSOR, &input_type, &output_type, class_id))
|
|
goto failed;
|
|
check_mft_get_info(class_id, &expect_mft_info);
|
|
|
|
if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER,
|
|
&IID_IMFTransform, (void **)&transform)))
|
|
goto failed;
|
|
|
|
todo_wine
|
|
check_interface(transform, &IID_IMFVideoProcessorControl, TRUE);
|
|
todo_wine
|
|
check_interface(transform, &IID_IMFRealTimeClientEx, TRUE);
|
|
check_interface(transform, &IID_IMFMediaEventGenerator, FALSE);
|
|
check_interface(transform, &IID_IMFShutdown, FALSE);
|
|
|
|
hr = IMFTransform_GetInputStatus(transform, 0, &flags);
|
|
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_GetOutputStatus(transform, &flags);
|
|
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type);
|
|
ok(hr == MF_E_NO_MORE_TYPES, "Unexpected hr %#lx.\n", hr);
|
|
|
|
check_mft_get_input_current_type(transform, NULL);
|
|
check_mft_get_output_current_type(transform, NULL);
|
|
|
|
check_mft_get_input_stream_info(transform, S_OK, &initial_input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, &initial_output_info);
|
|
|
|
/* Configure stream types. */
|
|
for (i = 0;;++i)
|
|
{
|
|
if (FAILED(hr = IMFTransform_GetInputAvailableType(transform, 0, i, &media_type)))
|
|
{
|
|
ok(hr == MF_E_NO_MORE_TYPES, "Unexpected hr %#lx.\n", hr);
|
|
break;
|
|
}
|
|
|
|
hr = IMFTransform_GetInputAvailableType(transform, 0, i, &media_type2);
|
|
ok(hr == S_OK, "Failed to get available type, hr %#lx.\n", hr);
|
|
ok(media_type != media_type2, "Unexpected instance.\n");
|
|
ref = IMFMediaType_Release(media_type2);
|
|
ok(ref == 0, "Release returned %ld\n", ref);
|
|
|
|
hr = IMFMediaType_GetMajorType(media_type, &guid);
|
|
ok(hr == S_OK, "Failed to get major type, hr %#lx.\n", hr);
|
|
ok(IsEqualGUID(&guid, &MFMediaType_Video), "Unexpected major type.\n");
|
|
|
|
hr = IMFMediaType_GetCount(media_type, &count);
|
|
ok(hr == S_OK, "Failed to get attributes count, hr %#lx.\n", hr);
|
|
ok(count == 2, "Unexpected count %u.\n", count);
|
|
|
|
hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid);
|
|
ok(hr == S_OK, "Failed to get subtype, hr %#lx.\n", hr);
|
|
ok(is_supported_video_type(&guid), "Unexpected media type %s.\n", wine_dbgstr_guid(&guid));
|
|
|
|
hr = IMFTransform_SetInputType(transform, 0, media_type, MFT_SET_TYPE_TEST_ONLY);
|
|
ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_SetInputType(transform, 0, media_type, 0);
|
|
ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_GetOutputCurrentType(transform, 0, &media_type2);
|
|
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#lx.\n", hr);
|
|
|
|
/* FIXME: figure out if those require additional attributes or simply advertised but not supported */
|
|
if (IsEqualGUID(&guid, &MFVideoFormat_L8) || IsEqualGUID(&guid, &MFVideoFormat_L16)
|
|
|| IsEqualGUID(&guid, &MFVideoFormat_D16) || IsEqualGUID(&guid, &MFVideoFormat_420O)
|
|
|| IsEqualGUID(&guid, &MFVideoFormat_A16B16G16R16F))
|
|
{
|
|
ref = IMFMediaType_Release(media_type);
|
|
ok(ref == 0, "Release returned %ld\n", ref);
|
|
continue;
|
|
}
|
|
|
|
hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ((UINT64)16 << 32) | 16);
|
|
ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_SetInputType(transform, 0, media_type, MFT_SET_TYPE_TEST_ONLY);
|
|
ok(hr == S_OK, "Failed to test input type %s, hr %#lx.\n", wine_dbgstr_guid(&guid), hr);
|
|
|
|
hr = IMFTransform_SetInputType(transform, 0, media_type, 0);
|
|
ok(hr == S_OK, "Failed to test input type, hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type2);
|
|
ok(hr == S_OK, "Failed to get current type, hr %#lx.\n", hr);
|
|
ok(media_type != media_type2, "Unexpected instance.\n");
|
|
IMFMediaType_Release(media_type2);
|
|
|
|
hr = IMFTransform_GetInputStatus(transform, 0, &flags);
|
|
ok(hr == S_OK, "Failed to get input status, hr %#lx.\n", hr);
|
|
ok(flags == MFT_INPUT_STATUS_ACCEPT_DATA, "Unexpected input status %#lx.\n", flags);
|
|
|
|
input_info.cbSize = 0;
|
|
if (IsEqualGUID(&guid, &MFVideoFormat_NV21))
|
|
input_info.cbSize = 0x180;
|
|
else if (!IsEqualGUID(&guid, &MFVideoFormat_P208) && !IsEqualGUID(&guid, &MEDIASUBTYPE_Y41T)
|
|
&& !IsEqualGUID(&guid, &MEDIASUBTYPE_Y42T))
|
|
{
|
|
hr = MFCalculateImageSize(&guid, 16, 16, (UINT32 *)&input_info.cbSize);
|
|
todo_wine_if(IsEqualGUID(&guid, &MFVideoFormat_Y216)
|
|
|| IsEqualGUID(&guid, &MFVideoFormat_v410)
|
|
|| IsEqualGUID(&guid, &MFVideoFormat_Y41P))
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
}
|
|
check_mft_get_input_stream_info(transform, S_OK, &input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, &initial_output_info);
|
|
|
|
IMFMediaType_Release(media_type);
|
|
}
|
|
|
|
/* IYUV -> RGB32 */
|
|
hr = MFCreateMediaType(&media_type);
|
|
ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr);
|
|
|
|
hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video);
|
|
ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr);
|
|
|
|
hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_IYUV);
|
|
ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr);
|
|
|
|
hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ((UINT64)16 << 32) | 16);
|
|
ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_SetInputType(transform, 0, media_type, 0);
|
|
ok(hr == S_OK, "Failed to set input type, hr %#lx.\n", hr);
|
|
|
|
hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_RGB32);
|
|
ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_SetOutputType(transform, 0, media_type, 0);
|
|
ok(hr == S_OK, "Failed to set output type, hr %#lx.\n", hr);
|
|
|
|
hr = MFCalculateImageSize(&MFVideoFormat_IYUV, 16, 16, (UINT32 *)&input_info.cbSize);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
hr = MFCalculateImageSize(&MFVideoFormat_RGB32, 16, 16, (UINT32 *)&output_info.cbSize);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
check_mft_get_input_stream_info(transform, S_OK, &input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, &output_info);
|
|
|
|
hr = MFCreateSample(&input_sample);
|
|
ok(hr == S_OK, "Failed to create a sample, hr %#lx.\n", hr);
|
|
|
|
hr = MFCreateSample(&output_sample);
|
|
ok(hr == S_OK, "Failed to create a sample, hr %#lx.\n", hr);
|
|
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
todo_wine
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
todo_wine
|
|
ok(hr == S_OK, "Failed to push a sample, hr %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
todo_wine
|
|
ok(hr == MF_E_NOTACCEPTING, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
todo_wine
|
|
ok(hr == MF_E_NO_SAMPLE_TIMESTAMP, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = IMFSample_SetSampleTime(input_sample, 0);
|
|
ok(hr == S_OK, "Failed to set sample time, hr %#lx.\n", hr);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
todo_wine
|
|
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = MFCreateMemoryBuffer(1024 * 1024, &buffer);
|
|
ok(hr == S_OK, "Failed to create a buffer, hr %#lx.\n", hr);
|
|
|
|
hr = IMFSample_AddBuffer(input_sample, buffer);
|
|
ok(hr == S_OK, "Failed to add a buffer, hr %#lx.\n", hr);
|
|
|
|
hr = IMFSample_AddBuffer(output_sample, buffer);
|
|
ok(hr == S_OK, "Failed to add a buffer, hr %#lx.\n", hr);
|
|
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
todo_wine
|
|
ok(hr == S_OK || broken(FAILED(hr)) /* Win8 */, "Failed to get output buffer, hr %#lx.\n", hr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "Unexpected hr %#lx.\n", hr);
|
|
}
|
|
|
|
ref = IMFTransform_Release(transform);
|
|
ok(ref == 0, "Release returned %ld\n", ref);
|
|
|
|
ref = IMFMediaType_Release(media_type);
|
|
ok(ref == 0, "Release returned %ld\n", ref);
|
|
ref = IMFSample_Release(input_sample);
|
|
ok(ref == 0, "Release returned %ld\n", ref);
|
|
ref = IMFSample_Release(output_sample);
|
|
ok(ref == 0, "Release returned %ld\n", ref);
|
|
ref = IMFMediaBuffer_Release(buffer);
|
|
ok(ref == 0, "Release returned %ld\n", ref);
|
|
|
|
|
|
hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
|
|
check_interface(transform, &IID_IMFTransform, TRUE);
|
|
check_interface(transform, &IID_IMediaObject, FALSE);
|
|
check_interface(transform, &IID_IPropertyStore, FALSE);
|
|
check_interface(transform, &IID_IPropertyBag, FALSE);
|
|
|
|
check_mft_optional_methods(transform, 1);
|
|
check_mft_get_attributes(transform, expect_transform_attributes, TRUE);
|
|
check_mft_get_input_stream_info(transform, S_OK, &initial_input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, &initial_output_info);
|
|
|
|
hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type);
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx\n", hr);
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetInputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("in %lu", i);
|
|
|
|
ok(hr == S_OK, "GetInputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, expect_available_common, -1);
|
|
|
|
hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid);
|
|
ok(hr == S_OK, "GetGUID returned %#lx\n", hr);
|
|
|
|
while (!IsEqualGUID(&expect_input->guid, &guid))
|
|
{
|
|
if (!expect_input->optional)
|
|
break;
|
|
expect_input++;
|
|
}
|
|
ok(IsEqualGUID(&expect_input->guid, &guid), "got subtype %s\n", debugstr_guid(&guid));
|
|
expect_input++;
|
|
|
|
/* FIXME: Skip exotic input types which aren't directly accepted */
|
|
if (IsEqualGUID(&guid, &MFVideoFormat_L8) || IsEqualGUID(&guid, &MFVideoFormat_L16)
|
|
|| IsEqualGUID(&guid, &MFAudioFormat_MPEG) || IsEqualGUID(&guid, &MFVideoFormat_420O)
|
|
|| IsEqualGUID(&guid, &MFVideoFormat_A16B16G16R16F) /* w1064v1507 */)
|
|
{
|
|
IMFMediaType_Release(media_type);
|
|
winetest_pop_context();
|
|
continue;
|
|
}
|
|
|
|
hr = IMFTransform_SetInputType(transform, 0, media_type, 0);
|
|
ok(hr == MF_E_ATTRIBUTENOTFOUND, "SetInputType returned %#lx.\n", hr);
|
|
hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, (UINT64)actual_width << 32 | actual_height);
|
|
ok(hr == S_OK, "SetUINT64 returned %#lx.\n", hr);
|
|
hr = IMFTransform_SetInputType(transform, 0, media_type, 0);
|
|
ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
|
|
|
|
hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type2);
|
|
ok(hr == S_OK, "GetOutputAvailableType returned %#lx.\n", hr);
|
|
hr = IMFMediaType_IsEqual(media_type, media_type2, &flags);
|
|
ok(hr == S_OK, "IsEqual returned %#lx.\n", hr);
|
|
IMFMediaType_Release(media_type2);
|
|
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret == 1, "Release returned %lu\n", ret);
|
|
|
|
j = k = 0;
|
|
while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++j, &media_type)))
|
|
{
|
|
winetest_push_context("out %lu", j);
|
|
ok(hr == S_OK, "GetOutputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, expect_available_common, -1);
|
|
|
|
hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &guid);
|
|
ok(hr == S_OK, "GetGUID returned %#lx\n", hr);
|
|
|
|
for (; k < ARRAY_SIZE(expect_available_outputs); k++)
|
|
if (IsEqualGUID(&expect_available_outputs[k], &guid))
|
|
break;
|
|
ok(k < ARRAY_SIZE(expect_available_outputs), "got subtype %s\n", debugstr_guid(&guid));
|
|
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx\n", hr);
|
|
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetInputAvailableType returned %#lx\n", hr);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(video_processor_tests); i++)
|
|
{
|
|
const struct transform_desc *test = video_processor_tests + i;
|
|
|
|
winetest_push_context("transform #%lu", i);
|
|
|
|
check_mft_set_input_type_required(transform, test->input_type_desc);
|
|
check_mft_set_input_type(transform, test->input_type_desc);
|
|
check_mft_get_input_current_type(transform, test->input_type_desc);
|
|
|
|
check_mft_set_output_type_required(transform, test->output_type_desc);
|
|
check_mft_set_output_type(transform, test->output_type_desc, S_OK);
|
|
check_mft_get_output_current_type(transform, test->output_type_desc);
|
|
|
|
if (test->output_sample_desc == &nv12_sample_desc)
|
|
{
|
|
output_info.cbSize = actual_width * actual_height * 3 / 2;
|
|
check_mft_get_output_stream_info(transform, S_OK, &output_info);
|
|
}
|
|
else if (test->output_sample_desc == &rgb555_sample_desc)
|
|
{
|
|
output_info.cbSize = actual_width * actual_height * 2;
|
|
check_mft_get_output_stream_info(transform, S_OK, &output_info);
|
|
}
|
|
else
|
|
{
|
|
output_info.cbSize = actual_width * actual_height * 4;
|
|
check_mft_get_output_stream_info(transform, S_OK, &output_info);
|
|
}
|
|
|
|
if (test->input_type_desc == nv12_default_stride)
|
|
{
|
|
input_info.cbSize = actual_width * actual_height * 3 / 2;
|
|
check_mft_get_input_stream_info(transform, S_OK, &input_info);
|
|
|
|
load_resource(L"nv12frame.bmp", &input_data, &input_data_len);
|
|
/* skip BMP header and RGB data from the dump */
|
|
length = *(DWORD *)(input_data + 2);
|
|
input_data_len = input_data_len - length;
|
|
ok(input_data_len == 13824, "got length %lu\n", input_data_len);
|
|
input_data = input_data + length;
|
|
}
|
|
else if (test->input_type_desc == rgb555_default_stride)
|
|
{
|
|
input_info.cbSize = actual_width * actual_height * 2;
|
|
check_mft_get_input_stream_info(transform, S_OK, &input_info);
|
|
|
|
load_resource(L"rgb555frame.bmp", &input_data, &input_data_len);
|
|
/* skip BMP header and RGB data from the dump */
|
|
length = *(DWORD *)(input_data + 2 + 2 * sizeof(DWORD));
|
|
input_data_len -= length;
|
|
ok(input_data_len == 18432, "got length %lu\n", input_data_len);
|
|
input_data += length;
|
|
}
|
|
else
|
|
{
|
|
input_info.cbSize = actual_width * actual_height * 4;
|
|
check_mft_get_input_stream_info(transform, S_OK, &input_info);
|
|
|
|
load_resource(L"rgb32frame.bmp", &input_data, &input_data_len);
|
|
/* skip BMP header and RGB data from the dump */
|
|
length = *(DWORD *)(input_data + 2 + 2 * sizeof(DWORD));
|
|
input_data_len -= length;
|
|
ok(input_data_len == 36864, "got length %lu\n", input_data_len);
|
|
input_data += length;
|
|
}
|
|
|
|
input_sample = create_sample(input_data, input_data_len);
|
|
hr = IMFSample_SetSampleTime(input_sample, 0);
|
|
ok(hr == S_OK, "SetSampleTime returned %#lx\n", hr);
|
|
hr = IMFSample_SetSampleDuration(input_sample, 10000000);
|
|
ok(hr == S_OK, "SetSampleDuration returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr);
|
|
hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0);
|
|
ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr);
|
|
ret = IMFSample_Release(input_sample);
|
|
ok(ret <= 1, "Release returned %ld\n", ret);
|
|
|
|
hr = MFCreateCollection(&output_samples);
|
|
ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr);
|
|
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
|
|
ok(hr == S_OK || broken(hr == MF_E_SHUTDOWN) /* w8 */, "ProcessOutput returned %#lx\n", hr);
|
|
if (hr != S_OK)
|
|
{
|
|
win_skip("ProcessOutput returned MF_E_SHUTDOWN, skipping tests.\n");
|
|
}
|
|
else
|
|
{
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
|
|
hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample);
|
|
ok(hr == S_OK, "AddElement returned %#lx\n", hr);
|
|
ref = IMFSample_Release(output_sample);
|
|
ok(ref == 1, "Release returned %ld\n", ref);
|
|
|
|
ret = check_mf_sample_collection(output_samples, test->output_sample_desc, test->result_bitmap);
|
|
ok(ret <= test->delta || broken(test->broken), "got %lu%% diff\n", ret);
|
|
IMFCollection_Release(output_samples);
|
|
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
hr = IMFSample_GetTotalLength(output_sample, &length);
|
|
ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr);
|
|
ok(length == 0, "got length %lu\n", length);
|
|
}
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
|
|
ret = IMFTransform_Release(transform);
|
|
ok(ret == 0, "Release returned %ld\n", ret);
|
|
|
|
failed:
|
|
winetest_pop_context();
|
|
CoUninitialize();
|
|
}
|
|
|
|
static void test_mp3_decoder(void)
|
|
{
|
|
const GUID *const class_id = &CLSID_CMP3DecMediaObject;
|
|
const struct transform_info expect_mft_info =
|
|
{
|
|
.name = L"MP3 Decoder MFT",
|
|
.major_type = &MFMediaType_Audio,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MFAudioFormat_MP3},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MFAudioFormat_PCM},
|
|
},
|
|
};
|
|
const struct transform_info expect_dmo_info =
|
|
{
|
|
.name = L"MP3 Decoder DMO",
|
|
.major_type = &MEDIATYPE_Audio,
|
|
.inputs =
|
|
{
|
|
{.subtype = &MFAudioFormat_MP3},
|
|
},
|
|
.outputs =
|
|
{
|
|
{.subtype = &MEDIASUBTYPE_PCM},
|
|
},
|
|
};
|
|
|
|
static const ULONG mp3dec_block_size = 0x1200;
|
|
static const media_type_desc expect_available_inputs[] =
|
|
{
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_MP3),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
},
|
|
};
|
|
static const media_type_desc expect_available_outputs[] =
|
|
{
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 32),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 176400),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 8),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 88200),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 8),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 44100),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 2),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 32),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 88200),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 44100),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 2),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
},
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 8),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 22050),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 1),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
},
|
|
};
|
|
|
|
const struct attribute_desc input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_MP3, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050),
|
|
{0},
|
|
};
|
|
static const struct attribute_desc output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050, .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 2 * (16 / 8), .required = TRUE),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 2 * (16 / 8) * 22050, .required = TRUE),
|
|
{0},
|
|
};
|
|
const struct attribute_desc expect_input_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_MP3),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2),
|
|
ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1),
|
|
{0},
|
|
};
|
|
static const struct attribute_desc expect_output_type_desc[] =
|
|
{
|
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio),
|
|
ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM),
|
|
ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16),
|
|
ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2),
|
|
ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050),
|
|
ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4),
|
|
ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 22050 * 4),
|
|
ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
|
|
ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1),
|
|
{0},
|
|
};
|
|
const MFT_OUTPUT_STREAM_INFO output_info =
|
|
{
|
|
.cbSize = mp3dec_block_size,
|
|
.cbAlignment = 1,
|
|
};
|
|
const MFT_INPUT_STREAM_INFO input_info =
|
|
{
|
|
.cbAlignment = 1,
|
|
};
|
|
|
|
const struct buffer_desc output_buffer_desc[] =
|
|
{
|
|
{.length = 0x9c0, .compare = compare_pcm16},
|
|
{.length = mp3dec_block_size, .compare = compare_pcm16},
|
|
};
|
|
const struct attribute_desc output_sample_attributes[] =
|
|
{
|
|
ATTR_UINT32(mft_output_sample_incomplete, 1),
|
|
ATTR_UINT32(MFSampleExtension_CleanPoint, 1),
|
|
{0},
|
|
};
|
|
const struct sample_desc output_sample_desc[] =
|
|
{
|
|
{
|
|
.attributes = output_sample_attributes + 0,
|
|
.sample_time = 0, .sample_duration = 282993,
|
|
.buffer_count = 1, .buffers = output_buffer_desc + 0,
|
|
},
|
|
{
|
|
.attributes = output_sample_attributes + 0,
|
|
.sample_time = 282993, .sample_duration = 522449,
|
|
.buffer_count = 1, .buffers = output_buffer_desc + 1, .repeat_count = 18,
|
|
},
|
|
{
|
|
.attributes = output_sample_attributes + 1, /* not MFT_OUTPUT_DATA_BUFFER_INCOMPLETE */
|
|
.sample_time = 10209524, .sample_duration = 522449,
|
|
.buffer_count = 1, .buffers = output_buffer_desc + 1,
|
|
},
|
|
};
|
|
|
|
MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Audio, MFAudioFormat_PCM};
|
|
MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Audio, MFAudioFormat_MP3};
|
|
IMFSample *input_sample, *output_sample;
|
|
IMFCollection *output_samples;
|
|
DWORD length, output_status;
|
|
IMFMediaType *media_type;
|
|
IMFTransform *transform;
|
|
const BYTE *mp3enc_data;
|
|
ULONG mp3enc_data_len;
|
|
ULONG i, ret, ref;
|
|
HRESULT hr;
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr);
|
|
|
|
winetest_push_context("mp3dec");
|
|
|
|
if (!check_mft_enum(MFT_CATEGORY_AUDIO_DECODER, &input_type, &output_type, class_id))
|
|
goto failed;
|
|
check_mft_get_info(class_id, &expect_mft_info);
|
|
check_dmo_get_info(class_id, &expect_dmo_info);
|
|
|
|
if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER,
|
|
&IID_IMFTransform, (void **)&transform)))
|
|
goto failed;
|
|
|
|
check_interface(transform, &IID_IMFTransform, TRUE);
|
|
check_interface(transform, &IID_IMediaObject, TRUE);
|
|
todo_wine
|
|
check_interface(transform, &IID_IPropertyStore, TRUE);
|
|
check_interface(transform, &IID_IPropertyBag, FALSE);
|
|
|
|
check_mft_optional_methods(transform, 1);
|
|
check_mft_get_attributes(transform, NULL, FALSE);
|
|
check_mft_get_input_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
|
|
check_mft_get_output_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
|
|
|
|
hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type);
|
|
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "GetOutputAvailableType returned %#lx\n", hr);
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetInputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("in %lu", i);
|
|
ok(hr == S_OK, "GetInputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, expect_available_inputs[i], -1);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
todo_wine
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetInputAvailableType returned %#lx\n", hr);
|
|
todo_wine
|
|
ok(i == ARRAY_SIZE(expect_available_inputs), "%lu input media types\n", i);
|
|
|
|
/* setting output media type first doesn't work */
|
|
check_mft_set_output_type(transform, output_type_desc, MF_E_TRANSFORM_TYPE_NOT_SET);
|
|
check_mft_get_output_current_type(transform, NULL);
|
|
|
|
check_mft_set_input_type_required(transform, input_type_desc);
|
|
check_mft_set_input_type(transform, input_type_desc);
|
|
check_mft_get_input_current_type(transform, expect_input_type_desc);
|
|
|
|
check_mft_get_input_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
|
|
check_mft_get_output_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
|
|
|
|
/* check new output media types */
|
|
|
|
i = -1;
|
|
while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &media_type)))
|
|
{
|
|
winetest_push_context("out %lu", i);
|
|
ok(hr == S_OK, "GetOutputAvailableType returned %#lx\n", hr);
|
|
check_media_type(media_type, expect_available_outputs[i], -1);
|
|
ret = IMFMediaType_Release(media_type);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx\n", hr);
|
|
ok(i == ARRAY_SIZE(expect_available_outputs), "%lu output media types\n", i);
|
|
|
|
check_mft_set_output_type_required(transform, output_type_desc);
|
|
check_mft_set_output_type(transform, output_type_desc, S_OK);
|
|
check_mft_get_output_current_type(transform, expect_output_type_desc);
|
|
|
|
check_mft_get_input_stream_info(transform, S_OK, &input_info);
|
|
check_mft_get_output_stream_info(transform, S_OK, &output_info);
|
|
|
|
load_resource(L"mp3encdata.bin", &mp3enc_data, &mp3enc_data_len);
|
|
ok(mp3enc_data_len == 6295, "got length %lu\n", mp3enc_data_len);
|
|
|
|
input_sample = create_sample(mp3enc_data, mp3enc_data_len);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);
|
|
ret = IMFSample_Release(input_sample);
|
|
ok(ret == 1, "Release returned %lu\n", ret);
|
|
|
|
input_sample = create_sample(mp3enc_data, mp3enc_data_len);
|
|
hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
|
|
ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr);
|
|
ret = IMFSample_Release(input_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0);
|
|
ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr);
|
|
|
|
hr = MFCreateCollection(&output_samples);
|
|
ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr);
|
|
|
|
/* first sample is broken */
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == MFT_OUTPUT_DATA_BUFFER_INCOMPLETE, "got output[0].dwStatus %#lx\n", output_status);
|
|
hr = IMFSample_GetTotalLength(output_sample, &length);
|
|
ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr);
|
|
ok(length == mp3dec_block_size /* Win8 */ || length == 0x9c0 /* Win10 */ || length == 0x900 /* Win7 */,
|
|
"got length %lu\n", length);
|
|
hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample);
|
|
ok(hr == S_OK, "AddElement returned %#lx\n", hr);
|
|
ref = IMFSample_Release(output_sample);
|
|
ok(ref == 1, "Release returned %ld\n", ref);
|
|
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
for (i = 0; SUCCEEDED(hr = check_mft_process_output(transform, output_sample, &output_status)); i++)
|
|
{
|
|
winetest_push_context("%lu", i);
|
|
ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr);
|
|
ok(!(output_status & ~MFT_OUTPUT_DATA_BUFFER_INCOMPLETE), "got output[0].dwStatus %#lx\n", output_status);
|
|
hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample);
|
|
ok(hr == S_OK, "AddElement returned %#lx\n", hr);
|
|
ref = IMFSample_Release(output_sample);
|
|
ok(ref == 1, "Release returned %ld\n", ref);
|
|
output_sample = create_sample(NULL, output_info.cbSize);
|
|
winetest_pop_context();
|
|
}
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
ok(i == 20 || broken(i == 41) /* Win7 */, "got %lu output samples\n", i);
|
|
|
|
if (broken(length != 0x9c0))
|
|
win_skip("Skipping MP3 decoder output sample checks on Win7 / Win8\n");
|
|
else
|
|
{
|
|
ret = check_mf_sample_collection(output_samples, output_sample_desc, L"mp3decdata.bin");
|
|
ok(ret == 0, "got %lu%% diff\n", ret);
|
|
}
|
|
IMFCollection_Release(output_samples);
|
|
|
|
output_sample = create_sample(NULL, mp3dec_block_size);
|
|
hr = check_mft_process_output(transform, output_sample, &output_status);
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
|
|
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
|
|
hr = IMFSample_GetTotalLength(output_sample, &length);
|
|
ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr);
|
|
ok(length == 0, "got length %lu\n", length);
|
|
ret = IMFSample_Release(output_sample);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
ret = IMFTransform_Release(transform);
|
|
ok(ret == 0, "Release returned %lu\n", ret);
|
|
|
|
failed:
|
|
winetest_pop_context();
|
|
CoUninitialize();
|
|
}
|
|
|
|
static HRESULT get_next_h264_output_sample(IMFTransform *transform, IMFSample **input_sample,
|
|
IMFSample *output_sample, MFT_OUTPUT_DATA_BUFFER *output, const BYTE **data, ULONG *data_len)
|
|
{
|
|
DWORD status;
|
|
HRESULT hr;
|
|
|
|
while (1)
|
|
{
|
|
status = 0;
|
|
memset(output, 0, sizeof(*output));
|
|
output[0].pSample = output_sample;
|
|
hr = IMFTransform_ProcessOutput(transform, 0, 1, output, &status);
|
|
if (hr != S_OK)
|
|
ok(output[0].pSample == output_sample, "got %p.\n", output[0].pSample);
|
|
if (hr != MF_E_TRANSFORM_NEED_MORE_INPUT)
|
|
return hr;
|
|
|
|
ok(status == 0, "got output[0].dwStatus %#lx\n", status);
|
|
hr = IMFTransform_ProcessInput(transform, 0, *input_sample, 0);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
IMFSample_Release(*input_sample);
|
|
*input_sample = next_h264_sample(data, data_len);
|
|
}
|
|
}
|
|
|
|
static void test_h264_with_dxgi_manager(void)
|
|
{
|
|
static const unsigned int set_width = 82, set_height = 84, aligned_width = 96, aligned_height = 96;
|
|
const struct attribute_desc output_sample_attributes[] =
|
|
{
|
|
ATTR_UINT32(MFSampleExtension_CleanPoint, 1),
|
|
{0},
|
|
};
|
|
const struct buffer_desc output_buffer_desc_nv12 =
|
|
{
|
|
.length = aligned_width * aligned_height * 3 / 2,
|
|
.compare = compare_nv12, .dump = dump_nv12, .rect = {.top=0, .left=0, .right = set_width, .bottom = set_height},
|
|
};
|
|
const struct sample_desc output_sample_desc_nv12 =
|
|
{
|
|
.attributes = output_sample_attributes,
|
|
.sample_time = 333667, .sample_duration = 333667,
|
|
.buffer_count = 1, .buffers = &output_buffer_desc_nv12,
|
|
};
|
|
|
|
IMFDXGIDeviceManager *manager = NULL;
|
|
IMFTrackedSample *tracked_sample;
|
|
IMFSample *input_sample, *sample;
|
|
MFT_OUTPUT_DATA_BUFFER output[1];
|
|
IMFTransform *transform = NULL;
|
|
ID3D11Multithread *multithread;
|
|
IMFCollection *output_samples;
|
|
MFT_OUTPUT_STREAM_INFO info;
|
|
IMFDXGIBuffer *dxgi_buffer;
|
|
unsigned int width, height;
|
|
D3D11_TEXTURE2D_DESC desc;
|
|
IMFMediaBuffer *buffer;
|
|
IMFAttributes *attribs;
|
|
ID3D11Texture2D *tex2d;
|
|
IMF2DBuffer2 *buffer2d;
|
|
ID3D11Device *d3d11;
|
|
IMFMediaType *type;
|
|
DWORD status, val;
|
|
UINT64 frame_size;
|
|
MFVideoArea area;
|
|
const BYTE *data;
|
|
ULONG data_len;
|
|
UINT32 value;
|
|
HRESULT hr;
|
|
UINT token;
|
|
GUID guid;
|
|
DWORD ret;
|
|
|
|
if (!pMFCreateDXGIDeviceManager)
|
|
{
|
|
win_skip("MFCreateDXGIDeviceManager() is not available, skipping tests.\n");
|
|
return;
|
|
}
|
|
|
|
hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_VIDEO_SUPPORT, NULL, 0,
|
|
D3D11_SDK_VERSION, &d3d11, NULL, NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
skip("D3D11 device creation failed, skipping tests.\n");
|
|
return;
|
|
}
|
|
|
|
hr = MFStartup(MF_VERSION, 0);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
|
|
hr = CoInitialize(NULL);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
|
|
hr = ID3D11Device_QueryInterface(d3d11, &IID_ID3D11Multithread, (void **)&multithread);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
ID3D11Multithread_SetMultithreadProtected(multithread, TRUE);
|
|
ID3D11Multithread_Release(multithread);
|
|
|
|
hr = pMFCreateDXGIDeviceManager(&token, &manager);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
hr = IMFDXGIDeviceManager_ResetDevice(manager, (IUnknown *)d3d11, token);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
ID3D11Device_Release(d3d11);
|
|
|
|
if (FAILED(hr = CoCreateInstance(&CLSID_MSH264DecoderMFT, NULL, CLSCTX_INPROC_SERVER,
|
|
&IID_IMFTransform, (void **)&transform)))
|
|
goto failed;
|
|
|
|
hr = IMFTransform_GetAttributes(transform, &attribs);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
|
|
hr = IMFAttributes_GetUINT32(attribs, &MF_SA_D3D11_AWARE, &value);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
ok(value == 1, "got %u.\n", value);
|
|
IMFAttributes_Release(attribs);
|
|
|
|
hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)transform);
|
|
ok(hr == E_NOINTERFACE, "got %#lx\n", hr);
|
|
|
|
hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)manager);
|
|
ok(hr == S_OK || broken(hr == E_NOINTERFACE), "got %#lx\n", hr);
|
|
if (hr == E_NOINTERFACE)
|
|
{
|
|
win_skip("No hardware video decoding support.\n");
|
|
goto failed;
|
|
}
|
|
|
|
hr = MFCreateMediaType(&type);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
hr = IMFMediaType_SetGUID(type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
hr = IMFMediaType_SetGUID(type, &MF_MT_SUBTYPE, &MFVideoFormat_H264);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
hr = IMFMediaType_SetUINT64(type, &MF_MT_FRAME_SIZE, 1088 | (1920ull << 32));
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
hr = IMFTransform_SetInputType(transform, 0, type, 0);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
IMFMediaType_Release(type);
|
|
|
|
hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &type);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
hr = IMFMediaType_SetGUID(type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
hr = IMFMediaType_SetGUID(type, &MF_MT_SUBTYPE, &MFVideoFormat_NV12);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
hr = IMFTransform_SetOutputType(transform, 0, type, 0);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
IMFMediaType_Release(type);
|
|
|
|
status = 0;
|
|
memset(output, 0, sizeof(output));
|
|
hr = IMFTransform_ProcessOutput(transform, 0, 1, output, &status);
|
|
ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "got %#lx\n", hr);
|
|
|
|
hr = IMFTransform_GetAttributes(transform, &attribs);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
hr = IMFAttributes_GetUINT32(attribs, &MF_SA_D3D11_AWARE, &value);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
ok(value == 1, "got %u.\n", value);
|
|
IMFAttributes_Release(attribs);
|
|
|
|
load_resource(L"h264data.bin", &data, &data_len);
|
|
|
|
input_sample = next_h264_sample(&data, &data_len);
|
|
hr = get_next_h264_output_sample(transform, &input_sample, NULL, output, &data, &data_len);
|
|
ok(hr == MF_E_TRANSFORM_STREAM_CHANGE, "got %#lx\n", hr);
|
|
ok(!output[0].pSample, "got %p.\n", output[0].pSample);
|
|
|
|
hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &type);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
width = frame_size >> 32;
|
|
height = frame_size & 0xffffffff;
|
|
ok(width == aligned_width, "got %u.\n", width);
|
|
ok(height == aligned_height, "got %u.\n", height);
|
|
memset(&area, 0xcc, sizeof(area));
|
|
hr = IMFMediaType_GetBlob(type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&area, sizeof(area), NULL);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
ok(!area.OffsetX.value && !area.OffsetX.fract, "got %d.%d.\n", area.OffsetX.value, area.OffsetX.fract);
|
|
ok(!area.OffsetY.value && !area.OffsetY.fract, "got %d.%d.\n", area.OffsetY.value, area.OffsetY.fract);
|
|
ok(area.Area.cx == set_width, "got %ld.\n", area.Area.cx);
|
|
ok(area.Area.cy == set_height, "got %ld.\n", area.Area.cy);
|
|
|
|
hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &guid);
|
|
ok(hr == S_OK, "Failed to get subtype, hr %#lx.\n", hr);
|
|
ok(IsEqualIID(&guid, &MEDIASUBTYPE_NV12), "got guid %s.\n", debugstr_guid(&guid));
|
|
|
|
hr = IMFTransform_SetOutputType(transform, 0, type, 0);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
IMFMediaType_Release(type);
|
|
|
|
hr = IMFTransform_GetOutputStreamInfo(transform, 0, &info);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
ok(info.dwFlags == (MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
|
|
| MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE | MFT_OUTPUT_STREAM_PROVIDES_SAMPLES), "got %#lx.\n", info.dwFlags);
|
|
|
|
hr = get_next_h264_output_sample(transform, &input_sample, NULL, output, &data, &data_len);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
ok(output[0].dwStatus == 0, "got %#lx.\n", status);
|
|
sample = output[0].pSample;
|
|
|
|
hr = IMFSample_QueryInterface(sample, &IID_IMFTrackedSample, (void **)&tracked_sample);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
IMFTrackedSample_Release(tracked_sample);
|
|
|
|
hr = IMFSample_GetBufferCount(sample, &val);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
ok(val == 1, "got %lu.\n", val);
|
|
hr = IMFSample_GetBufferByIndex(sample, 0, &buffer);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFDXGIBuffer, (void **)&dxgi_buffer);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer2, (void **)&buffer2d);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
|
|
hr = IMFDXGIBuffer_GetResource(dxgi_buffer, &IID_ID3D11Texture2D, (void **)&tex2d);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
memset(&desc, 0xcc, sizeof(desc));
|
|
ID3D11Texture2D_GetDesc(tex2d, &desc);
|
|
ok(desc.Format == DXGI_FORMAT_NV12, "got %u.\n", desc.Format);
|
|
ok(!desc.Usage, "got %u.\n", desc.Usage);
|
|
todo_wine ok(desc.BindFlags == D3D11_BIND_DECODER, "got %#x.\n", desc.BindFlags);
|
|
ok(!desc.CPUAccessFlags, "got %#x.\n", desc.CPUAccessFlags);
|
|
ok(!desc.MiscFlags, "got %#x.\n", desc.MiscFlags);
|
|
ok(desc.MipLevels == 1, "git %u.\n", desc.MipLevels);
|
|
ok(desc.Width == aligned_width, "got %u.\n", desc.Width);
|
|
ok(desc.Height == aligned_height, "got %u.\n", desc.Height);
|
|
|
|
ID3D11Texture2D_Release(tex2d);
|
|
IMFDXGIBuffer_Release(dxgi_buffer);
|
|
IMF2DBuffer2_Release(buffer2d);
|
|
IMFMediaBuffer_Release(buffer);
|
|
IMFSample_Release(sample);
|
|
|
|
status = 0;
|
|
hr = get_next_h264_output_sample(transform, &input_sample, NULL, output, &data, &data_len);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
ok(sample != output[0].pSample, "got %p.\n", output[0].pSample);
|
|
sample = output[0].pSample;
|
|
|
|
hr = MFCreateCollection(&output_samples);
|
|
ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr);
|
|
|
|
hr = IMFCollection_AddElement(output_samples, (IUnknown *)sample);
|
|
ok(hr == S_OK, "AddElement returned %#lx\n", hr);
|
|
IMFSample_Release(sample);
|
|
|
|
ret = check_mf_sample_collection(output_samples, &output_sample_desc_nv12, L"nv12frame.bmp");
|
|
ok(ret == 0, "got %lu%% diff\n", ret);
|
|
IMFCollection_Release(output_samples);
|
|
|
|
memset(&info, 0xcc, sizeof(info));
|
|
hr = IMFTransform_GetOutputStreamInfo(transform, 0, &info);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
ok(info.dwFlags == (MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
|
|
| MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE | MFT_OUTPUT_STREAM_PROVIDES_SAMPLES), "got %#lx.\n", info.dwFlags);
|
|
ok(info.cbSize == aligned_width * aligned_height * 2, "got %lu.\n", info.cbSize);
|
|
ok(!info.cbAlignment, "got %lu.\n", info.cbAlignment);
|
|
|
|
hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, 0);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
|
|
memset(&info, 0xcc, sizeof(info));
|
|
hr = IMFTransform_GetOutputStreamInfo(transform, 0, &info);
|
|
ok(hr == S_OK, "got %#lx\n", hr);
|
|
ok(info.dwFlags == (MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
|
|
| MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE), "got %#lx.\n", info.dwFlags);
|
|
if (0)
|
|
{
|
|
/* hangs on Windows. */
|
|
get_next_h264_output_sample(transform, &input_sample, NULL, output, &data, &data_len);
|
|
}
|
|
|
|
IMFSample_Release(input_sample);
|
|
|
|
failed:
|
|
if (manager)
|
|
IMFDXGIDeviceManager_Release(manager);
|
|
if (transform)
|
|
IMFTransform_Release(transform);
|
|
CoUninitialize();
|
|
}
|
|
|
|
static void test_iv50_encoder(void)
|
|
{
|
|
static const BITMAPINFOHEADER expect_iv50 =
|
|
{
|
|
.biSize = sizeof(BITMAPINFOHEADER),
|
|
.biWidth = 0x60, .biHeight = 0x60,
|
|
.biPlanes = 1, .biBitCount = 0x18,
|
|
.biCompression = mmioFOURCC('I','V','5','0'),
|
|
.biSizeImage = 0x5100,
|
|
};
|
|
const struct buffer_desc iv50_buffer_desc =
|
|
{
|
|
.length = 0x2e8,
|
|
};
|
|
const struct sample_desc iv50_sample_desc =
|
|
{
|
|
.buffer_count = 1, .buffers = &iv50_buffer_desc,
|
|
};
|
|
const BYTE *res_data;
|
|
BYTE rgb_data[0x6c00], iv50_data[0x5100];
|
|
BITMAPINFO rgb_info, iv50_info;
|
|
IMFCollection *collection;
|
|
DWORD flags, res_len, ret;
|
|
IMFSample *sample;
|
|
LRESULT res;
|
|
HRESULT hr;
|
|
HIC hic;
|
|
|
|
load_resource(L"rgb555frame.bmp", (const BYTE **)&res_data, &res_len);
|
|
res_data += 2 + 3 * sizeof(DWORD);
|
|
res_len -= 2 + 3 * sizeof(DWORD);
|
|
rgb_info.bmiHeader = *(BITMAPINFOHEADER *)res_data;
|
|
memcpy(rgb_data, res_data + sizeof(BITMAPINFOHEADER), res_len - sizeof(BITMAPINFOHEADER));
|
|
|
|
hic = ICOpen(ICTYPE_VIDEO, expect_iv50.biCompression, ICMODE_COMPRESS);
|
|
if (!hic)
|
|
{
|
|
todo_wine
|
|
win_skip("ICOpen failed to created IV50 compressor.\n");
|
|
return;
|
|
}
|
|
|
|
res = ICCompressQuery(hic, &rgb_info, NULL);
|
|
todo_wine
|
|
ok(!res, "got res %#Ix\n", res);
|
|
if (res)
|
|
goto done;
|
|
|
|
res = ICCompressGetSize(hic, &rgb_info, NULL);
|
|
ok(res == expect_iv50.biSizeImage, "got res %#Ix\n", res);
|
|
|
|
res = ICCompressGetFormatSize(hic, &rgb_info);
|
|
ok(res == sizeof(BITMAPINFOHEADER), "got res %#Ix\n", res);
|
|
res = ICCompressGetFormat(hic, &rgb_info, &iv50_info);
|
|
ok(!res, "got res %#Ix\n", res);
|
|
check_member(iv50_info.bmiHeader, expect_iv50, "%#lx", biSize);
|
|
check_member(iv50_info.bmiHeader, expect_iv50, "%#lx", biWidth);
|
|
check_member(iv50_info.bmiHeader, expect_iv50, "%#lx", biHeight);
|
|
check_member(iv50_info.bmiHeader, expect_iv50, "%#x", biPlanes);
|
|
check_member(iv50_info.bmiHeader, expect_iv50, "%#x", biBitCount);
|
|
check_member(iv50_info.bmiHeader, expect_iv50, "%#lx", biCompression);
|
|
check_member(iv50_info.bmiHeader, expect_iv50, "%#lx", biSizeImage);
|
|
check_member(iv50_info.bmiHeader, expect_iv50, "%#lx", biXPelsPerMeter);
|
|
check_member(iv50_info.bmiHeader, expect_iv50, "%#lx", biYPelsPerMeter);
|
|
check_member(iv50_info.bmiHeader, expect_iv50, "%#lx", biClrUsed);
|
|
check_member(iv50_info.bmiHeader, expect_iv50, "%#lx", biClrImportant);
|
|
res = ICCompressQuery(hic, &rgb_info, &iv50_info);
|
|
ok(!res, "got res %#Ix\n", res);
|
|
|
|
res = ICCompressBegin(hic, &rgb_info, &iv50_info);
|
|
ok(!res, "got res %#Ix\n", res);
|
|
memset(iv50_data, 0xcd, sizeof(iv50_data));
|
|
res = ICCompress(hic, ICCOMPRESS_KEYFRAME, &iv50_info.bmiHeader, iv50_data, &rgb_info.bmiHeader, rgb_data,
|
|
NULL, &flags, 1, 0, 0, NULL, NULL);
|
|
ok(!res, "got res %#Ix\n", res);
|
|
ok(flags == 0x10, "got flags %#lx\n", flags);
|
|
ok(iv50_info.bmiHeader.biSizeImage == 0x2e8, "got res %#Ix\n", res);
|
|
res = ICCompressEnd(hic);
|
|
ok(!res, "got res %#Ix\n", res);
|
|
|
|
hr = MFCreateCollection(&collection);
|
|
ok(hr == S_OK, "got hr %#lx\n", hr);
|
|
sample = create_sample(iv50_data, iv50_info.bmiHeader.biSizeImage);
|
|
ok(!!sample, "got sample %p\n", sample);
|
|
hr = IMFSample_SetSampleTime(sample, 0);
|
|
ok(hr == S_OK, "got hr %#lx\n", hr);
|
|
hr = IMFSample_SetSampleDuration(sample, 0);
|
|
ok(hr == S_OK, "got hr %#lx\n", hr);
|
|
hr = IMFCollection_AddElement(collection, (IUnknown *)sample);
|
|
ok(hr == S_OK, "got hr %#lx\n", hr);
|
|
ret = check_mf_sample_collection(collection, &iv50_sample_desc, L"iv50frame.bin");
|
|
ok(ret == 0, "got %lu%% diff\n", ret);
|
|
IMFCollection_Release(collection);
|
|
|
|
done:
|
|
res = ICClose(hic);
|
|
ok(!res, "got res %#Ix\n", res);
|
|
}
|
|
|
|
static void test_iv50_decoder(void)
|
|
{
|
|
static const BITMAPINFOHEADER expect_iv50 =
|
|
{
|
|
.biSize = sizeof(BITMAPINFOHEADER),
|
|
.biWidth = 0x60, .biHeight = 0x60,
|
|
.biPlanes = 1, .biBitCount = 24,
|
|
.biCompression = mmioFOURCC('I','V','5','0'),
|
|
.biSizeImage = 0x2e8,
|
|
};
|
|
static const BITMAPINFOHEADER expect_rgb =
|
|
{
|
|
.biSize = sizeof(BITMAPINFOHEADER),
|
|
.biWidth = 0x60, .biHeight = 0x60,
|
|
.biPlanes = 1, .biBitCount = 24,
|
|
.biCompression = BI_RGB,
|
|
.biSizeImage = 96 * 96 * 3,
|
|
};
|
|
const struct buffer_desc rgb_buffer_desc =
|
|
{
|
|
.length = 96 * 96 * 3, .compare = compare_rgb24, .dump = dump_rgb24,
|
|
.rect = {.right = 82, .bottom = 84},
|
|
};
|
|
const struct sample_desc rgb_sample_desc =
|
|
{
|
|
.buffer_count = 1, .buffers = &rgb_buffer_desc,
|
|
};
|
|
const BYTE *res_data;
|
|
BYTE rgb_data[0x6c00], iv50_data[0x5100];
|
|
BITMAPINFO rgb_info, iv50_info;
|
|
IMFCollection *collection;
|
|
DWORD res_len, ret;
|
|
IMFSample *sample;
|
|
LRESULT res;
|
|
HRESULT hr;
|
|
HIC hic;
|
|
|
|
load_resource(L"iv50frame.bin", (const BYTE **)&res_data, &res_len);
|
|
memcpy(iv50_data, res_data, res_len);
|
|
|
|
iv50_info.bmiHeader = expect_iv50;
|
|
hic = ICOpen(ICTYPE_VIDEO, expect_iv50.biCompression, ICMODE_DECOMPRESS);
|
|
if (!hic)
|
|
{
|
|
todo_wine
|
|
win_skip("ICOpen failed to created IV50 decompressor.\n");
|
|
return;
|
|
}
|
|
|
|
res = ICDecompressGetFormat(hic, &iv50_info, &rgb_info);
|
|
ok(!res, "got res %#Ix\n", res);
|
|
check_member(rgb_info.bmiHeader, expect_rgb, "%#lx", biSize);
|
|
check_member(rgb_info.bmiHeader, expect_rgb, "%#lx", biWidth);
|
|
check_member(rgb_info.bmiHeader, expect_rgb, "%#lx", biHeight);
|
|
check_member(rgb_info.bmiHeader, expect_rgb, "%#x", biPlanes);
|
|
todo_wine
|
|
check_member(rgb_info.bmiHeader, expect_rgb, "%#x", biBitCount);
|
|
check_member(rgb_info.bmiHeader, expect_rgb, "%#lx", biCompression);
|
|
todo_wine
|
|
check_member(rgb_info.bmiHeader, expect_rgb, "%#lx", biSizeImage);
|
|
check_member(rgb_info.bmiHeader, expect_rgb, "%#lx", biXPelsPerMeter);
|
|
check_member(rgb_info.bmiHeader, expect_rgb, "%#lx", biYPelsPerMeter);
|
|
check_member(rgb_info.bmiHeader, expect_rgb, "%#lx", biClrUsed);
|
|
check_member(rgb_info.bmiHeader, expect_rgb, "%#lx", biClrImportant);
|
|
rgb_info.bmiHeader = expect_rgb;
|
|
|
|
res = ICDecompressBegin(hic, &iv50_info, &rgb_info);
|
|
ok(!res, "got res %#Ix\n", res);
|
|
res = ICDecompress(hic, 0, &iv50_info.bmiHeader, iv50_data, &rgb_info.bmiHeader, rgb_data);
|
|
ok(!res, "got res %#Ix\n", res);
|
|
res = ICDecompressEnd(hic);
|
|
todo_wine
|
|
ok(!res, "got res %#Ix\n", res);
|
|
|
|
res = ICClose(hic);
|
|
ok(!res, "got res %#Ix\n", res);
|
|
|
|
|
|
hr = MFCreateCollection(&collection);
|
|
ok(hr == S_OK, "got hr %#lx\n", hr);
|
|
sample = create_sample(rgb_data, rgb_info.bmiHeader.biSizeImage);
|
|
ok(!!sample, "got sample %p\n", sample);
|
|
hr = IMFSample_SetSampleTime(sample, 0);
|
|
ok(hr == S_OK, "got hr %#lx\n", hr);
|
|
hr = IMFSample_SetSampleDuration(sample, 0);
|
|
ok(hr == S_OK, "got hr %#lx\n", hr);
|
|
hr = IMFCollection_AddElement(collection, (IUnknown *)sample);
|
|
ok(hr == S_OK, "got hr %#lx\n", hr);
|
|
ret = check_mf_sample_collection(collection, &rgb_sample_desc, L"rgb24frame.bmp");
|
|
ok(ret <= 4, "got %lu%% diff\n", ret);
|
|
IMFCollection_Release(collection);
|
|
}
|
|
|
|
START_TEST(transform)
|
|
{
|
|
init_functions();
|
|
|
|
test_sample_copier();
|
|
test_sample_copier_output_processing();
|
|
test_aac_encoder();
|
|
test_aac_decoder();
|
|
test_wma_encoder();
|
|
test_wma_decoder();
|
|
test_wma_decoder_dmo_input_type();
|
|
test_wma_decoder_dmo_output_type();
|
|
test_h264_encoder();
|
|
test_h264_decoder();
|
|
test_wmv_encoder();
|
|
test_wmv_decoder();
|
|
test_wmv_decoder_dmo_input_type();
|
|
test_wmv_decoder_dmo_output_type();
|
|
test_wmv_decoder_dmo_get_size_info();
|
|
test_wmv_decoder_media_object();
|
|
test_audio_convert();
|
|
test_color_convert();
|
|
test_video_processor();
|
|
test_mp3_decoder();
|
|
test_iv50_encoder();
|
|
test_iv50_decoder();
|
|
|
|
test_h264_with_dxgi_manager();
|
|
test_h264_decoder_concat_streams();
|
|
}
|