2 * Copyright 2019 Jactry Zeng for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "mfmediaengine.h"
32 #include "mmdeviceapi.h"
33 #include "audiosessiontypes.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
39 static BOOL
mf_array_reserve(void **elements
, size_t *capacity
, size_t count
, size_t size
)
41 size_t new_capacity
, max_capacity
;
44 if (count
<= *capacity
)
47 max_capacity
= ~(SIZE_T
)0 / size
;
48 if (count
> max_capacity
)
51 new_capacity
= max(4, *capacity
);
52 while (new_capacity
< count
&& new_capacity
<= max_capacity
/ 2)
54 if (new_capacity
< count
)
55 new_capacity
= max_capacity
;
57 if (!(new_elements
= realloc(*elements
, new_capacity
* size
)))
60 *elements
= new_elements
;
61 *capacity
= new_capacity
;
66 /* Convert 100ns to seconds */
67 static double mftime_to_seconds(MFTIME time
)
69 return (double)time
/ 10000000.0;
72 enum media_engine_mode
75 MEDIA_ENGINE_AUDIO_MODE
,
76 MEDIA_ENGINE_RENDERING_MODE
,
77 MEDIA_ENGINE_FRAME_SERVER_MODE
,
80 /* Used with create flags. */
81 enum media_engine_flags
83 /* MF_MEDIA_ENGINE_CREATEFLAGS_MASK is 0x1f. */
84 FLAGS_ENGINE_SHUT_DOWN
= 0x20,
85 FLAGS_ENGINE_AUTO_PLAY
= 0x40,
86 FLAGS_ENGINE_LOOP
= 0x80,
87 FLAGS_ENGINE_PAUSED
= 0x100,
88 FLAGS_ENGINE_WAITING
= 0x200,
89 FLAGS_ENGINE_MUTED
= 0x400,
90 FLAGS_ENGINE_HAS_AUDIO
= 0x800,
91 FLAGS_ENGINE_HAS_VIDEO
= 0x1000,
92 FLAGS_ENGINE_FIRST_FRAME
= 0x2000,
93 FLAGS_ENGINE_IS_ENDED
= 0x4000,
94 FLAGS_ENGINE_NEW_FRAME
= 0x8000,
95 FLAGS_ENGINE_SOURCE_PENDING
= 0x10000,
96 FLAGS_ENGINE_PLAY_PENDING
= 0x20000,
109 static const struct vec3 fullquad
[] =
111 {-1.0f
, -1.0f
, 0.0f
},
113 { 1.0f
, -1.0f
, 0.0f
},
119 float left
, top
, right
, bottom
;
130 struct effect
*effects
;
137 IMFMediaEngineEx IMFMediaEngineEx_iface
;
138 IMFGetService IMFGetService_iface
;
139 IMFAsyncCallback session_events
;
140 IMFAsyncCallback load_handler
;
141 IMFSampleGrabberSinkCallback grabber_callback
;
143 IMFMediaEngineNotify
*callback
;
144 IMFAttributes
*attributes
;
145 IMFDXGIDeviceManager
*device_manager
;
146 HANDLE device_handle
;
147 enum media_engine_mode mode
;
149 double playback_rate
;
150 double default_playback_rate
;
153 MF_MEDIA_ENGINE_NETWORK network_state
;
154 MF_MEDIA_ENGINE_ERR error_code
;
155 HRESULT extended_code
;
156 MF_MEDIA_ENGINE_READY ready_state
;
157 MF_MEDIA_ENGINE_PRELOAD preload
;
158 IMFMediaSession
*session
;
159 IMFPresentationClock
*clock
;
160 IMFSourceResolver
*resolver
;
161 IMFMediaEngineExtension
*extension
;
165 IMFMediaSource
*source
;
166 IMFPresentationDescriptor
*pd
;
168 struct effects video_effects
;
169 struct effects audio_effects
;
178 DXGI_FORMAT output_format
;
184 ID3D11Texture2D
*source
;
185 ID3D11ShaderResourceView
*srv
;
186 ID3D11SamplerState
*sampler
;
187 ID3D11InputLayout
*input_layout
;
188 ID3D11VertexShader
*vs
;
189 ID3D11PixelShader
*ps
;
195 struct color backcolor
;
202 static void media_engine_release_video_frame_resources(struct media_engine
*engine
)
204 if (engine
->video_frame
.d3d11
.vb
)
205 ID3D11Buffer_Release(engine
->video_frame
.d3d11
.vb
);
206 if (engine
->video_frame
.d3d11
.ps_cb
)
207 ID3D11Buffer_Release(engine
->video_frame
.d3d11
.ps_cb
);
208 if (engine
->video_frame
.d3d11
.source
)
209 ID3D11Texture2D_Release(engine
->video_frame
.d3d11
.source
);
210 if (engine
->video_frame
.d3d11
.srv
)
211 ID3D11ShaderResourceView_Release(engine
->video_frame
.d3d11
.srv
);
212 if (engine
->video_frame
.d3d11
.sampler
)
213 ID3D11SamplerState_Release(engine
->video_frame
.d3d11
.sampler
);
214 if (engine
->video_frame
.d3d11
.input_layout
)
215 ID3D11InputLayout_Release(engine
->video_frame
.d3d11
.input_layout
);
216 if (engine
->video_frame
.d3d11
.vs
)
217 ID3D11VertexShader_Release(engine
->video_frame
.d3d11
.vs
);
218 if (engine
->video_frame
.d3d11
.ps
)
219 ID3D11PixelShader_Release(engine
->video_frame
.d3d11
.ps
);
221 memset(&engine
->video_frame
.d3d11
, 0, sizeof(engine
->video_frame
.d3d11
));
222 memcpy(engine
->video_frame
.d3d11
.quad
, fullquad
, sizeof(fullquad
));
225 static HRESULT
media_engine_lock_d3d_device(struct media_engine
*engine
, ID3D11Device
**device
)
229 if (!engine
->device_manager
)
231 FIXME("Device manager wasn't set.\n");
235 if (!engine
->device_handle
)
237 if (FAILED(hr
= IMFDXGIDeviceManager_OpenDeviceHandle(engine
->device_manager
, &engine
->device_handle
)))
239 WARN("Failed to open device handle, hr %#lx.\n", hr
);
244 hr
= IMFDXGIDeviceManager_LockDevice(engine
->device_manager
, engine
->device_handle
, &IID_ID3D11Device
,
245 (void **)device
, TRUE
);
246 if (hr
== MF_E_DXGI_NEW_VIDEO_DEVICE
)
248 IMFDXGIDeviceManager_CloseDeviceHandle(engine
->device_manager
, engine
->device_handle
);
249 engine
->device_handle
= NULL
;
251 media_engine_release_video_frame_resources(engine
);
253 if (FAILED(hr
= IMFDXGIDeviceManager_OpenDeviceHandle(engine
->device_manager
, &engine
->device_handle
)))
255 WARN("Failed to open a device handle, hr %#lx.\n", hr
);
258 hr
= IMFDXGIDeviceManager_LockDevice(engine
->device_manager
, engine
->device_handle
, &IID_ID3D11Device
,
259 (void **)device
, TRUE
);
265 static void media_engine_unlock_d3d_device(struct media_engine
*engine
, ID3D11Device
*device
)
267 ID3D11Device_Release(device
);
268 IMFDXGIDeviceManager_UnlockDevice(engine
->device_manager
, engine
->device_handle
, FALSE
);
271 static HRESULT
media_engine_create_d3d11_video_frame_resources(struct media_engine
*engine
, ID3D11Device
*device
)
273 static const D3D11_INPUT_ELEMENT_DESC layout_desc
[] =
275 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT
, 0, 0, D3D11_INPUT_PER_VERTEX_DATA
, 0 },
277 static const DWORD vs_code
[] =
280 float4
main(float4 position
: POSITION
) : SV_POSITION
285 0x43425844, 0xa7a2f22d, 0x83ff2560, 0xe61638bd, 0x87e3ce90, 0x00000001, 0x000000d8, 0x00000003,
286 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
287 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x49534f50, 0x4e4f4954, 0xababab00,
288 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, 0x00000003,
289 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x52444853, 0x0000003c, 0x00010040,
290 0x0000000f, 0x0300005f, 0x001010f2, 0x00000000, 0x04000067, 0x001020f2, 0x00000000, 0x00000001,
291 0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000000, 0x0100003e,
293 static const DWORD ps_code
[] =
302 float4
main(float4 position
: SV_POSITION
) : SV_TARGET
306 if (position
.x
< dst
.x
|| position
.x
> dst
.z
) return backcolor
;
307 if (position
.y
< dst
.y
|| position
.y
> dst
.w
) return backcolor
;
308 p
.x
= (position
.x
- dst
.x
) / (dst
.z
- dst
.x
);
309 p
.y
= (position
.y
- dst
.y
) / (dst
.w
- dst
.y
);
310 p
.x
= src
.x
+ p
.x
* (src
.z
- src
.x
);
311 p
.y
= src
.y
+ p
.y
* (src
.w
- src
.y
);
312 return t
.Sample(s
, p
);
315 0x43425844, 0xae2162b7, 0x0fd69625, 0x6784c41a, 0x84ae95de, 0x00000001, 0x000002f8, 0x00000003,
316 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
317 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000030f, 0x505f5653, 0x5449534f, 0x004e4f49,
318 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
319 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054, 0x52444853, 0x0000025c, 0x00000040,
320 0x00000097, 0x04000059, 0x00208e46, 0x00000000, 0x00000003, 0x0300005a, 0x00106000, 0x00000000,
321 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x04002064, 0x00101032, 0x00000000, 0x00000001,
322 0x03000065, 0x001020f2, 0x00000000, 0x02000068, 0x00000002, 0x08000031, 0x00100012, 0x00000000,
323 0x0010100a, 0x00000000, 0x0020800a, 0x00000000, 0x00000000, 0x08000031, 0x00100022, 0x00000000,
324 0x0020802a, 0x00000000, 0x00000000, 0x0010100a, 0x00000000, 0x0700003c, 0x00100012, 0x00000000,
325 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x09000000, 0x00100062, 0x00000000, 0x00101106,
326 0x00000000, 0x80208106, 0x00000041, 0x00000000, 0x00000000, 0x0a000000, 0x00100032, 0x00000001,
327 0x80208046, 0x00000041, 0x00000000, 0x00000000, 0x00208ae6, 0x00000000, 0x00000000, 0x0700000e,
328 0x00100062, 0x00000000, 0x00100656, 0x00000000, 0x00100106, 0x00000001, 0x0a000000, 0x00100032,
329 0x00000001, 0x80208046, 0x00000041, 0x00000000, 0x00000001, 0x00208ae6, 0x00000000, 0x00000001,
330 0x0a000032, 0x00100062, 0x00000000, 0x00100656, 0x00000000, 0x00100106, 0x00000001, 0x00208106,
331 0x00000000, 0x00000001, 0x09000045, 0x001000f2, 0x00000001, 0x00100596, 0x00000000, 0x00107e46,
332 0x00000000, 0x00106000, 0x00000000, 0x0304001f, 0x0010000a, 0x00000000, 0x06000036, 0x001020f2,
333 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e, 0x01000015, 0x08000031, 0x00100012,
334 0x00000000, 0x0010101a, 0x00000000, 0x0020801a, 0x00000000, 0x00000000, 0x08000031, 0x00100022,
335 0x00000000, 0x0020803a, 0x00000000, 0x00000000, 0x0010101a, 0x00000000, 0x0700003c, 0x00100012,
336 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a, 0x00000000,
337 0x06000036, 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e, 0x01000015,
338 0x05000036, 0x001020f2, 0x00000000, 0x00100e46, 0x00000001, 0x0100003e,
340 D3D11_SUBRESOURCE_DATA resource_data
;
341 D3D11_TEXTURE2D_DESC texture_desc
;
342 D3D11_SAMPLER_DESC sampler_desc
;
343 D3D11_BUFFER_DESC buffer_desc
;
346 if (engine
->video_frame
.d3d11
.source
)
349 /* Default vertex buffer, updated on first transfer call. */
350 buffer_desc
.ByteWidth
= sizeof(engine
->video_frame
.d3d11
.quad
);
351 buffer_desc
.Usage
= D3D11_USAGE_DEFAULT
;
352 buffer_desc
.BindFlags
= D3D11_BIND_VERTEX_BUFFER
;
353 buffer_desc
.CPUAccessFlags
= 0;
354 buffer_desc
.MiscFlags
= 0;
355 buffer_desc
.StructureByteStride
= 0;
357 resource_data
.pSysMem
= engine
->video_frame
.d3d11
.quad
;
358 resource_data
.SysMemPitch
= 0;
359 resource_data
.SysMemSlicePitch
= 0;
361 if (FAILED(hr
= ID3D11Device_CreateBuffer(device
, &buffer_desc
, &resource_data
, &engine
->video_frame
.d3d11
.vb
)))
363 WARN("Failed to create a vertex buffer, hr %#lx.\n", hr
);
367 buffer_desc
.ByteWidth
= sizeof(engine
->video_frame
.d3d11
.cb
);
368 buffer_desc
.BindFlags
= D3D11_BIND_CONSTANT_BUFFER
;
370 if (FAILED(hr
= ID3D11Device_CreateBuffer(device
, &buffer_desc
, NULL
, &engine
->video_frame
.d3d11
.ps_cb
)))
372 WARN("Failed to create a buffer, hr %#lx.\n", hr
);
376 /* Source texture. */
377 texture_desc
.Width
= engine
->video_frame
.size
.cx
;
378 texture_desc
.Height
= engine
->video_frame
.size
.cy
;
379 texture_desc
.MipLevels
= 1;
380 texture_desc
.ArraySize
= 1;
381 texture_desc
.Format
= engine
->video_frame
.output_format
;
382 texture_desc
.SampleDesc
.Count
= 1;
383 texture_desc
.SampleDesc
.Quality
= 0;
384 texture_desc
.Usage
= D3D11_USAGE_DEFAULT
;
385 texture_desc
.BindFlags
= D3D11_BIND_SHADER_RESOURCE
;
386 texture_desc
.CPUAccessFlags
= 0;
387 texture_desc
.MiscFlags
= 0;
389 if (FAILED(hr
= ID3D11Device_CreateTexture2D(device
, &texture_desc
, NULL
, &engine
->video_frame
.d3d11
.source
)))
391 WARN("Failed to create source texture, hr %#lx.\n", hr
);
395 if (FAILED(hr
= ID3D11Device_CreateShaderResourceView(device
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.source
,
396 NULL
, &engine
->video_frame
.d3d11
.srv
)))
398 WARN("Failed to create SRV, hr %#lx.\n", hr
);
403 memset(&sampler_desc
, 0, sizeof(sampler_desc
));
404 sampler_desc
.Filter
= D3D11_FILTER_MIN_MAG_MIP_POINT
;
405 sampler_desc
.AddressU
= D3D11_TEXTURE_ADDRESS_CLAMP
;
406 sampler_desc
.AddressV
= D3D11_TEXTURE_ADDRESS_CLAMP
;
407 sampler_desc
.AddressW
= D3D11_TEXTURE_ADDRESS_CLAMP
;
409 if (FAILED(hr
= ID3D11Device_CreateSamplerState(device
, &sampler_desc
, &engine
->video_frame
.d3d11
.sampler
)))
411 WARN("Failed to create a sampler state, hr %#lx.\n", hr
);
416 if (FAILED(hr
= ID3D11Device_CreateInputLayout(device
, layout_desc
, ARRAY_SIZE(layout_desc
), vs_code
, sizeof(vs_code
),
417 &engine
->video_frame
.d3d11
.input_layout
)))
419 WARN("Failed to create input layout, hr %#lx.\n", hr
);
424 if (FAILED(hr
= ID3D11Device_CreateVertexShader(device
, vs_code
, sizeof(vs_code
), NULL
, &engine
->video_frame
.d3d11
.vs
)))
426 WARN("Failed to create the vertex shader, hr %#lx.\n", hr
);
430 if (FAILED(hr
= ID3D11Device_CreatePixelShader(device
, ps_code
, sizeof(ps_code
), NULL
, &engine
->video_frame
.d3d11
.ps
)))
432 WARN("Failed to create the pixel shader, hr %#lx.\n", hr
);
449 IMFMediaTimeRange IMFMediaTimeRange_iface
;
452 struct range
*ranges
;
457 static struct time_range
*impl_from_IMFMediaTimeRange(IMFMediaTimeRange
*iface
)
459 return CONTAINING_RECORD(iface
, struct time_range
, IMFMediaTimeRange_iface
);
464 IMFMediaError IMFMediaError_iface
;
467 HRESULT extended_code
;
470 static struct media_error
*impl_from_IMFMediaError(IMFMediaError
*iface
)
472 return CONTAINING_RECORD(iface
, struct media_error
, IMFMediaError_iface
);
475 static HRESULT WINAPI
media_error_QueryInterface(IMFMediaError
*iface
, REFIID riid
, void **obj
)
477 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
479 if (IsEqualIID(riid
, &IID_IMFMediaError
) ||
480 IsEqualIID(riid
, &IID_IUnknown
))
483 IMFMediaError_AddRef(iface
);
487 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
489 return E_NOINTERFACE
;
492 static ULONG WINAPI
media_error_AddRef(IMFMediaError
*iface
)
494 struct media_error
*me
= impl_from_IMFMediaError(iface
);
495 ULONG refcount
= InterlockedIncrement(&me
->refcount
);
497 TRACE("%p, refcount %lu.\n", iface
, refcount
);
502 static ULONG WINAPI
media_error_Release(IMFMediaError
*iface
)
504 struct media_error
*me
= impl_from_IMFMediaError(iface
);
505 ULONG refcount
= InterlockedDecrement(&me
->refcount
);
507 TRACE("%p, refcount %lu.\n", iface
, refcount
);
515 static USHORT WINAPI
media_error_GetErrorCode(IMFMediaError
*iface
)
517 struct media_error
*me
= impl_from_IMFMediaError(iface
);
518 TRACE("%p.\n", iface
);
522 static HRESULT WINAPI
media_error_GetExtendedErrorCode(IMFMediaError
*iface
)
524 struct media_error
*me
= impl_from_IMFMediaError(iface
);
525 TRACE("%p.\n", iface
);
526 return me
->extended_code
;
529 static HRESULT WINAPI
media_error_SetErrorCode(IMFMediaError
*iface
, MF_MEDIA_ENGINE_ERR code
)
531 struct media_error
*me
= impl_from_IMFMediaError(iface
);
533 TRACE("%p, %u.\n", iface
, code
);
535 if ((unsigned int)code
> MF_MEDIA_ENGINE_ERR_ENCRYPTED
)
543 static HRESULT WINAPI
media_error_SetExtendedErrorCode(IMFMediaError
*iface
, HRESULT code
)
545 struct media_error
*me
= impl_from_IMFMediaError(iface
);
547 TRACE("%p, %#lx.\n", iface
, code
);
549 me
->extended_code
= code
;
554 static const IMFMediaErrorVtbl media_error_vtbl
=
556 media_error_QueryInterface
,
559 media_error_GetErrorCode
,
560 media_error_GetExtendedErrorCode
,
561 media_error_SetErrorCode
,
562 media_error_SetExtendedErrorCode
,
565 static HRESULT
create_media_error(IMFMediaError
**ret
)
567 struct media_error
*object
;
571 if (!(object
= calloc(1, sizeof(*object
))))
572 return E_OUTOFMEMORY
;
574 object
->IMFMediaError_iface
.lpVtbl
= &media_error_vtbl
;
575 object
->refcount
= 1;
577 *ret
= &object
->IMFMediaError_iface
;
582 static HRESULT WINAPI
time_range_QueryInterface(IMFMediaTimeRange
*iface
, REFIID riid
, void **obj
)
584 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
586 if (IsEqualIID(riid
, &IID_IMFMediaTimeRange
) ||
587 IsEqualIID(riid
, &IID_IUnknown
))
590 IMFMediaTimeRange_AddRef(iface
);
594 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
596 return E_NOINTERFACE
;
599 static ULONG WINAPI
time_range_AddRef(IMFMediaTimeRange
*iface
)
601 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
602 ULONG refcount
= InterlockedIncrement(&range
->refcount
);
604 TRACE("%p, refcount %lu.\n", iface
, refcount
);
609 static ULONG WINAPI
time_range_Release(IMFMediaTimeRange
*iface
)
611 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
612 ULONG refcount
= InterlockedDecrement(&range
->refcount
);
614 TRACE("%p, refcount %lu.\n", iface
, refcount
);
625 static DWORD WINAPI
time_range_GetLength(IMFMediaTimeRange
*iface
)
627 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
629 TRACE("%p.\n", iface
);
634 static HRESULT WINAPI
time_range_GetStart(IMFMediaTimeRange
*iface
, DWORD idx
, double *start
)
636 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
638 TRACE("%p, %lu, %p.\n", iface
, idx
, start
);
640 if (idx
>= range
->count
)
643 *start
= range
->ranges
[idx
].start
;
648 static HRESULT WINAPI
time_range_GetEnd(IMFMediaTimeRange
*iface
, DWORD idx
, double *end
)
650 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
652 TRACE("%p, %lu, %p.\n", iface
, idx
, end
);
654 if (idx
>= range
->count
)
657 *end
= range
->ranges
[idx
].end
;
662 static BOOL WINAPI
time_range_ContainsTime(IMFMediaTimeRange
*iface
, double time
)
664 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
667 TRACE("%p, %.8e.\n", iface
, time
);
669 for (i
= 0; i
< range
->count
; ++i
)
671 if (time
>= range
->ranges
[i
].start
&& time
<= range
->ranges
[i
].end
)
678 static HRESULT WINAPI
time_range_AddRange(IMFMediaTimeRange
*iface
, double start
, double end
)
680 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
684 TRACE("%p, %.8e, %.8e.\n", iface
, start
, end
);
686 for (i
= 0; i
< range
->count
; ++i
)
688 c
= &range
->ranges
[i
];
690 /* New range is fully contained within existing one. */
691 if (c
->start
<= start
&& c
->end
>= end
)
694 /* New range fully contains existing one. */
695 if (c
->start
>= start
&& c
->end
<= end
)
702 /* Merge if ranges intersect. */
703 if ((start
>= c
->start
&& start
<= c
->end
) ||
704 (end
>= c
->start
&& end
<= c
->end
))
706 c
->start
= min(c
->start
, start
);
707 c
->end
= max(c
->end
, end
);
712 if (!mf_array_reserve((void **)&range
->ranges
, &range
->capacity
, range
->count
+ 1, sizeof(*range
->ranges
)))
713 return E_OUTOFMEMORY
;
715 range
->ranges
[range
->count
].start
= start
;
716 range
->ranges
[range
->count
].end
= end
;
722 static HRESULT WINAPI
time_range_Clear(IMFMediaTimeRange
*iface
)
724 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
726 TRACE("%p.\n", iface
);
733 static const IMFMediaTimeRangeVtbl time_range_vtbl
=
735 time_range_QueryInterface
,
738 time_range_GetLength
,
741 time_range_ContainsTime
,
746 static HRESULT
create_time_range(IMFMediaTimeRange
**range
)
748 struct time_range
*object
;
750 object
= calloc(1, sizeof(*object
));
752 return E_OUTOFMEMORY
;
754 object
->IMFMediaTimeRange_iface
.lpVtbl
= &time_range_vtbl
;
755 object
->refcount
= 1;
757 *range
= &object
->IMFMediaTimeRange_iface
;
762 static void media_engine_set_flag(struct media_engine
*engine
, unsigned int mask
, BOOL value
)
765 engine
->flags
|= mask
;
767 engine
->flags
&= ~mask
;
770 static inline struct media_engine
*impl_from_IMFMediaEngineEx(IMFMediaEngineEx
*iface
)
772 return CONTAINING_RECORD(iface
, struct media_engine
, IMFMediaEngineEx_iface
);
775 static inline struct media_engine
*impl_from_IMFGetService(IMFGetService
*iface
)
777 return CONTAINING_RECORD(iface
, struct media_engine
, IMFGetService_iface
);
780 static struct media_engine
*impl_from_session_events_IMFAsyncCallback(IMFAsyncCallback
*iface
)
782 return CONTAINING_RECORD(iface
, struct media_engine
, session_events
);
785 static struct media_engine
*impl_from_load_handler_IMFAsyncCallback(IMFAsyncCallback
*iface
)
787 return CONTAINING_RECORD(iface
, struct media_engine
, load_handler
);
790 static struct media_engine
*impl_from_IMFSampleGrabberSinkCallback(IMFSampleGrabberSinkCallback
*iface
)
792 return CONTAINING_RECORD(iface
, struct media_engine
, grabber_callback
);
795 static unsigned int get_gcd(unsigned int a
, unsigned int b
)
809 static void media_engine_get_frame_size(struct media_engine
*engine
, IMFTopology
*topology
)
811 IMFMediaTypeHandler
*handler
;
812 IMFMediaType
*media_type
;
813 IMFStreamDescriptor
*sd
;
814 IMFTopologyNode
*node
;
819 engine
->video_frame
.size
.cx
= 0;
820 engine
->video_frame
.size
.cy
= 0;
821 engine
->video_frame
.ratio
.cx
= 1;
822 engine
->video_frame
.ratio
.cy
= 1;
824 if (FAILED(IMFTopology_GetNodeByID(topology
, engine
->video_frame
.node_id
, &node
)))
827 hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_STREAM_DESCRIPTOR
,
828 &IID_IMFStreamDescriptor
, (void **)&sd
);
829 IMFTopologyNode_Release(node
);
833 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
834 IMFStreamDescriptor_Release(sd
);
838 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, &media_type
);
839 IMFMediaTypeHandler_Release(handler
);
842 WARN("Failed to get current media type %#lx.\n", hr
);
846 IMFMediaType_GetUINT64(media_type
, &MF_MT_FRAME_SIZE
, &size
);
848 engine
->video_frame
.size
.cx
= size
>> 32;
849 engine
->video_frame
.size
.cy
= size
;
851 if ((gcd
= get_gcd(engine
->video_frame
.size
.cx
, engine
->video_frame
.size
.cy
)))
853 engine
->video_frame
.ratio
.cx
= engine
->video_frame
.size
.cx
/ gcd
;
854 engine
->video_frame
.ratio
.cy
= engine
->video_frame
.size
.cy
/ gcd
;
857 IMFMediaType_Release(media_type
);
860 static void media_engine_apply_volume(const struct media_engine
*engine
)
862 IMFSimpleAudioVolume
*sa_volume
;
865 if (!engine
->session
)
868 if (FAILED(MFGetService((IUnknown
*)engine
->session
, &MR_POLICY_VOLUME_SERVICE
, &IID_IMFSimpleAudioVolume
, (void **)&sa_volume
)))
871 if (FAILED(hr
= IMFSimpleAudioVolume_SetMasterVolume(sa_volume
, engine
->volume
)))
872 WARN("Failed to set master volume, hr %#lx.\n", hr
);
874 IMFSimpleAudioVolume_Release(sa_volume
);
877 static HRESULT WINAPI
media_engine_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
879 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
880 IsEqualIID(riid
, &IID_IUnknown
))
883 IMFAsyncCallback_AddRef(iface
);
887 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
889 return E_NOINTERFACE
;
892 static ULONG WINAPI
media_engine_session_events_AddRef(IMFAsyncCallback
*iface
)
894 struct media_engine
*engine
= impl_from_session_events_IMFAsyncCallback(iface
);
895 return IMFMediaEngineEx_AddRef(&engine
->IMFMediaEngineEx_iface
);
898 static ULONG WINAPI
media_engine_session_events_Release(IMFAsyncCallback
*iface
)
900 struct media_engine
*engine
= impl_from_session_events_IMFAsyncCallback(iface
);
901 return IMFMediaEngineEx_Release(&engine
->IMFMediaEngineEx_iface
);
904 static HRESULT WINAPI
media_engine_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
909 static HRESULT WINAPI
media_engine_session_events_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
911 struct media_engine
*engine
= impl_from_session_events_IMFAsyncCallback(iface
);
912 IMFMediaEvent
*event
= NULL
;
913 MediaEventType event_type
;
916 if (FAILED(hr
= IMFMediaSession_EndGetEvent(engine
->session
, result
, &event
)))
918 WARN("Failed to get session event, hr %#lx.\n", hr
);
922 if (FAILED(hr
= IMFMediaEvent_GetType(event
, &event_type
)))
924 WARN("Failed to get event type, hr %#lx.\n", hr
);
930 case MEBufferingStarted
:
931 case MEBufferingStopped
:
933 IMFMediaEngineNotify_EventNotify(engine
->callback
, event_type
== MEBufferingStarted
?
934 MF_MEDIA_ENGINE_EVENT_BUFFERINGSTARTED
: MF_MEDIA_ENGINE_EVENT_BUFFERINGENDED
, 0, 0);
936 case MESessionTopologyStatus
:
938 UINT32 topo_status
= 0;
939 IMFTopology
*topology
;
942 IMFMediaEvent_GetUINT32(event
, &MF_EVENT_TOPOLOGY_STATUS
, &topo_status
);
943 if (topo_status
!= MF_TOPOSTATUS_READY
)
947 if (FAILED(IMFMediaEvent_GetValue(event
, &value
)))
950 if (value
.vt
!= VT_UNKNOWN
)
952 PropVariantClear(&value
);
956 topology
= (IMFTopology
*)value
.punkVal
;
958 EnterCriticalSection(&engine
->cs
);
960 media_engine_apply_volume(engine
);
962 engine
->ready_state
= MF_MEDIA_ENGINE_READY_HAVE_METADATA
;
964 media_engine_get_frame_size(engine
, topology
);
966 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE
, 0, 0);
967 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA
, 0, 0);
969 engine
->ready_state
= MF_MEDIA_ENGINE_READY_HAVE_ENOUGH_DATA
;
971 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_LOADEDDATA
, 0, 0);
972 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_CANPLAY
, 0, 0);
974 LeaveCriticalSection(&engine
->cs
);
976 PropVariantClear(&value
);
980 case MESessionStarted
:
982 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PLAYING
, 0, 0);
986 EnterCriticalSection(&engine
->cs
);
987 media_engine_set_flag(engine
, FLAGS_ENGINE_FIRST_FRAME
, FALSE
);
988 media_engine_set_flag(engine
, FLAGS_ENGINE_IS_ENDED
, TRUE
);
989 engine
->video_frame
.pts
= MINLONGLONG
;
990 LeaveCriticalSection(&engine
->cs
);
992 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_ENDED
, 0, 0);
999 IMFMediaEvent_Release(event
);
1001 if (FAILED(hr
= IMFMediaSession_BeginGetEvent(engine
->session
, iface
, NULL
)))
1002 WARN("Failed to subscribe to session events, hr %#lx.\n", hr
);
1007 static const IMFAsyncCallbackVtbl media_engine_session_events_vtbl
=
1009 media_engine_callback_QueryInterface
,
1010 media_engine_session_events_AddRef
,
1011 media_engine_session_events_Release
,
1012 media_engine_callback_GetParameters
,
1013 media_engine_session_events_Invoke
,
1016 static ULONG WINAPI
media_engine_load_handler_AddRef(IMFAsyncCallback
*iface
)
1018 struct media_engine
*engine
= impl_from_load_handler_IMFAsyncCallback(iface
);
1019 return IMFMediaEngineEx_AddRef(&engine
->IMFMediaEngineEx_iface
);
1022 static ULONG WINAPI
media_engine_load_handler_Release(IMFAsyncCallback
*iface
)
1024 struct media_engine
*engine
= impl_from_load_handler_IMFAsyncCallback(iface
);
1025 return IMFMediaEngineEx_Release(&engine
->IMFMediaEngineEx_iface
);
1028 static HRESULT
media_engine_create_source_node(IMFMediaSource
*source
, IMFPresentationDescriptor
*pd
, IMFStreamDescriptor
*sd
,
1029 IMFTopologyNode
**node
)
1033 if (FAILED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE
, node
)))
1036 IMFTopologyNode_SetUnknown(*node
, &MF_TOPONODE_SOURCE
, (IUnknown
*)source
);
1037 IMFTopologyNode_SetUnknown(*node
, &MF_TOPONODE_PRESENTATION_DESCRIPTOR
, (IUnknown
*)pd
);
1038 IMFTopologyNode_SetUnknown(*node
, &MF_TOPONODE_STREAM_DESCRIPTOR
, (IUnknown
*)sd
);
1043 static HRESULT
media_engine_create_effects(struct effect
*effects
, size_t count
,
1044 IMFTopologyNode
*src
, IMFTopologyNode
*sink
, IMFTopology
*topology
)
1046 IMFTopologyNode
*last
= src
;
1050 IMFTopologyNode_AddRef(last
);
1052 for (i
= 0; i
< count
; ++i
)
1054 IMFTopologyNode
*node
= NULL
;
1056 if (FAILED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE
, &node
)))
1058 WARN("Failed to create transform node, hr %#lx.\n", hr
);
1062 IMFTopologyNode_SetObject(node
, (IUnknown
*)effects
[i
].object
);
1063 IMFTopologyNode_SetUINT32(node
, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE
, FALSE
);
1065 if (effects
[i
].optional
)
1066 IMFTopologyNode_SetUINT32(node
, &MF_TOPONODE_CONNECT_METHOD
, MF_CONNECT_AS_OPTIONAL
);
1068 IMFTopology_AddNode(topology
, node
);
1069 IMFTopologyNode_ConnectOutput(last
, 0, node
, 0);
1071 IMFTopologyNode_Release(last
);
1075 IMFTopologyNode_Release(last
);
1078 hr
= IMFTopologyNode_ConnectOutput(last
, 0, sink
, 0);
1083 static HRESULT
media_engine_create_audio_renderer(struct media_engine
*engine
, IMFTopologyNode
**node
)
1085 unsigned int category
, role
;
1086 IMFActivate
*sar_activate
;
1091 if (FAILED(hr
= MFCreateAudioRendererActivate(&sar_activate
)))
1094 /* Configuration attributes keys differ between Engine and SAR. */
1095 if (SUCCEEDED(IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_CATEGORY
, &category
)))
1096 IMFActivate_SetUINT32(sar_activate
, &MF_AUDIO_RENDERER_ATTRIBUTE_STREAM_CATEGORY
, category
);
1097 if (SUCCEEDED(IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE
, &role
)))
1098 IMFActivate_SetUINT32(sar_activate
, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE
, role
);
1100 if (SUCCEEDED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE
, node
)))
1102 IMFTopologyNode_SetObject(*node
, (IUnknown
*)sar_activate
);
1103 IMFTopologyNode_SetUINT32(*node
, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE
, FALSE
);
1106 IMFActivate_Release(sar_activate
);
1111 static HRESULT
media_engine_create_video_renderer(struct media_engine
*engine
, IMFTopologyNode
**node
)
1113 IMFMediaType
*media_type
;
1114 IMFActivate
*activate
;
1115 UINT32 output_format
;
1121 if (FAILED(IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT
, &output_format
)))
1123 WARN("Output format was not specified.\n");
1127 memcpy(&subtype
, &MFVideoFormat_Base
, sizeof(subtype
));
1128 if (!(subtype
.Data1
= MFMapDXGIFormatToDX9Format(output_format
)))
1130 WARN("Unrecognized output format %#x.\n", output_format
);
1134 if (FAILED(hr
= MFCreateMediaType(&media_type
)))
1137 IMFMediaType_SetGUID(media_type
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Video
);
1138 IMFMediaType_SetGUID(media_type
, &MF_MT_SUBTYPE
, &subtype
);
1140 hr
= MFCreateSampleGrabberSinkActivate(media_type
, &engine
->grabber_callback
, &activate
);
1141 IMFMediaType_Release(media_type
);
1145 if (SUCCEEDED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE
, node
)))
1147 IMFTopologyNode_SetObject(*node
, (IUnknown
*)activate
);
1148 IMFTopologyNode_SetUINT32(*node
, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE
, FALSE
);
1151 IMFActivate_Release(activate
);
1153 engine
->video_frame
.output_format
= output_format
;
1158 static void media_engine_clear_presentation(struct media_engine
*engine
)
1160 if (engine
->presentation
.source
)
1162 IMFMediaSource_Shutdown(engine
->presentation
.source
);
1163 IMFMediaSource_Release(engine
->presentation
.source
);
1165 if (engine
->presentation
.pd
)
1166 IMFPresentationDescriptor_Release(engine
->presentation
.pd
);
1167 memset(&engine
->presentation
, 0, sizeof(engine
->presentation
));
1170 static void media_engine_clear_effects(struct effects
*effects
)
1174 for (i
= 0; i
< effects
->count
; ++i
)
1176 if (effects
->effects
[i
].object
)
1177 IUnknown_Release(effects
->effects
[i
].object
);
1180 free(effects
->effects
);
1181 memset(effects
, 0, sizeof(*effects
));
1184 static HRESULT
media_engine_create_topology(struct media_engine
*engine
, IMFMediaSource
*source
)
1186 IMFStreamDescriptor
*sd_audio
= NULL
, *sd_video
= NULL
;
1187 IMFPresentationDescriptor
*pd
;
1188 DWORD stream_count
= 0, i
;
1189 IMFTopology
*topology
;
1193 media_engine_release_video_frame_resources(engine
);
1194 media_engine_clear_presentation(engine
);
1196 if (FAILED(hr
= IMFMediaSource_CreatePresentationDescriptor(source
, &pd
)))
1199 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(pd
, &stream_count
)))
1200 WARN("Failed to get stream count, hr %#lx.\n", hr
);
1202 /* Enable first video stream and first audio stream. */
1204 for (i
= 0; i
< stream_count
; ++i
)
1206 IMFMediaTypeHandler
*type_handler
;
1207 IMFStreamDescriptor
*sd
;
1210 IMFPresentationDescriptor_DeselectStream(pd
, i
);
1212 if (sd_audio
&& sd_video
)
1215 IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd
, i
, &selected
, &sd
);
1217 if (SUCCEEDED(IMFStreamDescriptor_GetMediaTypeHandler(sd
, &type_handler
)))
1221 IMFMediaTypeHandler_GetMajorType(type_handler
, &major
);
1223 if (IsEqualGUID(&major
, &MFMediaType_Audio
) && !sd_audio
)
1226 IMFStreamDescriptor_AddRef(sd_audio
);
1227 IMFPresentationDescriptor_SelectStream(pd
, i
);
1229 else if (IsEqualGUID(&major
, &MFMediaType_Video
) && !sd_video
&& !(engine
->flags
& MF_MEDIA_ENGINE_AUDIOONLY
))
1232 IMFStreamDescriptor_AddRef(sd_video
);
1233 IMFPresentationDescriptor_SelectStream(pd
, i
);
1236 IMFMediaTypeHandler_Release(type_handler
);
1239 IMFStreamDescriptor_Release(sd
);
1242 if (!sd_video
&& !sd_audio
)
1244 IMFPresentationDescriptor_Release(pd
);
1245 return E_UNEXPECTED
;
1248 engine
->presentation
.source
= source
;
1249 IMFMediaSource_AddRef(engine
->presentation
.source
);
1250 engine
->presentation
.pd
= pd
;
1251 IMFPresentationDescriptor_AddRef(engine
->presentation
.pd
);
1253 media_engine_set_flag(engine
, FLAGS_ENGINE_HAS_VIDEO
, !!sd_video
);
1254 media_engine_set_flag(engine
, FLAGS_ENGINE_HAS_AUDIO
, !!sd_audio
);
1256 /* Assume live source if duration was not provided. */
1257 if (SUCCEEDED(IMFPresentationDescriptor_GetUINT64(pd
, &MF_PD_DURATION
, &duration
)))
1258 engine
->duration
= mftime_to_seconds(duration
);
1260 engine
->duration
= INFINITY
;
1262 if (SUCCEEDED(hr
= MFCreateTopology(&topology
)))
1264 IMFTopologyNode
*sar_node
= NULL
, *audio_src
= NULL
;
1265 IMFTopologyNode
*grabber_node
= NULL
, *video_src
= NULL
;
1267 if (engine
->flags
& MF_MEDIA_ENGINE_REAL_TIME_MODE
)
1268 IMFTopology_SetUINT32(topology
, &MF_LOW_LATENCY
, TRUE
);
1272 if (FAILED(hr
= media_engine_create_source_node(source
, pd
, sd_audio
, &audio_src
)))
1273 WARN("Failed to create audio source node, hr %#lx.\n", hr
);
1275 if (FAILED(hr
= media_engine_create_audio_renderer(engine
, &sar_node
)))
1276 WARN("Failed to create audio renderer node, hr %#lx.\n", hr
);
1278 if (sar_node
&& audio_src
)
1280 IMFTopology_AddNode(topology
, audio_src
);
1281 IMFTopology_AddNode(topology
, sar_node
);
1283 if (FAILED(hr
= media_engine_create_effects(engine
->audio_effects
.effects
, engine
->audio_effects
.count
,
1284 audio_src
, sar_node
, topology
)))
1285 WARN("Failed to create audio effect nodes, hr %#lx.\n", hr
);
1289 IMFTopologyNode_Release(sar_node
);
1291 IMFTopologyNode_Release(audio_src
);
1294 if (SUCCEEDED(hr
) && sd_video
)
1296 if (FAILED(hr
= media_engine_create_source_node(source
, pd
, sd_video
, &video_src
)))
1297 WARN("Failed to create video source node, hr %#lx.\n", hr
);
1299 if (FAILED(hr
= media_engine_create_video_renderer(engine
, &grabber_node
)))
1300 WARN("Failed to create video grabber node, hr %#lx.\n", hr
);
1302 if (grabber_node
&& video_src
)
1304 IMFTopology_AddNode(topology
, video_src
);
1305 IMFTopology_AddNode(topology
, grabber_node
);
1307 if (FAILED(hr
= media_engine_create_effects(engine
->video_effects
.effects
, engine
->video_effects
.count
,
1308 video_src
, grabber_node
, topology
)))
1309 WARN("Failed to create video effect nodes, hr %#lx.\n", hr
);
1313 IMFTopologyNode_GetTopoNodeID(video_src
, &engine
->video_frame
.node_id
);
1316 IMFTopologyNode_Release(grabber_node
);
1318 IMFTopologyNode_Release(video_src
);
1321 IMFTopology_SetUINT32(topology
, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES
, TRUE
);
1324 hr
= IMFMediaSession_SetTopology(engine
->session
, MFSESSION_SETTOPOLOGY_IMMEDIATE
, topology
);
1328 IMFTopology_Release(topology
);
1331 IMFStreamDescriptor_Release(sd_video
);
1333 IMFStreamDescriptor_Release(sd_audio
);
1335 IMFPresentationDescriptor_Release(pd
);
1340 static void media_engine_start_playback(struct media_engine
*engine
)
1345 IMFMediaSession_Start(engine
->session
, &GUID_NULL
, &var
);
1348 static HRESULT WINAPI
media_engine_load_handler_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1350 struct media_engine
*engine
= impl_from_load_handler_IMFAsyncCallback(iface
);
1351 IUnknown
*object
= NULL
, *state
;
1352 unsigned int start_playback
;
1353 MF_OBJECT_TYPE obj_type
;
1354 IMFMediaSource
*source
;
1357 EnterCriticalSection(&engine
->cs
);
1359 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1361 LeaveCriticalSection(&engine
->cs
);
1365 engine
->network_state
= MF_MEDIA_ENGINE_NETWORK_LOADING
;
1366 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_LOADSTART
, 0, 0);
1368 start_playback
= engine
->flags
& FLAGS_ENGINE_PLAY_PENDING
;
1369 media_engine_set_flag(engine
, FLAGS_ENGINE_SOURCE_PENDING
| FLAGS_ENGINE_PLAY_PENDING
, FALSE
);
1371 if (SUCCEEDED(IMFAsyncResult_GetState(result
, &state
)))
1373 hr
= IMFSourceResolver_EndCreateObjectFromByteStream(engine
->resolver
, result
, &obj_type
, &object
);
1374 IUnknown_Release(state
);
1377 hr
= IMFSourceResolver_EndCreateObjectFromURL(engine
->resolver
, result
, &obj_type
, &object
);
1380 WARN("Failed to create source object, hr %#lx.\n", hr
);
1384 if (SUCCEEDED(hr
= IUnknown_QueryInterface(object
, &IID_IMFMediaSource
, (void **)&source
)))
1386 hr
= media_engine_create_topology(engine
, source
);
1387 IMFMediaSource_Release(source
);
1389 IUnknown_Release(object
);
1394 engine
->network_state
= MF_MEDIA_ENGINE_NETWORK_IDLE
;
1396 media_engine_start_playback(engine
);
1400 engine
->network_state
= MF_MEDIA_ENGINE_NETWORK_NO_SOURCE
;
1401 engine
->error_code
= MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED
;
1402 engine
->extended_code
= hr
;
1403 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_ERROR
, engine
->error_code
,
1404 engine
->extended_code
);
1407 LeaveCriticalSection(&engine
->cs
);
1412 static const IMFAsyncCallbackVtbl media_engine_load_handler_vtbl
=
1414 media_engine_callback_QueryInterface
,
1415 media_engine_load_handler_AddRef
,
1416 media_engine_load_handler_Release
,
1417 media_engine_callback_GetParameters
,
1418 media_engine_load_handler_Invoke
,
1421 static HRESULT WINAPI
media_engine_QueryInterface(IMFMediaEngineEx
*iface
, REFIID riid
, void **obj
)
1423 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1425 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1427 if (IsEqualIID(riid
, &IID_IMFMediaEngineEx
) ||
1428 IsEqualIID(riid
, &IID_IMFMediaEngine
) ||
1429 IsEqualIID(riid
, &IID_IUnknown
))
1433 else if (IsEqualIID(riid
, &IID_IMFGetService
))
1435 *obj
= &engine
->IMFGetService_iface
;
1439 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
1441 return E_NOINTERFACE
;
1444 IUnknown_AddRef((IUnknown
*)*obj
);
1448 static ULONG WINAPI
media_engine_AddRef(IMFMediaEngineEx
*iface
)
1450 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1451 ULONG refcount
= InterlockedIncrement(&engine
->refcount
);
1453 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1458 static void free_media_engine(struct media_engine
*engine
)
1460 if (engine
->callback
)
1461 IMFMediaEngineNotify_Release(engine
->callback
);
1463 IMFPresentationClock_Release(engine
->clock
);
1464 if (engine
->session
)
1465 IMFMediaSession_Release(engine
->session
);
1466 if (engine
->attributes
)
1467 IMFAttributes_Release(engine
->attributes
);
1468 if (engine
->resolver
)
1469 IMFSourceResolver_Release(engine
->resolver
);
1470 if (engine
->extension
)
1471 IMFMediaEngineExtension_Release(engine
->extension
);
1472 media_engine_clear_effects(&engine
->audio_effects
);
1473 media_engine_clear_effects(&engine
->video_effects
);
1474 media_engine_release_video_frame_resources(engine
);
1475 media_engine_clear_presentation(engine
);
1476 if (engine
->device_manager
)
1478 IMFDXGIDeviceManager_CloseDeviceHandle(engine
->device_manager
, engine
->device_handle
);
1479 IMFDXGIDeviceManager_Release(engine
->device_manager
);
1481 SysFreeString(engine
->current_source
);
1482 DeleteCriticalSection(&engine
->cs
);
1483 free(engine
->video_frame
.buffer
);
1487 static ULONG WINAPI
media_engine_Release(IMFMediaEngineEx
*iface
)
1489 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1490 ULONG refcount
= InterlockedDecrement(&engine
->refcount
);
1492 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1495 free_media_engine(engine
);
1500 static HRESULT WINAPI
media_engine_GetError(IMFMediaEngineEx
*iface
, IMFMediaError
**error
)
1502 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1505 TRACE("%p, %p.\n", iface
, error
);
1509 EnterCriticalSection(&engine
->cs
);
1510 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1512 else if (engine
->error_code
)
1514 if (SUCCEEDED(hr
= create_media_error(error
)))
1516 IMFMediaError_SetErrorCode(*error
, engine
->error_code
);
1517 IMFMediaError_SetExtendedErrorCode(*error
, engine
->extended_code
);
1520 LeaveCriticalSection(&engine
->cs
);
1525 static HRESULT WINAPI
media_engine_SetErrorCode(IMFMediaEngineEx
*iface
, MF_MEDIA_ENGINE_ERR code
)
1527 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1530 TRACE("%p, %u.\n", iface
, code
);
1532 if ((unsigned int)code
> MF_MEDIA_ENGINE_ERR_ENCRYPTED
)
1533 return E_INVALIDARG
;
1535 EnterCriticalSection(&engine
->cs
);
1536 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1539 engine
->error_code
= code
;
1540 LeaveCriticalSection(&engine
->cs
);
1545 static HRESULT WINAPI
media_engine_SetSourceElements(IMFMediaEngineEx
*iface
, IMFMediaEngineSrcElements
*elements
)
1547 FIXME("(%p, %p): stub.\n", iface
, elements
);
1552 static HRESULT
media_engine_set_source(struct media_engine
*engine
, IMFByteStream
*bytestream
, BSTR url
)
1554 IPropertyStore
*props
= NULL
;
1558 SysFreeString(engine
->current_source
);
1559 engine
->current_source
= NULL
;
1561 engine
->current_source
= SysAllocString(url
);
1563 engine
->ready_state
= MF_MEDIA_ENGINE_READY_HAVE_NOTHING
;
1565 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS
, 0, 0);
1567 engine
->network_state
= MF_MEDIA_ENGINE_NETWORK_NO_SOURCE
;
1569 if (url
|| bytestream
)
1571 if (engine
->extension
)
1572 FIXME("Use extension to load from.\n");
1574 flags
= MF_RESOLUTION_MEDIASOURCE
| MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE
;
1575 if (engine
->flags
& MF_MEDIA_ENGINE_DISABLE_LOCAL_PLUGINS
)
1576 flags
|= MF_RESOLUTION_DISABLE_LOCAL_PLUGINS
;
1578 IMFAttributes_GetUnknown(engine
->attributes
, &MF_MEDIA_ENGINE_SOURCE_RESOLVER_CONFIG_STORE
,
1579 &IID_IPropertyStore
, (void **)&props
);
1581 hr
= IMFSourceResolver_BeginCreateObjectFromByteStream(engine
->resolver
, bytestream
, url
, flags
,
1582 props
, NULL
, &engine
->load_handler
, (IUnknown
*)bytestream
);
1584 hr
= IMFSourceResolver_BeginCreateObjectFromURL(engine
->resolver
, url
, flags
, props
, NULL
,
1585 &engine
->load_handler
, NULL
);
1587 media_engine_set_flag(engine
, FLAGS_ENGINE_SOURCE_PENDING
, TRUE
);
1590 IPropertyStore_Release(props
);
1596 static HRESULT WINAPI
media_engine_SetSource(IMFMediaEngineEx
*iface
, BSTR url
)
1598 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1601 TRACE("%p, %s.\n", iface
, debugstr_w(url
));
1603 EnterCriticalSection(&engine
->cs
);
1605 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1608 hr
= media_engine_set_source(engine
, NULL
, url
);
1610 LeaveCriticalSection(&engine
->cs
);
1615 static HRESULT WINAPI
media_engine_GetCurrentSource(IMFMediaEngineEx
*iface
, BSTR
*url
)
1617 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1620 TRACE("%p, %p.\n", iface
, url
);
1624 EnterCriticalSection(&engine
->cs
);
1626 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1628 if (engine
->current_source
)
1630 if (!(*url
= SysAllocString(engine
->current_source
)))
1634 LeaveCriticalSection(&engine
->cs
);
1639 static USHORT WINAPI
media_engine_GetNetworkState(IMFMediaEngineEx
*iface
)
1641 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1643 TRACE("%p.\n", iface
);
1645 return engine
->network_state
;
1648 static MF_MEDIA_ENGINE_PRELOAD WINAPI
media_engine_GetPreload(IMFMediaEngineEx
*iface
)
1650 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1651 MF_MEDIA_ENGINE_PRELOAD preload
;
1653 TRACE("%p.\n", iface
);
1655 EnterCriticalSection(&engine
->cs
);
1656 preload
= engine
->preload
;
1657 LeaveCriticalSection(&engine
->cs
);
1662 static HRESULT WINAPI
media_engine_SetPreload(IMFMediaEngineEx
*iface
, MF_MEDIA_ENGINE_PRELOAD preload
)
1664 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1666 TRACE("%p, %d.\n", iface
, preload
);
1668 EnterCriticalSection(&engine
->cs
);
1669 engine
->preload
= preload
;
1670 LeaveCriticalSection(&engine
->cs
);
1675 static HRESULT WINAPI
media_engine_GetBuffered(IMFMediaEngineEx
*iface
, IMFMediaTimeRange
**range
)
1677 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1680 TRACE("%p, %p.\n", iface
, range
);
1682 if (FAILED(hr
= create_time_range(range
)))
1685 EnterCriticalSection(&engine
->cs
);
1687 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1689 else if (!isnan(engine
->duration
))
1690 hr
= IMFMediaTimeRange_AddRange(*range
, 0.0, engine
->duration
);
1692 LeaveCriticalSection(&engine
->cs
);
1697 static HRESULT WINAPI
media_engine_Load(IMFMediaEngineEx
*iface
)
1699 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1700 HRESULT hr
= E_NOTIMPL
;
1702 FIXME("(%p): stub.\n", iface
);
1704 EnterCriticalSection(&engine
->cs
);
1706 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1709 LeaveCriticalSection(&engine
->cs
);
1714 static HRESULT WINAPI
media_engine_CanPlayType(IMFMediaEngineEx
*iface
, BSTR mime_type
, MF_MEDIA_ENGINE_CANPLAY
*answer
)
1716 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1717 HRESULT hr
= E_NOTIMPL
;
1719 TRACE("%p, %s, %p.\n", iface
, debugstr_w(mime_type
), answer
);
1721 EnterCriticalSection(&engine
->cs
);
1723 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1727 FIXME("Check builtin supported types.\n");
1729 if (engine
->extension
)
1730 hr
= IMFMediaEngineExtension_CanPlayType(engine
->extension
, !!(engine
->flags
& MF_MEDIA_ENGINE_AUDIOONLY
),
1734 LeaveCriticalSection(&engine
->cs
);
1739 static USHORT WINAPI
media_engine_GetReadyState(IMFMediaEngineEx
*iface
)
1741 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1742 unsigned short state
;
1744 TRACE("%p.\n", iface
);
1746 EnterCriticalSection(&engine
->cs
);
1747 state
= engine
->ready_state
;
1748 LeaveCriticalSection(&engine
->cs
);
1753 static BOOL WINAPI
media_engine_IsSeeking(IMFMediaEngineEx
*iface
)
1755 FIXME("(%p): stub.\n", iface
);
1760 static double WINAPI
media_engine_GetCurrentTime(IMFMediaEngineEx
*iface
)
1762 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1766 TRACE("%p.\n", iface
);
1768 EnterCriticalSection(&engine
->cs
);
1769 if (engine
->flags
& FLAGS_ENGINE_IS_ENDED
)
1771 ret
= engine
->duration
;
1773 else if (SUCCEEDED(IMFPresentationClock_GetTime(engine
->clock
, &clocktime
)))
1775 ret
= mftime_to_seconds(clocktime
);
1777 LeaveCriticalSection(&engine
->cs
);
1782 static HRESULT WINAPI
media_engine_SetCurrentTime(IMFMediaEngineEx
*iface
, double time
)
1784 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1785 HRESULT hr
= E_NOTIMPL
;
1787 FIXME("(%p, %f): stub.\n", iface
, time
);
1789 EnterCriticalSection(&engine
->cs
);
1791 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1794 LeaveCriticalSection(&engine
->cs
);
1799 static double WINAPI
media_engine_GetStartTime(IMFMediaEngineEx
*iface
)
1801 FIXME("(%p): stub.\n", iface
);
1806 static double WINAPI
media_engine_GetDuration(IMFMediaEngineEx
*iface
)
1808 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1811 TRACE("%p.\n", iface
);
1813 EnterCriticalSection(&engine
->cs
);
1814 value
= engine
->duration
;
1815 LeaveCriticalSection(&engine
->cs
);
1820 static BOOL WINAPI
media_engine_IsPaused(IMFMediaEngineEx
*iface
)
1822 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1825 TRACE("%p.\n", iface
);
1827 EnterCriticalSection(&engine
->cs
);
1828 value
= !!(engine
->flags
& FLAGS_ENGINE_PAUSED
);
1829 LeaveCriticalSection(&engine
->cs
);
1834 static double WINAPI
media_engine_GetDefaultPlaybackRate(IMFMediaEngineEx
*iface
)
1836 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1839 TRACE("%p.\n", iface
);
1841 EnterCriticalSection(&engine
->cs
);
1842 rate
= engine
->default_playback_rate
;
1843 LeaveCriticalSection(&engine
->cs
);
1848 static HRESULT WINAPI
media_engine_SetDefaultPlaybackRate(IMFMediaEngineEx
*iface
, double rate
)
1850 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1853 TRACE("%p, %f.\n", iface
, rate
);
1855 EnterCriticalSection(&engine
->cs
);
1856 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1858 else if (engine
->default_playback_rate
!= rate
)
1860 engine
->default_playback_rate
= rate
;
1861 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_RATECHANGE
, 0, 0);
1863 LeaveCriticalSection(&engine
->cs
);
1868 static double WINAPI
media_engine_GetPlaybackRate(IMFMediaEngineEx
*iface
)
1870 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1873 TRACE("%p.\n", iface
);
1875 EnterCriticalSection(&engine
->cs
);
1876 rate
= engine
->playback_rate
;
1877 LeaveCriticalSection(&engine
->cs
);
1882 static HRESULT WINAPI
media_engine_SetPlaybackRate(IMFMediaEngineEx
*iface
, double rate
)
1884 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1887 TRACE("%p, %f.\n", iface
, rate
);
1889 EnterCriticalSection(&engine
->cs
);
1890 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1892 else if (engine
->playback_rate
!= rate
)
1894 engine
->playback_rate
= rate
;
1895 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_RATECHANGE
, 0, 0);
1897 LeaveCriticalSection(&engine
->cs
);
1902 static HRESULT WINAPI
media_engine_GetPlayed(IMFMediaEngineEx
*iface
, IMFMediaTimeRange
**played
)
1904 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1905 HRESULT hr
= E_NOTIMPL
;
1907 FIXME("(%p, %p): stub.\n", iface
, played
);
1909 EnterCriticalSection(&engine
->cs
);
1911 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1914 LeaveCriticalSection(&engine
->cs
);
1919 static HRESULT WINAPI
media_engine_GetSeekable(IMFMediaEngineEx
*iface
, IMFMediaTimeRange
**seekable
)
1921 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1922 IMFMediaTimeRange
*time_range
= NULL
;
1926 TRACE("%p, %p.\n", iface
, seekable
);
1928 EnterCriticalSection(&engine
->cs
);
1930 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1934 hr
= create_time_range(&time_range
);
1935 if (SUCCEEDED(hr
) && !isnan(engine
->duration
) && engine
->presentation
.source
)
1937 hr
= IMFMediaSource_GetCharacteristics(engine
->presentation
.source
, &flags
);
1938 if (SUCCEEDED(hr
) && (flags
& MFBYTESTREAM_IS_SEEKABLE
))
1939 hr
= IMFMediaTimeRange_AddRange(time_range
, 0.0, engine
->duration
);
1943 LeaveCriticalSection(&engine
->cs
);
1945 if (FAILED(hr
) && time_range
)
1947 IMFMediaTimeRange_Release(time_range
);
1950 *seekable
= time_range
;
1954 static BOOL WINAPI
media_engine_IsEnded(IMFMediaEngineEx
*iface
)
1956 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1959 TRACE("%p.\n", iface
);
1961 EnterCriticalSection(&engine
->cs
);
1962 value
= !!(engine
->flags
& FLAGS_ENGINE_IS_ENDED
);
1963 LeaveCriticalSection(&engine
->cs
);
1968 static BOOL WINAPI
media_engine_GetAutoPlay(IMFMediaEngineEx
*iface
)
1970 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1973 TRACE("%p.\n", iface
);
1975 EnterCriticalSection(&engine
->cs
);
1976 value
= !!(engine
->flags
& FLAGS_ENGINE_AUTO_PLAY
);
1977 LeaveCriticalSection(&engine
->cs
);
1982 static HRESULT WINAPI
media_engine_SetAutoPlay(IMFMediaEngineEx
*iface
, BOOL autoplay
)
1984 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1986 FIXME("(%p, %d): stub.\n", iface
, autoplay
);
1988 EnterCriticalSection(&engine
->cs
);
1989 media_engine_set_flag(engine
, FLAGS_ENGINE_AUTO_PLAY
, autoplay
);
1990 LeaveCriticalSection(&engine
->cs
);
1995 static BOOL WINAPI
media_engine_GetLoop(IMFMediaEngineEx
*iface
)
1997 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2000 TRACE("%p.\n", iface
);
2002 EnterCriticalSection(&engine
->cs
);
2003 value
= !!(engine
->flags
& FLAGS_ENGINE_LOOP
);
2004 LeaveCriticalSection(&engine
->cs
);
2009 static HRESULT WINAPI
media_engine_SetLoop(IMFMediaEngineEx
*iface
, BOOL loop
)
2011 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2013 FIXME("(%p, %d): stub.\n", iface
, loop
);
2015 EnterCriticalSection(&engine
->cs
);
2016 media_engine_set_flag(engine
, FLAGS_ENGINE_LOOP
, loop
);
2017 LeaveCriticalSection(&engine
->cs
);
2022 static HRESULT WINAPI
media_engine_Play(IMFMediaEngineEx
*iface
)
2024 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2027 TRACE("%p.\n", iface
);
2029 EnterCriticalSection(&engine
->cs
);
2031 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2035 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS
, 0, 0);
2037 if (!(engine
->flags
& FLAGS_ENGINE_WAITING
))
2039 media_engine_set_flag(engine
, FLAGS_ENGINE_PAUSED
| FLAGS_ENGINE_IS_ENDED
, FALSE
);
2040 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PLAY
, 0, 0);
2042 if (!(engine
->flags
& FLAGS_ENGINE_SOURCE_PENDING
))
2043 media_engine_start_playback(engine
);
2045 media_engine_set_flag(engine
, FLAGS_ENGINE_PLAY_PENDING
, TRUE
);
2047 media_engine_set_flag(engine
, FLAGS_ENGINE_WAITING
, TRUE
);
2050 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_WAITING
, 0, 0);
2053 LeaveCriticalSection(&engine
->cs
);
2058 static HRESULT WINAPI
media_engine_Pause(IMFMediaEngineEx
*iface
)
2060 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2063 TRACE("%p.\n", iface
);
2065 EnterCriticalSection(&engine
->cs
);
2067 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2071 if (!(engine
->flags
& FLAGS_ENGINE_PAUSED
))
2073 if (SUCCEEDED(hr
= IMFMediaSession_Pause(engine
->session
)))
2075 media_engine_set_flag(engine
, FLAGS_ENGINE_WAITING
| FLAGS_ENGINE_IS_ENDED
, FALSE
);
2076 media_engine_set_flag(engine
, FLAGS_ENGINE_PAUSED
, TRUE
);
2078 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_TIMEUPDATE
, 0, 0);
2079 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PAUSE
, 0, 0);
2083 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS
, 0, 0);
2086 LeaveCriticalSection(&engine
->cs
);
2091 static BOOL WINAPI
media_engine_GetMuted(IMFMediaEngineEx
*iface
)
2093 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2096 TRACE("%p.\n", iface
);
2098 EnterCriticalSection(&engine
->cs
);
2099 ret
= !!(engine
->flags
& FLAGS_ENGINE_MUTED
);
2100 LeaveCriticalSection(&engine
->cs
);
2105 static HRESULT WINAPI
media_engine_SetMuted(IMFMediaEngineEx
*iface
, BOOL muted
)
2107 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2110 TRACE("%p, %d.\n", iface
, muted
);
2112 EnterCriticalSection(&engine
->cs
);
2113 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2115 else if (!!(engine
->flags
& FLAGS_ENGINE_MUTED
) ^ !!muted
)
2117 media_engine_set_flag(engine
, FLAGS_ENGINE_MUTED
, muted
);
2118 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE
, 0, 0);
2120 LeaveCriticalSection(&engine
->cs
);
2125 static double WINAPI
media_engine_GetVolume(IMFMediaEngineEx
*iface
)
2127 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2130 TRACE("%p.\n", iface
);
2132 EnterCriticalSection(&engine
->cs
);
2133 volume
= engine
->volume
;
2134 LeaveCriticalSection(&engine
->cs
);
2139 static HRESULT WINAPI
media_engine_SetVolume(IMFMediaEngineEx
*iface
, double volume
)
2141 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2144 TRACE("%p, %f.\n", iface
, volume
);
2146 EnterCriticalSection(&engine
->cs
);
2147 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2149 else if (volume
!= engine
->volume
)
2151 engine
->volume
= volume
;
2152 media_engine_apply_volume(engine
);
2153 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE
, 0, 0);
2155 LeaveCriticalSection(&engine
->cs
);
2160 static BOOL WINAPI
media_engine_HasVideo(IMFMediaEngineEx
*iface
)
2162 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2165 TRACE("%p.\n", iface
);
2167 EnterCriticalSection(&engine
->cs
);
2168 value
= !!(engine
->flags
& FLAGS_ENGINE_HAS_VIDEO
);
2169 LeaveCriticalSection(&engine
->cs
);
2174 static BOOL WINAPI
media_engine_HasAudio(IMFMediaEngineEx
*iface
)
2176 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2179 TRACE("%p.\n", iface
);
2181 EnterCriticalSection(&engine
->cs
);
2182 value
= !!(engine
->flags
& FLAGS_ENGINE_HAS_AUDIO
);
2183 LeaveCriticalSection(&engine
->cs
);
2188 static HRESULT WINAPI
media_engine_GetNativeVideoSize(IMFMediaEngineEx
*iface
, DWORD
*cx
, DWORD
*cy
)
2190 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2193 TRACE("%p, %p, %p.\n", iface
, cx
, cy
);
2196 return E_INVALIDARG
;
2198 EnterCriticalSection(&engine
->cs
);
2200 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2202 else if (!engine
->video_frame
.size
.cx
&& !engine
->video_frame
.size
.cy
)
2206 if (cx
) *cx
= engine
->video_frame
.size
.cx
;
2207 if (cy
) *cy
= engine
->video_frame
.size
.cy
;
2210 LeaveCriticalSection(&engine
->cs
);
2215 static HRESULT WINAPI
media_engine_GetVideoAspectRatio(IMFMediaEngineEx
*iface
, DWORD
*cx
, DWORD
*cy
)
2217 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2220 TRACE("%p, %p, %p.\n", iface
, cx
, cy
);
2223 return E_INVALIDARG
;
2225 EnterCriticalSection(&engine
->cs
);
2227 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2229 else if (!engine
->video_frame
.size
.cx
&& !engine
->video_frame
.size
.cy
)
2233 if (cx
) *cx
= engine
->video_frame
.ratio
.cx
;
2234 if (cy
) *cy
= engine
->video_frame
.ratio
.cy
;
2237 LeaveCriticalSection(&engine
->cs
);
2242 static HRESULT WINAPI
media_engine_Shutdown(IMFMediaEngineEx
*iface
)
2244 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2247 TRACE("%p.\n", iface
);
2249 EnterCriticalSection(&engine
->cs
);
2250 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2254 media_engine_set_flag(engine
, FLAGS_ENGINE_SHUT_DOWN
, TRUE
);
2255 media_engine_clear_presentation(engine
);
2256 IMFMediaSession_Shutdown(engine
->session
);
2258 LeaveCriticalSection(&engine
->cs
);
2263 static void set_rect(struct rect
*rect
, float left
, float top
, float right
, float bottom
)
2267 rect
->right
= right
;
2268 rect
->bottom
= bottom
;
2271 static void media_engine_adjust_destination_for_ratio(const struct media_engine
*engine
,
2272 struct rect
*src_n
, struct rect
*dst
)
2274 float dst_width
= dst
->right
- dst
->left
, dst_height
= dst
->bottom
- dst
->top
;
2275 D3D11_TEXTURE2D_DESC source_desc
;
2276 float src_width
, src_height
;
2279 ID3D11Texture2D_GetDesc(engine
->video_frame
.d3d11
.source
, &source_desc
);
2280 set_rect(&src
, src_n
->left
* source_desc
.Width
, src_n
->top
* source_desc
.Height
,
2281 src_n
->right
* source_desc
.Width
, src_n
->bottom
* source_desc
.Height
);
2283 src_width
= src
.right
- src
.left
;
2284 src_height
= src
.bottom
- src
.top
;
2286 if (src_width
* dst_height
> dst_width
* src_height
)
2288 /* src is "wider" than dst. */
2289 float dst_center
= (dst
->top
+ dst
->bottom
) / 2.0f
;
2290 float scaled_height
= src_height
* dst_width
/ src_width
;
2292 dst
->top
= dst_center
- scaled_height
/ 2.0f
;
2293 dst
->bottom
= dst
->top
+ scaled_height
;
2295 else if (src_width
* dst_height
< dst_width
* src_height
)
2297 /* src is "taller" than dst. */
2298 float dst_center
= (dst
->left
+ dst
->right
) / 2.0f
;
2299 float scaled_width
= src_width
* dst_height
/ src_height
;
2301 dst
->left
= dst_center
- scaled_width
/ 2.0f
;
2302 dst
->right
= dst
->left
+ scaled_width
;
2306 static void media_engine_update_d3d11_frame_surface(ID3D11DeviceContext
*context
, struct media_engine
*engine
)
2308 D3D11_TEXTURE2D_DESC surface_desc
;
2310 if (!(engine
->flags
& FLAGS_ENGINE_NEW_FRAME
))
2313 ID3D11Texture2D_GetDesc(engine
->video_frame
.d3d11
.source
, &surface_desc
);
2315 switch (surface_desc
.Format
)
2317 case DXGI_FORMAT_B8G8R8A8_UNORM
:
2318 case DXGI_FORMAT_B8G8R8X8_UNORM
:
2319 surface_desc
.Width
*= 4;
2322 FIXME("Unsupported format %#x.\n", surface_desc
.Format
);
2323 surface_desc
.Width
= 0;
2326 if (engine
->video_frame
.buffer_size
== surface_desc
.Width
* surface_desc
.Height
)
2328 ID3D11DeviceContext_UpdateSubresource(context
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.source
,
2329 0, NULL
, engine
->video_frame
.buffer
, surface_desc
.Width
, 0);
2332 media_engine_set_flag(engine
, FLAGS_ENGINE_NEW_FRAME
, FALSE
);
2335 static HRESULT
media_engine_transfer_to_d3d11_texture(struct media_engine
*engine
, ID3D11Texture2D
*texture
,
2336 const MFVideoNormalizedRect
*src_rect
, const RECT
*dst_rect
, const MFARGB
*color
)
2338 static const float black
[] = {0.0f
, 0.0f
, 0.0f
, 0.0f
};
2339 ID3D11Device
*device
, *dst_device
;
2340 ID3D11DeviceContext
*context
;
2341 ID3D11RenderTargetView
*rtv
;
2342 unsigned int stride
, offset
;
2343 D3D11_TEXTURE2D_DESC desc
;
2344 BOOL device_mismatch
;
2345 struct vec3 quad
[4];
2347 struct rect src
, dst
;
2348 struct color backcolor
;
2352 if (FAILED(hr
= media_engine_lock_d3d_device(engine
, &device
)))
2355 if (FAILED(hr
= media_engine_create_d3d11_video_frame_resources(engine
, device
)))
2357 WARN("Failed to create d3d resources, hr %#lx.\n", hr
);
2361 ID3D11Texture2D_GetDevice(texture
, &dst_device
);
2362 device_mismatch
= device
!= dst_device
;
2363 ID3D11Device_Release(dst_device
);
2365 if (device_mismatch
)
2367 WARN("Destination target from different device.\n");
2372 ID3D11Texture2D_GetDesc(texture
, &desc
);
2374 if (FAILED(hr
= ID3D11Device_CreateRenderTargetView(device
, (ID3D11Resource
*)texture
, NULL
, &rtv
)))
2376 WARN("Failed to create an rtv, hr %#lx.\n", hr
);
2380 ID3D11Device_GetImmediateContext(device
, &context
);
2382 /* Whole destination is cleared, regardless of specified rectangle. */
2383 ID3D11DeviceContext_ClearRenderTargetView(context
, rtv
, black
);
2387 rect
.left
= max(0, dst_rect
->left
);
2388 rect
.top
= max(0, dst_rect
->top
);
2389 rect
.right
= min(desc
.Width
, dst_rect
->right
);
2390 rect
.bottom
= min(desc
.Height
, dst_rect
->bottom
);
2392 quad
[0].x
= 2.0f
* rect
.left
/ desc
.Width
- 1.0f
;
2393 quad
[0].y
= -2.0f
* rect
.bottom
/ desc
.Height
+ 1.0f
;
2396 quad
[1].x
= quad
[0].x
;
2397 quad
[1].y
= -2.0f
* rect
.top
/ desc
.Height
+ 1.0f
;
2400 quad
[2].x
= 2.0f
* rect
.right
/ desc
.Width
- 1.0f
;
2401 quad
[2].y
= quad
[0].y
;
2404 quad
[3].x
= quad
[2].x
;
2405 quad
[3].y
= quad
[1].y
;
2408 set_rect(&dst
, dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
);
2412 memcpy(quad
, fullquad
, sizeof(quad
));
2413 set_rect(&dst
, 0.0f
, 0.0f
, desc
.Width
, desc
.Height
);
2417 memcpy(&src
, src_rect
, sizeof(src
));
2419 set_rect(&src
, 0.0f
, 0.0f
, 1.0f
, 1.0f
);
2421 media_engine_adjust_destination_for_ratio(engine
, &src
, &dst
);
2423 if (memcmp(quad
, engine
->video_frame
.d3d11
.quad
, sizeof(quad
)))
2425 memcpy(engine
->video_frame
.d3d11
.quad
, quad
, sizeof(quad
));
2426 ID3D11DeviceContext_UpdateSubresource(context
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.vb
, 0, NULL
, quad
, 0, 0);
2431 backcolor
.r
= color
->rgbRed
/ 255.0f
;
2432 backcolor
.g
= color
->rgbGreen
/ 255.0f
;
2433 backcolor
.b
= color
->rgbBlue
/ 255.0f
;
2434 backcolor
.a
= color
->rgbAlpha
/ 255.0f
;
2437 memcpy(&backcolor
, black
, sizeof(backcolor
));
2439 if (memcmp(&dst
, &engine
->video_frame
.d3d11
.cb
.dst
, sizeof(dst
)) ||
2440 memcmp(&src
, &engine
->video_frame
.d3d11
.cb
.src
, sizeof(src
)) ||
2441 memcmp(&backcolor
, &engine
->video_frame
.d3d11
.cb
.backcolor
, sizeof(backcolor
)))
2443 memcpy(&engine
->video_frame
.d3d11
.cb
.dst
, &dst
, sizeof(dst
));
2444 memcpy(&engine
->video_frame
.d3d11
.cb
.src
, &src
, sizeof(src
));
2445 memcpy(&engine
->video_frame
.d3d11
.cb
.backcolor
, &backcolor
, sizeof(backcolor
));
2447 ID3D11DeviceContext_UpdateSubresource(context
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.ps_cb
, 0, NULL
,
2448 &engine
->video_frame
.d3d11
.cb
, 0, 0);
2451 /* Update with new frame contents */
2452 media_engine_update_d3d11_frame_surface(context
, engine
);
2456 vp
.Width
= desc
.Width
;
2457 vp
.Height
= desc
.Height
;
2460 ID3D11DeviceContext_RSSetViewports(context
, 1, &vp
);
2462 ID3D11DeviceContext_IASetInputLayout(context
, engine
->video_frame
.d3d11
.input_layout
);
2463 ID3D11DeviceContext_IASetPrimitiveTopology(context
, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP
);
2464 stride
= sizeof(*quad
);
2466 ID3D11DeviceContext_IASetVertexBuffers(context
, 0, 1, &engine
->video_frame
.d3d11
.vb
, &stride
, &offset
);
2467 ID3D11DeviceContext_VSSetShader(context
, engine
->video_frame
.d3d11
.vs
, NULL
, 0);
2468 ID3D11DeviceContext_PSSetShader(context
, engine
->video_frame
.d3d11
.ps
, NULL
, 0);
2469 ID3D11DeviceContext_PSSetShaderResources(context
, 0, 1, &engine
->video_frame
.d3d11
.srv
);
2470 ID3D11DeviceContext_PSSetConstantBuffers(context
, 0, 1, &engine
->video_frame
.d3d11
.ps_cb
);
2471 ID3D11DeviceContext_PSSetSamplers(context
, 0, 1, &engine
->video_frame
.d3d11
.sampler
);
2472 ID3D11DeviceContext_OMSetRenderTargets(context
, 1, &rtv
, NULL
);
2474 ID3D11DeviceContext_Draw(context
, 4, 0);
2476 ID3D11RenderTargetView_Release(rtv
);
2477 ID3D11DeviceContext_Release(context
);
2480 media_engine_unlock_d3d_device(engine
, device
);
2485 static HRESULT WINAPI
media_engine_TransferVideoFrame(IMFMediaEngineEx
*iface
, IUnknown
*surface
,
2486 const MFVideoNormalizedRect
*src_rect
, const RECT
*dst_rect
, const MFARGB
*color
)
2488 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2489 ID3D11Texture2D
*texture
;
2490 HRESULT hr
= E_NOINTERFACE
;
2492 TRACE("%p, %p, %s, %s, %p.\n", iface
, surface
, src_rect
? wine_dbg_sprintf("(%f,%f)-(%f,%f)",
2493 src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
) : "(null)",
2494 wine_dbgstr_rect(dst_rect
), color
);
2496 EnterCriticalSection(&engine
->cs
);
2498 if (SUCCEEDED(IUnknown_QueryInterface(surface
, &IID_ID3D11Texture2D
, (void **)&texture
)))
2500 hr
= media_engine_transfer_to_d3d11_texture(engine
, texture
, src_rect
, dst_rect
, color
);
2501 ID3D11Texture2D_Release(texture
);
2505 FIXME("Unsupported destination type.\n");
2508 LeaveCriticalSection(&engine
->cs
);
2513 static HRESULT WINAPI
media_engine_OnVideoStreamTick(IMFMediaEngineEx
*iface
, LONGLONG
*pts
)
2515 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2518 TRACE("%p, %p.\n", iface
, pts
);
2520 EnterCriticalSection(&engine
->cs
);
2522 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2528 *pts
= engine
->video_frame
.pts
;
2529 hr
= *pts
== MINLONGLONG
? S_FALSE
: S_OK
;
2532 LeaveCriticalSection(&engine
->cs
);
2537 static HRESULT WINAPI
media_engine_SetSourceFromByteStream(IMFMediaEngineEx
*iface
, IMFByteStream
*bytestream
, BSTR url
)
2539 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2542 TRACE("%p, %p, %s.\n", iface
, bytestream
, debugstr_w(url
));
2544 EnterCriticalSection(&engine
->cs
);
2546 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2548 else if (!bytestream
|| !url
)
2551 hr
= media_engine_set_source(engine
, bytestream
, url
);
2553 LeaveCriticalSection(&engine
->cs
);
2558 static HRESULT WINAPI
media_engine_GetStatistics(IMFMediaEngineEx
*iface
, MF_MEDIA_ENGINE_STATISTIC stat_id
, PROPVARIANT
*stat
)
2560 FIXME("%p, %x, %p stub.\n", iface
, stat_id
, stat
);
2565 static HRESULT WINAPI
media_engine_UpdateVideoStream(IMFMediaEngineEx
*iface
, const MFVideoNormalizedRect
*src
,
2566 const RECT
*dst
, const MFARGB
*border_color
)
2568 FIXME("%p, %p, %p, %p stub.\n", iface
, src
, dst
, border_color
);
2573 static double WINAPI
media_engine_GetBalance(IMFMediaEngineEx
*iface
)
2575 FIXME("%p stub.\n", iface
);
2580 static HRESULT WINAPI
media_engine_SetBalance(IMFMediaEngineEx
*iface
, double balance
)
2582 FIXME("%p, %f stub.\n", iface
, balance
);
2587 static BOOL WINAPI
media_engine_IsPlaybackRateSupported(IMFMediaEngineEx
*iface
, double rate
)
2589 FIXME("%p, %f stub.\n", iface
, rate
);
2594 static HRESULT WINAPI
media_engine_FrameStep(IMFMediaEngineEx
*iface
, BOOL forward
)
2596 FIXME("%p, %d stub.\n", iface
, forward
);
2601 static HRESULT WINAPI
media_engine_GetResourceCharacteristics(IMFMediaEngineEx
*iface
, DWORD
*flags
)
2603 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2604 HRESULT hr
= E_FAIL
;
2606 TRACE("%p, %p.\n", iface
, flags
);
2608 EnterCriticalSection(&engine
->cs
);
2609 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2613 else if (engine
->presentation
.source
&& flags
)
2615 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(engine
->presentation
.source
, flags
)))
2617 *flags
= *flags
& 0xf;
2621 LeaveCriticalSection(&engine
->cs
);
2626 static HRESULT WINAPI
media_engine_GetPresentationAttribute(IMFMediaEngineEx
*iface
, REFGUID attribute
,
2629 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2630 HRESULT hr
= E_FAIL
;
2632 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(attribute
), value
);
2634 EnterCriticalSection(&engine
->cs
);
2635 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2637 else if (engine
->presentation
.pd
)
2638 hr
= IMFPresentationDescriptor_GetItem(engine
->presentation
.pd
, attribute
, value
);
2639 LeaveCriticalSection(&engine
->cs
);
2644 static HRESULT WINAPI
media_engine_GetNumberOfStreams(IMFMediaEngineEx
*iface
, DWORD
*stream_count
)
2646 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2647 HRESULT hr
= E_FAIL
;
2649 TRACE("%p, %p.\n", iface
, stream_count
);
2651 EnterCriticalSection(&engine
->cs
);
2652 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2654 else if (engine
->presentation
.pd
)
2655 hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(engine
->presentation
.pd
, stream_count
);
2656 LeaveCriticalSection(&engine
->cs
);
2661 static HRESULT WINAPI
media_engine_GetStreamAttribute(IMFMediaEngineEx
*iface
, DWORD stream_index
, REFGUID attribute
,
2664 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2665 IMFStreamDescriptor
*sd
;
2666 HRESULT hr
= E_FAIL
;
2669 TRACE("%p, %ld, %s, %p.\n", iface
, stream_index
, debugstr_guid(attribute
), value
);
2671 EnterCriticalSection(&engine
->cs
);
2672 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2674 else if (engine
->presentation
.pd
)
2676 if (SUCCEEDED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(engine
->presentation
.pd
,
2677 stream_index
, &selected
, &sd
)))
2679 hr
= IMFStreamDescriptor_GetItem(sd
, attribute
, value
);
2680 IMFStreamDescriptor_Release(sd
);
2683 LeaveCriticalSection(&engine
->cs
);
2688 static HRESULT WINAPI
media_engine_GetStreamSelection(IMFMediaEngineEx
*iface
, DWORD stream_index
, BOOL
*enabled
)
2690 FIXME("%p, %ld, %p stub.\n", iface
, stream_index
, enabled
);
2695 static HRESULT WINAPI
media_engine_SetStreamSelection(IMFMediaEngineEx
*iface
, DWORD stream_index
, BOOL enabled
)
2697 FIXME("%p, %ld, %d stub.\n", iface
, stream_index
, enabled
);
2702 static HRESULT WINAPI
media_engine_ApplyStreamSelections(IMFMediaEngineEx
*iface
)
2704 FIXME("%p stub.\n", iface
);
2709 static HRESULT WINAPI
media_engine_IsProtected(IMFMediaEngineEx
*iface
, BOOL
*protected)
2711 FIXME("%p, %p stub.\n", iface
, protected);
2716 static HRESULT
media_engine_insert_effect(struct media_engine
*engine
, struct effects
*effects
, IUnknown
*object
, BOOL is_optional
)
2720 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2722 else if (!mf_array_reserve((void **)&effects
->effects
, &effects
->capacity
, effects
->count
+ 1, sizeof(*effects
->effects
)))
2728 effects
->effects
[effects
->count
].object
= object
;
2731 IUnknown_AddRef(effects
->effects
[effects
->count
].object
);
2733 effects
->effects
[effects
->count
].optional
= is_optional
;
2741 static HRESULT WINAPI
media_engine_InsertVideoEffect(IMFMediaEngineEx
*iface
, IUnknown
*effect
, BOOL is_optional
)
2743 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2746 TRACE("%p, %p, %d.\n", iface
, effect
, is_optional
);
2748 EnterCriticalSection(&engine
->cs
);
2749 hr
= media_engine_insert_effect(engine
, &engine
->video_effects
, effect
, is_optional
);
2750 LeaveCriticalSection(&engine
->cs
);
2755 static HRESULT WINAPI
media_engine_InsertAudioEffect(IMFMediaEngineEx
*iface
, IUnknown
*effect
, BOOL is_optional
)
2757 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2760 TRACE("%p, %p, %d.\n", iface
, effect
, is_optional
);
2762 EnterCriticalSection(&engine
->cs
);
2763 hr
= media_engine_insert_effect(engine
, &engine
->audio_effects
, effect
, is_optional
);
2764 LeaveCriticalSection(&engine
->cs
);
2769 static HRESULT WINAPI
media_engine_RemoveAllEffects(IMFMediaEngineEx
*iface
)
2771 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2774 TRACE("%p.\n", iface
);
2776 EnterCriticalSection(&engine
->cs
);
2777 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2781 media_engine_clear_effects(&engine
->audio_effects
);
2782 media_engine_clear_effects(&engine
->video_effects
);
2784 LeaveCriticalSection(&engine
->cs
);
2789 static HRESULT WINAPI
media_engine_SetTimelineMarkerTimer(IMFMediaEngineEx
*iface
, double timeout
)
2791 FIXME("%p, %f stub.\n", iface
, timeout
);
2796 static HRESULT WINAPI
media_engine_GetTimelineMarkerTimer(IMFMediaEngineEx
*iface
, double *timeout
)
2798 FIXME("%p, %p stub.\n", iface
, timeout
);
2803 static HRESULT WINAPI
media_engine_CancelTimelineMarkerTimer(IMFMediaEngineEx
*iface
)
2805 FIXME("%p stub.\n", iface
);
2810 static BOOL WINAPI
media_engine_IsStereo3D(IMFMediaEngineEx
*iface
)
2812 FIXME("%p stub.\n", iface
);
2817 static HRESULT WINAPI
media_engine_GetStereo3DFramePackingMode(IMFMediaEngineEx
*iface
, MF_MEDIA_ENGINE_S3D_PACKING_MODE
*mode
)
2819 FIXME("%p, %p stub.\n", iface
, mode
);
2824 static HRESULT WINAPI
media_engine_SetStereo3DFramePackingMode(IMFMediaEngineEx
*iface
, MF_MEDIA_ENGINE_S3D_PACKING_MODE mode
)
2826 FIXME("%p, %#x stub.\n", iface
, mode
);
2831 static HRESULT WINAPI
media_engine_GetStereo3DRenderMode(IMFMediaEngineEx
*iface
, MF3DVideoOutputType
*output_type
)
2833 FIXME("%p, %p stub.\n", iface
, output_type
);
2838 static HRESULT WINAPI
media_engine_SetStereo3DRenderMode(IMFMediaEngineEx
*iface
, MF3DVideoOutputType output_type
)
2840 FIXME("%p, %#x stub.\n", iface
, output_type
);
2845 static HRESULT WINAPI
media_engine_EnableWindowlessSwapchainMode(IMFMediaEngineEx
*iface
, BOOL enable
)
2847 FIXME("%p, %d stub.\n", iface
, enable
);
2852 static HRESULT WINAPI
media_engine_GetVideoSwapchainHandle(IMFMediaEngineEx
*iface
, HANDLE
*swapchain
)
2854 FIXME("%p, %p stub.\n", iface
, swapchain
);
2859 static HRESULT WINAPI
media_engine_EnableHorizontalMirrorMode(IMFMediaEngineEx
*iface
, BOOL enable
)
2861 FIXME("%p, %d stub.\n", iface
, enable
);
2866 static HRESULT WINAPI
media_engine_GetAudioStreamCategory(IMFMediaEngineEx
*iface
, UINT32
*category
)
2868 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2871 TRACE("%p, %p.\n", iface
, category
);
2873 EnterCriticalSection(&engine
->cs
);
2875 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2878 hr
= IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_CATEGORY
, category
);
2880 LeaveCriticalSection(&engine
->cs
);
2885 static HRESULT WINAPI
media_engine_SetAudioStreamCategory(IMFMediaEngineEx
*iface
, UINT32 category
)
2887 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2890 TRACE("%p, %u.\n", iface
, category
);
2892 EnterCriticalSection(&engine
->cs
);
2894 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2897 hr
= IMFAttributes_SetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_CATEGORY
, category
);
2899 LeaveCriticalSection(&engine
->cs
);
2904 static HRESULT WINAPI
media_engine_GetAudioEndpointRole(IMFMediaEngineEx
*iface
, UINT32
*role
)
2906 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2909 TRACE("%p, %p.\n", iface
, role
);
2911 EnterCriticalSection(&engine
->cs
);
2913 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2916 hr
= IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE
, role
);
2918 LeaveCriticalSection(&engine
->cs
);
2923 static HRESULT WINAPI
media_engine_SetAudioEndpointRole(IMFMediaEngineEx
*iface
, UINT32 role
)
2925 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2928 TRACE("%p, %u.\n", iface
, role
);
2930 EnterCriticalSection(&engine
->cs
);
2932 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2935 hr
= IMFAttributes_SetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE
, role
);
2937 LeaveCriticalSection(&engine
->cs
);
2942 static HRESULT WINAPI
media_engine_GetRealTimeMode(IMFMediaEngineEx
*iface
, BOOL
*enabled
)
2944 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2947 TRACE("%p, %p.\n", iface
, enabled
);
2949 EnterCriticalSection(&engine
->cs
);
2950 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2953 *enabled
= !!(engine
->flags
& MF_MEDIA_ENGINE_REAL_TIME_MODE
);
2954 LeaveCriticalSection(&engine
->cs
);
2959 static HRESULT WINAPI
media_engine_SetRealTimeMode(IMFMediaEngineEx
*iface
, BOOL enable
)
2961 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2964 TRACE("%p, %d.\n", iface
, enable
);
2966 EnterCriticalSection(&engine
->cs
);
2967 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2970 media_engine_set_flag(engine
, MF_MEDIA_ENGINE_REAL_TIME_MODE
, enable
);
2971 LeaveCriticalSection(&engine
->cs
);
2976 static HRESULT WINAPI
media_engine_SetCurrentTimeEx(IMFMediaEngineEx
*iface
, double seektime
, MF_MEDIA_ENGINE_SEEK_MODE mode
)
2978 FIXME("%p, %f, %#x stub.\n", iface
, seektime
, mode
);
2983 static HRESULT WINAPI
media_engine_EnableTimeUpdateTimer(IMFMediaEngineEx
*iface
, BOOL enable
)
2985 FIXME("%p, %d stub.\n", iface
, enable
);
2990 static const IMFMediaEngineExVtbl media_engine_vtbl
=
2992 media_engine_QueryInterface
,
2993 media_engine_AddRef
,
2994 media_engine_Release
,
2995 media_engine_GetError
,
2996 media_engine_SetErrorCode
,
2997 media_engine_SetSourceElements
,
2998 media_engine_SetSource
,
2999 media_engine_GetCurrentSource
,
3000 media_engine_GetNetworkState
,
3001 media_engine_GetPreload
,
3002 media_engine_SetPreload
,
3003 media_engine_GetBuffered
,
3005 media_engine_CanPlayType
,
3006 media_engine_GetReadyState
,
3007 media_engine_IsSeeking
,
3008 media_engine_GetCurrentTime
,
3009 media_engine_SetCurrentTime
,
3010 media_engine_GetStartTime
,
3011 media_engine_GetDuration
,
3012 media_engine_IsPaused
,
3013 media_engine_GetDefaultPlaybackRate
,
3014 media_engine_SetDefaultPlaybackRate
,
3015 media_engine_GetPlaybackRate
,
3016 media_engine_SetPlaybackRate
,
3017 media_engine_GetPlayed
,
3018 media_engine_GetSeekable
,
3019 media_engine_IsEnded
,
3020 media_engine_GetAutoPlay
,
3021 media_engine_SetAutoPlay
,
3022 media_engine_GetLoop
,
3023 media_engine_SetLoop
,
3026 media_engine_GetMuted
,
3027 media_engine_SetMuted
,
3028 media_engine_GetVolume
,
3029 media_engine_SetVolume
,
3030 media_engine_HasVideo
,
3031 media_engine_HasAudio
,
3032 media_engine_GetNativeVideoSize
,
3033 media_engine_GetVideoAspectRatio
,
3034 media_engine_Shutdown
,
3035 media_engine_TransferVideoFrame
,
3036 media_engine_OnVideoStreamTick
,
3037 media_engine_SetSourceFromByteStream
,
3038 media_engine_GetStatistics
,
3039 media_engine_UpdateVideoStream
,
3040 media_engine_GetBalance
,
3041 media_engine_SetBalance
,
3042 media_engine_IsPlaybackRateSupported
,
3043 media_engine_FrameStep
,
3044 media_engine_GetResourceCharacteristics
,
3045 media_engine_GetPresentationAttribute
,
3046 media_engine_GetNumberOfStreams
,
3047 media_engine_GetStreamAttribute
,
3048 media_engine_GetStreamSelection
,
3049 media_engine_SetStreamSelection
,
3050 media_engine_ApplyStreamSelections
,
3051 media_engine_IsProtected
,
3052 media_engine_InsertVideoEffect
,
3053 media_engine_InsertAudioEffect
,
3054 media_engine_RemoveAllEffects
,
3055 media_engine_SetTimelineMarkerTimer
,
3056 media_engine_GetTimelineMarkerTimer
,
3057 media_engine_CancelTimelineMarkerTimer
,
3058 media_engine_IsStereo3D
,
3059 media_engine_GetStereo3DFramePackingMode
,
3060 media_engine_SetStereo3DFramePackingMode
,
3061 media_engine_GetStereo3DRenderMode
,
3062 media_engine_SetStereo3DRenderMode
,
3063 media_engine_EnableWindowlessSwapchainMode
,
3064 media_engine_GetVideoSwapchainHandle
,
3065 media_engine_EnableHorizontalMirrorMode
,
3066 media_engine_GetAudioStreamCategory
,
3067 media_engine_SetAudioStreamCategory
,
3068 media_engine_GetAudioEndpointRole
,
3069 media_engine_SetAudioEndpointRole
,
3070 media_engine_GetRealTimeMode
,
3071 media_engine_SetRealTimeMode
,
3072 media_engine_SetCurrentTimeEx
,
3073 media_engine_EnableTimeUpdateTimer
,
3076 static HRESULT WINAPI
media_engine_gs_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
3078 struct media_engine
*engine
= impl_from_IMFGetService(iface
);
3079 return IMFMediaEngineEx_QueryInterface(&engine
->IMFMediaEngineEx_iface
, riid
, obj
);
3082 static ULONG WINAPI
media_engine_gs_AddRef(IMFGetService
*iface
)
3084 struct media_engine
*engine
= impl_from_IMFGetService(iface
);
3085 return IMFMediaEngineEx_AddRef(&engine
->IMFMediaEngineEx_iface
);
3088 static ULONG WINAPI
media_engine_gs_Release(IMFGetService
*iface
)
3090 struct media_engine
*engine
= impl_from_IMFGetService(iface
);
3091 return IMFMediaEngineEx_Release(&engine
->IMFMediaEngineEx_iface
);
3094 static HRESULT WINAPI
media_engine_gs_GetService(IMFGetService
*iface
, REFGUID service
,
3095 REFIID riid
, void **object
)
3097 FIXME("%p, %s, %s, %p stub.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), object
);
3102 static const IMFGetServiceVtbl media_engine_get_service_vtbl
=
3104 media_engine_gs_QueryInterface
,
3105 media_engine_gs_AddRef
,
3106 media_engine_gs_Release
,
3107 media_engine_gs_GetService
,
3110 static HRESULT WINAPI
media_engine_grabber_callback_QueryInterface(IMFSampleGrabberSinkCallback
*iface
,
3111 REFIID riid
, void **obj
)
3113 if (IsEqualIID(riid
, &IID_IMFSampleGrabberSinkCallback
) ||
3114 IsEqualIID(riid
, &IID_IUnknown
))
3117 IMFSampleGrabberSinkCallback_AddRef(iface
);
3122 return E_NOINTERFACE
;
3125 static ULONG WINAPI
media_engine_grabber_callback_AddRef(IMFSampleGrabberSinkCallback
*iface
)
3127 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
3128 return IMFMediaEngineEx_AddRef(&engine
->IMFMediaEngineEx_iface
);
3131 static ULONG WINAPI
media_engine_grabber_callback_Release(IMFSampleGrabberSinkCallback
*iface
)
3133 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
3134 return IMFMediaEngineEx_Release(&engine
->IMFMediaEngineEx_iface
);
3137 static HRESULT WINAPI
media_engine_grabber_callback_OnClockStart(IMFSampleGrabberSinkCallback
*iface
,
3138 MFTIME systime
, LONGLONG start_offset
)
3143 static HRESULT WINAPI
media_engine_grabber_callback_OnClockStop(IMFSampleGrabberSinkCallback
*iface
,
3146 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
3148 EnterCriticalSection(&engine
->cs
);
3149 media_engine_set_flag(engine
, FLAGS_ENGINE_FIRST_FRAME
, FALSE
);
3150 engine
->video_frame
.pts
= MINLONGLONG
;
3151 LeaveCriticalSection(&engine
->cs
);
3156 static HRESULT WINAPI
media_engine_grabber_callback_OnClockPause(IMFSampleGrabberSinkCallback
*iface
,
3162 static HRESULT WINAPI
media_engine_grabber_callback_OnClockRestart(IMFSampleGrabberSinkCallback
*iface
,
3168 static HRESULT WINAPI
media_engine_grabber_callback_OnClockSetRate(IMFSampleGrabberSinkCallback
*iface
,
3169 MFTIME systime
, float rate
)
3174 static HRESULT WINAPI
media_engine_grabber_callback_OnSetPresentationClock(IMFSampleGrabberSinkCallback
*iface
,
3175 IMFPresentationClock
*clock
)
3180 static HRESULT WINAPI
media_engine_grabber_callback_OnProcessSample(IMFSampleGrabberSinkCallback
*iface
,
3181 REFGUID major_type
, DWORD sample_flags
, LONGLONG sample_time
, LONGLONG sample_duration
,
3182 const BYTE
*buffer
, DWORD buffer_size
)
3184 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
3186 EnterCriticalSection(&engine
->cs
);
3188 if (!(engine
->flags
& FLAGS_ENGINE_FIRST_FRAME
))
3190 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY
, 0, 0);
3191 media_engine_set_flag(engine
, FLAGS_ENGINE_FIRST_FRAME
, TRUE
);
3193 engine
->video_frame
.pts
= sample_time
;
3194 if (engine
->video_frame
.buffer_size
< buffer_size
)
3196 free(engine
->video_frame
.buffer
);
3197 if ((engine
->video_frame
.buffer
= malloc(buffer_size
)))
3198 engine
->video_frame
.buffer_size
= buffer_size
;
3200 if (engine
->video_frame
.buffer
)
3202 memcpy(engine
->video_frame
.buffer
, buffer
, buffer_size
);
3203 engine
->flags
|= FLAGS_ENGINE_NEW_FRAME
;
3206 LeaveCriticalSection(&engine
->cs
);
3211 static HRESULT WINAPI
media_engine_grabber_callback_OnShutdown(IMFSampleGrabberSinkCallback
*iface
)
3216 static const IMFSampleGrabberSinkCallbackVtbl media_engine_grabber_callback_vtbl
=
3218 media_engine_grabber_callback_QueryInterface
,
3219 media_engine_grabber_callback_AddRef
,
3220 media_engine_grabber_callback_Release
,
3221 media_engine_grabber_callback_OnClockStart
,
3222 media_engine_grabber_callback_OnClockStop
,
3223 media_engine_grabber_callback_OnClockPause
,
3224 media_engine_grabber_callback_OnClockRestart
,
3225 media_engine_grabber_callback_OnClockSetRate
,
3226 media_engine_grabber_callback_OnSetPresentationClock
,
3227 media_engine_grabber_callback_OnProcessSample
,
3228 media_engine_grabber_callback_OnShutdown
,
3231 static HRESULT WINAPI
media_engine_factory_QueryInterface(IMFMediaEngineClassFactory
*iface
, REFIID riid
, void **obj
)
3233 if (IsEqualIID(riid
, &IID_IMFMediaEngineClassFactory
) ||
3234 IsEqualIID(riid
, &IID_IUnknown
))
3237 IMFMediaEngineClassFactory_AddRef(iface
);
3241 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
3243 return E_NOINTERFACE
;
3246 static ULONG WINAPI
media_engine_factory_AddRef(IMFMediaEngineClassFactory
*iface
)
3251 static ULONG WINAPI
media_engine_factory_Release(IMFMediaEngineClassFactory
*iface
)
3256 static HRESULT
init_media_engine(DWORD flags
, IMFAttributes
*attributes
, struct media_engine
*engine
)
3258 UINT32 output_format
;
3259 UINT64 playback_hwnd
;
3263 engine
->IMFMediaEngineEx_iface
.lpVtbl
= &media_engine_vtbl
;
3264 engine
->IMFGetService_iface
.lpVtbl
= &media_engine_get_service_vtbl
;
3265 engine
->session_events
.lpVtbl
= &media_engine_session_events_vtbl
;
3266 engine
->load_handler
.lpVtbl
= &media_engine_load_handler_vtbl
;
3267 engine
->grabber_callback
.lpVtbl
= &media_engine_grabber_callback_vtbl
;
3268 engine
->refcount
= 1;
3269 engine
->flags
= (flags
& MF_MEDIA_ENGINE_CREATEFLAGS_MASK
) | FLAGS_ENGINE_PAUSED
;
3270 engine
->default_playback_rate
= 1.0;
3271 engine
->playback_rate
= 1.0;
3272 engine
->volume
= 1.0;
3273 engine
->duration
= NAN
;
3274 engine
->video_frame
.pts
= MINLONGLONG
;
3275 InitializeCriticalSection(&engine
->cs
);
3277 if (FAILED(hr
= IMFAttributes_GetUnknown(attributes
, &MF_MEDIA_ENGINE_CALLBACK
, &IID_IMFMediaEngineNotify
,
3278 (void **)&engine
->callback
)))
3280 WARN("Notification callback was not provided.\n");
3284 IMFAttributes_GetUnknown(attributes
, &MF_MEDIA_ENGINE_EXTENSION
, &IID_IMFMediaEngineExtension
,
3285 (void **)&engine
->extension
);
3287 IMFAttributes_GetUnknown(attributes
, &MF_MEDIA_ENGINE_DXGI_MANAGER
, &IID_IMFDXGIDeviceManager
,
3288 (void **)&engine
->device_manager
);
3290 if (FAILED(hr
= MFCreateMediaSession(NULL
, &engine
->session
)))
3293 if (FAILED(hr
= IMFMediaSession_GetClock(engine
->session
, &clock
)))
3296 hr
= IMFClock_QueryInterface(clock
, &IID_IMFPresentationClock
, (void **)&engine
->clock
);
3297 IMFClock_Release(clock
);
3301 if (FAILED(hr
= IMFMediaSession_BeginGetEvent(engine
->session
, &engine
->session_events
, NULL
)))
3304 if (FAILED(hr
= MFCreateSourceResolver(&engine
->resolver
)))
3307 if (FAILED(hr
= MFCreateAttributes(&engine
->attributes
, 0)))
3310 if (FAILED(hr
= IMFAttributes_CopyAllItems(attributes
, engine
->attributes
)))
3313 /* Set default audio configuration */
3314 if (FAILED(IMFAttributes_GetItem(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_CATEGORY
, NULL
)))
3315 IMFAttributes_SetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_CATEGORY
, AudioCategory_Other
);
3316 if (FAILED(IMFAttributes_GetItem(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE
, NULL
)))
3317 IMFAttributes_SetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE
, eMultimedia
);
3319 IMFAttributes_GetUINT64(attributes
, &MF_MEDIA_ENGINE_PLAYBACK_HWND
, &playback_hwnd
);
3320 hr
= IMFAttributes_GetUINT32(attributes
, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT
, &output_format
);
3321 if (playback_hwnd
) /* FIXME: handle MF_MEDIA_ENGINE_PLAYBACK_VISUAL */
3322 engine
->mode
= MEDIA_ENGINE_RENDERING_MODE
;
3326 engine
->mode
= MEDIA_ENGINE_FRAME_SERVER_MODE
;
3328 engine
->mode
= MEDIA_ENGINE_AUDIO_MODE
;
3334 static HRESULT WINAPI
media_engine_factory_CreateInstance(IMFMediaEngineClassFactory
*iface
, DWORD flags
,
3335 IMFAttributes
*attributes
, IMFMediaEngine
**engine
)
3337 struct media_engine
*object
;
3340 TRACE("%p, %#lx, %p, %p.\n", iface
, flags
, attributes
, engine
);
3342 if (!attributes
|| !engine
)
3345 object
= calloc(1, sizeof(*object
));
3347 return E_OUTOFMEMORY
;
3349 hr
= init_media_engine(flags
, attributes
, object
);
3352 free_media_engine(object
);
3356 *engine
= (IMFMediaEngine
*)&object
->IMFMediaEngineEx_iface
;
3361 static HRESULT WINAPI
media_engine_factory_CreateTimeRange(IMFMediaEngineClassFactory
*iface
,
3362 IMFMediaTimeRange
**range
)
3364 TRACE("%p, %p.\n", iface
, range
);
3366 return create_time_range(range
);
3369 static HRESULT WINAPI
media_engine_factory_CreateError(IMFMediaEngineClassFactory
*iface
, IMFMediaError
**error
)
3371 TRACE("%p, %p.\n", iface
, error
);
3373 return create_media_error(error
);
3376 static const IMFMediaEngineClassFactoryVtbl media_engine_factory_vtbl
=
3378 media_engine_factory_QueryInterface
,
3379 media_engine_factory_AddRef
,
3380 media_engine_factory_Release
,
3381 media_engine_factory_CreateInstance
,
3382 media_engine_factory_CreateTimeRange
,
3383 media_engine_factory_CreateError
,
3386 static IMFMediaEngineClassFactory media_engine_factory
= { &media_engine_factory_vtbl
};
3388 static HRESULT WINAPI
classfactory_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **obj
)
3390 TRACE("%s, %p.\n", debugstr_guid(riid
), obj
);
3392 if (IsEqualGUID(riid
, &IID_IClassFactory
) ||
3393 IsEqualGUID(riid
, &IID_IUnknown
))
3395 IClassFactory_AddRef(iface
);
3400 WARN("interface %s not implemented.\n", debugstr_guid(riid
));
3402 return E_NOINTERFACE
;
3405 static ULONG WINAPI
classfactory_AddRef(IClassFactory
*iface
)
3410 static ULONG WINAPI
classfactory_Release(IClassFactory
*iface
)
3415 static HRESULT WINAPI
classfactory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **obj
)
3417 TRACE("%p, %s, %p.\n", outer
, debugstr_guid(riid
), obj
);
3422 return CLASS_E_NOAGGREGATION
;
3424 return IMFMediaEngineClassFactory_QueryInterface(&media_engine_factory
, riid
, obj
);
3427 static HRESULT WINAPI
classfactory_LockServer(IClassFactory
*iface
, BOOL dolock
)
3429 FIXME("(%d): stub.\n", dolock
);
3433 static const IClassFactoryVtbl class_factory_vtbl
=
3435 classfactory_QueryInterface
,
3436 classfactory_AddRef
,
3437 classfactory_Release
,
3438 classfactory_CreateInstance
,
3439 classfactory_LockServer
,
3442 static IClassFactory classfactory
= { &class_factory_vtbl
};
3444 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **obj
)
3446 TRACE("%s, %s, %p.\n", debugstr_guid(clsid
), debugstr_guid(riid
), obj
);
3448 if (IsEqualGUID(clsid
, &CLSID_MFMediaEngineClassFactory
))
3449 return IClassFactory_QueryInterface(&classfactory
, riid
, obj
);
3451 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
3453 return CLASS_E_CLASSNOTAVAILABLE
;