mfmediaengine: Avoid implicit casts in IMFAttributes_GetUINT32 calls.
[wine.git] / dlls / mfmediaengine / main.c
blob0e16305ddda7d515d7931a8a3f49c62b71416e3b
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 IMFMediaEngineExtension *extension;
162 BSTR current_source;
163 struct
165 IMFMediaSource *source;
166 IMFPresentationDescriptor *pd;
167 } presentation;
168 struct effects video_effects;
169 struct effects audio_effects;
170 struct
172 LONGLONG pts;
173 SIZE size;
174 SIZE ratio;
175 TOPOID node_id;
176 BYTE *buffer;
177 UINT buffer_size;
178 DXGI_FORMAT output_format;
180 struct
182 ID3D11Buffer *vb;
183 ID3D11Buffer *ps_cb;
184 ID3D11Texture2D *source;
185 ID3D11ShaderResourceView *srv;
186 ID3D11SamplerState *sampler;
187 ID3D11InputLayout *input_layout;
188 ID3D11VertexShader *vs;
189 ID3D11PixelShader *ps;
190 struct vec3 quad[4];
191 struct
193 struct rect dst;
194 struct rect src;
195 struct color backcolor;
196 } cb;
197 } d3d11;
198 } video_frame;
199 CRITICAL_SECTION cs;
202 static void media_engine_release_video_frame_resources(struct media_engine *engine)
204 if (engine->video_frame.d3d11.vb)
205 ID3D11Buffer_Release(engine->video_frame.d3d11.vb);
206 if (engine->video_frame.d3d11.ps_cb)
207 ID3D11Buffer_Release(engine->video_frame.d3d11.ps_cb);
208 if (engine->video_frame.d3d11.source)
209 ID3D11Texture2D_Release(engine->video_frame.d3d11.source);
210 if (engine->video_frame.d3d11.srv)
211 ID3D11ShaderResourceView_Release(engine->video_frame.d3d11.srv);
212 if (engine->video_frame.d3d11.sampler)
213 ID3D11SamplerState_Release(engine->video_frame.d3d11.sampler);
214 if (engine->video_frame.d3d11.input_layout)
215 ID3D11InputLayout_Release(engine->video_frame.d3d11.input_layout);
216 if (engine->video_frame.d3d11.vs)
217 ID3D11VertexShader_Release(engine->video_frame.d3d11.vs);
218 if (engine->video_frame.d3d11.ps)
219 ID3D11PixelShader_Release(engine->video_frame.d3d11.ps);
221 memset(&engine->video_frame.d3d11, 0, sizeof(engine->video_frame.d3d11));
222 memcpy(engine->video_frame.d3d11.quad, fullquad, sizeof(fullquad));
225 static HRESULT media_engine_lock_d3d_device(struct media_engine *engine, ID3D11Device **device)
227 HRESULT hr;
229 if (!engine->device_manager)
231 FIXME("Device manager wasn't set.\n");
232 return E_UNEXPECTED;
235 if (!engine->device_handle)
237 if (FAILED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(engine->device_manager, &engine->device_handle)))
239 WARN("Failed to open device handle, hr %#lx.\n", hr);
240 return hr;
244 hr = IMFDXGIDeviceManager_LockDevice(engine->device_manager, engine->device_handle, &IID_ID3D11Device,
245 (void **)device, TRUE);
246 if (hr == MF_E_DXGI_NEW_VIDEO_DEVICE)
248 IMFDXGIDeviceManager_CloseDeviceHandle(engine->device_manager, engine->device_handle);
249 engine->device_handle = NULL;
251 media_engine_release_video_frame_resources(engine);
253 if (FAILED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(engine->device_manager, &engine->device_handle)))
255 WARN("Failed to open a device handle, hr %#lx.\n", hr);
256 return hr;
258 hr = IMFDXGIDeviceManager_LockDevice(engine->device_manager, engine->device_handle, &IID_ID3D11Device,
259 (void **)device, TRUE);
262 return hr;
265 static void media_engine_unlock_d3d_device(struct media_engine *engine, ID3D11Device *device)
267 ID3D11Device_Release(device);
268 IMFDXGIDeviceManager_UnlockDevice(engine->device_manager, engine->device_handle, FALSE);
271 static HRESULT media_engine_create_d3d11_video_frame_resources(struct media_engine *engine, ID3D11Device *device)
273 static const D3D11_INPUT_ELEMENT_DESC layout_desc[] =
275 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
277 static const DWORD vs_code[] =
279 #if 0
280 float4 main(float4 position : POSITION) : SV_POSITION
282 return position;
284 #endif
285 0x43425844, 0xa7a2f22d, 0x83ff2560, 0xe61638bd, 0x87e3ce90, 0x00000001, 0x000000d8, 0x00000003,
286 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
287 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x49534f50, 0x4e4f4954, 0xababab00,
288 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, 0x00000003,
289 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x52444853, 0x0000003c, 0x00010040,
290 0x0000000f, 0x0300005f, 0x001010f2, 0x00000000, 0x04000067, 0x001020f2, 0x00000000, 0x00000001,
291 0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000000, 0x0100003e,
293 static const DWORD ps_code[] =
295 #if 0
296 Texture2D t;
297 SamplerState s;
298 float4 dst;
299 float4 src;
300 float4 backcolor;
302 float4 main(float4 position : SV_POSITION) : SV_TARGET
304 float2 p;
306 if (position.x < dst.x || position.x > dst.z) return backcolor;
307 if (position.y < dst.y || position.y > dst.w) return backcolor;
308 p.x = (position.x - dst.x) / (dst.z - dst.x);
309 p.y = (position.y - dst.y) / (dst.w - dst.y);
310 p.x = src.x + p.x * (src.z - src.x);
311 p.y = src.y + p.y * (src.w - src.y);
312 return t.Sample(s, p);
314 #endif
315 0x43425844, 0xae2162b7, 0x0fd69625, 0x6784c41a, 0x84ae95de, 0x00000001, 0x000002f8, 0x00000003,
316 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
317 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000030f, 0x505f5653, 0x5449534f, 0x004e4f49,
318 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
319 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054, 0x52444853, 0x0000025c, 0x00000040,
320 0x00000097, 0x04000059, 0x00208e46, 0x00000000, 0x00000003, 0x0300005a, 0x00106000, 0x00000000,
321 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x04002064, 0x00101032, 0x00000000, 0x00000001,
322 0x03000065, 0x001020f2, 0x00000000, 0x02000068, 0x00000002, 0x08000031, 0x00100012, 0x00000000,
323 0x0010100a, 0x00000000, 0x0020800a, 0x00000000, 0x00000000, 0x08000031, 0x00100022, 0x00000000,
324 0x0020802a, 0x00000000, 0x00000000, 0x0010100a, 0x00000000, 0x0700003c, 0x00100012, 0x00000000,
325 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x09000000, 0x00100062, 0x00000000, 0x00101106,
326 0x00000000, 0x80208106, 0x00000041, 0x00000000, 0x00000000, 0x0a000000, 0x00100032, 0x00000001,
327 0x80208046, 0x00000041, 0x00000000, 0x00000000, 0x00208ae6, 0x00000000, 0x00000000, 0x0700000e,
328 0x00100062, 0x00000000, 0x00100656, 0x00000000, 0x00100106, 0x00000001, 0x0a000000, 0x00100032,
329 0x00000001, 0x80208046, 0x00000041, 0x00000000, 0x00000001, 0x00208ae6, 0x00000000, 0x00000001,
330 0x0a000032, 0x00100062, 0x00000000, 0x00100656, 0x00000000, 0x00100106, 0x00000001, 0x00208106,
331 0x00000000, 0x00000001, 0x09000045, 0x001000f2, 0x00000001, 0x00100596, 0x00000000, 0x00107e46,
332 0x00000000, 0x00106000, 0x00000000, 0x0304001f, 0x0010000a, 0x00000000, 0x06000036, 0x001020f2,
333 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e, 0x01000015, 0x08000031, 0x00100012,
334 0x00000000, 0x0010101a, 0x00000000, 0x0020801a, 0x00000000, 0x00000000, 0x08000031, 0x00100022,
335 0x00000000, 0x0020803a, 0x00000000, 0x00000000, 0x0010101a, 0x00000000, 0x0700003c, 0x00100012,
336 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a, 0x00000000,
337 0x06000036, 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e, 0x01000015,
338 0x05000036, 0x001020f2, 0x00000000, 0x00100e46, 0x00000001, 0x0100003e,
340 D3D11_SUBRESOURCE_DATA resource_data;
341 D3D11_TEXTURE2D_DESC texture_desc;
342 D3D11_SAMPLER_DESC sampler_desc;
343 D3D11_BUFFER_DESC buffer_desc;
344 HRESULT hr;
346 if (engine->video_frame.d3d11.source)
347 return S_OK;
349 /* Default vertex buffer, updated on first transfer call. */
350 buffer_desc.ByteWidth = sizeof(engine->video_frame.d3d11.quad);
351 buffer_desc.Usage = D3D11_USAGE_DEFAULT;
352 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
353 buffer_desc.CPUAccessFlags = 0;
354 buffer_desc.MiscFlags = 0;
355 buffer_desc.StructureByteStride = 0;
357 resource_data.pSysMem = engine->video_frame.d3d11.quad;
358 resource_data.SysMemPitch = 0;
359 resource_data.SysMemSlicePitch = 0;
361 if (FAILED(hr = ID3D11Device_CreateBuffer(device, &buffer_desc, &resource_data, &engine->video_frame.d3d11.vb)))
363 WARN("Failed to create a vertex buffer, hr %#lx.\n", hr);
364 goto failed;
367 buffer_desc.ByteWidth = sizeof(engine->video_frame.d3d11.cb);
368 buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
370 if (FAILED(hr = ID3D11Device_CreateBuffer(device, &buffer_desc, NULL, &engine->video_frame.d3d11.ps_cb)))
372 WARN("Failed to create a buffer, hr %#lx.\n", hr);
373 goto failed;
376 /* Source texture. */
377 texture_desc.Width = engine->video_frame.size.cx;
378 texture_desc.Height = engine->video_frame.size.cy;
379 texture_desc.MipLevels = 1;
380 texture_desc.ArraySize = 1;
381 texture_desc.Format = engine->video_frame.output_format;
382 texture_desc.SampleDesc.Count = 1;
383 texture_desc.SampleDesc.Quality = 0;
384 texture_desc.Usage = D3D11_USAGE_DEFAULT;
385 texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
386 texture_desc.CPUAccessFlags = 0;
387 texture_desc.MiscFlags = 0;
389 if (FAILED(hr = ID3D11Device_CreateTexture2D(device, &texture_desc, NULL, &engine->video_frame.d3d11.source)))
391 WARN("Failed to create source texture, hr %#lx.\n", hr);
392 goto failed;
395 if (FAILED(hr = ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource *)engine->video_frame.d3d11.source,
396 NULL, &engine->video_frame.d3d11.srv)))
398 WARN("Failed to create SRV, hr %#lx.\n", hr);
399 goto failed;
402 /* Sampler state. */
403 memset(&sampler_desc, 0, sizeof(sampler_desc));
404 sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
405 sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
406 sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
407 sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
409 if (FAILED(hr = ID3D11Device_CreateSamplerState(device, &sampler_desc, &engine->video_frame.d3d11.sampler)))
411 WARN("Failed to create a sampler state, hr %#lx.\n", hr);
412 goto failed;
415 /* Input layout */
416 if (FAILED(hr = ID3D11Device_CreateInputLayout(device, layout_desc, ARRAY_SIZE(layout_desc), vs_code, sizeof(vs_code),
417 &engine->video_frame.d3d11.input_layout)))
419 WARN("Failed to create input layout, hr %#lx.\n", hr);
420 goto failed;
423 /* Shaders */
424 if (FAILED(hr = ID3D11Device_CreateVertexShader(device, vs_code, sizeof(vs_code), NULL, &engine->video_frame.d3d11.vs)))
426 WARN("Failed to create the vertex shader, hr %#lx.\n", hr);
427 goto failed;
430 if (FAILED(hr = ID3D11Device_CreatePixelShader(device, ps_code, sizeof(ps_code), NULL, &engine->video_frame.d3d11.ps)))
432 WARN("Failed to create the pixel shader, hr %#lx.\n", hr);
433 goto failed;
436 failed:
438 return hr;
441 struct range
443 double start;
444 double end;
447 struct time_range
449 IMFMediaTimeRange IMFMediaTimeRange_iface;
450 LONG refcount;
452 struct range *ranges;
453 size_t count;
454 size_t capacity;
457 static struct time_range *impl_from_IMFMediaTimeRange(IMFMediaTimeRange *iface)
459 return CONTAINING_RECORD(iface, struct time_range, IMFMediaTimeRange_iface);
462 struct media_error
464 IMFMediaError IMFMediaError_iface;
465 LONG refcount;
466 unsigned int code;
467 HRESULT extended_code;
470 static struct media_error *impl_from_IMFMediaError(IMFMediaError *iface)
472 return CONTAINING_RECORD(iface, struct media_error, IMFMediaError_iface);
475 static HRESULT WINAPI media_error_QueryInterface(IMFMediaError *iface, REFIID riid, void **obj)
477 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
479 if (IsEqualIID(riid, &IID_IMFMediaError) ||
480 IsEqualIID(riid, &IID_IUnknown))
482 *obj = iface;
483 IMFMediaError_AddRef(iface);
484 return S_OK;
487 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
488 *obj = NULL;
489 return E_NOINTERFACE;
492 static ULONG WINAPI media_error_AddRef(IMFMediaError *iface)
494 struct media_error *me = impl_from_IMFMediaError(iface);
495 ULONG refcount = InterlockedIncrement(&me->refcount);
497 TRACE("%p, refcount %lu.\n", iface, refcount);
499 return refcount;
502 static ULONG WINAPI media_error_Release(IMFMediaError *iface)
504 struct media_error *me = impl_from_IMFMediaError(iface);
505 ULONG refcount = InterlockedDecrement(&me->refcount);
507 TRACE("%p, refcount %lu.\n", iface, refcount);
509 if (!refcount)
510 free(me);
512 return refcount;
515 static USHORT WINAPI media_error_GetErrorCode(IMFMediaError *iface)
517 struct media_error *me = impl_from_IMFMediaError(iface);
518 TRACE("%p.\n", iface);
519 return me->code;
522 static HRESULT WINAPI media_error_GetExtendedErrorCode(IMFMediaError *iface)
524 struct media_error *me = impl_from_IMFMediaError(iface);
525 TRACE("%p.\n", iface);
526 return me->extended_code;
529 static HRESULT WINAPI media_error_SetErrorCode(IMFMediaError *iface, MF_MEDIA_ENGINE_ERR code)
531 struct media_error *me = impl_from_IMFMediaError(iface);
533 TRACE("%p, %u.\n", iface, code);
535 if ((unsigned int)code > MF_MEDIA_ENGINE_ERR_ENCRYPTED)
536 return E_INVALIDARG;
538 me->code = code;
540 return S_OK;
543 static HRESULT WINAPI media_error_SetExtendedErrorCode(IMFMediaError *iface, HRESULT code)
545 struct media_error *me = impl_from_IMFMediaError(iface);
547 TRACE("%p, %#lx.\n", iface, code);
549 me->extended_code = code;
551 return S_OK;
554 static const IMFMediaErrorVtbl media_error_vtbl =
556 media_error_QueryInterface,
557 media_error_AddRef,
558 media_error_Release,
559 media_error_GetErrorCode,
560 media_error_GetExtendedErrorCode,
561 media_error_SetErrorCode,
562 media_error_SetExtendedErrorCode,
565 static HRESULT create_media_error(IMFMediaError **ret)
567 struct media_error *object;
569 *ret = NULL;
571 if (!(object = calloc(1, sizeof(*object))))
572 return E_OUTOFMEMORY;
574 object->IMFMediaError_iface.lpVtbl = &media_error_vtbl;
575 object->refcount = 1;
577 *ret = &object->IMFMediaError_iface;
579 return S_OK;
582 static HRESULT WINAPI time_range_QueryInterface(IMFMediaTimeRange *iface, REFIID riid, void **obj)
584 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
586 if (IsEqualIID(riid, &IID_IMFMediaTimeRange) ||
587 IsEqualIID(riid, &IID_IUnknown))
589 *obj = iface;
590 IMFMediaTimeRange_AddRef(iface);
591 return S_OK;
594 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
595 *obj = NULL;
596 return E_NOINTERFACE;
599 static ULONG WINAPI time_range_AddRef(IMFMediaTimeRange *iface)
601 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
602 ULONG refcount = InterlockedIncrement(&range->refcount);
604 TRACE("%p, refcount %lu.\n", iface, refcount);
606 return refcount;
609 static ULONG WINAPI time_range_Release(IMFMediaTimeRange *iface)
611 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
612 ULONG refcount = InterlockedDecrement(&range->refcount);
614 TRACE("%p, refcount %lu.\n", iface, refcount);
616 if (!refcount)
618 free(range->ranges);
619 free(range);
622 return refcount;
625 static DWORD WINAPI time_range_GetLength(IMFMediaTimeRange *iface)
627 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
629 TRACE("%p.\n", iface);
631 return range->count;
634 static HRESULT WINAPI time_range_GetStart(IMFMediaTimeRange *iface, DWORD idx, double *start)
636 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
638 TRACE("%p, %lu, %p.\n", iface, idx, start);
640 if (idx >= range->count)
641 return E_INVALIDARG;
643 *start = range->ranges[idx].start;
645 return S_OK;
648 static HRESULT WINAPI time_range_GetEnd(IMFMediaTimeRange *iface, DWORD idx, double *end)
650 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
652 TRACE("%p, %lu, %p.\n", iface, idx, end);
654 if (idx >= range->count)
655 return E_INVALIDARG;
657 *end = range->ranges[idx].end;
659 return S_OK;
662 static BOOL WINAPI time_range_ContainsTime(IMFMediaTimeRange *iface, double time)
664 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
665 size_t i;
667 TRACE("%p, %.8e.\n", iface, time);
669 for (i = 0; i < range->count; ++i)
671 if (time >= range->ranges[i].start && time <= range->ranges[i].end)
672 return TRUE;
675 return FALSE;
678 static HRESULT WINAPI time_range_AddRange(IMFMediaTimeRange *iface, double start, double end)
680 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
681 struct range *c;
682 size_t i;
684 TRACE("%p, %.8e, %.8e.\n", iface, start, end);
686 for (i = 0; i < range->count; ++i)
688 c = &range->ranges[i];
690 /* New range is fully contained within existing one. */
691 if (c->start <= start && c->end >= end)
692 return S_OK;
694 /* New range fully contains existing one. */
695 if (c->start >= start && c->end <= end)
697 c->start = start;
698 c->end = end;
699 return S_OK;
702 /* Merge if ranges intersect. */
703 if ((start >= c->start && start <= c->end) ||
704 (end >= c->start && end <= c->end))
706 c->start = min(c->start, start);
707 c->end = max(c->end, end);
708 return S_OK;
712 if (!mf_array_reserve((void **)&range->ranges, &range->capacity, range->count + 1, sizeof(*range->ranges)))
713 return E_OUTOFMEMORY;
715 range->ranges[range->count].start = start;
716 range->ranges[range->count].end = end;
717 range->count++;
719 return S_OK;
722 static HRESULT WINAPI time_range_Clear(IMFMediaTimeRange *iface)
724 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
726 TRACE("%p.\n", iface);
728 range->count = 0;
730 return S_OK;
733 static const IMFMediaTimeRangeVtbl time_range_vtbl =
735 time_range_QueryInterface,
736 time_range_AddRef,
737 time_range_Release,
738 time_range_GetLength,
739 time_range_GetStart,
740 time_range_GetEnd,
741 time_range_ContainsTime,
742 time_range_AddRange,
743 time_range_Clear,
746 static HRESULT create_time_range(IMFMediaTimeRange **range)
748 struct time_range *object;
750 object = calloc(1, sizeof(*object));
751 if (!object)
752 return E_OUTOFMEMORY;
754 object->IMFMediaTimeRange_iface.lpVtbl = &time_range_vtbl;
755 object->refcount = 1;
757 *range = &object->IMFMediaTimeRange_iface;
759 return S_OK;
762 static void media_engine_set_flag(struct media_engine *engine, unsigned int mask, BOOL value)
764 if (value)
765 engine->flags |= mask;
766 else
767 engine->flags &= ~mask;
770 static inline struct media_engine *impl_from_IMFMediaEngineEx(IMFMediaEngineEx *iface)
772 return CONTAINING_RECORD(iface, struct media_engine, IMFMediaEngineEx_iface);
775 static inline struct media_engine *impl_from_IMFGetService(IMFGetService *iface)
777 return CONTAINING_RECORD(iface, struct media_engine, IMFGetService_iface);
780 static struct media_engine *impl_from_session_events_IMFAsyncCallback(IMFAsyncCallback *iface)
782 return CONTAINING_RECORD(iface, struct media_engine, session_events);
785 static struct media_engine *impl_from_load_handler_IMFAsyncCallback(IMFAsyncCallback *iface)
787 return CONTAINING_RECORD(iface, struct media_engine, load_handler);
790 static struct media_engine *impl_from_IMFSampleGrabberSinkCallback(IMFSampleGrabberSinkCallback *iface)
792 return CONTAINING_RECORD(iface, struct media_engine, grabber_callback);
795 static unsigned int get_gcd(unsigned int a, unsigned int b)
797 unsigned int m;
799 while (b)
801 m = a % b;
802 a = b;
803 b = m;
806 return a;
809 static void media_engine_get_frame_size(struct media_engine *engine, IMFTopology *topology)
811 IMFMediaTypeHandler *handler;
812 IMFMediaType *media_type;
813 IMFStreamDescriptor *sd;
814 IMFTopologyNode *node;
815 unsigned int gcd;
816 UINT64 size;
817 HRESULT hr;
819 engine->video_frame.size.cx = 0;
820 engine->video_frame.size.cy = 0;
821 engine->video_frame.ratio.cx = 1;
822 engine->video_frame.ratio.cy = 1;
824 if (FAILED(IMFTopology_GetNodeByID(topology, engine->video_frame.node_id, &node)))
825 return;
827 hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR,
828 &IID_IMFStreamDescriptor, (void **)&sd);
829 IMFTopologyNode_Release(node);
830 if (FAILED(hr))
831 return;
833 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
834 IMFStreamDescriptor_Release(sd);
835 if (FAILED(hr))
836 return;
838 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &media_type);
839 IMFMediaTypeHandler_Release(handler);
840 if (FAILED(hr))
842 WARN("Failed to get current media type %#lx.\n", hr);
843 return;
846 IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &size);
848 engine->video_frame.size.cx = size >> 32;
849 engine->video_frame.size.cy = size;
851 if ((gcd = get_gcd(engine->video_frame.size.cx, engine->video_frame.size.cy)))
853 engine->video_frame.ratio.cx = engine->video_frame.size.cx / gcd;
854 engine->video_frame.ratio.cy = engine->video_frame.size.cy / gcd;
857 IMFMediaType_Release(media_type);
860 static void media_engine_apply_volume(const struct media_engine *engine)
862 IMFSimpleAudioVolume *sa_volume;
863 HRESULT hr;
865 if (!engine->session)
866 return;
868 if (FAILED(MFGetService((IUnknown *)engine->session, &MR_POLICY_VOLUME_SERVICE, &IID_IMFSimpleAudioVolume, (void **)&sa_volume)))
869 return;
871 if (FAILED(hr = IMFSimpleAudioVolume_SetMasterVolume(sa_volume, engine->volume)))
872 WARN("Failed to set master volume, hr %#lx.\n", hr);
874 IMFSimpleAudioVolume_Release(sa_volume);
877 static HRESULT WINAPI media_engine_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
879 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
880 IsEqualIID(riid, &IID_IUnknown))
882 *obj = iface;
883 IMFAsyncCallback_AddRef(iface);
884 return S_OK;
887 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
888 *obj = NULL;
889 return E_NOINTERFACE;
892 static ULONG WINAPI media_engine_session_events_AddRef(IMFAsyncCallback *iface)
894 struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
895 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
898 static ULONG WINAPI media_engine_session_events_Release(IMFAsyncCallback *iface)
900 struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
901 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
904 static HRESULT WINAPI media_engine_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
906 return E_NOTIMPL;
909 static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
911 struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
912 IMFMediaEvent *event = NULL;
913 MediaEventType event_type;
914 HRESULT hr;
916 if (FAILED(hr = IMFMediaSession_EndGetEvent(engine->session, result, &event)))
918 WARN("Failed to get session event, hr %#lx.\n", hr);
919 goto failed;
922 if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type)))
924 WARN("Failed to get event type, hr %#lx.\n", hr);
925 goto failed;
928 switch (event_type)
930 case MEBufferingStarted:
931 case MEBufferingStopped:
933 IMFMediaEngineNotify_EventNotify(engine->callback, event_type == MEBufferingStarted ?
934 MF_MEDIA_ENGINE_EVENT_BUFFERINGSTARTED : MF_MEDIA_ENGINE_EVENT_BUFFERINGENDED, 0, 0);
935 break;
936 case MESessionTopologyStatus:
938 UINT32 topo_status = 0;
939 IMFTopology *topology;
940 PROPVARIANT value;
942 IMFMediaEvent_GetUINT32(event, &MF_EVENT_TOPOLOGY_STATUS, &topo_status);
943 if (topo_status != MF_TOPOSTATUS_READY)
944 break;
946 value.vt = VT_EMPTY;
947 if (FAILED(IMFMediaEvent_GetValue(event, &value)))
948 break;
950 if (value.vt != VT_UNKNOWN)
952 PropVariantClear(&value);
953 break;
956 topology = (IMFTopology *)value.punkVal;
958 EnterCriticalSection(&engine->cs);
960 media_engine_apply_volume(engine);
962 engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_METADATA;
964 media_engine_get_frame_size(engine, topology);
966 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE, 0, 0);
967 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA, 0, 0);
969 engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_ENOUGH_DATA;
971 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDDATA, 0, 0);
972 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_CANPLAY, 0, 0);
974 LeaveCriticalSection(&engine->cs);
976 PropVariantClear(&value);
978 break;
980 case MESessionStarted:
982 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAYING, 0, 0);
983 break;
984 case MESessionEnded:
986 EnterCriticalSection(&engine->cs);
987 media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, FALSE);
988 media_engine_set_flag(engine, FLAGS_ENGINE_IS_ENDED, TRUE);
989 engine->video_frame.pts = MINLONGLONG;
990 LeaveCriticalSection(&engine->cs);
992 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ENDED, 0, 0);
993 break;
996 failed:
998 if (event)
999 IMFMediaEvent_Release(event);
1001 if (FAILED(hr = IMFMediaSession_BeginGetEvent(engine->session, iface, NULL)))
1002 WARN("Failed to subscribe to session events, hr %#lx.\n", hr);
1004 return S_OK;
1007 static const IMFAsyncCallbackVtbl media_engine_session_events_vtbl =
1009 media_engine_callback_QueryInterface,
1010 media_engine_session_events_AddRef,
1011 media_engine_session_events_Release,
1012 media_engine_callback_GetParameters,
1013 media_engine_session_events_Invoke,
1016 static ULONG WINAPI media_engine_load_handler_AddRef(IMFAsyncCallback *iface)
1018 struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
1019 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
1022 static ULONG WINAPI media_engine_load_handler_Release(IMFAsyncCallback *iface)
1024 struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
1025 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
1028 static HRESULT media_engine_create_source_node(IMFMediaSource *source, IMFPresentationDescriptor *pd, IMFStreamDescriptor *sd,
1029 IMFTopologyNode **node)
1031 HRESULT hr;
1033 if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, node)))
1034 return hr;
1036 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_SOURCE, (IUnknown *)source);
1037 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)pd);
1038 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd);
1040 return S_OK;
1043 static HRESULT media_engine_create_effects(struct effect *effects, size_t count,
1044 IMFTopologyNode *src, IMFTopologyNode *sink, IMFTopology *topology)
1046 IMFTopologyNode *last = src;
1047 HRESULT hr = S_OK;
1048 size_t i;
1050 IMFTopologyNode_AddRef(last);
1052 for (i = 0; i < count; ++i)
1054 IMFTopologyNode *node = NULL;
1056 if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node)))
1058 WARN("Failed to create transform node, hr %#lx.\n", hr);
1059 break;
1062 IMFTopologyNode_SetObject(node, (IUnknown *)effects[i].object);
1063 IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
1065 if (effects[i].optional)
1066 IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_CONNECT_METHOD, MF_CONNECT_AS_OPTIONAL);
1068 IMFTopology_AddNode(topology, node);
1069 IMFTopologyNode_ConnectOutput(last, 0, node, 0);
1071 IMFTopologyNode_Release(last);
1072 last = node;
1075 IMFTopologyNode_Release(last);
1077 if (SUCCEEDED(hr))
1078 hr = IMFTopologyNode_ConnectOutput(last, 0, sink, 0);
1080 return hr;
1083 static HRESULT media_engine_create_audio_renderer(struct media_engine *engine, IMFTopologyNode **node)
1085 unsigned int category, role;
1086 IMFActivate *sar_activate;
1087 HRESULT hr;
1089 *node = NULL;
1091 if (FAILED(hr = MFCreateAudioRendererActivate(&sar_activate)))
1092 return hr;
1094 /* Configuration attributes keys differ between Engine and SAR. */
1095 if (SUCCEEDED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, &category)))
1096 IMFActivate_SetUINT32(sar_activate, &MF_AUDIO_RENDERER_ATTRIBUTE_STREAM_CATEGORY, category);
1097 if (SUCCEEDED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, &role)))
1098 IMFActivate_SetUINT32(sar_activate, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, role);
1100 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, node)))
1102 IMFTopologyNode_SetObject(*node, (IUnknown *)sar_activate);
1103 IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
1106 IMFActivate_Release(sar_activate);
1108 return hr;
1111 static HRESULT media_engine_create_video_renderer(struct media_engine *engine, IMFTopologyNode **node)
1113 IMFMediaType *media_type;
1114 IMFActivate *activate;
1115 UINT32 output_format;
1116 GUID subtype;
1117 HRESULT hr;
1119 *node = NULL;
1121 if (FAILED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, &output_format)))
1123 WARN("Output format was not specified.\n");
1124 return E_FAIL;
1127 memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype));
1128 if (!(subtype.Data1 = MFMapDXGIFormatToDX9Format(output_format)))
1130 WARN("Unrecognized output format %#x.\n", output_format);
1131 return E_FAIL;
1134 if (FAILED(hr = MFCreateMediaType(&media_type)))
1135 return hr;
1137 IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video);
1138 IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &subtype);
1140 hr = MFCreateSampleGrabberSinkActivate(media_type, &engine->grabber_callback, &activate);
1141 IMFMediaType_Release(media_type);
1142 if (FAILED(hr))
1143 return hr;
1145 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, node)))
1147 IMFTopologyNode_SetObject(*node, (IUnknown *)activate);
1148 IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
1151 IMFActivate_Release(activate);
1153 engine->video_frame.output_format = output_format;
1155 return hr;
1158 static void media_engine_clear_presentation(struct media_engine *engine)
1160 if (engine->presentation.source)
1162 IMFMediaSource_Shutdown(engine->presentation.source);
1163 IMFMediaSource_Release(engine->presentation.source);
1165 if (engine->presentation.pd)
1166 IMFPresentationDescriptor_Release(engine->presentation.pd);
1167 memset(&engine->presentation, 0, sizeof(engine->presentation));
1170 static void media_engine_clear_effects(struct effects *effects)
1172 size_t i;
1174 for (i = 0; i < effects->count; ++i)
1176 if (effects->effects[i].object)
1177 IUnknown_Release(effects->effects[i].object);
1180 free(effects->effects);
1181 memset(effects, 0, sizeof(*effects));
1184 static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMediaSource *source)
1186 IMFStreamDescriptor *sd_audio = NULL, *sd_video = NULL;
1187 IMFPresentationDescriptor *pd;
1188 DWORD stream_count = 0, i;
1189 IMFTopology *topology;
1190 UINT64 duration;
1191 HRESULT hr;
1193 media_engine_release_video_frame_resources(engine);
1194 media_engine_clear_presentation(engine);
1196 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd)))
1197 return hr;
1199 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(pd, &stream_count)))
1200 WARN("Failed to get stream count, hr %#lx.\n", hr);
1202 /* Enable first video stream and first audio stream. */
1204 for (i = 0; i < stream_count; ++i)
1206 IMFMediaTypeHandler *type_handler;
1207 IMFStreamDescriptor *sd;
1208 BOOL selected;
1210 IMFPresentationDescriptor_DeselectStream(pd, i);
1212 if (sd_audio && sd_video)
1213 continue;
1215 IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, i, &selected, &sd);
1217 if (SUCCEEDED(IMFStreamDescriptor_GetMediaTypeHandler(sd, &type_handler)))
1219 GUID major = { 0 };
1221 IMFMediaTypeHandler_GetMajorType(type_handler, &major);
1223 if (IsEqualGUID(&major, &MFMediaType_Audio) && !sd_audio)
1225 sd_audio = sd;
1226 IMFStreamDescriptor_AddRef(sd_audio);
1227 IMFPresentationDescriptor_SelectStream(pd, i);
1229 else if (IsEqualGUID(&major, &MFMediaType_Video) && !sd_video && !(engine->flags & MF_MEDIA_ENGINE_AUDIOONLY))
1231 sd_video = sd;
1232 IMFStreamDescriptor_AddRef(sd_video);
1233 IMFPresentationDescriptor_SelectStream(pd, i);
1236 IMFMediaTypeHandler_Release(type_handler);
1239 IMFStreamDescriptor_Release(sd);
1242 if (!sd_video && !sd_audio)
1244 IMFPresentationDescriptor_Release(pd);
1245 return E_UNEXPECTED;
1248 engine->presentation.source = source;
1249 IMFMediaSource_AddRef(engine->presentation.source);
1250 engine->presentation.pd = pd;
1251 IMFPresentationDescriptor_AddRef(engine->presentation.pd);
1253 media_engine_set_flag(engine, FLAGS_ENGINE_HAS_VIDEO, !!sd_video);
1254 media_engine_set_flag(engine, FLAGS_ENGINE_HAS_AUDIO, !!sd_audio);
1256 /* Assume live source if duration was not provided. */
1257 if (SUCCEEDED(IMFPresentationDescriptor_GetUINT64(pd, &MF_PD_DURATION, &duration)))
1258 engine->duration = mftime_to_seconds(duration);
1259 else
1260 engine->duration = INFINITY;
1262 if (SUCCEEDED(hr = MFCreateTopology(&topology)))
1264 IMFTopologyNode *sar_node = NULL, *audio_src = NULL;
1265 IMFTopologyNode *grabber_node = NULL, *video_src = NULL;
1267 if (engine->flags & MF_MEDIA_ENGINE_REAL_TIME_MODE)
1268 IMFTopology_SetUINT32(topology, &MF_LOW_LATENCY, TRUE);
1270 if (sd_audio)
1272 if (FAILED(hr = media_engine_create_source_node(source, pd, sd_audio, &audio_src)))
1273 WARN("Failed to create audio source node, hr %#lx.\n", hr);
1275 if (FAILED(hr = media_engine_create_audio_renderer(engine, &sar_node)))
1276 WARN("Failed to create audio renderer node, hr %#lx.\n", hr);
1278 if (sar_node && audio_src)
1280 IMFTopology_AddNode(topology, audio_src);
1281 IMFTopology_AddNode(topology, sar_node);
1283 if (FAILED(hr = media_engine_create_effects(engine->audio_effects.effects, engine->audio_effects.count,
1284 audio_src, sar_node, topology)))
1285 WARN("Failed to create audio effect nodes, hr %#lx.\n", hr);
1288 if (sar_node)
1289 IMFTopologyNode_Release(sar_node);
1290 if (audio_src)
1291 IMFTopologyNode_Release(audio_src);
1294 if (SUCCEEDED(hr) && sd_video)
1296 if (FAILED(hr = media_engine_create_source_node(source, pd, sd_video, &video_src)))
1297 WARN("Failed to create video source node, hr %#lx.\n", hr);
1299 if (FAILED(hr = media_engine_create_video_renderer(engine, &grabber_node)))
1300 WARN("Failed to create video grabber node, hr %#lx.\n", hr);
1302 if (grabber_node && video_src)
1304 IMFTopology_AddNode(topology, video_src);
1305 IMFTopology_AddNode(topology, grabber_node);
1307 if (FAILED(hr = media_engine_create_effects(engine->video_effects.effects, engine->video_effects.count,
1308 video_src, grabber_node, topology)))
1309 WARN("Failed to create video effect nodes, hr %#lx.\n", hr);
1312 if (SUCCEEDED(hr))
1313 IMFTopologyNode_GetTopoNodeID(video_src, &engine->video_frame.node_id);
1315 if (grabber_node)
1316 IMFTopologyNode_Release(grabber_node);
1317 if (video_src)
1318 IMFTopologyNode_Release(video_src);
1321 IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, TRUE);
1323 if (SUCCEEDED(hr))
1324 hr = IMFMediaSession_SetTopology(engine->session, MFSESSION_SETTOPOLOGY_IMMEDIATE, topology);
1327 if (topology)
1328 IMFTopology_Release(topology);
1330 if (sd_video)
1331 IMFStreamDescriptor_Release(sd_video);
1332 if (sd_audio)
1333 IMFStreamDescriptor_Release(sd_audio);
1335 IMFPresentationDescriptor_Release(pd);
1337 return hr;
1340 static void media_engine_start_playback(struct media_engine *engine)
1342 PROPVARIANT var;
1344 var.vt = VT_EMPTY;
1345 IMFMediaSession_Start(engine->session, &GUID_NULL, &var);
1348 static HRESULT WINAPI media_engine_load_handler_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1350 struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
1351 IUnknown *object = NULL, *state;
1352 unsigned int start_playback;
1353 MF_OBJECT_TYPE obj_type;
1354 IMFMediaSource *source;
1355 HRESULT hr;
1357 EnterCriticalSection(&engine->cs);
1359 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1361 LeaveCriticalSection(&engine->cs);
1362 return S_OK;
1365 engine->network_state = MF_MEDIA_ENGINE_NETWORK_LOADING;
1366 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADSTART, 0, 0);
1368 start_playback = engine->flags & FLAGS_ENGINE_PLAY_PENDING;
1369 media_engine_set_flag(engine, FLAGS_ENGINE_SOURCE_PENDING | FLAGS_ENGINE_PLAY_PENDING, FALSE);
1371 if (SUCCEEDED(IMFAsyncResult_GetState(result, &state)))
1373 hr = IMFSourceResolver_EndCreateObjectFromByteStream(engine->resolver, result, &obj_type, &object);
1374 IUnknown_Release(state);
1376 else
1377 hr = IMFSourceResolver_EndCreateObjectFromURL(engine->resolver, result, &obj_type, &object);
1379 if (FAILED(hr))
1380 WARN("Failed to create source object, hr %#lx.\n", hr);
1382 if (object)
1384 if (SUCCEEDED(hr = IUnknown_QueryInterface(object, &IID_IMFMediaSource, (void **)&source)))
1386 hr = media_engine_create_topology(engine, source);
1387 IMFMediaSource_Release(source);
1389 IUnknown_Release(object);
1392 if (SUCCEEDED(hr))
1394 engine->network_state = MF_MEDIA_ENGINE_NETWORK_IDLE;
1395 if (start_playback)
1396 media_engine_start_playback(engine);
1398 else
1400 engine->network_state = MF_MEDIA_ENGINE_NETWORK_NO_SOURCE;
1401 engine->error_code = MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED;
1402 engine->extended_code = hr;
1403 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ERROR, engine->error_code,
1404 engine->extended_code);
1407 LeaveCriticalSection(&engine->cs);
1409 return S_OK;
1412 static const IMFAsyncCallbackVtbl media_engine_load_handler_vtbl =
1414 media_engine_callback_QueryInterface,
1415 media_engine_load_handler_AddRef,
1416 media_engine_load_handler_Release,
1417 media_engine_callback_GetParameters,
1418 media_engine_load_handler_Invoke,
1421 static HRESULT WINAPI media_engine_QueryInterface(IMFMediaEngineEx *iface, REFIID riid, void **obj)
1423 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1425 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1427 if (IsEqualIID(riid, &IID_IMFMediaEngineEx) ||
1428 IsEqualIID(riid, &IID_IMFMediaEngine) ||
1429 IsEqualIID(riid, &IID_IUnknown))
1431 *obj = iface;
1433 else if (IsEqualIID(riid, &IID_IMFGetService))
1435 *obj = &engine->IMFGetService_iface;
1437 else
1439 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1440 *obj = NULL;
1441 return E_NOINTERFACE;
1444 IUnknown_AddRef((IUnknown *)*obj);
1445 return S_OK;
1448 static ULONG WINAPI media_engine_AddRef(IMFMediaEngineEx *iface)
1450 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1451 ULONG refcount = InterlockedIncrement(&engine->refcount);
1453 TRACE("%p, refcount %lu.\n", iface, refcount);
1455 return refcount;
1458 static void free_media_engine(struct media_engine *engine)
1460 if (engine->callback)
1461 IMFMediaEngineNotify_Release(engine->callback);
1462 if (engine->clock)
1463 IMFPresentationClock_Release(engine->clock);
1464 if (engine->session)
1465 IMFMediaSession_Release(engine->session);
1466 if (engine->attributes)
1467 IMFAttributes_Release(engine->attributes);
1468 if (engine->resolver)
1469 IMFSourceResolver_Release(engine->resolver);
1470 if (engine->extension)
1471 IMFMediaEngineExtension_Release(engine->extension);
1472 media_engine_clear_effects(&engine->audio_effects);
1473 media_engine_clear_effects(&engine->video_effects);
1474 media_engine_release_video_frame_resources(engine);
1475 media_engine_clear_presentation(engine);
1476 if (engine->device_manager)
1478 IMFDXGIDeviceManager_CloseDeviceHandle(engine->device_manager, engine->device_handle);
1479 IMFDXGIDeviceManager_Release(engine->device_manager);
1481 SysFreeString(engine->current_source);
1482 DeleteCriticalSection(&engine->cs);
1483 free(engine->video_frame.buffer);
1484 free(engine);
1487 static ULONG WINAPI media_engine_Release(IMFMediaEngineEx *iface)
1489 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1490 ULONG refcount = InterlockedDecrement(&engine->refcount);
1492 TRACE("%p, refcount %lu.\n", iface, refcount);
1494 if (!refcount)
1495 free_media_engine(engine);
1497 return refcount;
1500 static HRESULT WINAPI media_engine_GetError(IMFMediaEngineEx *iface, IMFMediaError **error)
1502 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1503 HRESULT hr = S_OK;
1505 TRACE("%p, %p.\n", iface, error);
1507 *error = NULL;
1509 EnterCriticalSection(&engine->cs);
1510 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1511 hr = MF_E_SHUTDOWN;
1512 else if (engine->error_code)
1514 if (SUCCEEDED(hr = create_media_error(error)))
1516 IMFMediaError_SetErrorCode(*error, engine->error_code);
1517 IMFMediaError_SetExtendedErrorCode(*error, engine->extended_code);
1520 LeaveCriticalSection(&engine->cs);
1522 return hr;
1525 static HRESULT WINAPI media_engine_SetErrorCode(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_ERR code)
1527 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1528 HRESULT hr = S_OK;
1530 TRACE("%p, %u.\n", iface, code);
1532 if ((unsigned int)code > MF_MEDIA_ENGINE_ERR_ENCRYPTED)
1533 return E_INVALIDARG;
1535 EnterCriticalSection(&engine->cs);
1536 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1537 hr = MF_E_SHUTDOWN;
1538 else
1539 engine->error_code = code;
1540 LeaveCriticalSection(&engine->cs);
1542 return hr;
1545 static HRESULT WINAPI media_engine_SetSourceElements(IMFMediaEngineEx *iface, IMFMediaEngineSrcElements *elements)
1547 FIXME("(%p, %p): stub.\n", iface, elements);
1549 return E_NOTIMPL;
1552 static HRESULT media_engine_set_source(struct media_engine *engine, IMFByteStream *bytestream, BSTR url)
1554 IPropertyStore *props = NULL;
1555 unsigned int flags;
1556 HRESULT hr = S_OK;
1558 SysFreeString(engine->current_source);
1559 engine->current_source = NULL;
1560 if (url)
1561 engine->current_source = SysAllocString(url);
1563 engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_NOTHING;
1565 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
1567 engine->network_state = MF_MEDIA_ENGINE_NETWORK_NO_SOURCE;
1569 if (url || bytestream)
1571 if (engine->extension)
1572 FIXME("Use extension to load from.\n");
1574 flags = MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE;
1575 if (engine->flags & MF_MEDIA_ENGINE_DISABLE_LOCAL_PLUGINS)
1576 flags |= MF_RESOLUTION_DISABLE_LOCAL_PLUGINS;
1578 IMFAttributes_GetUnknown(engine->attributes, &MF_MEDIA_ENGINE_SOURCE_RESOLVER_CONFIG_STORE,
1579 &IID_IPropertyStore, (void **)&props);
1580 if (bytestream)
1581 hr = IMFSourceResolver_BeginCreateObjectFromByteStream(engine->resolver, bytestream, url, flags,
1582 props, NULL, &engine->load_handler, (IUnknown *)bytestream);
1583 else
1584 hr = IMFSourceResolver_BeginCreateObjectFromURL(engine->resolver, url, flags, props, NULL,
1585 &engine->load_handler, NULL);
1586 if (SUCCEEDED(hr))
1587 media_engine_set_flag(engine, FLAGS_ENGINE_SOURCE_PENDING, TRUE);
1589 if (props)
1590 IPropertyStore_Release(props);
1593 return hr;
1596 static HRESULT WINAPI media_engine_SetSource(IMFMediaEngineEx *iface, BSTR url)
1598 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1599 HRESULT hr;
1601 TRACE("%p, %s.\n", iface, debugstr_w(url));
1603 EnterCriticalSection(&engine->cs);
1605 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1606 hr = MF_E_SHUTDOWN;
1607 else
1608 hr = media_engine_set_source(engine, NULL, url);
1610 LeaveCriticalSection(&engine->cs);
1612 return hr;
1615 static HRESULT WINAPI media_engine_GetCurrentSource(IMFMediaEngineEx *iface, BSTR *url)
1617 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1618 HRESULT hr = S_OK;
1620 TRACE("%p, %p.\n", iface, url);
1622 *url = NULL;
1624 EnterCriticalSection(&engine->cs);
1626 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1627 hr = MF_E_SHUTDOWN;
1628 if (engine->current_source)
1630 if (!(*url = SysAllocString(engine->current_source)))
1631 hr = E_OUTOFMEMORY;
1634 LeaveCriticalSection(&engine->cs);
1636 return hr;
1639 static USHORT WINAPI media_engine_GetNetworkState(IMFMediaEngineEx *iface)
1641 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1643 TRACE("%p.\n", iface);
1645 return engine->network_state;
1648 static MF_MEDIA_ENGINE_PRELOAD WINAPI media_engine_GetPreload(IMFMediaEngineEx *iface)
1650 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1651 MF_MEDIA_ENGINE_PRELOAD preload;
1653 TRACE("%p.\n", iface);
1655 EnterCriticalSection(&engine->cs);
1656 preload = engine->preload;
1657 LeaveCriticalSection(&engine->cs);
1659 return preload;
1662 static HRESULT WINAPI media_engine_SetPreload(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_PRELOAD preload)
1664 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1666 TRACE("%p, %d.\n", iface, preload);
1668 EnterCriticalSection(&engine->cs);
1669 engine->preload = preload;
1670 LeaveCriticalSection(&engine->cs);
1672 return S_OK;
1675 static HRESULT WINAPI media_engine_GetBuffered(IMFMediaEngineEx *iface, IMFMediaTimeRange **range)
1677 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1678 HRESULT hr;
1680 TRACE("%p, %p.\n", iface, range);
1682 if (FAILED(hr = create_time_range(range)))
1683 return hr;
1685 EnterCriticalSection(&engine->cs);
1687 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1688 hr = MF_E_SHUTDOWN;
1689 else if (!isnan(engine->duration))
1690 hr = IMFMediaTimeRange_AddRange(*range, 0.0, engine->duration);
1692 LeaveCriticalSection(&engine->cs);
1694 return hr;
1697 static HRESULT WINAPI media_engine_Load(IMFMediaEngineEx *iface)
1699 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1700 HRESULT hr = E_NOTIMPL;
1702 FIXME("(%p): stub.\n", iface);
1704 EnterCriticalSection(&engine->cs);
1706 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1707 hr = MF_E_SHUTDOWN;
1709 LeaveCriticalSection(&engine->cs);
1711 return hr;
1714 static HRESULT WINAPI media_engine_CanPlayType(IMFMediaEngineEx *iface, BSTR mime_type, MF_MEDIA_ENGINE_CANPLAY *answer)
1716 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1717 HRESULT hr = E_NOTIMPL;
1719 TRACE("%p, %s, %p.\n", iface, debugstr_w(mime_type), answer);
1721 EnterCriticalSection(&engine->cs);
1723 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1724 hr = MF_E_SHUTDOWN;
1725 else
1727 FIXME("Check builtin supported types.\n");
1729 if (engine->extension)
1730 hr = IMFMediaEngineExtension_CanPlayType(engine->extension, !!(engine->flags & MF_MEDIA_ENGINE_AUDIOONLY),
1731 mime_type, answer);
1734 LeaveCriticalSection(&engine->cs);
1736 return hr;
1739 static USHORT WINAPI media_engine_GetReadyState(IMFMediaEngineEx *iface)
1741 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1742 unsigned short state;
1744 TRACE("%p.\n", iface);
1746 EnterCriticalSection(&engine->cs);
1747 state = engine->ready_state;
1748 LeaveCriticalSection(&engine->cs);
1750 return state;
1753 static BOOL WINAPI media_engine_IsSeeking(IMFMediaEngineEx *iface)
1755 FIXME("(%p): stub.\n", iface);
1757 return FALSE;
1760 static double WINAPI media_engine_GetCurrentTime(IMFMediaEngineEx *iface)
1762 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1763 double ret = 0.0;
1764 MFTIME clocktime;
1766 TRACE("%p.\n", iface);
1768 EnterCriticalSection(&engine->cs);
1769 if (engine->flags & FLAGS_ENGINE_IS_ENDED)
1771 ret = engine->duration;
1773 else if (SUCCEEDED(IMFPresentationClock_GetTime(engine->clock, &clocktime)))
1775 ret = mftime_to_seconds(clocktime);
1777 LeaveCriticalSection(&engine->cs);
1779 return ret;
1782 static HRESULT WINAPI media_engine_SetCurrentTime(IMFMediaEngineEx *iface, double time)
1784 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1785 HRESULT hr = E_NOTIMPL;
1787 FIXME("(%p, %f): stub.\n", iface, time);
1789 EnterCriticalSection(&engine->cs);
1791 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1792 hr = MF_E_SHUTDOWN;
1794 LeaveCriticalSection(&engine->cs);
1796 return hr;
1799 static double WINAPI media_engine_GetStartTime(IMFMediaEngineEx *iface)
1801 FIXME("(%p): stub.\n", iface);
1803 return 0.0;
1806 static double WINAPI media_engine_GetDuration(IMFMediaEngineEx *iface)
1808 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1809 double value;
1811 TRACE("%p.\n", iface);
1813 EnterCriticalSection(&engine->cs);
1814 value = engine->duration;
1815 LeaveCriticalSection(&engine->cs);
1817 return value;
1820 static BOOL WINAPI media_engine_IsPaused(IMFMediaEngineEx *iface)
1822 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1823 BOOL value;
1825 TRACE("%p.\n", iface);
1827 EnterCriticalSection(&engine->cs);
1828 value = !!(engine->flags & FLAGS_ENGINE_PAUSED);
1829 LeaveCriticalSection(&engine->cs);
1831 return value;
1834 static double WINAPI media_engine_GetDefaultPlaybackRate(IMFMediaEngineEx *iface)
1836 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1837 double rate;
1839 TRACE("%p.\n", iface);
1841 EnterCriticalSection(&engine->cs);
1842 rate = engine->default_playback_rate;
1843 LeaveCriticalSection(&engine->cs);
1845 return rate;
1848 static HRESULT WINAPI media_engine_SetDefaultPlaybackRate(IMFMediaEngineEx *iface, double rate)
1850 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1851 HRESULT hr = S_OK;
1853 TRACE("%p, %f.\n", iface, rate);
1855 EnterCriticalSection(&engine->cs);
1856 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1857 hr = MF_E_SHUTDOWN;
1858 else if (engine->default_playback_rate != rate)
1860 engine->default_playback_rate = rate;
1861 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_RATECHANGE, 0, 0);
1863 LeaveCriticalSection(&engine->cs);
1865 return hr;
1868 static double WINAPI media_engine_GetPlaybackRate(IMFMediaEngineEx *iface)
1870 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1871 double rate;
1873 TRACE("%p.\n", iface);
1875 EnterCriticalSection(&engine->cs);
1876 rate = engine->playback_rate;
1877 LeaveCriticalSection(&engine->cs);
1879 return rate;
1882 static HRESULT WINAPI media_engine_SetPlaybackRate(IMFMediaEngineEx *iface, double rate)
1884 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1885 HRESULT hr = S_OK;
1887 TRACE("%p, %f.\n", iface, rate);
1889 EnterCriticalSection(&engine->cs);
1890 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1891 hr = MF_E_SHUTDOWN;
1892 else if (engine->playback_rate != rate)
1894 engine->playback_rate = rate;
1895 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_RATECHANGE, 0, 0);
1897 LeaveCriticalSection(&engine->cs);
1899 return hr;
1902 static HRESULT WINAPI media_engine_GetPlayed(IMFMediaEngineEx *iface, IMFMediaTimeRange **played)
1904 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1905 HRESULT hr = E_NOTIMPL;
1907 FIXME("(%p, %p): stub.\n", iface, played);
1909 EnterCriticalSection(&engine->cs);
1911 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1912 hr = MF_E_SHUTDOWN;
1914 LeaveCriticalSection(&engine->cs);
1916 return hr;
1919 static HRESULT WINAPI media_engine_GetSeekable(IMFMediaEngineEx *iface, IMFMediaTimeRange **seekable)
1921 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1922 IMFMediaTimeRange *time_range = NULL;
1923 DWORD flags;
1924 HRESULT hr;
1926 TRACE("%p, %p.\n", iface, seekable);
1928 EnterCriticalSection(&engine->cs);
1930 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1931 hr = MF_E_SHUTDOWN;
1932 else
1934 hr = create_time_range(&time_range);
1935 if (SUCCEEDED(hr) && !isnan(engine->duration) && engine->presentation.source)
1937 hr = IMFMediaSource_GetCharacteristics(engine->presentation.source, &flags);
1938 if (SUCCEEDED(hr) && (flags & MFBYTESTREAM_IS_SEEKABLE))
1939 hr = IMFMediaTimeRange_AddRange(time_range, 0.0, engine->duration);
1943 LeaveCriticalSection(&engine->cs);
1945 if (FAILED(hr) && time_range)
1947 IMFMediaTimeRange_Release(time_range);
1948 time_range = NULL;
1950 *seekable = time_range;
1951 return hr;
1954 static BOOL WINAPI media_engine_IsEnded(IMFMediaEngineEx *iface)
1956 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1957 BOOL value;
1959 TRACE("%p.\n", iface);
1961 EnterCriticalSection(&engine->cs);
1962 value = !!(engine->flags & FLAGS_ENGINE_IS_ENDED);
1963 LeaveCriticalSection(&engine->cs);
1965 return value;
1968 static BOOL WINAPI media_engine_GetAutoPlay(IMFMediaEngineEx *iface)
1970 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1971 BOOL value;
1973 TRACE("%p.\n", iface);
1975 EnterCriticalSection(&engine->cs);
1976 value = !!(engine->flags & FLAGS_ENGINE_AUTO_PLAY);
1977 LeaveCriticalSection(&engine->cs);
1979 return value;
1982 static HRESULT WINAPI media_engine_SetAutoPlay(IMFMediaEngineEx *iface, BOOL autoplay)
1984 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1986 FIXME("(%p, %d): stub.\n", iface, autoplay);
1988 EnterCriticalSection(&engine->cs);
1989 media_engine_set_flag(engine, FLAGS_ENGINE_AUTO_PLAY, autoplay);
1990 LeaveCriticalSection(&engine->cs);
1992 return S_OK;
1995 static BOOL WINAPI media_engine_GetLoop(IMFMediaEngineEx *iface)
1997 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1998 BOOL value;
2000 TRACE("%p.\n", iface);
2002 EnterCriticalSection(&engine->cs);
2003 value = !!(engine->flags & FLAGS_ENGINE_LOOP);
2004 LeaveCriticalSection(&engine->cs);
2006 return value;
2009 static HRESULT WINAPI media_engine_SetLoop(IMFMediaEngineEx *iface, BOOL loop)
2011 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2013 FIXME("(%p, %d): stub.\n", iface, loop);
2015 EnterCriticalSection(&engine->cs);
2016 media_engine_set_flag(engine, FLAGS_ENGINE_LOOP, loop);
2017 LeaveCriticalSection(&engine->cs);
2019 return S_OK;
2022 static HRESULT WINAPI media_engine_Play(IMFMediaEngineEx *iface)
2024 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2025 HRESULT hr = S_OK;
2027 TRACE("%p.\n", iface);
2029 EnterCriticalSection(&engine->cs);
2031 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2032 hr = MF_E_SHUTDOWN;
2033 else
2035 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
2037 if (!(engine->flags & FLAGS_ENGINE_WAITING))
2039 media_engine_set_flag(engine, FLAGS_ENGINE_PAUSED | FLAGS_ENGINE_IS_ENDED, FALSE);
2040 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAY, 0, 0);
2042 if (!(engine->flags & FLAGS_ENGINE_SOURCE_PENDING))
2043 media_engine_start_playback(engine);
2044 else
2045 media_engine_set_flag(engine, FLAGS_ENGINE_PLAY_PENDING, TRUE);
2047 media_engine_set_flag(engine, FLAGS_ENGINE_WAITING, TRUE);
2050 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_WAITING, 0, 0);
2053 LeaveCriticalSection(&engine->cs);
2055 return hr;
2058 static HRESULT WINAPI media_engine_Pause(IMFMediaEngineEx *iface)
2060 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2061 HRESULT hr = S_OK;
2063 TRACE("%p.\n", iface);
2065 EnterCriticalSection(&engine->cs);
2067 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2068 hr = MF_E_SHUTDOWN;
2069 else
2071 if (!(engine->flags & FLAGS_ENGINE_PAUSED))
2073 if (SUCCEEDED(hr = IMFMediaSession_Pause(engine->session)))
2075 media_engine_set_flag(engine, FLAGS_ENGINE_WAITING | FLAGS_ENGINE_IS_ENDED, FALSE);
2076 media_engine_set_flag(engine, FLAGS_ENGINE_PAUSED, TRUE);
2078 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_TIMEUPDATE, 0, 0);
2079 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PAUSE, 0, 0);
2083 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
2086 LeaveCriticalSection(&engine->cs);
2088 return hr;
2091 static BOOL WINAPI media_engine_GetMuted(IMFMediaEngineEx *iface)
2093 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2094 BOOL ret;
2096 TRACE("%p.\n", iface);
2098 EnterCriticalSection(&engine->cs);
2099 ret = !!(engine->flags & FLAGS_ENGINE_MUTED);
2100 LeaveCriticalSection(&engine->cs);
2102 return ret;
2105 static HRESULT WINAPI media_engine_SetMuted(IMFMediaEngineEx *iface, BOOL muted)
2107 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2108 HRESULT hr = S_OK;
2110 TRACE("%p, %d.\n", iface, muted);
2112 EnterCriticalSection(&engine->cs);
2113 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2114 hr = MF_E_SHUTDOWN;
2115 else if (!!(engine->flags & FLAGS_ENGINE_MUTED) ^ !!muted)
2117 media_engine_set_flag(engine, FLAGS_ENGINE_MUTED, muted);
2118 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE, 0, 0);
2120 LeaveCriticalSection(&engine->cs);
2122 return hr;
2125 static double WINAPI media_engine_GetVolume(IMFMediaEngineEx *iface)
2127 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2128 double volume;
2130 TRACE("%p.\n", iface);
2132 EnterCriticalSection(&engine->cs);
2133 volume = engine->volume;
2134 LeaveCriticalSection(&engine->cs);
2136 return volume;
2139 static HRESULT WINAPI media_engine_SetVolume(IMFMediaEngineEx *iface, double volume)
2141 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2142 HRESULT hr = S_OK;
2144 TRACE("%p, %f.\n", iface, volume);
2146 EnterCriticalSection(&engine->cs);
2147 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2148 hr = MF_E_SHUTDOWN;
2149 else if (volume != engine->volume)
2151 engine->volume = volume;
2152 media_engine_apply_volume(engine);
2153 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE, 0, 0);
2155 LeaveCriticalSection(&engine->cs);
2157 return hr;
2160 static BOOL WINAPI media_engine_HasVideo(IMFMediaEngineEx *iface)
2162 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2163 BOOL value;
2165 TRACE("%p.\n", iface);
2167 EnterCriticalSection(&engine->cs);
2168 value = !!(engine->flags & FLAGS_ENGINE_HAS_VIDEO);
2169 LeaveCriticalSection(&engine->cs);
2171 return value;
2174 static BOOL WINAPI media_engine_HasAudio(IMFMediaEngineEx *iface)
2176 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2177 BOOL value;
2179 TRACE("%p.\n", iface);
2181 EnterCriticalSection(&engine->cs);
2182 value = !!(engine->flags & FLAGS_ENGINE_HAS_AUDIO);
2183 LeaveCriticalSection(&engine->cs);
2185 return value;
2188 static HRESULT WINAPI media_engine_GetNativeVideoSize(IMFMediaEngineEx *iface, DWORD *cx, DWORD *cy)
2190 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2191 HRESULT hr = S_OK;
2193 TRACE("%p, %p, %p.\n", iface, cx, cy);
2195 if (!cx && !cy)
2196 return E_INVALIDARG;
2198 EnterCriticalSection(&engine->cs);
2200 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2201 hr = MF_E_SHUTDOWN;
2202 else if (!engine->video_frame.size.cx && !engine->video_frame.size.cy)
2203 hr = E_FAIL;
2204 else
2206 if (cx) *cx = engine->video_frame.size.cx;
2207 if (cy) *cy = engine->video_frame.size.cy;
2210 LeaveCriticalSection(&engine->cs);
2212 return hr;
2215 static HRESULT WINAPI media_engine_GetVideoAspectRatio(IMFMediaEngineEx *iface, DWORD *cx, DWORD *cy)
2217 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2218 HRESULT hr = S_OK;
2220 TRACE("%p, %p, %p.\n", iface, cx, cy);
2222 if (!cx && !cy)
2223 return E_INVALIDARG;
2225 EnterCriticalSection(&engine->cs);
2227 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2228 hr = MF_E_SHUTDOWN;
2229 else if (!engine->video_frame.size.cx && !engine->video_frame.size.cy)
2230 hr = E_FAIL;
2231 else
2233 if (cx) *cx = engine->video_frame.ratio.cx;
2234 if (cy) *cy = engine->video_frame.ratio.cy;
2237 LeaveCriticalSection(&engine->cs);
2239 return hr;
2242 static HRESULT WINAPI media_engine_Shutdown(IMFMediaEngineEx *iface)
2244 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2245 HRESULT hr = S_OK;
2247 TRACE("%p.\n", iface);
2249 EnterCriticalSection(&engine->cs);
2250 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2251 hr = MF_E_SHUTDOWN;
2252 else
2254 media_engine_set_flag(engine, FLAGS_ENGINE_SHUT_DOWN, TRUE);
2255 media_engine_clear_presentation(engine);
2256 IMFMediaSession_Shutdown(engine->session);
2258 LeaveCriticalSection(&engine->cs);
2260 return hr;
2263 static void set_rect(struct rect *rect, float left, float top, float right, float bottom)
2265 rect->left = left;
2266 rect->top = top;
2267 rect->right = right;
2268 rect->bottom = bottom;
2271 static void media_engine_adjust_destination_for_ratio(const struct media_engine *engine,
2272 struct rect *src_n, struct rect *dst)
2274 float dst_width = dst->right - dst->left, dst_height = dst->bottom - dst->top;
2275 D3D11_TEXTURE2D_DESC source_desc;
2276 float src_width, src_height;
2277 struct rect src;
2279 ID3D11Texture2D_GetDesc(engine->video_frame.d3d11.source, &source_desc);
2280 set_rect(&src, src_n->left * source_desc.Width, src_n->top * source_desc.Height,
2281 src_n->right * source_desc.Width, src_n->bottom * source_desc.Height);
2283 src_width = src.right - src.left;
2284 src_height = src.bottom - src.top;
2286 if (src_width * dst_height > dst_width * src_height)
2288 /* src is "wider" than dst. */
2289 float dst_center = (dst->top + dst->bottom) / 2.0f;
2290 float scaled_height = src_height * dst_width / src_width;
2292 dst->top = dst_center - scaled_height / 2.0f;
2293 dst->bottom = dst->top + scaled_height;
2295 else if (src_width * dst_height < dst_width * src_height)
2297 /* src is "taller" than dst. */
2298 float dst_center = (dst->left + dst->right) / 2.0f;
2299 float scaled_width = src_width * dst_height / src_height;
2301 dst->left = dst_center - scaled_width / 2.0f;
2302 dst->right = dst->left + scaled_width;
2306 static void media_engine_update_d3d11_frame_surface(ID3D11DeviceContext *context, struct media_engine *engine)
2308 D3D11_TEXTURE2D_DESC surface_desc;
2310 if (!(engine->flags & FLAGS_ENGINE_NEW_FRAME))
2311 return;
2313 ID3D11Texture2D_GetDesc(engine->video_frame.d3d11.source, &surface_desc);
2315 switch (surface_desc.Format)
2317 case DXGI_FORMAT_B8G8R8A8_UNORM:
2318 case DXGI_FORMAT_B8G8R8X8_UNORM:
2319 surface_desc.Width *= 4;
2320 break;
2321 default:
2322 FIXME("Unsupported format %#x.\n", surface_desc.Format);
2323 surface_desc.Width = 0;
2326 if (engine->video_frame.buffer_size == surface_desc.Width * surface_desc.Height)
2328 ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)engine->video_frame.d3d11.source,
2329 0, NULL, engine->video_frame.buffer, surface_desc.Width, 0);
2332 media_engine_set_flag(engine, FLAGS_ENGINE_NEW_FRAME, FALSE);
2335 static HRESULT media_engine_transfer_to_d3d11_texture(struct media_engine *engine, ID3D11Texture2D *texture,
2336 const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color)
2338 static const float black[] = {0.0f, 0.0f, 0.0f, 0.0f};
2339 ID3D11Device *device, *dst_device;
2340 ID3D11DeviceContext *context;
2341 ID3D11RenderTargetView *rtv;
2342 unsigned int stride, offset;
2343 D3D11_TEXTURE2D_DESC desc;
2344 BOOL device_mismatch;
2345 struct vec3 quad[4];
2346 D3D11_VIEWPORT vp;
2347 struct rect src, dst;
2348 struct color backcolor;
2349 HRESULT hr;
2350 RECT rect;
2352 if (FAILED(hr = media_engine_lock_d3d_device(engine, &device)))
2353 return hr;
2355 if (FAILED(hr = media_engine_create_d3d11_video_frame_resources(engine, device)))
2357 WARN("Failed to create d3d resources, hr %#lx.\n", hr);
2358 goto done;
2361 ID3D11Texture2D_GetDevice(texture, &dst_device);
2362 device_mismatch = device != dst_device;
2363 ID3D11Device_Release(dst_device);
2365 if (device_mismatch)
2367 WARN("Destination target from different device.\n");
2368 hr = E_UNEXPECTED;
2369 goto done;
2372 ID3D11Texture2D_GetDesc(texture, &desc);
2374 if (FAILED(hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)texture, NULL, &rtv)))
2376 WARN("Failed to create an rtv, hr %#lx.\n", hr);
2377 goto done;
2380 ID3D11Device_GetImmediateContext(device, &context);
2382 /* Whole destination is cleared, regardless of specified rectangle. */
2383 ID3D11DeviceContext_ClearRenderTargetView(context, rtv, black);
2385 if (dst_rect)
2387 rect.left = max(0, dst_rect->left);
2388 rect.top = max(0, dst_rect->top);
2389 rect.right = min(desc.Width, dst_rect->right);
2390 rect.bottom = min(desc.Height, dst_rect->bottom);
2392 quad[0].x = 2.0f * rect.left / desc.Width - 1.0f;
2393 quad[0].y = -2.0f * rect.bottom / desc.Height + 1.0f;
2394 quad[0].z = 0.0f;
2396 quad[1].x = quad[0].x;
2397 quad[1].y = -2.0f * rect.top / desc.Height + 1.0f;
2398 quad[1].z = 0.0f;
2400 quad[2].x = 2.0f * rect.right / desc.Width - 1.0f;
2401 quad[2].y = quad[0].y;
2402 quad[2].z = 0.0f;
2404 quad[3].x = quad[2].x;
2405 quad[3].y = quad[1].y;
2406 quad[3].z = 0.0f;
2408 set_rect(&dst, dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom);
2410 else
2412 memcpy(quad, fullquad, sizeof(quad));
2413 set_rect(&dst, 0.0f, 0.0f, desc.Width, desc.Height);
2416 if (src_rect)
2417 memcpy(&src, src_rect, sizeof(src));
2418 else
2419 set_rect(&src, 0.0f, 0.0f, 1.0f, 1.0f);
2421 media_engine_adjust_destination_for_ratio(engine, &src, &dst);
2423 if (memcmp(quad, engine->video_frame.d3d11.quad, sizeof(quad)))
2425 memcpy(engine->video_frame.d3d11.quad, quad, sizeof(quad));
2426 ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)engine->video_frame.d3d11.vb, 0, NULL, quad, 0, 0);
2429 if (color)
2431 backcolor.r = color->rgbRed / 255.0f;
2432 backcolor.g = color->rgbGreen / 255.0f;
2433 backcolor.b = color->rgbBlue / 255.0f;
2434 backcolor.a = color->rgbAlpha / 255.0f;
2436 else
2437 memcpy(&backcolor, black, sizeof(backcolor));
2439 if (memcmp(&dst, &engine->video_frame.d3d11.cb.dst, sizeof(dst)) ||
2440 memcmp(&src, &engine->video_frame.d3d11.cb.src, sizeof(src)) ||
2441 memcmp(&backcolor, &engine->video_frame.d3d11.cb.backcolor, sizeof(backcolor)))
2443 memcpy(&engine->video_frame.d3d11.cb.dst, &dst, sizeof(dst));
2444 memcpy(&engine->video_frame.d3d11.cb.src, &src, sizeof(src));
2445 memcpy(&engine->video_frame.d3d11.cb.backcolor, &backcolor, sizeof(backcolor));
2447 ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)engine->video_frame.d3d11.ps_cb, 0, NULL,
2448 &engine->video_frame.d3d11.cb, 0, 0);
2451 /* Update with new frame contents */
2452 media_engine_update_d3d11_frame_surface(context, engine);
2454 vp.TopLeftX = 0.0f;
2455 vp.TopLeftY = 0.0f;
2456 vp.Width = desc.Width;
2457 vp.Height = desc.Height;
2458 vp.MinDepth = 0.0f;
2459 vp.MaxDepth = 1.0f;
2460 ID3D11DeviceContext_RSSetViewports(context, 1, &vp);
2462 ID3D11DeviceContext_IASetInputLayout(context, engine->video_frame.d3d11.input_layout);
2463 ID3D11DeviceContext_IASetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
2464 stride = sizeof(*quad);
2465 offset = 0;
2466 ID3D11DeviceContext_IASetVertexBuffers(context, 0, 1, &engine->video_frame.d3d11.vb, &stride, &offset);
2467 ID3D11DeviceContext_VSSetShader(context, engine->video_frame.d3d11.vs, NULL, 0);
2468 ID3D11DeviceContext_PSSetShader(context, engine->video_frame.d3d11.ps, NULL, 0);
2469 ID3D11DeviceContext_PSSetShaderResources(context, 0, 1, &engine->video_frame.d3d11.srv);
2470 ID3D11DeviceContext_PSSetConstantBuffers(context, 0, 1, &engine->video_frame.d3d11.ps_cb);
2471 ID3D11DeviceContext_PSSetSamplers(context, 0, 1, &engine->video_frame.d3d11.sampler);
2472 ID3D11DeviceContext_OMSetRenderTargets(context, 1, &rtv, NULL);
2474 ID3D11DeviceContext_Draw(context, 4, 0);
2476 ID3D11RenderTargetView_Release(rtv);
2477 ID3D11DeviceContext_Release(context);
2479 done:
2480 media_engine_unlock_d3d_device(engine, device);
2482 return hr;
2485 static HRESULT WINAPI media_engine_TransferVideoFrame(IMFMediaEngineEx *iface, IUnknown *surface,
2486 const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color)
2488 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2489 ID3D11Texture2D *texture;
2490 HRESULT hr = E_NOINTERFACE;
2492 TRACE("%p, %p, %s, %s, %p.\n", iface, surface, src_rect ? wine_dbg_sprintf("(%f,%f)-(%f,%f)",
2493 src_rect->left, src_rect->top, src_rect->right, src_rect->bottom) : "(null)",
2494 wine_dbgstr_rect(dst_rect), color);
2496 EnterCriticalSection(&engine->cs);
2498 if (SUCCEEDED(IUnknown_QueryInterface(surface, &IID_ID3D11Texture2D, (void **)&texture)))
2500 hr = media_engine_transfer_to_d3d11_texture(engine, texture, src_rect, dst_rect, color);
2501 ID3D11Texture2D_Release(texture);
2503 else
2505 FIXME("Unsupported destination type.\n");
2508 LeaveCriticalSection(&engine->cs);
2510 return hr;
2513 static HRESULT WINAPI media_engine_OnVideoStreamTick(IMFMediaEngineEx *iface, LONGLONG *pts)
2515 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2516 HRESULT hr;
2518 TRACE("%p, %p.\n", iface, pts);
2520 EnterCriticalSection(&engine->cs);
2522 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2523 hr = MF_E_SHUTDOWN;
2524 else if (!pts)
2525 hr = E_POINTER;
2526 else
2528 *pts = engine->video_frame.pts;
2529 hr = *pts == MINLONGLONG ? S_FALSE : S_OK;
2532 LeaveCriticalSection(&engine->cs);
2534 return hr;
2537 static HRESULT WINAPI media_engine_SetSourceFromByteStream(IMFMediaEngineEx *iface, IMFByteStream *bytestream, BSTR url)
2539 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2540 HRESULT hr;
2542 TRACE("%p, %p, %s.\n", iface, bytestream, debugstr_w(url));
2544 EnterCriticalSection(&engine->cs);
2546 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2547 hr = MF_E_SHUTDOWN;
2548 else if (!bytestream || !url)
2549 hr = E_POINTER;
2550 else
2551 hr = media_engine_set_source(engine, bytestream, url);
2553 LeaveCriticalSection(&engine->cs);
2555 return hr;
2558 static HRESULT WINAPI media_engine_GetStatistics(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_STATISTIC stat_id, PROPVARIANT *stat)
2560 FIXME("%p, %x, %p stub.\n", iface, stat_id, stat);
2562 return E_NOTIMPL;
2565 static HRESULT WINAPI media_engine_UpdateVideoStream(IMFMediaEngineEx *iface, const MFVideoNormalizedRect *src,
2566 const RECT *dst, const MFARGB *border_color)
2568 FIXME("%p, %p, %p, %p stub.\n", iface, src, dst, border_color);
2570 return E_NOTIMPL;
2573 static double WINAPI media_engine_GetBalance(IMFMediaEngineEx *iface)
2575 FIXME("%p stub.\n", iface);
2577 return 0.0;
2580 static HRESULT WINAPI media_engine_SetBalance(IMFMediaEngineEx *iface, double balance)
2582 FIXME("%p, %f stub.\n", iface, balance);
2584 return E_NOTIMPL;
2587 static BOOL WINAPI media_engine_IsPlaybackRateSupported(IMFMediaEngineEx *iface, double rate)
2589 FIXME("%p, %f stub.\n", iface, rate);
2591 return FALSE;
2594 static HRESULT WINAPI media_engine_FrameStep(IMFMediaEngineEx *iface, BOOL forward)
2596 FIXME("%p, %d stub.\n", iface, forward);
2598 return E_NOTIMPL;
2601 static HRESULT WINAPI media_engine_GetResourceCharacteristics(IMFMediaEngineEx *iface, DWORD *flags)
2603 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2604 HRESULT hr = E_FAIL;
2606 TRACE("%p, %p.\n", iface, flags);
2608 EnterCriticalSection(&engine->cs);
2609 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2611 hr = MF_E_SHUTDOWN;
2613 else if (engine->presentation.source && flags)
2615 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(engine->presentation.source, flags)))
2617 *flags = *flags & 0xf;
2618 hr = S_OK;
2621 LeaveCriticalSection(&engine->cs);
2623 return hr;
2626 static HRESULT WINAPI media_engine_GetPresentationAttribute(IMFMediaEngineEx *iface, REFGUID attribute,
2627 PROPVARIANT *value)
2629 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2630 HRESULT hr = E_FAIL;
2632 TRACE("%p, %s, %p.\n", iface, debugstr_guid(attribute), value);
2634 EnterCriticalSection(&engine->cs);
2635 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2636 hr = MF_E_SHUTDOWN;
2637 else if (engine->presentation.pd)
2638 hr = IMFPresentationDescriptor_GetItem(engine->presentation.pd, attribute, value);
2639 LeaveCriticalSection(&engine->cs);
2641 return hr;
2644 static HRESULT WINAPI media_engine_GetNumberOfStreams(IMFMediaEngineEx *iface, DWORD *stream_count)
2646 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2647 HRESULT hr = E_FAIL;
2649 TRACE("%p, %p.\n", iface, stream_count);
2651 EnterCriticalSection(&engine->cs);
2652 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2653 hr = MF_E_SHUTDOWN;
2654 else if (engine->presentation.pd)
2655 hr = IMFPresentationDescriptor_GetStreamDescriptorCount(engine->presentation.pd, stream_count);
2656 LeaveCriticalSection(&engine->cs);
2658 return hr;
2661 static HRESULT WINAPI media_engine_GetStreamAttribute(IMFMediaEngineEx *iface, DWORD stream_index, REFGUID attribute,
2662 PROPVARIANT *value)
2664 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2665 IMFStreamDescriptor *sd;
2666 HRESULT hr = E_FAIL;
2667 BOOL selected;
2669 TRACE("%p, %ld, %s, %p.\n", iface, stream_index, debugstr_guid(attribute), value);
2671 EnterCriticalSection(&engine->cs);
2672 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2673 hr = MF_E_SHUTDOWN;
2674 else if (engine->presentation.pd)
2676 if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(engine->presentation.pd,
2677 stream_index, &selected, &sd)))
2679 hr = IMFStreamDescriptor_GetItem(sd, attribute, value);
2680 IMFStreamDescriptor_Release(sd);
2683 LeaveCriticalSection(&engine->cs);
2685 return hr;
2688 static HRESULT WINAPI media_engine_GetStreamSelection(IMFMediaEngineEx *iface, DWORD stream_index, BOOL *enabled)
2690 FIXME("%p, %ld, %p stub.\n", iface, stream_index, enabled);
2692 return E_NOTIMPL;
2695 static HRESULT WINAPI media_engine_SetStreamSelection(IMFMediaEngineEx *iface, DWORD stream_index, BOOL enabled)
2697 FIXME("%p, %ld, %d stub.\n", iface, stream_index, enabled);
2699 return E_NOTIMPL;
2702 static HRESULT WINAPI media_engine_ApplyStreamSelections(IMFMediaEngineEx *iface)
2704 FIXME("%p stub.\n", iface);
2706 return E_NOTIMPL;
2709 static HRESULT WINAPI media_engine_IsProtected(IMFMediaEngineEx *iface, BOOL *protected)
2711 FIXME("%p, %p stub.\n", iface, protected);
2713 return E_NOTIMPL;
2716 static HRESULT media_engine_insert_effect(struct media_engine *engine, struct effects *effects, IUnknown *object, BOOL is_optional)
2718 HRESULT hr = S_OK;
2720 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2721 hr = MF_E_SHUTDOWN;
2722 else if (!mf_array_reserve((void **)&effects->effects, &effects->capacity, effects->count + 1, sizeof(*effects->effects)))
2724 hr = E_OUTOFMEMORY;
2726 else
2728 effects->effects[effects->count].object = object;
2729 if (object)
2731 IUnknown_AddRef(effects->effects[effects->count].object);
2733 effects->effects[effects->count].optional = is_optional;
2735 effects->count++;
2738 return hr;
2741 static HRESULT WINAPI media_engine_InsertVideoEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional)
2743 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2744 HRESULT hr = S_OK;
2746 TRACE("%p, %p, %d.\n", iface, effect, is_optional);
2748 EnterCriticalSection(&engine->cs);
2749 hr = media_engine_insert_effect(engine, &engine->video_effects, effect, is_optional);
2750 LeaveCriticalSection(&engine->cs);
2752 return hr;
2755 static HRESULT WINAPI media_engine_InsertAudioEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional)
2757 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2758 HRESULT hr = S_OK;
2760 TRACE("%p, %p, %d.\n", iface, effect, is_optional);
2762 EnterCriticalSection(&engine->cs);
2763 hr = media_engine_insert_effect(engine, &engine->audio_effects, effect, is_optional);
2764 LeaveCriticalSection(&engine->cs);
2766 return hr;
2769 static HRESULT WINAPI media_engine_RemoveAllEffects(IMFMediaEngineEx *iface)
2771 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2772 HRESULT hr = S_OK;
2774 TRACE("%p.\n", iface);
2776 EnterCriticalSection(&engine->cs);
2777 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2778 hr = MF_E_SHUTDOWN;
2779 else
2781 media_engine_clear_effects(&engine->audio_effects);
2782 media_engine_clear_effects(&engine->video_effects);
2784 LeaveCriticalSection(&engine->cs);
2786 return hr;
2789 static HRESULT WINAPI media_engine_SetTimelineMarkerTimer(IMFMediaEngineEx *iface, double timeout)
2791 FIXME("%p, %f stub.\n", iface, timeout);
2793 return E_NOTIMPL;
2796 static HRESULT WINAPI media_engine_GetTimelineMarkerTimer(IMFMediaEngineEx *iface, double *timeout)
2798 FIXME("%p, %p stub.\n", iface, timeout);
2800 return E_NOTIMPL;
2803 static HRESULT WINAPI media_engine_CancelTimelineMarkerTimer(IMFMediaEngineEx *iface)
2805 FIXME("%p stub.\n", iface);
2807 return E_NOTIMPL;
2810 static BOOL WINAPI media_engine_IsStereo3D(IMFMediaEngineEx *iface)
2812 FIXME("%p stub.\n", iface);
2814 return FALSE;
2817 static HRESULT WINAPI media_engine_GetStereo3DFramePackingMode(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_S3D_PACKING_MODE *mode)
2819 FIXME("%p, %p stub.\n", iface, mode);
2821 return E_NOTIMPL;
2824 static HRESULT WINAPI media_engine_SetStereo3DFramePackingMode(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_S3D_PACKING_MODE mode)
2826 FIXME("%p, %#x stub.\n", iface, mode);
2828 return E_NOTIMPL;
2831 static HRESULT WINAPI media_engine_GetStereo3DRenderMode(IMFMediaEngineEx *iface, MF3DVideoOutputType *output_type)
2833 FIXME("%p, %p stub.\n", iface, output_type);
2835 return E_NOTIMPL;
2838 static HRESULT WINAPI media_engine_SetStereo3DRenderMode(IMFMediaEngineEx *iface, MF3DVideoOutputType output_type)
2840 FIXME("%p, %#x stub.\n", iface, output_type);
2842 return E_NOTIMPL;
2845 static HRESULT WINAPI media_engine_EnableWindowlessSwapchainMode(IMFMediaEngineEx *iface, BOOL enable)
2847 FIXME("%p, %d stub.\n", iface, enable);
2849 return E_NOTIMPL;
2852 static HRESULT WINAPI media_engine_GetVideoSwapchainHandle(IMFMediaEngineEx *iface, HANDLE *swapchain)
2854 FIXME("%p, %p stub.\n", iface, swapchain);
2856 return E_NOTIMPL;
2859 static HRESULT WINAPI media_engine_EnableHorizontalMirrorMode(IMFMediaEngineEx *iface, BOOL enable)
2861 FIXME("%p, %d stub.\n", iface, enable);
2863 return E_NOTIMPL;
2866 static HRESULT WINAPI media_engine_GetAudioStreamCategory(IMFMediaEngineEx *iface, UINT32 *category)
2868 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2869 HRESULT hr;
2871 TRACE("%p, %p.\n", iface, category);
2873 EnterCriticalSection(&engine->cs);
2875 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2876 hr = MF_E_SHUTDOWN;
2877 else
2878 hr = IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, category);
2880 LeaveCriticalSection(&engine->cs);
2882 return hr;
2885 static HRESULT WINAPI media_engine_SetAudioStreamCategory(IMFMediaEngineEx *iface, UINT32 category)
2887 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2888 HRESULT hr;
2890 TRACE("%p, %u.\n", iface, category);
2892 EnterCriticalSection(&engine->cs);
2894 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2895 hr = MF_E_SHUTDOWN;
2896 else
2897 hr = IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, category);
2899 LeaveCriticalSection(&engine->cs);
2901 return hr;
2904 static HRESULT WINAPI media_engine_GetAudioEndpointRole(IMFMediaEngineEx *iface, UINT32 *role)
2906 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2907 HRESULT hr;
2909 TRACE("%p, %p.\n", iface, role);
2911 EnterCriticalSection(&engine->cs);
2913 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2914 hr = MF_E_SHUTDOWN;
2915 else
2916 hr = IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, role);
2918 LeaveCriticalSection(&engine->cs);
2920 return hr;
2923 static HRESULT WINAPI media_engine_SetAudioEndpointRole(IMFMediaEngineEx *iface, UINT32 role)
2925 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2926 HRESULT hr;
2928 TRACE("%p, %u.\n", iface, role);
2930 EnterCriticalSection(&engine->cs);
2932 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2933 hr = MF_E_SHUTDOWN;
2934 else
2935 hr = IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, role);
2937 LeaveCriticalSection(&engine->cs);
2939 return hr;
2942 static HRESULT WINAPI media_engine_GetRealTimeMode(IMFMediaEngineEx *iface, BOOL *enabled)
2944 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2945 HRESULT hr = S_OK;
2947 TRACE("%p, %p.\n", iface, enabled);
2949 EnterCriticalSection(&engine->cs);
2950 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2951 hr = MF_E_SHUTDOWN;
2952 else
2953 *enabled = !!(engine->flags & MF_MEDIA_ENGINE_REAL_TIME_MODE);
2954 LeaveCriticalSection(&engine->cs);
2956 return hr;
2959 static HRESULT WINAPI media_engine_SetRealTimeMode(IMFMediaEngineEx *iface, BOOL enable)
2961 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2962 HRESULT hr = S_OK;
2964 TRACE("%p, %d.\n", iface, enable);
2966 EnterCriticalSection(&engine->cs);
2967 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2968 hr = MF_E_SHUTDOWN;
2969 else
2970 media_engine_set_flag(engine, MF_MEDIA_ENGINE_REAL_TIME_MODE, enable);
2971 LeaveCriticalSection(&engine->cs);
2973 return hr;
2976 static HRESULT WINAPI media_engine_SetCurrentTimeEx(IMFMediaEngineEx *iface, double seektime, MF_MEDIA_ENGINE_SEEK_MODE mode)
2978 FIXME("%p, %f, %#x stub.\n", iface, seektime, mode);
2980 return E_NOTIMPL;
2983 static HRESULT WINAPI media_engine_EnableTimeUpdateTimer(IMFMediaEngineEx *iface, BOOL enable)
2985 FIXME("%p, %d stub.\n", iface, enable);
2987 return E_NOTIMPL;
2990 static const IMFMediaEngineExVtbl media_engine_vtbl =
2992 media_engine_QueryInterface,
2993 media_engine_AddRef,
2994 media_engine_Release,
2995 media_engine_GetError,
2996 media_engine_SetErrorCode,
2997 media_engine_SetSourceElements,
2998 media_engine_SetSource,
2999 media_engine_GetCurrentSource,
3000 media_engine_GetNetworkState,
3001 media_engine_GetPreload,
3002 media_engine_SetPreload,
3003 media_engine_GetBuffered,
3004 media_engine_Load,
3005 media_engine_CanPlayType,
3006 media_engine_GetReadyState,
3007 media_engine_IsSeeking,
3008 media_engine_GetCurrentTime,
3009 media_engine_SetCurrentTime,
3010 media_engine_GetStartTime,
3011 media_engine_GetDuration,
3012 media_engine_IsPaused,
3013 media_engine_GetDefaultPlaybackRate,
3014 media_engine_SetDefaultPlaybackRate,
3015 media_engine_GetPlaybackRate,
3016 media_engine_SetPlaybackRate,
3017 media_engine_GetPlayed,
3018 media_engine_GetSeekable,
3019 media_engine_IsEnded,
3020 media_engine_GetAutoPlay,
3021 media_engine_SetAutoPlay,
3022 media_engine_GetLoop,
3023 media_engine_SetLoop,
3024 media_engine_Play,
3025 media_engine_Pause,
3026 media_engine_GetMuted,
3027 media_engine_SetMuted,
3028 media_engine_GetVolume,
3029 media_engine_SetVolume,
3030 media_engine_HasVideo,
3031 media_engine_HasAudio,
3032 media_engine_GetNativeVideoSize,
3033 media_engine_GetVideoAspectRatio,
3034 media_engine_Shutdown,
3035 media_engine_TransferVideoFrame,
3036 media_engine_OnVideoStreamTick,
3037 media_engine_SetSourceFromByteStream,
3038 media_engine_GetStatistics,
3039 media_engine_UpdateVideoStream,
3040 media_engine_GetBalance,
3041 media_engine_SetBalance,
3042 media_engine_IsPlaybackRateSupported,
3043 media_engine_FrameStep,
3044 media_engine_GetResourceCharacteristics,
3045 media_engine_GetPresentationAttribute,
3046 media_engine_GetNumberOfStreams,
3047 media_engine_GetStreamAttribute,
3048 media_engine_GetStreamSelection,
3049 media_engine_SetStreamSelection,
3050 media_engine_ApplyStreamSelections,
3051 media_engine_IsProtected,
3052 media_engine_InsertVideoEffect,
3053 media_engine_InsertAudioEffect,
3054 media_engine_RemoveAllEffects,
3055 media_engine_SetTimelineMarkerTimer,
3056 media_engine_GetTimelineMarkerTimer,
3057 media_engine_CancelTimelineMarkerTimer,
3058 media_engine_IsStereo3D,
3059 media_engine_GetStereo3DFramePackingMode,
3060 media_engine_SetStereo3DFramePackingMode,
3061 media_engine_GetStereo3DRenderMode,
3062 media_engine_SetStereo3DRenderMode,
3063 media_engine_EnableWindowlessSwapchainMode,
3064 media_engine_GetVideoSwapchainHandle,
3065 media_engine_EnableHorizontalMirrorMode,
3066 media_engine_GetAudioStreamCategory,
3067 media_engine_SetAudioStreamCategory,
3068 media_engine_GetAudioEndpointRole,
3069 media_engine_SetAudioEndpointRole,
3070 media_engine_GetRealTimeMode,
3071 media_engine_SetRealTimeMode,
3072 media_engine_SetCurrentTimeEx,
3073 media_engine_EnableTimeUpdateTimer,
3076 static HRESULT WINAPI media_engine_gs_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
3078 struct media_engine *engine = impl_from_IMFGetService(iface);
3079 return IMFMediaEngineEx_QueryInterface(&engine->IMFMediaEngineEx_iface, riid, obj);
3082 static ULONG WINAPI media_engine_gs_AddRef(IMFGetService *iface)
3084 struct media_engine *engine = impl_from_IMFGetService(iface);
3085 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
3088 static ULONG WINAPI media_engine_gs_Release(IMFGetService *iface)
3090 struct media_engine *engine = impl_from_IMFGetService(iface);
3091 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
3094 static HRESULT WINAPI media_engine_gs_GetService(IMFGetService *iface, REFGUID service,
3095 REFIID riid, void **object)
3097 FIXME("%p, %s, %s, %p stub.\n", iface, debugstr_guid(service), debugstr_guid(riid), object);
3099 return E_NOTIMPL;
3102 static const IMFGetServiceVtbl media_engine_get_service_vtbl =
3104 media_engine_gs_QueryInterface,
3105 media_engine_gs_AddRef,
3106 media_engine_gs_Release,
3107 media_engine_gs_GetService,
3110 static HRESULT WINAPI media_engine_grabber_callback_QueryInterface(IMFSampleGrabberSinkCallback *iface,
3111 REFIID riid, void **obj)
3113 if (IsEqualIID(riid, &IID_IMFSampleGrabberSinkCallback) ||
3114 IsEqualIID(riid, &IID_IUnknown))
3116 *obj = iface;
3117 IMFSampleGrabberSinkCallback_AddRef(iface);
3118 return S_OK;
3121 *obj = NULL;
3122 return E_NOINTERFACE;
3125 static ULONG WINAPI media_engine_grabber_callback_AddRef(IMFSampleGrabberSinkCallback *iface)
3127 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
3128 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
3131 static ULONG WINAPI media_engine_grabber_callback_Release(IMFSampleGrabberSinkCallback *iface)
3133 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
3134 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
3137 static HRESULT WINAPI media_engine_grabber_callback_OnClockStart(IMFSampleGrabberSinkCallback *iface,
3138 MFTIME systime, LONGLONG start_offset)
3140 return S_OK;
3143 static HRESULT WINAPI media_engine_grabber_callback_OnClockStop(IMFSampleGrabberSinkCallback *iface,
3144 MFTIME systime)
3146 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
3148 EnterCriticalSection(&engine->cs);
3149 media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, FALSE);
3150 engine->video_frame.pts = MINLONGLONG;
3151 LeaveCriticalSection(&engine->cs);
3153 return S_OK;
3156 static HRESULT WINAPI media_engine_grabber_callback_OnClockPause(IMFSampleGrabberSinkCallback *iface,
3157 MFTIME systime)
3159 return S_OK;
3162 static HRESULT WINAPI media_engine_grabber_callback_OnClockRestart(IMFSampleGrabberSinkCallback *iface,
3163 MFTIME systime)
3165 return S_OK;
3168 static HRESULT WINAPI media_engine_grabber_callback_OnClockSetRate(IMFSampleGrabberSinkCallback *iface,
3169 MFTIME systime, float rate)
3171 return S_OK;
3174 static HRESULT WINAPI media_engine_grabber_callback_OnSetPresentationClock(IMFSampleGrabberSinkCallback *iface,
3175 IMFPresentationClock *clock)
3177 return S_OK;
3180 static HRESULT WINAPI media_engine_grabber_callback_OnProcessSample(IMFSampleGrabberSinkCallback *iface,
3181 REFGUID major_type, DWORD sample_flags, LONGLONG sample_time, LONGLONG sample_duration,
3182 const BYTE *buffer, DWORD buffer_size)
3184 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
3186 EnterCriticalSection(&engine->cs);
3188 if (!(engine->flags & FLAGS_ENGINE_FIRST_FRAME))
3190 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY, 0, 0);
3191 media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, TRUE);
3193 engine->video_frame.pts = sample_time;
3194 if (engine->video_frame.buffer_size < buffer_size)
3196 free(engine->video_frame.buffer);
3197 if ((engine->video_frame.buffer = malloc(buffer_size)))
3198 engine->video_frame.buffer_size = buffer_size;
3200 if (engine->video_frame.buffer)
3202 memcpy(engine->video_frame.buffer, buffer, buffer_size);
3203 engine->flags |= FLAGS_ENGINE_NEW_FRAME;
3206 LeaveCriticalSection(&engine->cs);
3208 return S_OK;
3211 static HRESULT WINAPI media_engine_grabber_callback_OnShutdown(IMFSampleGrabberSinkCallback *iface)
3213 return S_OK;
3216 static const IMFSampleGrabberSinkCallbackVtbl media_engine_grabber_callback_vtbl =
3218 media_engine_grabber_callback_QueryInterface,
3219 media_engine_grabber_callback_AddRef,
3220 media_engine_grabber_callback_Release,
3221 media_engine_grabber_callback_OnClockStart,
3222 media_engine_grabber_callback_OnClockStop,
3223 media_engine_grabber_callback_OnClockPause,
3224 media_engine_grabber_callback_OnClockRestart,
3225 media_engine_grabber_callback_OnClockSetRate,
3226 media_engine_grabber_callback_OnSetPresentationClock,
3227 media_engine_grabber_callback_OnProcessSample,
3228 media_engine_grabber_callback_OnShutdown,
3231 static HRESULT WINAPI media_engine_factory_QueryInterface(IMFMediaEngineClassFactory *iface, REFIID riid, void **obj)
3233 if (IsEqualIID(riid, &IID_IMFMediaEngineClassFactory) ||
3234 IsEqualIID(riid, &IID_IUnknown))
3236 *obj = iface;
3237 IMFMediaEngineClassFactory_AddRef(iface);
3238 return S_OK;
3241 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
3242 *obj = NULL;
3243 return E_NOINTERFACE;
3246 static ULONG WINAPI media_engine_factory_AddRef(IMFMediaEngineClassFactory *iface)
3248 return 2;
3251 static ULONG WINAPI media_engine_factory_Release(IMFMediaEngineClassFactory *iface)
3253 return 1;
3256 static HRESULT init_media_engine(DWORD flags, IMFAttributes *attributes, struct media_engine *engine)
3258 UINT32 output_format;
3259 UINT64 playback_hwnd;
3260 IMFClock *clock;
3261 HRESULT hr;
3263 engine->IMFMediaEngineEx_iface.lpVtbl = &media_engine_vtbl;
3264 engine->IMFGetService_iface.lpVtbl = &media_engine_get_service_vtbl;
3265 engine->session_events.lpVtbl = &media_engine_session_events_vtbl;
3266 engine->load_handler.lpVtbl = &media_engine_load_handler_vtbl;
3267 engine->grabber_callback.lpVtbl = &media_engine_grabber_callback_vtbl;
3268 engine->refcount = 1;
3269 engine->flags = (flags & MF_MEDIA_ENGINE_CREATEFLAGS_MASK) | FLAGS_ENGINE_PAUSED;
3270 engine->default_playback_rate = 1.0;
3271 engine->playback_rate = 1.0;
3272 engine->volume = 1.0;
3273 engine->duration = NAN;
3274 engine->video_frame.pts = MINLONGLONG;
3275 InitializeCriticalSection(&engine->cs);
3277 if (FAILED(hr = IMFAttributes_GetUnknown(attributes, &MF_MEDIA_ENGINE_CALLBACK, &IID_IMFMediaEngineNotify,
3278 (void **)&engine->callback)))
3280 WARN("Notification callback was not provided.\n");
3281 return hr;
3284 IMFAttributes_GetUnknown(attributes, &MF_MEDIA_ENGINE_EXTENSION, &IID_IMFMediaEngineExtension,
3285 (void **)&engine->extension);
3287 IMFAttributes_GetUnknown(attributes, &MF_MEDIA_ENGINE_DXGI_MANAGER, &IID_IMFDXGIDeviceManager,
3288 (void **)&engine->device_manager);
3290 if (FAILED(hr = MFCreateMediaSession(NULL, &engine->session)))
3291 return hr;
3293 if (FAILED(hr = IMFMediaSession_GetClock(engine->session, &clock)))
3294 return hr;
3296 hr = IMFClock_QueryInterface(clock, &IID_IMFPresentationClock, (void **)&engine->clock);
3297 IMFClock_Release(clock);
3298 if (FAILED(hr))
3299 return hr;
3301 if (FAILED(hr = IMFMediaSession_BeginGetEvent(engine->session, &engine->session_events, NULL)))
3302 return hr;
3304 if (FAILED(hr = MFCreateSourceResolver(&engine->resolver)))
3305 return hr;
3307 if (FAILED(hr = MFCreateAttributes(&engine->attributes, 0)))
3308 return hr;
3310 if (FAILED(hr = IMFAttributes_CopyAllItems(attributes, engine->attributes)))
3311 return hr;
3313 /* Set default audio configuration */
3314 if (FAILED(IMFAttributes_GetItem(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, NULL)))
3315 IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, AudioCategory_Other);
3316 if (FAILED(IMFAttributes_GetItem(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, NULL)))
3317 IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, eMultimedia);
3319 IMFAttributes_GetUINT64(attributes, &MF_MEDIA_ENGINE_PLAYBACK_HWND, &playback_hwnd);
3320 hr = IMFAttributes_GetUINT32(attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, &output_format);
3321 if (playback_hwnd) /* FIXME: handle MF_MEDIA_ENGINE_PLAYBACK_VISUAL */
3322 engine->mode = MEDIA_ENGINE_RENDERING_MODE;
3323 else
3325 if (SUCCEEDED(hr))
3326 engine->mode = MEDIA_ENGINE_FRAME_SERVER_MODE;
3327 else
3328 engine->mode = MEDIA_ENGINE_AUDIO_MODE;
3331 return S_OK;
3334 static HRESULT WINAPI media_engine_factory_CreateInstance(IMFMediaEngineClassFactory *iface, DWORD flags,
3335 IMFAttributes *attributes, IMFMediaEngine **engine)
3337 struct media_engine *object;
3338 HRESULT hr;
3340 TRACE("%p, %#lx, %p, %p.\n", iface, flags, attributes, engine);
3342 if (!attributes || !engine)
3343 return E_POINTER;
3345 object = calloc(1, sizeof(*object));
3346 if (!object)
3347 return E_OUTOFMEMORY;
3349 hr = init_media_engine(flags, attributes, object);
3350 if (FAILED(hr))
3352 free_media_engine(object);
3353 return hr;
3356 *engine = (IMFMediaEngine *)&object->IMFMediaEngineEx_iface;
3358 return S_OK;
3361 static HRESULT WINAPI media_engine_factory_CreateTimeRange(IMFMediaEngineClassFactory *iface,
3362 IMFMediaTimeRange **range)
3364 TRACE("%p, %p.\n", iface, range);
3366 return create_time_range(range);
3369 static HRESULT WINAPI media_engine_factory_CreateError(IMFMediaEngineClassFactory *iface, IMFMediaError **error)
3371 TRACE("%p, %p.\n", iface, error);
3373 return create_media_error(error);
3376 static const IMFMediaEngineClassFactoryVtbl media_engine_factory_vtbl =
3378 media_engine_factory_QueryInterface,
3379 media_engine_factory_AddRef,
3380 media_engine_factory_Release,
3381 media_engine_factory_CreateInstance,
3382 media_engine_factory_CreateTimeRange,
3383 media_engine_factory_CreateError,
3386 static IMFMediaEngineClassFactory media_engine_factory = { &media_engine_factory_vtbl };
3388 static HRESULT WINAPI classfactory_QueryInterface(IClassFactory *iface, REFIID riid, void **obj)
3390 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
3392 if (IsEqualGUID(riid, &IID_IClassFactory) ||
3393 IsEqualGUID(riid, &IID_IUnknown))
3395 IClassFactory_AddRef(iface);
3396 *obj = iface;
3397 return S_OK;
3400 WARN("interface %s not implemented.\n", debugstr_guid(riid));
3401 *obj = NULL;
3402 return E_NOINTERFACE;
3405 static ULONG WINAPI classfactory_AddRef(IClassFactory *iface)
3407 return 2;
3410 static ULONG WINAPI classfactory_Release(IClassFactory *iface)
3412 return 1;
3415 static HRESULT WINAPI classfactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **obj)
3417 TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), obj);
3419 *obj = NULL;
3421 if (outer)
3422 return CLASS_E_NOAGGREGATION;
3424 return IMFMediaEngineClassFactory_QueryInterface(&media_engine_factory, riid, obj);
3427 static HRESULT WINAPI classfactory_LockServer(IClassFactory *iface, BOOL dolock)
3429 FIXME("(%d): stub.\n", dolock);
3430 return S_OK;
3433 static const IClassFactoryVtbl class_factory_vtbl =
3435 classfactory_QueryInterface,
3436 classfactory_AddRef,
3437 classfactory_Release,
3438 classfactory_CreateInstance,
3439 classfactory_LockServer,
3442 static IClassFactory classfactory = { &class_factory_vtbl };
3444 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **obj)
3446 TRACE("%s, %s, %p.\n", debugstr_guid(clsid), debugstr_guid(riid), obj);
3448 if (IsEqualGUID(clsid, &CLSID_MFMediaEngineClassFactory))
3449 return IClassFactory_QueryInterface(&classfactory, riid, obj);
3451 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
3452 *obj = NULL;
3453 return CLASS_E_CLASSNOTAVAILABLE;