ntdll: Rename local variables in heap_reallocate.
[wine.git] / dlls / mfmediaengine / main.c
bloba191448b69f3a92d8f61a18263138f94f10b1c82
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 = 1.0f - (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, 0x5892e3b1, 0x24c17f7c, 0x9999f143, 0x49667872, 0x00000001, 0x0000032c, 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, 0x00000290, 0x00000040,
298 0x000000a4, 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, 0x0304001f, 0x0010000a, 0x00000000, 0x06000036,
304 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e, 0x01000015, 0x08000031,
305 0x00100012, 0x00000000, 0x0010101a, 0x00000000, 0x0020801a, 0x00000000, 0x00000000, 0x08000031,
306 0x00100022, 0x00000000, 0x0020803a, 0x00000000, 0x00000000, 0x0010101a, 0x00000000, 0x0700003c,
307 0x00100012, 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a,
308 0x00000000, 0x06000036, 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e,
309 0x01000015, 0x09000000, 0x00100032, 0x00000000, 0x00101046, 0x00000000, 0x80208046, 0x00000041,
310 0x00000000, 0x00000000, 0x0a000000, 0x001000c2, 0x00000000, 0x80208406, 0x00000041, 0x00000000,
311 0x00000000, 0x00208ea6, 0x00000000, 0x00000000, 0x0700000e, 0x00100032, 0x00000000, 0x00100046,
312 0x00000000, 0x00100ae6, 0x00000000, 0x08000000, 0x00100022, 0x00000000, 0x8010001a, 0x00000041,
313 0x00000000, 0x00004001, 0x3f800000, 0x0a000000, 0x001000c2, 0x00000000, 0x80208406, 0x00000041,
314 0x00000000, 0x00000001, 0x00208ea6, 0x00000000, 0x00000001, 0x0a000032, 0x00100012, 0x00000001,
315 0x0010000a, 0x00000000, 0x0010002a, 0x00000000, 0x0020800a, 0x00000000, 0x00000001, 0x0a000032,
316 0x00100022, 0x00000001, 0x0010001a, 0x00000000, 0x0010003a, 0x00000000, 0x0020801a, 0x00000000,
317 0x00000001, 0x09000045, 0x001020f2, 0x00000000, 0x00100046, 0x00000001, 0x00107e46, 0x00000000,
318 0x00106000, 0x00000000, 0x0100003e,
320 D3D11_SUBRESOURCE_DATA resource_data;
321 D3D11_TEXTURE2D_DESC texture_desc;
322 D3D11_SAMPLER_DESC sampler_desc;
323 D3D11_BUFFER_DESC buffer_desc;
324 HRESULT hr;
326 if (engine->video_frame.d3d11.source)
327 return S_OK;
329 /* Default vertex buffer, updated on first transfer call. */
330 buffer_desc.ByteWidth = sizeof(engine->video_frame.d3d11.quad);
331 buffer_desc.Usage = D3D11_USAGE_DEFAULT;
332 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
333 buffer_desc.CPUAccessFlags = 0;
334 buffer_desc.MiscFlags = 0;
335 buffer_desc.StructureByteStride = 0;
337 resource_data.pSysMem = engine->video_frame.d3d11.quad;
338 resource_data.SysMemPitch = 0;
339 resource_data.SysMemSlicePitch = 0;
341 if (FAILED(hr = ID3D11Device_CreateBuffer(device, &buffer_desc, &resource_data, &engine->video_frame.d3d11.vb)))
343 WARN("Failed to create a vertex buffer, hr %#lx.\n", hr);
344 goto failed;
347 buffer_desc.ByteWidth = sizeof(engine->video_frame.d3d11.cb);
348 buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
350 if (FAILED(hr = ID3D11Device_CreateBuffer(device, &buffer_desc, NULL, &engine->video_frame.d3d11.ps_cb)))
352 WARN("Failed to create a buffer, hr %#lx.\n", hr);
353 goto failed;
356 /* Source texture. */
357 texture_desc.Width = engine->video_frame.size.cx;
358 texture_desc.Height = engine->video_frame.size.cy;
359 texture_desc.MipLevels = 1;
360 texture_desc.ArraySize = 1;
361 texture_desc.Format = engine->video_frame.output_format;
362 texture_desc.SampleDesc.Count = 1;
363 texture_desc.SampleDesc.Quality = 0;
364 texture_desc.Usage = D3D11_USAGE_DEFAULT;
365 texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
366 texture_desc.CPUAccessFlags = 0;
367 texture_desc.MiscFlags = 0;
369 if (FAILED(hr = ID3D11Device_CreateTexture2D(device, &texture_desc, NULL, &engine->video_frame.d3d11.source)))
371 WARN("Failed to create source texture, hr %#lx.\n", hr);
372 goto failed;
375 if (FAILED(hr = ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource *)engine->video_frame.d3d11.source,
376 NULL, &engine->video_frame.d3d11.srv)))
378 WARN("Failed to create SRV, hr %#lx.\n", hr);
379 goto failed;
382 /* Sampler state. */
383 memset(&sampler_desc, 0, sizeof(sampler_desc));
384 sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
385 sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
386 sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
387 sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
389 if (FAILED(hr = ID3D11Device_CreateSamplerState(device, &sampler_desc, &engine->video_frame.d3d11.sampler)))
391 WARN("Failed to create a sampler state, hr %#lx.\n", hr);
392 goto failed;
395 /* Input layout */
396 if (FAILED(hr = ID3D11Device_CreateInputLayout(device, layout_desc, ARRAY_SIZE(layout_desc), vs_code, sizeof(vs_code),
397 &engine->video_frame.d3d11.input_layout)))
399 WARN("Failed to create input layout, hr %#lx.\n", hr);
400 goto failed;
403 /* Shaders */
404 if (FAILED(hr = ID3D11Device_CreateVertexShader(device, vs_code, sizeof(vs_code), NULL, &engine->video_frame.d3d11.vs)))
406 WARN("Failed to create the vertex shader, hr %#lx.\n", hr);
407 goto failed;
410 if (FAILED(hr = ID3D11Device_CreatePixelShader(device, ps_code, sizeof(ps_code), NULL, &engine->video_frame.d3d11.ps)))
412 WARN("Failed to create the pixel shader, hr %#lx.\n", hr);
413 goto failed;
416 failed:
418 return hr;
421 struct range
423 double start;
424 double end;
427 struct time_range
429 IMFMediaTimeRange IMFMediaTimeRange_iface;
430 LONG refcount;
432 struct range *ranges;
433 size_t count;
434 size_t capacity;
437 static struct time_range *impl_from_IMFMediaTimeRange(IMFMediaTimeRange *iface)
439 return CONTAINING_RECORD(iface, struct time_range, IMFMediaTimeRange_iface);
442 struct media_error
444 IMFMediaError IMFMediaError_iface;
445 LONG refcount;
446 unsigned int code;
447 HRESULT extended_code;
450 static struct media_error *impl_from_IMFMediaError(IMFMediaError *iface)
452 return CONTAINING_RECORD(iface, struct media_error, IMFMediaError_iface);
455 static HRESULT WINAPI media_error_QueryInterface(IMFMediaError *iface, REFIID riid, void **obj)
457 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
459 if (IsEqualIID(riid, &IID_IMFMediaError) ||
460 IsEqualIID(riid, &IID_IUnknown))
462 *obj = iface;
463 IMFMediaError_AddRef(iface);
464 return S_OK;
467 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
468 *obj = NULL;
469 return E_NOINTERFACE;
472 static ULONG WINAPI media_error_AddRef(IMFMediaError *iface)
474 struct media_error *me = impl_from_IMFMediaError(iface);
475 ULONG refcount = InterlockedIncrement(&me->refcount);
477 TRACE("%p, refcount %lu.\n", iface, refcount);
479 return refcount;
482 static ULONG WINAPI media_error_Release(IMFMediaError *iface)
484 struct media_error *me = impl_from_IMFMediaError(iface);
485 ULONG refcount = InterlockedDecrement(&me->refcount);
487 TRACE("%p, refcount %lu.\n", iface, refcount);
489 if (!refcount)
490 free(me);
492 return refcount;
495 static USHORT WINAPI media_error_GetErrorCode(IMFMediaError *iface)
497 struct media_error *me = impl_from_IMFMediaError(iface);
498 TRACE("%p.\n", iface);
499 return me->code;
502 static HRESULT WINAPI media_error_GetExtendedErrorCode(IMFMediaError *iface)
504 struct media_error *me = impl_from_IMFMediaError(iface);
505 TRACE("%p.\n", iface);
506 return me->extended_code;
509 static HRESULT WINAPI media_error_SetErrorCode(IMFMediaError *iface, MF_MEDIA_ENGINE_ERR code)
511 struct media_error *me = impl_from_IMFMediaError(iface);
513 TRACE("%p, %u.\n", iface, code);
515 if ((unsigned int)code > MF_MEDIA_ENGINE_ERR_ENCRYPTED)
516 return E_INVALIDARG;
518 me->code = code;
520 return S_OK;
523 static HRESULT WINAPI media_error_SetExtendedErrorCode(IMFMediaError *iface, HRESULT code)
525 struct media_error *me = impl_from_IMFMediaError(iface);
527 TRACE("%p, %#lx.\n", iface, code);
529 me->extended_code = code;
531 return S_OK;
534 static const IMFMediaErrorVtbl media_error_vtbl =
536 media_error_QueryInterface,
537 media_error_AddRef,
538 media_error_Release,
539 media_error_GetErrorCode,
540 media_error_GetExtendedErrorCode,
541 media_error_SetErrorCode,
542 media_error_SetExtendedErrorCode,
545 static HRESULT create_media_error(IMFMediaError **ret)
547 struct media_error *object;
549 *ret = NULL;
551 if (!(object = calloc(1, sizeof(*object))))
552 return E_OUTOFMEMORY;
554 object->IMFMediaError_iface.lpVtbl = &media_error_vtbl;
555 object->refcount = 1;
557 *ret = &object->IMFMediaError_iface;
559 return S_OK;
562 static HRESULT WINAPI time_range_QueryInterface(IMFMediaTimeRange *iface, REFIID riid, void **obj)
564 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
566 if (IsEqualIID(riid, &IID_IMFMediaTimeRange) ||
567 IsEqualIID(riid, &IID_IUnknown))
569 *obj = iface;
570 IMFMediaTimeRange_AddRef(iface);
571 return S_OK;
574 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
575 *obj = NULL;
576 return E_NOINTERFACE;
579 static ULONG WINAPI time_range_AddRef(IMFMediaTimeRange *iface)
581 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
582 ULONG refcount = InterlockedIncrement(&range->refcount);
584 TRACE("%p, refcount %lu.\n", iface, refcount);
586 return refcount;
589 static ULONG WINAPI time_range_Release(IMFMediaTimeRange *iface)
591 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
592 ULONG refcount = InterlockedDecrement(&range->refcount);
594 TRACE("%p, refcount %lu.\n", iface, refcount);
596 if (!refcount)
598 free(range->ranges);
599 free(range);
602 return refcount;
605 static DWORD WINAPI time_range_GetLength(IMFMediaTimeRange *iface)
607 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
609 TRACE("%p.\n", iface);
611 return range->count;
614 static HRESULT WINAPI time_range_GetStart(IMFMediaTimeRange *iface, DWORD idx, double *start)
616 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
618 TRACE("%p, %lu, %p.\n", iface, idx, start);
620 if (idx >= range->count)
621 return E_INVALIDARG;
623 *start = range->ranges[idx].start;
625 return S_OK;
628 static HRESULT WINAPI time_range_GetEnd(IMFMediaTimeRange *iface, DWORD idx, double *end)
630 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
632 TRACE("%p, %lu, %p.\n", iface, idx, end);
634 if (idx >= range->count)
635 return E_INVALIDARG;
637 *end = range->ranges[idx].end;
639 return S_OK;
642 static BOOL WINAPI time_range_ContainsTime(IMFMediaTimeRange *iface, double time)
644 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
645 size_t i;
647 TRACE("%p, %.8e.\n", iface, time);
649 for (i = 0; i < range->count; ++i)
651 if (time >= range->ranges[i].start && time <= range->ranges[i].end)
652 return TRUE;
655 return FALSE;
658 static HRESULT WINAPI time_range_AddRange(IMFMediaTimeRange *iface, double start, double end)
660 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
661 struct range *c;
662 size_t i;
664 TRACE("%p, %.8e, %.8e.\n", iface, start, end);
666 for (i = 0; i < range->count; ++i)
668 c = &range->ranges[i];
670 /* New range is fully contained within existing one. */
671 if (c->start <= start && c->end >= end)
672 return S_OK;
674 /* New range fully contains existing one. */
675 if (c->start >= start && c->end <= end)
677 c->start = start;
678 c->end = end;
679 return S_OK;
682 /* Merge if ranges intersect. */
683 if ((start >= c->start && start <= c->end) ||
684 (end >= c->start && end <= c->end))
686 c->start = min(c->start, start);
687 c->end = max(c->end, end);
688 return S_OK;
692 if (!mf_array_reserve((void **)&range->ranges, &range->capacity, range->count + 1, sizeof(*range->ranges)))
693 return E_OUTOFMEMORY;
695 range->ranges[range->count].start = start;
696 range->ranges[range->count].end = end;
697 range->count++;
699 return S_OK;
702 static HRESULT WINAPI time_range_Clear(IMFMediaTimeRange *iface)
704 struct time_range *range = impl_from_IMFMediaTimeRange(iface);
706 TRACE("%p.\n", iface);
708 range->count = 0;
710 return S_OK;
713 static const IMFMediaTimeRangeVtbl time_range_vtbl =
715 time_range_QueryInterface,
716 time_range_AddRef,
717 time_range_Release,
718 time_range_GetLength,
719 time_range_GetStart,
720 time_range_GetEnd,
721 time_range_ContainsTime,
722 time_range_AddRange,
723 time_range_Clear,
726 static HRESULT create_time_range(IMFMediaTimeRange **range)
728 struct time_range *object;
730 object = calloc(1, sizeof(*object));
731 if (!object)
732 return E_OUTOFMEMORY;
734 object->IMFMediaTimeRange_iface.lpVtbl = &time_range_vtbl;
735 object->refcount = 1;
737 *range = &object->IMFMediaTimeRange_iface;
739 return S_OK;
742 static void media_engine_set_flag(struct media_engine *engine, unsigned int mask, BOOL value)
744 if (value)
745 engine->flags |= mask;
746 else
747 engine->flags &= ~mask;
750 static inline struct media_engine *impl_from_IMFMediaEngineEx(IMFMediaEngineEx *iface)
752 return CONTAINING_RECORD(iface, struct media_engine, IMFMediaEngineEx_iface);
755 static inline struct media_engine *impl_from_IMFGetService(IMFGetService *iface)
757 return CONTAINING_RECORD(iface, struct media_engine, IMFGetService_iface);
760 static struct media_engine *impl_from_session_events_IMFAsyncCallback(IMFAsyncCallback *iface)
762 return CONTAINING_RECORD(iface, struct media_engine, session_events);
765 static struct media_engine *impl_from_load_handler_IMFAsyncCallback(IMFAsyncCallback *iface)
767 return CONTAINING_RECORD(iface, struct media_engine, load_handler);
770 static struct media_engine *impl_from_IMFSampleGrabberSinkCallback(IMFSampleGrabberSinkCallback *iface)
772 return CONTAINING_RECORD(iface, struct media_engine, grabber_callback);
775 static unsigned int get_gcd(unsigned int a, unsigned int b)
777 unsigned int m;
779 while (b)
781 m = a % b;
782 a = b;
783 b = m;
786 return a;
789 static void media_engine_get_frame_size(struct media_engine *engine, IMFTopology *topology)
791 IMFMediaTypeHandler *handler;
792 IMFMediaType *media_type;
793 IMFStreamDescriptor *sd;
794 IMFTopologyNode *node;
795 unsigned int gcd;
796 UINT64 size;
797 HRESULT hr;
799 engine->video_frame.size.cx = 0;
800 engine->video_frame.size.cy = 0;
801 engine->video_frame.ratio.cx = 1;
802 engine->video_frame.ratio.cy = 1;
804 if (FAILED(IMFTopology_GetNodeByID(topology, engine->video_frame.node_id, &node)))
805 return;
807 hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR,
808 &IID_IMFStreamDescriptor, (void **)&sd);
809 IMFTopologyNode_Release(node);
810 if (FAILED(hr))
811 return;
813 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
814 IMFStreamDescriptor_Release(sd);
815 if (FAILED(hr))
816 return;
818 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &media_type);
819 IMFMediaTypeHandler_Release(handler);
820 if (FAILED(hr))
822 WARN("Failed to get current media type %#lx.\n", hr);
823 return;
826 IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &size);
828 engine->video_frame.size.cx = size >> 32;
829 engine->video_frame.size.cy = size;
831 if ((gcd = get_gcd(engine->video_frame.size.cx, engine->video_frame.size.cy)))
833 engine->video_frame.ratio.cx = engine->video_frame.size.cx / gcd;
834 engine->video_frame.ratio.cy = engine->video_frame.size.cy / gcd;
837 IMFMediaType_Release(media_type);
840 static HRESULT WINAPI media_engine_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
842 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
843 IsEqualIID(riid, &IID_IUnknown))
845 *obj = iface;
846 IMFAsyncCallback_AddRef(iface);
847 return S_OK;
850 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
851 *obj = NULL;
852 return E_NOINTERFACE;
855 static ULONG WINAPI media_engine_session_events_AddRef(IMFAsyncCallback *iface)
857 struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
858 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
861 static ULONG WINAPI media_engine_session_events_Release(IMFAsyncCallback *iface)
863 struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
864 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
867 static HRESULT WINAPI media_engine_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
869 return E_NOTIMPL;
872 static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
874 struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface);
875 IMFMediaEvent *event = NULL;
876 MediaEventType event_type;
877 HRESULT hr;
879 if (FAILED(hr = IMFMediaSession_EndGetEvent(engine->session, result, &event)))
881 WARN("Failed to get session event, hr %#lx.\n", hr);
882 goto failed;
885 if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type)))
887 WARN("Failed to get event type, hr %#lx.\n", hr);
888 goto failed;
891 switch (event_type)
893 case MEBufferingStarted:
894 case MEBufferingStopped:
896 IMFMediaEngineNotify_EventNotify(engine->callback, event_type == MEBufferingStarted ?
897 MF_MEDIA_ENGINE_EVENT_BUFFERINGSTARTED : MF_MEDIA_ENGINE_EVENT_BUFFERINGENDED, 0, 0);
898 break;
899 case MESessionTopologyStatus:
901 UINT32 topo_status = 0;
902 IMFTopology *topology;
903 PROPVARIANT value;
905 IMFMediaEvent_GetUINT32(event, &MF_EVENT_TOPOLOGY_STATUS, &topo_status);
906 if (topo_status != MF_TOPOSTATUS_READY)
907 break;
909 value.vt = VT_EMPTY;
910 if (FAILED(IMFMediaEvent_GetValue(event, &value)))
911 break;
913 if (value.vt != VT_UNKNOWN)
915 PropVariantClear(&value);
916 break;
919 topology = (IMFTopology *)value.punkVal;
921 EnterCriticalSection(&engine->cs);
923 engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_METADATA;
925 media_engine_get_frame_size(engine, topology);
927 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE, 0, 0);
928 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA, 0, 0);
930 engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_ENOUGH_DATA;
932 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDDATA, 0, 0);
933 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_CANPLAY, 0, 0);
935 LeaveCriticalSection(&engine->cs);
937 PropVariantClear(&value);
939 break;
941 case MESessionStarted:
943 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAYING, 0, 0);
944 break;
945 case MESessionEnded:
947 EnterCriticalSection(&engine->cs);
948 media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, FALSE);
949 media_engine_set_flag(engine, FLAGS_ENGINE_IS_ENDED, TRUE);
950 engine->video_frame.pts = MINLONGLONG;
951 LeaveCriticalSection(&engine->cs);
953 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ENDED, 0, 0);
954 break;
957 failed:
959 if (event)
960 IMFMediaEvent_Release(event);
962 if (FAILED(hr = IMFMediaSession_BeginGetEvent(engine->session, iface, NULL)))
963 WARN("Failed to subscribe to session events, hr %#lx.\n", hr);
965 return S_OK;
968 static const IMFAsyncCallbackVtbl media_engine_session_events_vtbl =
970 media_engine_callback_QueryInterface,
971 media_engine_session_events_AddRef,
972 media_engine_session_events_Release,
973 media_engine_callback_GetParameters,
974 media_engine_session_events_Invoke,
977 static ULONG WINAPI media_engine_load_handler_AddRef(IMFAsyncCallback *iface)
979 struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
980 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
983 static ULONG WINAPI media_engine_load_handler_Release(IMFAsyncCallback *iface)
985 struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
986 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
989 static HRESULT media_engine_create_source_node(IMFMediaSource *source, IMFPresentationDescriptor *pd, IMFStreamDescriptor *sd,
990 IMFTopologyNode **node)
992 HRESULT hr;
994 if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, node)))
995 return hr;
997 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_SOURCE, (IUnknown *)source);
998 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)pd);
999 IMFTopologyNode_SetUnknown(*node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd);
1001 return S_OK;
1004 static HRESULT media_engine_create_audio_renderer(struct media_engine *engine, IMFTopologyNode **node)
1006 unsigned int category, role;
1007 IMFActivate *sar_activate;
1008 HRESULT hr;
1010 *node = NULL;
1012 if (FAILED(hr = MFCreateAudioRendererActivate(&sar_activate)))
1013 return hr;
1015 /* Configuration attributes keys differ between Engine and SAR. */
1016 if (SUCCEEDED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, &category)))
1017 IMFActivate_SetUINT32(sar_activate, &MF_AUDIO_RENDERER_ATTRIBUTE_STREAM_CATEGORY, category);
1018 if (SUCCEEDED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, &role)))
1019 IMFActivate_SetUINT32(sar_activate, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, role);
1021 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, node)))
1023 IMFTopologyNode_SetObject(*node, (IUnknown *)sar_activate);
1024 IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
1027 IMFActivate_Release(sar_activate);
1029 return hr;
1032 static HRESULT media_engine_create_video_renderer(struct media_engine *engine, IMFTopologyNode **node)
1034 DXGI_FORMAT output_format;
1035 IMFMediaType *media_type;
1036 IMFActivate *activate;
1037 GUID subtype;
1038 HRESULT hr;
1040 *node = NULL;
1042 if (FAILED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, &output_format)))
1044 WARN("Output format was not specified.\n");
1045 return E_FAIL;
1048 memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype));
1049 if (!(subtype.Data1 = MFMapDXGIFormatToDX9Format(output_format)))
1051 WARN("Unrecognized output format %#x.\n", output_format);
1052 return E_FAIL;
1055 if (FAILED(hr = MFCreateMediaType(&media_type)))
1056 return hr;
1058 IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video);
1059 IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &subtype);
1061 hr = MFCreateSampleGrabberSinkActivate(media_type, &engine->grabber_callback, &activate);
1062 IMFMediaType_Release(media_type);
1063 if (FAILED(hr))
1064 return hr;
1066 if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, node)))
1068 IMFTopologyNode_SetObject(*node, (IUnknown *)activate);
1069 IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
1072 IMFActivate_Release(activate);
1074 engine->video_frame.output_format = output_format;
1076 return hr;
1079 static void media_engine_clear_presentation(struct media_engine *engine)
1081 if (engine->presentation.source)
1083 IMFMediaSource_Shutdown(engine->presentation.source);
1084 IMFMediaSource_Release(engine->presentation.source);
1086 if (engine->presentation.pd)
1087 IMFPresentationDescriptor_Release(engine->presentation.pd);
1088 memset(&engine->presentation, 0, sizeof(engine->presentation));
1091 static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMediaSource *source)
1093 IMFStreamDescriptor *sd_audio = NULL, *sd_video = NULL;
1094 IMFPresentationDescriptor *pd;
1095 DWORD stream_count = 0, i;
1096 IMFTopology *topology;
1097 UINT64 duration;
1098 HRESULT hr;
1100 media_engine_release_video_frame_resources(engine);
1101 media_engine_clear_presentation(engine);
1103 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd)))
1104 return hr;
1106 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(pd, &stream_count)))
1107 WARN("Failed to get stream count, hr %#lx.\n", hr);
1109 /* Enable first video stream and first audio stream. */
1111 for (i = 0; i < stream_count; ++i)
1113 IMFMediaTypeHandler *type_handler;
1114 IMFStreamDescriptor *sd;
1115 BOOL selected;
1117 IMFPresentationDescriptor_DeselectStream(pd, i);
1119 if (sd_audio && sd_video)
1120 continue;
1122 IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, i, &selected, &sd);
1124 if (SUCCEEDED(IMFStreamDescriptor_GetMediaTypeHandler(sd, &type_handler)))
1126 GUID major = { 0 };
1128 IMFMediaTypeHandler_GetMajorType(type_handler, &major);
1130 if (IsEqualGUID(&major, &MFMediaType_Audio) && !sd_audio)
1132 sd_audio = sd;
1133 IMFStreamDescriptor_AddRef(sd_audio);
1134 IMFPresentationDescriptor_SelectStream(pd, i);
1136 else if (IsEqualGUID(&major, &MFMediaType_Video) && !sd_video && !(engine->flags & MF_MEDIA_ENGINE_AUDIOONLY))
1138 sd_video = sd;
1139 IMFStreamDescriptor_AddRef(sd_video);
1140 IMFPresentationDescriptor_SelectStream(pd, i);
1143 IMFMediaTypeHandler_Release(type_handler);
1146 IMFStreamDescriptor_Release(sd);
1149 if (!sd_video && !sd_audio)
1151 IMFPresentationDescriptor_Release(pd);
1152 return E_UNEXPECTED;
1155 engine->presentation.source = source;
1156 IMFMediaSource_AddRef(engine->presentation.source);
1157 engine->presentation.pd = pd;
1158 IMFPresentationDescriptor_AddRef(engine->presentation.pd);
1160 media_engine_set_flag(engine, FLAGS_ENGINE_HAS_VIDEO, !!sd_video);
1161 media_engine_set_flag(engine, FLAGS_ENGINE_HAS_AUDIO, !!sd_audio);
1163 /* Assume live source if duration was not provided. */
1164 if (SUCCEEDED(IMFPresentationDescriptor_GetUINT64(pd, &MF_PD_DURATION, &duration)))
1166 /* Convert 100ns to seconds. */
1167 engine->duration = duration / 10000000;
1169 else
1170 engine->duration = INFINITY;
1172 if (SUCCEEDED(hr = MFCreateTopology(&topology)))
1174 IMFTopologyNode *sar_node = NULL, *audio_src = NULL;
1175 IMFTopologyNode *grabber_node = NULL, *video_src = NULL;
1177 if (engine->flags & MF_MEDIA_ENGINE_REAL_TIME_MODE)
1178 IMFTopology_SetUINT32(topology, &MF_LOW_LATENCY, TRUE);
1180 if (sd_audio)
1182 if (FAILED(hr = media_engine_create_source_node(source, pd, sd_audio, &audio_src)))
1183 WARN("Failed to create audio source node, hr %#lx.\n", hr);
1185 if (FAILED(hr = media_engine_create_audio_renderer(engine, &sar_node)))
1186 WARN("Failed to create audio renderer node, hr %#lx.\n", hr);
1188 if (sar_node && audio_src)
1190 IMFTopology_AddNode(topology, audio_src);
1191 IMFTopology_AddNode(topology, sar_node);
1192 IMFTopologyNode_ConnectOutput(audio_src, 0, sar_node, 0);
1195 if (sar_node)
1196 IMFTopologyNode_Release(sar_node);
1197 if (audio_src)
1198 IMFTopologyNode_Release(audio_src);
1201 if (SUCCEEDED(hr) && sd_video)
1203 if (FAILED(hr = media_engine_create_source_node(source, pd, sd_video, &video_src)))
1204 WARN("Failed to create video source node, hr %#lx.\n", hr);
1206 if (FAILED(hr = media_engine_create_video_renderer(engine, &grabber_node)))
1207 WARN("Failed to create video grabber node, hr %#lx.\n", hr);
1209 if (grabber_node && video_src)
1211 IMFTopology_AddNode(topology, video_src);
1212 IMFTopology_AddNode(topology, grabber_node);
1213 IMFTopologyNode_ConnectOutput(video_src, 0, grabber_node, 0);
1216 if (SUCCEEDED(hr))
1217 IMFTopologyNode_GetTopoNodeID(video_src, &engine->video_frame.node_id);
1219 if (grabber_node)
1220 IMFTopologyNode_Release(grabber_node);
1221 if (video_src)
1222 IMFTopologyNode_Release(video_src);
1225 IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, TRUE);
1227 if (SUCCEEDED(hr))
1228 hr = IMFMediaSession_SetTopology(engine->session, MFSESSION_SETTOPOLOGY_IMMEDIATE, topology);
1231 if (topology)
1232 IMFTopology_Release(topology);
1234 if (sd_video)
1235 IMFStreamDescriptor_Release(sd_video);
1236 if (sd_audio)
1237 IMFStreamDescriptor_Release(sd_audio);
1239 IMFPresentationDescriptor_Release(pd);
1241 return hr;
1244 static void media_engine_start_playback(struct media_engine *engine)
1246 PROPVARIANT var;
1248 var.vt = VT_EMPTY;
1249 IMFMediaSession_Start(engine->session, &GUID_NULL, &var);
1252 static HRESULT WINAPI media_engine_load_handler_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1254 struct media_engine *engine = impl_from_load_handler_IMFAsyncCallback(iface);
1255 IUnknown *object = NULL, *state;
1256 unsigned int start_playback;
1257 MF_OBJECT_TYPE obj_type;
1258 IMFMediaSource *source;
1259 HRESULT hr;
1261 EnterCriticalSection(&engine->cs);
1263 engine->network_state = MF_MEDIA_ENGINE_NETWORK_LOADING;
1264 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADSTART, 0, 0);
1266 start_playback = engine->flags & FLAGS_ENGINE_PLAY_PENDING;
1267 media_engine_set_flag(engine, FLAGS_ENGINE_SOURCE_PENDING | FLAGS_ENGINE_PLAY_PENDING, FALSE);
1269 if (SUCCEEDED(IMFAsyncResult_GetState(result, &state)))
1271 hr = IMFSourceResolver_EndCreateObjectFromByteStream(engine->resolver, result, &obj_type, &object);
1272 IUnknown_Release(state);
1274 else
1275 hr = IMFSourceResolver_EndCreateObjectFromURL(engine->resolver, result, &obj_type, &object);
1277 if (FAILED(hr))
1278 WARN("Failed to create source object, hr %#lx.\n", hr);
1280 if (object)
1282 if (SUCCEEDED(hr = IUnknown_QueryInterface(object, &IID_IMFMediaSource, (void **)&source)))
1284 hr = media_engine_create_topology(engine, source);
1285 IMFMediaSource_Release(source);
1287 IUnknown_Release(object);
1290 if (SUCCEEDED(hr))
1292 engine->network_state = MF_MEDIA_ENGINE_NETWORK_IDLE;
1293 if (start_playback)
1294 media_engine_start_playback(engine);
1296 else
1298 engine->network_state = MF_MEDIA_ENGINE_NETWORK_NO_SOURCE;
1299 engine->error_code = MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED;
1300 engine->extended_code = hr;
1301 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ERROR, engine->error_code,
1302 engine->extended_code);
1305 LeaveCriticalSection(&engine->cs);
1307 return S_OK;
1310 static const IMFAsyncCallbackVtbl media_engine_load_handler_vtbl =
1312 media_engine_callback_QueryInterface,
1313 media_engine_load_handler_AddRef,
1314 media_engine_load_handler_Release,
1315 media_engine_callback_GetParameters,
1316 media_engine_load_handler_Invoke,
1319 static HRESULT WINAPI media_engine_QueryInterface(IMFMediaEngineEx *iface, REFIID riid, void **obj)
1321 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1323 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1325 if (IsEqualIID(riid, &IID_IMFMediaEngineEx) ||
1326 IsEqualIID(riid, &IID_IMFMediaEngine) ||
1327 IsEqualIID(riid, &IID_IUnknown))
1329 *obj = iface;
1331 else if (IsEqualIID(riid, &IID_IMFGetService))
1333 *obj = &engine->IMFGetService_iface;
1335 else
1337 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1338 *obj = NULL;
1339 return E_NOINTERFACE;
1342 IUnknown_AddRef((IUnknown *)*obj);
1343 return S_OK;
1346 static ULONG WINAPI media_engine_AddRef(IMFMediaEngineEx *iface)
1348 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1349 ULONG refcount = InterlockedIncrement(&engine->refcount);
1351 TRACE("%p, refcount %lu.\n", iface, refcount);
1353 return refcount;
1356 static void free_media_engine(struct media_engine *engine)
1358 if (engine->callback)
1359 IMFMediaEngineNotify_Release(engine->callback);
1360 if (engine->clock)
1361 IMFPresentationClock_Release(engine->clock);
1362 if (engine->session)
1363 IMFMediaSession_Release(engine->session);
1364 if (engine->attributes)
1365 IMFAttributes_Release(engine->attributes);
1366 if (engine->resolver)
1367 IMFSourceResolver_Release(engine->resolver);
1368 media_engine_release_video_frame_resources(engine);
1369 media_engine_clear_presentation(engine);
1370 if (engine->device_manager)
1372 IMFDXGIDeviceManager_CloseDeviceHandle(engine->device_manager, engine->device_handle);
1373 IMFDXGIDeviceManager_Release(engine->device_manager);
1375 SysFreeString(engine->current_source);
1376 DeleteCriticalSection(&engine->cs);
1377 free(engine->video_frame.buffer);
1378 free(engine);
1381 static ULONG WINAPI media_engine_Release(IMFMediaEngineEx *iface)
1383 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1384 ULONG refcount = InterlockedDecrement(&engine->refcount);
1386 TRACE("%p, refcount %lu.\n", iface, refcount);
1388 if (!refcount)
1389 free_media_engine(engine);
1391 return refcount;
1394 static HRESULT WINAPI media_engine_GetError(IMFMediaEngineEx *iface, IMFMediaError **error)
1396 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1397 HRESULT hr = S_OK;
1399 TRACE("%p, %p.\n", iface, error);
1401 *error = NULL;
1403 EnterCriticalSection(&engine->cs);
1404 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1405 hr = MF_E_SHUTDOWN;
1406 else if (engine->error_code)
1408 if (SUCCEEDED(hr = create_media_error(error)))
1410 IMFMediaError_SetErrorCode(*error, engine->error_code);
1411 IMFMediaError_SetExtendedErrorCode(*error, engine->extended_code);
1414 LeaveCriticalSection(&engine->cs);
1416 return hr;
1419 static HRESULT WINAPI media_engine_SetErrorCode(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_ERR code)
1421 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1422 HRESULT hr = S_OK;
1424 TRACE("%p, %u.\n", iface, code);
1426 if ((unsigned int)code > MF_MEDIA_ENGINE_ERR_ENCRYPTED)
1427 return E_INVALIDARG;
1429 EnterCriticalSection(&engine->cs);
1430 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1431 hr = MF_E_SHUTDOWN;
1432 else
1433 engine->error_code = code;
1434 LeaveCriticalSection(&engine->cs);
1436 return hr;
1439 static HRESULT WINAPI media_engine_SetSourceElements(IMFMediaEngineEx *iface, IMFMediaEngineSrcElements *elements)
1441 FIXME("(%p, %p): stub.\n", iface, elements);
1443 return E_NOTIMPL;
1446 static HRESULT media_engine_set_source(struct media_engine *engine, IMFByteStream *bytestream, BSTR url)
1448 IPropertyStore *props = NULL;
1449 unsigned int flags;
1450 HRESULT hr = S_OK;
1452 SysFreeString(engine->current_source);
1453 engine->current_source = NULL;
1454 if (url)
1455 engine->current_source = SysAllocString(url);
1457 engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_NOTHING;
1459 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
1461 engine->network_state = MF_MEDIA_ENGINE_NETWORK_NO_SOURCE;
1463 if (url || bytestream)
1465 flags = MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE;
1466 if (engine->flags & MF_MEDIA_ENGINE_DISABLE_LOCAL_PLUGINS)
1467 flags |= MF_RESOLUTION_DISABLE_LOCAL_PLUGINS;
1469 IMFAttributes_GetUnknown(engine->attributes, &MF_MEDIA_ENGINE_SOURCE_RESOLVER_CONFIG_STORE,
1470 &IID_IPropertyStore, (void **)&props);
1471 if (bytestream)
1472 hr = IMFSourceResolver_BeginCreateObjectFromByteStream(engine->resolver, bytestream, url, flags,
1473 props, NULL, &engine->load_handler, (IUnknown *)bytestream);
1474 else
1475 hr = IMFSourceResolver_BeginCreateObjectFromURL(engine->resolver, url, flags, props, NULL,
1476 &engine->load_handler, NULL);
1477 if (SUCCEEDED(hr))
1478 media_engine_set_flag(engine, FLAGS_ENGINE_SOURCE_PENDING, TRUE);
1480 if (props)
1481 IPropertyStore_Release(props);
1484 return hr;
1487 static HRESULT WINAPI media_engine_SetSource(IMFMediaEngineEx *iface, BSTR url)
1489 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1490 HRESULT hr;
1492 TRACE("%p, %s.\n", iface, debugstr_w(url));
1494 EnterCriticalSection(&engine->cs);
1496 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1497 hr = MF_E_SHUTDOWN;
1498 else
1499 hr = media_engine_set_source(engine, NULL, url);
1501 LeaveCriticalSection(&engine->cs);
1503 return hr;
1506 static HRESULT WINAPI media_engine_GetCurrentSource(IMFMediaEngineEx *iface, BSTR *url)
1508 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1509 HRESULT hr = S_OK;
1511 TRACE("%p, %p.\n", iface, url);
1513 *url = NULL;
1515 EnterCriticalSection(&engine->cs);
1517 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1518 hr = MF_E_SHUTDOWN;
1519 if (engine->current_source)
1521 if (!(*url = SysAllocString(engine->current_source)))
1522 hr = E_OUTOFMEMORY;
1525 LeaveCriticalSection(&engine->cs);
1527 return hr;
1530 static USHORT WINAPI media_engine_GetNetworkState(IMFMediaEngineEx *iface)
1532 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1534 TRACE("%p.\n", iface);
1536 return engine->network_state;
1539 static MF_MEDIA_ENGINE_PRELOAD WINAPI media_engine_GetPreload(IMFMediaEngineEx *iface)
1541 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1542 MF_MEDIA_ENGINE_PRELOAD preload;
1544 TRACE("%p.\n", iface);
1546 EnterCriticalSection(&engine->cs);
1547 preload = engine->preload;
1548 LeaveCriticalSection(&engine->cs);
1550 return preload;
1553 static HRESULT WINAPI media_engine_SetPreload(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_PRELOAD preload)
1555 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1557 TRACE("%p, %d.\n", iface, preload);
1559 EnterCriticalSection(&engine->cs);
1560 engine->preload = preload;
1561 LeaveCriticalSection(&engine->cs);
1563 return S_OK;
1566 static HRESULT WINAPI media_engine_GetBuffered(IMFMediaEngineEx *iface, IMFMediaTimeRange **range)
1568 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1569 HRESULT hr;
1571 TRACE("%p, %p.\n", iface, range);
1573 if (FAILED(hr = create_time_range(range)))
1574 return hr;
1576 EnterCriticalSection(&engine->cs);
1578 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1579 hr = MF_E_SHUTDOWN;
1580 else if (!isnan(engine->duration))
1581 hr = IMFMediaTimeRange_AddRange(*range, 0.0, engine->duration);
1583 LeaveCriticalSection(&engine->cs);
1585 return hr;
1588 static HRESULT WINAPI media_engine_Load(IMFMediaEngineEx *iface)
1590 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1591 HRESULT hr = E_NOTIMPL;
1593 FIXME("(%p): stub.\n", iface);
1595 EnterCriticalSection(&engine->cs);
1597 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1598 hr = MF_E_SHUTDOWN;
1600 LeaveCriticalSection(&engine->cs);
1602 return hr;
1605 static HRESULT WINAPI media_engine_CanPlayType(IMFMediaEngineEx *iface, BSTR type, MF_MEDIA_ENGINE_CANPLAY *answer)
1607 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1608 HRESULT hr = E_NOTIMPL;
1610 FIXME("(%p, %s, %p): stub.\n", iface, debugstr_w(type), answer);
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 USHORT WINAPI media_engine_GetReadyState(IMFMediaEngineEx *iface)
1624 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1625 unsigned short state;
1627 TRACE("%p.\n", iface);
1629 EnterCriticalSection(&engine->cs);
1630 state = engine->ready_state;
1631 LeaveCriticalSection(&engine->cs);
1633 return state;
1636 static BOOL WINAPI media_engine_IsSeeking(IMFMediaEngineEx *iface)
1638 FIXME("(%p): stub.\n", iface);
1640 return FALSE;
1643 static double WINAPI media_engine_GetCurrentTime(IMFMediaEngineEx *iface)
1645 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1646 double ret = 0.0;
1647 MFTIME clocktime;
1649 TRACE("%p.\n", iface);
1651 EnterCriticalSection(&engine->cs);
1652 if (engine->flags & FLAGS_ENGINE_IS_ENDED)
1654 ret = engine->duration;
1656 else if (SUCCEEDED(IMFPresentationClock_GetTime(engine->clock, &clocktime)))
1658 ret = (double)clocktime / 10000000.0;
1660 LeaveCriticalSection(&engine->cs);
1662 return ret;
1665 static HRESULT WINAPI media_engine_SetCurrentTime(IMFMediaEngineEx *iface, double time)
1667 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1668 HRESULT hr = E_NOTIMPL;
1670 FIXME("(%p, %f): stub.\n", iface, time);
1672 EnterCriticalSection(&engine->cs);
1674 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1675 hr = MF_E_SHUTDOWN;
1677 LeaveCriticalSection(&engine->cs);
1679 return hr;
1682 static double WINAPI media_engine_GetStartTime(IMFMediaEngineEx *iface)
1684 FIXME("(%p): stub.\n", iface);
1686 return 0.0;
1689 static double WINAPI media_engine_GetDuration(IMFMediaEngineEx *iface)
1691 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1692 double value;
1694 TRACE("%p.\n", iface);
1696 EnterCriticalSection(&engine->cs);
1697 value = engine->duration;
1698 LeaveCriticalSection(&engine->cs);
1700 return value;
1703 static BOOL WINAPI media_engine_IsPaused(IMFMediaEngineEx *iface)
1705 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1706 BOOL value;
1708 TRACE("%p.\n", iface);
1710 EnterCriticalSection(&engine->cs);
1711 value = !!(engine->flags & FLAGS_ENGINE_PAUSED);
1712 LeaveCriticalSection(&engine->cs);
1714 return value;
1717 static double WINAPI media_engine_GetDefaultPlaybackRate(IMFMediaEngineEx *iface)
1719 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1720 double rate;
1722 TRACE("%p.\n", iface);
1724 EnterCriticalSection(&engine->cs);
1725 rate = engine->default_playback_rate;
1726 LeaveCriticalSection(&engine->cs);
1728 return rate;
1731 static HRESULT WINAPI media_engine_SetDefaultPlaybackRate(IMFMediaEngineEx *iface, double rate)
1733 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1734 HRESULT hr = S_OK;
1736 TRACE("%p, %f.\n", iface, rate);
1738 EnterCriticalSection(&engine->cs);
1739 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1740 hr = MF_E_SHUTDOWN;
1741 else if (engine->default_playback_rate != rate)
1743 engine->default_playback_rate = rate;
1744 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_RATECHANGE, 0, 0);
1746 LeaveCriticalSection(&engine->cs);
1748 return hr;
1751 static double WINAPI media_engine_GetPlaybackRate(IMFMediaEngineEx *iface)
1753 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1754 double rate;
1756 TRACE("%p.\n", iface);
1758 EnterCriticalSection(&engine->cs);
1759 rate = engine->playback_rate;
1760 LeaveCriticalSection(&engine->cs);
1762 return rate;
1765 static HRESULT WINAPI media_engine_SetPlaybackRate(IMFMediaEngineEx *iface, double rate)
1767 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1768 HRESULT hr = S_OK;
1770 TRACE("%p, %f.\n", iface, rate);
1772 EnterCriticalSection(&engine->cs);
1773 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1774 hr = MF_E_SHUTDOWN;
1775 else if (engine->playback_rate != rate)
1777 engine->playback_rate = rate;
1778 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_RATECHANGE, 0, 0);
1780 LeaveCriticalSection(&engine->cs);
1782 return hr;
1785 static HRESULT WINAPI media_engine_GetPlayed(IMFMediaEngineEx *iface, IMFMediaTimeRange **played)
1787 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1788 HRESULT hr = E_NOTIMPL;
1790 FIXME("(%p, %p): stub.\n", iface, played);
1792 EnterCriticalSection(&engine->cs);
1794 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1795 hr = MF_E_SHUTDOWN;
1797 LeaveCriticalSection(&engine->cs);
1799 return hr;
1802 static HRESULT WINAPI media_engine_GetSeekable(IMFMediaEngineEx *iface, IMFMediaTimeRange **seekable)
1804 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1805 HRESULT hr = E_NOTIMPL;
1807 FIXME("(%p, %p): stub.\n", iface, seekable);
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 BOOL WINAPI media_engine_IsEnded(IMFMediaEngineEx *iface)
1821 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1822 BOOL value;
1824 TRACE("%p.\n", iface);
1826 EnterCriticalSection(&engine->cs);
1827 value = !!(engine->flags & FLAGS_ENGINE_IS_ENDED);
1828 LeaveCriticalSection(&engine->cs);
1830 return value;
1833 static BOOL WINAPI media_engine_GetAutoPlay(IMFMediaEngineEx *iface)
1835 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1836 BOOL value;
1838 TRACE("%p.\n", iface);
1840 EnterCriticalSection(&engine->cs);
1841 value = !!(engine->flags & FLAGS_ENGINE_AUTO_PLAY);
1842 LeaveCriticalSection(&engine->cs);
1844 return value;
1847 static HRESULT WINAPI media_engine_SetAutoPlay(IMFMediaEngineEx *iface, BOOL autoplay)
1849 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1851 FIXME("(%p, %d): stub.\n", iface, autoplay);
1853 EnterCriticalSection(&engine->cs);
1854 media_engine_set_flag(engine, FLAGS_ENGINE_AUTO_PLAY, autoplay);
1855 LeaveCriticalSection(&engine->cs);
1857 return S_OK;
1860 static BOOL WINAPI media_engine_GetLoop(IMFMediaEngineEx *iface)
1862 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1863 BOOL value;
1865 TRACE("%p.\n", iface);
1867 EnterCriticalSection(&engine->cs);
1868 value = !!(engine->flags & FLAGS_ENGINE_LOOP);
1869 LeaveCriticalSection(&engine->cs);
1871 return value;
1874 static HRESULT WINAPI media_engine_SetLoop(IMFMediaEngineEx *iface, BOOL loop)
1876 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1878 FIXME("(%p, %d): stub.\n", iface, loop);
1880 EnterCriticalSection(&engine->cs);
1881 media_engine_set_flag(engine, FLAGS_ENGINE_LOOP, loop);
1882 LeaveCriticalSection(&engine->cs);
1884 return S_OK;
1887 static HRESULT WINAPI media_engine_Play(IMFMediaEngineEx *iface)
1889 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1890 HRESULT hr = S_OK;
1892 TRACE("%p.\n", iface);
1894 EnterCriticalSection(&engine->cs);
1896 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1897 hr = MF_E_SHUTDOWN;
1898 else
1900 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
1902 if (!(engine->flags & FLAGS_ENGINE_WAITING))
1904 media_engine_set_flag(engine, FLAGS_ENGINE_PAUSED | FLAGS_ENGINE_IS_ENDED, FALSE);
1905 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAY, 0, 0);
1907 if (!(engine->flags & FLAGS_ENGINE_SOURCE_PENDING))
1908 media_engine_start_playback(engine);
1909 else
1910 media_engine_set_flag(engine, FLAGS_ENGINE_PLAY_PENDING, TRUE);
1912 media_engine_set_flag(engine, FLAGS_ENGINE_WAITING, TRUE);
1915 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_WAITING, 0, 0);
1918 LeaveCriticalSection(&engine->cs);
1920 return hr;
1923 static HRESULT WINAPI media_engine_Pause(IMFMediaEngineEx *iface)
1925 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1926 HRESULT hr = S_OK;
1928 TRACE("%p.\n", iface);
1930 EnterCriticalSection(&engine->cs);
1932 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1933 hr = MF_E_SHUTDOWN;
1934 else
1936 if (!(engine->flags & FLAGS_ENGINE_PAUSED))
1938 media_engine_set_flag(engine, FLAGS_ENGINE_WAITING | FLAGS_ENGINE_IS_ENDED, FALSE);
1939 media_engine_set_flag(engine, FLAGS_ENGINE_PAUSED, TRUE);
1941 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_TIMEUPDATE, 0, 0);
1942 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PAUSE, 0, 0);
1945 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, 0, 0);
1948 LeaveCriticalSection(&engine->cs);
1950 return hr;
1953 static BOOL WINAPI media_engine_GetMuted(IMFMediaEngineEx *iface)
1955 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1956 BOOL ret;
1958 TRACE("%p.\n", iface);
1960 EnterCriticalSection(&engine->cs);
1961 ret = !!(engine->flags & FLAGS_ENGINE_MUTED);
1962 LeaveCriticalSection(&engine->cs);
1964 return ret;
1967 static HRESULT WINAPI media_engine_SetMuted(IMFMediaEngineEx *iface, BOOL muted)
1969 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1970 HRESULT hr = S_OK;
1972 TRACE("%p, %d.\n", iface, muted);
1974 EnterCriticalSection(&engine->cs);
1975 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
1976 hr = MF_E_SHUTDOWN;
1977 else if (!!(engine->flags & FLAGS_ENGINE_MUTED) ^ !!muted)
1979 media_engine_set_flag(engine, FLAGS_ENGINE_MUTED, muted);
1980 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE, 0, 0);
1982 LeaveCriticalSection(&engine->cs);
1984 return hr;
1987 static double WINAPI media_engine_GetVolume(IMFMediaEngineEx *iface)
1989 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
1990 double volume;
1992 TRACE("%p.\n", iface);
1994 EnterCriticalSection(&engine->cs);
1995 volume = engine->volume;
1996 LeaveCriticalSection(&engine->cs);
1998 return volume;
2001 static HRESULT WINAPI media_engine_SetVolume(IMFMediaEngineEx *iface, double volume)
2003 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2004 HRESULT hr = S_OK;
2006 TRACE("%p, %f.\n", iface, volume);
2008 EnterCriticalSection(&engine->cs);
2009 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2010 hr = MF_E_SHUTDOWN;
2011 else if (volume != engine->volume)
2013 engine->volume = volume;
2014 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE, 0, 0);
2016 LeaveCriticalSection(&engine->cs);
2018 return hr;
2021 static BOOL WINAPI media_engine_HasVideo(IMFMediaEngineEx *iface)
2023 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2024 BOOL value;
2026 TRACE("%p.\n", iface);
2028 EnterCriticalSection(&engine->cs);
2029 value = !!(engine->flags & FLAGS_ENGINE_HAS_VIDEO);
2030 LeaveCriticalSection(&engine->cs);
2032 return value;
2035 static BOOL WINAPI media_engine_HasAudio(IMFMediaEngineEx *iface)
2037 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2038 BOOL value;
2040 TRACE("%p.\n", iface);
2042 EnterCriticalSection(&engine->cs);
2043 value = !!(engine->flags & FLAGS_ENGINE_HAS_AUDIO);
2044 LeaveCriticalSection(&engine->cs);
2046 return value;
2049 static HRESULT WINAPI media_engine_GetNativeVideoSize(IMFMediaEngineEx *iface, DWORD *cx, DWORD *cy)
2051 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2052 HRESULT hr = S_OK;
2054 TRACE("%p, %p, %p.\n", iface, cx, cy);
2056 if (!cx && !cy)
2057 return E_INVALIDARG;
2059 EnterCriticalSection(&engine->cs);
2061 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2062 hr = MF_E_SHUTDOWN;
2063 else if (!engine->video_frame.size.cx && !engine->video_frame.size.cy)
2064 hr = E_FAIL;
2065 else
2067 if (cx) *cx = engine->video_frame.size.cx;
2068 if (cy) *cy = engine->video_frame.size.cy;
2071 LeaveCriticalSection(&engine->cs);
2073 return hr;
2076 static HRESULT WINAPI media_engine_GetVideoAspectRatio(IMFMediaEngineEx *iface, DWORD *cx, DWORD *cy)
2078 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2079 HRESULT hr = S_OK;
2081 TRACE("%p, %p, %p.\n", iface, cx, cy);
2083 if (!cx && !cy)
2084 return E_INVALIDARG;
2086 EnterCriticalSection(&engine->cs);
2088 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2089 hr = MF_E_SHUTDOWN;
2090 else if (!engine->video_frame.size.cx && !engine->video_frame.size.cy)
2091 hr = E_FAIL;
2092 else
2094 if (cx) *cx = engine->video_frame.ratio.cx;
2095 if (cy) *cy = engine->video_frame.ratio.cy;
2098 LeaveCriticalSection(&engine->cs);
2100 return hr;
2103 static HRESULT WINAPI media_engine_Shutdown(IMFMediaEngineEx *iface)
2105 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2106 HRESULT hr = S_OK;
2108 FIXME("(%p): stub.\n", iface);
2110 EnterCriticalSection(&engine->cs);
2111 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2112 hr = MF_E_SHUTDOWN;
2113 else
2115 media_engine_set_flag(engine, FLAGS_ENGINE_SHUT_DOWN, TRUE);
2116 media_engine_clear_presentation(engine);
2117 IMFMediaSession_Shutdown(engine->session);
2119 LeaveCriticalSection(&engine->cs);
2121 return hr;
2124 static void set_rect(struct rect *rect, float left, float top, float right, float bottom)
2126 rect->left = left;
2127 rect->top = top;
2128 rect->right = right;
2129 rect->bottom = bottom;
2132 static void media_engine_adjust_destination_for_ratio(const struct media_engine *engine,
2133 struct rect *src_n, struct rect *dst)
2135 float dst_width = dst->right - dst->left, dst_height = dst->bottom - dst->top;
2136 D3D11_TEXTURE2D_DESC source_desc;
2137 float src_width, src_height;
2138 struct rect src;
2140 ID3D11Texture2D_GetDesc(engine->video_frame.d3d11.source, &source_desc);
2141 set_rect(&src, src_n->left * source_desc.Width, src_n->top * source_desc.Height,
2142 src_n->right * source_desc.Width, src_n->bottom * source_desc.Height);
2144 src_width = src.right - src.left;
2145 src_height = src.bottom - src.top;
2147 if (src_width * dst_height > dst_width * src_height)
2149 /* src is "wider" than dst. */
2150 float dst_center = (dst->top + dst->bottom) / 2.0f;
2151 float scaled_height = src_height * dst_width / src_width;
2153 dst->top = dst_center - scaled_height / 2.0f;
2154 dst->bottom = dst->top + scaled_height;
2156 else if (src_width * dst_height < dst_width * src_height)
2158 /* src is "taller" than dst. */
2159 float dst_center = (dst->left + dst->right) / 2.0f;
2160 float scaled_width = src_width * dst_height / src_height;
2162 dst->left = dst_center - scaled_width / 2.0f;
2163 dst->right = dst->left + scaled_width;
2167 static void media_engine_update_d3d11_frame_surface(ID3D11DeviceContext *context, struct media_engine *engine)
2169 D3D11_TEXTURE2D_DESC surface_desc;
2171 if (!(engine->flags & FLAGS_ENGINE_NEW_FRAME))
2172 return;
2174 ID3D11Texture2D_GetDesc(engine->video_frame.d3d11.source, &surface_desc);
2176 switch (surface_desc.Format)
2178 case DXGI_FORMAT_B8G8R8A8_UNORM:
2179 case DXGI_FORMAT_B8G8R8X8_UNORM:
2180 surface_desc.Width *= 4;
2181 break;
2182 default:
2183 FIXME("Unsupported format %#x.\n", surface_desc.Format);
2184 surface_desc.Width = 0;
2187 if (engine->video_frame.buffer_size == surface_desc.Width * surface_desc.Height)
2189 ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)engine->video_frame.d3d11.source,
2190 0, NULL, engine->video_frame.buffer, surface_desc.Width, 0);
2193 media_engine_set_flag(engine, FLAGS_ENGINE_NEW_FRAME, FALSE);
2196 static HRESULT media_engine_transfer_to_d3d11_texture(struct media_engine *engine, ID3D11Texture2D *texture,
2197 const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color)
2199 static const float black[] = {0.0f, 0.0f, 0.0f, 0.0f};
2200 ID3D11Device *device, *dst_device;
2201 ID3D11DeviceContext *context;
2202 ID3D11RenderTargetView *rtv;
2203 unsigned int stride, offset;
2204 D3D11_TEXTURE2D_DESC desc;
2205 BOOL device_mismatch;
2206 struct vec3 quad[4];
2207 D3D11_VIEWPORT vp;
2208 struct rect src, dst;
2209 struct color backcolor;
2210 HRESULT hr;
2211 RECT rect;
2213 if (FAILED(hr = media_engine_lock_d3d_device(engine, &device)))
2214 return hr;
2216 if (FAILED(hr = media_engine_create_d3d11_video_frame_resources(engine, device)))
2218 WARN("Failed to create d3d resources, hr %#lx.\n", hr);
2219 goto done;
2222 ID3D11Texture2D_GetDevice(texture, &dst_device);
2223 device_mismatch = device != dst_device;
2224 ID3D11Device_Release(dst_device);
2226 if (device_mismatch)
2228 WARN("Destination target from different device.\n");
2229 hr = E_UNEXPECTED;
2230 goto done;
2233 ID3D11Texture2D_GetDesc(texture, &desc);
2235 if (FAILED(hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)texture, NULL, &rtv)))
2237 WARN("Failed to create an rtv, hr %#lx.\n", hr);
2238 goto done;
2241 ID3D11Device_GetImmediateContext(device, &context);
2243 /* Whole destination is cleared, regardless of specified rectangle. */
2244 ID3D11DeviceContext_ClearRenderTargetView(context, rtv, black);
2246 if (dst_rect)
2248 rect.left = max(0, dst_rect->left);
2249 rect.top = max(0, dst_rect->top);
2250 rect.right = min(desc.Width, dst_rect->right);
2251 rect.bottom = min(desc.Height, dst_rect->bottom);
2253 quad[0].x = 2.0f * rect.left / desc.Width - 1.0f;
2254 quad[0].y = -2.0f * rect.bottom / desc.Height + 1.0f;
2255 quad[0].z = 0.0f;
2257 quad[1].x = quad[0].x;
2258 quad[1].y = -2.0f * rect.top / desc.Height + 1.0f;
2259 quad[1].z = 0.0f;
2261 quad[2].x = 2.0f * rect.right / desc.Width - 1.0f;
2262 quad[2].y = quad[0].y;
2263 quad[2].z = 0.0f;
2265 quad[3].x = quad[2].x;
2266 quad[3].y = quad[1].y;
2267 quad[3].z = 0.0f;
2269 set_rect(&dst, dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom);
2271 else
2273 memcpy(quad, fullquad, sizeof(quad));
2274 set_rect(&dst, 0.0f, 0.0f, desc.Width, desc.Height);
2277 if (src_rect)
2278 memcpy(&src, src_rect, sizeof(src));
2279 else
2280 set_rect(&src, 0.0f, 0.0f, 1.0f, 1.0f);
2282 media_engine_adjust_destination_for_ratio(engine, &src, &dst);
2284 if (memcmp(quad, engine->video_frame.d3d11.quad, sizeof(quad)))
2286 memcpy(engine->video_frame.d3d11.quad, quad, sizeof(quad));
2287 ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)engine->video_frame.d3d11.vb, 0, NULL, quad, 0, 0);
2290 if (color)
2292 backcolor.r = color->rgbRed / 255.0f;
2293 backcolor.g = color->rgbGreen / 255.0f;
2294 backcolor.b = color->rgbBlue / 255.0f;
2295 backcolor.a = color->rgbAlpha / 255.0f;
2297 else
2298 memcpy(&backcolor, black, sizeof(backcolor));
2300 if (memcmp(&dst, &engine->video_frame.d3d11.cb.dst, sizeof(dst)) ||
2301 memcmp(&src, &engine->video_frame.d3d11.cb.src, sizeof(src)) ||
2302 memcmp(&backcolor, &engine->video_frame.d3d11.cb.backcolor, sizeof(backcolor)))
2304 memcpy(&engine->video_frame.d3d11.cb.dst, &dst, sizeof(dst));
2305 memcpy(&engine->video_frame.d3d11.cb.src, &src, sizeof(src));
2306 memcpy(&engine->video_frame.d3d11.cb.backcolor, &backcolor, sizeof(backcolor));
2308 ID3D11DeviceContext_UpdateSubresource(context, (ID3D11Resource *)engine->video_frame.d3d11.ps_cb, 0, NULL,
2309 &engine->video_frame.d3d11.cb, 0, 0);
2312 /* Update with new frame contents */
2313 media_engine_update_d3d11_frame_surface(context, engine);
2315 vp.TopLeftX = 0.0f;
2316 vp.TopLeftY = 0.0f;
2317 vp.Width = desc.Width;
2318 vp.Height = desc.Height;
2319 vp.MinDepth = 0.0f;
2320 vp.MaxDepth = 1.0f;
2321 ID3D11DeviceContext_RSSetViewports(context, 1, &vp);
2323 ID3D11DeviceContext_IASetInputLayout(context, engine->video_frame.d3d11.input_layout);
2324 ID3D11DeviceContext_IASetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
2325 stride = sizeof(*quad);
2326 offset = 0;
2327 ID3D11DeviceContext_IASetVertexBuffers(context, 0, 1, &engine->video_frame.d3d11.vb, &stride, &offset);
2328 ID3D11DeviceContext_VSSetShader(context, engine->video_frame.d3d11.vs, NULL, 0);
2329 ID3D11DeviceContext_PSSetShader(context, engine->video_frame.d3d11.ps, NULL, 0);
2330 ID3D11DeviceContext_PSSetShaderResources(context, 0, 1, &engine->video_frame.d3d11.srv);
2331 ID3D11DeviceContext_PSSetConstantBuffers(context, 0, 1, &engine->video_frame.d3d11.ps_cb);
2332 ID3D11DeviceContext_PSSetSamplers(context, 0, 1, &engine->video_frame.d3d11.sampler);
2333 ID3D11DeviceContext_OMSetRenderTargets(context, 1, &rtv, NULL);
2335 ID3D11DeviceContext_Draw(context, 4, 0);
2337 ID3D11RenderTargetView_Release(rtv);
2338 ID3D11DeviceContext_Release(context);
2340 done:
2341 media_engine_unlock_d3d_device(engine, device);
2343 return hr;
2346 static HRESULT WINAPI media_engine_TransferVideoFrame(IMFMediaEngineEx *iface, IUnknown *surface,
2347 const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color)
2349 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2350 ID3D11Texture2D *texture;
2351 HRESULT hr = E_NOINTERFACE;
2353 TRACE("%p, %p, %s, %s, %p.\n", iface, surface, src_rect ? wine_dbg_sprintf("(%f,%f)-(%f,%f)",
2354 src_rect->left, src_rect->top, src_rect->right, src_rect->bottom) : "(null)",
2355 wine_dbgstr_rect(dst_rect), color);
2357 EnterCriticalSection(&engine->cs);
2359 if (SUCCEEDED(IUnknown_QueryInterface(surface, &IID_ID3D11Texture2D, (void **)&texture)))
2361 hr = media_engine_transfer_to_d3d11_texture(engine, texture, src_rect, dst_rect, color);
2362 ID3D11Texture2D_Release(texture);
2364 else
2366 FIXME("Unsupported destination type.\n");
2369 LeaveCriticalSection(&engine->cs);
2371 return hr;
2374 static HRESULT WINAPI media_engine_OnVideoStreamTick(IMFMediaEngineEx *iface, LONGLONG *pts)
2376 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2377 HRESULT hr;
2379 TRACE("%p, %p.\n", iface, pts);
2381 EnterCriticalSection(&engine->cs);
2383 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2384 hr = MF_E_SHUTDOWN;
2385 else if (!pts)
2386 hr = E_POINTER;
2387 else
2389 *pts = engine->video_frame.pts;
2390 hr = *pts == MINLONGLONG ? S_FALSE : S_OK;
2393 LeaveCriticalSection(&engine->cs);
2395 return hr;
2398 static HRESULT WINAPI media_engine_SetSourceFromByteStream(IMFMediaEngineEx *iface, IMFByteStream *bytestream, BSTR url)
2400 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2401 HRESULT hr;
2403 TRACE("%p, %p, %s.\n", iface, bytestream, debugstr_w(url));
2405 EnterCriticalSection(&engine->cs);
2407 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2408 hr = MF_E_SHUTDOWN;
2409 else if (!bytestream || !url)
2410 hr = E_POINTER;
2411 else
2412 hr = media_engine_set_source(engine, bytestream, url);
2414 LeaveCriticalSection(&engine->cs);
2416 return hr;
2419 static HRESULT WINAPI media_engine_GetStatistics(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_STATISTIC stat_id, PROPVARIANT *stat)
2421 FIXME("%p, %x, %p stub.\n", iface, stat_id, stat);
2423 return E_NOTIMPL;
2426 static HRESULT WINAPI media_engine_UpdateVideoStream(IMFMediaEngineEx *iface, const MFVideoNormalizedRect *src,
2427 const RECT *dst, const MFARGB *border_color)
2429 FIXME("%p, %p, %p, %p stub.\n", iface, src, dst, border_color);
2431 return E_NOTIMPL;
2434 static double WINAPI media_engine_GetBalance(IMFMediaEngineEx *iface)
2436 FIXME("%p stub.\n", iface);
2438 return 0.0;
2441 static HRESULT WINAPI media_engine_SetBalance(IMFMediaEngineEx *iface, double balance)
2443 FIXME("%p, %f stub.\n", iface, balance);
2445 return E_NOTIMPL;
2448 static BOOL WINAPI media_engine_IsPlaybackRateSupported(IMFMediaEngineEx *iface, double rate)
2450 FIXME("%p, %f stub.\n", iface, rate);
2452 return FALSE;
2455 static HRESULT WINAPI media_engine_FrameStep(IMFMediaEngineEx *iface, BOOL forward)
2457 FIXME("%p, %d stub.\n", iface, forward);
2459 return E_NOTIMPL;
2462 static HRESULT WINAPI media_engine_GetResourceCharacteristics(IMFMediaEngineEx *iface, DWORD *flags)
2464 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2465 HRESULT hr = E_FAIL;
2467 TRACE("%p, %p.\n", iface, flags);
2469 EnterCriticalSection(&engine->cs);
2470 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2471 hr = MF_E_SHUTDOWN;
2472 else if (engine->presentation.source)
2473 hr = IMFMediaSource_GetCharacteristics(engine->presentation.source, flags);
2474 LeaveCriticalSection(&engine->cs);
2476 return hr;
2479 static HRESULT WINAPI media_engine_GetPresentationAttribute(IMFMediaEngineEx *iface, REFGUID attribute,
2480 PROPVARIANT *value)
2482 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2483 HRESULT hr = E_FAIL;
2485 TRACE("%p, %s, %p.\n", iface, debugstr_guid(attribute), value);
2487 EnterCriticalSection(&engine->cs);
2488 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2489 hr = MF_E_SHUTDOWN;
2490 else if (engine->presentation.pd)
2491 hr = IMFPresentationDescriptor_GetItem(engine->presentation.pd, attribute, value);
2492 LeaveCriticalSection(&engine->cs);
2494 return hr;
2497 static HRESULT WINAPI media_engine_GetNumberOfStreams(IMFMediaEngineEx *iface, DWORD *stream_count)
2499 FIXME("%p, %p stub.\n", iface, stream_count);
2501 return E_NOTIMPL;
2504 static HRESULT WINAPI media_engine_GetStreamAttribute(IMFMediaEngineEx *iface, DWORD stream_index, REFGUID attribute,
2505 PROPVARIANT *value)
2507 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2508 IMFStreamDescriptor *sd;
2509 HRESULT hr = E_FAIL;
2510 BOOL selected;
2512 TRACE("%p, %ld, %s, %p.\n", iface, stream_index, debugstr_guid(attribute), value);
2514 EnterCriticalSection(&engine->cs);
2515 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2516 hr = MF_E_SHUTDOWN;
2517 else if (engine->presentation.pd)
2519 if (SUCCEEDED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(engine->presentation.pd,
2520 stream_index, &selected, &sd)))
2522 hr = IMFStreamDescriptor_GetItem(sd, attribute, value);
2523 IMFStreamDescriptor_Release(sd);
2526 LeaveCriticalSection(&engine->cs);
2528 return hr;
2531 static HRESULT WINAPI media_engine_GetStreamSelection(IMFMediaEngineEx *iface, DWORD stream_index, BOOL *enabled)
2533 FIXME("%p, %ld, %p stub.\n", iface, stream_index, enabled);
2535 return E_NOTIMPL;
2538 static HRESULT WINAPI media_engine_SetStreamSelection(IMFMediaEngineEx *iface, DWORD stream_index, BOOL enabled)
2540 FIXME("%p, %ld, %d stub.\n", iface, stream_index, enabled);
2542 return E_NOTIMPL;
2545 static HRESULT WINAPI media_engine_ApplyStreamSelections(IMFMediaEngineEx *iface)
2547 FIXME("%p stub.\n", iface);
2549 return E_NOTIMPL;
2552 static HRESULT WINAPI media_engine_IsProtected(IMFMediaEngineEx *iface, BOOL *protected)
2554 FIXME("%p, %p stub.\n", iface, protected);
2556 return E_NOTIMPL;
2559 static HRESULT WINAPI media_engine_InsertVideoEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional)
2561 FIXME("%p, %p, %d stub.\n", iface, effect, is_optional);
2563 return E_NOTIMPL;
2566 static HRESULT WINAPI media_engine_InsertAudioEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional)
2568 FIXME("%p, %p, %d stub.\n", iface, effect, is_optional);
2570 return E_NOTIMPL;
2573 static HRESULT WINAPI media_engine_RemoveAllEffects(IMFMediaEngineEx *iface)
2575 FIXME("%p stub.\n", iface);
2577 return E_NOTIMPL;
2580 static HRESULT WINAPI media_engine_SetTimelineMarkerTimer(IMFMediaEngineEx *iface, double timeout)
2582 FIXME("%p, %f stub.\n", iface, timeout);
2584 return E_NOTIMPL;
2587 static HRESULT WINAPI media_engine_GetTimelineMarkerTimer(IMFMediaEngineEx *iface, double *timeout)
2589 FIXME("%p, %p stub.\n", iface, timeout);
2591 return E_NOTIMPL;
2594 static HRESULT WINAPI media_engine_CancelTimelineMarkerTimer(IMFMediaEngineEx *iface)
2596 FIXME("%p stub.\n", iface);
2598 return E_NOTIMPL;
2601 static BOOL WINAPI media_engine_IsStereo3D(IMFMediaEngineEx *iface)
2603 FIXME("%p stub.\n", iface);
2605 return FALSE;
2608 static HRESULT WINAPI media_engine_GetStereo3DFramePackingMode(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_S3D_PACKING_MODE *mode)
2610 FIXME("%p, %p stub.\n", iface, mode);
2612 return E_NOTIMPL;
2615 static HRESULT WINAPI media_engine_SetStereo3DFramePackingMode(IMFMediaEngineEx *iface, MF_MEDIA_ENGINE_S3D_PACKING_MODE mode)
2617 FIXME("%p, %#x stub.\n", iface, mode);
2619 return E_NOTIMPL;
2622 static HRESULT WINAPI media_engine_GetStereo3DRenderMode(IMFMediaEngineEx *iface, MF3DVideoOutputType *output_type)
2624 FIXME("%p, %p stub.\n", iface, output_type);
2626 return E_NOTIMPL;
2629 static HRESULT WINAPI media_engine_SetStereo3DRenderMode(IMFMediaEngineEx *iface, MF3DVideoOutputType output_type)
2631 FIXME("%p, %#x stub.\n", iface, output_type);
2633 return E_NOTIMPL;
2636 static HRESULT WINAPI media_engine_EnableWindowlessSwapchainMode(IMFMediaEngineEx *iface, BOOL enable)
2638 FIXME("%p, %d stub.\n", iface, enable);
2640 return E_NOTIMPL;
2643 static HRESULT WINAPI media_engine_GetVideoSwapchainHandle(IMFMediaEngineEx *iface, HANDLE *swapchain)
2645 FIXME("%p, %p stub.\n", iface, swapchain);
2647 return E_NOTIMPL;
2650 static HRESULT WINAPI media_engine_EnableHorizontalMirrorMode(IMFMediaEngineEx *iface, BOOL enable)
2652 FIXME("%p, %d stub.\n", iface, enable);
2654 return E_NOTIMPL;
2657 static HRESULT WINAPI media_engine_GetAudioStreamCategory(IMFMediaEngineEx *iface, UINT32 *category)
2659 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2660 HRESULT hr;
2662 TRACE("%p, %p.\n", iface, category);
2664 EnterCriticalSection(&engine->cs);
2666 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2667 hr = MF_E_SHUTDOWN;
2668 else
2669 hr = IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, category);
2671 LeaveCriticalSection(&engine->cs);
2673 return hr;
2676 static HRESULT WINAPI media_engine_SetAudioStreamCategory(IMFMediaEngineEx *iface, UINT32 category)
2678 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2679 HRESULT hr;
2681 TRACE("%p, %u.\n", iface, category);
2683 EnterCriticalSection(&engine->cs);
2685 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2686 hr = MF_E_SHUTDOWN;
2687 else
2688 hr = IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, category);
2690 LeaveCriticalSection(&engine->cs);
2692 return hr;
2695 static HRESULT WINAPI media_engine_GetAudioEndpointRole(IMFMediaEngineEx *iface, UINT32 *role)
2697 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2698 HRESULT hr;
2700 TRACE("%p, %p.\n", iface, role);
2702 EnterCriticalSection(&engine->cs);
2704 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2705 hr = MF_E_SHUTDOWN;
2706 else
2707 hr = IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, role);
2709 LeaveCriticalSection(&engine->cs);
2711 return hr;
2714 static HRESULT WINAPI media_engine_SetAudioEndpointRole(IMFMediaEngineEx *iface, UINT32 role)
2716 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2717 HRESULT hr;
2719 TRACE("%p, %u.\n", iface, role);
2721 EnterCriticalSection(&engine->cs);
2723 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2724 hr = MF_E_SHUTDOWN;
2725 else
2726 hr = IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, role);
2728 LeaveCriticalSection(&engine->cs);
2730 return hr;
2733 static HRESULT WINAPI media_engine_GetRealTimeMode(IMFMediaEngineEx *iface, BOOL *enabled)
2735 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2736 HRESULT hr = S_OK;
2738 TRACE("%p, %p.\n", iface, enabled);
2740 EnterCriticalSection(&engine->cs);
2741 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2742 hr = MF_E_SHUTDOWN;
2743 else
2744 *enabled = !!(engine->flags & MF_MEDIA_ENGINE_REAL_TIME_MODE);
2745 LeaveCriticalSection(&engine->cs);
2747 return hr;
2750 static HRESULT WINAPI media_engine_SetRealTimeMode(IMFMediaEngineEx *iface, BOOL enable)
2752 struct media_engine *engine = impl_from_IMFMediaEngineEx(iface);
2753 HRESULT hr = S_OK;
2755 TRACE("%p, %d.\n", iface, enable);
2757 EnterCriticalSection(&engine->cs);
2758 if (engine->flags & FLAGS_ENGINE_SHUT_DOWN)
2759 hr = MF_E_SHUTDOWN;
2760 else
2761 media_engine_set_flag(engine, MF_MEDIA_ENGINE_REAL_TIME_MODE, enable);
2762 LeaveCriticalSection(&engine->cs);
2764 return hr;
2767 static HRESULT WINAPI media_engine_SetCurrentTimeEx(IMFMediaEngineEx *iface, double seektime, MF_MEDIA_ENGINE_SEEK_MODE mode)
2769 FIXME("%p, %f, %#x stub.\n", iface, seektime, mode);
2771 return E_NOTIMPL;
2774 static HRESULT WINAPI media_engine_EnableTimeUpdateTimer(IMFMediaEngineEx *iface, BOOL enable)
2776 FIXME("%p, %d stub.\n", iface, enable);
2778 return E_NOTIMPL;
2781 static const IMFMediaEngineExVtbl media_engine_vtbl =
2783 media_engine_QueryInterface,
2784 media_engine_AddRef,
2785 media_engine_Release,
2786 media_engine_GetError,
2787 media_engine_SetErrorCode,
2788 media_engine_SetSourceElements,
2789 media_engine_SetSource,
2790 media_engine_GetCurrentSource,
2791 media_engine_GetNetworkState,
2792 media_engine_GetPreload,
2793 media_engine_SetPreload,
2794 media_engine_GetBuffered,
2795 media_engine_Load,
2796 media_engine_CanPlayType,
2797 media_engine_GetReadyState,
2798 media_engine_IsSeeking,
2799 media_engine_GetCurrentTime,
2800 media_engine_SetCurrentTime,
2801 media_engine_GetStartTime,
2802 media_engine_GetDuration,
2803 media_engine_IsPaused,
2804 media_engine_GetDefaultPlaybackRate,
2805 media_engine_SetDefaultPlaybackRate,
2806 media_engine_GetPlaybackRate,
2807 media_engine_SetPlaybackRate,
2808 media_engine_GetPlayed,
2809 media_engine_GetSeekable,
2810 media_engine_IsEnded,
2811 media_engine_GetAutoPlay,
2812 media_engine_SetAutoPlay,
2813 media_engine_GetLoop,
2814 media_engine_SetLoop,
2815 media_engine_Play,
2816 media_engine_Pause,
2817 media_engine_GetMuted,
2818 media_engine_SetMuted,
2819 media_engine_GetVolume,
2820 media_engine_SetVolume,
2821 media_engine_HasVideo,
2822 media_engine_HasAudio,
2823 media_engine_GetNativeVideoSize,
2824 media_engine_GetVideoAspectRatio,
2825 media_engine_Shutdown,
2826 media_engine_TransferVideoFrame,
2827 media_engine_OnVideoStreamTick,
2828 media_engine_SetSourceFromByteStream,
2829 media_engine_GetStatistics,
2830 media_engine_UpdateVideoStream,
2831 media_engine_GetBalance,
2832 media_engine_SetBalance,
2833 media_engine_IsPlaybackRateSupported,
2834 media_engine_FrameStep,
2835 media_engine_GetResourceCharacteristics,
2836 media_engine_GetPresentationAttribute,
2837 media_engine_GetNumberOfStreams,
2838 media_engine_GetStreamAttribute,
2839 media_engine_GetStreamSelection,
2840 media_engine_SetStreamSelection,
2841 media_engine_ApplyStreamSelections,
2842 media_engine_IsProtected,
2843 media_engine_InsertVideoEffect,
2844 media_engine_InsertAudioEffect,
2845 media_engine_RemoveAllEffects,
2846 media_engine_SetTimelineMarkerTimer,
2847 media_engine_GetTimelineMarkerTimer,
2848 media_engine_CancelTimelineMarkerTimer,
2849 media_engine_IsStereo3D,
2850 media_engine_GetStereo3DFramePackingMode,
2851 media_engine_SetStereo3DFramePackingMode,
2852 media_engine_GetStereo3DRenderMode,
2853 media_engine_SetStereo3DRenderMode,
2854 media_engine_EnableWindowlessSwapchainMode,
2855 media_engine_GetVideoSwapchainHandle,
2856 media_engine_EnableHorizontalMirrorMode,
2857 media_engine_GetAudioStreamCategory,
2858 media_engine_SetAudioStreamCategory,
2859 media_engine_GetAudioEndpointRole,
2860 media_engine_SetAudioEndpointRole,
2861 media_engine_GetRealTimeMode,
2862 media_engine_SetRealTimeMode,
2863 media_engine_SetCurrentTimeEx,
2864 media_engine_EnableTimeUpdateTimer,
2867 static HRESULT WINAPI media_engine_gs_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
2869 struct media_engine *engine = impl_from_IMFGetService(iface);
2870 return IMFMediaEngineEx_QueryInterface(&engine->IMFMediaEngineEx_iface, riid, obj);
2873 static ULONG WINAPI media_engine_gs_AddRef(IMFGetService *iface)
2875 struct media_engine *engine = impl_from_IMFGetService(iface);
2876 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
2879 static ULONG WINAPI media_engine_gs_Release(IMFGetService *iface)
2881 struct media_engine *engine = impl_from_IMFGetService(iface);
2882 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
2885 static HRESULT WINAPI media_engine_gs_GetService(IMFGetService *iface, REFGUID service,
2886 REFIID riid, void **object)
2888 FIXME("%p, %s, %s, %p stub.\n", iface, debugstr_guid(service), debugstr_guid(riid), object);
2890 return E_NOTIMPL;
2893 static const IMFGetServiceVtbl media_engine_get_service_vtbl =
2895 media_engine_gs_QueryInterface,
2896 media_engine_gs_AddRef,
2897 media_engine_gs_Release,
2898 media_engine_gs_GetService,
2901 static HRESULT WINAPI media_engine_grabber_callback_QueryInterface(IMFSampleGrabberSinkCallback *iface,
2902 REFIID riid, void **obj)
2904 if (IsEqualIID(riid, &IID_IMFSampleGrabberSinkCallback) ||
2905 IsEqualIID(riid, &IID_IUnknown))
2907 *obj = iface;
2908 IMFSampleGrabberSinkCallback_AddRef(iface);
2909 return S_OK;
2912 *obj = NULL;
2913 return E_NOINTERFACE;
2916 static ULONG WINAPI media_engine_grabber_callback_AddRef(IMFSampleGrabberSinkCallback *iface)
2918 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
2919 return IMFMediaEngineEx_AddRef(&engine->IMFMediaEngineEx_iface);
2922 static ULONG WINAPI media_engine_grabber_callback_Release(IMFSampleGrabberSinkCallback *iface)
2924 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
2925 return IMFMediaEngineEx_Release(&engine->IMFMediaEngineEx_iface);
2928 static HRESULT WINAPI media_engine_grabber_callback_OnClockStart(IMFSampleGrabberSinkCallback *iface,
2929 MFTIME systime, LONGLONG start_offset)
2931 return S_OK;
2934 static HRESULT WINAPI media_engine_grabber_callback_OnClockStop(IMFSampleGrabberSinkCallback *iface,
2935 MFTIME systime)
2937 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
2939 EnterCriticalSection(&engine->cs);
2940 media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, FALSE);
2941 engine->video_frame.pts = MINLONGLONG;
2942 LeaveCriticalSection(&engine->cs);
2944 return S_OK;
2947 static HRESULT WINAPI media_engine_grabber_callback_OnClockPause(IMFSampleGrabberSinkCallback *iface,
2948 MFTIME systime)
2950 return S_OK;
2953 static HRESULT WINAPI media_engine_grabber_callback_OnClockRestart(IMFSampleGrabberSinkCallback *iface,
2954 MFTIME systime)
2956 return S_OK;
2959 static HRESULT WINAPI media_engine_grabber_callback_OnClockSetRate(IMFSampleGrabberSinkCallback *iface,
2960 MFTIME systime, float rate)
2962 return S_OK;
2965 static HRESULT WINAPI media_engine_grabber_callback_OnSetPresentationClock(IMFSampleGrabberSinkCallback *iface,
2966 IMFPresentationClock *clock)
2968 return S_OK;
2971 static HRESULT WINAPI media_engine_grabber_callback_OnProcessSample(IMFSampleGrabberSinkCallback *iface,
2972 REFGUID major_type, DWORD sample_flags, LONGLONG sample_time, LONGLONG sample_duration,
2973 const BYTE *buffer, DWORD buffer_size)
2975 struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface);
2977 EnterCriticalSection(&engine->cs);
2979 if (!(engine->flags & FLAGS_ENGINE_FIRST_FRAME))
2981 IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY, 0, 0);
2982 media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, TRUE);
2984 engine->video_frame.pts = sample_time;
2985 if (engine->video_frame.buffer_size < buffer_size)
2987 free(engine->video_frame.buffer);
2988 if ((engine->video_frame.buffer = malloc(buffer_size)))
2989 engine->video_frame.buffer_size = buffer_size;
2991 if (engine->video_frame.buffer)
2993 memcpy(engine->video_frame.buffer, buffer, buffer_size);
2994 engine->flags |= FLAGS_ENGINE_NEW_FRAME;
2997 LeaveCriticalSection(&engine->cs);
2999 return S_OK;
3002 static HRESULT WINAPI media_engine_grabber_callback_OnShutdown(IMFSampleGrabberSinkCallback *iface)
3004 return S_OK;
3007 static const IMFSampleGrabberSinkCallbackVtbl media_engine_grabber_callback_vtbl =
3009 media_engine_grabber_callback_QueryInterface,
3010 media_engine_grabber_callback_AddRef,
3011 media_engine_grabber_callback_Release,
3012 media_engine_grabber_callback_OnClockStart,
3013 media_engine_grabber_callback_OnClockStop,
3014 media_engine_grabber_callback_OnClockPause,
3015 media_engine_grabber_callback_OnClockRestart,
3016 media_engine_grabber_callback_OnClockSetRate,
3017 media_engine_grabber_callback_OnSetPresentationClock,
3018 media_engine_grabber_callback_OnProcessSample,
3019 media_engine_grabber_callback_OnShutdown,
3022 static HRESULT WINAPI media_engine_factory_QueryInterface(IMFMediaEngineClassFactory *iface, REFIID riid, void **obj)
3024 if (IsEqualIID(riid, &IID_IMFMediaEngineClassFactory) ||
3025 IsEqualIID(riid, &IID_IUnknown))
3027 *obj = iface;
3028 IMFMediaEngineClassFactory_AddRef(iface);
3029 return S_OK;
3032 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
3033 *obj = NULL;
3034 return E_NOINTERFACE;
3037 static ULONG WINAPI media_engine_factory_AddRef(IMFMediaEngineClassFactory *iface)
3039 return 2;
3042 static ULONG WINAPI media_engine_factory_Release(IMFMediaEngineClassFactory *iface)
3044 return 1;
3047 static HRESULT init_media_engine(DWORD flags, IMFAttributes *attributes, struct media_engine *engine)
3049 DXGI_FORMAT output_format;
3050 UINT64 playback_hwnd;
3051 IMFClock *clock;
3052 HRESULT hr;
3054 engine->IMFMediaEngineEx_iface.lpVtbl = &media_engine_vtbl;
3055 engine->IMFGetService_iface.lpVtbl = &media_engine_get_service_vtbl;
3056 engine->session_events.lpVtbl = &media_engine_session_events_vtbl;
3057 engine->load_handler.lpVtbl = &media_engine_load_handler_vtbl;
3058 engine->grabber_callback.lpVtbl = &media_engine_grabber_callback_vtbl;
3059 engine->refcount = 1;
3060 engine->flags = (flags & MF_MEDIA_ENGINE_CREATEFLAGS_MASK) | FLAGS_ENGINE_PAUSED;
3061 engine->default_playback_rate = 1.0;
3062 engine->playback_rate = 1.0;
3063 engine->volume = 1.0;
3064 engine->duration = NAN;
3065 engine->video_frame.pts = MINLONGLONG;
3066 InitializeCriticalSection(&engine->cs);
3068 hr = IMFAttributes_GetUnknown(attributes, &MF_MEDIA_ENGINE_CALLBACK, &IID_IMFMediaEngineNotify,
3069 (void **)&engine->callback);
3070 if (FAILED(hr))
3071 return hr;
3073 IMFAttributes_GetUnknown(attributes, &MF_MEDIA_ENGINE_DXGI_MANAGER, &IID_IMFDXGIDeviceManager,
3074 (void **)&engine->device_manager);
3076 if (FAILED(hr = MFCreateMediaSession(NULL, &engine->session)))
3077 return hr;
3079 if (FAILED(hr = IMFMediaSession_GetClock(engine->session, &clock)))
3080 return hr;
3082 hr = IMFClock_QueryInterface(clock, &IID_IMFPresentationClock, (void **)&engine->clock);
3083 IMFClock_Release(clock);
3084 if (FAILED(hr))
3085 return hr;
3087 if (FAILED(hr = IMFMediaSession_BeginGetEvent(engine->session, &engine->session_events, NULL)))
3088 return hr;
3090 if (FAILED(hr = MFCreateSourceResolver(&engine->resolver)))
3091 return hr;
3093 if (FAILED(hr = MFCreateAttributes(&engine->attributes, 0)))
3094 return hr;
3096 if (FAILED(hr = IMFAttributes_CopyAllItems(attributes, engine->attributes)))
3097 return hr;
3099 /* Set default audio configuration */
3100 if (FAILED(IMFAttributes_GetItem(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, NULL)))
3101 IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_CATEGORY, AudioCategory_Other);
3102 if (FAILED(IMFAttributes_GetItem(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, NULL)))
3103 IMFAttributes_SetUINT32(engine->attributes, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE, eMultimedia);
3105 IMFAttributes_GetUINT64(attributes, &MF_MEDIA_ENGINE_PLAYBACK_HWND, &playback_hwnd);
3106 hr = IMFAttributes_GetUINT32(attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, &output_format);
3107 if (playback_hwnd) /* FIXME: handle MF_MEDIA_ENGINE_PLAYBACK_VISUAL */
3108 engine->mode = MEDIA_ENGINE_RENDERING_MODE;
3109 else
3111 if (SUCCEEDED(hr))
3112 engine->mode = MEDIA_ENGINE_FRAME_SERVER_MODE;
3113 else
3114 engine->mode = MEDIA_ENGINE_AUDIO_MODE;
3117 return S_OK;
3120 static HRESULT WINAPI media_engine_factory_CreateInstance(IMFMediaEngineClassFactory *iface, DWORD flags,
3121 IMFAttributes *attributes, IMFMediaEngine **engine)
3123 struct media_engine *object;
3124 HRESULT hr;
3126 TRACE("%p, %#lx, %p, %p.\n", iface, flags, attributes, engine);
3128 if (!attributes || !engine)
3129 return E_POINTER;
3131 object = calloc(1, sizeof(*object));
3132 if (!object)
3133 return E_OUTOFMEMORY;
3135 hr = init_media_engine(flags, attributes, object);
3136 if (FAILED(hr))
3138 free_media_engine(object);
3139 return hr;
3142 *engine = (IMFMediaEngine *)&object->IMFMediaEngineEx_iface;
3144 return S_OK;
3147 static HRESULT WINAPI media_engine_factory_CreateTimeRange(IMFMediaEngineClassFactory *iface,
3148 IMFMediaTimeRange **range)
3150 TRACE("%p, %p.\n", iface, range);
3152 return create_time_range(range);
3155 static HRESULT WINAPI media_engine_factory_CreateError(IMFMediaEngineClassFactory *iface, IMFMediaError **error)
3157 TRACE("%p, %p.\n", iface, error);
3159 return create_media_error(error);
3162 static const IMFMediaEngineClassFactoryVtbl media_engine_factory_vtbl =
3164 media_engine_factory_QueryInterface,
3165 media_engine_factory_AddRef,
3166 media_engine_factory_Release,
3167 media_engine_factory_CreateInstance,
3168 media_engine_factory_CreateTimeRange,
3169 media_engine_factory_CreateError,
3172 static IMFMediaEngineClassFactory media_engine_factory = { &media_engine_factory_vtbl };
3174 static HRESULT WINAPI classfactory_QueryInterface(IClassFactory *iface, REFIID riid, void **obj)
3176 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
3178 if (IsEqualGUID(riid, &IID_IClassFactory) ||
3179 IsEqualGUID(riid, &IID_IUnknown))
3181 IClassFactory_AddRef(iface);
3182 *obj = iface;
3183 return S_OK;
3186 WARN("interface %s not implemented.\n", debugstr_guid(riid));
3187 *obj = NULL;
3188 return E_NOINTERFACE;
3191 static ULONG WINAPI classfactory_AddRef(IClassFactory *iface)
3193 return 2;
3196 static ULONG WINAPI classfactory_Release(IClassFactory *iface)
3198 return 1;
3201 static HRESULT WINAPI classfactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **obj)
3203 TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), obj);
3205 *obj = NULL;
3207 if (outer)
3208 return CLASS_E_NOAGGREGATION;
3210 return IMFMediaEngineClassFactory_QueryInterface(&media_engine_factory, riid, obj);
3213 static HRESULT WINAPI classfactory_LockServer(IClassFactory *iface, BOOL dolock)
3215 FIXME("(%d): stub.\n", dolock);
3216 return S_OK;
3219 static const IClassFactoryVtbl class_factory_vtbl =
3221 classfactory_QueryInterface,
3222 classfactory_AddRef,
3223 classfactory_Release,
3224 classfactory_CreateInstance,
3225 classfactory_LockServer,
3228 static IClassFactory classfactory = { &class_factory_vtbl };
3230 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **obj)
3232 TRACE("%s, %s, %p.\n", debugstr_guid(clsid), debugstr_guid(riid), obj);
3234 if (IsEqualGUID(clsid, &CLSID_MFMediaEngineClassFactory))
3235 return IClassFactory_QueryInterface(&classfactory, riid, obj);
3237 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
3238 *obj = NULL;
3239 return CLASS_E_CLASSNOTAVAILABLE;