include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / mfmediaengine / main.c
blob026b825a7a5a9898ac81e5afcf0300886746a868
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,
97 FLAGS_ENGINE_SEEKING = 0x40000,
100 struct vec3
102 float x, y, z;
105 struct color
107 float r, g, b, a;
110 static const struct vec3 fullquad[] =
112 {-1.0f, -1.0f, 0.0f},
113 {-1.0f, 1.0f, 0.0f},
114 { 1.0f, -1.0f, 0.0f},
115 { 1.0f, 1.0f, 0.0f},
118 struct rect
120 float left, top, right, bottom;
123 struct effect
125 IUnknown *object;
126 BOOL optional;
129 struct effects
131 struct effect *effects;
132 size_t count;
133 size_t capacity;
136 struct media_engine
138 IMFMediaEngineEx IMFMediaEngineEx_iface;
139 IMFGetService IMFGetService_iface;
140 IMFAsyncCallback session_events;
141 IMFAsyncCallback load_handler;
142 IMFSampleGrabberSinkCallback grabber_callback;
143 LONG refcount;
144 IMFMediaEngineNotify *callback;
145 IMFAttributes *attributes;
146 IMFDXGIDeviceManager *device_manager;
147 HANDLE device_handle;
148 enum media_engine_mode mode;
149 unsigned int flags;
150 double playback_rate;
151 double default_playback_rate;
152 double volume;
153 double duration;
154 MF_MEDIA_ENGINE_NETWORK network_state;
155 MF_MEDIA_ENGINE_ERR error_code;
156 HRESULT extended_code;
157 MF_MEDIA_ENGINE_READY ready_state;
158 MF_MEDIA_ENGINE_PRELOAD preload;
159 IMFMediaSession *session;
160 IMFPresentationClock *clock;
161 IMFSourceResolver *resolver;
162 IMFMediaEngineExtension *extension;
163 BSTR current_source;
164 struct
166 IMFMediaSource *source;
167 IMFPresentationDescriptor *pd;
168 PROPVARIANT start_position;
169 } presentation;
170 struct effects video_effects;
171 struct effects audio_effects;
172 struct
174 LONGLONG pts;
175 SIZE size;
176 SIZE ratio;
177 TOPOID node_id;
178 BYTE *buffer;
179 UINT buffer_size;
180 DXGI_FORMAT output_format;
182 struct
184 ID3D11Buffer *vb;
185 ID3D11Buffer *ps_cb;
186 ID3D11Texture2D *source;
187 ID3D11ShaderResourceView *srv;
188 ID3D11SamplerState *sampler;
189 ID3D11InputLayout *input_layout;
190 ID3D11VertexShader *vs;
191 ID3D11PixelShader *ps;
192 struct vec3 quad[4];
193 struct
195 struct rect dst;
196 struct rect src;
197 struct color backcolor;
198 } cb;
199 } d3d11;
200 } video_frame;
201 CRITICAL_SECTION cs;
204 static void media_engine_release_video_frame_resources(struct media_engine *engine)
206 if (engine->video_frame.d3d11.vb)
207 ID3D11Buffer_Release(engine->video_frame.d3d11.vb);
208 if (engine->video_frame.d3d11.ps_cb)
209 ID3D11Buffer_Release(engine->video_frame.d3d11.ps_cb);
210 if (engine->video_frame.d3d11.source)
211 ID3D11Texture2D_Release(engine->video_frame.d3d11.source);
212 if (engine->video_frame.d3d11.srv)
213 ID3D11ShaderResourceView_Release(engine->video_frame.d3d11.srv);
214 if (engine->video_frame.d3d11.sampler)
215 ID3D11SamplerState_Release(engine->video_frame.d3d11.sampler);
216 if (engine->video_frame.d3d11.input_layout)
217 ID3D11InputLayout_Release(engine->video_frame.d3d11.input_layout);
218 if (engine->video_frame.d3d11.vs)
219 ID3D11VertexShader_Release(engine->video_frame.d3d11.vs);
220 if (engine->video_frame.d3d11.ps)
221 ID3D11PixelShader_Release(engine->video_frame.d3d11.ps);
223 memset(&engine->video_frame.d3d11, 0, sizeof(engine->video_frame.d3d11));
224 memcpy(engine->video_frame.d3d11.quad, fullquad, sizeof(fullquad));
227 static HRESULT media_engine_lock_d3d_device(struct media_engine *engine, ID3D11Device **device)
229 HRESULT hr;
231 if (!engine->device_manager)
233 FIXME("Device manager wasn't set.\n");
234 return E_UNEXPECTED;
237 if (!engine->device_handle)
239 if (FAILED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(engine->device_manager, &engine->device_handle)))
241 WARN("Failed to open device handle, hr %#lx.\n", hr);
242 return hr;
246 hr = IMFDXGIDeviceManager_LockDevice(engine->device_manager, engine->device_handle, &IID_ID3D11Device,
247 (void **)device, TRUE);
248 if (hr == MF_E_DXGI_NEW_VIDEO_DEVICE)
250 IMFDXGIDeviceManager_CloseDeviceHandle(engine->device_manager, engine->device_handle);
251 engine->device_handle = NULL;
253 media_engine_release_video_frame_resources(engine);
255 if (FAILED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(engine->device_manager, &engine->device_handle)))
257 WARN("Failed to open a device handle, hr %#lx.\n", hr);
258 return hr;
260 hr = IMFDXGIDeviceManager_LockDevice(engine->device_manager, engine->device_handle, &IID_ID3D11Device,
261 (void **)device, TRUE);
264 return hr;
267 static void media_engine_unlock_d3d_device(struct media_engine *engine, ID3D11Device *device)
269 ID3D11Device_Release(device);
270 IMFDXGIDeviceManager_UnlockDevice(engine->device_manager, engine->device_handle, FALSE);
273 static HRESULT media_engine_create_d3d11_video_frame_resources(struct media_engine *engine, ID3D11Device *device)
275 static const D3D11_INPUT_ELEMENT_DESC layout_desc[] =
277 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
279 static const DWORD vs_code[] =
281 #if 0
282 float4 main(float4 position : POSITION) : SV_POSITION
284 return position;
286 #endif
287 0x43425844, 0xa7a2f22d, 0x83ff2560, 0xe61638bd, 0x87e3ce90, 0x00000001, 0x000000d8, 0x00000003,
288 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
289 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x49534f50, 0x4e4f4954, 0xababab00,
290 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, 0x00000003,
291 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x52444853, 0x0000003c, 0x00010040,
292 0x0000000f, 0x0300005f, 0x001010f2, 0x00000000, 0x04000067, 0x001020f2, 0x00000000, 0x00000001,
293 0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000000, 0x0100003e,
295 static const DWORD ps_code[] =
297 #if 0
298 Texture2D t;
299 SamplerState s;
300 float4 dst;
301 float4 src;
302 float4 backcolor;
304 float4 main(float4 position : SV_POSITION) : SV_TARGET
306 float2 p;
308 if (position.x < dst.x || position.x > dst.z) return backcolor;
309 if (position.y < dst.y || position.y > dst.w) return backcolor;
310 p.x = (position.x - dst.x) / (dst.z - dst.x);
311 p.y = (position.y - dst.y) / (dst.w - dst.y);
312 p.x = src.x + p.x * (src.z - src.x);
313 p.y = src.y + p.y * (src.w - src.y);
314 return t.Sample(s, p);
316 #endif
317 0x43425844, 0xae2162b7, 0x0fd69625, 0x6784c41a, 0x84ae95de, 0x00000001, 0x000002f8, 0x00000003,
318 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
319 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000030f, 0x505f5653, 0x5449534f, 0x004e4f49,
320 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
321 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054, 0x52444853, 0x0000025c, 0x00000040,
322 0x00000097, 0x04000059, 0x00208e46, 0x00000000, 0x00000003, 0x0300005a, 0x00106000, 0x00000000,
323 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x04002064, 0x00101032, 0x00000000, 0x00000001,
324 0x03000065, 0x001020f2, 0x00000000, 0x02000068, 0x00000002, 0x08000031, 0x00100012, 0x00000000,
325 0x0010100a, 0x00000000, 0x0020800a, 0x00000000, 0x00000000, 0x08000031, 0x00100022, 0x00000000,
326 0x0020802a, 0x00000000, 0x00000000, 0x0010100a, 0x00000000, 0x0700003c, 0x00100012, 0x00000000,
327 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x09000000, 0x00100062, 0x00000000, 0x00101106,
328 0x00000000, 0x80208106, 0x00000041, 0x00000000, 0x00000000, 0x0a000000, 0x00100032, 0x00000001,
329 0x80208046, 0x00000041, 0x00000000, 0x00000000, 0x00208ae6, 0x00000000, 0x00000000, 0x0700000e,
330 0x00100062, 0x00000000, 0x00100656, 0x00000000, 0x00100106, 0x00000001, 0x0a000000, 0x00100032,
331 0x00000001, 0x80208046, 0x00000041, 0x00000000, 0x00000001, 0x00208ae6, 0x00000000, 0x00000001,
332 0x0a000032, 0x00100062, 0x00000000, 0x00100656, 0x00000000, 0x00100106, 0x00000001, 0x00208106,
333 0x00000000, 0x00000001, 0x09000045, 0x001000f2, 0x00000001, 0x00100596, 0x00000000, 0x00107e46,
334 0x00000000, 0x00106000, 0x00000000, 0x0304001f, 0x0010000a, 0x00000000, 0x06000036, 0x001020f2,
335 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e, 0x01000015, 0x08000031, 0x00100012,
336 0x00000000, 0x0010101a, 0x00000000, 0x0020801a, 0x00000000, 0x00000000, 0x08000031, 0x00100022,
337 0x00000000, 0x0020803a, 0x00000000, 0x00000000, 0x0010101a, 0x00000000, 0x0700003c, 0x00100012,
338 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a, 0x00000000,
339 0x06000036, 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e, 0x01000015,
340 0x05000036, 0x001020f2, 0x00000000, 0x00100e46, 0x00000001, 0x0100003e,
342 D3D11_SUBRESOURCE_DATA resource_data;
343 D3D11_TEXTURE2D_DESC texture_desc;
344 D3D11_SAMPLER_DESC sampler_desc;
345 D3D11_BUFFER_DESC buffer_desc;
346 HRESULT hr;
348 if (engine->video_frame.d3d11.source)
349 return S_OK;
351 /* Default vertex buffer, updated on first transfer call. */
352 buffer_desc.ByteWidth = sizeof(engine->video_frame.d3d11.quad);
353 buffer_desc.Usage = D3D11_USAGE_DEFAULT;
354 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
355 buffer_desc.CPUAccessFlags = 0;
356 buffer_desc.MiscFlags = 0;
357 buffer_desc.StructureByteStride = 0;
359 resource_data.pSysMem = engine->video_frame.d3d11.quad;
360 resource_data.SysMemPitch = 0;
361 resource_data.SysMemSlicePitch = 0;
363 if (FAILED(hr = ID3D11Device_CreateBuffer(device, &buffer_desc, &resource_data, &engine->video_frame.d3d11.vb)))
365 WARN("Failed to create a vertex buffer, hr %#lx.\n", hr);
366 goto failed;
369 buffer_desc.ByteWidth = sizeof(engine->video_frame.d3d11.cb);
370 buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
372 if (FAILED(hr = ID3D11Device_CreateBuffer(device, &buffer_desc, NULL, &engine->video_frame.d3d11.ps_cb)))
374 WARN("Failed to create a buffer, hr %#lx.\n", hr);
375 goto failed;
378 /* Source texture. */
379 texture_desc.Width = engine->video_frame.size.cx;
380 texture_desc.Height = engine->video_frame.size.cy;
381 texture_desc.MipLevels = 1;
382 texture_desc.ArraySize = 1;
383 texture_desc.Format = engine->video_frame.output_format;
384 texture_desc.SampleDesc.Count = 1;
385 texture_desc.SampleDesc.Quality = 0;
386 texture_desc.Usage = D3D11_USAGE_DEFAULT;
387 texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
388 texture_desc.CPUAccessFlags = 0;
389 texture_desc.MiscFlags = 0;
391 if (FAILED(hr = ID3D11Device_CreateTexture2D(device, &texture_desc, NULL, &engine->video_frame.d3d11.source)))
393 WARN("Failed to create source texture, hr %#lx.\n", hr);
394 goto failed;
397 if (FAILED(hr = ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource *)engine->video_frame.d3d11.source,
398 NULL, &engine->video_frame.d3d11.srv)))
400 WARN("Failed to create SRV, hr %#lx.\n", hr);
401 goto failed;
404 /* Sampler state. */
405 memset(&sampler_desc, 0, sizeof(sampler_desc));
406 sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
407 sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
408 sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
409 sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
411 if (FAILED(hr = ID3D11Device_CreateSamplerState(device, &sampler_desc, &engine->video_frame.d3d11.sampler)))
413 WARN("Failed to create a sampler state, hr %#lx.\n", hr);
414 goto failed;
417 /* Input layout */
418 if (FAILED(hr = ID3D11Device_CreateInputLayout(device, layout_desc, ARRAY_SIZE(layout_desc), vs_code, sizeof(vs_code),
419 &engine->video_frame.d3d11.input_layout)))
421 WARN("Failed to create input layout, hr %#lx.\n", hr);
422 goto failed;
425 /* Shaders */
426 if (FAILED(hr = ID3D11Device_CreateVertexShader(device, vs_code, sizeof(vs_code), NULL, &engine->video_frame.d3d11.vs)))
428 WARN("Failed to create the vertex shader, hr %#lx.\n", hr);
429 goto failed;
432 if (FAILED(hr = ID3D11Device_CreatePixelShader(device, ps_code, sizeof(ps_code), NULL, &engine->video_frame.d3d11.ps)))
434 WARN("Failed to create the pixel shader, hr %#lx.\n", hr);
435 goto failed;
438 failed:
440 return hr;
443 struct range
445 double start;
446 double end;
449 struct time_range
451 IMFMediaTimeRange IMFMediaTimeRange_iface;
452 LONG refcount;
454 struct range *ranges;
455 size_t count;
456 size_t capacity;
459 static struct time_range *impl_from_IMFMediaTimeRange(IMFMediaTimeRange *iface)
461 return CONTAINING_RECORD(iface, struct time_range, IMFMediaTimeRange_iface);
464 struct media_error
466 IMFMediaError IMFMediaError_iface;
467 LONG refcount;
468 unsigned int code;
469 HRESULT extended_code;
472 static struct media_error *impl_from_IMFMediaError(IMFMediaError *iface)
474 return CONTAINING_RECORD(iface, struct media_error, IMFMediaError_iface);
477 static HRESULT WINAPI media_error_QueryInterface(IMFMediaError *iface, REFIID riid, void **obj)
479 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
481 if (IsEqualIID(riid, &IID_IMFMediaError) ||
482 IsEqualIID(riid, &IID_IUnknown))
484 *obj = iface;
485 IMFMediaError_AddRef(iface);
486 return S_OK;
489 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
490 *obj = NULL;
491 return E_NOINTERFACE;
494 static ULONG WINAPI media_error_AddRef(IMFMediaError *iface)
496 struct media_error *me = impl_from_IMFMediaError(iface);
497 ULONG refcount = InterlockedIncrement(&me->refcount);
499 TRACE("%p, refcount %lu.\n", iface, refcount);
501 return refcount;
504 static ULONG WINAPI media_error_Release(IMFMediaError *iface)
506 struct media_error *me = impl_from_IMFMediaError(iface);
507 ULONG refcount = InterlockedDecrement(&me->refcount);
509 TRACE("%p, refcount %lu.\n", iface, refcount);
511 if (!refcount)
512 free(me);
514 return refcount;
517 static USHORT WINAPI media_error_GetErrorCode(IMFMediaError *iface)
519 struct media_error *me = impl_from_IMFMediaError(iface);
520 TRACE("%p.\n", iface);
521 return me->code;
524 static HRESULT WINAPI media_error_GetExtendedErrorCode(IMFMediaError *iface)
526 struct media_error *me = impl_from_IMFMediaError(iface);
527 TRACE("%p.\n", iface);
528 return me->extended_code;
531 static HRESULT WINAPI media_error_SetErrorCode(IMFMediaError *iface, MF_MEDIA_ENGINE_ERR code)
533 struct media_error *me = impl_from_IMFMediaError(iface);
535 TRACE("%p, %u.\n", iface, code);
537 if ((unsigned int)code > MF_MEDIA_ENGINE_ERR_ENCRYPTED)
538 return E_INVALIDARG;
540 me->code = code;
542 return S_OK;
545 static HRESULT WINAPI media_error_SetExtendedErrorCode(IMFMediaError *iface, HRESULT code)
547 struct media_error *me = impl_from_IMFMediaError(iface);
549 TRACE("%p, %#lx.\n", iface, code);
551 me->extended_code = code;
553 return S_OK;
556 static const IMFMediaErrorVtbl media_error_vtbl =
558 media_error_QueryInterface,
559 media_error_AddRef,
560 media_error_Release,
561 media_error_GetErrorCode,
562 media_error_GetExtendedErrorCode,
563 media_error_SetErrorCode,
564 media_error_SetExtendedErrorCode,
567 static HRESULT create_media_error(IMFMediaError **ret)
569 struct media_error *object;
571 *ret = NULL;
573 if (!(object = calloc(1, sizeof(*object))))
574 return E_OUTOFMEMORY;
576 object->IMFMediaError_iface.lpVtbl = &media_error_vtbl;
577 object->refcount = 1;
579 *ret = &object->IMFMediaError_iface;
581 return S_OK;
584 static HRESULT WINAPI time_range_QueryInterface(IMFMediaTimeRange *iface, REFIID riid, void **obj)
586 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
588 if (IsEqualIID(riid, &IID_IMFMediaTimeRange) ||
589 IsEqualIID(riid, &IID_IUnknown))
591 *obj = iface;
592 IMFMediaTimeRange_AddRef(iface);
593 return S_OK;
596 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
597 *obj = NULL;
598 return E_NOINTERFACE;
601 static ULONG WINAPI time_range_AddRef(IMFMediaTimeRange *iface)
603 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
604 ULONG refcount = InterlockedIncrement(&range->refcount);
606 TRACE("%p, refcount %lu.\n", iface, refcount);
608 return refcount;
611 static ULONG WINAPI time_range_Release(IMFMediaTimeRange *iface)
613 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
614 ULONG refcount = InterlockedDecrement(&range->refcount);
616 TRACE("%p, refcount %lu.\n", iface, refcount);
618 if (!refcount)
620 free(range->ranges);
621 free(range);
624 return refcount;
627 static DWORD WINAPI time_range_GetLength(IMFMediaTimeRange *iface)
629 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
631 TRACE("%p.\n", iface);
633 return range->count;
636 static HRESULT WINAPI time_range_GetStart(IMFMediaTimeRange *iface, DWORD idx, double *start)
638 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
640 TRACE("%p, %lu, %p.\n", iface, idx, start);
642 if (idx >= range->count)
643 return E_INVALIDARG;
645 *start = range->ranges[idx].start;
647 return S_OK;
650 static HRESULT WINAPI time_range_GetEnd(IMFMediaTimeRange *iface, DWORD idx, double *end)
652 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
654 TRACE("%p, %lu, %p.\n", iface, idx, end);
656 if (idx >= range->count)
657 return E_INVALIDARG;
659 *end = range->ranges[idx].end;
661 return S_OK;
664 static BOOL WINAPI time_range_ContainsTime(IMFMediaTimeRange *iface, double time)
666 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
667 size_t i;
669 TRACE("%p, %.8e.\n", iface, time);
671 for (i = 0; i < range->count; ++i)
673 if (time >= range->ranges[i].start && time <= range->ranges[i].end)
674 return TRUE;
677 return FALSE;
680 static HRESULT WINAPI time_range_AddRange(IMFMediaTimeRange *iface, double start, double end)
682 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
683 struct range *c;
684 size_t i;
686 TRACE("%p, %.8e, %.8e.\n", iface, start, end);
688 for (i = 0; i < range->count; ++i)
690 c = &range->ranges[i];
692 /* New range is fully contained within existing one. */
693 if (c->start <= start && c->end >= end)
694 return S_OK;
696 /* New range fully contains existing one. */
697 if (c->start >= start && c->end <= end)
699 c->start = start;
700 c->end = end;
701 return S_OK;
704 /* Merge if ranges intersect. */
705 if ((start >= c->start && start <= c->end) ||
706 (end >= c->start && end <= c->end))
708 c->start = min(c->start, start);
709 c->end = max(c->end, end);
710 return S_OK;
714 if (!mf_array_reserve((void **)&range->ranges, &range->capacity, range->count + 1, sizeof(*range->ranges)))
715 return E_OUTOFMEMORY;
717 range->ranges[range->count].start = start;
718 range->ranges[range->count].end = end;
719 range->count++;
721 return S_OK;
724 static HRESULT WINAPI time_range_Clear(IMFMediaTimeRange *iface)
726 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
728 TRACE("%p.\n", iface);
730 range->count = 0;
732 return S_OK;
735 static const IMFMediaTimeRangeVtbl time_range_vtbl =
737 time_range_QueryInterface,
738 time_range_AddRef,
739 time_range_Release,
740 time_range_GetLength,
741 time_range_GetStart,
742 time_range_GetEnd,
743 time_range_ContainsTime,
744 time_range_AddRange,
745 time_range_Clear,
748 static HRESULT create_time_range(IMFMediaTimeRange **range)
750 struct time_range *object;
752 object = calloc(1, sizeof(*object));
753 if (!object)
754 return E_OUTOFMEMORY;
756 object->IMFMediaTimeRange_iface.lpVtbl = &time_range_vtbl;
757 object->refcount = 1;
759 *range = &object->IMFMediaTimeRange_iface;
761 return S_OK;
764 static void media_engine_set_flag(struct media_engine *engine, unsigned int mask, BOOL value)
766 if (value)
767 engine->flags |= mask;
768 else
769 engine->flags &= ~mask;
772 static inline struct media_engine *impl_from_IMFMediaEngineEx(IMFMediaEngineEx *iface)
774 return CONTAINING_RECORD(iface, struct media_engine, IMFMediaEngineEx_iface);
777 static inline struct media_engine *impl_from_IMFGetService(IMFGetService *iface)
779 return CONTAINING_RECORD(iface, struct media_engine, IMFGetService_iface);
782 static struct media_engine *impl_from_session_events_IMFAsyncCallback(IMFAsyncCallback *iface)
784 return CONTAINING_RECORD(iface, struct media_engine, session_events);
787 static struct media_engine *impl_from_load_handler_IMFAsyncCallback(IMFAsyncCallback *iface)
789 return CONTAINING_RECORD(iface, struct media_engine, load_handler);
792 static struct media_engine *impl_from_IMFSampleGrabberSinkCallback(IMFSampleGrabberSinkCallback *iface)
794 return CONTAINING_RECORD(iface, struct media_engine, grabber_callback);
797 static unsigned int get_gcd(unsigned int a, unsigned int b)
799 unsigned int m;
801 while (b)
803 m = a % b;
804 a = b;
805 b = m;
808 return a;
811 static void media_engine_get_frame_size(struct media_engine *engine, IMFTopology *topology)
813 IMFMediaTypeHandler *handler;
814 IMFMediaType *media_type;
815 IMFStreamDescriptor *sd;
816 IMFTopologyNode *node;
817 unsigned int gcd;
818 UINT64 size;
819 HRESULT hr;
821 engine->video_frame.size.cx = 0;
822 engine->video_frame.size.cy = 0;
823 engine->video_frame.ratio.cx = 1;
824 engine->video_frame.ratio.cy = 1;
826 if (FAILED(IMFTopology_GetNodeByID(topology, engine->video_frame.node_id, &node)))
827 return;
829 hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR,
830 &IID_IMFStreamDescriptor, (void **)&sd);
831 IMFTopologyNode_Release(node);
832 if (FAILED(hr))
833 return;
835 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
836 IMFStreamDescriptor_Release(sd);
837 if (FAILED(hr))
838 return;
840 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &media_type);
841 IMFMediaTypeHandler_Release(handler);
842 if (FAILED(hr))
844 WARN("Failed to get current media type %#lx.\n", hr);
845 return;
848 IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &size);
850 engine->video_frame.size.cx = size >> 32;
851 engine->video_frame.size.cy = size;
853 if ((gcd = get_gcd(engine->video_frame.size.cx, engine->video_frame.size.cy)))
855 engine->video_frame.ratio.cx = engine->video_frame.size.cx / gcd;
856 engine->video_frame.ratio.cy = engine->video_frame.size.cy / gcd;
859 IMFMediaType_Release(media_type);
862 static void media_engine_apply_volume(const struct media_engine *engine)
864 IMFSimpleAudioVolume *sa_volume;
865 HRESULT hr;
867 if (!engine->session)
868 return;
870 if (FAILED(MFGetService((IUnknown *)engine->session, &MR_POLICY_VOLUME_SERVICE, &IID_IMFSimpleAudioVolume, (void **)&sa_volume)))
871 return;
873 if (FAILED(hr = IMFSimpleAudioVolume_SetMasterVolume(sa_volume, engine->volume)))
874 WARN("Failed to set master volume, hr %#lx.\n", hr);
876 IMFSimpleAudioVolume_Release(sa_volume);
879 static HRESULT WINAPI media_engine_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
881 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
882 IsEqualIID(riid, &IID_IUnknown))
884 *obj = iface;
885 IMFAsyncCallback_AddRef(iface);
886 return S_OK;
889 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
890 *obj = NULL;
891 return E_NOINTERFACE;
894 static ULONG WINAPI media_engine_session_events_AddRef(IMFAsyncCallback *iface)
896 struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
897 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
900 static ULONG WINAPI media_engine_session_events_Release(IMFAsyncCallback *iface)
902 struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
903 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
906 static HRESULT WINAPI media_engine_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
908 return E_NOTIMPL;
911 static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
913 struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
914 IMFMediaEvent *event = NULL;
915 MediaEventType event_type;
916 HRESULT hr;
918 if (FAILED(hr = IMFMediaSession_EndGetEvent(engine->session, result, &event)))
920 WARN("Failed to get session event, hr %#lx.\n", hr);
921 goto failed;
924 if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type)))
926 WARN("Failed to get event type, hr %#lx.\n", hr);
927 goto failed;
930 switch (event_type)
932 case MEBufferingStarted:
933 case MEBufferingStopped:
935 IMFMediaEngineNotify_EventNotify(engine->callback, event_type == MEBufferingStarted ?
936 MF_MEDIA_ENGINE_EVENT_BUFFERINGSTARTED : MF_MEDIA_ENGINE_EVENT_BUFFERINGENDED, 0, 0);
937 break;
938 case MESessionTopologyStatus:
940 UINT32 topo_status = 0;
941 IMFTopology *topology;
942 PROPVARIANT value;
944 IMFMediaEvent_GetUINT32(event, &MF_EVENT_TOPOLOGY_STATUS, &topo_status);
945 if (topo_status != MF_TOPOSTATUS_READY)
946 break;
948 value.vt = VT_EMPTY;
949 if (FAILED(IMFMediaEvent_GetValue(event, &value)))
950 break;
952 if (value.vt != VT_UNKNOWN)
954 PropVariantClear(&value);
955 break;
958 topology = (IMFTopology *)value.punkVal;
960 EnterCriticalSection(&engine->cs);
962 media_engine_apply_volume(engine);
964 engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_METADATA;
966 media_engine_get_frame_size(engine, topology);
968 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE, 0, 0);
969 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA, 0, 0);
971 engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_ENOUGH_DATA;
973 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDDATA, 0, 0);
974 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_CANPLAY, 0, 0);
976 LeaveCriticalSection(&engine->cs);
978 PropVariantClear(&value);
980 break;
982 case MESessionStarted:
983 EnterCriticalSection(&engine->cs);
984 if (engine->flags & FLAGS_ENGINE_SEEKING)
986 media_engine_set_flag(engine, FLAGS_ENGINE_SEEKING | FLAGS_ENGINE_IS_ENDED, FALSE);
987 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_SEEKED, 0, 0);
988 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_TIMEUPDATE, 0, 0);
990 LeaveCriticalSection(&engine->cs);
991 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAYING, 0, 0);
992 break;
993 case MESessionEnded:
995 EnterCriticalSection(&engine->cs);
996 media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, FALSE);
997 media_engine_set_flag(engine, FLAGS_ENGINE_IS_ENDED, TRUE);
998 engine->video_frame.pts = MINLONGLONG;
999 LeaveCriticalSection(&engine->cs);
1001 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ENDED, 0, 0);
1002 break;
1005 failed:
1007 if (event)
1008 IMFMediaEvent_Release(event);
1010 if (FAILED(hr = IMFMediaSession_BeginGetEvent(engine->session, iface, NULL)))
1011 WARN("Failed to subscribe to session events, hr %#lx.\n", hr);
1013 return S_OK;
1016 static const IMFAsyncCallbackVtbl media_engine_session_events_vtbl =
1018 media_engine_callback_QueryInterface,
1019 media_engine_session_events_AddRef,
1020 media_engine_session_events_Release,
1021 media_engine_callback_GetParameters,
1022 media_engine_session_events_Invoke,
1025 static ULONG WINAPI media_engine_load_handler_AddRef(IMFAsyncCallback *iface)
1027 struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
1028 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
1031 static ULONG WINAPI media_engine_load_handler_Release(IMFAsyncCallback *iface)
1033 struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
1034 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
1037 static HRESULT media_engine_create_source_node(IMFMediaSource *source, IMFPresentationDescriptor *pd, IMFStreamDescriptor *sd,
1038 IMFTopologyNode **node)
1040 HRESULT hr;
1042 if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, node)))
1043 return hr;
1045 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_SOURCE, (IUnknown *)source);
1046 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)pd);
1047 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd);
1049 return S_OK;
1052 static HRESULT media_engine_create_effects(struct effect *effects, size_t count,
1053 IMFTopologyNode *src, IMFTopologyNode *sink, IMFTopology *topology)
1055 IMFTopologyNode *last = src;
1056 HRESULT hr = S_OK;
1057 size_t i;
1059 IMFTopologyNode_AddRef(last);
1061 for (i = 0; i < count; ++i)
1063 UINT32 method = MF_CONNECT_ALLOW_DECODER;
1064 IMFTopologyNode *node = NULL;
1066 if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node)))
1068 WARN("Failed to create transform node, hr %#lx.\n", hr);
1069 break;
1072 IMFTopologyNode_SetObject(node, (IUnknown *)effects[i].object);
1073 IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
1075 if (effects[i].optional)
1076 method |= MF_CONNECT_AS_OPTIONAL;
1077 IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_CONNECT_METHOD, method);
1079 IMFTopology_AddNode(topology, node);
1080 IMFTopologyNode_ConnectOutput(last, 0, node, 0);
1082 IMFTopologyNode_Release(last);
1083 last = node;
1086 IMFTopologyNode_Release(last);
1088 if (SUCCEEDED(hr))
1089 hr = IMFTopologyNode_ConnectOutput(last, 0, sink, 0);
1091 return hr;
1094 static HRESULT media_engine_create_audio_renderer(struct media_engine *engine, IMFTopologyNode **node)
1096 unsigned int category, role;
1097 IMFActivate *sar_activate;
1098 HRESULT hr;
1100 *node = NULL;
1102 if (FAILED(hr = MFCreateAudioRendererActivate(&sar_activate)))
1103 return hr;
1105 /* Configuration attributes keys differ between Engine and SAR. */
1106 if (SUCCEEDED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, &category)))
1107 IMFActivate_SetUINT32(sar_activate, &MF_AUDIO_RENDERER_ATTRIBUTE_STREAM_CATEGORY, category);
1108 if (SUCCEEDED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, &role)))
1109 IMFActivate_SetUINT32(sar_activate, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, role);
1111 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, node)))
1113 IMFTopologyNode_SetObject(*node, (IUnknown *)sar_activate);
1114 IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
1117 IMFActivate_Release(sar_activate);
1119 return hr;
1122 static HRESULT media_engine_create_video_renderer(struct media_engine *engine, IMFTopologyNode **node)
1124 IMFMediaType *media_type;
1125 IMFActivate *activate;
1126 UINT32 output_format;
1127 GUID subtype;
1128 HRESULT hr;
1130 *node = NULL;
1132 if (FAILED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, &output_format)))
1134 WARN("Output format was not specified.\n");
1135 return E_FAIL;
1138 memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype));
1139 if (!(subtype.Data1 = MFMapDXGIFormatToDX9Format(output_format)))
1141 WARN("Unrecognized output format %#x.\n", output_format);
1142 return E_FAIL;
1145 if (FAILED(hr = MFCreateMediaType(&media_type)))
1146 return hr;
1148 IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video);
1149 IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &subtype);
1151 hr = MFCreateSampleGrabberSinkActivate(media_type, &engine->grabber_callback, &activate);
1152 IMFMediaType_Release(media_type);
1153 if (FAILED(hr))
1154 return hr;
1156 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, node)))
1158 IMFTopologyNode_SetObject(*node, (IUnknown *)activate);
1159 IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
1162 IMFActivate_Release(activate);
1164 engine->video_frame.output_format = output_format;
1166 return hr;
1169 static void media_engine_clear_presentation(struct media_engine *engine)
1171 if (engine->presentation.source)
1173 IMFMediaSource_Shutdown(engine->presentation.source);
1174 IMFMediaSource_Release(engine->presentation.source);
1176 if (engine->presentation.pd)
1177 IMFPresentationDescriptor_Release(engine->presentation.pd);
1178 memset(&engine->presentation, 0, sizeof(engine->presentation));
1181 static void media_engine_clear_effects(struct effects *effects)
1183 size_t i;
1185 for (i = 0; i < effects->count; ++i)
1187 if (effects->effects[i].object)
1188 IUnknown_Release(effects->effects[i].object);
1191 free(effects->effects);
1192 memset(effects, 0, sizeof(*effects));
1195 static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMediaSource *source)
1197 IMFStreamDescriptor *sd_audio = NULL, *sd_video = NULL;
1198 IMFPresentationDescriptor *pd;
1199 DWORD stream_count = 0, i;
1200 IMFTopology *topology;
1201 UINT64 duration;
1202 HRESULT hr;
1204 media_engine_release_video_frame_resources(engine);
1205 media_engine_clear_presentation(engine);
1207 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd)))
1208 return hr;
1210 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(pd, &stream_count)))
1211 WARN("Failed to get stream count, hr %#lx.\n", hr);
1213 /* Enable first video stream and first audio stream. */
1215 for (i = 0; i < stream_count; ++i)
1217 IMFMediaTypeHandler *type_handler;
1218 IMFStreamDescriptor *sd;
1219 BOOL selected;
1221 IMFPresentationDescriptor_DeselectStream(pd, i);
1223 if (sd_audio && sd_video)
1224 continue;
1226 IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, i, &selected, &sd);
1228 if (SUCCEEDED(IMFStreamDescriptor_GetMediaTypeHandler(sd, &type_handler)))
1230 GUID major = { 0 };
1232 IMFMediaTypeHandler_GetMajorType(type_handler, &major);
1234 if (IsEqualGUID(&major, &MFMediaType_Audio) && !sd_audio)
1236 sd_audio = sd;
1237 IMFStreamDescriptor_AddRef(sd_audio);
1238 IMFPresentationDescriptor_SelectStream(pd, i);
1240 else if (IsEqualGUID(&major, &MFMediaType_Video) && !sd_video && !(engine->flags & MF_MEDIA_ENGINE_AUDIOONLY))
1242 sd_video = sd;
1243 IMFStreamDescriptor_AddRef(sd_video);
1244 IMFPresentationDescriptor_SelectStream(pd, i);
1247 IMFMediaTypeHandler_Release(type_handler);
1250 IMFStreamDescriptor_Release(sd);
1253 if (!sd_video && !sd_audio)
1255 IMFPresentationDescriptor_Release(pd);
1256 return E_UNEXPECTED;
1259 engine->presentation.source = source;
1260 IMFMediaSource_AddRef(engine->presentation.source);
1261 engine->presentation.pd = pd;
1262 IMFPresentationDescriptor_AddRef(engine->presentation.pd);
1264 media_engine_set_flag(engine, FLAGS_ENGINE_HAS_VIDEO, !!sd_video);
1265 media_engine_set_flag(engine, FLAGS_ENGINE_HAS_AUDIO, !!sd_audio);
1267 /* Assume live source if duration was not provided. */
1268 if (SUCCEEDED(IMFPresentationDescriptor_GetUINT64(pd, &MF_PD_DURATION, &duration)))
1269 engine->duration = mftime_to_seconds(duration);
1270 else
1271 engine->duration = INFINITY;
1273 if (SUCCEEDED(hr = MFCreateTopology(&topology)))
1275 IMFTopologyNode *sar_node = NULL, *audio_src = NULL;
1276 IMFTopologyNode *grabber_node = NULL, *video_src = NULL;
1278 if (engine->flags & MF_MEDIA_ENGINE_REAL_TIME_MODE)
1279 IMFTopology_SetUINT32(topology, &MF_LOW_LATENCY, TRUE);
1281 if (sd_audio)
1283 if (FAILED(hr = media_engine_create_source_node(source, pd, sd_audio, &audio_src)))
1284 WARN("Failed to create audio source node, hr %#lx.\n", hr);
1286 if (FAILED(hr = media_engine_create_audio_renderer(engine, &sar_node)))
1287 WARN("Failed to create audio renderer node, hr %#lx.\n", hr);
1289 if (sar_node && audio_src)
1291 IMFTopology_AddNode(topology, audio_src);
1292 IMFTopology_AddNode(topology, sar_node);
1294 if (FAILED(hr = media_engine_create_effects(engine->audio_effects.effects, engine->audio_effects.count,
1295 audio_src, sar_node, topology)))
1296 WARN("Failed to create audio effect nodes, hr %#lx.\n", hr);
1299 if (sar_node)
1300 IMFTopologyNode_Release(sar_node);
1301 if (audio_src)
1302 IMFTopologyNode_Release(audio_src);
1305 if (SUCCEEDED(hr) && sd_video)
1307 if (FAILED(hr = media_engine_create_source_node(source, pd, sd_video, &video_src)))
1308 WARN("Failed to create video source node, hr %#lx.\n", hr);
1310 if (FAILED(hr = media_engine_create_video_renderer(engine, &grabber_node)))
1311 WARN("Failed to create video grabber node, hr %#lx.\n", hr);
1313 if (grabber_node && video_src)
1315 IMFTopology_AddNode(topology, video_src);
1316 IMFTopology_AddNode(topology, grabber_node);
1318 if (FAILED(hr = media_engine_create_effects(engine->video_effects.effects, engine->video_effects.count,
1319 video_src, grabber_node, topology)))
1320 WARN("Failed to create video effect nodes, hr %#lx.\n", hr);
1323 if (SUCCEEDED(hr))
1324 IMFTopologyNode_GetTopoNodeID(video_src, &engine->video_frame.node_id);
1326 if (grabber_node)
1327 IMFTopologyNode_Release(grabber_node);
1328 if (video_src)
1329 IMFTopologyNode_Release(video_src);
1332 IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, TRUE);
1334 if (SUCCEEDED(hr))
1335 hr = IMFMediaSession_SetTopology(engine->session, MFSESSION_SETTOPOLOGY_IMMEDIATE, topology);
1338 if (topology)
1339 IMFTopology_Release(topology);
1341 if (sd_video)
1342 IMFStreamDescriptor_Release(sd_video);
1343 if (sd_audio)
1344 IMFStreamDescriptor_Release(sd_audio);
1346 IMFPresentationDescriptor_Release(pd);
1348 return hr;
1351 static void media_engine_start_playback(struct media_engine *engine)
1353 IMFMediaSession_Start(engine->session, &GUID_NULL, &engine->presentation.start_position);
1354 /* Reset the playback position to the current position */
1355 engine->presentation.start_position.vt = VT_EMPTY;
1358 static HRESULT WINAPI media_engine_load_handler_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1360 struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
1361 IUnknown *object = NULL, *state;
1362 unsigned int start_playback;
1363 MF_OBJECT_TYPE obj_type;
1364 IMFMediaSource *source;
1365 HRESULT hr;
1367 EnterCriticalSection(&engine->cs);
1369 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1371 LeaveCriticalSection(&engine->cs);
1372 return S_OK;
1375 engine->network_state = MF_MEDIA_ENGINE_NETWORK_LOADING;
1376 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADSTART, 0, 0);
1378 start_playback = engine->flags & FLAGS_ENGINE_PLAY_PENDING;
1379 media_engine_set_flag(engine, FLAGS_ENGINE_SOURCE_PENDING | FLAGS_ENGINE_PLAY_PENDING, FALSE);
1381 if (SUCCEEDED(IMFAsyncResult_GetState(result, &state)))
1383 hr = IMFSourceResolver_EndCreateObjectFromByteStream(engine->resolver, result, &obj_type, &object);
1384 IUnknown_Release(state);
1386 else
1387 hr = IMFSourceResolver_EndCreateObjectFromURL(engine->resolver, result, &obj_type, &object);
1389 if (FAILED(hr))
1390 WARN("Failed to create source object, hr %#lx.\n", hr);
1392 if (object)
1394 if (SUCCEEDED(hr = IUnknown_QueryInterface(object, &IID_IMFMediaSource, (void **)&source)))
1396 hr = media_engine_create_topology(engine, source);
1397 IMFMediaSource_Release(source);
1399 IUnknown_Release(object);
1402 if (SUCCEEDED(hr))
1404 engine->network_state = MF_MEDIA_ENGINE_NETWORK_IDLE;
1405 if (start_playback)
1406 media_engine_start_playback(engine);
1408 else
1410 engine->network_state = MF_MEDIA_ENGINE_NETWORK_NO_SOURCE;
1411 engine->error_code = MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED;
1412 engine->extended_code = hr;
1413 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ERROR, engine->error_code,
1414 engine->extended_code);
1417 LeaveCriticalSection(&engine->cs);
1419 return S_OK;
1422 static const IMFAsyncCallbackVtbl media_engine_load_handler_vtbl =
1424 media_engine_callback_QueryInterface,
1425 media_engine_load_handler_AddRef,
1426 media_engine_load_handler_Release,
1427 media_engine_callback_GetParameters,
1428 media_engine_load_handler_Invoke,
1431 static HRESULT WINAPI media_engine_QueryInterface(IMFMediaEngineEx *iface, REFIID riid, void **obj)
1433 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1435 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1437 if (IsEqualIID(riid, &IID_IMFMediaEngineEx) ||
1438 IsEqualIID(riid, &IID_IMFMediaEngine) ||
1439 IsEqualIID(riid, &IID_IUnknown))
1441 *obj = iface;
1443 else if (IsEqualIID(riid, &IID_IMFGetService))
1445 *obj = &engine->IMFGetService_iface;
1447 else
1449 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1450 *obj = NULL;
1451 return E_NOINTERFACE;
1454 IUnknown_AddRef((IUnknown *)*obj);
1455 return S_OK;
1458 static ULONG WINAPI media_engine_AddRef(IMFMediaEngineEx *iface)
1460 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1461 ULONG refcount = InterlockedIncrement(&engine->refcount);
1463 TRACE("%p, refcount %lu.\n", iface, refcount);
1465 return refcount;
1468 static void free_media_engine(struct media_engine *engine)
1470 if (engine->callback)
1471 IMFMediaEngineNotify_Release(engine->callback);
1472 if (engine->clock)
1473 IMFPresentationClock_Release(engine->clock);
1474 if (engine->session)
1475 IMFMediaSession_Release(engine->session);
1476 if (engine->attributes)
1477 IMFAttributes_Release(engine->attributes);
1478 if (engine->resolver)
1479 IMFSourceResolver_Release(engine->resolver);
1480 if (engine->extension)
1481 IMFMediaEngineExtension_Release(engine->extension);
1482 media_engine_clear_effects(&engine->audio_effects);
1483 media_engine_clear_effects(&engine->video_effects);
1484 media_engine_release_video_frame_resources(engine);
1485 media_engine_clear_presentation(engine);
1486 if (engine->device_manager)
1488 IMFDXGIDeviceManager_CloseDeviceHandle(engine->device_manager, engine->device_handle);
1489 IMFDXGIDeviceManager_Release(engine->device_manager);
1491 SysFreeString(engine->current_source);
1492 DeleteCriticalSection(&engine->cs);
1493 free(engine->video_frame.buffer);
1494 free(engine);
1497 static ULONG WINAPI media_engine_Release(IMFMediaEngineEx *iface)
1499 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1500 ULONG refcount = InterlockedDecrement(&engine->refcount);
1502 TRACE("%p, refcount %lu.\n", iface, refcount);
1504 if (!refcount)
1505 free_media_engine(engine);
1507 return refcount;
1510 static HRESULT WINAPI media_engine_GetError(IMFMediaEngineEx *iface, IMFMediaError **error)
1512 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1513 HRESULT hr = S_OK;
1515 TRACE("%p, %p.\n", iface, error);
1517 *error = NULL;
1519 EnterCriticalSection(&engine->cs);
1520 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1521 hr = MF_E_SHUTDOWN;
1522 else if (engine->error_code)
1524 if (SUCCEEDED(hr = create_media_error(error)))
1526 IMFMediaError_SetErrorCode(*error, engine->error_code);
1527 IMFMediaError_SetExtendedErrorCode(*error, engine->extended_code);
1530 LeaveCriticalSection(&engine->cs);
1532 return hr;
1535 static HRESULT WINAPI media_engine_SetErrorCode(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_ERR code)
1537 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1538 HRESULT hr = S_OK;
1540 TRACE("%p, %u.\n", iface, code);
1542 if ((unsigned int)code > MF_MEDIA_ENGINE_ERR_ENCRYPTED)
1543 return E_INVALIDARG;
1545 EnterCriticalSection(&engine->cs);
1546 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1547 hr = MF_E_SHUTDOWN;
1548 else
1549 engine->error_code = code;
1550 LeaveCriticalSection(&engine->cs);
1552 return hr;
1555 static HRESULT WINAPI media_engine_SetSourceElements(IMFMediaEngineEx *iface, IMFMediaEngineSrcElements *elements)
1557 FIXME("(%p, %p): stub.\n", iface, elements);
1559 return E_NOTIMPL;
1562 static HRESULT media_engine_set_source(struct media_engine *engine, IMFByteStream *bytestream, BSTR url)
1564 IPropertyStore *props = NULL;
1565 unsigned int flags;
1566 HRESULT hr = S_OK;
1568 SysFreeString(engine->current_source);
1569 engine->current_source = NULL;
1570 if (url)
1571 engine->current_source = SysAllocString(url);
1573 engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_NOTHING;
1575 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
1577 engine->network_state = MF_MEDIA_ENGINE_NETWORK_NO_SOURCE;
1579 if (url || bytestream)
1581 if (engine->extension)
1582 FIXME("Use extension to load from.\n");
1584 flags = MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE;
1585 if (engine->flags & MF_MEDIA_ENGINE_DISABLE_LOCAL_PLUGINS)
1586 flags |= MF_RESOLUTION_DISABLE_LOCAL_PLUGINS;
1588 IMFAttributes_GetUnknown(engine->attributes, &MF_MEDIA_ENGINE_SOURCE_RESOLVER_CONFIG_STORE,
1589 &IID_IPropertyStore, (void **)&props);
1590 if (bytestream)
1591 hr = IMFSourceResolver_BeginCreateObjectFromByteStream(engine->resolver, bytestream, url, flags,
1592 props, NULL, &engine->load_handler, (IUnknown *)bytestream);
1593 else
1594 hr = IMFSourceResolver_BeginCreateObjectFromURL(engine->resolver, url, flags, props, NULL,
1595 &engine->load_handler, NULL);
1596 if (SUCCEEDED(hr))
1597 media_engine_set_flag(engine, FLAGS_ENGINE_SOURCE_PENDING, TRUE);
1599 if (props)
1600 IPropertyStore_Release(props);
1603 return hr;
1606 static HRESULT WINAPI media_engine_SetSource(IMFMediaEngineEx *iface, BSTR url)
1608 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1609 HRESULT hr;
1611 TRACE("%p, %s.\n", iface, debugstr_w(url));
1613 EnterCriticalSection(&engine->cs);
1615 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1616 hr = MF_E_SHUTDOWN;
1617 else
1618 hr = media_engine_set_source(engine, NULL, url);
1620 LeaveCriticalSection(&engine->cs);
1622 return hr;
1625 static HRESULT WINAPI media_engine_GetCurrentSource(IMFMediaEngineEx *iface, BSTR *url)
1627 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1628 HRESULT hr = S_OK;
1630 TRACE("%p, %p.\n", iface, url);
1632 *url = NULL;
1634 EnterCriticalSection(&engine->cs);
1636 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1637 hr = MF_E_SHUTDOWN;
1638 if (engine->current_source)
1640 if (!(*url = SysAllocString(engine->current_source)))
1641 hr = E_OUTOFMEMORY;
1644 LeaveCriticalSection(&engine->cs);
1646 return hr;
1649 static USHORT WINAPI media_engine_GetNetworkState(IMFMediaEngineEx *iface)
1651 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1653 TRACE("%p.\n", iface);
1655 return engine->network_state;
1658 static MF_MEDIA_ENGINE_PRELOAD WINAPI media_engine_GetPreload(IMFMediaEngineEx *iface)
1660 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1661 MF_MEDIA_ENGINE_PRELOAD preload;
1663 TRACE("%p.\n", iface);
1665 EnterCriticalSection(&engine->cs);
1666 preload = engine->preload;
1667 LeaveCriticalSection(&engine->cs);
1669 return preload;
1672 static HRESULT WINAPI media_engine_SetPreload(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_PRELOAD preload)
1674 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1676 TRACE("%p, %d.\n", iface, preload);
1678 EnterCriticalSection(&engine->cs);
1679 engine->preload = preload;
1680 LeaveCriticalSection(&engine->cs);
1682 return S_OK;
1685 static HRESULT WINAPI media_engine_GetBuffered(IMFMediaEngineEx *iface, IMFMediaTimeRange **range)
1687 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1688 HRESULT hr;
1690 TRACE("%p, %p.\n", iface, range);
1692 if (FAILED(hr = create_time_range(range)))
1693 return hr;
1695 EnterCriticalSection(&engine->cs);
1697 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1698 hr = MF_E_SHUTDOWN;
1699 else if (!isnan(engine->duration))
1700 hr = IMFMediaTimeRange_AddRange(*range, 0.0, engine->duration);
1702 LeaveCriticalSection(&engine->cs);
1704 return hr;
1707 static HRESULT WINAPI media_engine_Load(IMFMediaEngineEx *iface)
1709 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1710 HRESULT hr = E_NOTIMPL;
1712 FIXME("(%p): stub.\n", iface);
1714 EnterCriticalSection(&engine->cs);
1716 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1717 hr = MF_E_SHUTDOWN;
1719 LeaveCriticalSection(&engine->cs);
1721 return hr;
1724 static HRESULT WINAPI media_engine_CanPlayType(IMFMediaEngineEx *iface, BSTR mime_type, MF_MEDIA_ENGINE_CANPLAY *answer)
1726 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1727 HRESULT hr = E_NOTIMPL;
1729 TRACE("%p, %s, %p.\n", iface, debugstr_w(mime_type), answer);
1731 EnterCriticalSection(&engine->cs);
1733 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1734 hr = MF_E_SHUTDOWN;
1735 else
1737 FIXME("Check builtin supported types.\n");
1739 if (engine->extension)
1740 hr = IMFMediaEngineExtension_CanPlayType(engine->extension, !!(engine->flags & MF_MEDIA_ENGINE_AUDIOONLY),
1741 mime_type, answer);
1744 LeaveCriticalSection(&engine->cs);
1746 return hr;
1749 static USHORT WINAPI media_engine_GetReadyState(IMFMediaEngineEx *iface)
1751 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1752 unsigned short state;
1754 TRACE("%p.\n", iface);
1756 EnterCriticalSection(&engine->cs);
1757 state = engine->ready_state;
1758 LeaveCriticalSection(&engine->cs);
1760 return state;
1763 static BOOL WINAPI media_engine_IsSeeking(IMFMediaEngineEx *iface)
1765 FIXME("(%p): stub.\n", iface);
1767 return FALSE;
1770 static double WINAPI media_engine_GetCurrentTime(IMFMediaEngineEx *iface)
1772 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1773 double ret = 0.0;
1774 MFTIME clocktime;
1776 TRACE("%p.\n", iface);
1778 EnterCriticalSection(&engine->cs);
1779 if (engine->flags & FLAGS_ENGINE_IS_ENDED)
1781 ret = engine->duration;
1783 else if (engine->flags & FLAGS_ENGINE_PAUSED && engine->presentation.start_position.vt == VT_I8)
1785 ret = (double)engine->presentation.start_position.hVal.QuadPart / 10000000;
1787 else if (SUCCEEDED(IMFPresentationClock_GetTime(engine->clock, &clocktime)))
1789 ret = mftime_to_seconds(clocktime);
1791 LeaveCriticalSection(&engine->cs);
1793 return ret;
1796 static HRESULT media_engine_set_current_time(struct media_engine *engine, double seektime)
1798 PROPVARIANT position;
1799 DWORD caps;
1800 HRESULT hr;
1802 hr = IMFMediaSession_GetSessionCapabilities(engine->session, &caps);
1803 if (FAILED(hr) || !(caps & MFSESSIONCAP_SEEK))
1804 return hr;
1806 position.vt = VT_I8;
1807 position.hVal.QuadPart = min(max(0, seektime), engine->duration) * 10000000;
1809 if (IMFMediaEngineEx_IsPaused(&engine->IMFMediaEngineEx_iface))
1811 engine->presentation.start_position = position;
1812 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_SEEKING, 0, 0);
1813 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_SEEKED, 0, 0);
1814 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_TIMEUPDATE, 0, 0);
1815 return S_OK;
1818 if (SUCCEEDED(hr = IMFMediaSession_Start(engine->session, &GUID_NULL, &position)))
1820 media_engine_set_flag(engine, FLAGS_ENGINE_SEEKING, TRUE);
1821 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_SEEKING, 0, 0);
1824 return hr;
1827 static HRESULT WINAPI media_engine_SetCurrentTime(IMFMediaEngineEx *iface, double time)
1829 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1830 HRESULT hr;
1832 TRACE("%p, %f.\n", iface, time);
1834 EnterCriticalSection(&engine->cs);
1836 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1837 hr = MF_E_SHUTDOWN;
1838 else
1839 hr = media_engine_set_current_time(engine, time);
1841 LeaveCriticalSection(&engine->cs);
1843 return hr;
1846 static double WINAPI media_engine_GetStartTime(IMFMediaEngineEx *iface)
1848 FIXME("(%p): stub.\n", iface);
1850 return 0.0;
1853 static double WINAPI media_engine_GetDuration(IMFMediaEngineEx *iface)
1855 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1856 double value;
1858 TRACE("%p.\n", iface);
1860 EnterCriticalSection(&engine->cs);
1861 value = engine->duration;
1862 LeaveCriticalSection(&engine->cs);
1864 return value;
1867 static BOOL WINAPI media_engine_IsPaused(IMFMediaEngineEx *iface)
1869 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1870 BOOL value;
1872 TRACE("%p.\n", iface);
1874 EnterCriticalSection(&engine->cs);
1875 value = !!(engine->flags & FLAGS_ENGINE_PAUSED);
1876 LeaveCriticalSection(&engine->cs);
1878 return value;
1881 static double WINAPI media_engine_GetDefaultPlaybackRate(IMFMediaEngineEx *iface)
1883 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1884 double rate;
1886 TRACE("%p.\n", iface);
1888 EnterCriticalSection(&engine->cs);
1889 rate = engine->default_playback_rate;
1890 LeaveCriticalSection(&engine->cs);
1892 return rate;
1895 static HRESULT WINAPI media_engine_SetDefaultPlaybackRate(IMFMediaEngineEx *iface, double rate)
1897 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1898 HRESULT hr = S_OK;
1900 TRACE("%p, %f.\n", iface, rate);
1902 EnterCriticalSection(&engine->cs);
1903 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1904 hr = MF_E_SHUTDOWN;
1905 else if (engine->default_playback_rate != rate)
1907 engine->default_playback_rate = rate;
1908 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_RATECHANGE, 0, 0);
1910 LeaveCriticalSection(&engine->cs);
1912 return hr;
1915 static double WINAPI media_engine_GetPlaybackRate(IMFMediaEngineEx *iface)
1917 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1918 double rate;
1920 TRACE("%p.\n", iface);
1922 EnterCriticalSection(&engine->cs);
1923 rate = engine->playback_rate;
1924 LeaveCriticalSection(&engine->cs);
1926 return rate;
1929 static HRESULT WINAPI media_engine_SetPlaybackRate(IMFMediaEngineEx *iface, double rate)
1931 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1932 HRESULT hr = S_OK;
1934 TRACE("%p, %f.\n", iface, rate);
1936 EnterCriticalSection(&engine->cs);
1937 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1938 hr = MF_E_SHUTDOWN;
1939 else if (engine->playback_rate != rate)
1941 engine->playback_rate = rate;
1942 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_RATECHANGE, 0, 0);
1944 LeaveCriticalSection(&engine->cs);
1946 return hr;
1949 static HRESULT WINAPI media_engine_GetPlayed(IMFMediaEngineEx *iface, IMFMediaTimeRange **played)
1951 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1952 HRESULT hr = E_NOTIMPL;
1954 FIXME("(%p, %p): stub.\n", iface, played);
1956 EnterCriticalSection(&engine->cs);
1958 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1959 hr = MF_E_SHUTDOWN;
1961 LeaveCriticalSection(&engine->cs);
1963 return hr;
1966 static HRESULT WINAPI media_engine_GetSeekable(IMFMediaEngineEx *iface, IMFMediaTimeRange **seekable)
1968 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1969 IMFMediaTimeRange *time_range = NULL;
1970 DWORD flags;
1971 HRESULT hr;
1973 TRACE("%p, %p.\n", iface, seekable);
1975 EnterCriticalSection(&engine->cs);
1977 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1978 hr = MF_E_SHUTDOWN;
1979 else
1981 hr = create_time_range(&time_range);
1982 if (SUCCEEDED(hr) && !isnan(engine->duration) && engine->presentation.source)
1984 hr = IMFMediaSource_GetCharacteristics(engine->presentation.source, &flags);
1985 if (SUCCEEDED(hr) && (flags & MFBYTESTREAM_IS_SEEKABLE))
1986 hr = IMFMediaTimeRange_AddRange(time_range, 0.0, engine->duration);
1990 LeaveCriticalSection(&engine->cs);
1992 if (FAILED(hr) && time_range)
1994 IMFMediaTimeRange_Release(time_range);
1995 time_range = NULL;
1997 *seekable = time_range;
1998 return hr;
2001 static BOOL WINAPI media_engine_IsEnded(IMFMediaEngineEx *iface)
2003 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2004 BOOL value;
2006 TRACE("%p.\n", iface);
2008 EnterCriticalSection(&engine->cs);
2009 value = !!(engine->flags & FLAGS_ENGINE_IS_ENDED);
2010 LeaveCriticalSection(&engine->cs);
2012 return value;
2015 static BOOL WINAPI media_engine_GetAutoPlay(IMFMediaEngineEx *iface)
2017 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2018 BOOL value;
2020 TRACE("%p.\n", iface);
2022 EnterCriticalSection(&engine->cs);
2023 value = !!(engine->flags & FLAGS_ENGINE_AUTO_PLAY);
2024 LeaveCriticalSection(&engine->cs);
2026 return value;
2029 static HRESULT WINAPI media_engine_SetAutoPlay(IMFMediaEngineEx *iface, BOOL autoplay)
2031 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2033 FIXME("(%p, %d): stub.\n", iface, autoplay);
2035 EnterCriticalSection(&engine->cs);
2036 media_engine_set_flag(engine, FLAGS_ENGINE_AUTO_PLAY, autoplay);
2037 LeaveCriticalSection(&engine->cs);
2039 return S_OK;
2042 static BOOL WINAPI media_engine_GetLoop(IMFMediaEngineEx *iface)
2044 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2045 BOOL value;
2047 TRACE("%p.\n", iface);
2049 EnterCriticalSection(&engine->cs);
2050 value = !!(engine->flags & FLAGS_ENGINE_LOOP);
2051 LeaveCriticalSection(&engine->cs);
2053 return value;
2056 static HRESULT WINAPI media_engine_SetLoop(IMFMediaEngineEx *iface, BOOL loop)
2058 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2060 FIXME("(%p, %d): stub.\n", iface, loop);
2062 EnterCriticalSection(&engine->cs);
2063 media_engine_set_flag(engine, FLAGS_ENGINE_LOOP, loop);
2064 LeaveCriticalSection(&engine->cs);
2066 return S_OK;
2069 static HRESULT WINAPI media_engine_Play(IMFMediaEngineEx *iface)
2071 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2072 HRESULT hr = S_OK;
2074 TRACE("%p.\n", iface);
2076 EnterCriticalSection(&engine->cs);
2078 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2079 hr = MF_E_SHUTDOWN;
2080 else
2082 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
2084 if (!(engine->flags & FLAGS_ENGINE_WAITING))
2086 media_engine_set_flag(engine, FLAGS_ENGINE_PAUSED | FLAGS_ENGINE_IS_ENDED, FALSE);
2087 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAY, 0, 0);
2089 if (!(engine->flags & FLAGS_ENGINE_SOURCE_PENDING))
2090 media_engine_start_playback(engine);
2091 else
2092 media_engine_set_flag(engine, FLAGS_ENGINE_PLAY_PENDING, TRUE);
2094 media_engine_set_flag(engine, FLAGS_ENGINE_WAITING, TRUE);
2097 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_WAITING, 0, 0);
2100 LeaveCriticalSection(&engine->cs);
2102 return hr;
2105 static HRESULT WINAPI media_engine_Pause(IMFMediaEngineEx *iface)
2107 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2108 HRESULT hr = S_OK;
2110 TRACE("%p.\n", iface);
2112 EnterCriticalSection(&engine->cs);
2114 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2115 hr = MF_E_SHUTDOWN;
2116 else
2118 if (!(engine->flags & FLAGS_ENGINE_PAUSED))
2120 if (SUCCEEDED(hr = IMFMediaSession_Pause(engine->session)))
2122 media_engine_set_flag(engine, FLAGS_ENGINE_WAITING | FLAGS_ENGINE_IS_ENDED, FALSE);
2123 media_engine_set_flag(engine, FLAGS_ENGINE_PAUSED, TRUE);
2125 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_TIMEUPDATE, 0, 0);
2126 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PAUSE, 0, 0);
2130 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
2133 LeaveCriticalSection(&engine->cs);
2135 return hr;
2138 static BOOL WINAPI media_engine_GetMuted(IMFMediaEngineEx *iface)
2140 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2141 BOOL ret;
2143 TRACE("%p.\n", iface);
2145 EnterCriticalSection(&engine->cs);
2146 ret = !!(engine->flags & FLAGS_ENGINE_MUTED);
2147 LeaveCriticalSection(&engine->cs);
2149 return ret;
2152 static HRESULT WINAPI media_engine_SetMuted(IMFMediaEngineEx *iface, BOOL muted)
2154 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2155 HRESULT hr = S_OK;
2157 TRACE("%p, %d.\n", iface, muted);
2159 EnterCriticalSection(&engine->cs);
2160 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2161 hr = MF_E_SHUTDOWN;
2162 else if (!!(engine->flags & FLAGS_ENGINE_MUTED) ^ !!muted)
2164 media_engine_set_flag(engine, FLAGS_ENGINE_MUTED, muted);
2165 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE, 0, 0);
2167 LeaveCriticalSection(&engine->cs);
2169 return hr;
2172 static double WINAPI media_engine_GetVolume(IMFMediaEngineEx *iface)
2174 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2175 double volume;
2177 TRACE("%p.\n", iface);
2179 EnterCriticalSection(&engine->cs);
2180 volume = engine->volume;
2181 LeaveCriticalSection(&engine->cs);
2183 return volume;
2186 static HRESULT WINAPI media_engine_SetVolume(IMFMediaEngineEx *iface, double volume)
2188 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2189 HRESULT hr = S_OK;
2191 TRACE("%p, %f.\n", iface, volume);
2193 EnterCriticalSection(&engine->cs);
2194 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2195 hr = MF_E_SHUTDOWN;
2196 else if (volume != engine->volume)
2198 engine->volume = volume;
2199 media_engine_apply_volume(engine);
2200 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE, 0, 0);
2202 LeaveCriticalSection(&engine->cs);
2204 return hr;
2207 static BOOL WINAPI media_engine_HasVideo(IMFMediaEngineEx *iface)
2209 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2210 BOOL value;
2212 TRACE("%p.\n", iface);
2214 EnterCriticalSection(&engine->cs);
2215 value = !!(engine->flags & FLAGS_ENGINE_HAS_VIDEO);
2216 LeaveCriticalSection(&engine->cs);
2218 return value;
2221 static BOOL WINAPI media_engine_HasAudio(IMFMediaEngineEx *iface)
2223 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2224 BOOL value;
2226 TRACE("%p.\n", iface);
2228 EnterCriticalSection(&engine->cs);
2229 value = !!(engine->flags & FLAGS_ENGINE_HAS_AUDIO);
2230 LeaveCriticalSection(&engine->cs);
2232 return value;
2235 static HRESULT WINAPI media_engine_GetNativeVideoSize(IMFMediaEngineEx *iface, DWORD *cx, DWORD *cy)
2237 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2238 HRESULT hr = S_OK;
2240 TRACE("%p, %p, %p.\n", iface, cx, cy);
2242 if (!cx && !cy)
2243 return E_INVALIDARG;
2245 EnterCriticalSection(&engine->cs);
2247 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2248 hr = MF_E_SHUTDOWN;
2249 else if (!engine->video_frame.size.cx && !engine->video_frame.size.cy)
2250 hr = E_FAIL;
2251 else
2253 if (cx) *cx = engine->video_frame.size.cx;
2254 if (cy) *cy = engine->video_frame.size.cy;
2257 LeaveCriticalSection(&engine->cs);
2259 return hr;
2262 static HRESULT WINAPI media_engine_GetVideoAspectRatio(IMFMediaEngineEx *iface, DWORD *cx, DWORD *cy)
2264 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2265 HRESULT hr = S_OK;
2267 TRACE("%p, %p, %p.\n", iface, cx, cy);
2269 if (!cx && !cy)
2270 return E_INVALIDARG;
2272 EnterCriticalSection(&engine->cs);
2274 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2275 hr = MF_E_SHUTDOWN;
2276 else if (!engine->video_frame.size.cx && !engine->video_frame.size.cy)
2277 hr = E_FAIL;
2278 else
2280 if (cx) *cx = engine->video_frame.ratio.cx;
2281 if (cy) *cy = engine->video_frame.ratio.cy;
2284 LeaveCriticalSection(&engine->cs);
2286 return hr;
2289 static HRESULT WINAPI media_engine_Shutdown(IMFMediaEngineEx *iface)
2291 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2292 HRESULT hr = S_OK;
2294 TRACE("%p.\n", iface);
2296 EnterCriticalSection(&engine->cs);
2297 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2298 hr = MF_E_SHUTDOWN;
2299 else
2301 media_engine_set_flag(engine, FLAGS_ENGINE_SHUT_DOWN, TRUE);
2302 media_engine_clear_presentation(engine);
2303 IMFMediaSession_Shutdown(engine->session);
2305 LeaveCriticalSection(&engine->cs);
2307 return hr;
2310 static void set_rect(struct rect *rect, float left, float top, float right, float bottom)
2312 rect->left = left;
2313 rect->top = top;
2314 rect->right = right;
2315 rect->bottom = bottom;
2318 static void media_engine_adjust_destination_for_ratio(const struct media_engine *engine,
2319 struct rect *src_n, struct rect *dst)
2321 float dst_width = dst->right - dst->left, dst_height = dst->bottom - dst->top;
2322 D3D11_TEXTURE2D_DESC source_desc;
2323 float src_width, src_height;
2324 struct rect src;
2326 ID3D11Texture2D_GetDesc(engine->video_frame.d3d11.source, &source_desc);
2327 set_rect(&src, src_n->left * source_desc.Width, src_n->top * source_desc.Height,
2328 src_n->right * source_desc.Width, src_n->bottom * source_desc.Height);
2330 src_width = src.right - src.left;
2331 src_height = src.bottom - src.top;
2333 if (src_width * dst_height > dst_width * src_height)
2335 /* src is "wider" than dst. */
2336 float dst_center = (dst->top + dst->bottom) / 2.0f;
2337 float scaled_height = src_height * dst_width / src_width;
2339 dst->top = dst_center - scaled_height / 2.0f;
2340 dst->bottom = dst->top + scaled_height;
2342 else if (src_width * dst_height < dst_width * src_height)
2344 /* src is "taller" than dst. */
2345 float dst_center = (dst->left + dst->right) / 2.0f;
2346 float scaled_width = src_width * dst_height / src_height;
2348 dst->left = dst_center - scaled_width / 2.0f;
2349 dst->right = dst->left + scaled_width;
2353 static void media_engine_update_d3d11_frame_surface(ID3D11DeviceContext *context, struct media_engine *engine)
2355 D3D11_TEXTURE2D_DESC surface_desc;
2357 if (!(engine->flags & FLAGS_ENGINE_NEW_FRAME))
2358 return;
2360 ID3D11Texture2D_GetDesc(engine->video_frame.d3d11.source, &surface_desc);
2362 switch (surface_desc.Format)
2364 case DXGI_FORMAT_B8G8R8A8_UNORM:
2365 case DXGI_FORMAT_B8G8R8X8_UNORM:
2366 surface_desc.Width *= 4;
2367 break;
2368 default:
2369 FIXME("Unsupported format %#x.\n", surface_desc.Format);
2370 surface_desc.Width = 0;
2373 if (engine->video_frame.buffer_size == surface_desc.Width * surface_desc.Height)
2375 ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)engine->video_frame.d3d11.source,
2376 0, NULL, engine->video_frame.buffer, surface_desc.Width, 0);
2379 media_engine_set_flag(engine, FLAGS_ENGINE_NEW_FRAME, FALSE);
2382 static HRESULT media_engine_transfer_to_d3d11_texture(struct media_engine *engine, ID3D11Texture2D *texture,
2383 const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color)
2385 static const float black[] = {0.0f, 0.0f, 0.0f, 0.0f};
2386 ID3D11Device *device, *dst_device;
2387 ID3D11DeviceContext *context;
2388 ID3D11RenderTargetView *rtv;
2389 unsigned int stride, offset;
2390 D3D11_TEXTURE2D_DESC desc;
2391 BOOL device_mismatch;
2392 struct vec3 quad[4];
2393 D3D11_VIEWPORT vp;
2394 struct rect src, dst;
2395 struct color backcolor;
2396 HRESULT hr;
2397 RECT rect;
2399 if (FAILED(hr = media_engine_lock_d3d_device(engine, &device)))
2400 return hr;
2402 if (FAILED(hr = media_engine_create_d3d11_video_frame_resources(engine, device)))
2404 WARN("Failed to create d3d resources, hr %#lx.\n", hr);
2405 goto done;
2408 ID3D11Texture2D_GetDevice(texture, &dst_device);
2409 device_mismatch = device != dst_device;
2410 ID3D11Device_Release(dst_device);
2412 if (device_mismatch)
2414 WARN("Destination target from different device.\n");
2415 hr = E_UNEXPECTED;
2416 goto done;
2419 ID3D11Texture2D_GetDesc(texture, &desc);
2421 if (FAILED(hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)texture, NULL, &rtv)))
2423 WARN("Failed to create an rtv, hr %#lx.\n", hr);
2424 goto done;
2427 ID3D11Device_GetImmediateContext(device, &context);
2429 /* Whole destination is cleared, regardless of specified rectangle. */
2430 ID3D11DeviceContext_ClearRenderTargetView(context, rtv, black);
2432 if (dst_rect)
2434 rect.left = max(0, dst_rect->left);
2435 rect.top = max(0, dst_rect->top);
2436 rect.right = min(desc.Width, dst_rect->right);
2437 rect.bottom = min(desc.Height, dst_rect->bottom);
2439 quad[0].x = 2.0f * rect.left / desc.Width - 1.0f;
2440 quad[0].y = -2.0f * rect.bottom / desc.Height + 1.0f;
2441 quad[0].z = 0.0f;
2443 quad[1].x = quad[0].x;
2444 quad[1].y = -2.0f * rect.top / desc.Height + 1.0f;
2445 quad[1].z = 0.0f;
2447 quad[2].x = 2.0f * rect.right / desc.Width - 1.0f;
2448 quad[2].y = quad[0].y;
2449 quad[2].z = 0.0f;
2451 quad[3].x = quad[2].x;
2452 quad[3].y = quad[1].y;
2453 quad[3].z = 0.0f;
2455 set_rect(&dst, dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom);
2457 else
2459 memcpy(quad, fullquad, sizeof(quad));
2460 set_rect(&dst, 0.0f, 0.0f, desc.Width, desc.Height);
2463 if (src_rect)
2464 memcpy(&src, src_rect, sizeof(src));
2465 else
2466 set_rect(&src, 0.0f, 0.0f, 1.0f, 1.0f);
2468 media_engine_adjust_destination_for_ratio(engine, &src, &dst);
2470 if (memcmp(quad, engine->video_frame.d3d11.quad, sizeof(quad)))
2472 memcpy(engine->video_frame.d3d11.quad, quad, sizeof(quad));
2473 ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)engine->video_frame.d3d11.vb, 0, NULL, quad, 0, 0);
2476 if (color)
2478 backcolor.r = color->rgbRed / 255.0f;
2479 backcolor.g = color->rgbGreen / 255.0f;
2480 backcolor.b = color->rgbBlue / 255.0f;
2481 backcolor.a = color->rgbAlpha / 255.0f;
2483 else
2484 memcpy(&backcolor, black, sizeof(backcolor));
2486 if (memcmp(&dst, &engine->video_frame.d3d11.cb.dst, sizeof(dst)) ||
2487 memcmp(&src, &engine->video_frame.d3d11.cb.src, sizeof(src)) ||
2488 memcmp(&backcolor, &engine->video_frame.d3d11.cb.backcolor, sizeof(backcolor)))
2490 memcpy(&engine->video_frame.d3d11.cb.dst, &dst, sizeof(dst));
2491 memcpy(&engine->video_frame.d3d11.cb.src, &src, sizeof(src));
2492 memcpy(&engine->video_frame.d3d11.cb.backcolor, &backcolor, sizeof(backcolor));
2494 ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)engine->video_frame.d3d11.ps_cb, 0, NULL,
2495 &engine->video_frame.d3d11.cb, 0, 0);
2498 /* Update with new frame contents */
2499 media_engine_update_d3d11_frame_surface(context, engine);
2501 vp.TopLeftX = 0.0f;
2502 vp.TopLeftY = 0.0f;
2503 vp.Width = desc.Width;
2504 vp.Height = desc.Height;
2505 vp.MinDepth = 0.0f;
2506 vp.MaxDepth = 1.0f;
2507 ID3D11DeviceContext_RSSetViewports(context, 1, &vp);
2509 ID3D11DeviceContext_IASetInputLayout(context, engine->video_frame.d3d11.input_layout);
2510 ID3D11DeviceContext_IASetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
2511 stride = sizeof(*quad);
2512 offset = 0;
2513 ID3D11DeviceContext_IASetVertexBuffers(context, 0, 1, &engine->video_frame.d3d11.vb, &stride, &offset);
2514 ID3D11DeviceContext_VSSetShader(context, engine->video_frame.d3d11.vs, NULL, 0);
2515 ID3D11DeviceContext_PSSetShader(context, engine->video_frame.d3d11.ps, NULL, 0);
2516 ID3D11DeviceContext_PSSetShaderResources(context, 0, 1, &engine->video_frame.d3d11.srv);
2517 ID3D11DeviceContext_PSSetConstantBuffers(context, 0, 1, &engine->video_frame.d3d11.ps_cb);
2518 ID3D11DeviceContext_PSSetSamplers(context, 0, 1, &engine->video_frame.d3d11.sampler);
2519 ID3D11DeviceContext_OMSetRenderTargets(context, 1, &rtv, NULL);
2521 ID3D11DeviceContext_Draw(context, 4, 0);
2523 ID3D11RenderTargetView_Release(rtv);
2524 ID3D11DeviceContext_Release(context);
2526 done:
2527 media_engine_unlock_d3d_device(engine, device);
2529 return hr;
2532 static HRESULT WINAPI media_engine_TransferVideoFrame(IMFMediaEngineEx *iface, IUnknown *surface,
2533 const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color)
2535 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2536 ID3D11Texture2D *texture;
2537 HRESULT hr = E_NOINTERFACE;
2539 TRACE("%p, %p, %s, %s, %p.\n", iface, surface, src_rect ? wine_dbg_sprintf("(%f,%f)-(%f,%f)",
2540 src_rect->left, src_rect->top, src_rect->right, src_rect->bottom) : "(null)",
2541 wine_dbgstr_rect(dst_rect), color);
2543 EnterCriticalSection(&engine->cs);
2545 if (SUCCEEDED(IUnknown_QueryInterface(surface, &IID_ID3D11Texture2D, (void **)&texture)))
2547 hr = media_engine_transfer_to_d3d11_texture(engine, texture, src_rect, dst_rect, color);
2548 ID3D11Texture2D_Release(texture);
2550 else
2552 FIXME("Unsupported destination type.\n");
2555 LeaveCriticalSection(&engine->cs);
2557 return hr;
2560 static HRESULT WINAPI media_engine_OnVideoStreamTick(IMFMediaEngineEx *iface, LONGLONG *pts)
2562 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2563 HRESULT hr;
2565 TRACE("%p, %p.\n", iface, pts);
2567 EnterCriticalSection(&engine->cs);
2569 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2570 hr = MF_E_SHUTDOWN;
2571 else if (!pts)
2572 hr = E_POINTER;
2573 else
2575 *pts = engine->video_frame.pts;
2576 hr = *pts == MINLONGLONG ? S_FALSE : S_OK;
2579 LeaveCriticalSection(&engine->cs);
2581 return hr;
2584 static HRESULT WINAPI media_engine_SetSourceFromByteStream(IMFMediaEngineEx *iface, IMFByteStream *bytestream, BSTR url)
2586 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2587 HRESULT hr;
2589 TRACE("%p, %p, %s.\n", iface, bytestream, debugstr_w(url));
2591 EnterCriticalSection(&engine->cs);
2593 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2594 hr = MF_E_SHUTDOWN;
2595 else if (!bytestream || !url)
2596 hr = E_POINTER;
2597 else
2598 hr = media_engine_set_source(engine, bytestream, url);
2600 LeaveCriticalSection(&engine->cs);
2602 return hr;
2605 static HRESULT WINAPI media_engine_GetStatistics(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_STATISTIC stat_id, PROPVARIANT *stat)
2607 FIXME("%p, %x, %p stub.\n", iface, stat_id, stat);
2609 return E_NOTIMPL;
2612 static HRESULT WINAPI media_engine_UpdateVideoStream(IMFMediaEngineEx *iface, const MFVideoNormalizedRect *src,
2613 const RECT *dst, const MFARGB *border_color)
2615 FIXME("%p, %p, %p, %p stub.\n", iface, src, dst, border_color);
2617 return E_NOTIMPL;
2620 static double WINAPI media_engine_GetBalance(IMFMediaEngineEx *iface)
2622 FIXME("%p stub.\n", iface);
2624 return 0.0;
2627 static HRESULT WINAPI media_engine_SetBalance(IMFMediaEngineEx *iface, double balance)
2629 FIXME("%p, %f stub.\n", iface, balance);
2631 return E_NOTIMPL;
2634 static BOOL WINAPI media_engine_IsPlaybackRateSupported(IMFMediaEngineEx *iface, double rate)
2636 FIXME("%p, %f stub.\n", iface, rate);
2638 return FALSE;
2641 static HRESULT WINAPI media_engine_FrameStep(IMFMediaEngineEx *iface, BOOL forward)
2643 FIXME("%p, %d stub.\n", iface, forward);
2645 return E_NOTIMPL;
2648 static HRESULT WINAPI media_engine_GetResourceCharacteristics(IMFMediaEngineEx *iface, DWORD *flags)
2650 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2651 HRESULT hr = E_FAIL;
2653 TRACE("%p, %p.\n", iface, flags);
2655 EnterCriticalSection(&engine->cs);
2656 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2658 hr = MF_E_SHUTDOWN;
2660 else if (engine->presentation.source && flags)
2662 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(engine->presentation.source, flags)))
2664 *flags = *flags & 0xf;
2665 hr = S_OK;
2668 LeaveCriticalSection(&engine->cs);
2670 return hr;
2673 static HRESULT WINAPI media_engine_GetPresentationAttribute(IMFMediaEngineEx *iface, REFGUID attribute,
2674 PROPVARIANT *value)
2676 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2677 HRESULT hr = E_FAIL;
2679 TRACE("%p, %s, %p.\n", iface, debugstr_guid(attribute), value);
2681 EnterCriticalSection(&engine->cs);
2682 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2683 hr = MF_E_SHUTDOWN;
2684 else if (engine->presentation.pd)
2685 hr = IMFPresentationDescriptor_GetItem(engine->presentation.pd, attribute, value);
2686 LeaveCriticalSection(&engine->cs);
2688 return hr;
2691 static HRESULT WINAPI media_engine_GetNumberOfStreams(IMFMediaEngineEx *iface, DWORD *stream_count)
2693 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2694 HRESULT hr = E_FAIL;
2696 TRACE("%p, %p.\n", iface, stream_count);
2698 EnterCriticalSection(&engine->cs);
2699 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2700 hr = MF_E_SHUTDOWN;
2701 else if (engine->presentation.pd)
2702 hr = IMFPresentationDescriptor_GetStreamDescriptorCount(engine->presentation.pd, stream_count);
2703 LeaveCriticalSection(&engine->cs);
2705 return hr;
2708 static HRESULT WINAPI media_engine_GetStreamAttribute(IMFMediaEngineEx *iface, DWORD stream_index, REFGUID attribute,
2709 PROPVARIANT *value)
2711 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2712 IMFStreamDescriptor *sd;
2713 HRESULT hr = E_FAIL;
2714 BOOL selected;
2716 TRACE("%p, %ld, %s, %p.\n", iface, stream_index, debugstr_guid(attribute), value);
2718 EnterCriticalSection(&engine->cs);
2719 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2720 hr = MF_E_SHUTDOWN;
2721 else if (engine->presentation.pd)
2723 if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(engine->presentation.pd,
2724 stream_index, &selected, &sd)))
2726 hr = IMFStreamDescriptor_GetItem(sd, attribute, value);
2727 IMFStreamDescriptor_Release(sd);
2730 LeaveCriticalSection(&engine->cs);
2732 return hr;
2735 static HRESULT WINAPI media_engine_GetStreamSelection(IMFMediaEngineEx *iface, DWORD stream_index, BOOL *enabled)
2737 FIXME("%p, %ld, %p stub.\n", iface, stream_index, enabled);
2739 return E_NOTIMPL;
2742 static HRESULT WINAPI media_engine_SetStreamSelection(IMFMediaEngineEx *iface, DWORD stream_index, BOOL enabled)
2744 FIXME("%p, %ld, %d stub.\n", iface, stream_index, enabled);
2746 return E_NOTIMPL;
2749 static HRESULT WINAPI media_engine_ApplyStreamSelections(IMFMediaEngineEx *iface)
2751 FIXME("%p stub.\n", iface);
2753 return E_NOTIMPL;
2756 static HRESULT WINAPI media_engine_IsProtected(IMFMediaEngineEx *iface, BOOL *protected)
2758 FIXME("%p, %p stub.\n", iface, protected);
2760 return E_NOTIMPL;
2763 static HRESULT media_engine_insert_effect(struct media_engine *engine, struct effects *effects, IUnknown *object, BOOL is_optional)
2765 HRESULT hr = S_OK;
2767 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2768 hr = MF_E_SHUTDOWN;
2769 else if (!mf_array_reserve((void **)&effects->effects, &effects->capacity, effects->count + 1, sizeof(*effects->effects)))
2771 hr = E_OUTOFMEMORY;
2773 else
2775 effects->effects[effects->count].object = object;
2776 if (object)
2778 IUnknown_AddRef(effects->effects[effects->count].object);
2780 effects->effects[effects->count].optional = is_optional;
2782 effects->count++;
2785 return hr;
2788 static HRESULT WINAPI media_engine_InsertVideoEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional)
2790 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2791 HRESULT hr = S_OK;
2793 TRACE("%p, %p, %d.\n", iface, effect, is_optional);
2795 EnterCriticalSection(&engine->cs);
2796 hr = media_engine_insert_effect(engine, &engine->video_effects, effect, is_optional);
2797 LeaveCriticalSection(&engine->cs);
2799 return hr;
2802 static HRESULT WINAPI media_engine_InsertAudioEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional)
2804 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2805 HRESULT hr = S_OK;
2807 TRACE("%p, %p, %d.\n", iface, effect, is_optional);
2809 EnterCriticalSection(&engine->cs);
2810 hr = media_engine_insert_effect(engine, &engine->audio_effects, effect, is_optional);
2811 LeaveCriticalSection(&engine->cs);
2813 return hr;
2816 static HRESULT WINAPI media_engine_RemoveAllEffects(IMFMediaEngineEx *iface)
2818 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2819 HRESULT hr = S_OK;
2821 TRACE("%p.\n", iface);
2823 EnterCriticalSection(&engine->cs);
2824 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2825 hr = MF_E_SHUTDOWN;
2826 else
2828 media_engine_clear_effects(&engine->audio_effects);
2829 media_engine_clear_effects(&engine->video_effects);
2831 LeaveCriticalSection(&engine->cs);
2833 return hr;
2836 static HRESULT WINAPI media_engine_SetTimelineMarkerTimer(IMFMediaEngineEx *iface, double timeout)
2838 FIXME("%p, %f stub.\n", iface, timeout);
2840 return E_NOTIMPL;
2843 static HRESULT WINAPI media_engine_GetTimelineMarkerTimer(IMFMediaEngineEx *iface, double *timeout)
2845 FIXME("%p, %p stub.\n", iface, timeout);
2847 return E_NOTIMPL;
2850 static HRESULT WINAPI media_engine_CancelTimelineMarkerTimer(IMFMediaEngineEx *iface)
2852 FIXME("%p stub.\n", iface);
2854 return E_NOTIMPL;
2857 static BOOL WINAPI media_engine_IsStereo3D(IMFMediaEngineEx *iface)
2859 FIXME("%p stub.\n", iface);
2861 return FALSE;
2864 static HRESULT WINAPI media_engine_GetStereo3DFramePackingMode(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_S3D_PACKING_MODE *mode)
2866 FIXME("%p, %p stub.\n", iface, mode);
2868 return E_NOTIMPL;
2871 static HRESULT WINAPI media_engine_SetStereo3DFramePackingMode(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_S3D_PACKING_MODE mode)
2873 FIXME("%p, %#x stub.\n", iface, mode);
2875 return E_NOTIMPL;
2878 static HRESULT WINAPI media_engine_GetStereo3DRenderMode(IMFMediaEngineEx *iface, MF3DVideoOutputType *output_type)
2880 FIXME("%p, %p stub.\n", iface, output_type);
2882 return E_NOTIMPL;
2885 static HRESULT WINAPI media_engine_SetStereo3DRenderMode(IMFMediaEngineEx *iface, MF3DVideoOutputType output_type)
2887 FIXME("%p, %#x stub.\n", iface, output_type);
2889 return E_NOTIMPL;
2892 static HRESULT WINAPI media_engine_EnableWindowlessSwapchainMode(IMFMediaEngineEx *iface, BOOL enable)
2894 FIXME("%p, %d stub.\n", iface, enable);
2896 return E_NOTIMPL;
2899 static HRESULT WINAPI media_engine_GetVideoSwapchainHandle(IMFMediaEngineEx *iface, HANDLE *swapchain)
2901 FIXME("%p, %p stub.\n", iface, swapchain);
2903 return E_NOTIMPL;
2906 static HRESULT WINAPI media_engine_EnableHorizontalMirrorMode(IMFMediaEngineEx *iface, BOOL enable)
2908 FIXME("%p, %d stub.\n", iface, enable);
2910 return E_NOTIMPL;
2913 static HRESULT WINAPI media_engine_GetAudioStreamCategory(IMFMediaEngineEx *iface, UINT32 *category)
2915 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2916 HRESULT hr;
2918 TRACE("%p, %p.\n", iface, category);
2920 EnterCriticalSection(&engine->cs);
2922 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2923 hr = MF_E_SHUTDOWN;
2924 else
2925 hr = IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, category);
2927 LeaveCriticalSection(&engine->cs);
2929 return hr;
2932 static HRESULT WINAPI media_engine_SetAudioStreamCategory(IMFMediaEngineEx *iface, UINT32 category)
2934 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2935 HRESULT hr;
2937 TRACE("%p, %u.\n", iface, category);
2939 EnterCriticalSection(&engine->cs);
2941 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2942 hr = MF_E_SHUTDOWN;
2943 else
2944 hr = IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, category);
2946 LeaveCriticalSection(&engine->cs);
2948 return hr;
2951 static HRESULT WINAPI media_engine_GetAudioEndpointRole(IMFMediaEngineEx *iface, UINT32 *role)
2953 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2954 HRESULT hr;
2956 TRACE("%p, %p.\n", iface, role);
2958 EnterCriticalSection(&engine->cs);
2960 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2961 hr = MF_E_SHUTDOWN;
2962 else
2963 hr = IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, role);
2965 LeaveCriticalSection(&engine->cs);
2967 return hr;
2970 static HRESULT WINAPI media_engine_SetAudioEndpointRole(IMFMediaEngineEx *iface, UINT32 role)
2972 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2973 HRESULT hr;
2975 TRACE("%p, %u.\n", iface, role);
2977 EnterCriticalSection(&engine->cs);
2979 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2980 hr = MF_E_SHUTDOWN;
2981 else
2982 hr = IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, role);
2984 LeaveCriticalSection(&engine->cs);
2986 return hr;
2989 static HRESULT WINAPI media_engine_GetRealTimeMode(IMFMediaEngineEx *iface, BOOL *enabled)
2991 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2992 HRESULT hr = S_OK;
2994 TRACE("%p, %p.\n", iface, enabled);
2996 EnterCriticalSection(&engine->cs);
2997 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2998 hr = MF_E_SHUTDOWN;
2999 else
3000 *enabled = !!(engine->flags & MF_MEDIA_ENGINE_REAL_TIME_MODE);
3001 LeaveCriticalSection(&engine->cs);
3003 return hr;
3006 static HRESULT WINAPI media_engine_SetRealTimeMode(IMFMediaEngineEx *iface, BOOL enable)
3008 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
3009 HRESULT hr = S_OK;
3011 TRACE("%p, %d.\n", iface, enable);
3013 EnterCriticalSection(&engine->cs);
3014 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
3015 hr = MF_E_SHUTDOWN;
3016 else
3017 media_engine_set_flag(engine, MF_MEDIA_ENGINE_REAL_TIME_MODE, enable);
3018 LeaveCriticalSection(&engine->cs);
3020 return hr;
3023 static HRESULT WINAPI media_engine_SetCurrentTimeEx(IMFMediaEngineEx *iface, double seektime, MF_MEDIA_ENGINE_SEEK_MODE mode)
3025 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
3026 HRESULT hr;
3028 TRACE("%p, %f, %#x.\n", iface, seektime, mode);
3030 if (mode)
3031 FIXME("mode %#x is ignored.\n", mode);
3033 EnterCriticalSection(&engine->cs);
3035 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
3036 hr = MF_E_SHUTDOWN;
3037 else
3038 hr = media_engine_set_current_time(engine, seektime);
3040 LeaveCriticalSection(&engine->cs);
3042 return hr;
3045 static HRESULT WINAPI media_engine_EnableTimeUpdateTimer(IMFMediaEngineEx *iface, BOOL enable)
3047 FIXME("%p, %d stub.\n", iface, enable);
3049 return E_NOTIMPL;
3052 static const IMFMediaEngineExVtbl media_engine_vtbl =
3054 media_engine_QueryInterface,
3055 media_engine_AddRef,
3056 media_engine_Release,
3057 media_engine_GetError,
3058 media_engine_SetErrorCode,
3059 media_engine_SetSourceElements,
3060 media_engine_SetSource,
3061 media_engine_GetCurrentSource,
3062 media_engine_GetNetworkState,
3063 media_engine_GetPreload,
3064 media_engine_SetPreload,
3065 media_engine_GetBuffered,
3066 media_engine_Load,
3067 media_engine_CanPlayType,
3068 media_engine_GetReadyState,
3069 media_engine_IsSeeking,
3070 media_engine_GetCurrentTime,
3071 media_engine_SetCurrentTime,
3072 media_engine_GetStartTime,
3073 media_engine_GetDuration,
3074 media_engine_IsPaused,
3075 media_engine_GetDefaultPlaybackRate,
3076 media_engine_SetDefaultPlaybackRate,
3077 media_engine_GetPlaybackRate,
3078 media_engine_SetPlaybackRate,
3079 media_engine_GetPlayed,
3080 media_engine_GetSeekable,
3081 media_engine_IsEnded,
3082 media_engine_GetAutoPlay,
3083 media_engine_SetAutoPlay,
3084 media_engine_GetLoop,
3085 media_engine_SetLoop,
3086 media_engine_Play,
3087 media_engine_Pause,
3088 media_engine_GetMuted,
3089 media_engine_SetMuted,
3090 media_engine_GetVolume,
3091 media_engine_SetVolume,
3092 media_engine_HasVideo,
3093 media_engine_HasAudio,
3094 media_engine_GetNativeVideoSize,
3095 media_engine_GetVideoAspectRatio,
3096 media_engine_Shutdown,
3097 media_engine_TransferVideoFrame,
3098 media_engine_OnVideoStreamTick,
3099 media_engine_SetSourceFromByteStream,
3100 media_engine_GetStatistics,
3101 media_engine_UpdateVideoStream,
3102 media_engine_GetBalance,
3103 media_engine_SetBalance,
3104 media_engine_IsPlaybackRateSupported,
3105 media_engine_FrameStep,
3106 media_engine_GetResourceCharacteristics,
3107 media_engine_GetPresentationAttribute,
3108 media_engine_GetNumberOfStreams,
3109 media_engine_GetStreamAttribute,
3110 media_engine_GetStreamSelection,
3111 media_engine_SetStreamSelection,
3112 media_engine_ApplyStreamSelections,
3113 media_engine_IsProtected,
3114 media_engine_InsertVideoEffect,
3115 media_engine_InsertAudioEffect,
3116 media_engine_RemoveAllEffects,
3117 media_engine_SetTimelineMarkerTimer,
3118 media_engine_GetTimelineMarkerTimer,
3119 media_engine_CancelTimelineMarkerTimer,
3120 media_engine_IsStereo3D,
3121 media_engine_GetStereo3DFramePackingMode,
3122 media_engine_SetStereo3DFramePackingMode,
3123 media_engine_GetStereo3DRenderMode,
3124 media_engine_SetStereo3DRenderMode,
3125 media_engine_EnableWindowlessSwapchainMode,
3126 media_engine_GetVideoSwapchainHandle,
3127 media_engine_EnableHorizontalMirrorMode,
3128 media_engine_GetAudioStreamCategory,
3129 media_engine_SetAudioStreamCategory,
3130 media_engine_GetAudioEndpointRole,
3131 media_engine_SetAudioEndpointRole,
3132 media_engine_GetRealTimeMode,
3133 media_engine_SetRealTimeMode,
3134 media_engine_SetCurrentTimeEx,
3135 media_engine_EnableTimeUpdateTimer,
3138 static HRESULT WINAPI media_engine_gs_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
3140 struct media_engine *engine = impl_from_IMFGetService(iface);
3141 return IMFMediaEngineEx_QueryInterface(&engine->IMFMediaEngineEx_iface, riid, obj);
3144 static ULONG WINAPI media_engine_gs_AddRef(IMFGetService *iface)
3146 struct media_engine *engine = impl_from_IMFGetService(iface);
3147 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
3150 static ULONG WINAPI media_engine_gs_Release(IMFGetService *iface)
3152 struct media_engine *engine = impl_from_IMFGetService(iface);
3153 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
3156 static HRESULT WINAPI media_engine_gs_GetService(IMFGetService *iface, REFGUID service,
3157 REFIID riid, void **object)
3159 FIXME("%p, %s, %s, %p stub.\n", iface, debugstr_guid(service), debugstr_guid(riid), object);
3161 return E_NOTIMPL;
3164 static const IMFGetServiceVtbl media_engine_get_service_vtbl =
3166 media_engine_gs_QueryInterface,
3167 media_engine_gs_AddRef,
3168 media_engine_gs_Release,
3169 media_engine_gs_GetService,
3172 static HRESULT WINAPI media_engine_grabber_callback_QueryInterface(IMFSampleGrabberSinkCallback *iface,
3173 REFIID riid, void **obj)
3175 if (IsEqualIID(riid, &IID_IMFSampleGrabberSinkCallback) ||
3176 IsEqualIID(riid, &IID_IUnknown))
3178 *obj = iface;
3179 IMFSampleGrabberSinkCallback_AddRef(iface);
3180 return S_OK;
3183 *obj = NULL;
3184 return E_NOINTERFACE;
3187 static ULONG WINAPI media_engine_grabber_callback_AddRef(IMFSampleGrabberSinkCallback *iface)
3189 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
3190 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
3193 static ULONG WINAPI media_engine_grabber_callback_Release(IMFSampleGrabberSinkCallback *iface)
3195 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
3196 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
3199 static HRESULT WINAPI media_engine_grabber_callback_OnClockStart(IMFSampleGrabberSinkCallback *iface,
3200 MFTIME systime, LONGLONG start_offset)
3202 return S_OK;
3205 static HRESULT WINAPI media_engine_grabber_callback_OnClockStop(IMFSampleGrabberSinkCallback *iface,
3206 MFTIME systime)
3208 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
3210 EnterCriticalSection(&engine->cs);
3211 media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, FALSE);
3212 engine->video_frame.pts = MINLONGLONG;
3213 LeaveCriticalSection(&engine->cs);
3215 return S_OK;
3218 static HRESULT WINAPI media_engine_grabber_callback_OnClockPause(IMFSampleGrabberSinkCallback *iface,
3219 MFTIME systime)
3221 return S_OK;
3224 static HRESULT WINAPI media_engine_grabber_callback_OnClockRestart(IMFSampleGrabberSinkCallback *iface,
3225 MFTIME systime)
3227 return S_OK;
3230 static HRESULT WINAPI media_engine_grabber_callback_OnClockSetRate(IMFSampleGrabberSinkCallback *iface,
3231 MFTIME systime, float rate)
3233 return S_OK;
3236 static HRESULT WINAPI media_engine_grabber_callback_OnSetPresentationClock(IMFSampleGrabberSinkCallback *iface,
3237 IMFPresentationClock *clock)
3239 return S_OK;
3242 static HRESULT WINAPI media_engine_grabber_callback_OnProcessSample(IMFSampleGrabberSinkCallback *iface,
3243 REFGUID major_type, DWORD sample_flags, LONGLONG sample_time, LONGLONG sample_duration,
3244 const BYTE *buffer, DWORD buffer_size)
3246 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
3248 EnterCriticalSection(&engine->cs);
3250 if (!(engine->flags & FLAGS_ENGINE_FIRST_FRAME))
3252 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY, 0, 0);
3253 media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, TRUE);
3255 engine->video_frame.pts = sample_time;
3256 if (engine->video_frame.buffer_size < buffer_size)
3258 free(engine->video_frame.buffer);
3259 if ((engine->video_frame.buffer = malloc(buffer_size)))
3260 engine->video_frame.buffer_size = buffer_size;
3262 if (engine->video_frame.buffer)
3264 memcpy(engine->video_frame.buffer, buffer, buffer_size);
3265 engine->flags |= FLAGS_ENGINE_NEW_FRAME;
3268 LeaveCriticalSection(&engine->cs);
3270 return S_OK;
3273 static HRESULT WINAPI media_engine_grabber_callback_OnShutdown(IMFSampleGrabberSinkCallback *iface)
3275 return S_OK;
3278 static const IMFSampleGrabberSinkCallbackVtbl media_engine_grabber_callback_vtbl =
3280 media_engine_grabber_callback_QueryInterface,
3281 media_engine_grabber_callback_AddRef,
3282 media_engine_grabber_callback_Release,
3283 media_engine_grabber_callback_OnClockStart,
3284 media_engine_grabber_callback_OnClockStop,
3285 media_engine_grabber_callback_OnClockPause,
3286 media_engine_grabber_callback_OnClockRestart,
3287 media_engine_grabber_callback_OnClockSetRate,
3288 media_engine_grabber_callback_OnSetPresentationClock,
3289 media_engine_grabber_callback_OnProcessSample,
3290 media_engine_grabber_callback_OnShutdown,
3293 static HRESULT WINAPI media_engine_factory_QueryInterface(IMFMediaEngineClassFactory *iface, REFIID riid, void **obj)
3295 if (IsEqualIID(riid, &IID_IMFMediaEngineClassFactory) ||
3296 IsEqualIID(riid, &IID_IUnknown))
3298 *obj = iface;
3299 IMFMediaEngineClassFactory_AddRef(iface);
3300 return S_OK;
3303 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
3304 *obj = NULL;
3305 return E_NOINTERFACE;
3308 static ULONG WINAPI media_engine_factory_AddRef(IMFMediaEngineClassFactory *iface)
3310 return 2;
3313 static ULONG WINAPI media_engine_factory_Release(IMFMediaEngineClassFactory *iface)
3315 return 1;
3318 static HRESULT init_media_engine(DWORD flags, IMFAttributes *attributes, struct media_engine *engine)
3320 UINT32 output_format;
3321 UINT64 playback_hwnd;
3322 IMFClock *clock;
3323 HRESULT hr;
3325 engine->IMFMediaEngineEx_iface.lpVtbl = &media_engine_vtbl;
3326 engine->IMFGetService_iface.lpVtbl = &media_engine_get_service_vtbl;
3327 engine->session_events.lpVtbl = &media_engine_session_events_vtbl;
3328 engine->load_handler.lpVtbl = &media_engine_load_handler_vtbl;
3329 engine->grabber_callback.lpVtbl = &media_engine_grabber_callback_vtbl;
3330 engine->refcount = 1;
3331 engine->flags = (flags & MF_MEDIA_ENGINE_CREATEFLAGS_MASK) | FLAGS_ENGINE_PAUSED;
3332 engine->default_playback_rate = 1.0;
3333 engine->playback_rate = 1.0;
3334 engine->volume = 1.0;
3335 engine->duration = NAN;
3336 engine->video_frame.pts = MINLONGLONG;
3337 InitializeCriticalSection(&engine->cs);
3339 if (FAILED(hr = IMFAttributes_GetUnknown(attributes, &MF_MEDIA_ENGINE_CALLBACK, &IID_IMFMediaEngineNotify,
3340 (void **)&engine->callback)))
3342 WARN("Notification callback was not provided.\n");
3343 return hr;
3346 IMFAttributes_GetUnknown(attributes, &MF_MEDIA_ENGINE_EXTENSION, &IID_IMFMediaEngineExtension,
3347 (void **)&engine->extension);
3349 IMFAttributes_GetUnknown(attributes, &MF_MEDIA_ENGINE_DXGI_MANAGER, &IID_IMFDXGIDeviceManager,
3350 (void **)&engine->device_manager);
3352 if (FAILED(hr = MFCreateMediaSession(NULL, &engine->session)))
3353 return hr;
3355 if (FAILED(hr = IMFMediaSession_GetClock(engine->session, &clock)))
3356 return hr;
3358 hr = IMFClock_QueryInterface(clock, &IID_IMFPresentationClock, (void **)&engine->clock);
3359 IMFClock_Release(clock);
3360 if (FAILED(hr))
3361 return hr;
3363 if (FAILED(hr = IMFMediaSession_BeginGetEvent(engine->session, &engine->session_events, NULL)))
3364 return hr;
3366 if (FAILED(hr = MFCreateSourceResolver(&engine->resolver)))
3367 return hr;
3369 if (FAILED(hr = MFCreateAttributes(&engine->attributes, 0)))
3370 return hr;
3372 if (FAILED(hr = IMFAttributes_CopyAllItems(attributes, engine->attributes)))
3373 return hr;
3375 /* Set default audio configuration */
3376 if (FAILED(IMFAttributes_GetItem(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, NULL)))
3377 IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, AudioCategory_Other);
3378 if (FAILED(IMFAttributes_GetItem(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, NULL)))
3379 IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, eMultimedia);
3381 IMFAttributes_GetUINT64(attributes, &MF_MEDIA_ENGINE_PLAYBACK_HWND, &playback_hwnd);
3382 hr = IMFAttributes_GetUINT32(attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, &output_format);
3383 if (playback_hwnd) /* FIXME: handle MF_MEDIA_ENGINE_PLAYBACK_VISUAL */
3384 engine->mode = MEDIA_ENGINE_RENDERING_MODE;
3385 else
3387 if (SUCCEEDED(hr))
3388 engine->mode = MEDIA_ENGINE_FRAME_SERVER_MODE;
3389 else
3390 engine->mode = MEDIA_ENGINE_AUDIO_MODE;
3393 return S_OK;
3396 static HRESULT WINAPI media_engine_factory_CreateInstance(IMFMediaEngineClassFactory *iface, DWORD flags,
3397 IMFAttributes *attributes, IMFMediaEngine **engine)
3399 struct media_engine *object;
3400 HRESULT hr;
3402 TRACE("%p, %#lx, %p, %p.\n", iface, flags, attributes, engine);
3404 if (!attributes || !engine)
3405 return E_POINTER;
3407 object = calloc(1, sizeof(*object));
3408 if (!object)
3409 return E_OUTOFMEMORY;
3411 hr = init_media_engine(flags, attributes, object);
3412 if (FAILED(hr))
3414 free_media_engine(object);
3415 return hr;
3418 *engine = (IMFMediaEngine *)&object->IMFMediaEngineEx_iface;
3420 return S_OK;
3423 static HRESULT WINAPI media_engine_factory_CreateTimeRange(IMFMediaEngineClassFactory *iface,
3424 IMFMediaTimeRange **range)
3426 TRACE("%p, %p.\n", iface, range);
3428 return create_time_range(range);
3431 static HRESULT WINAPI media_engine_factory_CreateError(IMFMediaEngineClassFactory *iface, IMFMediaError **error)
3433 TRACE("%p, %p.\n", iface, error);
3435 return create_media_error(error);
3438 static const IMFMediaEngineClassFactoryVtbl media_engine_factory_vtbl =
3440 media_engine_factory_QueryInterface,
3441 media_engine_factory_AddRef,
3442 media_engine_factory_Release,
3443 media_engine_factory_CreateInstance,
3444 media_engine_factory_CreateTimeRange,
3445 media_engine_factory_CreateError,
3448 static IMFMediaEngineClassFactory media_engine_factory = { &media_engine_factory_vtbl };
3450 static HRESULT WINAPI classfactory_QueryInterface(IClassFactory *iface, REFIID riid, void **obj)
3452 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
3454 if (IsEqualGUID(riid, &IID_IClassFactory) ||
3455 IsEqualGUID(riid, &IID_IUnknown))
3457 IClassFactory_AddRef(iface);
3458 *obj = iface;
3459 return S_OK;
3462 WARN("interface %s not implemented.\n", debugstr_guid(riid));
3463 *obj = NULL;
3464 return E_NOINTERFACE;
3467 static ULONG WINAPI classfactory_AddRef(IClassFactory *iface)
3469 return 2;
3472 static ULONG WINAPI classfactory_Release(IClassFactory *iface)
3474 return 1;
3477 static HRESULT WINAPI classfactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **obj)
3479 TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), obj);
3481 *obj = NULL;
3483 if (outer)
3484 return CLASS_E_NOAGGREGATION;
3486 return IMFMediaEngineClassFactory_QueryInterface(&media_engine_factory, riid, obj);
3489 static HRESULT WINAPI classfactory_LockServer(IClassFactory *iface, BOOL dolock)
3491 FIXME("(%d): stub.\n", dolock);
3492 return S_OK;
3495 static const IClassFactoryVtbl class_factory_vtbl =
3497 classfactory_QueryInterface,
3498 classfactory_AddRef,
3499 classfactory_Release,
3500 classfactory_CreateInstance,
3501 classfactory_LockServer,
3504 static IClassFactory classfactory = { &class_factory_vtbl };
3506 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **obj)
3508 TRACE("%s, %s, %p.\n", debugstr_guid(clsid), debugstr_guid(riid), obj);
3510 if (IsEqualGUID(clsid, &CLSID_MFMediaEngineClassFactory))
3511 return IClassFactory_QueryInterface(&classfactory, riid, obj);
3513 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
3514 *obj = NULL;
3515 return CLASS_E_CLASSNOTAVAILABLE;