winewayland.drv: Update desktop window size on display changes.
[wine.git] / dlls / mfmediaengine / main.c
blobb3ac236c78e86a0277054958f160078d09883437
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 enum media_engine_mode
68 MEDIA_ENGINE_INVALID,
69 MEDIA_ENGINE_AUDIO_MODE,
70 MEDIA_ENGINE_RENDERING_MODE,
71 MEDIA_ENGINE_FRAME_SERVER_MODE,
74 /* Used with create flags. */
75 enum media_engine_flags
77 /* MF_MEDIA_ENGINE_CREATEFLAGS_MASK is 0x1f. */
78 FLAGS_ENGINE_SHUT_DOWN = 0x20,
79 FLAGS_ENGINE_AUTO_PLAY = 0x40,
80 FLAGS_ENGINE_LOOP = 0x80,
81 FLAGS_ENGINE_PAUSED = 0x100,
82 FLAGS_ENGINE_WAITING = 0x200,
83 FLAGS_ENGINE_MUTED = 0x400,
84 FLAGS_ENGINE_HAS_AUDIO = 0x800,
85 FLAGS_ENGINE_HAS_VIDEO = 0x1000,
86 FLAGS_ENGINE_FIRST_FRAME = 0x2000,
87 FLAGS_ENGINE_IS_ENDED = 0x4000,
88 FLAGS_ENGINE_NEW_FRAME = 0x8000,
89 FLAGS_ENGINE_SOURCE_PENDING = 0x10000,
90 FLAGS_ENGINE_PLAY_PENDING = 0x20000,
93 struct vec3
95 float x, y, z;
98 struct color
100 float r, g, b, a;
103 static const struct vec3 fullquad[] =
105 {-1.0f, -1.0f, 0.0f},
106 {-1.0f, 1.0f, 0.0f},
107 { 1.0f, -1.0f, 0.0f},
108 { 1.0f, 1.0f, 0.0f},
111 struct rect
113 float left, top, right, bottom;
116 struct media_engine
118 IMFMediaEngineEx IMFMediaEngineEx_iface;
119 IMFGetService IMFGetService_iface;
120 IMFAsyncCallback session_events;
121 IMFAsyncCallback load_handler;
122 IMFSampleGrabberSinkCallback grabber_callback;
123 LONG refcount;
124 IMFMediaEngineNotify *callback;
125 IMFAttributes *attributes;
126 IMFDXGIDeviceManager *device_manager;
127 HANDLE device_handle;
128 enum media_engine_mode mode;
129 unsigned int flags;
130 double playback_rate;
131 double default_playback_rate;
132 double volume;
133 double duration;
134 MF_MEDIA_ENGINE_NETWORK network_state;
135 MF_MEDIA_ENGINE_ERR error_code;
136 HRESULT extended_code;
137 MF_MEDIA_ENGINE_READY ready_state;
138 MF_MEDIA_ENGINE_PRELOAD preload;
139 IMFMediaSession *session;
140 IMFPresentationClock *clock;
141 IMFSourceResolver *resolver;
142 BSTR current_source;
143 struct
145 IMFMediaSource *source;
146 IMFPresentationDescriptor *pd;
147 } presentation;
148 struct
150 LONGLONG pts;
151 SIZE size;
152 SIZE ratio;
153 TOPOID node_id;
154 BYTE *buffer;
155 UINT buffer_size;
156 DXGI_FORMAT output_format;
158 struct
160 ID3D11Buffer *vb;
161 ID3D11Buffer *ps_cb;
162 ID3D11Texture2D *source;
163 ID3D11ShaderResourceView *srv;
164 ID3D11SamplerState *sampler;
165 ID3D11InputLayout *input_layout;
166 ID3D11VertexShader *vs;
167 ID3D11PixelShader *ps;
168 struct vec3 quad[4];
169 struct
171 struct rect dst;
172 struct rect src;
173 struct color backcolor;
174 } cb;
175 } d3d11;
176 } video_frame;
177 CRITICAL_SECTION cs;
180 static void media_engine_release_video_frame_resources(struct media_engine *engine)
182 if (engine->video_frame.d3d11.vb)
183 ID3D11Buffer_Release(engine->video_frame.d3d11.vb);
184 if (engine->video_frame.d3d11.ps_cb)
185 ID3D11Buffer_Release(engine->video_frame.d3d11.ps_cb);
186 if (engine->video_frame.d3d11.source)
187 ID3D11Texture2D_Release(engine->video_frame.d3d11.source);
188 if (engine->video_frame.d3d11.srv)
189 ID3D11ShaderResourceView_Release(engine->video_frame.d3d11.srv);
190 if (engine->video_frame.d3d11.sampler)
191 ID3D11SamplerState_Release(engine->video_frame.d3d11.sampler);
192 if (engine->video_frame.d3d11.input_layout)
193 ID3D11InputLayout_Release(engine->video_frame.d3d11.input_layout);
194 if (engine->video_frame.d3d11.vs)
195 ID3D11VertexShader_Release(engine->video_frame.d3d11.vs);
196 if (engine->video_frame.d3d11.ps)
197 ID3D11PixelShader_Release(engine->video_frame.d3d11.ps);
199 memset(&engine->video_frame.d3d11, 0, sizeof(engine->video_frame.d3d11));
200 memcpy(engine->video_frame.d3d11.quad, fullquad, sizeof(fullquad));
203 static HRESULT media_engine_lock_d3d_device(struct media_engine *engine, ID3D11Device **device)
205 HRESULT hr;
207 if (!engine->device_manager)
209 FIXME("Device manager wasn't set.\n");
210 return E_UNEXPECTED;
213 if (!engine->device_handle)
215 if (FAILED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(engine->device_manager, &engine->device_handle)))
217 WARN("Failed to open device handle, hr %#lx.\n", hr);
218 return hr;
222 hr = IMFDXGIDeviceManager_LockDevice(engine->device_manager, engine->device_handle, &IID_ID3D11Device,
223 (void **)device, TRUE);
224 if (hr == MF_E_DXGI_NEW_VIDEO_DEVICE)
226 IMFDXGIDeviceManager_CloseDeviceHandle(engine->device_manager, engine->device_handle);
227 engine->device_handle = NULL;
229 media_engine_release_video_frame_resources(engine);
231 if (FAILED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(engine->device_manager, &engine->device_handle)))
233 WARN("Failed to open a device handle, hr %#lx.\n", hr);
234 return hr;
236 hr = IMFDXGIDeviceManager_LockDevice(engine->device_manager, engine->device_handle, &IID_ID3D11Device,
237 (void **)device, TRUE);
240 return hr;
243 static void media_engine_unlock_d3d_device(struct media_engine *engine, ID3D11Device *device)
245 ID3D11Device_Release(device);
246 IMFDXGIDeviceManager_UnlockDevice(engine->device_manager, engine->device_handle, FALSE);
249 static HRESULT media_engine_create_d3d11_video_frame_resources(struct media_engine *engine, ID3D11Device *device)
251 static const D3D11_INPUT_ELEMENT_DESC layout_desc[] =
253 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
255 static const DWORD vs_code[] =
257 #if 0
258 float4 main(float4 position : POSITION) : SV_POSITION
260 return position;
262 #endif
263 0x43425844, 0xa7a2f22d, 0x83ff2560, 0xe61638bd, 0x87e3ce90, 0x00000001, 0x000000d8, 0x00000003,
264 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
265 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x49534f50, 0x4e4f4954, 0xababab00,
266 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, 0x00000003,
267 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x52444853, 0x0000003c, 0x00010040,
268 0x0000000f, 0x0300005f, 0x001010f2, 0x00000000, 0x04000067, 0x001020f2, 0x00000000, 0x00000001,
269 0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000000, 0x0100003e,
271 static const DWORD ps_code[] =
273 #if 0
274 Texture2D t;
275 SamplerState s;
276 float4 dst;
277 float4 src;
278 float4 backcolor;
280 float4 main(float4 position : SV_POSITION) : SV_TARGET
282 float2 p;
284 if (position.x < dst.x || position.x > dst.z) return backcolor;
285 if (position.y < dst.y || position.y > dst.w) return backcolor;
286 p.x = (position.x - dst.x) / (dst.z - dst.x);
287 p.y = (position.y - dst.y) / (dst.w - dst.y);
288 p.x = src.x + p.x * (src.z - src.x);
289 p.y = src.y + p.y * (src.w - src.y);
290 return t.Sample(s, p);
292 #endif
293 0x43425844, 0xae2162b7, 0x0fd69625, 0x6784c41a, 0x84ae95de, 0x00000001, 0x000002f8, 0x00000003,
294 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
295 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000030f, 0x505f5653, 0x5449534f, 0x004e4f49,
296 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
297 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054, 0x52444853, 0x0000025c, 0x00000040,
298 0x00000097, 0x04000059, 0x00208e46, 0x00000000, 0x00000003, 0x0300005a, 0x00106000, 0x00000000,
299 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x04002064, 0x00101032, 0x00000000, 0x00000001,
300 0x03000065, 0x001020f2, 0x00000000, 0x02000068, 0x00000002, 0x08000031, 0x00100012, 0x00000000,
301 0x0010100a, 0x00000000, 0x0020800a, 0x00000000, 0x00000000, 0x08000031, 0x00100022, 0x00000000,
302 0x0020802a, 0x00000000, 0x00000000, 0x0010100a, 0x00000000, 0x0700003c, 0x00100012, 0x00000000,
303 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x09000000, 0x00100062, 0x00000000, 0x00101106,
304 0x00000000, 0x80208106, 0x00000041, 0x00000000, 0x00000000, 0x0a000000, 0x00100032, 0x00000001,
305 0x80208046, 0x00000041, 0x00000000, 0x00000000, 0x00208ae6, 0x00000000, 0x00000000, 0x0700000e,
306 0x00100062, 0x00000000, 0x00100656, 0x00000000, 0x00100106, 0x00000001, 0x0a000000, 0x00100032,
307 0x00000001, 0x80208046, 0x00000041, 0x00000000, 0x00000001, 0x00208ae6, 0x00000000, 0x00000001,
308 0x0a000032, 0x00100062, 0x00000000, 0x00100656, 0x00000000, 0x00100106, 0x00000001, 0x00208106,
309 0x00000000, 0x00000001, 0x09000045, 0x001000f2, 0x00000001, 0x00100596, 0x00000000, 0x00107e46,
310 0x00000000, 0x00106000, 0x00000000, 0x0304001f, 0x0010000a, 0x00000000, 0x06000036, 0x001020f2,
311 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e, 0x01000015, 0x08000031, 0x00100012,
312 0x00000000, 0x0010101a, 0x00000000, 0x0020801a, 0x00000000, 0x00000000, 0x08000031, 0x00100022,
313 0x00000000, 0x0020803a, 0x00000000, 0x00000000, 0x0010101a, 0x00000000, 0x0700003c, 0x00100012,
314 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a, 0x00000000,
315 0x06000036, 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e, 0x01000015,
316 0x05000036, 0x001020f2, 0x00000000, 0x00100e46, 0x00000001, 0x0100003e,
318 D3D11_SUBRESOURCE_DATA resource_data;
319 D3D11_TEXTURE2D_DESC texture_desc;
320 D3D11_SAMPLER_DESC sampler_desc;
321 D3D11_BUFFER_DESC buffer_desc;
322 HRESULT hr;
324 if (engine->video_frame.d3d11.source)
325 return S_OK;
327 /* Default vertex buffer, updated on first transfer call. */
328 buffer_desc.ByteWidth = sizeof(engine->video_frame.d3d11.quad);
329 buffer_desc.Usage = D3D11_USAGE_DEFAULT;
330 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
331 buffer_desc.CPUAccessFlags = 0;
332 buffer_desc.MiscFlags = 0;
333 buffer_desc.StructureByteStride = 0;
335 resource_data.pSysMem = engine->video_frame.d3d11.quad;
336 resource_data.SysMemPitch = 0;
337 resource_data.SysMemSlicePitch = 0;
339 if (FAILED(hr = ID3D11Device_CreateBuffer(device, &buffer_desc, &resource_data, &engine->video_frame.d3d11.vb)))
341 WARN("Failed to create a vertex buffer, hr %#lx.\n", hr);
342 goto failed;
345 buffer_desc.ByteWidth = sizeof(engine->video_frame.d3d11.cb);
346 buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
348 if (FAILED(hr = ID3D11Device_CreateBuffer(device, &buffer_desc, NULL, &engine->video_frame.d3d11.ps_cb)))
350 WARN("Failed to create a buffer, hr %#lx.\n", hr);
351 goto failed;
354 /* Source texture. */
355 texture_desc.Width = engine->video_frame.size.cx;
356 texture_desc.Height = engine->video_frame.size.cy;
357 texture_desc.MipLevels = 1;
358 texture_desc.ArraySize = 1;
359 texture_desc.Format = engine->video_frame.output_format;
360 texture_desc.SampleDesc.Count = 1;
361 texture_desc.SampleDesc.Quality = 0;
362 texture_desc.Usage = D3D11_USAGE_DEFAULT;
363 texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
364 texture_desc.CPUAccessFlags = 0;
365 texture_desc.MiscFlags = 0;
367 if (FAILED(hr = ID3D11Device_CreateTexture2D(device, &texture_desc, NULL, &engine->video_frame.d3d11.source)))
369 WARN("Failed to create source texture, hr %#lx.\n", hr);
370 goto failed;
373 if (FAILED(hr = ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource *)engine->video_frame.d3d11.source,
374 NULL, &engine->video_frame.d3d11.srv)))
376 WARN("Failed to create SRV, hr %#lx.\n", hr);
377 goto failed;
380 /* Sampler state. */
381 memset(&sampler_desc, 0, sizeof(sampler_desc));
382 sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
383 sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
384 sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
385 sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
387 if (FAILED(hr = ID3D11Device_CreateSamplerState(device, &sampler_desc, &engine->video_frame.d3d11.sampler)))
389 WARN("Failed to create a sampler state, hr %#lx.\n", hr);
390 goto failed;
393 /* Input layout */
394 if (FAILED(hr = ID3D11Device_CreateInputLayout(device, layout_desc, ARRAY_SIZE(layout_desc), vs_code, sizeof(vs_code),
395 &engine->video_frame.d3d11.input_layout)))
397 WARN("Failed to create input layout, hr %#lx.\n", hr);
398 goto failed;
401 /* Shaders */
402 if (FAILED(hr = ID3D11Device_CreateVertexShader(device, vs_code, sizeof(vs_code), NULL, &engine->video_frame.d3d11.vs)))
404 WARN("Failed to create the vertex shader, hr %#lx.\n", hr);
405 goto failed;
408 if (FAILED(hr = ID3D11Device_CreatePixelShader(device, ps_code, sizeof(ps_code), NULL, &engine->video_frame.d3d11.ps)))
410 WARN("Failed to create the pixel shader, hr %#lx.\n", hr);
411 goto failed;
414 failed:
416 return hr;
419 struct range
421 double start;
422 double end;
425 struct time_range
427 IMFMediaTimeRange IMFMediaTimeRange_iface;
428 LONG refcount;
430 struct range *ranges;
431 size_t count;
432 size_t capacity;
435 static struct time_range *impl_from_IMFMediaTimeRange(IMFMediaTimeRange *iface)
437 return CONTAINING_RECORD(iface, struct time_range, IMFMediaTimeRange_iface);
440 struct media_error
442 IMFMediaError IMFMediaError_iface;
443 LONG refcount;
444 unsigned int code;
445 HRESULT extended_code;
448 static struct media_error *impl_from_IMFMediaError(IMFMediaError *iface)
450 return CONTAINING_RECORD(iface, struct media_error, IMFMediaError_iface);
453 static HRESULT WINAPI media_error_QueryInterface(IMFMediaError *iface, REFIID riid, void **obj)
455 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
457 if (IsEqualIID(riid, &IID_IMFMediaError) ||
458 IsEqualIID(riid, &IID_IUnknown))
460 *obj = iface;
461 IMFMediaError_AddRef(iface);
462 return S_OK;
465 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
466 *obj = NULL;
467 return E_NOINTERFACE;
470 static ULONG WINAPI media_error_AddRef(IMFMediaError *iface)
472 struct media_error *me = impl_from_IMFMediaError(iface);
473 ULONG refcount = InterlockedIncrement(&me->refcount);
475 TRACE("%p, refcount %lu.\n", iface, refcount);
477 return refcount;
480 static ULONG WINAPI media_error_Release(IMFMediaError *iface)
482 struct media_error *me = impl_from_IMFMediaError(iface);
483 ULONG refcount = InterlockedDecrement(&me->refcount);
485 TRACE("%p, refcount %lu.\n", iface, refcount);
487 if (!refcount)
488 free(me);
490 return refcount;
493 static USHORT WINAPI media_error_GetErrorCode(IMFMediaError *iface)
495 struct media_error *me = impl_from_IMFMediaError(iface);
496 TRACE("%p.\n", iface);
497 return me->code;
500 static HRESULT WINAPI media_error_GetExtendedErrorCode(IMFMediaError *iface)
502 struct media_error *me = impl_from_IMFMediaError(iface);
503 TRACE("%p.\n", iface);
504 return me->extended_code;
507 static HRESULT WINAPI media_error_SetErrorCode(IMFMediaError *iface, MF_MEDIA_ENGINE_ERR code)
509 struct media_error *me = impl_from_IMFMediaError(iface);
511 TRACE("%p, %u.\n", iface, code);
513 if ((unsigned int)code > MF_MEDIA_ENGINE_ERR_ENCRYPTED)
514 return E_INVALIDARG;
516 me->code = code;
518 return S_OK;
521 static HRESULT WINAPI media_error_SetExtendedErrorCode(IMFMediaError *iface, HRESULT code)
523 struct media_error *me = impl_from_IMFMediaError(iface);
525 TRACE("%p, %#lx.\n", iface, code);
527 me->extended_code = code;
529 return S_OK;
532 static const IMFMediaErrorVtbl media_error_vtbl =
534 media_error_QueryInterface,
535 media_error_AddRef,
536 media_error_Release,
537 media_error_GetErrorCode,
538 media_error_GetExtendedErrorCode,
539 media_error_SetErrorCode,
540 media_error_SetExtendedErrorCode,
543 static HRESULT create_media_error(IMFMediaError **ret)
545 struct media_error *object;
547 *ret = NULL;
549 if (!(object = calloc(1, sizeof(*object))))
550 return E_OUTOFMEMORY;
552 object->IMFMediaError_iface.lpVtbl = &media_error_vtbl;
553 object->refcount = 1;
555 *ret = &object->IMFMediaError_iface;
557 return S_OK;
560 static HRESULT WINAPI time_range_QueryInterface(IMFMediaTimeRange *iface, REFIID riid, void **obj)
562 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
564 if (IsEqualIID(riid, &IID_IMFMediaTimeRange) ||
565 IsEqualIID(riid, &IID_IUnknown))
567 *obj = iface;
568 IMFMediaTimeRange_AddRef(iface);
569 return S_OK;
572 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
573 *obj = NULL;
574 return E_NOINTERFACE;
577 static ULONG WINAPI time_range_AddRef(IMFMediaTimeRange *iface)
579 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
580 ULONG refcount = InterlockedIncrement(&range->refcount);
582 TRACE("%p, refcount %lu.\n", iface, refcount);
584 return refcount;
587 static ULONG WINAPI time_range_Release(IMFMediaTimeRange *iface)
589 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
590 ULONG refcount = InterlockedDecrement(&range->refcount);
592 TRACE("%p, refcount %lu.\n", iface, refcount);
594 if (!refcount)
596 free(range->ranges);
597 free(range);
600 return refcount;
603 static DWORD WINAPI time_range_GetLength(IMFMediaTimeRange *iface)
605 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
607 TRACE("%p.\n", iface);
609 return range->count;
612 static HRESULT WINAPI time_range_GetStart(IMFMediaTimeRange *iface, DWORD idx, double *start)
614 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
616 TRACE("%p, %lu, %p.\n", iface, idx, start);
618 if (idx >= range->count)
619 return E_INVALIDARG;
621 *start = range->ranges[idx].start;
623 return S_OK;
626 static HRESULT WINAPI time_range_GetEnd(IMFMediaTimeRange *iface, DWORD idx, double *end)
628 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
630 TRACE("%p, %lu, %p.\n", iface, idx, end);
632 if (idx >= range->count)
633 return E_INVALIDARG;
635 *end = range->ranges[idx].end;
637 return S_OK;
640 static BOOL WINAPI time_range_ContainsTime(IMFMediaTimeRange *iface, double time)
642 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
643 size_t i;
645 TRACE("%p, %.8e.\n", iface, time);
647 for (i = 0; i < range->count; ++i)
649 if (time >= range->ranges[i].start && time <= range->ranges[i].end)
650 return TRUE;
653 return FALSE;
656 static HRESULT WINAPI time_range_AddRange(IMFMediaTimeRange *iface, double start, double end)
658 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
659 struct range *c;
660 size_t i;
662 TRACE("%p, %.8e, %.8e.\n", iface, start, end);
664 for (i = 0; i < range->count; ++i)
666 c = &range->ranges[i];
668 /* New range is fully contained within existing one. */
669 if (c->start <= start && c->end >= end)
670 return S_OK;
672 /* New range fully contains existing one. */
673 if (c->start >= start && c->end <= end)
675 c->start = start;
676 c->end = end;
677 return S_OK;
680 /* Merge if ranges intersect. */
681 if ((start >= c->start && start <= c->end) ||
682 (end >= c->start && end <= c->end))
684 c->start = min(c->start, start);
685 c->end = max(c->end, end);
686 return S_OK;
690 if (!mf_array_reserve((void **)&range->ranges, &range->capacity, range->count + 1, sizeof(*range->ranges)))
691 return E_OUTOFMEMORY;
693 range->ranges[range->count].start = start;
694 range->ranges[range->count].end = end;
695 range->count++;
697 return S_OK;
700 static HRESULT WINAPI time_range_Clear(IMFMediaTimeRange *iface)
702 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
704 TRACE("%p.\n", iface);
706 range->count = 0;
708 return S_OK;
711 static const IMFMediaTimeRangeVtbl time_range_vtbl =
713 time_range_QueryInterface,
714 time_range_AddRef,
715 time_range_Release,
716 time_range_GetLength,
717 time_range_GetStart,
718 time_range_GetEnd,
719 time_range_ContainsTime,
720 time_range_AddRange,
721 time_range_Clear,
724 static HRESULT create_time_range(IMFMediaTimeRange **range)
726 struct time_range *object;
728 object = calloc(1, sizeof(*object));
729 if (!object)
730 return E_OUTOFMEMORY;
732 object->IMFMediaTimeRange_iface.lpVtbl = &time_range_vtbl;
733 object->refcount = 1;
735 *range = &object->IMFMediaTimeRange_iface;
737 return S_OK;
740 static void media_engine_set_flag(struct media_engine *engine, unsigned int mask, BOOL value)
742 if (value)
743 engine->flags |= mask;
744 else
745 engine->flags &= ~mask;
748 static inline struct media_engine *impl_from_IMFMediaEngineEx(IMFMediaEngineEx *iface)
750 return CONTAINING_RECORD(iface, struct media_engine, IMFMediaEngineEx_iface);
753 static inline struct media_engine *impl_from_IMFGetService(IMFGetService *iface)
755 return CONTAINING_RECORD(iface, struct media_engine, IMFGetService_iface);
758 static struct media_engine *impl_from_session_events_IMFAsyncCallback(IMFAsyncCallback *iface)
760 return CONTAINING_RECORD(iface, struct media_engine, session_events);
763 static struct media_engine *impl_from_load_handler_IMFAsyncCallback(IMFAsyncCallback *iface)
765 return CONTAINING_RECORD(iface, struct media_engine, load_handler);
768 static struct media_engine *impl_from_IMFSampleGrabberSinkCallback(IMFSampleGrabberSinkCallback *iface)
770 return CONTAINING_RECORD(iface, struct media_engine, grabber_callback);
773 static unsigned int get_gcd(unsigned int a, unsigned int b)
775 unsigned int m;
777 while (b)
779 m = a % b;
780 a = b;
781 b = m;
784 return a;
787 static void media_engine_get_frame_size(struct media_engine *engine, IMFTopology *topology)
789 IMFMediaTypeHandler *handler;
790 IMFMediaType *media_type;
791 IMFStreamDescriptor *sd;
792 IMFTopologyNode *node;
793 unsigned int gcd;
794 UINT64 size;
795 HRESULT hr;
797 engine->video_frame.size.cx = 0;
798 engine->video_frame.size.cy = 0;
799 engine->video_frame.ratio.cx = 1;
800 engine->video_frame.ratio.cy = 1;
802 if (FAILED(IMFTopology_GetNodeByID(topology, engine->video_frame.node_id, &node)))
803 return;
805 hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR,
806 &IID_IMFStreamDescriptor, (void **)&sd);
807 IMFTopologyNode_Release(node);
808 if (FAILED(hr))
809 return;
811 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
812 IMFStreamDescriptor_Release(sd);
813 if (FAILED(hr))
814 return;
816 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &media_type);
817 IMFMediaTypeHandler_Release(handler);
818 if (FAILED(hr))
820 WARN("Failed to get current media type %#lx.\n", hr);
821 return;
824 IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &size);
826 engine->video_frame.size.cx = size >> 32;
827 engine->video_frame.size.cy = size;
829 if ((gcd = get_gcd(engine->video_frame.size.cx, engine->video_frame.size.cy)))
831 engine->video_frame.ratio.cx = engine->video_frame.size.cx / gcd;
832 engine->video_frame.ratio.cy = engine->video_frame.size.cy / gcd;
835 IMFMediaType_Release(media_type);
838 static void media_engine_apply_volume(const struct media_engine *engine)
840 IMFSimpleAudioVolume *sa_volume;
841 HRESULT hr;
843 if (!engine->session)
844 return;
846 if (FAILED(MFGetService((IUnknown *)engine->session, &MR_POLICY_VOLUME_SERVICE, &IID_IMFSimpleAudioVolume, (void **)&sa_volume)))
847 return;
849 if (FAILED(hr = IMFSimpleAudioVolume_SetMasterVolume(sa_volume, engine->volume)))
850 WARN("Failed to set master volume, hr %#lx.\n", hr);
852 IMFSimpleAudioVolume_Release(sa_volume);
855 static HRESULT WINAPI media_engine_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
857 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
858 IsEqualIID(riid, &IID_IUnknown))
860 *obj = iface;
861 IMFAsyncCallback_AddRef(iface);
862 return S_OK;
865 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
866 *obj = NULL;
867 return E_NOINTERFACE;
870 static ULONG WINAPI media_engine_session_events_AddRef(IMFAsyncCallback *iface)
872 struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
873 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
876 static ULONG WINAPI media_engine_session_events_Release(IMFAsyncCallback *iface)
878 struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
879 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
882 static HRESULT WINAPI media_engine_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
884 return E_NOTIMPL;
887 static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
889 struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
890 IMFMediaEvent *event = NULL;
891 MediaEventType event_type;
892 HRESULT hr;
894 if (FAILED(hr = IMFMediaSession_EndGetEvent(engine->session, result, &event)))
896 WARN("Failed to get session event, hr %#lx.\n", hr);
897 goto failed;
900 if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type)))
902 WARN("Failed to get event type, hr %#lx.\n", hr);
903 goto failed;
906 switch (event_type)
908 case MEBufferingStarted:
909 case MEBufferingStopped:
911 IMFMediaEngineNotify_EventNotify(engine->callback, event_type == MEBufferingStarted ?
912 MF_MEDIA_ENGINE_EVENT_BUFFERINGSTARTED : MF_MEDIA_ENGINE_EVENT_BUFFERINGENDED, 0, 0);
913 break;
914 case MESessionTopologyStatus:
916 UINT32 topo_status = 0;
917 IMFTopology *topology;
918 PROPVARIANT value;
920 IMFMediaEvent_GetUINT32(event, &MF_EVENT_TOPOLOGY_STATUS, &topo_status);
921 if (topo_status != MF_TOPOSTATUS_READY)
922 break;
924 value.vt = VT_EMPTY;
925 if (FAILED(IMFMediaEvent_GetValue(event, &value)))
926 break;
928 if (value.vt != VT_UNKNOWN)
930 PropVariantClear(&value);
931 break;
934 topology = (IMFTopology *)value.punkVal;
936 EnterCriticalSection(&engine->cs);
938 media_engine_apply_volume(engine);
940 engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_METADATA;
942 media_engine_get_frame_size(engine, topology);
944 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE, 0, 0);
945 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA, 0, 0);
947 engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_ENOUGH_DATA;
949 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDDATA, 0, 0);
950 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_CANPLAY, 0, 0);
952 LeaveCriticalSection(&engine->cs);
954 PropVariantClear(&value);
956 break;
958 case MESessionStarted:
960 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAYING, 0, 0);
961 break;
962 case MESessionEnded:
964 EnterCriticalSection(&engine->cs);
965 media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, FALSE);
966 media_engine_set_flag(engine, FLAGS_ENGINE_IS_ENDED, TRUE);
967 engine->video_frame.pts = MINLONGLONG;
968 LeaveCriticalSection(&engine->cs);
970 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ENDED, 0, 0);
971 break;
974 failed:
976 if (event)
977 IMFMediaEvent_Release(event);
979 if (FAILED(hr = IMFMediaSession_BeginGetEvent(engine->session, iface, NULL)))
980 WARN("Failed to subscribe to session events, hr %#lx.\n", hr);
982 return S_OK;
985 static const IMFAsyncCallbackVtbl media_engine_session_events_vtbl =
987 media_engine_callback_QueryInterface,
988 media_engine_session_events_AddRef,
989 media_engine_session_events_Release,
990 media_engine_callback_GetParameters,
991 media_engine_session_events_Invoke,
994 static ULONG WINAPI media_engine_load_handler_AddRef(IMFAsyncCallback *iface)
996 struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
997 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
1000 static ULONG WINAPI media_engine_load_handler_Release(IMFAsyncCallback *iface)
1002 struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
1003 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
1006 static HRESULT media_engine_create_source_node(IMFMediaSource *source, IMFPresentationDescriptor *pd, IMFStreamDescriptor *sd,
1007 IMFTopologyNode **node)
1009 HRESULT hr;
1011 if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, node)))
1012 return hr;
1014 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_SOURCE, (IUnknown *)source);
1015 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)pd);
1016 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd);
1018 return S_OK;
1021 static HRESULT media_engine_create_audio_renderer(struct media_engine *engine, IMFTopologyNode **node)
1023 unsigned int category, role;
1024 IMFActivate *sar_activate;
1025 HRESULT hr;
1027 *node = NULL;
1029 if (FAILED(hr = MFCreateAudioRendererActivate(&sar_activate)))
1030 return hr;
1032 /* Configuration attributes keys differ between Engine and SAR. */
1033 if (SUCCEEDED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, &category)))
1034 IMFActivate_SetUINT32(sar_activate, &MF_AUDIO_RENDERER_ATTRIBUTE_STREAM_CATEGORY, category);
1035 if (SUCCEEDED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, &role)))
1036 IMFActivate_SetUINT32(sar_activate, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, role);
1038 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, node)))
1040 IMFTopologyNode_SetObject(*node, (IUnknown *)sar_activate);
1041 IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
1044 IMFActivate_Release(sar_activate);
1046 return hr;
1049 static HRESULT media_engine_create_video_renderer(struct media_engine *engine, IMFTopologyNode **node)
1051 DXGI_FORMAT output_format;
1052 IMFMediaType *media_type;
1053 IMFActivate *activate;
1054 GUID subtype;
1055 HRESULT hr;
1057 *node = NULL;
1059 if (FAILED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, &output_format)))
1061 WARN("Output format was not specified.\n");
1062 return E_FAIL;
1065 memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype));
1066 if (!(subtype.Data1 = MFMapDXGIFormatToDX9Format(output_format)))
1068 WARN("Unrecognized output format %#x.\n", output_format);
1069 return E_FAIL;
1072 if (FAILED(hr = MFCreateMediaType(&media_type)))
1073 return hr;
1075 IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video);
1076 IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &subtype);
1078 hr = MFCreateSampleGrabberSinkActivate(media_type, &engine->grabber_callback, &activate);
1079 IMFMediaType_Release(media_type);
1080 if (FAILED(hr))
1081 return hr;
1083 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, node)))
1085 IMFTopologyNode_SetObject(*node, (IUnknown *)activate);
1086 IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
1089 IMFActivate_Release(activate);
1091 engine->video_frame.output_format = output_format;
1093 return hr;
1096 static void media_engine_clear_presentation(struct media_engine *engine)
1098 if (engine->presentation.source)
1100 IMFMediaSource_Shutdown(engine->presentation.source);
1101 IMFMediaSource_Release(engine->presentation.source);
1103 if (engine->presentation.pd)
1104 IMFPresentationDescriptor_Release(engine->presentation.pd);
1105 memset(&engine->presentation, 0, sizeof(engine->presentation));
1108 static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMediaSource *source)
1110 IMFStreamDescriptor *sd_audio = NULL, *sd_video = NULL;
1111 IMFPresentationDescriptor *pd;
1112 DWORD stream_count = 0, i;
1113 IMFTopology *topology;
1114 UINT64 duration;
1115 HRESULT hr;
1117 media_engine_release_video_frame_resources(engine);
1118 media_engine_clear_presentation(engine);
1120 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd)))
1121 return hr;
1123 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(pd, &stream_count)))
1124 WARN("Failed to get stream count, hr %#lx.\n", hr);
1126 /* Enable first video stream and first audio stream. */
1128 for (i = 0; i < stream_count; ++i)
1130 IMFMediaTypeHandler *type_handler;
1131 IMFStreamDescriptor *sd;
1132 BOOL selected;
1134 IMFPresentationDescriptor_DeselectStream(pd, i);
1136 if (sd_audio && sd_video)
1137 continue;
1139 IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, i, &selected, &sd);
1141 if (SUCCEEDED(IMFStreamDescriptor_GetMediaTypeHandler(sd, &type_handler)))
1143 GUID major = { 0 };
1145 IMFMediaTypeHandler_GetMajorType(type_handler, &major);
1147 if (IsEqualGUID(&major, &MFMediaType_Audio) && !sd_audio)
1149 sd_audio = sd;
1150 IMFStreamDescriptor_AddRef(sd_audio);
1151 IMFPresentationDescriptor_SelectStream(pd, i);
1153 else if (IsEqualGUID(&major, &MFMediaType_Video) && !sd_video && !(engine->flags & MF_MEDIA_ENGINE_AUDIOONLY))
1155 sd_video = sd;
1156 IMFStreamDescriptor_AddRef(sd_video);
1157 IMFPresentationDescriptor_SelectStream(pd, i);
1160 IMFMediaTypeHandler_Release(type_handler);
1163 IMFStreamDescriptor_Release(sd);
1166 if (!sd_video && !sd_audio)
1168 IMFPresentationDescriptor_Release(pd);
1169 return E_UNEXPECTED;
1172 engine->presentation.source = source;
1173 IMFMediaSource_AddRef(engine->presentation.source);
1174 engine->presentation.pd = pd;
1175 IMFPresentationDescriptor_AddRef(engine->presentation.pd);
1177 media_engine_set_flag(engine, FLAGS_ENGINE_HAS_VIDEO, !!sd_video);
1178 media_engine_set_flag(engine, FLAGS_ENGINE_HAS_AUDIO, !!sd_audio);
1180 /* Assume live source if duration was not provided. */
1181 if (SUCCEEDED(IMFPresentationDescriptor_GetUINT64(pd, &MF_PD_DURATION, &duration)))
1183 /* Convert 100ns to seconds. */
1184 engine->duration = duration / 10000000;
1186 else
1187 engine->duration = INFINITY;
1189 if (SUCCEEDED(hr = MFCreateTopology(&topology)))
1191 IMFTopologyNode *sar_node = NULL, *audio_src = NULL;
1192 IMFTopologyNode *grabber_node = NULL, *video_src = NULL;
1194 if (engine->flags & MF_MEDIA_ENGINE_REAL_TIME_MODE)
1195 IMFTopology_SetUINT32(topology, &MF_LOW_LATENCY, TRUE);
1197 if (sd_audio)
1199 if (FAILED(hr = media_engine_create_source_node(source, pd, sd_audio, &audio_src)))
1200 WARN("Failed to create audio source node, hr %#lx.\n", hr);
1202 if (FAILED(hr = media_engine_create_audio_renderer(engine, &sar_node)))
1203 WARN("Failed to create audio renderer node, hr %#lx.\n", hr);
1205 if (sar_node && audio_src)
1207 IMFTopology_AddNode(topology, audio_src);
1208 IMFTopology_AddNode(topology, sar_node);
1209 IMFTopologyNode_ConnectOutput(audio_src, 0, sar_node, 0);
1212 if (sar_node)
1213 IMFTopologyNode_Release(sar_node);
1214 if (audio_src)
1215 IMFTopologyNode_Release(audio_src);
1218 if (SUCCEEDED(hr) && sd_video)
1220 if (FAILED(hr = media_engine_create_source_node(source, pd, sd_video, &video_src)))
1221 WARN("Failed to create video source node, hr %#lx.\n", hr);
1223 if (FAILED(hr = media_engine_create_video_renderer(engine, &grabber_node)))
1224 WARN("Failed to create video grabber node, hr %#lx.\n", hr);
1226 if (grabber_node && video_src)
1228 IMFTopology_AddNode(topology, video_src);
1229 IMFTopology_AddNode(topology, grabber_node);
1230 IMFTopologyNode_ConnectOutput(video_src, 0, grabber_node, 0);
1233 if (SUCCEEDED(hr))
1234 IMFTopologyNode_GetTopoNodeID(video_src, &engine->video_frame.node_id);
1236 if (grabber_node)
1237 IMFTopologyNode_Release(grabber_node);
1238 if (video_src)
1239 IMFTopologyNode_Release(video_src);
1242 IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, TRUE);
1244 if (SUCCEEDED(hr))
1245 hr = IMFMediaSession_SetTopology(engine->session, MFSESSION_SETTOPOLOGY_IMMEDIATE, topology);
1248 if (topology)
1249 IMFTopology_Release(topology);
1251 if (sd_video)
1252 IMFStreamDescriptor_Release(sd_video);
1253 if (sd_audio)
1254 IMFStreamDescriptor_Release(sd_audio);
1256 IMFPresentationDescriptor_Release(pd);
1258 return hr;
1261 static void media_engine_start_playback(struct media_engine *engine)
1263 PROPVARIANT var;
1265 var.vt = VT_EMPTY;
1266 IMFMediaSession_Start(engine->session, &GUID_NULL, &var);
1269 static HRESULT WINAPI media_engine_load_handler_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1271 struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
1272 IUnknown *object = NULL, *state;
1273 unsigned int start_playback;
1274 MF_OBJECT_TYPE obj_type;
1275 IMFMediaSource *source;
1276 HRESULT hr;
1278 EnterCriticalSection(&engine->cs);
1280 engine->network_state = MF_MEDIA_ENGINE_NETWORK_LOADING;
1281 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADSTART, 0, 0);
1283 start_playback = engine->flags & FLAGS_ENGINE_PLAY_PENDING;
1284 media_engine_set_flag(engine, FLAGS_ENGINE_SOURCE_PENDING | FLAGS_ENGINE_PLAY_PENDING, FALSE);
1286 if (SUCCEEDED(IMFAsyncResult_GetState(result, &state)))
1288 hr = IMFSourceResolver_EndCreateObjectFromByteStream(engine->resolver, result, &obj_type, &object);
1289 IUnknown_Release(state);
1291 else
1292 hr = IMFSourceResolver_EndCreateObjectFromURL(engine->resolver, result, &obj_type, &object);
1294 if (FAILED(hr))
1295 WARN("Failed to create source object, hr %#lx.\n", hr);
1297 if (object)
1299 if (SUCCEEDED(hr = IUnknown_QueryInterface(object, &IID_IMFMediaSource, (void **)&source)))
1301 hr = media_engine_create_topology(engine, source);
1302 IMFMediaSource_Release(source);
1304 IUnknown_Release(object);
1307 if (SUCCEEDED(hr))
1309 engine->network_state = MF_MEDIA_ENGINE_NETWORK_IDLE;
1310 if (start_playback)
1311 media_engine_start_playback(engine);
1313 else
1315 engine->network_state = MF_MEDIA_ENGINE_NETWORK_NO_SOURCE;
1316 engine->error_code = MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED;
1317 engine->extended_code = hr;
1318 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ERROR, engine->error_code,
1319 engine->extended_code);
1322 LeaveCriticalSection(&engine->cs);
1324 return S_OK;
1327 static const IMFAsyncCallbackVtbl media_engine_load_handler_vtbl =
1329 media_engine_callback_QueryInterface,
1330 media_engine_load_handler_AddRef,
1331 media_engine_load_handler_Release,
1332 media_engine_callback_GetParameters,
1333 media_engine_load_handler_Invoke,
1336 static HRESULT WINAPI media_engine_QueryInterface(IMFMediaEngineEx *iface, REFIID riid, void **obj)
1338 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1340 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1342 if (IsEqualIID(riid, &IID_IMFMediaEngineEx) ||
1343 IsEqualIID(riid, &IID_IMFMediaEngine) ||
1344 IsEqualIID(riid, &IID_IUnknown))
1346 *obj = iface;
1348 else if (IsEqualIID(riid, &IID_IMFGetService))
1350 *obj = &engine->IMFGetService_iface;
1352 else
1354 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1355 *obj = NULL;
1356 return E_NOINTERFACE;
1359 IUnknown_AddRef((IUnknown *)*obj);
1360 return S_OK;
1363 static ULONG WINAPI media_engine_AddRef(IMFMediaEngineEx *iface)
1365 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1366 ULONG refcount = InterlockedIncrement(&engine->refcount);
1368 TRACE("%p, refcount %lu.\n", iface, refcount);
1370 return refcount;
1373 static void free_media_engine(struct media_engine *engine)
1375 if (engine->callback)
1376 IMFMediaEngineNotify_Release(engine->callback);
1377 if (engine->clock)
1378 IMFPresentationClock_Release(engine->clock);
1379 if (engine->session)
1380 IMFMediaSession_Release(engine->session);
1381 if (engine->attributes)
1382 IMFAttributes_Release(engine->attributes);
1383 if (engine->resolver)
1384 IMFSourceResolver_Release(engine->resolver);
1385 media_engine_release_video_frame_resources(engine);
1386 media_engine_clear_presentation(engine);
1387 if (engine->device_manager)
1389 IMFDXGIDeviceManager_CloseDeviceHandle(engine->device_manager, engine->device_handle);
1390 IMFDXGIDeviceManager_Release(engine->device_manager);
1392 SysFreeString(engine->current_source);
1393 DeleteCriticalSection(&engine->cs);
1394 free(engine->video_frame.buffer);
1395 free(engine);
1398 static ULONG WINAPI media_engine_Release(IMFMediaEngineEx *iface)
1400 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1401 ULONG refcount = InterlockedDecrement(&engine->refcount);
1403 TRACE("%p, refcount %lu.\n", iface, refcount);
1405 if (!refcount)
1406 free_media_engine(engine);
1408 return refcount;
1411 static HRESULT WINAPI media_engine_GetError(IMFMediaEngineEx *iface, IMFMediaError **error)
1413 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1414 HRESULT hr = S_OK;
1416 TRACE("%p, %p.\n", iface, error);
1418 *error = NULL;
1420 EnterCriticalSection(&engine->cs);
1421 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1422 hr = MF_E_SHUTDOWN;
1423 else if (engine->error_code)
1425 if (SUCCEEDED(hr = create_media_error(error)))
1427 IMFMediaError_SetErrorCode(*error, engine->error_code);
1428 IMFMediaError_SetExtendedErrorCode(*error, engine->extended_code);
1431 LeaveCriticalSection(&engine->cs);
1433 return hr;
1436 static HRESULT WINAPI media_engine_SetErrorCode(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_ERR code)
1438 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1439 HRESULT hr = S_OK;
1441 TRACE("%p, %u.\n", iface, code);
1443 if ((unsigned int)code > MF_MEDIA_ENGINE_ERR_ENCRYPTED)
1444 return E_INVALIDARG;
1446 EnterCriticalSection(&engine->cs);
1447 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1448 hr = MF_E_SHUTDOWN;
1449 else
1450 engine->error_code = code;
1451 LeaveCriticalSection(&engine->cs);
1453 return hr;
1456 static HRESULT WINAPI media_engine_SetSourceElements(IMFMediaEngineEx *iface, IMFMediaEngineSrcElements *elements)
1458 FIXME("(%p, %p): stub.\n", iface, elements);
1460 return E_NOTIMPL;
1463 static HRESULT media_engine_set_source(struct media_engine *engine, IMFByteStream *bytestream, BSTR url)
1465 IPropertyStore *props = NULL;
1466 unsigned int flags;
1467 HRESULT hr = S_OK;
1469 SysFreeString(engine->current_source);
1470 engine->current_source = NULL;
1471 if (url)
1472 engine->current_source = SysAllocString(url);
1474 engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_NOTHING;
1476 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
1478 engine->network_state = MF_MEDIA_ENGINE_NETWORK_NO_SOURCE;
1480 if (url || bytestream)
1482 flags = MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE;
1483 if (engine->flags & MF_MEDIA_ENGINE_DISABLE_LOCAL_PLUGINS)
1484 flags |= MF_RESOLUTION_DISABLE_LOCAL_PLUGINS;
1486 IMFAttributes_GetUnknown(engine->attributes, &MF_MEDIA_ENGINE_SOURCE_RESOLVER_CONFIG_STORE,
1487 &IID_IPropertyStore, (void **)&props);
1488 if (bytestream)
1489 hr = IMFSourceResolver_BeginCreateObjectFromByteStream(engine->resolver, bytestream, url, flags,
1490 props, NULL, &engine->load_handler, (IUnknown *)bytestream);
1491 else
1492 hr = IMFSourceResolver_BeginCreateObjectFromURL(engine->resolver, url, flags, props, NULL,
1493 &engine->load_handler, NULL);
1494 if (SUCCEEDED(hr))
1495 media_engine_set_flag(engine, FLAGS_ENGINE_SOURCE_PENDING, TRUE);
1497 if (props)
1498 IPropertyStore_Release(props);
1501 return hr;
1504 static HRESULT WINAPI media_engine_SetSource(IMFMediaEngineEx *iface, BSTR url)
1506 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1507 HRESULT hr;
1509 TRACE("%p, %s.\n", iface, debugstr_w(url));
1511 EnterCriticalSection(&engine->cs);
1513 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1514 hr = MF_E_SHUTDOWN;
1515 else
1516 hr = media_engine_set_source(engine, NULL, url);
1518 LeaveCriticalSection(&engine->cs);
1520 return hr;
1523 static HRESULT WINAPI media_engine_GetCurrentSource(IMFMediaEngineEx *iface, BSTR *url)
1525 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1526 HRESULT hr = S_OK;
1528 TRACE("%p, %p.\n", iface, url);
1530 *url = NULL;
1532 EnterCriticalSection(&engine->cs);
1534 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1535 hr = MF_E_SHUTDOWN;
1536 if (engine->current_source)
1538 if (!(*url = SysAllocString(engine->current_source)))
1539 hr = E_OUTOFMEMORY;
1542 LeaveCriticalSection(&engine->cs);
1544 return hr;
1547 static USHORT WINAPI media_engine_GetNetworkState(IMFMediaEngineEx *iface)
1549 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1551 TRACE("%p.\n", iface);
1553 return engine->network_state;
1556 static MF_MEDIA_ENGINE_PRELOAD WINAPI media_engine_GetPreload(IMFMediaEngineEx *iface)
1558 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1559 MF_MEDIA_ENGINE_PRELOAD preload;
1561 TRACE("%p.\n", iface);
1563 EnterCriticalSection(&engine->cs);
1564 preload = engine->preload;
1565 LeaveCriticalSection(&engine->cs);
1567 return preload;
1570 static HRESULT WINAPI media_engine_SetPreload(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_PRELOAD preload)
1572 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1574 TRACE("%p, %d.\n", iface, preload);
1576 EnterCriticalSection(&engine->cs);
1577 engine->preload = preload;
1578 LeaveCriticalSection(&engine->cs);
1580 return S_OK;
1583 static HRESULT WINAPI media_engine_GetBuffered(IMFMediaEngineEx *iface, IMFMediaTimeRange **range)
1585 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1586 HRESULT hr;
1588 TRACE("%p, %p.\n", iface, range);
1590 if (FAILED(hr = create_time_range(range)))
1591 return hr;
1593 EnterCriticalSection(&engine->cs);
1595 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1596 hr = MF_E_SHUTDOWN;
1597 else if (!isnan(engine->duration))
1598 hr = IMFMediaTimeRange_AddRange(*range, 0.0, engine->duration);
1600 LeaveCriticalSection(&engine->cs);
1602 return hr;
1605 static HRESULT WINAPI media_engine_Load(IMFMediaEngineEx *iface)
1607 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1608 HRESULT hr = E_NOTIMPL;
1610 FIXME("(%p): stub.\n", iface);
1612 EnterCriticalSection(&engine->cs);
1614 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1615 hr = MF_E_SHUTDOWN;
1617 LeaveCriticalSection(&engine->cs);
1619 return hr;
1622 static HRESULT WINAPI media_engine_CanPlayType(IMFMediaEngineEx *iface, BSTR type, MF_MEDIA_ENGINE_CANPLAY *answer)
1624 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1625 HRESULT hr = E_NOTIMPL;
1627 FIXME("(%p, %s, %p): stub.\n", iface, debugstr_w(type), answer);
1629 EnterCriticalSection(&engine->cs);
1631 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1632 hr = MF_E_SHUTDOWN;
1634 LeaveCriticalSection(&engine->cs);
1636 return hr;
1639 static USHORT WINAPI media_engine_GetReadyState(IMFMediaEngineEx *iface)
1641 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1642 unsigned short state;
1644 TRACE("%p.\n", iface);
1646 EnterCriticalSection(&engine->cs);
1647 state = engine->ready_state;
1648 LeaveCriticalSection(&engine->cs);
1650 return state;
1653 static BOOL WINAPI media_engine_IsSeeking(IMFMediaEngineEx *iface)
1655 FIXME("(%p): stub.\n", iface);
1657 return FALSE;
1660 static double WINAPI media_engine_GetCurrentTime(IMFMediaEngineEx *iface)
1662 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1663 double ret = 0.0;
1664 MFTIME clocktime;
1666 TRACE("%p.\n", iface);
1668 EnterCriticalSection(&engine->cs);
1669 if (engine->flags & FLAGS_ENGINE_IS_ENDED)
1671 ret = engine->duration;
1673 else if (SUCCEEDED(IMFPresentationClock_GetTime(engine->clock, &clocktime)))
1675 ret = (double)clocktime / 10000000.0;
1677 LeaveCriticalSection(&engine->cs);
1679 return ret;
1682 static HRESULT WINAPI media_engine_SetCurrentTime(IMFMediaEngineEx *iface, double time)
1684 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1685 HRESULT hr = E_NOTIMPL;
1687 FIXME("(%p, %f): stub.\n", iface, time);
1689 EnterCriticalSection(&engine->cs);
1691 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1692 hr = MF_E_SHUTDOWN;
1694 LeaveCriticalSection(&engine->cs);
1696 return hr;
1699 static double WINAPI media_engine_GetStartTime(IMFMediaEngineEx *iface)
1701 FIXME("(%p): stub.\n", iface);
1703 return 0.0;
1706 static double WINAPI media_engine_GetDuration(IMFMediaEngineEx *iface)
1708 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1709 double value;
1711 TRACE("%p.\n", iface);
1713 EnterCriticalSection(&engine->cs);
1714 value = engine->duration;
1715 LeaveCriticalSection(&engine->cs);
1717 return value;
1720 static BOOL WINAPI media_engine_IsPaused(IMFMediaEngineEx *iface)
1722 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1723 BOOL value;
1725 TRACE("%p.\n", iface);
1727 EnterCriticalSection(&engine->cs);
1728 value = !!(engine->flags & FLAGS_ENGINE_PAUSED);
1729 LeaveCriticalSection(&engine->cs);
1731 return value;
1734 static double WINAPI media_engine_GetDefaultPlaybackRate(IMFMediaEngineEx *iface)
1736 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1737 double rate;
1739 TRACE("%p.\n", iface);
1741 EnterCriticalSection(&engine->cs);
1742 rate = engine->default_playback_rate;
1743 LeaveCriticalSection(&engine->cs);
1745 return rate;
1748 static HRESULT WINAPI media_engine_SetDefaultPlaybackRate(IMFMediaEngineEx *iface, double rate)
1750 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1751 HRESULT hr = S_OK;
1753 TRACE("%p, %f.\n", iface, rate);
1755 EnterCriticalSection(&engine->cs);
1756 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1757 hr = MF_E_SHUTDOWN;
1758 else if (engine->default_playback_rate != rate)
1760 engine->default_playback_rate = rate;
1761 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_RATECHANGE, 0, 0);
1763 LeaveCriticalSection(&engine->cs);
1765 return hr;
1768 static double WINAPI media_engine_GetPlaybackRate(IMFMediaEngineEx *iface)
1770 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1771 double rate;
1773 TRACE("%p.\n", iface);
1775 EnterCriticalSection(&engine->cs);
1776 rate = engine->playback_rate;
1777 LeaveCriticalSection(&engine->cs);
1779 return rate;
1782 static HRESULT WINAPI media_engine_SetPlaybackRate(IMFMediaEngineEx *iface, double rate)
1784 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1785 HRESULT hr = S_OK;
1787 TRACE("%p, %f.\n", iface, rate);
1789 EnterCriticalSection(&engine->cs);
1790 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1791 hr = MF_E_SHUTDOWN;
1792 else if (engine->playback_rate != rate)
1794 engine->playback_rate = rate;
1795 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_RATECHANGE, 0, 0);
1797 LeaveCriticalSection(&engine->cs);
1799 return hr;
1802 static HRESULT WINAPI media_engine_GetPlayed(IMFMediaEngineEx *iface, IMFMediaTimeRange **played)
1804 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1805 HRESULT hr = E_NOTIMPL;
1807 FIXME("(%p, %p): stub.\n", iface, played);
1809 EnterCriticalSection(&engine->cs);
1811 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1812 hr = MF_E_SHUTDOWN;
1814 LeaveCriticalSection(&engine->cs);
1816 return hr;
1819 static HRESULT WINAPI media_engine_GetSeekable(IMFMediaEngineEx *iface, IMFMediaTimeRange **seekable)
1821 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1822 HRESULT hr = E_NOTIMPL;
1824 FIXME("(%p, %p): stub.\n", iface, seekable);
1826 EnterCriticalSection(&engine->cs);
1828 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1829 hr = MF_E_SHUTDOWN;
1831 LeaveCriticalSection(&engine->cs);
1833 return hr;
1836 static BOOL WINAPI media_engine_IsEnded(IMFMediaEngineEx *iface)
1838 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1839 BOOL value;
1841 TRACE("%p.\n", iface);
1843 EnterCriticalSection(&engine->cs);
1844 value = !!(engine->flags & FLAGS_ENGINE_IS_ENDED);
1845 LeaveCriticalSection(&engine->cs);
1847 return value;
1850 static BOOL WINAPI media_engine_GetAutoPlay(IMFMediaEngineEx *iface)
1852 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1853 BOOL value;
1855 TRACE("%p.\n", iface);
1857 EnterCriticalSection(&engine->cs);
1858 value = !!(engine->flags & FLAGS_ENGINE_AUTO_PLAY);
1859 LeaveCriticalSection(&engine->cs);
1861 return value;
1864 static HRESULT WINAPI media_engine_SetAutoPlay(IMFMediaEngineEx *iface, BOOL autoplay)
1866 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1868 FIXME("(%p, %d): stub.\n", iface, autoplay);
1870 EnterCriticalSection(&engine->cs);
1871 media_engine_set_flag(engine, FLAGS_ENGINE_AUTO_PLAY, autoplay);
1872 LeaveCriticalSection(&engine->cs);
1874 return S_OK;
1877 static BOOL WINAPI media_engine_GetLoop(IMFMediaEngineEx *iface)
1879 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1880 BOOL value;
1882 TRACE("%p.\n", iface);
1884 EnterCriticalSection(&engine->cs);
1885 value = !!(engine->flags & FLAGS_ENGINE_LOOP);
1886 LeaveCriticalSection(&engine->cs);
1888 return value;
1891 static HRESULT WINAPI media_engine_SetLoop(IMFMediaEngineEx *iface, BOOL loop)
1893 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1895 FIXME("(%p, %d): stub.\n", iface, loop);
1897 EnterCriticalSection(&engine->cs);
1898 media_engine_set_flag(engine, FLAGS_ENGINE_LOOP, loop);
1899 LeaveCriticalSection(&engine->cs);
1901 return S_OK;
1904 static HRESULT WINAPI media_engine_Play(IMFMediaEngineEx *iface)
1906 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1907 HRESULT hr = S_OK;
1909 TRACE("%p.\n", iface);
1911 EnterCriticalSection(&engine->cs);
1913 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1914 hr = MF_E_SHUTDOWN;
1915 else
1917 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
1919 if (!(engine->flags & FLAGS_ENGINE_WAITING))
1921 media_engine_set_flag(engine, FLAGS_ENGINE_PAUSED | FLAGS_ENGINE_IS_ENDED, FALSE);
1922 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAY, 0, 0);
1924 if (!(engine->flags & FLAGS_ENGINE_SOURCE_PENDING))
1925 media_engine_start_playback(engine);
1926 else
1927 media_engine_set_flag(engine, FLAGS_ENGINE_PLAY_PENDING, TRUE);
1929 media_engine_set_flag(engine, FLAGS_ENGINE_WAITING, TRUE);
1932 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_WAITING, 0, 0);
1935 LeaveCriticalSection(&engine->cs);
1937 return hr;
1940 static HRESULT WINAPI media_engine_Pause(IMFMediaEngineEx *iface)
1942 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1943 HRESULT hr = S_OK;
1945 TRACE("%p.\n", iface);
1947 EnterCriticalSection(&engine->cs);
1949 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1950 hr = MF_E_SHUTDOWN;
1951 else
1953 if (!(engine->flags & FLAGS_ENGINE_PAUSED))
1955 if (SUCCEEDED(hr = IMFMediaSession_Pause(engine->session)))
1957 media_engine_set_flag(engine, FLAGS_ENGINE_WAITING | FLAGS_ENGINE_IS_ENDED, FALSE);
1958 media_engine_set_flag(engine, FLAGS_ENGINE_PAUSED, TRUE);
1960 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_TIMEUPDATE, 0, 0);
1961 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PAUSE, 0, 0);
1965 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
1968 LeaveCriticalSection(&engine->cs);
1970 return hr;
1973 static BOOL WINAPI media_engine_GetMuted(IMFMediaEngineEx *iface)
1975 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1976 BOOL ret;
1978 TRACE("%p.\n", iface);
1980 EnterCriticalSection(&engine->cs);
1981 ret = !!(engine->flags & FLAGS_ENGINE_MUTED);
1982 LeaveCriticalSection(&engine->cs);
1984 return ret;
1987 static HRESULT WINAPI media_engine_SetMuted(IMFMediaEngineEx *iface, BOOL muted)
1989 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1990 HRESULT hr = S_OK;
1992 TRACE("%p, %d.\n", iface, muted);
1994 EnterCriticalSection(&engine->cs);
1995 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1996 hr = MF_E_SHUTDOWN;
1997 else if (!!(engine->flags & FLAGS_ENGINE_MUTED) ^ !!muted)
1999 media_engine_set_flag(engine, FLAGS_ENGINE_MUTED, muted);
2000 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE, 0, 0);
2002 LeaveCriticalSection(&engine->cs);
2004 return hr;
2007 static double WINAPI media_engine_GetVolume(IMFMediaEngineEx *iface)
2009 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2010 double volume;
2012 TRACE("%p.\n", iface);
2014 EnterCriticalSection(&engine->cs);
2015 volume = engine->volume;
2016 LeaveCriticalSection(&engine->cs);
2018 return volume;
2021 static HRESULT WINAPI media_engine_SetVolume(IMFMediaEngineEx *iface, double volume)
2023 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2024 HRESULT hr = S_OK;
2026 TRACE("%p, %f.\n", iface, volume);
2028 EnterCriticalSection(&engine->cs);
2029 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2030 hr = MF_E_SHUTDOWN;
2031 else if (volume != engine->volume)
2033 engine->volume = volume;
2034 media_engine_apply_volume(engine);
2035 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE, 0, 0);
2037 LeaveCriticalSection(&engine->cs);
2039 return hr;
2042 static BOOL WINAPI media_engine_HasVideo(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_HAS_VIDEO);
2051 LeaveCriticalSection(&engine->cs);
2053 return value;
2056 static BOOL WINAPI media_engine_HasAudio(IMFMediaEngineEx *iface)
2058 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2059 BOOL value;
2061 TRACE("%p.\n", iface);
2063 EnterCriticalSection(&engine->cs);
2064 value = !!(engine->flags & FLAGS_ENGINE_HAS_AUDIO);
2065 LeaveCriticalSection(&engine->cs);
2067 return value;
2070 static HRESULT WINAPI media_engine_GetNativeVideoSize(IMFMediaEngineEx *iface, DWORD *cx, DWORD *cy)
2072 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2073 HRESULT hr = S_OK;
2075 TRACE("%p, %p, %p.\n", iface, cx, cy);
2077 if (!cx && !cy)
2078 return E_INVALIDARG;
2080 EnterCriticalSection(&engine->cs);
2082 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2083 hr = MF_E_SHUTDOWN;
2084 else if (!engine->video_frame.size.cx && !engine->video_frame.size.cy)
2085 hr = E_FAIL;
2086 else
2088 if (cx) *cx = engine->video_frame.size.cx;
2089 if (cy) *cy = engine->video_frame.size.cy;
2092 LeaveCriticalSection(&engine->cs);
2094 return hr;
2097 static HRESULT WINAPI media_engine_GetVideoAspectRatio(IMFMediaEngineEx *iface, DWORD *cx, DWORD *cy)
2099 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2100 HRESULT hr = S_OK;
2102 TRACE("%p, %p, %p.\n", iface, cx, cy);
2104 if (!cx && !cy)
2105 return E_INVALIDARG;
2107 EnterCriticalSection(&engine->cs);
2109 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2110 hr = MF_E_SHUTDOWN;
2111 else if (!engine->video_frame.size.cx && !engine->video_frame.size.cy)
2112 hr = E_FAIL;
2113 else
2115 if (cx) *cx = engine->video_frame.ratio.cx;
2116 if (cy) *cy = engine->video_frame.ratio.cy;
2119 LeaveCriticalSection(&engine->cs);
2121 return hr;
2124 static HRESULT WINAPI media_engine_Shutdown(IMFMediaEngineEx *iface)
2126 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2127 HRESULT hr = S_OK;
2129 TRACE("%p.\n", iface);
2131 EnterCriticalSection(&engine->cs);
2132 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2133 hr = MF_E_SHUTDOWN;
2134 else
2136 media_engine_set_flag(engine, FLAGS_ENGINE_SHUT_DOWN, TRUE);
2137 media_engine_clear_presentation(engine);
2138 IMFMediaSession_Shutdown(engine->session);
2140 LeaveCriticalSection(&engine->cs);
2142 return hr;
2145 static void set_rect(struct rect *rect, float left, float top, float right, float bottom)
2147 rect->left = left;
2148 rect->top = top;
2149 rect->right = right;
2150 rect->bottom = bottom;
2153 static void media_engine_adjust_destination_for_ratio(const struct media_engine *engine,
2154 struct rect *src_n, struct rect *dst)
2156 float dst_width = dst->right - dst->left, dst_height = dst->bottom - dst->top;
2157 D3D11_TEXTURE2D_DESC source_desc;
2158 float src_width, src_height;
2159 struct rect src;
2161 ID3D11Texture2D_GetDesc(engine->video_frame.d3d11.source, &source_desc);
2162 set_rect(&src, src_n->left * source_desc.Width, src_n->top * source_desc.Height,
2163 src_n->right * source_desc.Width, src_n->bottom * source_desc.Height);
2165 src_width = src.right - src.left;
2166 src_height = src.bottom - src.top;
2168 if (src_width * dst_height > dst_width * src_height)
2170 /* src is "wider" than dst. */
2171 float dst_center = (dst->top + dst->bottom) / 2.0f;
2172 float scaled_height = src_height * dst_width / src_width;
2174 dst->top = dst_center - scaled_height / 2.0f;
2175 dst->bottom = dst->top + scaled_height;
2177 else if (src_width * dst_height < dst_width * src_height)
2179 /* src is "taller" than dst. */
2180 float dst_center = (dst->left + dst->right) / 2.0f;
2181 float scaled_width = src_width * dst_height / src_height;
2183 dst->left = dst_center - scaled_width / 2.0f;
2184 dst->right = dst->left + scaled_width;
2188 static void media_engine_update_d3d11_frame_surface(ID3D11DeviceContext *context, struct media_engine *engine)
2190 D3D11_TEXTURE2D_DESC surface_desc;
2192 if (!(engine->flags & FLAGS_ENGINE_NEW_FRAME))
2193 return;
2195 ID3D11Texture2D_GetDesc(engine->video_frame.d3d11.source, &surface_desc);
2197 switch (surface_desc.Format)
2199 case DXGI_FORMAT_B8G8R8A8_UNORM:
2200 case DXGI_FORMAT_B8G8R8X8_UNORM:
2201 surface_desc.Width *= 4;
2202 break;
2203 default:
2204 FIXME("Unsupported format %#x.\n", surface_desc.Format);
2205 surface_desc.Width = 0;
2208 if (engine->video_frame.buffer_size == surface_desc.Width * surface_desc.Height)
2210 ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)engine->video_frame.d3d11.source,
2211 0, NULL, engine->video_frame.buffer, surface_desc.Width, 0);
2214 media_engine_set_flag(engine, FLAGS_ENGINE_NEW_FRAME, FALSE);
2217 static HRESULT media_engine_transfer_to_d3d11_texture(struct media_engine *engine, ID3D11Texture2D *texture,
2218 const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color)
2220 static const float black[] = {0.0f, 0.0f, 0.0f, 0.0f};
2221 ID3D11Device *device, *dst_device;
2222 ID3D11DeviceContext *context;
2223 ID3D11RenderTargetView *rtv;
2224 unsigned int stride, offset;
2225 D3D11_TEXTURE2D_DESC desc;
2226 BOOL device_mismatch;
2227 struct vec3 quad[4];
2228 D3D11_VIEWPORT vp;
2229 struct rect src, dst;
2230 struct color backcolor;
2231 HRESULT hr;
2232 RECT rect;
2234 if (FAILED(hr = media_engine_lock_d3d_device(engine, &device)))
2235 return hr;
2237 if (FAILED(hr = media_engine_create_d3d11_video_frame_resources(engine, device)))
2239 WARN("Failed to create d3d resources, hr %#lx.\n", hr);
2240 goto done;
2243 ID3D11Texture2D_GetDevice(texture, &dst_device);
2244 device_mismatch = device != dst_device;
2245 ID3D11Device_Release(dst_device);
2247 if (device_mismatch)
2249 WARN("Destination target from different device.\n");
2250 hr = E_UNEXPECTED;
2251 goto done;
2254 ID3D11Texture2D_GetDesc(texture, &desc);
2256 if (FAILED(hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)texture, NULL, &rtv)))
2258 WARN("Failed to create an rtv, hr %#lx.\n", hr);
2259 goto done;
2262 ID3D11Device_GetImmediateContext(device, &context);
2264 /* Whole destination is cleared, regardless of specified rectangle. */
2265 ID3D11DeviceContext_ClearRenderTargetView(context, rtv, black);
2267 if (dst_rect)
2269 rect.left = max(0, dst_rect->left);
2270 rect.top = max(0, dst_rect->top);
2271 rect.right = min(desc.Width, dst_rect->right);
2272 rect.bottom = min(desc.Height, dst_rect->bottom);
2274 quad[0].x = 2.0f * rect.left / desc.Width - 1.0f;
2275 quad[0].y = -2.0f * rect.bottom / desc.Height + 1.0f;
2276 quad[0].z = 0.0f;
2278 quad[1].x = quad[0].x;
2279 quad[1].y = -2.0f * rect.top / desc.Height + 1.0f;
2280 quad[1].z = 0.0f;
2282 quad[2].x = 2.0f * rect.right / desc.Width - 1.0f;
2283 quad[2].y = quad[0].y;
2284 quad[2].z = 0.0f;
2286 quad[3].x = quad[2].x;
2287 quad[3].y = quad[1].y;
2288 quad[3].z = 0.0f;
2290 set_rect(&dst, dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom);
2292 else
2294 memcpy(quad, fullquad, sizeof(quad));
2295 set_rect(&dst, 0.0f, 0.0f, desc.Width, desc.Height);
2298 if (src_rect)
2299 memcpy(&src, src_rect, sizeof(src));
2300 else
2301 set_rect(&src, 0.0f, 0.0f, 1.0f, 1.0f);
2303 media_engine_adjust_destination_for_ratio(engine, &src, &dst);
2305 if (memcmp(quad, engine->video_frame.d3d11.quad, sizeof(quad)))
2307 memcpy(engine->video_frame.d3d11.quad, quad, sizeof(quad));
2308 ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)engine->video_frame.d3d11.vb, 0, NULL, quad, 0, 0);
2311 if (color)
2313 backcolor.r = color->rgbRed / 255.0f;
2314 backcolor.g = color->rgbGreen / 255.0f;
2315 backcolor.b = color->rgbBlue / 255.0f;
2316 backcolor.a = color->rgbAlpha / 255.0f;
2318 else
2319 memcpy(&backcolor, black, sizeof(backcolor));
2321 if (memcmp(&dst, &engine->video_frame.d3d11.cb.dst, sizeof(dst)) ||
2322 memcmp(&src, &engine->video_frame.d3d11.cb.src, sizeof(src)) ||
2323 memcmp(&backcolor, &engine->video_frame.d3d11.cb.backcolor, sizeof(backcolor)))
2325 memcpy(&engine->video_frame.d3d11.cb.dst, &dst, sizeof(dst));
2326 memcpy(&engine->video_frame.d3d11.cb.src, &src, sizeof(src));
2327 memcpy(&engine->video_frame.d3d11.cb.backcolor, &backcolor, sizeof(backcolor));
2329 ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)engine->video_frame.d3d11.ps_cb, 0, NULL,
2330 &engine->video_frame.d3d11.cb, 0, 0);
2333 /* Update with new frame contents */
2334 media_engine_update_d3d11_frame_surface(context, engine);
2336 vp.TopLeftX = 0.0f;
2337 vp.TopLeftY = 0.0f;
2338 vp.Width = desc.Width;
2339 vp.Height = desc.Height;
2340 vp.MinDepth = 0.0f;
2341 vp.MaxDepth = 1.0f;
2342 ID3D11DeviceContext_RSSetViewports(context, 1, &vp);
2344 ID3D11DeviceContext_IASetInputLayout(context, engine->video_frame.d3d11.input_layout);
2345 ID3D11DeviceContext_IASetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
2346 stride = sizeof(*quad);
2347 offset = 0;
2348 ID3D11DeviceContext_IASetVertexBuffers(context, 0, 1, &engine->video_frame.d3d11.vb, &stride, &offset);
2349 ID3D11DeviceContext_VSSetShader(context, engine->video_frame.d3d11.vs, NULL, 0);
2350 ID3D11DeviceContext_PSSetShader(context, engine->video_frame.d3d11.ps, NULL, 0);
2351 ID3D11DeviceContext_PSSetShaderResources(context, 0, 1, &engine->video_frame.d3d11.srv);
2352 ID3D11DeviceContext_PSSetConstantBuffers(context, 0, 1, &engine->video_frame.d3d11.ps_cb);
2353 ID3D11DeviceContext_PSSetSamplers(context, 0, 1, &engine->video_frame.d3d11.sampler);
2354 ID3D11DeviceContext_OMSetRenderTargets(context, 1, &rtv, NULL);
2356 ID3D11DeviceContext_Draw(context, 4, 0);
2358 ID3D11RenderTargetView_Release(rtv);
2359 ID3D11DeviceContext_Release(context);
2361 done:
2362 media_engine_unlock_d3d_device(engine, device);
2364 return hr;
2367 static HRESULT WINAPI media_engine_TransferVideoFrame(IMFMediaEngineEx *iface, IUnknown *surface,
2368 const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color)
2370 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2371 ID3D11Texture2D *texture;
2372 HRESULT hr = E_NOINTERFACE;
2374 TRACE("%p, %p, %s, %s, %p.\n", iface, surface, src_rect ? wine_dbg_sprintf("(%f,%f)-(%f,%f)",
2375 src_rect->left, src_rect->top, src_rect->right, src_rect->bottom) : "(null)",
2376 wine_dbgstr_rect(dst_rect), color);
2378 EnterCriticalSection(&engine->cs);
2380 if (SUCCEEDED(IUnknown_QueryInterface(surface, &IID_ID3D11Texture2D, (void **)&texture)))
2382 hr = media_engine_transfer_to_d3d11_texture(engine, texture, src_rect, dst_rect, color);
2383 ID3D11Texture2D_Release(texture);
2385 else
2387 FIXME("Unsupported destination type.\n");
2390 LeaveCriticalSection(&engine->cs);
2392 return hr;
2395 static HRESULT WINAPI media_engine_OnVideoStreamTick(IMFMediaEngineEx *iface, LONGLONG *pts)
2397 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2398 HRESULT hr;
2400 TRACE("%p, %p.\n", iface, pts);
2402 EnterCriticalSection(&engine->cs);
2404 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2405 hr = MF_E_SHUTDOWN;
2406 else if (!pts)
2407 hr = E_POINTER;
2408 else
2410 *pts = engine->video_frame.pts;
2411 hr = *pts == MINLONGLONG ? S_FALSE : S_OK;
2414 LeaveCriticalSection(&engine->cs);
2416 return hr;
2419 static HRESULT WINAPI media_engine_SetSourceFromByteStream(IMFMediaEngineEx *iface, IMFByteStream *bytestream, BSTR url)
2421 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2422 HRESULT hr;
2424 TRACE("%p, %p, %s.\n", iface, bytestream, debugstr_w(url));
2426 EnterCriticalSection(&engine->cs);
2428 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2429 hr = MF_E_SHUTDOWN;
2430 else if (!bytestream || !url)
2431 hr = E_POINTER;
2432 else
2433 hr = media_engine_set_source(engine, bytestream, url);
2435 LeaveCriticalSection(&engine->cs);
2437 return hr;
2440 static HRESULT WINAPI media_engine_GetStatistics(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_STATISTIC stat_id, PROPVARIANT *stat)
2442 FIXME("%p, %x, %p stub.\n", iface, stat_id, stat);
2444 return E_NOTIMPL;
2447 static HRESULT WINAPI media_engine_UpdateVideoStream(IMFMediaEngineEx *iface, const MFVideoNormalizedRect *src,
2448 const RECT *dst, const MFARGB *border_color)
2450 FIXME("%p, %p, %p, %p stub.\n", iface, src, dst, border_color);
2452 return E_NOTIMPL;
2455 static double WINAPI media_engine_GetBalance(IMFMediaEngineEx *iface)
2457 FIXME("%p stub.\n", iface);
2459 return 0.0;
2462 static HRESULT WINAPI media_engine_SetBalance(IMFMediaEngineEx *iface, double balance)
2464 FIXME("%p, %f stub.\n", iface, balance);
2466 return E_NOTIMPL;
2469 static BOOL WINAPI media_engine_IsPlaybackRateSupported(IMFMediaEngineEx *iface, double rate)
2471 FIXME("%p, %f stub.\n", iface, rate);
2473 return FALSE;
2476 static HRESULT WINAPI media_engine_FrameStep(IMFMediaEngineEx *iface, BOOL forward)
2478 FIXME("%p, %d stub.\n", iface, forward);
2480 return E_NOTIMPL;
2483 static HRESULT WINAPI media_engine_GetResourceCharacteristics(IMFMediaEngineEx *iface, DWORD *flags)
2485 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2486 HRESULT hr = E_FAIL;
2488 TRACE("%p, %p.\n", iface, flags);
2490 EnterCriticalSection(&engine->cs);
2491 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2492 hr = MF_E_SHUTDOWN;
2493 else if (engine->presentation.source)
2494 hr = IMFMediaSource_GetCharacteristics(engine->presentation.source, flags);
2495 LeaveCriticalSection(&engine->cs);
2497 return hr;
2500 static HRESULT WINAPI media_engine_GetPresentationAttribute(IMFMediaEngineEx *iface, REFGUID attribute,
2501 PROPVARIANT *value)
2503 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2504 HRESULT hr = E_FAIL;
2506 TRACE("%p, %s, %p.\n", iface, debugstr_guid(attribute), value);
2508 EnterCriticalSection(&engine->cs);
2509 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2510 hr = MF_E_SHUTDOWN;
2511 else if (engine->presentation.pd)
2512 hr = IMFPresentationDescriptor_GetItem(engine->presentation.pd, attribute, value);
2513 LeaveCriticalSection(&engine->cs);
2515 return hr;
2518 static HRESULT WINAPI media_engine_GetNumberOfStreams(IMFMediaEngineEx *iface, DWORD *stream_count)
2520 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2521 HRESULT hr = E_FAIL;
2523 TRACE("%p, %p.\n", iface, stream_count);
2525 EnterCriticalSection(&engine->cs);
2526 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2527 hr = MF_E_SHUTDOWN;
2528 else if (engine->presentation.pd)
2529 hr = IMFPresentationDescriptor_GetStreamDescriptorCount(engine->presentation.pd, stream_count);
2530 LeaveCriticalSection(&engine->cs);
2532 return hr;
2535 static HRESULT WINAPI media_engine_GetStreamAttribute(IMFMediaEngineEx *iface, DWORD stream_index, REFGUID attribute,
2536 PROPVARIANT *value)
2538 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2539 IMFStreamDescriptor *sd;
2540 HRESULT hr = E_FAIL;
2541 BOOL selected;
2543 TRACE("%p, %ld, %s, %p.\n", iface, stream_index, debugstr_guid(attribute), value);
2545 EnterCriticalSection(&engine->cs);
2546 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2547 hr = MF_E_SHUTDOWN;
2548 else if (engine->presentation.pd)
2550 if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(engine->presentation.pd,
2551 stream_index, &selected, &sd)))
2553 hr = IMFStreamDescriptor_GetItem(sd, attribute, value);
2554 IMFStreamDescriptor_Release(sd);
2557 LeaveCriticalSection(&engine->cs);
2559 return hr;
2562 static HRESULT WINAPI media_engine_GetStreamSelection(IMFMediaEngineEx *iface, DWORD stream_index, BOOL *enabled)
2564 FIXME("%p, %ld, %p stub.\n", iface, stream_index, enabled);
2566 return E_NOTIMPL;
2569 static HRESULT WINAPI media_engine_SetStreamSelection(IMFMediaEngineEx *iface, DWORD stream_index, BOOL enabled)
2571 FIXME("%p, %ld, %d stub.\n", iface, stream_index, enabled);
2573 return E_NOTIMPL;
2576 static HRESULT WINAPI media_engine_ApplyStreamSelections(IMFMediaEngineEx *iface)
2578 FIXME("%p stub.\n", iface);
2580 return E_NOTIMPL;
2583 static HRESULT WINAPI media_engine_IsProtected(IMFMediaEngineEx *iface, BOOL *protected)
2585 FIXME("%p, %p stub.\n", iface, protected);
2587 return E_NOTIMPL;
2590 static HRESULT WINAPI media_engine_InsertVideoEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional)
2592 FIXME("%p, %p, %d stub.\n", iface, effect, is_optional);
2594 return E_NOTIMPL;
2597 static HRESULT WINAPI media_engine_InsertAudioEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional)
2599 FIXME("%p, %p, %d stub.\n", iface, effect, is_optional);
2601 return E_NOTIMPL;
2604 static HRESULT WINAPI media_engine_RemoveAllEffects(IMFMediaEngineEx *iface)
2606 FIXME("%p stub.\n", iface);
2608 return E_NOTIMPL;
2611 static HRESULT WINAPI media_engine_SetTimelineMarkerTimer(IMFMediaEngineEx *iface, double timeout)
2613 FIXME("%p, %f stub.\n", iface, timeout);
2615 return E_NOTIMPL;
2618 static HRESULT WINAPI media_engine_GetTimelineMarkerTimer(IMFMediaEngineEx *iface, double *timeout)
2620 FIXME("%p, %p stub.\n", iface, timeout);
2622 return E_NOTIMPL;
2625 static HRESULT WINAPI media_engine_CancelTimelineMarkerTimer(IMFMediaEngineEx *iface)
2627 FIXME("%p stub.\n", iface);
2629 return E_NOTIMPL;
2632 static BOOL WINAPI media_engine_IsStereo3D(IMFMediaEngineEx *iface)
2634 FIXME("%p stub.\n", iface);
2636 return FALSE;
2639 static HRESULT WINAPI media_engine_GetStereo3DFramePackingMode(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_S3D_PACKING_MODE *mode)
2641 FIXME("%p, %p stub.\n", iface, mode);
2643 return E_NOTIMPL;
2646 static HRESULT WINAPI media_engine_SetStereo3DFramePackingMode(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_S3D_PACKING_MODE mode)
2648 FIXME("%p, %#x stub.\n", iface, mode);
2650 return E_NOTIMPL;
2653 static HRESULT WINAPI media_engine_GetStereo3DRenderMode(IMFMediaEngineEx *iface, MF3DVideoOutputType *output_type)
2655 FIXME("%p, %p stub.\n", iface, output_type);
2657 return E_NOTIMPL;
2660 static HRESULT WINAPI media_engine_SetStereo3DRenderMode(IMFMediaEngineEx *iface, MF3DVideoOutputType output_type)
2662 FIXME("%p, %#x stub.\n", iface, output_type);
2664 return E_NOTIMPL;
2667 static HRESULT WINAPI media_engine_EnableWindowlessSwapchainMode(IMFMediaEngineEx *iface, BOOL enable)
2669 FIXME("%p, %d stub.\n", iface, enable);
2671 return E_NOTIMPL;
2674 static HRESULT WINAPI media_engine_GetVideoSwapchainHandle(IMFMediaEngineEx *iface, HANDLE *swapchain)
2676 FIXME("%p, %p stub.\n", iface, swapchain);
2678 return E_NOTIMPL;
2681 static HRESULT WINAPI media_engine_EnableHorizontalMirrorMode(IMFMediaEngineEx *iface, BOOL enable)
2683 FIXME("%p, %d stub.\n", iface, enable);
2685 return E_NOTIMPL;
2688 static HRESULT WINAPI media_engine_GetAudioStreamCategory(IMFMediaEngineEx *iface, UINT32 *category)
2690 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2691 HRESULT hr;
2693 TRACE("%p, %p.\n", iface, category);
2695 EnterCriticalSection(&engine->cs);
2697 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2698 hr = MF_E_SHUTDOWN;
2699 else
2700 hr = IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, category);
2702 LeaveCriticalSection(&engine->cs);
2704 return hr;
2707 static HRESULT WINAPI media_engine_SetAudioStreamCategory(IMFMediaEngineEx *iface, UINT32 category)
2709 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2710 HRESULT hr;
2712 TRACE("%p, %u.\n", iface, category);
2714 EnterCriticalSection(&engine->cs);
2716 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2717 hr = MF_E_SHUTDOWN;
2718 else
2719 hr = IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, category);
2721 LeaveCriticalSection(&engine->cs);
2723 return hr;
2726 static HRESULT WINAPI media_engine_GetAudioEndpointRole(IMFMediaEngineEx *iface, UINT32 *role)
2728 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2729 HRESULT hr;
2731 TRACE("%p, %p.\n", iface, role);
2733 EnterCriticalSection(&engine->cs);
2735 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2736 hr = MF_E_SHUTDOWN;
2737 else
2738 hr = IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, role);
2740 LeaveCriticalSection(&engine->cs);
2742 return hr;
2745 static HRESULT WINAPI media_engine_SetAudioEndpointRole(IMFMediaEngineEx *iface, UINT32 role)
2747 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2748 HRESULT hr;
2750 TRACE("%p, %u.\n", iface, role);
2752 EnterCriticalSection(&engine->cs);
2754 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2755 hr = MF_E_SHUTDOWN;
2756 else
2757 hr = IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, role);
2759 LeaveCriticalSection(&engine->cs);
2761 return hr;
2764 static HRESULT WINAPI media_engine_GetRealTimeMode(IMFMediaEngineEx *iface, BOOL *enabled)
2766 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2767 HRESULT hr = S_OK;
2769 TRACE("%p, %p.\n", iface, enabled);
2771 EnterCriticalSection(&engine->cs);
2772 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2773 hr = MF_E_SHUTDOWN;
2774 else
2775 *enabled = !!(engine->flags & MF_MEDIA_ENGINE_REAL_TIME_MODE);
2776 LeaveCriticalSection(&engine->cs);
2778 return hr;
2781 static HRESULT WINAPI media_engine_SetRealTimeMode(IMFMediaEngineEx *iface, BOOL enable)
2783 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2784 HRESULT hr = S_OK;
2786 TRACE("%p, %d.\n", iface, enable);
2788 EnterCriticalSection(&engine->cs);
2789 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2790 hr = MF_E_SHUTDOWN;
2791 else
2792 media_engine_set_flag(engine, MF_MEDIA_ENGINE_REAL_TIME_MODE, enable);
2793 LeaveCriticalSection(&engine->cs);
2795 return hr;
2798 static HRESULT WINAPI media_engine_SetCurrentTimeEx(IMFMediaEngineEx *iface, double seektime, MF_MEDIA_ENGINE_SEEK_MODE mode)
2800 FIXME("%p, %f, %#x stub.\n", iface, seektime, mode);
2802 return E_NOTIMPL;
2805 static HRESULT WINAPI media_engine_EnableTimeUpdateTimer(IMFMediaEngineEx *iface, BOOL enable)
2807 FIXME("%p, %d stub.\n", iface, enable);
2809 return E_NOTIMPL;
2812 static const IMFMediaEngineExVtbl media_engine_vtbl =
2814 media_engine_QueryInterface,
2815 media_engine_AddRef,
2816 media_engine_Release,
2817 media_engine_GetError,
2818 media_engine_SetErrorCode,
2819 media_engine_SetSourceElements,
2820 media_engine_SetSource,
2821 media_engine_GetCurrentSource,
2822 media_engine_GetNetworkState,
2823 media_engine_GetPreload,
2824 media_engine_SetPreload,
2825 media_engine_GetBuffered,
2826 media_engine_Load,
2827 media_engine_CanPlayType,
2828 media_engine_GetReadyState,
2829 media_engine_IsSeeking,
2830 media_engine_GetCurrentTime,
2831 media_engine_SetCurrentTime,
2832 media_engine_GetStartTime,
2833 media_engine_GetDuration,
2834 media_engine_IsPaused,
2835 media_engine_GetDefaultPlaybackRate,
2836 media_engine_SetDefaultPlaybackRate,
2837 media_engine_GetPlaybackRate,
2838 media_engine_SetPlaybackRate,
2839 media_engine_GetPlayed,
2840 media_engine_GetSeekable,
2841 media_engine_IsEnded,
2842 media_engine_GetAutoPlay,
2843 media_engine_SetAutoPlay,
2844 media_engine_GetLoop,
2845 media_engine_SetLoop,
2846 media_engine_Play,
2847 media_engine_Pause,
2848 media_engine_GetMuted,
2849 media_engine_SetMuted,
2850 media_engine_GetVolume,
2851 media_engine_SetVolume,
2852 media_engine_HasVideo,
2853 media_engine_HasAudio,
2854 media_engine_GetNativeVideoSize,
2855 media_engine_GetVideoAspectRatio,
2856 media_engine_Shutdown,
2857 media_engine_TransferVideoFrame,
2858 media_engine_OnVideoStreamTick,
2859 media_engine_SetSourceFromByteStream,
2860 media_engine_GetStatistics,
2861 media_engine_UpdateVideoStream,
2862 media_engine_GetBalance,
2863 media_engine_SetBalance,
2864 media_engine_IsPlaybackRateSupported,
2865 media_engine_FrameStep,
2866 media_engine_GetResourceCharacteristics,
2867 media_engine_GetPresentationAttribute,
2868 media_engine_GetNumberOfStreams,
2869 media_engine_GetStreamAttribute,
2870 media_engine_GetStreamSelection,
2871 media_engine_SetStreamSelection,
2872 media_engine_ApplyStreamSelections,
2873 media_engine_IsProtected,
2874 media_engine_InsertVideoEffect,
2875 media_engine_InsertAudioEffect,
2876 media_engine_RemoveAllEffects,
2877 media_engine_SetTimelineMarkerTimer,
2878 media_engine_GetTimelineMarkerTimer,
2879 media_engine_CancelTimelineMarkerTimer,
2880 media_engine_IsStereo3D,
2881 media_engine_GetStereo3DFramePackingMode,
2882 media_engine_SetStereo3DFramePackingMode,
2883 media_engine_GetStereo3DRenderMode,
2884 media_engine_SetStereo3DRenderMode,
2885 media_engine_EnableWindowlessSwapchainMode,
2886 media_engine_GetVideoSwapchainHandle,
2887 media_engine_EnableHorizontalMirrorMode,
2888 media_engine_GetAudioStreamCategory,
2889 media_engine_SetAudioStreamCategory,
2890 media_engine_GetAudioEndpointRole,
2891 media_engine_SetAudioEndpointRole,
2892 media_engine_GetRealTimeMode,
2893 media_engine_SetRealTimeMode,
2894 media_engine_SetCurrentTimeEx,
2895 media_engine_EnableTimeUpdateTimer,
2898 static HRESULT WINAPI media_engine_gs_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
2900 struct media_engine *engine = impl_from_IMFGetService(iface);
2901 return IMFMediaEngineEx_QueryInterface(&engine->IMFMediaEngineEx_iface, riid, obj);
2904 static ULONG WINAPI media_engine_gs_AddRef(IMFGetService *iface)
2906 struct media_engine *engine = impl_from_IMFGetService(iface);
2907 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
2910 static ULONG WINAPI media_engine_gs_Release(IMFGetService *iface)
2912 struct media_engine *engine = impl_from_IMFGetService(iface);
2913 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
2916 static HRESULT WINAPI media_engine_gs_GetService(IMFGetService *iface, REFGUID service,
2917 REFIID riid, void **object)
2919 FIXME("%p, %s, %s, %p stub.\n", iface, debugstr_guid(service), debugstr_guid(riid), object);
2921 return E_NOTIMPL;
2924 static const IMFGetServiceVtbl media_engine_get_service_vtbl =
2926 media_engine_gs_QueryInterface,
2927 media_engine_gs_AddRef,
2928 media_engine_gs_Release,
2929 media_engine_gs_GetService,
2932 static HRESULT WINAPI media_engine_grabber_callback_QueryInterface(IMFSampleGrabberSinkCallback *iface,
2933 REFIID riid, void **obj)
2935 if (IsEqualIID(riid, &IID_IMFSampleGrabberSinkCallback) ||
2936 IsEqualIID(riid, &IID_IUnknown))
2938 *obj = iface;
2939 IMFSampleGrabberSinkCallback_AddRef(iface);
2940 return S_OK;
2943 *obj = NULL;
2944 return E_NOINTERFACE;
2947 static ULONG WINAPI media_engine_grabber_callback_AddRef(IMFSampleGrabberSinkCallback *iface)
2949 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
2950 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
2953 static ULONG WINAPI media_engine_grabber_callback_Release(IMFSampleGrabberSinkCallback *iface)
2955 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
2956 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
2959 static HRESULT WINAPI media_engine_grabber_callback_OnClockStart(IMFSampleGrabberSinkCallback *iface,
2960 MFTIME systime, LONGLONG start_offset)
2962 return S_OK;
2965 static HRESULT WINAPI media_engine_grabber_callback_OnClockStop(IMFSampleGrabberSinkCallback *iface,
2966 MFTIME systime)
2968 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
2970 EnterCriticalSection(&engine->cs);
2971 media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, FALSE);
2972 engine->video_frame.pts = MINLONGLONG;
2973 LeaveCriticalSection(&engine->cs);
2975 return S_OK;
2978 static HRESULT WINAPI media_engine_grabber_callback_OnClockPause(IMFSampleGrabberSinkCallback *iface,
2979 MFTIME systime)
2981 return S_OK;
2984 static HRESULT WINAPI media_engine_grabber_callback_OnClockRestart(IMFSampleGrabberSinkCallback *iface,
2985 MFTIME systime)
2987 return S_OK;
2990 static HRESULT WINAPI media_engine_grabber_callback_OnClockSetRate(IMFSampleGrabberSinkCallback *iface,
2991 MFTIME systime, float rate)
2993 return S_OK;
2996 static HRESULT WINAPI media_engine_grabber_callback_OnSetPresentationClock(IMFSampleGrabberSinkCallback *iface,
2997 IMFPresentationClock *clock)
2999 return S_OK;
3002 static HRESULT WINAPI media_engine_grabber_callback_OnProcessSample(IMFSampleGrabberSinkCallback *iface,
3003 REFGUID major_type, DWORD sample_flags, LONGLONG sample_time, LONGLONG sample_duration,
3004 const BYTE *buffer, DWORD buffer_size)
3006 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
3008 EnterCriticalSection(&engine->cs);
3010 if (!(engine->flags & FLAGS_ENGINE_FIRST_FRAME))
3012 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY, 0, 0);
3013 media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, TRUE);
3015 engine->video_frame.pts = sample_time;
3016 if (engine->video_frame.buffer_size < buffer_size)
3018 free(engine->video_frame.buffer);
3019 if ((engine->video_frame.buffer = malloc(buffer_size)))
3020 engine->video_frame.buffer_size = buffer_size;
3022 if (engine->video_frame.buffer)
3024 memcpy(engine->video_frame.buffer, buffer, buffer_size);
3025 engine->flags |= FLAGS_ENGINE_NEW_FRAME;
3028 LeaveCriticalSection(&engine->cs);
3030 return S_OK;
3033 static HRESULT WINAPI media_engine_grabber_callback_OnShutdown(IMFSampleGrabberSinkCallback *iface)
3035 return S_OK;
3038 static const IMFSampleGrabberSinkCallbackVtbl media_engine_grabber_callback_vtbl =
3040 media_engine_grabber_callback_QueryInterface,
3041 media_engine_grabber_callback_AddRef,
3042 media_engine_grabber_callback_Release,
3043 media_engine_grabber_callback_OnClockStart,
3044 media_engine_grabber_callback_OnClockStop,
3045 media_engine_grabber_callback_OnClockPause,
3046 media_engine_grabber_callback_OnClockRestart,
3047 media_engine_grabber_callback_OnClockSetRate,
3048 media_engine_grabber_callback_OnSetPresentationClock,
3049 media_engine_grabber_callback_OnProcessSample,
3050 media_engine_grabber_callback_OnShutdown,
3053 static HRESULT WINAPI media_engine_factory_QueryInterface(IMFMediaEngineClassFactory *iface, REFIID riid, void **obj)
3055 if (IsEqualIID(riid, &IID_IMFMediaEngineClassFactory) ||
3056 IsEqualIID(riid, &IID_IUnknown))
3058 *obj = iface;
3059 IMFMediaEngineClassFactory_AddRef(iface);
3060 return S_OK;
3063 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
3064 *obj = NULL;
3065 return E_NOINTERFACE;
3068 static ULONG WINAPI media_engine_factory_AddRef(IMFMediaEngineClassFactory *iface)
3070 return 2;
3073 static ULONG WINAPI media_engine_factory_Release(IMFMediaEngineClassFactory *iface)
3075 return 1;
3078 static HRESULT init_media_engine(DWORD flags, IMFAttributes *attributes, struct media_engine *engine)
3080 DXGI_FORMAT output_format;
3081 UINT64 playback_hwnd;
3082 IMFClock *clock;
3083 HRESULT hr;
3085 engine->IMFMediaEngineEx_iface.lpVtbl = &media_engine_vtbl;
3086 engine->IMFGetService_iface.lpVtbl = &media_engine_get_service_vtbl;
3087 engine->session_events.lpVtbl = &media_engine_session_events_vtbl;
3088 engine->load_handler.lpVtbl = &media_engine_load_handler_vtbl;
3089 engine->grabber_callback.lpVtbl = &media_engine_grabber_callback_vtbl;
3090 engine->refcount = 1;
3091 engine->flags = (flags & MF_MEDIA_ENGINE_CREATEFLAGS_MASK) | FLAGS_ENGINE_PAUSED;
3092 engine->default_playback_rate = 1.0;
3093 engine->playback_rate = 1.0;
3094 engine->volume = 1.0;
3095 engine->duration = NAN;
3096 engine->video_frame.pts = MINLONGLONG;
3097 InitializeCriticalSection(&engine->cs);
3099 hr = IMFAttributes_GetUnknown(attributes, &MF_MEDIA_ENGINE_CALLBACK, &IID_IMFMediaEngineNotify,
3100 (void **)&engine->callback);
3101 if (FAILED(hr))
3102 return hr;
3104 IMFAttributes_GetUnknown(attributes, &MF_MEDIA_ENGINE_DXGI_MANAGER, &IID_IMFDXGIDeviceManager,
3105 (void **)&engine->device_manager);
3107 if (FAILED(hr = MFCreateMediaSession(NULL, &engine->session)))
3108 return hr;
3110 if (FAILED(hr = IMFMediaSession_GetClock(engine->session, &clock)))
3111 return hr;
3113 hr = IMFClock_QueryInterface(clock, &IID_IMFPresentationClock, (void **)&engine->clock);
3114 IMFClock_Release(clock);
3115 if (FAILED(hr))
3116 return hr;
3118 if (FAILED(hr = IMFMediaSession_BeginGetEvent(engine->session, &engine->session_events, NULL)))
3119 return hr;
3121 if (FAILED(hr = MFCreateSourceResolver(&engine->resolver)))
3122 return hr;
3124 if (FAILED(hr = MFCreateAttributes(&engine->attributes, 0)))
3125 return hr;
3127 if (FAILED(hr = IMFAttributes_CopyAllItems(attributes, engine->attributes)))
3128 return hr;
3130 /* Set default audio configuration */
3131 if (FAILED(IMFAttributes_GetItem(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, NULL)))
3132 IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, AudioCategory_Other);
3133 if (FAILED(IMFAttributes_GetItem(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, NULL)))
3134 IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, eMultimedia);
3136 IMFAttributes_GetUINT64(attributes, &MF_MEDIA_ENGINE_PLAYBACK_HWND, &playback_hwnd);
3137 hr = IMFAttributes_GetUINT32(attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, &output_format);
3138 if (playback_hwnd) /* FIXME: handle MF_MEDIA_ENGINE_PLAYBACK_VISUAL */
3139 engine->mode = MEDIA_ENGINE_RENDERING_MODE;
3140 else
3142 if (SUCCEEDED(hr))
3143 engine->mode = MEDIA_ENGINE_FRAME_SERVER_MODE;
3144 else
3145 engine->mode = MEDIA_ENGINE_AUDIO_MODE;
3148 return S_OK;
3151 static HRESULT WINAPI media_engine_factory_CreateInstance(IMFMediaEngineClassFactory *iface, DWORD flags,
3152 IMFAttributes *attributes, IMFMediaEngine **engine)
3154 struct media_engine *object;
3155 HRESULT hr;
3157 TRACE("%p, %#lx, %p, %p.\n", iface, flags, attributes, engine);
3159 if (!attributes || !engine)
3160 return E_POINTER;
3162 object = calloc(1, sizeof(*object));
3163 if (!object)
3164 return E_OUTOFMEMORY;
3166 hr = init_media_engine(flags, attributes, object);
3167 if (FAILED(hr))
3169 free_media_engine(object);
3170 return hr;
3173 *engine = (IMFMediaEngine *)&object->IMFMediaEngineEx_iface;
3175 return S_OK;
3178 static HRESULT WINAPI media_engine_factory_CreateTimeRange(IMFMediaEngineClassFactory *iface,
3179 IMFMediaTimeRange **range)
3181 TRACE("%p, %p.\n", iface, range);
3183 return create_time_range(range);
3186 static HRESULT WINAPI media_engine_factory_CreateError(IMFMediaEngineClassFactory *iface, IMFMediaError **error)
3188 TRACE("%p, %p.\n", iface, error);
3190 return create_media_error(error);
3193 static const IMFMediaEngineClassFactoryVtbl media_engine_factory_vtbl =
3195 media_engine_factory_QueryInterface,
3196 media_engine_factory_AddRef,
3197 media_engine_factory_Release,
3198 media_engine_factory_CreateInstance,
3199 media_engine_factory_CreateTimeRange,
3200 media_engine_factory_CreateError,
3203 static IMFMediaEngineClassFactory media_engine_factory = { &media_engine_factory_vtbl };
3205 static HRESULT WINAPI classfactory_QueryInterface(IClassFactory *iface, REFIID riid, void **obj)
3207 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
3209 if (IsEqualGUID(riid, &IID_IClassFactory) ||
3210 IsEqualGUID(riid, &IID_IUnknown))
3212 IClassFactory_AddRef(iface);
3213 *obj = iface;
3214 return S_OK;
3217 WARN("interface %s not implemented.\n", debugstr_guid(riid));
3218 *obj = NULL;
3219 return E_NOINTERFACE;
3222 static ULONG WINAPI classfactory_AddRef(IClassFactory *iface)
3224 return 2;
3227 static ULONG WINAPI classfactory_Release(IClassFactory *iface)
3229 return 1;
3232 static HRESULT WINAPI classfactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **obj)
3234 TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), obj);
3236 *obj = NULL;
3238 if (outer)
3239 return CLASS_E_NOAGGREGATION;
3241 return IMFMediaEngineClassFactory_QueryInterface(&media_engine_factory, riid, obj);
3244 static HRESULT WINAPI classfactory_LockServer(IClassFactory *iface, BOOL dolock)
3246 FIXME("(%d): stub.\n", dolock);
3247 return S_OK;
3250 static const IClassFactoryVtbl class_factory_vtbl =
3252 classfactory_QueryInterface,
3253 classfactory_AddRef,
3254 classfactory_Release,
3255 classfactory_CreateInstance,
3256 classfactory_LockServer,
3259 static IClassFactory classfactory = { &class_factory_vtbl };
3261 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **obj)
3263 TRACE("%s, %s, %p.\n", debugstr_guid(clsid), debugstr_guid(riid), obj);
3265 if (IsEqualGUID(clsid, &CLSID_MFMediaEngineClassFactory))
3266 return IClassFactory_QueryInterface(&classfactory, riid, obj);
3268 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
3269 *obj = NULL;
3270 return CLASS_E_CLASSNOTAVAILABLE;