msxml4/tests: Copy namespaces as attributes tests.
[wine.git] / dlls / mfmediaengine / main.c
blob1395eb9bffcc848cf59c4497e6b282f889b66d54
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 #define COBJMACROS
21 #include <math.h>
22 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
27 #include "mfapi.h"
28 #include "mfmediaengine.h"
29 #include "mferror.h"
30 #include "dxgi.h"
31 #include "d3d11.h"
32 #include "mmdeviceapi.h"
33 #include "audiosessiontypes.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
39 static BOOL mf_array_reserve(void **elements, size_t *capacity, size_t count, size_t size)
41 size_t new_capacity, max_capacity;
42 void *new_elements;
44 if (count <= *capacity)
45 return TRUE;
47 max_capacity = ~(SIZE_T)0 / size;
48 if (count > max_capacity)
49 return FALSE;
51 new_capacity = max(4, *capacity);
52 while (new_capacity < count && new_capacity <= max_capacity / 2)
53 new_capacity *= 2;
54 if (new_capacity < count)
55 new_capacity = max_capacity;
57 if (!(new_elements = realloc(*elements, new_capacity * size)))
58 return FALSE;
60 *elements = new_elements;
61 *capacity = new_capacity;
63 return TRUE;
66 /* Convert 100ns to seconds */
67 static double mftime_to_seconds(MFTIME time)
69 return (double)time / 10000000.0;
72 enum media_engine_mode
74 MEDIA_ENGINE_INVALID,
75 MEDIA_ENGINE_AUDIO_MODE,
76 MEDIA_ENGINE_RENDERING_MODE,
77 MEDIA_ENGINE_FRAME_SERVER_MODE,
80 /* Used with create flags. */
81 enum media_engine_flags
83 /* MF_MEDIA_ENGINE_CREATEFLAGS_MASK is 0x1f. */
84 FLAGS_ENGINE_SHUT_DOWN = 0x20,
85 FLAGS_ENGINE_AUTO_PLAY = 0x40,
86 FLAGS_ENGINE_LOOP = 0x80,
87 FLAGS_ENGINE_PAUSED = 0x100,
88 FLAGS_ENGINE_WAITING = 0x200,
89 FLAGS_ENGINE_MUTED = 0x400,
90 FLAGS_ENGINE_HAS_AUDIO = 0x800,
91 FLAGS_ENGINE_HAS_VIDEO = 0x1000,
92 FLAGS_ENGINE_FIRST_FRAME = 0x2000,
93 FLAGS_ENGINE_IS_ENDED = 0x4000,
94 FLAGS_ENGINE_NEW_FRAME = 0x8000,
95 FLAGS_ENGINE_SOURCE_PENDING = 0x10000,
96 FLAGS_ENGINE_PLAY_PENDING = 0x20000,
99 struct vec3
101 float x, y, z;
104 struct color
106 float r, g, b, a;
109 static const struct vec3 fullquad[] =
111 {-1.0f, -1.0f, 0.0f},
112 {-1.0f, 1.0f, 0.0f},
113 { 1.0f, -1.0f, 0.0f},
114 { 1.0f, 1.0f, 0.0f},
117 struct rect
119 float left, top, right, bottom;
122 struct effect
124 IUnknown *object;
125 BOOL optional;
128 struct effects
130 struct effect *effects;
131 size_t count;
132 size_t capacity;
135 struct media_engine
137 IMFMediaEngineEx IMFMediaEngineEx_iface;
138 IMFGetService IMFGetService_iface;
139 IMFAsyncCallback session_events;
140 IMFAsyncCallback load_handler;
141 IMFSampleGrabberSinkCallback grabber_callback;
142 LONG refcount;
143 IMFMediaEngineNotify *callback;
144 IMFAttributes *attributes;
145 IMFDXGIDeviceManager *device_manager;
146 HANDLE device_handle;
147 enum media_engine_mode mode;
148 unsigned int flags;
149 double playback_rate;
150 double default_playback_rate;
151 double volume;
152 double duration;
153 MF_MEDIA_ENGINE_NETWORK network_state;
154 MF_MEDIA_ENGINE_ERR error_code;
155 HRESULT extended_code;
156 MF_MEDIA_ENGINE_READY ready_state;
157 MF_MEDIA_ENGINE_PRELOAD preload;
158 IMFMediaSession *session;
159 IMFPresentationClock *clock;
160 IMFSourceResolver *resolver;
161 BSTR current_source;
162 struct
164 IMFMediaSource *source;
165 IMFPresentationDescriptor *pd;
166 } presentation;
167 struct effects video_effects;
168 struct effects audio_effects;
169 struct
171 LONGLONG pts;
172 SIZE size;
173 SIZE ratio;
174 TOPOID node_id;
175 BYTE *buffer;
176 UINT buffer_size;
177 DXGI_FORMAT output_format;
179 struct
181 ID3D11Buffer *vb;
182 ID3D11Buffer *ps_cb;
183 ID3D11Texture2D *source;
184 ID3D11ShaderResourceView *srv;
185 ID3D11SamplerState *sampler;
186 ID3D11InputLayout *input_layout;
187 ID3D11VertexShader *vs;
188 ID3D11PixelShader *ps;
189 struct vec3 quad[4];
190 struct
192 struct rect dst;
193 struct rect src;
194 struct color backcolor;
195 } cb;
196 } d3d11;
197 } video_frame;
198 CRITICAL_SECTION cs;
201 static void media_engine_release_video_frame_resources(struct media_engine *engine)
203 if (engine->video_frame.d3d11.vb)
204 ID3D11Buffer_Release(engine->video_frame.d3d11.vb);
205 if (engine->video_frame.d3d11.ps_cb)
206 ID3D11Buffer_Release(engine->video_frame.d3d11.ps_cb);
207 if (engine->video_frame.d3d11.source)
208 ID3D11Texture2D_Release(engine->video_frame.d3d11.source);
209 if (engine->video_frame.d3d11.srv)
210 ID3D11ShaderResourceView_Release(engine->video_frame.d3d11.srv);
211 if (engine->video_frame.d3d11.sampler)
212 ID3D11SamplerState_Release(engine->video_frame.d3d11.sampler);
213 if (engine->video_frame.d3d11.input_layout)
214 ID3D11InputLayout_Release(engine->video_frame.d3d11.input_layout);
215 if (engine->video_frame.d3d11.vs)
216 ID3D11VertexShader_Release(engine->video_frame.d3d11.vs);
217 if (engine->video_frame.d3d11.ps)
218 ID3D11PixelShader_Release(engine->video_frame.d3d11.ps);
220 memset(&engine->video_frame.d3d11, 0, sizeof(engine->video_frame.d3d11));
221 memcpy(engine->video_frame.d3d11.quad, fullquad, sizeof(fullquad));
224 static HRESULT media_engine_lock_d3d_device(struct media_engine *engine, ID3D11Device **device)
226 HRESULT hr;
228 if (!engine->device_manager)
230 FIXME("Device manager wasn't set.\n");
231 return E_UNEXPECTED;
234 if (!engine->device_handle)
236 if (FAILED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(engine->device_manager, &engine->device_handle)))
238 WARN("Failed to open device handle, hr %#lx.\n", hr);
239 return hr;
243 hr = IMFDXGIDeviceManager_LockDevice(engine->device_manager, engine->device_handle, &IID_ID3D11Device,
244 (void **)device, TRUE);
245 if (hr == MF_E_DXGI_NEW_VIDEO_DEVICE)
247 IMFDXGIDeviceManager_CloseDeviceHandle(engine->device_manager, engine->device_handle);
248 engine->device_handle = NULL;
250 media_engine_release_video_frame_resources(engine);
252 if (FAILED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(engine->device_manager, &engine->device_handle)))
254 WARN("Failed to open a device handle, hr %#lx.\n", hr);
255 return hr;
257 hr = IMFDXGIDeviceManager_LockDevice(engine->device_manager, engine->device_handle, &IID_ID3D11Device,
258 (void **)device, TRUE);
261 return hr;
264 static void media_engine_unlock_d3d_device(struct media_engine *engine, ID3D11Device *device)
266 ID3D11Device_Release(device);
267 IMFDXGIDeviceManager_UnlockDevice(engine->device_manager, engine->device_handle, FALSE);
270 static HRESULT media_engine_create_d3d11_video_frame_resources(struct media_engine *engine, ID3D11Device *device)
272 static const D3D11_INPUT_ELEMENT_DESC layout_desc[] =
274 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
276 static const DWORD vs_code[] =
278 #if 0
279 float4 main(float4 position : POSITION) : SV_POSITION
281 return position;
283 #endif
284 0x43425844, 0xa7a2f22d, 0x83ff2560, 0xe61638bd, 0x87e3ce90, 0x00000001, 0x000000d8, 0x00000003,
285 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
286 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x49534f50, 0x4e4f4954, 0xababab00,
287 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, 0x00000003,
288 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x52444853, 0x0000003c, 0x00010040,
289 0x0000000f, 0x0300005f, 0x001010f2, 0x00000000, 0x04000067, 0x001020f2, 0x00000000, 0x00000001,
290 0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000000, 0x0100003e,
292 static const DWORD ps_code[] =
294 #if 0
295 Texture2D t;
296 SamplerState s;
297 float4 dst;
298 float4 src;
299 float4 backcolor;
301 float4 main(float4 position : SV_POSITION) : SV_TARGET
303 float2 p;
305 if (position.x < dst.x || position.x > dst.z) return backcolor;
306 if (position.y < dst.y || position.y > dst.w) return backcolor;
307 p.x = (position.x - dst.x) / (dst.z - dst.x);
308 p.y = (position.y - dst.y) / (dst.w - dst.y);
309 p.x = src.x + p.x * (src.z - src.x);
310 p.y = src.y + p.y * (src.w - src.y);
311 return t.Sample(s, p);
313 #endif
314 0x43425844, 0xae2162b7, 0x0fd69625, 0x6784c41a, 0x84ae95de, 0x00000001, 0x000002f8, 0x00000003,
315 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
316 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000030f, 0x505f5653, 0x5449534f, 0x004e4f49,
317 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
318 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054, 0x52444853, 0x0000025c, 0x00000040,
319 0x00000097, 0x04000059, 0x00208e46, 0x00000000, 0x00000003, 0x0300005a, 0x00106000, 0x00000000,
320 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x04002064, 0x00101032, 0x00000000, 0x00000001,
321 0x03000065, 0x001020f2, 0x00000000, 0x02000068, 0x00000002, 0x08000031, 0x00100012, 0x00000000,
322 0x0010100a, 0x00000000, 0x0020800a, 0x00000000, 0x00000000, 0x08000031, 0x00100022, 0x00000000,
323 0x0020802a, 0x00000000, 0x00000000, 0x0010100a, 0x00000000, 0x0700003c, 0x00100012, 0x00000000,
324 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x09000000, 0x00100062, 0x00000000, 0x00101106,
325 0x00000000, 0x80208106, 0x00000041, 0x00000000, 0x00000000, 0x0a000000, 0x00100032, 0x00000001,
326 0x80208046, 0x00000041, 0x00000000, 0x00000000, 0x00208ae6, 0x00000000, 0x00000000, 0x0700000e,
327 0x00100062, 0x00000000, 0x00100656, 0x00000000, 0x00100106, 0x00000001, 0x0a000000, 0x00100032,
328 0x00000001, 0x80208046, 0x00000041, 0x00000000, 0x00000001, 0x00208ae6, 0x00000000, 0x00000001,
329 0x0a000032, 0x00100062, 0x00000000, 0x00100656, 0x00000000, 0x00100106, 0x00000001, 0x00208106,
330 0x00000000, 0x00000001, 0x09000045, 0x001000f2, 0x00000001, 0x00100596, 0x00000000, 0x00107e46,
331 0x00000000, 0x00106000, 0x00000000, 0x0304001f, 0x0010000a, 0x00000000, 0x06000036, 0x001020f2,
332 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e, 0x01000015, 0x08000031, 0x00100012,
333 0x00000000, 0x0010101a, 0x00000000, 0x0020801a, 0x00000000, 0x00000000, 0x08000031, 0x00100022,
334 0x00000000, 0x0020803a, 0x00000000, 0x00000000, 0x0010101a, 0x00000000, 0x0700003c, 0x00100012,
335 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a, 0x00000000,
336 0x06000036, 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e, 0x01000015,
337 0x05000036, 0x001020f2, 0x00000000, 0x00100e46, 0x00000001, 0x0100003e,
339 D3D11_SUBRESOURCE_DATA resource_data;
340 D3D11_TEXTURE2D_DESC texture_desc;
341 D3D11_SAMPLER_DESC sampler_desc;
342 D3D11_BUFFER_DESC buffer_desc;
343 HRESULT hr;
345 if (engine->video_frame.d3d11.source)
346 return S_OK;
348 /* Default vertex buffer, updated on first transfer call. */
349 buffer_desc.ByteWidth = sizeof(engine->video_frame.d3d11.quad);
350 buffer_desc.Usage = D3D11_USAGE_DEFAULT;
351 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
352 buffer_desc.CPUAccessFlags = 0;
353 buffer_desc.MiscFlags = 0;
354 buffer_desc.StructureByteStride = 0;
356 resource_data.pSysMem = engine->video_frame.d3d11.quad;
357 resource_data.SysMemPitch = 0;
358 resource_data.SysMemSlicePitch = 0;
360 if (FAILED(hr = ID3D11Device_CreateBuffer(device, &buffer_desc, &resource_data, &engine->video_frame.d3d11.vb)))
362 WARN("Failed to create a vertex buffer, hr %#lx.\n", hr);
363 goto failed;
366 buffer_desc.ByteWidth = sizeof(engine->video_frame.d3d11.cb);
367 buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
369 if (FAILED(hr = ID3D11Device_CreateBuffer(device, &buffer_desc, NULL, &engine->video_frame.d3d11.ps_cb)))
371 WARN("Failed to create a buffer, hr %#lx.\n", hr);
372 goto failed;
375 /* Source texture. */
376 texture_desc.Width = engine->video_frame.size.cx;
377 texture_desc.Height = engine->video_frame.size.cy;
378 texture_desc.MipLevels = 1;
379 texture_desc.ArraySize = 1;
380 texture_desc.Format = engine->video_frame.output_format;
381 texture_desc.SampleDesc.Count = 1;
382 texture_desc.SampleDesc.Quality = 0;
383 texture_desc.Usage = D3D11_USAGE_DEFAULT;
384 texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
385 texture_desc.CPUAccessFlags = 0;
386 texture_desc.MiscFlags = 0;
388 if (FAILED(hr = ID3D11Device_CreateTexture2D(device, &texture_desc, NULL, &engine->video_frame.d3d11.source)))
390 WARN("Failed to create source texture, hr %#lx.\n", hr);
391 goto failed;
394 if (FAILED(hr = ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource *)engine->video_frame.d3d11.source,
395 NULL, &engine->video_frame.d3d11.srv)))
397 WARN("Failed to create SRV, hr %#lx.\n", hr);
398 goto failed;
401 /* Sampler state. */
402 memset(&sampler_desc, 0, sizeof(sampler_desc));
403 sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
404 sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
405 sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
406 sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
408 if (FAILED(hr = ID3D11Device_CreateSamplerState(device, &sampler_desc, &engine->video_frame.d3d11.sampler)))
410 WARN("Failed to create a sampler state, hr %#lx.\n", hr);
411 goto failed;
414 /* Input layout */
415 if (FAILED(hr = ID3D11Device_CreateInputLayout(device, layout_desc, ARRAY_SIZE(layout_desc), vs_code, sizeof(vs_code),
416 &engine->video_frame.d3d11.input_layout)))
418 WARN("Failed to create input layout, hr %#lx.\n", hr);
419 goto failed;
422 /* Shaders */
423 if (FAILED(hr = ID3D11Device_CreateVertexShader(device, vs_code, sizeof(vs_code), NULL, &engine->video_frame.d3d11.vs)))
425 WARN("Failed to create the vertex shader, hr %#lx.\n", hr);
426 goto failed;
429 if (FAILED(hr = ID3D11Device_CreatePixelShader(device, ps_code, sizeof(ps_code), NULL, &engine->video_frame.d3d11.ps)))
431 WARN("Failed to create the pixel shader, hr %#lx.\n", hr);
432 goto failed;
435 failed:
437 return hr;
440 struct range
442 double start;
443 double end;
446 struct time_range
448 IMFMediaTimeRange IMFMediaTimeRange_iface;
449 LONG refcount;
451 struct range *ranges;
452 size_t count;
453 size_t capacity;
456 static struct time_range *impl_from_IMFMediaTimeRange(IMFMediaTimeRange *iface)
458 return CONTAINING_RECORD(iface, struct time_range, IMFMediaTimeRange_iface);
461 struct media_error
463 IMFMediaError IMFMediaError_iface;
464 LONG refcount;
465 unsigned int code;
466 HRESULT extended_code;
469 static struct media_error *impl_from_IMFMediaError(IMFMediaError *iface)
471 return CONTAINING_RECORD(iface, struct media_error, IMFMediaError_iface);
474 static HRESULT WINAPI media_error_QueryInterface(IMFMediaError *iface, REFIID riid, void **obj)
476 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
478 if (IsEqualIID(riid, &IID_IMFMediaError) ||
479 IsEqualIID(riid, &IID_IUnknown))
481 *obj = iface;
482 IMFMediaError_AddRef(iface);
483 return S_OK;
486 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
487 *obj = NULL;
488 return E_NOINTERFACE;
491 static ULONG WINAPI media_error_AddRef(IMFMediaError *iface)
493 struct media_error *me = impl_from_IMFMediaError(iface);
494 ULONG refcount = InterlockedIncrement(&me->refcount);
496 TRACE("%p, refcount %lu.\n", iface, refcount);
498 return refcount;
501 static ULONG WINAPI media_error_Release(IMFMediaError *iface)
503 struct media_error *me = impl_from_IMFMediaError(iface);
504 ULONG refcount = InterlockedDecrement(&me->refcount);
506 TRACE("%p, refcount %lu.\n", iface, refcount);
508 if (!refcount)
509 free(me);
511 return refcount;
514 static USHORT WINAPI media_error_GetErrorCode(IMFMediaError *iface)
516 struct media_error *me = impl_from_IMFMediaError(iface);
517 TRACE("%p.\n", iface);
518 return me->code;
521 static HRESULT WINAPI media_error_GetExtendedErrorCode(IMFMediaError *iface)
523 struct media_error *me = impl_from_IMFMediaError(iface);
524 TRACE("%p.\n", iface);
525 return me->extended_code;
528 static HRESULT WINAPI media_error_SetErrorCode(IMFMediaError *iface, MF_MEDIA_ENGINE_ERR code)
530 struct media_error *me = impl_from_IMFMediaError(iface);
532 TRACE("%p, %u.\n", iface, code);
534 if ((unsigned int)code > MF_MEDIA_ENGINE_ERR_ENCRYPTED)
535 return E_INVALIDARG;
537 me->code = code;
539 return S_OK;
542 static HRESULT WINAPI media_error_SetExtendedErrorCode(IMFMediaError *iface, HRESULT code)
544 struct media_error *me = impl_from_IMFMediaError(iface);
546 TRACE("%p, %#lx.\n", iface, code);
548 me->extended_code = code;
550 return S_OK;
553 static const IMFMediaErrorVtbl media_error_vtbl =
555 media_error_QueryInterface,
556 media_error_AddRef,
557 media_error_Release,
558 media_error_GetErrorCode,
559 media_error_GetExtendedErrorCode,
560 media_error_SetErrorCode,
561 media_error_SetExtendedErrorCode,
564 static HRESULT create_media_error(IMFMediaError **ret)
566 struct media_error *object;
568 *ret = NULL;
570 if (!(object = calloc(1, sizeof(*object))))
571 return E_OUTOFMEMORY;
573 object->IMFMediaError_iface.lpVtbl = &media_error_vtbl;
574 object->refcount = 1;
576 *ret = &object->IMFMediaError_iface;
578 return S_OK;
581 static HRESULT WINAPI time_range_QueryInterface(IMFMediaTimeRange *iface, REFIID riid, void **obj)
583 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
585 if (IsEqualIID(riid, &IID_IMFMediaTimeRange) ||
586 IsEqualIID(riid, &IID_IUnknown))
588 *obj = iface;
589 IMFMediaTimeRange_AddRef(iface);
590 return S_OK;
593 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
594 *obj = NULL;
595 return E_NOINTERFACE;
598 static ULONG WINAPI time_range_AddRef(IMFMediaTimeRange *iface)
600 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
601 ULONG refcount = InterlockedIncrement(&range->refcount);
603 TRACE("%p, refcount %lu.\n", iface, refcount);
605 return refcount;
608 static ULONG WINAPI time_range_Release(IMFMediaTimeRange *iface)
610 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
611 ULONG refcount = InterlockedDecrement(&range->refcount);
613 TRACE("%p, refcount %lu.\n", iface, refcount);
615 if (!refcount)
617 free(range->ranges);
618 free(range);
621 return refcount;
624 static DWORD WINAPI time_range_GetLength(IMFMediaTimeRange *iface)
626 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
628 TRACE("%p.\n", iface);
630 return range->count;
633 static HRESULT WINAPI time_range_GetStart(IMFMediaTimeRange *iface, DWORD idx, double *start)
635 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
637 TRACE("%p, %lu, %p.\n", iface, idx, start);
639 if (idx >= range->count)
640 return E_INVALIDARG;
642 *start = range->ranges[idx].start;
644 return S_OK;
647 static HRESULT WINAPI time_range_GetEnd(IMFMediaTimeRange *iface, DWORD idx, double *end)
649 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
651 TRACE("%p, %lu, %p.\n", iface, idx, end);
653 if (idx >= range->count)
654 return E_INVALIDARG;
656 *end = range->ranges[idx].end;
658 return S_OK;
661 static BOOL WINAPI time_range_ContainsTime(IMFMediaTimeRange *iface, double time)
663 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
664 size_t i;
666 TRACE("%p, %.8e.\n", iface, time);
668 for (i = 0; i < range->count; ++i)
670 if (time >= range->ranges[i].start && time <= range->ranges[i].end)
671 return TRUE;
674 return FALSE;
677 static HRESULT WINAPI time_range_AddRange(IMFMediaTimeRange *iface, double start, double end)
679 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
680 struct range *c;
681 size_t i;
683 TRACE("%p, %.8e, %.8e.\n", iface, start, end);
685 for (i = 0; i < range->count; ++i)
687 c = &range->ranges[i];
689 /* New range is fully contained within existing one. */
690 if (c->start <= start && c->end >= end)
691 return S_OK;
693 /* New range fully contains existing one. */
694 if (c->start >= start && c->end <= end)
696 c->start = start;
697 c->end = end;
698 return S_OK;
701 /* Merge if ranges intersect. */
702 if ((start >= c->start && start <= c->end) ||
703 (end >= c->start && end <= c->end))
705 c->start = min(c->start, start);
706 c->end = max(c->end, end);
707 return S_OK;
711 if (!mf_array_reserve((void **)&range->ranges, &range->capacity, range->count + 1, sizeof(*range->ranges)))
712 return E_OUTOFMEMORY;
714 range->ranges[range->count].start = start;
715 range->ranges[range->count].end = end;
716 range->count++;
718 return S_OK;
721 static HRESULT WINAPI time_range_Clear(IMFMediaTimeRange *iface)
723 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
725 TRACE("%p.\n", iface);
727 range->count = 0;
729 return S_OK;
732 static const IMFMediaTimeRangeVtbl time_range_vtbl =
734 time_range_QueryInterface,
735 time_range_AddRef,
736 time_range_Release,
737 time_range_GetLength,
738 time_range_GetStart,
739 time_range_GetEnd,
740 time_range_ContainsTime,
741 time_range_AddRange,
742 time_range_Clear,
745 static HRESULT create_time_range(IMFMediaTimeRange **range)
747 struct time_range *object;
749 object = calloc(1, sizeof(*object));
750 if (!object)
751 return E_OUTOFMEMORY;
753 object->IMFMediaTimeRange_iface.lpVtbl = &time_range_vtbl;
754 object->refcount = 1;
756 *range = &object->IMFMediaTimeRange_iface;
758 return S_OK;
761 static void media_engine_set_flag(struct media_engine *engine, unsigned int mask, BOOL value)
763 if (value)
764 engine->flags |= mask;
765 else
766 engine->flags &= ~mask;
769 static inline struct media_engine *impl_from_IMFMediaEngineEx(IMFMediaEngineEx *iface)
771 return CONTAINING_RECORD(iface, struct media_engine, IMFMediaEngineEx_iface);
774 static inline struct media_engine *impl_from_IMFGetService(IMFGetService *iface)
776 return CONTAINING_RECORD(iface, struct media_engine, IMFGetService_iface);
779 static struct media_engine *impl_from_session_events_IMFAsyncCallback(IMFAsyncCallback *iface)
781 return CONTAINING_RECORD(iface, struct media_engine, session_events);
784 static struct media_engine *impl_from_load_handler_IMFAsyncCallback(IMFAsyncCallback *iface)
786 return CONTAINING_RECORD(iface, struct media_engine, load_handler);
789 static struct media_engine *impl_from_IMFSampleGrabberSinkCallback(IMFSampleGrabberSinkCallback *iface)
791 return CONTAINING_RECORD(iface, struct media_engine, grabber_callback);
794 static unsigned int get_gcd(unsigned int a, unsigned int b)
796 unsigned int m;
798 while (b)
800 m = a % b;
801 a = b;
802 b = m;
805 return a;
808 static void media_engine_get_frame_size(struct media_engine *engine, IMFTopology *topology)
810 IMFMediaTypeHandler *handler;
811 IMFMediaType *media_type;
812 IMFStreamDescriptor *sd;
813 IMFTopologyNode *node;
814 unsigned int gcd;
815 UINT64 size;
816 HRESULT hr;
818 engine->video_frame.size.cx = 0;
819 engine->video_frame.size.cy = 0;
820 engine->video_frame.ratio.cx = 1;
821 engine->video_frame.ratio.cy = 1;
823 if (FAILED(IMFTopology_GetNodeByID(topology, engine->video_frame.node_id, &node)))
824 return;
826 hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR,
827 &IID_IMFStreamDescriptor, (void **)&sd);
828 IMFTopologyNode_Release(node);
829 if (FAILED(hr))
830 return;
832 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
833 IMFStreamDescriptor_Release(sd);
834 if (FAILED(hr))
835 return;
837 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &media_type);
838 IMFMediaTypeHandler_Release(handler);
839 if (FAILED(hr))
841 WARN("Failed to get current media type %#lx.\n", hr);
842 return;
845 IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &size);
847 engine->video_frame.size.cx = size >> 32;
848 engine->video_frame.size.cy = size;
850 if ((gcd = get_gcd(engine->video_frame.size.cx, engine->video_frame.size.cy)))
852 engine->video_frame.ratio.cx = engine->video_frame.size.cx / gcd;
853 engine->video_frame.ratio.cy = engine->video_frame.size.cy / gcd;
856 IMFMediaType_Release(media_type);
859 static void media_engine_apply_volume(const struct media_engine *engine)
861 IMFSimpleAudioVolume *sa_volume;
862 HRESULT hr;
864 if (!engine->session)
865 return;
867 if (FAILED(MFGetService((IUnknown *)engine->session, &MR_POLICY_VOLUME_SERVICE, &IID_IMFSimpleAudioVolume, (void **)&sa_volume)))
868 return;
870 if (FAILED(hr = IMFSimpleAudioVolume_SetMasterVolume(sa_volume, engine->volume)))
871 WARN("Failed to set master volume, hr %#lx.\n", hr);
873 IMFSimpleAudioVolume_Release(sa_volume);
876 static HRESULT WINAPI media_engine_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
878 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
879 IsEqualIID(riid, &IID_IUnknown))
881 *obj = iface;
882 IMFAsyncCallback_AddRef(iface);
883 return S_OK;
886 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
887 *obj = NULL;
888 return E_NOINTERFACE;
891 static ULONG WINAPI media_engine_session_events_AddRef(IMFAsyncCallback *iface)
893 struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
894 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
897 static ULONG WINAPI media_engine_session_events_Release(IMFAsyncCallback *iface)
899 struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
900 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
903 static HRESULT WINAPI media_engine_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
905 return E_NOTIMPL;
908 static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
910 struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
911 IMFMediaEvent *event = NULL;
912 MediaEventType event_type;
913 HRESULT hr;
915 if (FAILED(hr = IMFMediaSession_EndGetEvent(engine->session, result, &event)))
917 WARN("Failed to get session event, hr %#lx.\n", hr);
918 goto failed;
921 if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type)))
923 WARN("Failed to get event type, hr %#lx.\n", hr);
924 goto failed;
927 switch (event_type)
929 case MEBufferingStarted:
930 case MEBufferingStopped:
932 IMFMediaEngineNotify_EventNotify(engine->callback, event_type == MEBufferingStarted ?
933 MF_MEDIA_ENGINE_EVENT_BUFFERINGSTARTED : MF_MEDIA_ENGINE_EVENT_BUFFERINGENDED, 0, 0);
934 break;
935 case MESessionTopologyStatus:
937 UINT32 topo_status = 0;
938 IMFTopology *topology;
939 PROPVARIANT value;
941 IMFMediaEvent_GetUINT32(event, &MF_EVENT_TOPOLOGY_STATUS, &topo_status);
942 if (topo_status != MF_TOPOSTATUS_READY)
943 break;
945 value.vt = VT_EMPTY;
946 if (FAILED(IMFMediaEvent_GetValue(event, &value)))
947 break;
949 if (value.vt != VT_UNKNOWN)
951 PropVariantClear(&value);
952 break;
955 topology = (IMFTopology *)value.punkVal;
957 EnterCriticalSection(&engine->cs);
959 media_engine_apply_volume(engine);
961 engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_METADATA;
963 media_engine_get_frame_size(engine, topology);
965 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE, 0, 0);
966 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA, 0, 0);
968 engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_ENOUGH_DATA;
970 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDDATA, 0, 0);
971 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_CANPLAY, 0, 0);
973 LeaveCriticalSection(&engine->cs);
975 PropVariantClear(&value);
977 break;
979 case MESessionStarted:
981 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAYING, 0, 0);
982 break;
983 case MESessionEnded:
985 EnterCriticalSection(&engine->cs);
986 media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, FALSE);
987 media_engine_set_flag(engine, FLAGS_ENGINE_IS_ENDED, TRUE);
988 engine->video_frame.pts = MINLONGLONG;
989 LeaveCriticalSection(&engine->cs);
991 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ENDED, 0, 0);
992 break;
995 failed:
997 if (event)
998 IMFMediaEvent_Release(event);
1000 if (FAILED(hr = IMFMediaSession_BeginGetEvent(engine->session, iface, NULL)))
1001 WARN("Failed to subscribe to session events, hr %#lx.\n", hr);
1003 return S_OK;
1006 static const IMFAsyncCallbackVtbl media_engine_session_events_vtbl =
1008 media_engine_callback_QueryInterface,
1009 media_engine_session_events_AddRef,
1010 media_engine_session_events_Release,
1011 media_engine_callback_GetParameters,
1012 media_engine_session_events_Invoke,
1015 static ULONG WINAPI media_engine_load_handler_AddRef(IMFAsyncCallback *iface)
1017 struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
1018 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
1021 static ULONG WINAPI media_engine_load_handler_Release(IMFAsyncCallback *iface)
1023 struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
1024 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
1027 static HRESULT media_engine_create_source_node(IMFMediaSource *source, IMFPresentationDescriptor *pd, IMFStreamDescriptor *sd,
1028 IMFTopologyNode **node)
1030 HRESULT hr;
1032 if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, node)))
1033 return hr;
1035 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_SOURCE, (IUnknown *)source);
1036 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)pd);
1037 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd);
1039 return S_OK;
1042 static HRESULT media_engine_create_effects(struct effect *effects, size_t count,
1043 IMFTopologyNode *src, IMFTopologyNode *sink, IMFTopology *topology)
1045 IMFTopologyNode *last = src;
1046 HRESULT hr = S_OK;
1047 size_t i;
1049 IMFTopologyNode_AddRef(last);
1051 for (i = 0; i < count; ++i)
1053 IMFTopologyNode *node = NULL;
1055 if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node)))
1057 WARN("Failed to create transform node, hr %#lx.\n", hr);
1058 break;
1061 IMFTopologyNode_SetObject(node, (IUnknown *)effects[i].object);
1062 IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
1064 if (effects[i].optional)
1065 IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_CONNECT_METHOD, MF_CONNECT_AS_OPTIONAL);
1067 IMFTopology_AddNode(topology, node);
1068 IMFTopologyNode_ConnectOutput(last, 0, node, 0);
1070 IMFTopologyNode_Release(last);
1071 last = node;
1074 IMFTopologyNode_Release(last);
1076 if (SUCCEEDED(hr))
1077 hr = IMFTopologyNode_ConnectOutput(last, 0, sink, 0);
1079 return hr;
1082 static HRESULT media_engine_create_audio_renderer(struct media_engine *engine, IMFTopologyNode **node)
1084 unsigned int category, role;
1085 IMFActivate *sar_activate;
1086 HRESULT hr;
1088 *node = NULL;
1090 if (FAILED(hr = MFCreateAudioRendererActivate(&sar_activate)))
1091 return hr;
1093 /* Configuration attributes keys differ between Engine and SAR. */
1094 if (SUCCEEDED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, &category)))
1095 IMFActivate_SetUINT32(sar_activate, &MF_AUDIO_RENDERER_ATTRIBUTE_STREAM_CATEGORY, category);
1096 if (SUCCEEDED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, &role)))
1097 IMFActivate_SetUINT32(sar_activate, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, role);
1099 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, node)))
1101 IMFTopologyNode_SetObject(*node, (IUnknown *)sar_activate);
1102 IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
1105 IMFActivate_Release(sar_activate);
1107 return hr;
1110 static HRESULT media_engine_create_video_renderer(struct media_engine *engine, IMFTopologyNode **node)
1112 DXGI_FORMAT output_format;
1113 IMFMediaType *media_type;
1114 IMFActivate *activate;
1115 GUID subtype;
1116 HRESULT hr;
1118 *node = NULL;
1120 if (FAILED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, &output_format)))
1122 WARN("Output format was not specified.\n");
1123 return E_FAIL;
1126 memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype));
1127 if (!(subtype.Data1 = MFMapDXGIFormatToDX9Format(output_format)))
1129 WARN("Unrecognized output format %#x.\n", output_format);
1130 return E_FAIL;
1133 if (FAILED(hr = MFCreateMediaType(&media_type)))
1134 return hr;
1136 IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video);
1137 IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &subtype);
1139 hr = MFCreateSampleGrabberSinkActivate(media_type, &engine->grabber_callback, &activate);
1140 IMFMediaType_Release(media_type);
1141 if (FAILED(hr))
1142 return hr;
1144 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, node)))
1146 IMFTopologyNode_SetObject(*node, (IUnknown *)activate);
1147 IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
1150 IMFActivate_Release(activate);
1152 engine->video_frame.output_format = output_format;
1154 return hr;
1157 static void media_engine_clear_presentation(struct media_engine *engine)
1159 if (engine->presentation.source)
1161 IMFMediaSource_Shutdown(engine->presentation.source);
1162 IMFMediaSource_Release(engine->presentation.source);
1164 if (engine->presentation.pd)
1165 IMFPresentationDescriptor_Release(engine->presentation.pd);
1166 memset(&engine->presentation, 0, sizeof(engine->presentation));
1169 static void media_engine_clear_effects(struct effects *effects)
1171 size_t i;
1173 for (i = 0; i < effects->count; ++i)
1175 if (effects->effects[i].object)
1176 IUnknown_Release(effects->effects[i].object);
1179 free(effects->effects);
1180 memset(effects, 0, sizeof(*effects));
1183 static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMediaSource *source)
1185 IMFStreamDescriptor *sd_audio = NULL, *sd_video = NULL;
1186 IMFPresentationDescriptor *pd;
1187 DWORD stream_count = 0, i;
1188 IMFTopology *topology;
1189 UINT64 duration;
1190 HRESULT hr;
1192 media_engine_release_video_frame_resources(engine);
1193 media_engine_clear_presentation(engine);
1195 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd)))
1196 return hr;
1198 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(pd, &stream_count)))
1199 WARN("Failed to get stream count, hr %#lx.\n", hr);
1201 /* Enable first video stream and first audio stream. */
1203 for (i = 0; i < stream_count; ++i)
1205 IMFMediaTypeHandler *type_handler;
1206 IMFStreamDescriptor *sd;
1207 BOOL selected;
1209 IMFPresentationDescriptor_DeselectStream(pd, i);
1211 if (sd_audio && sd_video)
1212 continue;
1214 IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, i, &selected, &sd);
1216 if (SUCCEEDED(IMFStreamDescriptor_GetMediaTypeHandler(sd, &type_handler)))
1218 GUID major = { 0 };
1220 IMFMediaTypeHandler_GetMajorType(type_handler, &major);
1222 if (IsEqualGUID(&major, &MFMediaType_Audio) && !sd_audio)
1224 sd_audio = sd;
1225 IMFStreamDescriptor_AddRef(sd_audio);
1226 IMFPresentationDescriptor_SelectStream(pd, i);
1228 else if (IsEqualGUID(&major, &MFMediaType_Video) && !sd_video && !(engine->flags & MF_MEDIA_ENGINE_AUDIOONLY))
1230 sd_video = sd;
1231 IMFStreamDescriptor_AddRef(sd_video);
1232 IMFPresentationDescriptor_SelectStream(pd, i);
1235 IMFMediaTypeHandler_Release(type_handler);
1238 IMFStreamDescriptor_Release(sd);
1241 if (!sd_video && !sd_audio)
1243 IMFPresentationDescriptor_Release(pd);
1244 return E_UNEXPECTED;
1247 engine->presentation.source = source;
1248 IMFMediaSource_AddRef(engine->presentation.source);
1249 engine->presentation.pd = pd;
1250 IMFPresentationDescriptor_AddRef(engine->presentation.pd);
1252 media_engine_set_flag(engine, FLAGS_ENGINE_HAS_VIDEO, !!sd_video);
1253 media_engine_set_flag(engine, FLAGS_ENGINE_HAS_AUDIO, !!sd_audio);
1255 /* Assume live source if duration was not provided. */
1256 if (SUCCEEDED(IMFPresentationDescriptor_GetUINT64(pd, &MF_PD_DURATION, &duration)))
1257 engine->duration = mftime_to_seconds(duration);
1258 else
1259 engine->duration = INFINITY;
1261 if (SUCCEEDED(hr = MFCreateTopology(&topology)))
1263 IMFTopologyNode *sar_node = NULL, *audio_src = NULL;
1264 IMFTopologyNode *grabber_node = NULL, *video_src = NULL;
1266 if (engine->flags & MF_MEDIA_ENGINE_REAL_TIME_MODE)
1267 IMFTopology_SetUINT32(topology, &MF_LOW_LATENCY, TRUE);
1269 if (sd_audio)
1271 if (FAILED(hr = media_engine_create_source_node(source, pd, sd_audio, &audio_src)))
1272 WARN("Failed to create audio source node, hr %#lx.\n", hr);
1274 if (FAILED(hr = media_engine_create_audio_renderer(engine, &sar_node)))
1275 WARN("Failed to create audio renderer node, hr %#lx.\n", hr);
1277 if (sar_node && audio_src)
1279 IMFTopology_AddNode(topology, audio_src);
1280 IMFTopology_AddNode(topology, sar_node);
1282 if (FAILED(hr = media_engine_create_effects(engine->audio_effects.effects, engine->audio_effects.count,
1283 audio_src, sar_node, topology)))
1284 WARN("Failed to create audio effect nodes, hr %#lx.\n", hr);
1287 if (sar_node)
1288 IMFTopologyNode_Release(sar_node);
1289 if (audio_src)
1290 IMFTopologyNode_Release(audio_src);
1293 if (SUCCEEDED(hr) && sd_video)
1295 if (FAILED(hr = media_engine_create_source_node(source, pd, sd_video, &video_src)))
1296 WARN("Failed to create video source node, hr %#lx.\n", hr);
1298 if (FAILED(hr = media_engine_create_video_renderer(engine, &grabber_node)))
1299 WARN("Failed to create video grabber node, hr %#lx.\n", hr);
1301 if (grabber_node && video_src)
1303 IMFTopology_AddNode(topology, video_src);
1304 IMFTopology_AddNode(topology, grabber_node);
1306 if (FAILED(hr = media_engine_create_effects(engine->video_effects.effects, engine->video_effects.count,
1307 video_src, grabber_node, topology)))
1308 WARN("Failed to create video effect nodes, hr %#lx.\n", hr);
1311 if (SUCCEEDED(hr))
1312 IMFTopologyNode_GetTopoNodeID(video_src, &engine->video_frame.node_id);
1314 if (grabber_node)
1315 IMFTopologyNode_Release(grabber_node);
1316 if (video_src)
1317 IMFTopologyNode_Release(video_src);
1320 IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, TRUE);
1322 if (SUCCEEDED(hr))
1323 hr = IMFMediaSession_SetTopology(engine->session, MFSESSION_SETTOPOLOGY_IMMEDIATE, topology);
1326 if (topology)
1327 IMFTopology_Release(topology);
1329 if (sd_video)
1330 IMFStreamDescriptor_Release(sd_video);
1331 if (sd_audio)
1332 IMFStreamDescriptor_Release(sd_audio);
1334 IMFPresentationDescriptor_Release(pd);
1336 return hr;
1339 static void media_engine_start_playback(struct media_engine *engine)
1341 PROPVARIANT var;
1343 var.vt = VT_EMPTY;
1344 IMFMediaSession_Start(engine->session, &GUID_NULL, &var);
1347 static HRESULT WINAPI media_engine_load_handler_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1349 struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
1350 IUnknown *object = NULL, *state;
1351 unsigned int start_playback;
1352 MF_OBJECT_TYPE obj_type;
1353 IMFMediaSource *source;
1354 HRESULT hr;
1356 EnterCriticalSection(&engine->cs);
1358 engine->network_state = MF_MEDIA_ENGINE_NETWORK_LOADING;
1359 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADSTART, 0, 0);
1361 start_playback = engine->flags & FLAGS_ENGINE_PLAY_PENDING;
1362 media_engine_set_flag(engine, FLAGS_ENGINE_SOURCE_PENDING | FLAGS_ENGINE_PLAY_PENDING, FALSE);
1364 if (SUCCEEDED(IMFAsyncResult_GetState(result, &state)))
1366 hr = IMFSourceResolver_EndCreateObjectFromByteStream(engine->resolver, result, &obj_type, &object);
1367 IUnknown_Release(state);
1369 else
1370 hr = IMFSourceResolver_EndCreateObjectFromURL(engine->resolver, result, &obj_type, &object);
1372 if (FAILED(hr))
1373 WARN("Failed to create source object, hr %#lx.\n", hr);
1375 if (object)
1377 if (SUCCEEDED(hr = IUnknown_QueryInterface(object, &IID_IMFMediaSource, (void **)&source)))
1379 hr = media_engine_create_topology(engine, source);
1380 IMFMediaSource_Release(source);
1382 IUnknown_Release(object);
1385 if (SUCCEEDED(hr))
1387 engine->network_state = MF_MEDIA_ENGINE_NETWORK_IDLE;
1388 if (start_playback)
1389 media_engine_start_playback(engine);
1391 else
1393 engine->network_state = MF_MEDIA_ENGINE_NETWORK_NO_SOURCE;
1394 engine->error_code = MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED;
1395 engine->extended_code = hr;
1396 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ERROR, engine->error_code,
1397 engine->extended_code);
1400 LeaveCriticalSection(&engine->cs);
1402 return S_OK;
1405 static const IMFAsyncCallbackVtbl media_engine_load_handler_vtbl =
1407 media_engine_callback_QueryInterface,
1408 media_engine_load_handler_AddRef,
1409 media_engine_load_handler_Release,
1410 media_engine_callback_GetParameters,
1411 media_engine_load_handler_Invoke,
1414 static HRESULT WINAPI media_engine_QueryInterface(IMFMediaEngineEx *iface, REFIID riid, void **obj)
1416 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1418 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1420 if (IsEqualIID(riid, &IID_IMFMediaEngineEx) ||
1421 IsEqualIID(riid, &IID_IMFMediaEngine) ||
1422 IsEqualIID(riid, &IID_IUnknown))
1424 *obj = iface;
1426 else if (IsEqualIID(riid, &IID_IMFGetService))
1428 *obj = &engine->IMFGetService_iface;
1430 else
1432 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1433 *obj = NULL;
1434 return E_NOINTERFACE;
1437 IUnknown_AddRef((IUnknown *)*obj);
1438 return S_OK;
1441 static ULONG WINAPI media_engine_AddRef(IMFMediaEngineEx *iface)
1443 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1444 ULONG refcount = InterlockedIncrement(&engine->refcount);
1446 TRACE("%p, refcount %lu.\n", iface, refcount);
1448 return refcount;
1451 static void free_media_engine(struct media_engine *engine)
1453 if (engine->callback)
1454 IMFMediaEngineNotify_Release(engine->callback);
1455 if (engine->clock)
1456 IMFPresentationClock_Release(engine->clock);
1457 if (engine->session)
1458 IMFMediaSession_Release(engine->session);
1459 if (engine->attributes)
1460 IMFAttributes_Release(engine->attributes);
1461 if (engine->resolver)
1462 IMFSourceResolver_Release(engine->resolver);
1463 media_engine_clear_effects(&engine->audio_effects);
1464 media_engine_clear_effects(&engine->video_effects);
1465 media_engine_release_video_frame_resources(engine);
1466 media_engine_clear_presentation(engine);
1467 if (engine->device_manager)
1469 IMFDXGIDeviceManager_CloseDeviceHandle(engine->device_manager, engine->device_handle);
1470 IMFDXGIDeviceManager_Release(engine->device_manager);
1472 SysFreeString(engine->current_source);
1473 DeleteCriticalSection(&engine->cs);
1474 free(engine->video_frame.buffer);
1475 free(engine);
1478 static ULONG WINAPI media_engine_Release(IMFMediaEngineEx *iface)
1480 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1481 ULONG refcount = InterlockedDecrement(&engine->refcount);
1483 TRACE("%p, refcount %lu.\n", iface, refcount);
1485 if (!refcount)
1486 free_media_engine(engine);
1488 return refcount;
1491 static HRESULT WINAPI media_engine_GetError(IMFMediaEngineEx *iface, IMFMediaError **error)
1493 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1494 HRESULT hr = S_OK;
1496 TRACE("%p, %p.\n", iface, error);
1498 *error = NULL;
1500 EnterCriticalSection(&engine->cs);
1501 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1502 hr = MF_E_SHUTDOWN;
1503 else if (engine->error_code)
1505 if (SUCCEEDED(hr = create_media_error(error)))
1507 IMFMediaError_SetErrorCode(*error, engine->error_code);
1508 IMFMediaError_SetExtendedErrorCode(*error, engine->extended_code);
1511 LeaveCriticalSection(&engine->cs);
1513 return hr;
1516 static HRESULT WINAPI media_engine_SetErrorCode(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_ERR code)
1518 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1519 HRESULT hr = S_OK;
1521 TRACE("%p, %u.\n", iface, code);
1523 if ((unsigned int)code > MF_MEDIA_ENGINE_ERR_ENCRYPTED)
1524 return E_INVALIDARG;
1526 EnterCriticalSection(&engine->cs);
1527 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1528 hr = MF_E_SHUTDOWN;
1529 else
1530 engine->error_code = code;
1531 LeaveCriticalSection(&engine->cs);
1533 return hr;
1536 static HRESULT WINAPI media_engine_SetSourceElements(IMFMediaEngineEx *iface, IMFMediaEngineSrcElements *elements)
1538 FIXME("(%p, %p): stub.\n", iface, elements);
1540 return E_NOTIMPL;
1543 static HRESULT media_engine_set_source(struct media_engine *engine, IMFByteStream *bytestream, BSTR url)
1545 IPropertyStore *props = NULL;
1546 unsigned int flags;
1547 HRESULT hr = S_OK;
1549 SysFreeString(engine->current_source);
1550 engine->current_source = NULL;
1551 if (url)
1552 engine->current_source = SysAllocString(url);
1554 engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_NOTHING;
1556 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
1558 engine->network_state = MF_MEDIA_ENGINE_NETWORK_NO_SOURCE;
1560 if (url || bytestream)
1562 flags = MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE;
1563 if (engine->flags & MF_MEDIA_ENGINE_DISABLE_LOCAL_PLUGINS)
1564 flags |= MF_RESOLUTION_DISABLE_LOCAL_PLUGINS;
1566 IMFAttributes_GetUnknown(engine->attributes, &MF_MEDIA_ENGINE_SOURCE_RESOLVER_CONFIG_STORE,
1567 &IID_IPropertyStore, (void **)&props);
1568 if (bytestream)
1569 hr = IMFSourceResolver_BeginCreateObjectFromByteStream(engine->resolver, bytestream, url, flags,
1570 props, NULL, &engine->load_handler, (IUnknown *)bytestream);
1571 else
1572 hr = IMFSourceResolver_BeginCreateObjectFromURL(engine->resolver, url, flags, props, NULL,
1573 &engine->load_handler, NULL);
1574 if (SUCCEEDED(hr))
1575 media_engine_set_flag(engine, FLAGS_ENGINE_SOURCE_PENDING, TRUE);
1577 if (props)
1578 IPropertyStore_Release(props);
1581 return hr;
1584 static HRESULT WINAPI media_engine_SetSource(IMFMediaEngineEx *iface, BSTR url)
1586 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1587 HRESULT hr;
1589 TRACE("%p, %s.\n", iface, debugstr_w(url));
1591 EnterCriticalSection(&engine->cs);
1593 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1594 hr = MF_E_SHUTDOWN;
1595 else
1596 hr = media_engine_set_source(engine, NULL, url);
1598 LeaveCriticalSection(&engine->cs);
1600 return hr;
1603 static HRESULT WINAPI media_engine_GetCurrentSource(IMFMediaEngineEx *iface, BSTR *url)
1605 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1606 HRESULT hr = S_OK;
1608 TRACE("%p, %p.\n", iface, url);
1610 *url = NULL;
1612 EnterCriticalSection(&engine->cs);
1614 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1615 hr = MF_E_SHUTDOWN;
1616 if (engine->current_source)
1618 if (!(*url = SysAllocString(engine->current_source)))
1619 hr = E_OUTOFMEMORY;
1622 LeaveCriticalSection(&engine->cs);
1624 return hr;
1627 static USHORT WINAPI media_engine_GetNetworkState(IMFMediaEngineEx *iface)
1629 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1631 TRACE("%p.\n", iface);
1633 return engine->network_state;
1636 static MF_MEDIA_ENGINE_PRELOAD WINAPI media_engine_GetPreload(IMFMediaEngineEx *iface)
1638 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1639 MF_MEDIA_ENGINE_PRELOAD preload;
1641 TRACE("%p.\n", iface);
1643 EnterCriticalSection(&engine->cs);
1644 preload = engine->preload;
1645 LeaveCriticalSection(&engine->cs);
1647 return preload;
1650 static HRESULT WINAPI media_engine_SetPreload(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_PRELOAD preload)
1652 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1654 TRACE("%p, %d.\n", iface, preload);
1656 EnterCriticalSection(&engine->cs);
1657 engine->preload = preload;
1658 LeaveCriticalSection(&engine->cs);
1660 return S_OK;
1663 static HRESULT WINAPI media_engine_GetBuffered(IMFMediaEngineEx *iface, IMFMediaTimeRange **range)
1665 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1666 HRESULT hr;
1668 TRACE("%p, %p.\n", iface, range);
1670 if (FAILED(hr = create_time_range(range)))
1671 return hr;
1673 EnterCriticalSection(&engine->cs);
1675 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1676 hr = MF_E_SHUTDOWN;
1677 else if (!isnan(engine->duration))
1678 hr = IMFMediaTimeRange_AddRange(*range, 0.0, engine->duration);
1680 LeaveCriticalSection(&engine->cs);
1682 return hr;
1685 static HRESULT WINAPI media_engine_Load(IMFMediaEngineEx *iface)
1687 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1688 HRESULT hr = E_NOTIMPL;
1690 FIXME("(%p): stub.\n", iface);
1692 EnterCriticalSection(&engine->cs);
1694 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1695 hr = MF_E_SHUTDOWN;
1697 LeaveCriticalSection(&engine->cs);
1699 return hr;
1702 static HRESULT WINAPI media_engine_CanPlayType(IMFMediaEngineEx *iface, BSTR type, MF_MEDIA_ENGINE_CANPLAY *answer)
1704 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1705 HRESULT hr = E_NOTIMPL;
1707 FIXME("(%p, %s, %p): stub.\n", iface, debugstr_w(type), answer);
1709 EnterCriticalSection(&engine->cs);
1711 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1712 hr = MF_E_SHUTDOWN;
1714 LeaveCriticalSection(&engine->cs);
1716 return hr;
1719 static USHORT WINAPI media_engine_GetReadyState(IMFMediaEngineEx *iface)
1721 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1722 unsigned short state;
1724 TRACE("%p.\n", iface);
1726 EnterCriticalSection(&engine->cs);
1727 state = engine->ready_state;
1728 LeaveCriticalSection(&engine->cs);
1730 return state;
1733 static BOOL WINAPI media_engine_IsSeeking(IMFMediaEngineEx *iface)
1735 FIXME("(%p): stub.\n", iface);
1737 return FALSE;
1740 static double WINAPI media_engine_GetCurrentTime(IMFMediaEngineEx *iface)
1742 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1743 double ret = 0.0;
1744 MFTIME clocktime;
1746 TRACE("%p.\n", iface);
1748 EnterCriticalSection(&engine->cs);
1749 if (engine->flags & FLAGS_ENGINE_IS_ENDED)
1751 ret = engine->duration;
1753 else if (SUCCEEDED(IMFPresentationClock_GetTime(engine->clock, &clocktime)))
1755 ret = mftime_to_seconds(clocktime);
1757 LeaveCriticalSection(&engine->cs);
1759 return ret;
1762 static HRESULT WINAPI media_engine_SetCurrentTime(IMFMediaEngineEx *iface, double time)
1764 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1765 HRESULT hr = E_NOTIMPL;
1767 FIXME("(%p, %f): stub.\n", iface, time);
1769 EnterCriticalSection(&engine->cs);
1771 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1772 hr = MF_E_SHUTDOWN;
1774 LeaveCriticalSection(&engine->cs);
1776 return hr;
1779 static double WINAPI media_engine_GetStartTime(IMFMediaEngineEx *iface)
1781 FIXME("(%p): stub.\n", iface);
1783 return 0.0;
1786 static double WINAPI media_engine_GetDuration(IMFMediaEngineEx *iface)
1788 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1789 double value;
1791 TRACE("%p.\n", iface);
1793 EnterCriticalSection(&engine->cs);
1794 value = engine->duration;
1795 LeaveCriticalSection(&engine->cs);
1797 return value;
1800 static BOOL WINAPI media_engine_IsPaused(IMFMediaEngineEx *iface)
1802 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1803 BOOL value;
1805 TRACE("%p.\n", iface);
1807 EnterCriticalSection(&engine->cs);
1808 value = !!(engine->flags & FLAGS_ENGINE_PAUSED);
1809 LeaveCriticalSection(&engine->cs);
1811 return value;
1814 static double WINAPI media_engine_GetDefaultPlaybackRate(IMFMediaEngineEx *iface)
1816 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1817 double rate;
1819 TRACE("%p.\n", iface);
1821 EnterCriticalSection(&engine->cs);
1822 rate = engine->default_playback_rate;
1823 LeaveCriticalSection(&engine->cs);
1825 return rate;
1828 static HRESULT WINAPI media_engine_SetDefaultPlaybackRate(IMFMediaEngineEx *iface, double rate)
1830 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1831 HRESULT hr = S_OK;
1833 TRACE("%p, %f.\n", iface, rate);
1835 EnterCriticalSection(&engine->cs);
1836 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1837 hr = MF_E_SHUTDOWN;
1838 else if (engine->default_playback_rate != rate)
1840 engine->default_playback_rate = rate;
1841 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_RATECHANGE, 0, 0);
1843 LeaveCriticalSection(&engine->cs);
1845 return hr;
1848 static double WINAPI media_engine_GetPlaybackRate(IMFMediaEngineEx *iface)
1850 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1851 double rate;
1853 TRACE("%p.\n", iface);
1855 EnterCriticalSection(&engine->cs);
1856 rate = engine->playback_rate;
1857 LeaveCriticalSection(&engine->cs);
1859 return rate;
1862 static HRESULT WINAPI media_engine_SetPlaybackRate(IMFMediaEngineEx *iface, double rate)
1864 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1865 HRESULT hr = S_OK;
1867 TRACE("%p, %f.\n", iface, rate);
1869 EnterCriticalSection(&engine->cs);
1870 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1871 hr = MF_E_SHUTDOWN;
1872 else if (engine->playback_rate != rate)
1874 engine->playback_rate = rate;
1875 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_RATECHANGE, 0, 0);
1877 LeaveCriticalSection(&engine->cs);
1879 return hr;
1882 static HRESULT WINAPI media_engine_GetPlayed(IMFMediaEngineEx *iface, IMFMediaTimeRange **played)
1884 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1885 HRESULT hr = E_NOTIMPL;
1887 FIXME("(%p, %p): stub.\n", iface, played);
1889 EnterCriticalSection(&engine->cs);
1891 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1892 hr = MF_E_SHUTDOWN;
1894 LeaveCriticalSection(&engine->cs);
1896 return hr;
1899 static HRESULT WINAPI media_engine_GetSeekable(IMFMediaEngineEx *iface, IMFMediaTimeRange **seekable)
1901 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1902 IMFMediaTimeRange *time_range = NULL;
1903 DWORD flags;
1904 HRESULT hr;
1906 TRACE("%p, %p.\n", iface, seekable);
1908 EnterCriticalSection(&engine->cs);
1910 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1911 hr = MF_E_SHUTDOWN;
1912 else
1914 hr = create_time_range(&time_range);
1915 if (SUCCEEDED(hr) && !isnan(engine->duration) && engine->presentation.source)
1917 hr = IMFMediaSource_GetCharacteristics(engine->presentation.source, &flags);
1918 if (SUCCEEDED(hr) && (flags & MFBYTESTREAM_IS_SEEKABLE))
1919 hr = IMFMediaTimeRange_AddRange(time_range, 0.0, engine->duration);
1923 LeaveCriticalSection(&engine->cs);
1925 if (FAILED(hr) && time_range)
1927 IMFMediaTimeRange_Release(time_range);
1928 time_range = NULL;
1930 *seekable = time_range;
1931 return hr;
1934 static BOOL WINAPI media_engine_IsEnded(IMFMediaEngineEx *iface)
1936 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1937 BOOL value;
1939 TRACE("%p.\n", iface);
1941 EnterCriticalSection(&engine->cs);
1942 value = !!(engine->flags & FLAGS_ENGINE_IS_ENDED);
1943 LeaveCriticalSection(&engine->cs);
1945 return value;
1948 static BOOL WINAPI media_engine_GetAutoPlay(IMFMediaEngineEx *iface)
1950 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1951 BOOL value;
1953 TRACE("%p.\n", iface);
1955 EnterCriticalSection(&engine->cs);
1956 value = !!(engine->flags & FLAGS_ENGINE_AUTO_PLAY);
1957 LeaveCriticalSection(&engine->cs);
1959 return value;
1962 static HRESULT WINAPI media_engine_SetAutoPlay(IMFMediaEngineEx *iface, BOOL autoplay)
1964 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1966 FIXME("(%p, %d): stub.\n", iface, autoplay);
1968 EnterCriticalSection(&engine->cs);
1969 media_engine_set_flag(engine, FLAGS_ENGINE_AUTO_PLAY, autoplay);
1970 LeaveCriticalSection(&engine->cs);
1972 return S_OK;
1975 static BOOL WINAPI media_engine_GetLoop(IMFMediaEngineEx *iface)
1977 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1978 BOOL value;
1980 TRACE("%p.\n", iface);
1982 EnterCriticalSection(&engine->cs);
1983 value = !!(engine->flags & FLAGS_ENGINE_LOOP);
1984 LeaveCriticalSection(&engine->cs);
1986 return value;
1989 static HRESULT WINAPI media_engine_SetLoop(IMFMediaEngineEx *iface, BOOL loop)
1991 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1993 FIXME("(%p, %d): stub.\n", iface, loop);
1995 EnterCriticalSection(&engine->cs);
1996 media_engine_set_flag(engine, FLAGS_ENGINE_LOOP, loop);
1997 LeaveCriticalSection(&engine->cs);
1999 return S_OK;
2002 static HRESULT WINAPI media_engine_Play(IMFMediaEngineEx *iface)
2004 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2005 HRESULT hr = S_OK;
2007 TRACE("%p.\n", iface);
2009 EnterCriticalSection(&engine->cs);
2011 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2012 hr = MF_E_SHUTDOWN;
2013 else
2015 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
2017 if (!(engine->flags & FLAGS_ENGINE_WAITING))
2019 media_engine_set_flag(engine, FLAGS_ENGINE_PAUSED | FLAGS_ENGINE_IS_ENDED, FALSE);
2020 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAY, 0, 0);
2022 if (!(engine->flags & FLAGS_ENGINE_SOURCE_PENDING))
2023 media_engine_start_playback(engine);
2024 else
2025 media_engine_set_flag(engine, FLAGS_ENGINE_PLAY_PENDING, TRUE);
2027 media_engine_set_flag(engine, FLAGS_ENGINE_WAITING, TRUE);
2030 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_WAITING, 0, 0);
2033 LeaveCriticalSection(&engine->cs);
2035 return hr;
2038 static HRESULT WINAPI media_engine_Pause(IMFMediaEngineEx *iface)
2040 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2041 HRESULT hr = S_OK;
2043 TRACE("%p.\n", iface);
2045 EnterCriticalSection(&engine->cs);
2047 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2048 hr = MF_E_SHUTDOWN;
2049 else
2051 if (!(engine->flags & FLAGS_ENGINE_PAUSED))
2053 if (SUCCEEDED(hr = IMFMediaSession_Pause(engine->session)))
2055 media_engine_set_flag(engine, FLAGS_ENGINE_WAITING | FLAGS_ENGINE_IS_ENDED, FALSE);
2056 media_engine_set_flag(engine, FLAGS_ENGINE_PAUSED, TRUE);
2058 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_TIMEUPDATE, 0, 0);
2059 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PAUSE, 0, 0);
2063 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
2066 LeaveCriticalSection(&engine->cs);
2068 return hr;
2071 static BOOL WINAPI media_engine_GetMuted(IMFMediaEngineEx *iface)
2073 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2074 BOOL ret;
2076 TRACE("%p.\n", iface);
2078 EnterCriticalSection(&engine->cs);
2079 ret = !!(engine->flags & FLAGS_ENGINE_MUTED);
2080 LeaveCriticalSection(&engine->cs);
2082 return ret;
2085 static HRESULT WINAPI media_engine_SetMuted(IMFMediaEngineEx *iface, BOOL muted)
2087 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2088 HRESULT hr = S_OK;
2090 TRACE("%p, %d.\n", iface, muted);
2092 EnterCriticalSection(&engine->cs);
2093 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2094 hr = MF_E_SHUTDOWN;
2095 else if (!!(engine->flags & FLAGS_ENGINE_MUTED) ^ !!muted)
2097 media_engine_set_flag(engine, FLAGS_ENGINE_MUTED, muted);
2098 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE, 0, 0);
2100 LeaveCriticalSection(&engine->cs);
2102 return hr;
2105 static double WINAPI media_engine_GetVolume(IMFMediaEngineEx *iface)
2107 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2108 double volume;
2110 TRACE("%p.\n", iface);
2112 EnterCriticalSection(&engine->cs);
2113 volume = engine->volume;
2114 LeaveCriticalSection(&engine->cs);
2116 return volume;
2119 static HRESULT WINAPI media_engine_SetVolume(IMFMediaEngineEx *iface, double volume)
2121 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2122 HRESULT hr = S_OK;
2124 TRACE("%p, %f.\n", iface, volume);
2126 EnterCriticalSection(&engine->cs);
2127 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2128 hr = MF_E_SHUTDOWN;
2129 else if (volume != engine->volume)
2131 engine->volume = volume;
2132 media_engine_apply_volume(engine);
2133 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE, 0, 0);
2135 LeaveCriticalSection(&engine->cs);
2137 return hr;
2140 static BOOL WINAPI media_engine_HasVideo(IMFMediaEngineEx *iface)
2142 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2143 BOOL value;
2145 TRACE("%p.\n", iface);
2147 EnterCriticalSection(&engine->cs);
2148 value = !!(engine->flags & FLAGS_ENGINE_HAS_VIDEO);
2149 LeaveCriticalSection(&engine->cs);
2151 return value;
2154 static BOOL WINAPI media_engine_HasAudio(IMFMediaEngineEx *iface)
2156 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2157 BOOL value;
2159 TRACE("%p.\n", iface);
2161 EnterCriticalSection(&engine->cs);
2162 value = !!(engine->flags & FLAGS_ENGINE_HAS_AUDIO);
2163 LeaveCriticalSection(&engine->cs);
2165 return value;
2168 static HRESULT WINAPI media_engine_GetNativeVideoSize(IMFMediaEngineEx *iface, DWORD *cx, DWORD *cy)
2170 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2171 HRESULT hr = S_OK;
2173 TRACE("%p, %p, %p.\n", iface, cx, cy);
2175 if (!cx && !cy)
2176 return E_INVALIDARG;
2178 EnterCriticalSection(&engine->cs);
2180 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2181 hr = MF_E_SHUTDOWN;
2182 else if (!engine->video_frame.size.cx && !engine->video_frame.size.cy)
2183 hr = E_FAIL;
2184 else
2186 if (cx) *cx = engine->video_frame.size.cx;
2187 if (cy) *cy = engine->video_frame.size.cy;
2190 LeaveCriticalSection(&engine->cs);
2192 return hr;
2195 static HRESULT WINAPI media_engine_GetVideoAspectRatio(IMFMediaEngineEx *iface, DWORD *cx, DWORD *cy)
2197 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2198 HRESULT hr = S_OK;
2200 TRACE("%p, %p, %p.\n", iface, cx, cy);
2202 if (!cx && !cy)
2203 return E_INVALIDARG;
2205 EnterCriticalSection(&engine->cs);
2207 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2208 hr = MF_E_SHUTDOWN;
2209 else if (!engine->video_frame.size.cx && !engine->video_frame.size.cy)
2210 hr = E_FAIL;
2211 else
2213 if (cx) *cx = engine->video_frame.ratio.cx;
2214 if (cy) *cy = engine->video_frame.ratio.cy;
2217 LeaveCriticalSection(&engine->cs);
2219 return hr;
2222 static HRESULT WINAPI media_engine_Shutdown(IMFMediaEngineEx *iface)
2224 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2225 HRESULT hr = S_OK;
2227 TRACE("%p.\n", iface);
2229 EnterCriticalSection(&engine->cs);
2230 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2231 hr = MF_E_SHUTDOWN;
2232 else
2234 media_engine_set_flag(engine, FLAGS_ENGINE_SHUT_DOWN, TRUE);
2235 media_engine_clear_presentation(engine);
2236 IMFMediaSession_Shutdown(engine->session);
2238 LeaveCriticalSection(&engine->cs);
2240 return hr;
2243 static void set_rect(struct rect *rect, float left, float top, float right, float bottom)
2245 rect->left = left;
2246 rect->top = top;
2247 rect->right = right;
2248 rect->bottom = bottom;
2251 static void media_engine_adjust_destination_for_ratio(const struct media_engine *engine,
2252 struct rect *src_n, struct rect *dst)
2254 float dst_width = dst->right - dst->left, dst_height = dst->bottom - dst->top;
2255 D3D11_TEXTURE2D_DESC source_desc;
2256 float src_width, src_height;
2257 struct rect src;
2259 ID3D11Texture2D_GetDesc(engine->video_frame.d3d11.source, &source_desc);
2260 set_rect(&src, src_n->left * source_desc.Width, src_n->top * source_desc.Height,
2261 src_n->right * source_desc.Width, src_n->bottom * source_desc.Height);
2263 src_width = src.right - src.left;
2264 src_height = src.bottom - src.top;
2266 if (src_width * dst_height > dst_width * src_height)
2268 /* src is "wider" than dst. */
2269 float dst_center = (dst->top + dst->bottom) / 2.0f;
2270 float scaled_height = src_height * dst_width / src_width;
2272 dst->top = dst_center - scaled_height / 2.0f;
2273 dst->bottom = dst->top + scaled_height;
2275 else if (src_width * dst_height < dst_width * src_height)
2277 /* src is "taller" than dst. */
2278 float dst_center = (dst->left + dst->right) / 2.0f;
2279 float scaled_width = src_width * dst_height / src_height;
2281 dst->left = dst_center - scaled_width / 2.0f;
2282 dst->right = dst->left + scaled_width;
2286 static void media_engine_update_d3d11_frame_surface(ID3D11DeviceContext *context, struct media_engine *engine)
2288 D3D11_TEXTURE2D_DESC surface_desc;
2290 if (!(engine->flags & FLAGS_ENGINE_NEW_FRAME))
2291 return;
2293 ID3D11Texture2D_GetDesc(engine->video_frame.d3d11.source, &surface_desc);
2295 switch (surface_desc.Format)
2297 case DXGI_FORMAT_B8G8R8A8_UNORM:
2298 case DXGI_FORMAT_B8G8R8X8_UNORM:
2299 surface_desc.Width *= 4;
2300 break;
2301 default:
2302 FIXME("Unsupported format %#x.\n", surface_desc.Format);
2303 surface_desc.Width = 0;
2306 if (engine->video_frame.buffer_size == surface_desc.Width * surface_desc.Height)
2308 ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)engine->video_frame.d3d11.source,
2309 0, NULL, engine->video_frame.buffer, surface_desc.Width, 0);
2312 media_engine_set_flag(engine, FLAGS_ENGINE_NEW_FRAME, FALSE);
2315 static HRESULT media_engine_transfer_to_d3d11_texture(struct media_engine *engine, ID3D11Texture2D *texture,
2316 const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color)
2318 static const float black[] = {0.0f, 0.0f, 0.0f, 0.0f};
2319 ID3D11Device *device, *dst_device;
2320 ID3D11DeviceContext *context;
2321 ID3D11RenderTargetView *rtv;
2322 unsigned int stride, offset;
2323 D3D11_TEXTURE2D_DESC desc;
2324 BOOL device_mismatch;
2325 struct vec3 quad[4];
2326 D3D11_VIEWPORT vp;
2327 struct rect src, dst;
2328 struct color backcolor;
2329 HRESULT hr;
2330 RECT rect;
2332 if (FAILED(hr = media_engine_lock_d3d_device(engine, &device)))
2333 return hr;
2335 if (FAILED(hr = media_engine_create_d3d11_video_frame_resources(engine, device)))
2337 WARN("Failed to create d3d resources, hr %#lx.\n", hr);
2338 goto done;
2341 ID3D11Texture2D_GetDevice(texture, &dst_device);
2342 device_mismatch = device != dst_device;
2343 ID3D11Device_Release(dst_device);
2345 if (device_mismatch)
2347 WARN("Destination target from different device.\n");
2348 hr = E_UNEXPECTED;
2349 goto done;
2352 ID3D11Texture2D_GetDesc(texture, &desc);
2354 if (FAILED(hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)texture, NULL, &rtv)))
2356 WARN("Failed to create an rtv, hr %#lx.\n", hr);
2357 goto done;
2360 ID3D11Device_GetImmediateContext(device, &context);
2362 /* Whole destination is cleared, regardless of specified rectangle. */
2363 ID3D11DeviceContext_ClearRenderTargetView(context, rtv, black);
2365 if (dst_rect)
2367 rect.left = max(0, dst_rect->left);
2368 rect.top = max(0, dst_rect->top);
2369 rect.right = min(desc.Width, dst_rect->right);
2370 rect.bottom = min(desc.Height, dst_rect->bottom);
2372 quad[0].x = 2.0f * rect.left / desc.Width - 1.0f;
2373 quad[0].y = -2.0f * rect.bottom / desc.Height + 1.0f;
2374 quad[0].z = 0.0f;
2376 quad[1].x = quad[0].x;
2377 quad[1].y = -2.0f * rect.top / desc.Height + 1.0f;
2378 quad[1].z = 0.0f;
2380 quad[2].x = 2.0f * rect.right / desc.Width - 1.0f;
2381 quad[2].y = quad[0].y;
2382 quad[2].z = 0.0f;
2384 quad[3].x = quad[2].x;
2385 quad[3].y = quad[1].y;
2386 quad[3].z = 0.0f;
2388 set_rect(&dst, dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom);
2390 else
2392 memcpy(quad, fullquad, sizeof(quad));
2393 set_rect(&dst, 0.0f, 0.0f, desc.Width, desc.Height);
2396 if (src_rect)
2397 memcpy(&src, src_rect, sizeof(src));
2398 else
2399 set_rect(&src, 0.0f, 0.0f, 1.0f, 1.0f);
2401 media_engine_adjust_destination_for_ratio(engine, &src, &dst);
2403 if (memcmp(quad, engine->video_frame.d3d11.quad, sizeof(quad)))
2405 memcpy(engine->video_frame.d3d11.quad, quad, sizeof(quad));
2406 ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)engine->video_frame.d3d11.vb, 0, NULL, quad, 0, 0);
2409 if (color)
2411 backcolor.r = color->rgbRed / 255.0f;
2412 backcolor.g = color->rgbGreen / 255.0f;
2413 backcolor.b = color->rgbBlue / 255.0f;
2414 backcolor.a = color->rgbAlpha / 255.0f;
2416 else
2417 memcpy(&backcolor, black, sizeof(backcolor));
2419 if (memcmp(&dst, &engine->video_frame.d3d11.cb.dst, sizeof(dst)) ||
2420 memcmp(&src, &engine->video_frame.d3d11.cb.src, sizeof(src)) ||
2421 memcmp(&backcolor, &engine->video_frame.d3d11.cb.backcolor, sizeof(backcolor)))
2423 memcpy(&engine->video_frame.d3d11.cb.dst, &dst, sizeof(dst));
2424 memcpy(&engine->video_frame.d3d11.cb.src, &src, sizeof(src));
2425 memcpy(&engine->video_frame.d3d11.cb.backcolor, &backcolor, sizeof(backcolor));
2427 ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)engine->video_frame.d3d11.ps_cb, 0, NULL,
2428 &engine->video_frame.d3d11.cb, 0, 0);
2431 /* Update with new frame contents */
2432 media_engine_update_d3d11_frame_surface(context, engine);
2434 vp.TopLeftX = 0.0f;
2435 vp.TopLeftY = 0.0f;
2436 vp.Width = desc.Width;
2437 vp.Height = desc.Height;
2438 vp.MinDepth = 0.0f;
2439 vp.MaxDepth = 1.0f;
2440 ID3D11DeviceContext_RSSetViewports(context, 1, &vp);
2442 ID3D11DeviceContext_IASetInputLayout(context, engine->video_frame.d3d11.input_layout);
2443 ID3D11DeviceContext_IASetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
2444 stride = sizeof(*quad);
2445 offset = 0;
2446 ID3D11DeviceContext_IASetVertexBuffers(context, 0, 1, &engine->video_frame.d3d11.vb, &stride, &offset);
2447 ID3D11DeviceContext_VSSetShader(context, engine->video_frame.d3d11.vs, NULL, 0);
2448 ID3D11DeviceContext_PSSetShader(context, engine->video_frame.d3d11.ps, NULL, 0);
2449 ID3D11DeviceContext_PSSetShaderResources(context, 0, 1, &engine->video_frame.d3d11.srv);
2450 ID3D11DeviceContext_PSSetConstantBuffers(context, 0, 1, &engine->video_frame.d3d11.ps_cb);
2451 ID3D11DeviceContext_PSSetSamplers(context, 0, 1, &engine->video_frame.d3d11.sampler);
2452 ID3D11DeviceContext_OMSetRenderTargets(context, 1, &rtv, NULL);
2454 ID3D11DeviceContext_Draw(context, 4, 0);
2456 ID3D11RenderTargetView_Release(rtv);
2457 ID3D11DeviceContext_Release(context);
2459 done:
2460 media_engine_unlock_d3d_device(engine, device);
2462 return hr;
2465 static HRESULT WINAPI media_engine_TransferVideoFrame(IMFMediaEngineEx *iface, IUnknown *surface,
2466 const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color)
2468 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2469 ID3D11Texture2D *texture;
2470 HRESULT hr = E_NOINTERFACE;
2472 TRACE("%p, %p, %s, %s, %p.\n", iface, surface, src_rect ? wine_dbg_sprintf("(%f,%f)-(%f,%f)",
2473 src_rect->left, src_rect->top, src_rect->right, src_rect->bottom) : "(null)",
2474 wine_dbgstr_rect(dst_rect), color);
2476 EnterCriticalSection(&engine->cs);
2478 if (SUCCEEDED(IUnknown_QueryInterface(surface, &IID_ID3D11Texture2D, (void **)&texture)))
2480 hr = media_engine_transfer_to_d3d11_texture(engine, texture, src_rect, dst_rect, color);
2481 ID3D11Texture2D_Release(texture);
2483 else
2485 FIXME("Unsupported destination type.\n");
2488 LeaveCriticalSection(&engine->cs);
2490 return hr;
2493 static HRESULT WINAPI media_engine_OnVideoStreamTick(IMFMediaEngineEx *iface, LONGLONG *pts)
2495 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2496 HRESULT hr;
2498 TRACE("%p, %p.\n", iface, pts);
2500 EnterCriticalSection(&engine->cs);
2502 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2503 hr = MF_E_SHUTDOWN;
2504 else if (!pts)
2505 hr = E_POINTER;
2506 else
2508 *pts = engine->video_frame.pts;
2509 hr = *pts == MINLONGLONG ? S_FALSE : S_OK;
2512 LeaveCriticalSection(&engine->cs);
2514 return hr;
2517 static HRESULT WINAPI media_engine_SetSourceFromByteStream(IMFMediaEngineEx *iface, IMFByteStream *bytestream, BSTR url)
2519 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2520 HRESULT hr;
2522 TRACE("%p, %p, %s.\n", iface, bytestream, debugstr_w(url));
2524 EnterCriticalSection(&engine->cs);
2526 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2527 hr = MF_E_SHUTDOWN;
2528 else if (!bytestream || !url)
2529 hr = E_POINTER;
2530 else
2531 hr = media_engine_set_source(engine, bytestream, url);
2533 LeaveCriticalSection(&engine->cs);
2535 return hr;
2538 static HRESULT WINAPI media_engine_GetStatistics(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_STATISTIC stat_id, PROPVARIANT *stat)
2540 FIXME("%p, %x, %p stub.\n", iface, stat_id, stat);
2542 return E_NOTIMPL;
2545 static HRESULT WINAPI media_engine_UpdateVideoStream(IMFMediaEngineEx *iface, const MFVideoNormalizedRect *src,
2546 const RECT *dst, const MFARGB *border_color)
2548 FIXME("%p, %p, %p, %p stub.\n", iface, src, dst, border_color);
2550 return E_NOTIMPL;
2553 static double WINAPI media_engine_GetBalance(IMFMediaEngineEx *iface)
2555 FIXME("%p stub.\n", iface);
2557 return 0.0;
2560 static HRESULT WINAPI media_engine_SetBalance(IMFMediaEngineEx *iface, double balance)
2562 FIXME("%p, %f stub.\n", iface, balance);
2564 return E_NOTIMPL;
2567 static BOOL WINAPI media_engine_IsPlaybackRateSupported(IMFMediaEngineEx *iface, double rate)
2569 FIXME("%p, %f stub.\n", iface, rate);
2571 return FALSE;
2574 static HRESULT WINAPI media_engine_FrameStep(IMFMediaEngineEx *iface, BOOL forward)
2576 FIXME("%p, %d stub.\n", iface, forward);
2578 return E_NOTIMPL;
2581 static HRESULT WINAPI media_engine_GetResourceCharacteristics(IMFMediaEngineEx *iface, DWORD *flags)
2583 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2584 HRESULT hr = E_FAIL;
2586 TRACE("%p, %p.\n", iface, flags);
2588 EnterCriticalSection(&engine->cs);
2589 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2590 hr = MF_E_SHUTDOWN;
2591 else if (engine->presentation.source)
2592 hr = IMFMediaSource_GetCharacteristics(engine->presentation.source, flags);
2593 LeaveCriticalSection(&engine->cs);
2595 return hr;
2598 static HRESULT WINAPI media_engine_GetPresentationAttribute(IMFMediaEngineEx *iface, REFGUID attribute,
2599 PROPVARIANT *value)
2601 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2602 HRESULT hr = E_FAIL;
2604 TRACE("%p, %s, %p.\n", iface, debugstr_guid(attribute), value);
2606 EnterCriticalSection(&engine->cs);
2607 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2608 hr = MF_E_SHUTDOWN;
2609 else if (engine->presentation.pd)
2610 hr = IMFPresentationDescriptor_GetItem(engine->presentation.pd, attribute, value);
2611 LeaveCriticalSection(&engine->cs);
2613 return hr;
2616 static HRESULT WINAPI media_engine_GetNumberOfStreams(IMFMediaEngineEx *iface, DWORD *stream_count)
2618 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2619 HRESULT hr = E_FAIL;
2621 TRACE("%p, %p.\n", iface, stream_count);
2623 EnterCriticalSection(&engine->cs);
2624 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2625 hr = MF_E_SHUTDOWN;
2626 else if (engine->presentation.pd)
2627 hr = IMFPresentationDescriptor_GetStreamDescriptorCount(engine->presentation.pd, stream_count);
2628 LeaveCriticalSection(&engine->cs);
2630 return hr;
2633 static HRESULT WINAPI media_engine_GetStreamAttribute(IMFMediaEngineEx *iface, DWORD stream_index, REFGUID attribute,
2634 PROPVARIANT *value)
2636 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2637 IMFStreamDescriptor *sd;
2638 HRESULT hr = E_FAIL;
2639 BOOL selected;
2641 TRACE("%p, %ld, %s, %p.\n", iface, stream_index, debugstr_guid(attribute), value);
2643 EnterCriticalSection(&engine->cs);
2644 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2645 hr = MF_E_SHUTDOWN;
2646 else if (engine->presentation.pd)
2648 if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(engine->presentation.pd,
2649 stream_index, &selected, &sd)))
2651 hr = IMFStreamDescriptor_GetItem(sd, attribute, value);
2652 IMFStreamDescriptor_Release(sd);
2655 LeaveCriticalSection(&engine->cs);
2657 return hr;
2660 static HRESULT WINAPI media_engine_GetStreamSelection(IMFMediaEngineEx *iface, DWORD stream_index, BOOL *enabled)
2662 FIXME("%p, %ld, %p stub.\n", iface, stream_index, enabled);
2664 return E_NOTIMPL;
2667 static HRESULT WINAPI media_engine_SetStreamSelection(IMFMediaEngineEx *iface, DWORD stream_index, BOOL enabled)
2669 FIXME("%p, %ld, %d stub.\n", iface, stream_index, enabled);
2671 return E_NOTIMPL;
2674 static HRESULT WINAPI media_engine_ApplyStreamSelections(IMFMediaEngineEx *iface)
2676 FIXME("%p stub.\n", iface);
2678 return E_NOTIMPL;
2681 static HRESULT WINAPI media_engine_IsProtected(IMFMediaEngineEx *iface, BOOL *protected)
2683 FIXME("%p, %p stub.\n", iface, protected);
2685 return E_NOTIMPL;
2688 static HRESULT media_engine_insert_effect(struct media_engine *engine, struct effects *effects, IUnknown *object, BOOL is_optional)
2690 HRESULT hr = S_OK;
2692 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2693 hr = MF_E_SHUTDOWN;
2694 else if (!mf_array_reserve((void **)&effects->effects, &effects->capacity, effects->count + 1, sizeof(*effects->effects)))
2696 hr = E_OUTOFMEMORY;
2698 else
2700 effects->effects[effects->count].object = object;
2701 if (object)
2703 IUnknown_AddRef(effects->effects[effects->count].object);
2705 effects->effects[effects->count].optional = is_optional;
2707 effects->count++;
2710 return hr;
2713 static HRESULT WINAPI media_engine_InsertVideoEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional)
2715 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2716 HRESULT hr = S_OK;
2718 TRACE("%p, %p, %d.\n", iface, effect, is_optional);
2720 EnterCriticalSection(&engine->cs);
2721 hr = media_engine_insert_effect(engine, &engine->video_effects, effect, is_optional);
2722 LeaveCriticalSection(&engine->cs);
2724 return hr;
2727 static HRESULT WINAPI media_engine_InsertAudioEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional)
2729 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2730 HRESULT hr = S_OK;
2732 TRACE("%p, %p, %d.\n", iface, effect, is_optional);
2734 EnterCriticalSection(&engine->cs);
2735 hr = media_engine_insert_effect(engine, &engine->audio_effects, effect, is_optional);
2736 LeaveCriticalSection(&engine->cs);
2738 return hr;
2741 static HRESULT WINAPI media_engine_RemoveAllEffects(IMFMediaEngineEx *iface)
2743 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2744 HRESULT hr = S_OK;
2746 TRACE("%p.\n", iface);
2748 EnterCriticalSection(&engine->cs);
2749 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2750 hr = MF_E_SHUTDOWN;
2751 else
2753 media_engine_clear_effects(&engine->audio_effects);
2754 media_engine_clear_effects(&engine->video_effects);
2756 LeaveCriticalSection(&engine->cs);
2758 return hr;
2761 static HRESULT WINAPI media_engine_SetTimelineMarkerTimer(IMFMediaEngineEx *iface, double timeout)
2763 FIXME("%p, %f stub.\n", iface, timeout);
2765 return E_NOTIMPL;
2768 static HRESULT WINAPI media_engine_GetTimelineMarkerTimer(IMFMediaEngineEx *iface, double *timeout)
2770 FIXME("%p, %p stub.\n", iface, timeout);
2772 return E_NOTIMPL;
2775 static HRESULT WINAPI media_engine_CancelTimelineMarkerTimer(IMFMediaEngineEx *iface)
2777 FIXME("%p stub.\n", iface);
2779 return E_NOTIMPL;
2782 static BOOL WINAPI media_engine_IsStereo3D(IMFMediaEngineEx *iface)
2784 FIXME("%p stub.\n", iface);
2786 return FALSE;
2789 static HRESULT WINAPI media_engine_GetStereo3DFramePackingMode(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_S3D_PACKING_MODE *mode)
2791 FIXME("%p, %p stub.\n", iface, mode);
2793 return E_NOTIMPL;
2796 static HRESULT WINAPI media_engine_SetStereo3DFramePackingMode(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_S3D_PACKING_MODE mode)
2798 FIXME("%p, %#x stub.\n", iface, mode);
2800 return E_NOTIMPL;
2803 static HRESULT WINAPI media_engine_GetStereo3DRenderMode(IMFMediaEngineEx *iface, MF3DVideoOutputType *output_type)
2805 FIXME("%p, %p stub.\n", iface, output_type);
2807 return E_NOTIMPL;
2810 static HRESULT WINAPI media_engine_SetStereo3DRenderMode(IMFMediaEngineEx *iface, MF3DVideoOutputType output_type)
2812 FIXME("%p, %#x stub.\n", iface, output_type);
2814 return E_NOTIMPL;
2817 static HRESULT WINAPI media_engine_EnableWindowlessSwapchainMode(IMFMediaEngineEx *iface, BOOL enable)
2819 FIXME("%p, %d stub.\n", iface, enable);
2821 return E_NOTIMPL;
2824 static HRESULT WINAPI media_engine_GetVideoSwapchainHandle(IMFMediaEngineEx *iface, HANDLE *swapchain)
2826 FIXME("%p, %p stub.\n", iface, swapchain);
2828 return E_NOTIMPL;
2831 static HRESULT WINAPI media_engine_EnableHorizontalMirrorMode(IMFMediaEngineEx *iface, BOOL enable)
2833 FIXME("%p, %d stub.\n", iface, enable);
2835 return E_NOTIMPL;
2838 static HRESULT WINAPI media_engine_GetAudioStreamCategory(IMFMediaEngineEx *iface, UINT32 *category)
2840 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2841 HRESULT hr;
2843 TRACE("%p, %p.\n", iface, category);
2845 EnterCriticalSection(&engine->cs);
2847 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2848 hr = MF_E_SHUTDOWN;
2849 else
2850 hr = IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, category);
2852 LeaveCriticalSection(&engine->cs);
2854 return hr;
2857 static HRESULT WINAPI media_engine_SetAudioStreamCategory(IMFMediaEngineEx *iface, UINT32 category)
2859 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2860 HRESULT hr;
2862 TRACE("%p, %u.\n", iface, category);
2864 EnterCriticalSection(&engine->cs);
2866 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2867 hr = MF_E_SHUTDOWN;
2868 else
2869 hr = IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, category);
2871 LeaveCriticalSection(&engine->cs);
2873 return hr;
2876 static HRESULT WINAPI media_engine_GetAudioEndpointRole(IMFMediaEngineEx *iface, UINT32 *role)
2878 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2879 HRESULT hr;
2881 TRACE("%p, %p.\n", iface, role);
2883 EnterCriticalSection(&engine->cs);
2885 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2886 hr = MF_E_SHUTDOWN;
2887 else
2888 hr = IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, role);
2890 LeaveCriticalSection(&engine->cs);
2892 return hr;
2895 static HRESULT WINAPI media_engine_SetAudioEndpointRole(IMFMediaEngineEx *iface, UINT32 role)
2897 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2898 HRESULT hr;
2900 TRACE("%p, %u.\n", iface, role);
2902 EnterCriticalSection(&engine->cs);
2904 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2905 hr = MF_E_SHUTDOWN;
2906 else
2907 hr = IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, role);
2909 LeaveCriticalSection(&engine->cs);
2911 return hr;
2914 static HRESULT WINAPI media_engine_GetRealTimeMode(IMFMediaEngineEx *iface, BOOL *enabled)
2916 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2917 HRESULT hr = S_OK;
2919 TRACE("%p, %p.\n", iface, enabled);
2921 EnterCriticalSection(&engine->cs);
2922 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2923 hr = MF_E_SHUTDOWN;
2924 else
2925 *enabled = !!(engine->flags & MF_MEDIA_ENGINE_REAL_TIME_MODE);
2926 LeaveCriticalSection(&engine->cs);
2928 return hr;
2931 static HRESULT WINAPI media_engine_SetRealTimeMode(IMFMediaEngineEx *iface, BOOL enable)
2933 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2934 HRESULT hr = S_OK;
2936 TRACE("%p, %d.\n", iface, enable);
2938 EnterCriticalSection(&engine->cs);
2939 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2940 hr = MF_E_SHUTDOWN;
2941 else
2942 media_engine_set_flag(engine, MF_MEDIA_ENGINE_REAL_TIME_MODE, enable);
2943 LeaveCriticalSection(&engine->cs);
2945 return hr;
2948 static HRESULT WINAPI media_engine_SetCurrentTimeEx(IMFMediaEngineEx *iface, double seektime, MF_MEDIA_ENGINE_SEEK_MODE mode)
2950 FIXME("%p, %f, %#x stub.\n", iface, seektime, mode);
2952 return E_NOTIMPL;
2955 static HRESULT WINAPI media_engine_EnableTimeUpdateTimer(IMFMediaEngineEx *iface, BOOL enable)
2957 FIXME("%p, %d stub.\n", iface, enable);
2959 return E_NOTIMPL;
2962 static const IMFMediaEngineExVtbl media_engine_vtbl =
2964 media_engine_QueryInterface,
2965 media_engine_AddRef,
2966 media_engine_Release,
2967 media_engine_GetError,
2968 media_engine_SetErrorCode,
2969 media_engine_SetSourceElements,
2970 media_engine_SetSource,
2971 media_engine_GetCurrentSource,
2972 media_engine_GetNetworkState,
2973 media_engine_GetPreload,
2974 media_engine_SetPreload,
2975 media_engine_GetBuffered,
2976 media_engine_Load,
2977 media_engine_CanPlayType,
2978 media_engine_GetReadyState,
2979 media_engine_IsSeeking,
2980 media_engine_GetCurrentTime,
2981 media_engine_SetCurrentTime,
2982 media_engine_GetStartTime,
2983 media_engine_GetDuration,
2984 media_engine_IsPaused,
2985 media_engine_GetDefaultPlaybackRate,
2986 media_engine_SetDefaultPlaybackRate,
2987 media_engine_GetPlaybackRate,
2988 media_engine_SetPlaybackRate,
2989 media_engine_GetPlayed,
2990 media_engine_GetSeekable,
2991 media_engine_IsEnded,
2992 media_engine_GetAutoPlay,
2993 media_engine_SetAutoPlay,
2994 media_engine_GetLoop,
2995 media_engine_SetLoop,
2996 media_engine_Play,
2997 media_engine_Pause,
2998 media_engine_GetMuted,
2999 media_engine_SetMuted,
3000 media_engine_GetVolume,
3001 media_engine_SetVolume,
3002 media_engine_HasVideo,
3003 media_engine_HasAudio,
3004 media_engine_GetNativeVideoSize,
3005 media_engine_GetVideoAspectRatio,
3006 media_engine_Shutdown,
3007 media_engine_TransferVideoFrame,
3008 media_engine_OnVideoStreamTick,
3009 media_engine_SetSourceFromByteStream,
3010 media_engine_GetStatistics,
3011 media_engine_UpdateVideoStream,
3012 media_engine_GetBalance,
3013 media_engine_SetBalance,
3014 media_engine_IsPlaybackRateSupported,
3015 media_engine_FrameStep,
3016 media_engine_GetResourceCharacteristics,
3017 media_engine_GetPresentationAttribute,
3018 media_engine_GetNumberOfStreams,
3019 media_engine_GetStreamAttribute,
3020 media_engine_GetStreamSelection,
3021 media_engine_SetStreamSelection,
3022 media_engine_ApplyStreamSelections,
3023 media_engine_IsProtected,
3024 media_engine_InsertVideoEffect,
3025 media_engine_InsertAudioEffect,
3026 media_engine_RemoveAllEffects,
3027 media_engine_SetTimelineMarkerTimer,
3028 media_engine_GetTimelineMarkerTimer,
3029 media_engine_CancelTimelineMarkerTimer,
3030 media_engine_IsStereo3D,
3031 media_engine_GetStereo3DFramePackingMode,
3032 media_engine_SetStereo3DFramePackingMode,
3033 media_engine_GetStereo3DRenderMode,
3034 media_engine_SetStereo3DRenderMode,
3035 media_engine_EnableWindowlessSwapchainMode,
3036 media_engine_GetVideoSwapchainHandle,
3037 media_engine_EnableHorizontalMirrorMode,
3038 media_engine_GetAudioStreamCategory,
3039 media_engine_SetAudioStreamCategory,
3040 media_engine_GetAudioEndpointRole,
3041 media_engine_SetAudioEndpointRole,
3042 media_engine_GetRealTimeMode,
3043 media_engine_SetRealTimeMode,
3044 media_engine_SetCurrentTimeEx,
3045 media_engine_EnableTimeUpdateTimer,
3048 static HRESULT WINAPI media_engine_gs_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
3050 struct media_engine *engine = impl_from_IMFGetService(iface);
3051 return IMFMediaEngineEx_QueryInterface(&engine->IMFMediaEngineEx_iface, riid, obj);
3054 static ULONG WINAPI media_engine_gs_AddRef(IMFGetService *iface)
3056 struct media_engine *engine = impl_from_IMFGetService(iface);
3057 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
3060 static ULONG WINAPI media_engine_gs_Release(IMFGetService *iface)
3062 struct media_engine *engine = impl_from_IMFGetService(iface);
3063 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
3066 static HRESULT WINAPI media_engine_gs_GetService(IMFGetService *iface, REFGUID service,
3067 REFIID riid, void **object)
3069 FIXME("%p, %s, %s, %p stub.\n", iface, debugstr_guid(service), debugstr_guid(riid), object);
3071 return E_NOTIMPL;
3074 static const IMFGetServiceVtbl media_engine_get_service_vtbl =
3076 media_engine_gs_QueryInterface,
3077 media_engine_gs_AddRef,
3078 media_engine_gs_Release,
3079 media_engine_gs_GetService,
3082 static HRESULT WINAPI media_engine_grabber_callback_QueryInterface(IMFSampleGrabberSinkCallback *iface,
3083 REFIID riid, void **obj)
3085 if (IsEqualIID(riid, &IID_IMFSampleGrabberSinkCallback) ||
3086 IsEqualIID(riid, &IID_IUnknown))
3088 *obj = iface;
3089 IMFSampleGrabberSinkCallback_AddRef(iface);
3090 return S_OK;
3093 *obj = NULL;
3094 return E_NOINTERFACE;
3097 static ULONG WINAPI media_engine_grabber_callback_AddRef(IMFSampleGrabberSinkCallback *iface)
3099 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
3100 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
3103 static ULONG WINAPI media_engine_grabber_callback_Release(IMFSampleGrabberSinkCallback *iface)
3105 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
3106 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
3109 static HRESULT WINAPI media_engine_grabber_callback_OnClockStart(IMFSampleGrabberSinkCallback *iface,
3110 MFTIME systime, LONGLONG start_offset)
3112 return S_OK;
3115 static HRESULT WINAPI media_engine_grabber_callback_OnClockStop(IMFSampleGrabberSinkCallback *iface,
3116 MFTIME systime)
3118 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
3120 EnterCriticalSection(&engine->cs);
3121 media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, FALSE);
3122 engine->video_frame.pts = MINLONGLONG;
3123 LeaveCriticalSection(&engine->cs);
3125 return S_OK;
3128 static HRESULT WINAPI media_engine_grabber_callback_OnClockPause(IMFSampleGrabberSinkCallback *iface,
3129 MFTIME systime)
3131 return S_OK;
3134 static HRESULT WINAPI media_engine_grabber_callback_OnClockRestart(IMFSampleGrabberSinkCallback *iface,
3135 MFTIME systime)
3137 return S_OK;
3140 static HRESULT WINAPI media_engine_grabber_callback_OnClockSetRate(IMFSampleGrabberSinkCallback *iface,
3141 MFTIME systime, float rate)
3143 return S_OK;
3146 static HRESULT WINAPI media_engine_grabber_callback_OnSetPresentationClock(IMFSampleGrabberSinkCallback *iface,
3147 IMFPresentationClock *clock)
3149 return S_OK;
3152 static HRESULT WINAPI media_engine_grabber_callback_OnProcessSample(IMFSampleGrabberSinkCallback *iface,
3153 REFGUID major_type, DWORD sample_flags, LONGLONG sample_time, LONGLONG sample_duration,
3154 const BYTE *buffer, DWORD buffer_size)
3156 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
3158 EnterCriticalSection(&engine->cs);
3160 if (!(engine->flags & FLAGS_ENGINE_FIRST_FRAME))
3162 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY, 0, 0);
3163 media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, TRUE);
3165 engine->video_frame.pts = sample_time;
3166 if (engine->video_frame.buffer_size < buffer_size)
3168 free(engine->video_frame.buffer);
3169 if ((engine->video_frame.buffer = malloc(buffer_size)))
3170 engine->video_frame.buffer_size = buffer_size;
3172 if (engine->video_frame.buffer)
3174 memcpy(engine->video_frame.buffer, buffer, buffer_size);
3175 engine->flags |= FLAGS_ENGINE_NEW_FRAME;
3178 LeaveCriticalSection(&engine->cs);
3180 return S_OK;
3183 static HRESULT WINAPI media_engine_grabber_callback_OnShutdown(IMFSampleGrabberSinkCallback *iface)
3185 return S_OK;
3188 static const IMFSampleGrabberSinkCallbackVtbl media_engine_grabber_callback_vtbl =
3190 media_engine_grabber_callback_QueryInterface,
3191 media_engine_grabber_callback_AddRef,
3192 media_engine_grabber_callback_Release,
3193 media_engine_grabber_callback_OnClockStart,
3194 media_engine_grabber_callback_OnClockStop,
3195 media_engine_grabber_callback_OnClockPause,
3196 media_engine_grabber_callback_OnClockRestart,
3197 media_engine_grabber_callback_OnClockSetRate,
3198 media_engine_grabber_callback_OnSetPresentationClock,
3199 media_engine_grabber_callback_OnProcessSample,
3200 media_engine_grabber_callback_OnShutdown,
3203 static HRESULT WINAPI media_engine_factory_QueryInterface(IMFMediaEngineClassFactory *iface, REFIID riid, void **obj)
3205 if (IsEqualIID(riid, &IID_IMFMediaEngineClassFactory) ||
3206 IsEqualIID(riid, &IID_IUnknown))
3208 *obj = iface;
3209 IMFMediaEngineClassFactory_AddRef(iface);
3210 return S_OK;
3213 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
3214 *obj = NULL;
3215 return E_NOINTERFACE;
3218 static ULONG WINAPI media_engine_factory_AddRef(IMFMediaEngineClassFactory *iface)
3220 return 2;
3223 static ULONG WINAPI media_engine_factory_Release(IMFMediaEngineClassFactory *iface)
3225 return 1;
3228 static HRESULT init_media_engine(DWORD flags, IMFAttributes *attributes, struct media_engine *engine)
3230 DXGI_FORMAT output_format;
3231 UINT64 playback_hwnd;
3232 IMFClock *clock;
3233 HRESULT hr;
3235 engine->IMFMediaEngineEx_iface.lpVtbl = &media_engine_vtbl;
3236 engine->IMFGetService_iface.lpVtbl = &media_engine_get_service_vtbl;
3237 engine->session_events.lpVtbl = &media_engine_session_events_vtbl;
3238 engine->load_handler.lpVtbl = &media_engine_load_handler_vtbl;
3239 engine->grabber_callback.lpVtbl = &media_engine_grabber_callback_vtbl;
3240 engine->refcount = 1;
3241 engine->flags = (flags & MF_MEDIA_ENGINE_CREATEFLAGS_MASK) | FLAGS_ENGINE_PAUSED;
3242 engine->default_playback_rate = 1.0;
3243 engine->playback_rate = 1.0;
3244 engine->volume = 1.0;
3245 engine->duration = NAN;
3246 engine->video_frame.pts = MINLONGLONG;
3247 InitializeCriticalSection(&engine->cs);
3249 hr = IMFAttributes_GetUnknown(attributes, &MF_MEDIA_ENGINE_CALLBACK, &IID_IMFMediaEngineNotify,
3250 (void **)&engine->callback);
3251 if (FAILED(hr))
3252 return hr;
3254 IMFAttributes_GetUnknown(attributes, &MF_MEDIA_ENGINE_DXGI_MANAGER, &IID_IMFDXGIDeviceManager,
3255 (void **)&engine->device_manager);
3257 if (FAILED(hr = MFCreateMediaSession(NULL, &engine->session)))
3258 return hr;
3260 if (FAILED(hr = IMFMediaSession_GetClock(engine->session, &clock)))
3261 return hr;
3263 hr = IMFClock_QueryInterface(clock, &IID_IMFPresentationClock, (void **)&engine->clock);
3264 IMFClock_Release(clock);
3265 if (FAILED(hr))
3266 return hr;
3268 if (FAILED(hr = IMFMediaSession_BeginGetEvent(engine->session, &engine->session_events, NULL)))
3269 return hr;
3271 if (FAILED(hr = MFCreateSourceResolver(&engine->resolver)))
3272 return hr;
3274 if (FAILED(hr = MFCreateAttributes(&engine->attributes, 0)))
3275 return hr;
3277 if (FAILED(hr = IMFAttributes_CopyAllItems(attributes, engine->attributes)))
3278 return hr;
3280 /* Set default audio configuration */
3281 if (FAILED(IMFAttributes_GetItem(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, NULL)))
3282 IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, AudioCategory_Other);
3283 if (FAILED(IMFAttributes_GetItem(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, NULL)))
3284 IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, eMultimedia);
3286 IMFAttributes_GetUINT64(attributes, &MF_MEDIA_ENGINE_PLAYBACK_HWND, &playback_hwnd);
3287 hr = IMFAttributes_GetUINT32(attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, &output_format);
3288 if (playback_hwnd) /* FIXME: handle MF_MEDIA_ENGINE_PLAYBACK_VISUAL */
3289 engine->mode = MEDIA_ENGINE_RENDERING_MODE;
3290 else
3292 if (SUCCEEDED(hr))
3293 engine->mode = MEDIA_ENGINE_FRAME_SERVER_MODE;
3294 else
3295 engine->mode = MEDIA_ENGINE_AUDIO_MODE;
3298 return S_OK;
3301 static HRESULT WINAPI media_engine_factory_CreateInstance(IMFMediaEngineClassFactory *iface, DWORD flags,
3302 IMFAttributes *attributes, IMFMediaEngine **engine)
3304 struct media_engine *object;
3305 HRESULT hr;
3307 TRACE("%p, %#lx, %p, %p.\n", iface, flags, attributes, engine);
3309 if (!attributes || !engine)
3310 return E_POINTER;
3312 object = calloc(1, sizeof(*object));
3313 if (!object)
3314 return E_OUTOFMEMORY;
3316 hr = init_media_engine(flags, attributes, object);
3317 if (FAILED(hr))
3319 free_media_engine(object);
3320 return hr;
3323 *engine = (IMFMediaEngine *)&object->IMFMediaEngineEx_iface;
3325 return S_OK;
3328 static HRESULT WINAPI media_engine_factory_CreateTimeRange(IMFMediaEngineClassFactory *iface,
3329 IMFMediaTimeRange **range)
3331 TRACE("%p, %p.\n", iface, range);
3333 return create_time_range(range);
3336 static HRESULT WINAPI media_engine_factory_CreateError(IMFMediaEngineClassFactory *iface, IMFMediaError **error)
3338 TRACE("%p, %p.\n", iface, error);
3340 return create_media_error(error);
3343 static const IMFMediaEngineClassFactoryVtbl media_engine_factory_vtbl =
3345 media_engine_factory_QueryInterface,
3346 media_engine_factory_AddRef,
3347 media_engine_factory_Release,
3348 media_engine_factory_CreateInstance,
3349 media_engine_factory_CreateTimeRange,
3350 media_engine_factory_CreateError,
3353 static IMFMediaEngineClassFactory media_engine_factory = { &media_engine_factory_vtbl };
3355 static HRESULT WINAPI classfactory_QueryInterface(IClassFactory *iface, REFIID riid, void **obj)
3357 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
3359 if (IsEqualGUID(riid, &IID_IClassFactory) ||
3360 IsEqualGUID(riid, &IID_IUnknown))
3362 IClassFactory_AddRef(iface);
3363 *obj = iface;
3364 return S_OK;
3367 WARN("interface %s not implemented.\n", debugstr_guid(riid));
3368 *obj = NULL;
3369 return E_NOINTERFACE;
3372 static ULONG WINAPI classfactory_AddRef(IClassFactory *iface)
3374 return 2;
3377 static ULONG WINAPI classfactory_Release(IClassFactory *iface)
3379 return 1;
3382 static HRESULT WINAPI classfactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **obj)
3384 TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), obj);
3386 *obj = NULL;
3388 if (outer)
3389 return CLASS_E_NOAGGREGATION;
3391 return IMFMediaEngineClassFactory_QueryInterface(&media_engine_factory, riid, obj);
3394 static HRESULT WINAPI classfactory_LockServer(IClassFactory *iface, BOOL dolock)
3396 FIXME("(%d): stub.\n", dolock);
3397 return S_OK;
3400 static const IClassFactoryVtbl class_factory_vtbl =
3402 classfactory_QueryInterface,
3403 classfactory_AddRef,
3404 classfactory_Release,
3405 classfactory_CreateInstance,
3406 classfactory_LockServer,
3409 static IClassFactory classfactory = { &class_factory_vtbl };
3411 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **obj)
3413 TRACE("%s, %s, %p.\n", debugstr_guid(clsid), debugstr_guid(riid), obj);
3415 if (IsEqualGUID(clsid, &CLSID_MFMediaEngineClassFactory))
3416 return IClassFactory_QueryInterface(&classfactory, riid, obj);
3418 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
3419 *obj = NULL;
3420 return CLASS_E_CLASSNOTAVAILABLE;