mfmediaengine: Use a mftime_to_seconds() helper to convert time.
[wine.git] / dlls / mfmediaengine / tests / mfmediaengine.c
blob7ddc1fa06799ff896a7b41dab3516674a261f52f
1 /*
2 * Copyright 2019 Jactry Zeng for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
20 #include <math.h>
22 #define COBJMACROS
24 #include "windef.h"
25 #include "winbase.h"
27 #include "mfapi.h"
28 #include "mfidl.h"
29 #include "mfmediaengine.h"
30 #include "mferror.h"
31 #include "dxgi.h"
32 #include "d3d11.h"
33 #include "initguid.h"
34 #include "mmdeviceapi.h"
35 #include "audiosessiontypes.h"
37 #include "wine/test.h"
39 static HRESULT (WINAPI *pMFCreateDXGIDeviceManager)(UINT *token, IMFDXGIDeviceManager **manager);
40 static HRESULT (WINAPI *pD3D11CreateDevice)(IDXGIAdapter *adapter, D3D_DRIVER_TYPE driver_type, HMODULE swrast, UINT flags,
41 const D3D_FEATURE_LEVEL *feature_levels, UINT levels, UINT sdk_version, ID3D11Device **device_out,
42 D3D_FEATURE_LEVEL *obtained_feature_level, ID3D11DeviceContext **immediate_context);
44 static IMFMediaEngineClassFactory *factory;
46 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
47 static void _expect_ref(IUnknown *obj, ULONG ref, int line)
49 ULONG rc;
50 IUnknown_AddRef(obj);
51 rc = IUnknown_Release(obj);
52 ok_(__FILE__,line)(rc == ref, "Unexpected refcount %ld, expected %ld.\n", rc, ref);
55 #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
56 static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported)
58 IUnknown *iface = iface_ptr;
59 HRESULT hr, expected_hr;
60 IUnknown *unk;
62 expected_hr = supported ? S_OK : E_NOINTERFACE;
64 hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
65 ok_(__FILE__, line)(hr == expected_hr, "Got hr %#lx, expected %#lx.\n", hr, expected_hr);
66 if (SUCCEEDED(hr))
67 IUnknown_Release(unk);
70 static BOOL compare_double(double a, double b, double allowed_error)
72 return fabs(a - b) <= allowed_error;
75 static DWORD compare_rgb32(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect)
77 DWORD x, y, size, diff = 0, width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf;
79 /* skip BMP header from the dump */
80 size = *(DWORD *)(expect + 2 + 2 * sizeof(DWORD));
81 *length = *length + size;
82 expect = expect + size;
84 for (y = 0; y < height; y++, data += width * 4, expect += width * 4)
86 if (y < rect->top || y >= rect->bottom) continue;
87 for (x = 0; x < width; x++)
89 if (x < rect->left || x >= rect->right) continue;
90 diff += abs((int)expect[4 * x + 0] - (int)data[4 * x + 0]);
91 diff += abs((int)expect[4 * x + 1] - (int)data[4 * x + 1]);
92 diff += abs((int)expect[4 * x + 2] - (int)data[4 * x + 2]);
96 size = (rect->right - rect->left) * (rect->bottom - rect->top) * 3;
97 return diff * 100 / 256 / size;
100 static void dump_rgb32(const BYTE *data, DWORD length, const RECT *rect, HANDLE output)
102 DWORD width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf;
103 static const char magic[2] = "BM";
104 struct
106 DWORD length;
107 DWORD reserved;
108 DWORD offset;
109 BITMAPINFOHEADER biHeader;
110 } header =
112 .length = length + sizeof(header) + 2, .offset = sizeof(header) + 2,
113 .biHeader =
115 .biSize = sizeof(BITMAPINFOHEADER), .biWidth = width, .biHeight = height, .biPlanes = 1,
116 .biBitCount = 32, .biCompression = BI_RGB, .biSizeImage = width * height * 4,
119 DWORD written;
120 BOOL ret;
122 ret = WriteFile(output, magic, sizeof(magic), &written, NULL);
123 ok(ret, "WriteFile failed, error %lu\n", GetLastError());
124 ok(written == sizeof(magic), "written %lu bytes\n", written);
125 ret = WriteFile(output, &header, sizeof(header), &written, NULL);
126 ok(ret, "WriteFile failed, error %lu\n", GetLastError());
127 ok(written == sizeof(header), "written %lu bytes\n", written);
128 ret = WriteFile(output, data, length, &written, NULL);
129 ok(ret, "WriteFile failed, error %lu\n", GetLastError());
130 ok(written == length, "written %lu bytes\n", written);
133 #define check_rgb32_data(a, b, c, d) check_rgb32_data_(__LINE__, a, b, c, d)
134 static void check_rgb32_data_(int line, const WCHAR *filename, const BYTE *data, DWORD length, const RECT *rect)
136 WCHAR output_path[MAX_PATH];
137 const BYTE *expect_data;
138 HRSRC resource;
139 HANDLE output;
140 DWORD diff;
142 GetTempPathW(ARRAY_SIZE(output_path), output_path);
143 lstrcatW(output_path, filename);
144 output = CreateFileW(output_path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
145 ok(output != INVALID_HANDLE_VALUE, "CreateFileW failed, error %lu\n", GetLastError());
146 dump_rgb32(data, length, rect, output);
147 trace("created %s\n", debugstr_w(output_path));
148 CloseHandle(output);
150 resource = FindResourceW(NULL, filename, (const WCHAR *)RT_RCDATA);
151 ok(resource != 0, "FindResourceW failed, error %lu\n", GetLastError());
152 expect_data = LockResource(LoadResource(GetModuleHandleW(NULL), resource));
154 diff = compare_rgb32(data, &length, rect, expect_data);
155 ok_(__FILE__, line)(diff == 0, "Unexpected %lu%% diff\n", diff);
158 static void init_functions(void)
160 HMODULE mod;
162 #define X(f) p##f = (void*)GetProcAddress(mod, #f)
163 if ((mod = GetModuleHandleA("mfplat.dll")))
165 X(MFCreateDXGIDeviceManager);
168 if ((mod = LoadLibraryA("d3d11.dll")))
170 X(D3D11CreateDevice);
172 #undef X
175 struct media_engine_notify
177 IMFMediaEngineNotify IMFMediaEngineNotify_iface;
178 LONG refcount;
181 static inline struct media_engine_notify *impl_from_IMFMediaEngineNotify(IMFMediaEngineNotify *iface)
183 return CONTAINING_RECORD(iface, struct media_engine_notify, IMFMediaEngineNotify_iface);
186 static HRESULT WINAPI media_engine_notify_QueryInterface(IMFMediaEngineNotify *iface, REFIID riid, void **obj)
188 if (IsEqualIID(riid, &IID_IMFMediaEngineNotify) ||
189 IsEqualIID(riid, &IID_IUnknown))
191 *obj = iface;
192 IMFMediaEngineNotify_AddRef(iface);
193 return S_OK;
196 *obj = NULL;
197 return E_NOINTERFACE;
200 static ULONG WINAPI media_engine_notify_AddRef(IMFMediaEngineNotify *iface)
202 struct media_engine_notify *notify = impl_from_IMFMediaEngineNotify(iface);
203 return InterlockedIncrement(&notify->refcount);
206 static ULONG WINAPI media_engine_notify_Release(IMFMediaEngineNotify *iface)
208 struct media_engine_notify *notify = impl_from_IMFMediaEngineNotify(iface);
209 ULONG refcount = InterlockedDecrement(&notify->refcount);
211 if (!refcount)
212 free(notify);
214 return refcount;
217 static HRESULT WINAPI media_engine_notify_EventNotify(IMFMediaEngineNotify *iface, DWORD event, DWORD_PTR param1, DWORD param2)
219 return S_OK;
222 static IMFMediaEngineNotifyVtbl media_engine_notify_vtbl =
224 media_engine_notify_QueryInterface,
225 media_engine_notify_AddRef,
226 media_engine_notify_Release,
227 media_engine_notify_EventNotify,
230 static struct media_engine_notify *create_callback(void)
232 struct media_engine_notify *object;
234 object = calloc(1, sizeof(*object));
236 object->IMFMediaEngineNotify_iface.lpVtbl = &media_engine_notify_vtbl;
237 object->refcount = 1;
239 return object;
242 static ID3D11Device *create_d3d11_device(void)
244 static const D3D_FEATURE_LEVEL default_feature_level[] =
246 D3D_FEATURE_LEVEL_11_0,
247 D3D_FEATURE_LEVEL_10_1,
248 D3D_FEATURE_LEVEL_10_0,
250 const D3D_FEATURE_LEVEL *feature_level;
251 unsigned int feature_level_count;
252 ID3D11Device *device;
254 feature_level = default_feature_level;
255 feature_level_count = ARRAY_SIZE(default_feature_level);
257 if (SUCCEEDED(pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0,
258 feature_level, feature_level_count, D3D11_SDK_VERSION, &device, NULL, NULL)))
259 return device;
260 if (SUCCEEDED(pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_WARP, NULL, 0,
261 feature_level, feature_level_count, D3D11_SDK_VERSION, &device, NULL, NULL)))
262 return device;
263 if (SUCCEEDED(pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_REFERENCE, NULL, 0,
264 feature_level, feature_level_count, D3D11_SDK_VERSION, &device, NULL, NULL)))
265 return device;
267 return NULL;
270 static IMFMediaEngine *create_media_engine(IMFMediaEngineNotify *callback, IMFDXGIDeviceManager *manager, UINT32 output_format)
272 IMFMediaEngine *media_engine;
273 IMFAttributes *attributes;
274 HRESULT hr;
276 hr = MFCreateAttributes(&attributes, 3);
277 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
279 if (manager)
281 hr = IMFAttributes_SetUnknown(attributes, &MF_MEDIA_ENGINE_DXGI_MANAGER, (IUnknown *)manager);
282 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
285 hr = IMFAttributes_SetUnknown(attributes, &MF_MEDIA_ENGINE_CALLBACK, (IUnknown *)callback);
286 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
287 hr = IMFAttributes_SetUINT32(attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, output_format);
288 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
290 hr = IMFMediaEngineClassFactory_CreateInstance(factory, 0, attributes, &media_engine);
291 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
293 IMFAttributes_Release(attributes);
295 return media_engine;
298 static IMFMediaEngineEx *create_media_engine_ex(IMFMediaEngineNotify *callback, IMFDXGIDeviceManager *manager, UINT32 output_format)
300 IMFMediaEngine *engine = create_media_engine(callback, manager, output_format);
301 IMFMediaEngineEx *engine_ex = NULL;
303 if (engine)
305 IMFMediaEngine_QueryInterface(engine, &IID_IMFMediaEngineEx, (void **)&engine_ex);
306 IMFMediaEngine_Release(engine);
309 return engine_ex;
312 static void test_factory(void)
314 IMFMediaEngineClassFactory *factory, *factory2;
315 struct media_engine_notify *notify;
316 IMFDXGIDeviceManager *manager;
317 IMFMediaEngine *media_engine;
318 IMFAttributes *attributes;
319 UINT token;
320 HRESULT hr;
322 hr = CoCreateInstance(&CLSID_MFMediaEngineClassFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IMFMediaEngineClassFactory,
323 (void **)&factory);
324 ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG) /* pre-win8 */, "Failed to create class factory, hr %#lx.\n", hr);
325 if (FAILED(hr))
327 win_skip("Media Engine is not supported.\n");
328 return;
331 notify = create_callback();
333 /* Aggregation is not supported. */
334 hr = CoCreateInstance(&CLSID_MFMediaEngineClassFactory, (IUnknown *)factory, CLSCTX_INPROC_SERVER,
335 &IID_IMFMediaEngineClassFactory, (void **)&factory2);
336 ok(hr == CLASS_E_NOAGGREGATION, "Unexpected hr %#lx.\n", hr);
338 hr = pMFCreateDXGIDeviceManager(&token, &manager);
339 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
340 hr = MFCreateAttributes(&attributes, 3);
341 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
343 hr = IMFMediaEngineClassFactory_CreateInstance(factory, MF_MEDIA_ENGINE_WAITFORSTABLE_STATE, attributes, &media_engine);
344 ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr);
346 hr = IMFAttributes_SetUnknown(attributes, &MF_MEDIA_ENGINE_OPM_HWND, NULL);
347 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
348 hr = IMFMediaEngineClassFactory_CreateInstance(factory, MF_MEDIA_ENGINE_WAITFORSTABLE_STATE, attributes, &media_engine);
349 ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr);
351 IMFAttributes_DeleteAllItems(attributes);
352 hr = IMFAttributes_SetUnknown(attributes, &MF_MEDIA_ENGINE_CALLBACK, (IUnknown *)&notify->IMFMediaEngineNotify_iface);
353 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
354 hr = IMFAttributes_SetUINT32(attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, DXGI_FORMAT_UNKNOWN);
355 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
356 EXPECT_REF(factory, 1);
357 hr = IMFMediaEngineClassFactory_CreateInstance(factory, MF_MEDIA_ENGINE_WAITFORSTABLE_STATE, attributes, &media_engine);
358 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
359 EXPECT_REF(factory, 1);
361 IMFMediaEngine_Release(media_engine);
362 IMFAttributes_Release(attributes);
363 IMFDXGIDeviceManager_Release(manager);
364 IMFMediaEngineClassFactory_Release(factory);
365 IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
368 static void test_CreateInstance(void)
370 struct media_engine_notify *notify;
371 IMFMediaEngineEx *media_engine_ex;
372 IMFDXGIDeviceManager *manager;
373 IMFMediaEngine *media_engine;
374 IMFAttributes *attributes;
375 IUnknown *unk;
376 UINT token;
377 HRESULT hr;
378 BOOL ret;
380 notify = create_callback();
382 hr = pMFCreateDXGIDeviceManager(&token, &manager);
383 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
385 hr = MFCreateAttributes(&attributes, 3);
386 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
388 hr = IMFMediaEngineClassFactory_CreateInstance(factory, MF_MEDIA_ENGINE_WAITFORSTABLE_STATE,
389 attributes, &media_engine);
390 ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr);
392 hr = IMFAttributes_SetUnknown(attributes, &MF_MEDIA_ENGINE_OPM_HWND, NULL);
393 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
395 hr = IMFMediaEngineClassFactory_CreateInstance(factory, MF_MEDIA_ENGINE_WAITFORSTABLE_STATE,
396 attributes, &media_engine);
397 ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr);
399 IMFAttributes_DeleteAllItems(attributes);
401 hr = IMFAttributes_SetUnknown(attributes, &MF_MEDIA_ENGINE_CALLBACK, (IUnknown *)&notify->IMFMediaEngineNotify_iface);
402 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
403 hr = IMFAttributes_SetUINT32(attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, DXGI_FORMAT_UNKNOWN);
404 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
406 hr = IMFMediaEngineClassFactory_CreateInstance(factory, MF_MEDIA_ENGINE_REAL_TIME_MODE
407 | MF_MEDIA_ENGINE_WAITFORSTABLE_STATE, attributes, &media_engine);
408 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
410 check_interface(media_engine, &IID_IMFMediaEngine, TRUE);
412 hr = IMFMediaEngine_QueryInterface(media_engine, &IID_IMFGetService, (void **)&unk);
413 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* supported since win10 */, "Unexpected hr %#lx.\n", hr);
414 if (SUCCEEDED(hr))
415 IUnknown_Release(unk);
417 if (SUCCEEDED(IMFMediaEngine_QueryInterface(media_engine, &IID_IMFMediaEngineEx, (void **)&media_engine_ex)))
419 hr = IMFMediaEngineEx_GetRealTimeMode(media_engine_ex, &ret);
420 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
421 ok(ret, "Unexpected value.\n");
423 hr = IMFMediaEngineEx_SetRealTimeMode(media_engine_ex, FALSE);
424 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
426 hr = IMFMediaEngineEx_GetRealTimeMode(media_engine_ex, &ret);
427 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
428 ok(!ret, "Unexpected value.\n");
430 hr = IMFMediaEngineEx_SetRealTimeMode(media_engine_ex, TRUE);
431 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
433 hr = IMFMediaEngineEx_GetRealTimeMode(media_engine_ex, &ret);
434 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
435 ok(ret, "Unexpected value.\n");
437 IMFMediaEngineEx_Release(media_engine_ex);
440 IMFMediaEngine_Release(media_engine);
441 IMFAttributes_Release(attributes);
442 IMFDXGIDeviceManager_Release(manager);
443 IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
446 static void test_Shutdown(void)
448 struct media_engine_notify *notify;
449 IMFMediaEngineEx *media_engine_ex;
450 IMFMediaTimeRange *time_range;
451 IMFMediaEngine *media_engine;
452 PROPVARIANT propvar;
453 DWORD flags, cx, cy;
454 unsigned int state;
455 UINT32 value;
456 double val;
457 HRESULT hr;
458 BSTR str;
459 BOOL ret;
461 notify = create_callback();
463 media_engine = create_media_engine(&notify->IMFMediaEngineNotify_iface, NULL, DXGI_FORMAT_UNKNOWN);
465 hr = IMFMediaEngine_Shutdown(media_engine);
466 ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr);
468 hr = IMFMediaEngine_Shutdown(media_engine);
469 ok(hr == MF_E_SHUTDOWN || broken(hr == S_OK) /* before win10 */, "Unexpected hr %#lx.\n", hr);
471 hr = IMFMediaEngine_SetSource(media_engine, NULL);
472 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
474 hr = IMFMediaEngine_GetCurrentSource(media_engine, &str);
475 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
477 state = IMFMediaEngine_GetNetworkState(media_engine);
478 ok(!state, "Unexpected state %d.\n", state);
480 /* Preload mode is still accessible. */
481 state = IMFMediaEngine_GetPreload(media_engine);
482 ok(!state, "Unexpected state %d.\n", state);
484 hr = IMFMediaEngine_SetPreload(media_engine, MF_MEDIA_ENGINE_PRELOAD_AUTOMATIC);
485 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
487 state = IMFMediaEngine_GetPreload(media_engine);
488 ok(state == MF_MEDIA_ENGINE_PRELOAD_AUTOMATIC, "Unexpected state %d.\n", state);
490 hr = IMFMediaEngine_SetPreload(media_engine, 100);
491 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
493 state = IMFMediaEngine_GetPreload(media_engine);
494 ok(state == 100, "Unexpected state %d.\n", state);
496 hr = IMFMediaEngine_GetBuffered(media_engine, &time_range);
497 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
499 hr = IMFMediaEngine_Load(media_engine);
500 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
502 str = SysAllocString(L"video/mp4");
503 hr = IMFMediaEngine_CanPlayType(media_engine, str, &state);
504 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
505 SysFreeString(str);
507 state = IMFMediaEngine_GetReadyState(media_engine);
508 ok(!state, "Unexpected state %d.\n", state);
510 state = IMFMediaEngine_IsSeeking(media_engine);
511 ok(!state, "Unexpected state %d.\n", state);
513 val = IMFMediaEngine_GetCurrentTime(media_engine);
514 ok(val == 0.0, "Unexpected time %f.\n", val);
516 hr = IMFMediaEngine_SetCurrentTime(media_engine, 1.0);
517 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
519 val = IMFMediaEngine_GetStartTime(media_engine);
520 ok(val == 0.0, "Unexpected time %f.\n", val);
522 state = IMFMediaEngine_IsPaused(media_engine);
523 ok(!!state, "Unexpected state %d.\n", state);
525 val = IMFMediaEngine_GetDefaultPlaybackRate(media_engine);
526 ok(val == 1.0, "Unexpected rate %f.\n", val);
528 hr = IMFMediaEngine_SetDefaultPlaybackRate(media_engine, 2.0);
529 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
531 val = IMFMediaEngine_GetPlaybackRate(media_engine);
532 ok(val == 1.0, "Unexpected rate %f.\n", val);
534 hr = IMFMediaEngine_GetPlayed(media_engine, &time_range);
535 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
537 hr = IMFMediaEngine_GetSeekable(media_engine, &time_range);
538 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
540 state = IMFMediaEngine_IsEnded(media_engine);
541 ok(!state, "Unexpected state %d.\n", state);
543 /* Autoplay mode is still accessible. */
544 state = IMFMediaEngine_GetAutoPlay(media_engine);
545 ok(!state, "Unexpected state.\n");
547 hr = IMFMediaEngine_SetAutoPlay(media_engine, TRUE);
548 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
550 state = IMFMediaEngine_GetAutoPlay(media_engine);
551 ok(!!state, "Unexpected state.\n");
553 /* Loop mode is still accessible. */
554 state = IMFMediaEngine_GetLoop(media_engine);
555 ok(!state, "Unexpected state.\n");
557 hr = IMFMediaEngine_SetLoop(media_engine, TRUE);
558 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
560 state = IMFMediaEngine_GetLoop(media_engine);
561 ok(!!state, "Unexpected state.\n");
563 hr = IMFMediaEngine_Play(media_engine);
564 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
566 hr = IMFMediaEngine_Pause(media_engine);
567 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
569 state = IMFMediaEngine_GetMuted(media_engine);
570 ok(!state, "Unexpected state.\n");
572 hr = IMFMediaEngine_SetMuted(media_engine, TRUE);
573 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
575 val = IMFMediaEngine_GetVolume(media_engine);
576 ok(val == 1.0, "Unexpected value %f.\n", val);
578 hr = IMFMediaEngine_SetVolume(media_engine, 2.0);
579 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
581 state = IMFMediaEngine_HasVideo(media_engine);
582 ok(!state, "Unexpected state.\n");
584 state = IMFMediaEngine_HasAudio(media_engine);
585 ok(!state, "Unexpected state.\n");
587 hr = IMFMediaEngine_GetNativeVideoSize(media_engine, &cx, &cy);
588 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
590 hr = IMFMediaEngine_GetVideoAspectRatio(media_engine, &cx, &cy);
591 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
593 if (SUCCEEDED(IMFMediaEngine_QueryInterface(media_engine, &IID_IMFMediaEngineEx, (void **)&media_engine_ex)))
595 hr = IMFMediaEngineEx_SetSourceFromByteStream(media_engine_ex, NULL, NULL);
596 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
598 hr = IMFMediaEngineEx_GetAudioStreamCategory(media_engine_ex, &value);
599 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
601 hr = IMFMediaEngineEx_GetAudioEndpointRole(media_engine_ex, &value);
602 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
604 hr = IMFMediaEngineEx_SetAudioStreamCategory(media_engine_ex, AudioCategory_ForegroundOnlyMedia);
605 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
607 hr = IMFMediaEngineEx_SetAudioEndpointRole(media_engine_ex, eConsole);
608 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
610 hr = IMFMediaEngineEx_GetResourceCharacteristics(media_engine_ex, NULL);
611 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
613 hr = IMFMediaEngineEx_GetResourceCharacteristics(media_engine_ex, &flags);
614 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
616 hr = IMFMediaEngineEx_GetRealTimeMode(media_engine_ex, NULL);
617 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
619 hr = IMFMediaEngineEx_GetRealTimeMode(media_engine_ex, &ret);
620 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
622 hr = IMFMediaEngineEx_SetRealTimeMode(media_engine_ex, TRUE);
623 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
625 hr = IMFMediaEngineEx_GetPresentationAttribute(media_engine_ex, &MF_PD_DURATION, &propvar);
626 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
628 hr = IMFMediaEngineEx_GetStreamAttribute(media_engine_ex, 0, &MF_SD_PROTECTED, &propvar);
629 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
631 IMFMediaEngineEx_Release(media_engine_ex);
634 IMFMediaEngine_Release(media_engine);
635 IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
638 static void test_Play(void)
640 struct media_engine_notify *notify;
641 IMFMediaTimeRange *range, *range1;
642 IMFMediaEngine *media_engine;
643 LONGLONG pts;
644 DWORD count;
645 HRESULT hr;
646 BOOL ret;
648 notify = create_callback();
650 media_engine = create_media_engine(&notify->IMFMediaEngineNotify_iface, NULL, DXGI_FORMAT_UNKNOWN);
652 hr = IMFMediaEngine_GetBuffered(media_engine, &range);
653 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
654 hr = IMFMediaEngine_GetBuffered(media_engine, &range1);
655 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
656 ok(range != range1, "Unexpected pointer.\n");
658 count = IMFMediaTimeRange_GetLength(range);
659 ok(!count, "Unexpected count %lu.\n", count);
661 IMFMediaTimeRange_Release(range);
662 IMFMediaTimeRange_Release(range1);
664 ret = IMFMediaEngine_IsPaused(media_engine);
665 ok(ret, "Unexpected state %d.\n", ret);
667 hr = IMFMediaEngine_OnVideoStreamTick(media_engine, NULL);
668 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
670 pts = 0;
671 hr = IMFMediaEngine_OnVideoStreamTick(media_engine, &pts);
672 ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
673 ok(pts == MINLONGLONG, "Unexpected timestamp.\n");
675 hr = IMFMediaEngine_Play(media_engine);
676 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
678 ret = IMFMediaEngine_IsPaused(media_engine);
679 ok(!ret, "Unexpected state %d.\n", ret);
681 hr = IMFMediaEngine_Play(media_engine);
682 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
684 hr = IMFMediaEngine_Shutdown(media_engine);
685 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
687 hr = IMFMediaEngine_OnVideoStreamTick(media_engine, NULL);
688 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
690 hr = IMFMediaEngine_OnVideoStreamTick(media_engine, &pts);
691 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
693 ret = IMFMediaEngine_IsPaused(media_engine);
694 ok(!ret, "Unexpected state %d.\n", ret);
696 IMFMediaEngine_Release(media_engine);
698 /* Play -> Pause */
699 media_engine = create_media_engine(&notify->IMFMediaEngineNotify_iface, NULL, DXGI_FORMAT_UNKNOWN);
701 hr = IMFMediaEngine_Play(media_engine);
702 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
704 ret = IMFMediaEngine_IsPaused(media_engine);
705 ok(!ret, "Unexpected state %d.\n", ret);
707 hr = IMFMediaEngine_Pause(media_engine);
708 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
710 ret = IMFMediaEngine_IsPaused(media_engine);
711 ok(!!ret, "Unexpected state %d.\n", ret);
713 IMFMediaEngine_Release(media_engine);
714 IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
717 static void test_playback_rate(void)
719 struct media_engine_notify *notify;
720 IMFMediaEngine *media_engine;
721 double rate;
722 HRESULT hr;
724 notify = create_callback();
726 media_engine = create_media_engine(&notify->IMFMediaEngineNotify_iface, NULL, DXGI_FORMAT_UNKNOWN);
728 rate = IMFMediaEngine_GetDefaultPlaybackRate(media_engine);
729 ok(rate == 1.0, "Unexpected default rate.\n");
731 rate = IMFMediaEngine_GetPlaybackRate(media_engine);
732 ok(rate == 1.0, "Unexpected default rate.\n");
734 hr = IMFMediaEngine_SetPlaybackRate(media_engine, 0.0);
735 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
737 rate = IMFMediaEngine_GetPlaybackRate(media_engine);
738 ok(rate == 0.0, "Unexpected default rate.\n");
740 hr = IMFMediaEngine_SetDefaultPlaybackRate(media_engine, 0.0);
741 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
743 IMFMediaEngine_Release(media_engine);
744 IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
747 static void test_mute(void)
749 struct media_engine_notify *notify;
750 IMFMediaEngine *media_engine;
751 HRESULT hr;
752 BOOL ret;
754 notify = create_callback();
756 media_engine = create_media_engine(&notify->IMFMediaEngineNotify_iface, NULL, DXGI_FORMAT_UNKNOWN);
758 ret = IMFMediaEngine_GetMuted(media_engine);
759 ok(!ret, "Unexpected state.\n");
761 hr = IMFMediaEngine_SetMuted(media_engine, TRUE);
762 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
764 ret = IMFMediaEngine_GetMuted(media_engine);
765 ok(ret, "Unexpected state.\n");
767 hr = IMFMediaEngine_Shutdown(media_engine);
768 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
770 ret = IMFMediaEngine_GetMuted(media_engine);
771 ok(ret, "Unexpected state.\n");
773 IMFMediaEngine_Release(media_engine);
774 IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
777 static void test_error(void)
779 struct media_engine_notify *notify;
780 IMFMediaEngine *media_engine;
781 IMFMediaError *eo, *eo2;
782 unsigned int code;
783 HRESULT hr;
785 notify = create_callback();
787 media_engine = create_media_engine(&notify->IMFMediaEngineNotify_iface, NULL, DXGI_FORMAT_UNKNOWN);
789 eo = (void *)0xdeadbeef;
790 hr = IMFMediaEngine_GetError(media_engine, &eo);
791 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
792 ok(!eo, "Unexpected instance.\n");
794 hr = IMFMediaEngine_SetErrorCode(media_engine, MF_MEDIA_ENGINE_ERR_ENCRYPTED + 1);
795 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
797 hr = IMFMediaEngine_SetErrorCode(media_engine, MF_MEDIA_ENGINE_ERR_ABORTED);
798 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
800 eo = NULL;
801 hr = IMFMediaEngine_GetError(media_engine, &eo);
802 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
803 ok(!!eo, "Unexpected instance.\n");
805 eo2 = NULL;
806 hr = IMFMediaEngine_GetError(media_engine, &eo2);
807 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
808 ok(eo2 != eo, "Unexpected instance.\n");
810 IMFMediaError_Release(eo2);
811 IMFMediaError_Release(eo);
813 hr = IMFMediaEngine_SetErrorCode(media_engine, MF_MEDIA_ENGINE_ERR_NOERROR);
814 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
816 eo = (void *)0xdeadbeef;
817 hr = IMFMediaEngine_GetError(media_engine, &eo);
818 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
819 ok(!eo, "Unexpected instance.\n");
821 hr = IMFMediaEngine_Shutdown(media_engine);
822 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
824 eo = (void *)0xdeadbeef;
825 hr = IMFMediaEngine_GetError(media_engine, &eo);
826 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
827 ok(!eo, "Unexpected instance.\n");
829 hr = IMFMediaEngine_SetErrorCode(media_engine, MF_MEDIA_ENGINE_ERR_NOERROR);
830 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
832 IMFMediaEngine_Release(media_engine);
834 /* Error object. */
835 hr = IMFMediaEngineClassFactory_CreateError(factory, &eo);
836 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
838 code = IMFMediaError_GetErrorCode(eo);
839 ok(code == MF_MEDIA_ENGINE_ERR_NOERROR, "Unexpected code %u.\n", code);
841 hr = IMFMediaError_GetExtendedErrorCode(eo);
842 ok(hr == S_OK, "Unexpected code %#lx.\n", hr);
844 hr = IMFMediaError_SetErrorCode(eo, MF_MEDIA_ENGINE_ERR_ENCRYPTED + 1);
845 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
847 hr = IMFMediaError_SetErrorCode(eo, MF_MEDIA_ENGINE_ERR_ABORTED);
848 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
850 code = IMFMediaError_GetErrorCode(eo);
851 ok(code == MF_MEDIA_ENGINE_ERR_ABORTED, "Unexpected code %u.\n", code);
853 hr = IMFMediaError_SetExtendedErrorCode(eo, E_FAIL);
854 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
856 hr = IMFMediaError_GetExtendedErrorCode(eo);
857 ok(hr == E_FAIL, "Unexpected code %#lx.\n", hr);
859 IMFMediaError_Release(eo);
860 IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
863 static void test_time_range(void)
865 IMFMediaTimeRange *range;
866 double start, end;
867 DWORD count;
868 HRESULT hr;
869 BOOL ret;
871 hr = IMFMediaEngineClassFactory_CreateTimeRange(factory, &range);
872 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
874 /* Empty ranges. */
875 hr = IMFMediaTimeRange_Clear(range);
876 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
878 ret = IMFMediaTimeRange_ContainsTime(range, 10.0);
879 ok(!ret, "Unexpected return value %d.\n", ret);
881 count = IMFMediaTimeRange_GetLength(range);
882 ok(!count, "Unexpected range count.\n");
884 hr = IMFMediaTimeRange_GetStart(range, 0, &start);
885 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
887 hr = IMFMediaTimeRange_GetEnd(range, 0, &end);
888 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
890 /* Add a range. */
891 hr = IMFMediaTimeRange_AddRange(range, 10.0, 1.0);
892 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
894 count = IMFMediaTimeRange_GetLength(range);
895 ok(count == 1, "Unexpected range count.\n");
897 hr = IMFMediaTimeRange_GetStart(range, 0, &start);
898 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
899 ok(start == 10.0, "Unexpected start %.e.\n", start);
901 hr = IMFMediaTimeRange_GetEnd(range, 0, &end);
902 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
903 ok(end == 1.0, "Unexpected end %.e.\n", end);
905 hr = IMFMediaTimeRange_AddRange(range, 2.0, 3.0);
906 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
908 count = IMFMediaTimeRange_GetLength(range);
909 ok(count == 1, "Unexpected range count.\n");
911 hr = IMFMediaTimeRange_GetStart(range, 0, &start);
912 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
913 ok(start == 2.0, "Unexpected start %.8e.\n", start);
915 hr = IMFMediaTimeRange_GetEnd(range, 0, &end);
916 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
917 ok(end == 3.0, "Unexpected end %.8e.\n", end);
919 hr = IMFMediaTimeRange_AddRange(range, 10.0, 9.0);
920 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
922 count = IMFMediaTimeRange_GetLength(range);
923 ok(count == 2, "Unexpected range count.\n");
925 hr = IMFMediaTimeRange_GetStart(range, 0, &start);
926 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
927 ok(start == 2.0, "Unexpected start %.8e.\n", start);
929 hr = IMFMediaTimeRange_GetEnd(range, 0, &end);
930 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
931 ok(end == 3.0, "Unexpected end %.8e.\n", end);
933 start = 0.0;
934 hr = IMFMediaTimeRange_GetStart(range, 1, &start);
935 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
936 ok(start == 10.0, "Unexpected start %.8e.\n", start);
938 hr = IMFMediaTimeRange_GetEnd(range, 1, &end);
939 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
940 ok(end == 9.0, "Unexpected end %.8e.\n", end);
942 hr = IMFMediaTimeRange_AddRange(range, 2.0, 9.1);
943 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
945 count = IMFMediaTimeRange_GetLength(range);
946 ok(count == 2, "Unexpected range count.\n");
948 hr = IMFMediaTimeRange_GetStart(range, 0, &start);
949 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
950 ok(start == 2.0, "Unexpected start %.8e.\n", start);
952 hr = IMFMediaTimeRange_GetEnd(range, 0, &end);
953 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
954 ok(end == 9.1, "Unexpected end %.8e.\n", end);
956 hr = IMFMediaTimeRange_GetStart(range, 1, &start);
957 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
958 ok(start == 10.0, "Unexpected start %.8e.\n", start);
960 hr = IMFMediaTimeRange_GetEnd(range, 1, &end);
961 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
962 ok(end == 9.0, "Unexpected end %.8e.\n", end);
964 hr = IMFMediaTimeRange_AddRange(range, 8.5, 2.5);
965 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
967 count = IMFMediaTimeRange_GetLength(range);
968 ok(count == 2, "Unexpected range count.\n");
970 hr = IMFMediaTimeRange_GetStart(range, 0, &start);
971 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
972 ok(start == 2.0, "Unexpected start %.8e.\n", start);
974 hr = IMFMediaTimeRange_GetEnd(range, 0, &end);
975 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
976 ok(end == 9.1, "Unexpected end %.8e.\n", end);
978 hr = IMFMediaTimeRange_AddRange(range, 20.0, 20.0);
979 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
981 count = IMFMediaTimeRange_GetLength(range);
982 ok(count == 3, "Unexpected range count.\n");
984 hr = IMFMediaTimeRange_Clear(range);
985 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
987 count = IMFMediaTimeRange_GetLength(range);
988 ok(!count, "Unexpected range count.\n");
990 /* Intersect */
991 hr = IMFMediaTimeRange_AddRange(range, 5.0, 10.0);
992 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
994 hr = IMFMediaTimeRange_AddRange(range, 6.0, 12.0);
995 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
997 hr = IMFMediaTimeRange_GetStart(range, 0, &start);
998 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
999 ok(start == 5.0, "Unexpected start %.8e.\n", start);
1001 hr = IMFMediaTimeRange_GetEnd(range, 0, &end);
1002 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1003 ok(end == 12.0, "Unexpected end %.8e.\n", end);
1005 count = IMFMediaTimeRange_GetLength(range);
1006 ok(count == 1, "Unexpected range count.\n");
1008 hr = IMFMediaTimeRange_AddRange(range, 4.0, 6.0);
1009 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1011 count = IMFMediaTimeRange_GetLength(range);
1012 ok(count == 1, "Unexpected range count.\n");
1014 hr = IMFMediaTimeRange_GetStart(range, 0, &start);
1015 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1016 ok(start == 4.0, "Unexpected start %.8e.\n", start);
1018 hr = IMFMediaTimeRange_GetEnd(range, 0, &end);
1019 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1020 ok(end == 12.0, "Unexpected end %.8e.\n", end);
1022 hr = IMFMediaTimeRange_AddRange(range, 5.0, 3.0);
1023 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1025 count = IMFMediaTimeRange_GetLength(range);
1026 ok(count == 1, "Unexpected range count.\n");
1028 hr = IMFMediaTimeRange_GetStart(range, 0, &start);
1029 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1030 ok(start == 4.0, "Unexpected start %.8e.\n", start);
1032 hr = IMFMediaTimeRange_GetEnd(range, 0, &end);
1033 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1034 ok(end == 12.0, "Unexpected end %.8e.\n", end);
1036 IMFMediaTimeRange_Release(range);
1039 static void test_SetSourceFromByteStream(void)
1041 struct media_engine_notify *notify;
1042 IMFMediaEngineEx *media_engine;
1043 PROPVARIANT propvar;
1044 DWORD count, flags;
1045 HRESULT hr;
1047 notify = create_callback();
1049 media_engine = create_media_engine_ex(&notify->IMFMediaEngineNotify_iface, NULL, DXGI_FORMAT_UNKNOWN);
1050 if (!media_engine)
1052 win_skip("IMFMediaEngineEx is not supported.\n");
1053 IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
1054 return;
1057 hr = IMFMediaEngineEx_SetSourceFromByteStream(media_engine, NULL, NULL);
1058 ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
1060 hr = IMFMediaEngineEx_GetResourceCharacteristics(media_engine, NULL);
1061 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
1063 hr = IMFMediaEngineEx_GetResourceCharacteristics(media_engine, &flags);
1064 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
1066 hr = IMFMediaEngineEx_GetPresentationAttribute(media_engine, &MF_PD_DURATION, &propvar);
1067 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
1069 hr = IMFMediaEngineEx_GetStreamAttribute(media_engine, 0, &MF_SD_PROTECTED, &propvar);
1070 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
1072 hr = IMFMediaEngineEx_GetNumberOfStreams(media_engine, NULL);
1073 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
1075 count = 123;
1076 hr = IMFMediaEngineEx_GetNumberOfStreams(media_engine, &count);
1077 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
1078 ok(count == 123, "Unexpected value %lu.\n", count);
1080 IMFMediaEngineEx_Release(media_engine);
1081 IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
1084 static void test_audio_configuration(void)
1086 struct media_engine_notify *notify;
1087 IMFMediaEngineEx *media_engine;
1088 UINT32 value;
1089 HRESULT hr;
1091 notify = create_callback();
1093 media_engine = create_media_engine_ex(&notify->IMFMediaEngineNotify_iface, NULL, DXGI_FORMAT_UNKNOWN);
1094 if (!media_engine)
1096 IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
1097 return;
1100 hr = IMFMediaEngineEx_GetAudioStreamCategory(media_engine, &value);
1101 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1102 ok(value == AudioCategory_Other, "Unexpected value %u.\n", value);
1104 hr = IMFMediaEngineEx_GetAudioEndpointRole(media_engine, &value);
1105 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1106 ok(value == eMultimedia, "Unexpected value %u.\n", value);
1108 IMFMediaEngineEx_Release(media_engine);
1109 IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
1112 static IMFByteStream *load_resource(const WCHAR *name, const WCHAR *mime)
1114 IMFAttributes *attributes;
1115 const BYTE *resource_data;
1116 IMFByteStream *stream;
1117 ULONG resource_len;
1118 HRSRC resource;
1119 HRESULT hr;
1121 resource = FindResourceW(NULL, name, (const WCHAR *)RT_RCDATA);
1122 ok(resource != 0, "FindResourceW %s failed, error %lu\n", debugstr_w(name), GetLastError());
1123 resource_data = LockResource(LoadResource(GetModuleHandleW(NULL), resource));
1124 resource_len = SizeofResource(GetModuleHandleW(NULL), resource);
1126 hr = MFCreateTempFile(MF_ACCESSMODE_READWRITE, MF_OPENMODE_DELETE_IF_EXIST, MF_FILEFLAGS_NONE, &stream);
1127 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1128 hr = IMFByteStream_Write(stream, resource_data, resource_len, &resource_len);
1129 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1130 hr = IMFByteStream_SetCurrentPosition(stream, 0);
1131 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1133 hr = IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attributes);
1134 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1135 hr = IMFAttributes_SetString(attributes, &MF_BYTESTREAM_CONTENT_TYPE, mime);
1136 ok(hr == S_OK, "Failed to set string value, hr %#lx.\n", hr);
1137 IMFAttributes_Release(attributes);
1139 return stream;
1142 struct test_transfer_notify
1144 IMFMediaEngineNotify IMFMediaEngineNotify_iface;
1145 LONG refcount;
1147 IMFMediaEngineEx *media_engine;
1148 HANDLE ready_event, frame_ready_event;
1149 HRESULT error;
1152 static struct test_transfer_notify *impl_from_test_transfer_notify(IMFMediaEngineNotify *iface)
1154 return CONTAINING_RECORD(iface, struct test_transfer_notify, IMFMediaEngineNotify_iface);
1157 static HRESULT WINAPI test_transfer_notify_QueryInterface(IMFMediaEngineNotify *iface, REFIID riid, void **obj)
1159 if (IsEqualIID(riid, &IID_IUnknown)
1160 || IsEqualIID(riid, &IID_IMFMediaEngineNotify))
1162 *obj = iface;
1163 IMFMediaEngineNotify_AddRef(iface);
1164 return S_OK;
1167 *obj = NULL;
1168 return E_NOINTERFACE;
1171 static ULONG WINAPI test_transfer_notify_AddRef(IMFMediaEngineNotify *iface)
1173 struct test_transfer_notify *notify = impl_from_test_transfer_notify(iface);
1174 return InterlockedIncrement(&notify->refcount);
1177 static ULONG WINAPI test_transfer_notify_Release(IMFMediaEngineNotify *iface)
1179 struct test_transfer_notify *notify = impl_from_test_transfer_notify(iface);
1180 ULONG refcount = InterlockedDecrement(&notify->refcount);
1182 if (!refcount)
1184 CloseHandle(notify->frame_ready_event);
1185 CloseHandle(notify->ready_event);
1186 free(notify);
1189 return refcount;
1192 static HRESULT WINAPI test_transfer_notify_EventNotify(IMFMediaEngineNotify *iface, DWORD event, DWORD_PTR param1, DWORD param2)
1194 struct test_transfer_notify *notify = impl_from_test_transfer_notify(iface);
1195 IMFMediaEngineEx *media_engine = notify->media_engine;
1196 DWORD width, height;
1197 HRESULT hr;
1198 BOOL ret;
1200 switch (event)
1202 case MF_MEDIA_ENGINE_EVENT_CANPLAY:
1203 hr = IMFMediaEngineEx_Play(media_engine);
1204 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1205 break;
1207 case MF_MEDIA_ENGINE_EVENT_FORMATCHANGE:
1208 ret = IMFMediaEngineEx_HasVideo(media_engine);
1209 ok(ret, "Unexpected HasVideo %u.\n", ret);
1210 hr = IMFMediaEngineEx_GetNativeVideoSize(media_engine, &width, &height);
1211 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1212 ok(width == 64, "Unexpected width %lu.\n", width);
1213 ok(height == 64, "Unexpected height %lu.\n", height);
1214 break;
1216 case MF_MEDIA_ENGINE_EVENT_ERROR:
1217 ok(broken(param2 == MF_E_UNSUPPORTED_BYTESTREAM_TYPE), "Unexpected error %#lx\n", param2);
1218 notify->error = param2;
1219 /* fallthrough */
1220 case MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY:
1221 SetEvent(notify->frame_ready_event);
1222 break;
1223 case MF_MEDIA_ENGINE_EVENT_TIMEUPDATE:
1224 SetEvent(notify->ready_event);
1225 break;
1228 return S_OK;
1231 static IMFMediaEngineNotifyVtbl test_transfer_notify_vtbl =
1233 test_transfer_notify_QueryInterface,
1234 test_transfer_notify_AddRef,
1235 test_transfer_notify_Release,
1236 test_transfer_notify_EventNotify,
1239 static struct test_transfer_notify *create_transfer_notify(void)
1241 struct test_transfer_notify *object;
1243 object = calloc(1, sizeof(*object));
1244 object->IMFMediaEngineNotify_iface.lpVtbl = &test_transfer_notify_vtbl;
1245 object->refcount = 1;
1246 object->ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1247 ok(!!object->ready_event, "Failed to create an event, error %lu.\n", GetLastError());
1249 object->frame_ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1250 ok(!!object->frame_ready_event, "Failed to create an event, error %lu.\n", GetLastError());
1252 return object;
1255 static void test_TransferVideoFrame(void)
1257 struct test_transfer_notify *notify;
1258 ID3D11Texture2D *texture = NULL, *rb_texture;
1259 D3D11_MAPPED_SUBRESOURCE map_desc;
1260 IMFMediaEngineEx *media_engine = NULL;
1261 IMFDXGIDeviceManager *manager;
1262 ID3D11DeviceContext *context;
1263 D3D11_TEXTURE2D_DESC desc;
1264 IMFByteStream *stream;
1265 ID3D11Device *device;
1266 RECT dst_rect;
1267 UINT token;
1268 HRESULT hr;
1269 DWORD res;
1270 BSTR url;
1272 stream = load_resource(L"i420-64x64.avi", L"video/avi");
1274 notify = create_transfer_notify();
1276 if (!(device = create_d3d11_device()))
1278 skip("Failed to create a D3D11 device, skipping tests.\n");
1279 goto done;
1282 hr = pMFCreateDXGIDeviceManager(&token, &manager);
1283 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1284 hr = IMFDXGIDeviceManager_ResetDevice(manager, (IUnknown *)device, token);
1285 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1287 media_engine = create_media_engine_ex(&notify->IMFMediaEngineNotify_iface, manager, DXGI_FORMAT_B8G8R8X8_UNORM);
1289 IMFDXGIDeviceManager_Release(manager);
1291 if (!(notify->media_engine = media_engine))
1292 goto done;
1294 memset(&desc, 0, sizeof(desc));
1295 desc.Width = 64;
1296 desc.Height = 64;
1297 desc.ArraySize = 1;
1298 desc.Format = DXGI_FORMAT_B8G8R8X8_UNORM;
1299 desc.BindFlags = D3D11_BIND_RENDER_TARGET;
1300 desc.SampleDesc.Count = 1;
1301 hr = ID3D11Device_CreateTexture2D(device, &desc, NULL, &texture);
1302 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1304 url = SysAllocString(L"i420-64x64.avi");
1305 hr = IMFMediaEngineEx_SetSourceFromByteStream(media_engine, stream, url);
1306 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1307 SysFreeString(url);
1308 IMFByteStream_Release(stream);
1310 res = WaitForSingleObject(notify->frame_ready_event, 5000);
1311 ok(!res, "Unexpected res %#lx.\n", res);
1313 if (FAILED(notify->error))
1315 win_skip("Media engine reported error %#lx, skipping tests.\n", notify->error);
1316 goto done;
1319 res = 0;
1320 hr = IMFMediaEngineEx_GetNumberOfStreams(media_engine, &res);
1321 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1322 ok(res == 2, "Unexpected stream count %lu.\n", res);
1324 /* FIXME: Wine first video frame is often full of garbage, wait for another update */
1325 res = WaitForSingleObject(notify->ready_event, 500);
1326 /* It's also missing the MF_MEDIA_ENGINE_EVENT_TIMEUPDATE notifications */
1327 todo_wine
1328 ok(!res, "Unexpected res %#lx.\n", res);
1330 SetRect(&dst_rect, 0, 0, desc.Width, desc.Height);
1331 hr = IMFMediaEngineEx_TransferVideoFrame(notify->media_engine, (IUnknown *)texture, NULL, &dst_rect, NULL);
1332 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1334 ID3D11Texture2D_GetDesc(texture, &desc);
1335 desc.Usage = D3D11_USAGE_STAGING;
1336 desc.BindFlags = 0;
1337 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
1338 desc.MiscFlags = 0;
1339 hr = ID3D11Device_CreateTexture2D(device, &desc, NULL, &rb_texture);
1340 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1342 ID3D11Device_GetImmediateContext(device, &context);
1343 ID3D11DeviceContext_CopySubresourceRegion(context, (ID3D11Resource *)rb_texture,
1344 0, 0, 0, 0, (ID3D11Resource *)texture, 0, NULL);
1346 memset(&map_desc, 0, sizeof(map_desc));
1347 hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)rb_texture, 0, D3D11_MAP_READ, 0, &map_desc);
1348 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1349 ok(!!map_desc.pData, "got pData %p\n", map_desc.pData);
1350 ok(map_desc.DepthPitch == 16384, "got DepthPitch %u\n", map_desc.DepthPitch);
1351 ok(map_desc.RowPitch == desc.Width * 4, "got RowPitch %u\n", map_desc.RowPitch);
1352 check_rgb32_data(L"rgb32frame.bmp", map_desc.pData, map_desc.RowPitch * desc.Height, &dst_rect);
1353 ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)rb_texture, 0);
1355 ID3D11DeviceContext_Release(context);
1356 ID3D11Texture2D_Release(rb_texture);
1358 done:
1359 if (media_engine)
1361 IMFMediaEngineEx_Shutdown(media_engine);
1362 IMFMediaEngineEx_Release(media_engine);
1365 if (texture)
1366 ID3D11Texture2D_Release(texture);
1367 if (device)
1368 ID3D11Device_Release(device);
1370 IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
1373 struct passthrough_mft
1375 IMFTransform IMFTransform_iface;
1376 LONG refcount;
1378 IMFMediaType *media_type_in, *media_type_out;
1379 IMFSample *sample;
1380 LONG processing_count;
1381 UINT32 index;
1383 CRITICAL_SECTION cs;
1386 static struct passthrough_mft *impl_from_IMFTransform(IMFTransform *iface)
1388 return CONTAINING_RECORD(iface, struct passthrough_mft, IMFTransform_iface);
1391 static HRESULT WINAPI passthrough_mft_QueryInterface(IMFTransform *iface, REFIID iid, void **out)
1393 struct passthrough_mft *impl = impl_from_IMFTransform(iface);
1395 if (IsEqualGUID(iid, &IID_IUnknown) ||
1396 IsEqualGUID(iid, &IID_IMFTransform))
1398 *out = &impl->IMFTransform_iface;
1399 IUnknown_AddRef((IUnknown *)*out);
1400 return S_OK;
1403 *out = NULL;
1404 return E_NOINTERFACE;
1407 static ULONG WINAPI passthrough_mft_AddRef(IMFTransform *iface)
1409 struct passthrough_mft *impl = impl_from_IMFTransform(iface);
1410 ULONG refcount = InterlockedIncrement(&impl->refcount);
1411 return refcount;
1414 static ULONG WINAPI passthrough_mft_Release(IMFTransform *iface)
1416 struct passthrough_mft *impl = impl_from_IMFTransform(iface);
1417 ULONG refcount = InterlockedDecrement(&impl->refcount);
1419 if (!refcount)
1421 if (impl->media_type_out) IMFMediaType_Release(impl->media_type_out);
1422 if (impl->media_type_in) IMFMediaType_Release(impl->media_type_in);
1423 DeleteCriticalSection(&impl->cs);
1424 free(impl);
1427 return refcount;
1430 static HRESULT WINAPI passthrough_mft_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum,
1431 DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum)
1433 *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1;
1434 return S_OK;
1437 static HRESULT WINAPI passthrough_mft_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
1439 *inputs = *outputs = 1;
1440 return S_OK;
1443 static HRESULT WINAPI passthrough_mft_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
1444 DWORD output_size, DWORD *outputs)
1446 return E_NOTIMPL;
1449 static HRESULT WINAPI passthrough_mft_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
1451 return E_NOTIMPL;
1454 static HRESULT WINAPI passthrough_mft_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
1456 if (id)
1457 return MF_E_INVALIDSTREAMNUMBER;
1459 info->dwFlags =
1460 MFT_OUTPUT_STREAM_PROVIDES_SAMPLES |
1461 MFT_OUTPUT_STREAM_WHOLE_SAMPLES |
1462 MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE |
1463 MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER;
1465 info->cbAlignment = 0;
1466 info->cbSize = 0;
1467 return S_OK;
1470 static HRESULT WINAPI passthrough_mft_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
1472 return E_NOTIMPL;
1475 static HRESULT WINAPI passthrough_mft_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
1477 return E_NOTIMPL;
1480 static HRESULT WINAPI passthrough_mft_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
1482 return E_NOTIMPL;
1485 static HRESULT WINAPI passthrough_mft_DeleteInputStream(IMFTransform *iface, DWORD id)
1487 return E_NOTIMPL;
1490 static HRESULT WINAPI passthrough_mft_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
1492 return E_NOTIMPL;
1495 static HRESULT WINAPI passthrough_mft_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
1496 IMFMediaType **type)
1498 static const GUID *types[] = { &MFMediaType_Video, &MFMediaType_Audio };
1499 HRESULT hr;
1501 if (id)
1502 return MF_E_INVALIDSTREAMNUMBER;
1504 if (index > ARRAY_SIZE(types) - 1)
1505 return MF_E_NO_MORE_TYPES;
1507 if (SUCCEEDED(hr = MFCreateMediaType(type)))
1508 hr = IMFMediaType_SetGUID(*type, &MF_MT_MAJOR_TYPE, types[index]);
1510 return hr;
1513 static HRESULT WINAPI passthrough_mft_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
1514 IMFMediaType **type)
1516 struct passthrough_mft *impl = impl_from_IMFTransform(iface);
1517 HRESULT hr = S_OK;
1519 if (id)
1520 return MF_E_INVALIDSTREAMNUMBER;
1522 EnterCriticalSection(&impl->cs);
1524 if (index)
1526 hr = MF_E_NO_MORE_TYPES;
1528 else if (impl->media_type_out)
1530 *type = impl->media_type_out;
1531 IMFMediaType_AddRef(*type);
1533 else if (impl->media_type_in)
1535 *type = impl->media_type_in;
1536 IMFMediaType_AddRef(*type);
1538 else
1540 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
1543 LeaveCriticalSection(&impl->cs);
1545 return hr;
1548 static HRESULT WINAPI passthrough_mft_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
1550 struct passthrough_mft *impl = impl_from_IMFTransform(iface);
1551 HRESULT hr = S_OK;
1553 if (id)
1554 return MF_E_INVALIDSTREAMNUMBER;
1556 EnterCriticalSection(&impl->cs);
1558 if (!(flags & MFT_SET_TYPE_TEST_ONLY))
1560 if (impl->media_type_in)
1561 IMFMediaType_Release(impl->media_type_in);
1563 impl->media_type_in = type;
1564 IMFMediaType_AddRef(impl->media_type_in);
1567 LeaveCriticalSection(&impl->cs);
1569 return hr;
1572 static HRESULT WINAPI passthrough_mft_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
1574 struct passthrough_mft *impl = impl_from_IMFTransform(iface);
1576 if (id)
1577 return MF_E_INVALIDSTREAMNUMBER;
1579 EnterCriticalSection(&impl->cs);
1581 if (impl->media_type_out)
1582 IMFMediaType_Release(impl->media_type_out);
1584 impl->media_type_out = type;
1585 IMFMediaType_AddRef(impl->media_type_out);
1587 LeaveCriticalSection(&impl->cs);
1589 return S_OK;
1592 static HRESULT WINAPI passthrough_mft_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
1594 struct passthrough_mft *impl = impl_from_IMFTransform(iface);
1595 HRESULT hr = S_OK;
1597 if (id)
1598 return MF_E_INVALIDSTREAMNUMBER;
1600 EnterCriticalSection(&impl->cs);
1601 if (impl->media_type_in)
1603 *type = impl->media_type_in;
1604 IMFMediaType_AddRef(*type);
1606 else
1608 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
1610 LeaveCriticalSection(&impl->cs);
1612 return hr;
1615 static HRESULT WINAPI passthrough_mft_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
1617 struct passthrough_mft *impl = impl_from_IMFTransform(iface);
1618 HRESULT hr = S_OK;
1620 if (id)
1621 return MF_E_INVALIDSTREAMNUMBER;
1623 EnterCriticalSection(&impl->cs);
1625 if (impl->media_type_out)
1627 *type = impl->media_type_out;
1628 IMFMediaType_AddRef(*type);
1630 else
1632 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
1635 LeaveCriticalSection(&impl->cs);
1637 return hr;
1640 static HRESULT WINAPI passthrough_mft_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
1642 return E_NOTIMPL;
1645 static HRESULT WINAPI passthrough_mft_GetOutputStatus(IMFTransform *iface, DWORD *flags)
1647 return E_NOTIMPL;
1650 static HRESULT WINAPI passthrough_mft_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
1652 return E_NOTIMPL;
1655 static HRESULT WINAPI passthrough_mft_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
1657 return E_NOTIMPL;
1660 static HRESULT WINAPI passthrough_mft_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
1662 if (message == MFT_MESSAGE_COMMAND_FLUSH)
1663 return E_NOTIMPL;
1665 return S_OK;
1668 static HRESULT WINAPI passthrough_mft_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
1670 struct passthrough_mft *impl = impl_from_IMFTransform(iface);
1671 HRESULT hr = S_OK;
1673 if (id)
1674 return MF_E_INVALIDSTREAMNUMBER;
1676 EnterCriticalSection(&impl->cs);
1677 if (impl->sample)
1679 hr = MF_E_NOTACCEPTING;
1681 else
1683 impl->sample = sample;
1684 IMFSample_AddRef(impl->sample);
1687 LeaveCriticalSection(&impl->cs);
1689 return hr;
1692 static HRESULT WINAPI passthrough_mft_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
1693 MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
1695 struct passthrough_mft *impl = impl_from_IMFTransform(iface);
1696 HRESULT hr = S_OK;
1697 UINT32 val = 41;
1699 if (count != 1)
1700 return E_INVALIDARG;
1702 EnterCriticalSection(&impl->cs);
1704 if (impl->sample)
1706 hr = IMFSample_GetUINT32(impl->sample, &IID_IMFSample, &val);
1708 if (impl->index > 0)
1710 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1711 ok(val == impl->index, "Got unexpected value %u.\n", val);
1713 else
1715 ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr);
1718 IMFSample_SetUINT32(impl->sample, &IID_IMFSample, impl->index + 1);
1720 samples->pSample = impl->sample;
1721 *status = samples[0].dwStatus = 0;
1722 impl->processing_count++;
1724 impl->sample = NULL;
1726 hr = S_OK;
1728 else
1730 hr = MF_E_TRANSFORM_NEED_MORE_INPUT;
1733 LeaveCriticalSection(&impl->cs);
1735 return hr;
1738 static const IMFTransformVtbl passthrough_mft_vtbl =
1740 passthrough_mft_QueryInterface,
1741 passthrough_mft_AddRef,
1742 passthrough_mft_Release,
1743 passthrough_mft_GetStreamLimits,
1744 passthrough_mft_GetStreamCount,
1745 passthrough_mft_GetStreamIDs,
1746 passthrough_mft_GetInputStreamInfo,
1747 passthrough_mft_GetOutputStreamInfo,
1748 passthrough_mft_GetAttributes,
1749 passthrough_mft_GetInputStreamAttributes,
1750 passthrough_mft_GetOutputStreamAttributes,
1751 passthrough_mft_DeleteInputStream,
1752 passthrough_mft_AddInputStreams,
1753 passthrough_mft_GetInputAvailableType,
1754 passthrough_mft_GetOutputAvailableType,
1755 passthrough_mft_SetInputType,
1756 passthrough_mft_SetOutputType,
1757 passthrough_mft_GetInputCurrentType,
1758 passthrough_mft_GetOutputCurrentType,
1759 passthrough_mft_GetInputStatus,
1760 passthrough_mft_GetOutputStatus,
1761 passthrough_mft_SetOutputBounds,
1762 passthrough_mft_ProcessEvent,
1763 passthrough_mft_ProcessMessage,
1764 passthrough_mft_ProcessInput,
1765 passthrough_mft_ProcessOutput,
1768 HRESULT passthrough_mft_create(UINT32 index, struct passthrough_mft **out)
1770 struct passthrough_mft *impl;
1772 *out = NULL;
1774 if (!(impl = calloc(1, sizeof(*impl))))
1775 return E_OUTOFMEMORY;
1777 impl->IMFTransform_iface.lpVtbl = &passthrough_mft_vtbl;
1778 impl->index = index;
1779 impl->refcount = 1;
1781 InitializeCriticalSection(&impl->cs);
1783 *out = impl;
1784 return S_OK;
1787 static void test_effect(void)
1789 struct passthrough_mft *video_effect = NULL, *video_effect2 = NULL, *audio_effect = NULL, *audio_effect2 = NULL;
1790 struct test_transfer_notify *notify;
1791 IMFMediaEngineEx *media_engine_ex = NULL;
1792 ID3D11Texture2D *texture = NULL;
1793 IMFDXGIDeviceManager *manager;
1794 ID3D11Device *device = NULL;
1795 D3D11_TEXTURE2D_DESC desc;
1796 IMFByteStream *stream;
1797 IMFMediaSink *sink;
1798 RECT dst_rect;
1799 UINT token;
1800 HRESULT hr;
1801 DWORD res;
1802 BSTR url;
1804 stream = load_resource(L"i420-64x64.avi", L"video/avi");
1806 notify = create_transfer_notify();
1808 if (!(device = create_d3d11_device()))
1810 skip("Failed to create a D3D11 device, skipping tests.\n");
1811 goto done;
1814 hr = pMFCreateDXGIDeviceManager(&token, &manager);
1815 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1816 hr = IMFDXGIDeviceManager_ResetDevice(manager, (IUnknown *)device, token);
1817 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1819 media_engine_ex = create_media_engine_ex(&notify->IMFMediaEngineNotify_iface,
1820 manager, DXGI_FORMAT_B8G8R8X8_UNORM);
1822 IMFDXGIDeviceManager_Release(manager);
1824 if (!(notify->media_engine = media_engine_ex))
1825 goto done;
1827 memset(&desc, 0, sizeof(desc));
1828 desc.Width = 64;
1829 desc.Height = 64;
1830 desc.ArraySize = 1;
1831 desc.Format = DXGI_FORMAT_B8G8R8X8_UNORM;
1832 desc.BindFlags = D3D11_BIND_RENDER_TARGET;
1833 desc.SampleDesc.Count = 1;
1834 hr = ID3D11Device_CreateTexture2D(device, &desc, NULL, &texture);
1835 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1837 hr = IMFMediaEngineEx_RemoveAllEffects(media_engine_ex);
1838 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1840 hr = passthrough_mft_create(0, &video_effect);
1841 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1843 hr = passthrough_mft_create(1, &video_effect2);
1844 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1846 hr = IMFMediaEngineEx_InsertVideoEffect(media_engine_ex, (IUnknown *)&video_effect->IMFTransform_iface, FALSE);
1847 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1848 EXPECT_REF(&video_effect->IMFTransform_iface, 2);
1850 hr = IMFMediaEngineEx_InsertVideoEffect(media_engine_ex, (IUnknown *)&video_effect2->IMFTransform_iface, FALSE);
1851 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1852 EXPECT_REF(&video_effect2->IMFTransform_iface, 2);
1854 hr = IMFMediaEngineEx_RemoveAllEffects(media_engine_ex);
1855 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1856 EXPECT_REF(&video_effect->IMFTransform_iface, 1);
1857 EXPECT_REF(&video_effect2->IMFTransform_iface, 1);
1859 hr = IMFMediaEngineEx_InsertVideoEffect(media_engine_ex, (IUnknown *)&video_effect->IMFTransform_iface, FALSE);
1860 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1861 EXPECT_REF(&video_effect->IMFTransform_iface, 2);
1863 hr = IMFMediaEngineEx_InsertVideoEffect(media_engine_ex, (IUnknown *)&video_effect2->IMFTransform_iface, FALSE);
1864 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1865 EXPECT_REF(&video_effect2->IMFTransform_iface, 2);
1867 hr = passthrough_mft_create(0, &audio_effect);
1868 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1870 hr = passthrough_mft_create(1, &audio_effect2);
1871 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1873 hr = IMFMediaEngineEx_InsertAudioEffect(media_engine_ex, (IUnknown *)&audio_effect->IMFTransform_iface, FALSE);
1874 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1875 EXPECT_REF(&audio_effect->IMFTransform_iface, 2);
1877 hr = IMFMediaEngineEx_InsertAudioEffect(media_engine_ex, (IUnknown *)&audio_effect2->IMFTransform_iface, FALSE);
1878 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1879 EXPECT_REF(&audio_effect2->IMFTransform_iface, 2);
1881 url = SysAllocString(L"i420-64x64.avi");
1882 hr = IMFMediaEngineEx_SetSourceFromByteStream(media_engine_ex, stream, url);
1883 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1884 SysFreeString(url);
1885 IMFByteStream_Release(stream);
1887 /* Wait for MediaEngine to be ready. */
1888 res = WaitForSingleObject(notify->frame_ready_event, 5000);
1889 ok(!res, "Unexpected res %#lx.\n", res);
1891 SetRect(&dst_rect, 0, 0, desc.Width, desc.Height);
1892 hr = IMFMediaEngineEx_TransferVideoFrame(notify->media_engine, (IUnknown *)texture, NULL, &dst_rect, NULL);
1893 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1895 ok(video_effect->processing_count > 0, "Unexpected processing count %lu.\n", video_effect->processing_count);
1896 ok(video_effect2->processing_count > 0, "Unexpected processing count %lu.\n", video_effect2->processing_count);
1898 if (SUCCEEDED(hr = MFCreateAudioRenderer(NULL, &sink)))
1900 ok(audio_effect->processing_count > 0, "Unexpected processing count %lu.\n", audio_effect->processing_count);
1901 ok(audio_effect2->processing_count > 0, "Unexpected processing count %lu.\n", audio_effect2->processing_count);
1903 IMFMediaSink_Release(sink);
1905 else if (hr == MF_E_NO_AUDIO_PLAYBACK_DEVICE)
1907 ok(!audio_effect->processing_count, "Unexpected processing count %lu.\n", audio_effect->processing_count);
1908 ok(!audio_effect2->processing_count, "Unexpected processing count %lu.\n", audio_effect2->processing_count);
1911 done:
1912 if (media_engine_ex)
1914 IMFMediaEngineEx_Shutdown(media_engine_ex);
1916 hr = IMFMediaEngineEx_RemoveAllEffects(media_engine_ex);
1917 ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
1919 IMFMediaEngineEx_Release(media_engine_ex);
1922 if (texture)
1923 ID3D11Texture2D_Release(texture);
1924 if (device)
1925 ID3D11Device_Release(device);
1927 if (audio_effect2)
1928 IMFTransform_Release(&audio_effect2->IMFTransform_iface);
1929 if (audio_effect)
1930 IMFTransform_Release(&audio_effect->IMFTransform_iface);
1932 if (video_effect2)
1933 IMFTransform_Release(&video_effect2->IMFTransform_iface);
1934 if (video_effect)
1935 IMFTransform_Release(&video_effect->IMFTransform_iface);
1937 IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
1940 static void test_GetDuration(void)
1942 static const double allowed_error = 0.000001;
1943 struct test_transfer_notify *notify;
1944 IMFMediaEngineEx *media_engine;
1945 IMFByteStream *stream;
1946 double duration;
1947 HRESULT hr;
1948 DWORD res;
1949 BSTR url;
1951 notify = create_transfer_notify();
1952 media_engine = create_media_engine_ex(&notify->IMFMediaEngineNotify_iface, NULL, DXGI_FORMAT_B8G8R8X8_UNORM);
1953 notify->media_engine = media_engine;
1954 ok(!!media_engine, "create_media_engine_ex failed.\n");
1956 stream = load_resource(L"i420-64x64.avi", L"video/avi");
1957 url = SysAllocString(L"i420-64x64.avi");
1958 hr = IMFMediaEngineEx_SetSourceFromByteStream(media_engine, stream, url);
1959 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1960 res = WaitForSingleObject(notify->ready_event, 5000);
1961 ok(!res, "Unexpected res %#lx.\n", res);
1963 duration = IMFMediaEngineEx_GetDuration(media_engine);
1964 ok(compare_double(duration, 0.133467, allowed_error), "Got unexpected duration %lf.\n", duration);
1966 SysFreeString(url);
1967 IMFByteStream_Release(stream);
1968 IMFMediaEngineEx_Shutdown(media_engine);
1969 IMFMediaEngineEx_Release(media_engine);
1970 IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
1973 START_TEST(mfmediaengine)
1975 HRESULT hr;
1977 CoInitialize(NULL);
1979 hr = CoCreateInstance(&CLSID_MFMediaEngineClassFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IMFMediaEngineClassFactory,
1980 (void **)&factory);
1981 if (FAILED(hr))
1983 win_skip("Media Engine is not supported.\n");
1984 CoUninitialize();
1985 return;
1988 init_functions();
1990 hr = MFStartup(MF_VERSION, MFSTARTUP_FULL);
1991 ok(hr == S_OK, "MFStartup failed: %#lx.\n", hr);
1993 test_factory();
1994 test_CreateInstance();
1995 test_Shutdown();
1996 test_Play();
1997 test_playback_rate();
1998 test_mute();
1999 test_error();
2000 test_time_range();
2001 test_SetSourceFromByteStream();
2002 test_audio_configuration();
2003 test_TransferVideoFrame();
2004 test_effect();
2005 test_GetDuration();
2007 IMFMediaEngineClassFactory_Release(factory);
2009 CoUninitialize();
2011 MFShutdown();