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