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