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 enum media_engine_mode
69 MEDIA_ENGINE_AUDIO_MODE
,
70 MEDIA_ENGINE_RENDERING_MODE
,
71 MEDIA_ENGINE_FRAME_SERVER_MODE
,
74 /* Used with create flags. */
75 enum media_engine_flags
77 /* MF_MEDIA_ENGINE_CREATEFLAGS_MASK is 0x1f. */
78 FLAGS_ENGINE_SHUT_DOWN
= 0x20,
79 FLAGS_ENGINE_AUTO_PLAY
= 0x40,
80 FLAGS_ENGINE_LOOP
= 0x80,
81 FLAGS_ENGINE_PAUSED
= 0x100,
82 FLAGS_ENGINE_WAITING
= 0x200,
83 FLAGS_ENGINE_MUTED
= 0x400,
84 FLAGS_ENGINE_HAS_AUDIO
= 0x800,
85 FLAGS_ENGINE_HAS_VIDEO
= 0x1000,
86 FLAGS_ENGINE_FIRST_FRAME
= 0x2000,
87 FLAGS_ENGINE_IS_ENDED
= 0x4000,
88 FLAGS_ENGINE_NEW_FRAME
= 0x8000,
89 FLAGS_ENGINE_SOURCE_PENDING
= 0x10000,
90 FLAGS_ENGINE_PLAY_PENDING
= 0x20000,
103 static const struct vec3 fullquad
[] =
105 {-1.0f
, -1.0f
, 0.0f
},
107 { 1.0f
, -1.0f
, 0.0f
},
113 float left
, top
, right
, bottom
;
118 IMFMediaEngineEx IMFMediaEngineEx_iface
;
119 IMFGetService IMFGetService_iface
;
120 IMFAsyncCallback session_events
;
121 IMFAsyncCallback load_handler
;
122 IMFSampleGrabberSinkCallback grabber_callback
;
124 IMFMediaEngineNotify
*callback
;
125 IMFAttributes
*attributes
;
126 IMFDXGIDeviceManager
*device_manager
;
127 HANDLE device_handle
;
128 enum media_engine_mode mode
;
130 double playback_rate
;
131 double default_playback_rate
;
134 MF_MEDIA_ENGINE_NETWORK network_state
;
135 MF_MEDIA_ENGINE_ERR error_code
;
136 HRESULT extended_code
;
137 MF_MEDIA_ENGINE_READY ready_state
;
138 MF_MEDIA_ENGINE_PRELOAD preload
;
139 IMFMediaSession
*session
;
140 IMFPresentationClock
*clock
;
141 IMFSourceResolver
*resolver
;
151 DXGI_FORMAT output_format
;
157 ID3D11Texture2D
*source
;
158 ID3D11ShaderResourceView
*srv
;
159 ID3D11SamplerState
*sampler
;
160 ID3D11InputLayout
*input_layout
;
161 ID3D11VertexShader
*vs
;
162 ID3D11PixelShader
*ps
;
168 struct color backcolor
;
175 static void media_engine_release_video_frame_resources(struct media_engine
*engine
)
177 if (engine
->video_frame
.d3d11
.vb
)
178 ID3D11Buffer_Release(engine
->video_frame
.d3d11
.vb
);
179 if (engine
->video_frame
.d3d11
.ps_cb
)
180 ID3D11Buffer_Release(engine
->video_frame
.d3d11
.ps_cb
);
181 if (engine
->video_frame
.d3d11
.source
)
182 ID3D11Texture2D_Release(engine
->video_frame
.d3d11
.source
);
183 if (engine
->video_frame
.d3d11
.srv
)
184 ID3D11ShaderResourceView_Release(engine
->video_frame
.d3d11
.srv
);
185 if (engine
->video_frame
.d3d11
.sampler
)
186 ID3D11SamplerState_Release(engine
->video_frame
.d3d11
.sampler
);
187 if (engine
->video_frame
.d3d11
.input_layout
)
188 ID3D11InputLayout_Release(engine
->video_frame
.d3d11
.input_layout
);
189 if (engine
->video_frame
.d3d11
.vs
)
190 ID3D11VertexShader_Release(engine
->video_frame
.d3d11
.vs
);
191 if (engine
->video_frame
.d3d11
.ps
)
192 ID3D11PixelShader_Release(engine
->video_frame
.d3d11
.ps
);
194 memset(&engine
->video_frame
.d3d11
, 0, sizeof(engine
->video_frame
.d3d11
));
195 memcpy(engine
->video_frame
.d3d11
.quad
, fullquad
, sizeof(fullquad
));
198 static HRESULT
media_engine_lock_d3d_device(struct media_engine
*engine
, ID3D11Device
**device
)
202 if (!engine
->device_manager
)
204 FIXME("Device manager wasn't set.\n");
208 if (!engine
->device_handle
)
210 if (FAILED(hr
= IMFDXGIDeviceManager_OpenDeviceHandle(engine
->device_manager
, &engine
->device_handle
)))
212 WARN("Failed to open device handle, hr %#x.\n", hr
);
217 hr
= IMFDXGIDeviceManager_LockDevice(engine
->device_manager
, engine
->device_handle
, &IID_ID3D11Device
,
218 (void **)device
, TRUE
);
219 if (hr
== MF_E_DXGI_NEW_VIDEO_DEVICE
)
221 IMFDXGIDeviceManager_CloseDeviceHandle(engine
->device_manager
, engine
->device_handle
);
222 engine
->device_handle
= NULL
;
224 media_engine_release_video_frame_resources(engine
);
226 if (FAILED(hr
= IMFDXGIDeviceManager_OpenDeviceHandle(engine
->device_manager
, &engine
->device_handle
)))
228 WARN("Failed to open a device handle, hr %#x.\n", hr
);
231 hr
= IMFDXGIDeviceManager_LockDevice(engine
->device_manager
, engine
->device_handle
, &IID_ID3D11Device
,
232 (void **)device
, TRUE
);
238 static void media_engine_unlock_d3d_device(struct media_engine
*engine
, ID3D11Device
*device
)
240 ID3D11Device_Release(device
);
241 IMFDXGIDeviceManager_UnlockDevice(engine
->device_manager
, engine
->device_handle
, FALSE
);
244 static HRESULT
media_engine_create_d3d11_video_frame_resources(struct media_engine
*engine
, ID3D11Device
*device
)
246 static const D3D11_INPUT_ELEMENT_DESC layout_desc
[] =
248 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT
, 0, 0, D3D11_INPUT_PER_VERTEX_DATA
, 0 },
250 static const DWORD vs_code
[] =
253 float4
main(float4 position
: POSITION
) : SV_POSITION
258 0x43425844, 0xa7a2f22d, 0x83ff2560, 0xe61638bd, 0x87e3ce90, 0x00000001, 0x000000d8, 0x00000003,
259 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
260 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x49534f50, 0x4e4f4954, 0xababab00,
261 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, 0x00000003,
262 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x52444853, 0x0000003c, 0x00010040,
263 0x0000000f, 0x0300005f, 0x001010f2, 0x00000000, 0x04000067, 0x001020f2, 0x00000000, 0x00000001,
264 0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000000, 0x0100003e,
266 static const DWORD ps_code
[] =
275 float4
main(float4 position
: SV_POSITION
) : SV_TARGET
279 if (position
.x
< dst
.x
|| position
.x
> dst
.z
) return backcolor
;
280 if (position
.y
< dst
.y
|| position
.y
> dst
.w
) return backcolor
;
281 p
.x
= (position
.x
- dst
.x
) / (dst
.z
- dst
.x
);
282 p
.y
= 1.0f
- (position
.y
- dst
.y
) / (dst
.w
- dst
.y
);
283 p
.x
= src
.x
+ p
.x
* (src
.z
- src
.x
);
284 p
.y
= src
.y
+ p
.y
* (src
.w
- src
.y
);
285 return t
.Sample(s
, p
);
288 0x43425844, 0x5892e3b1, 0x24c17f7c, 0x9999f143, 0x49667872, 0x00000001, 0x0000032c, 0x00000003,
289 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
290 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000030f, 0x505f5653, 0x5449534f, 0x004e4f49,
291 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
292 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054, 0x52444853, 0x00000290, 0x00000040,
293 0x000000a4, 0x04000059, 0x00208e46, 0x00000000, 0x00000003, 0x0300005a, 0x00106000, 0x00000000,
294 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x04002064, 0x00101032, 0x00000000, 0x00000001,
295 0x03000065, 0x001020f2, 0x00000000, 0x02000068, 0x00000002, 0x08000031, 0x00100012, 0x00000000,
296 0x0010100a, 0x00000000, 0x0020800a, 0x00000000, 0x00000000, 0x08000031, 0x00100022, 0x00000000,
297 0x0020802a, 0x00000000, 0x00000000, 0x0010100a, 0x00000000, 0x0700003c, 0x00100012, 0x00000000,
298 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a, 0x00000000, 0x06000036,
299 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e, 0x01000015, 0x08000031,
300 0x00100012, 0x00000000, 0x0010101a, 0x00000000, 0x0020801a, 0x00000000, 0x00000000, 0x08000031,
301 0x00100022, 0x00000000, 0x0020803a, 0x00000000, 0x00000000, 0x0010101a, 0x00000000, 0x0700003c,
302 0x00100012, 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a,
303 0x00000000, 0x06000036, 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e,
304 0x01000015, 0x09000000, 0x00100032, 0x00000000, 0x00101046, 0x00000000, 0x80208046, 0x00000041,
305 0x00000000, 0x00000000, 0x0a000000, 0x001000c2, 0x00000000, 0x80208406, 0x00000041, 0x00000000,
306 0x00000000, 0x00208ea6, 0x00000000, 0x00000000, 0x0700000e, 0x00100032, 0x00000000, 0x00100046,
307 0x00000000, 0x00100ae6, 0x00000000, 0x08000000, 0x00100022, 0x00000000, 0x8010001a, 0x00000041,
308 0x00000000, 0x00004001, 0x3f800000, 0x0a000000, 0x001000c2, 0x00000000, 0x80208406, 0x00000041,
309 0x00000000, 0x00000001, 0x00208ea6, 0x00000000, 0x00000001, 0x0a000032, 0x00100012, 0x00000001,
310 0x0010000a, 0x00000000, 0x0010002a, 0x00000000, 0x0020800a, 0x00000000, 0x00000001, 0x0a000032,
311 0x00100022, 0x00000001, 0x0010001a, 0x00000000, 0x0010003a, 0x00000000, 0x0020801a, 0x00000000,
312 0x00000001, 0x09000045, 0x001020f2, 0x00000000, 0x00100046, 0x00000001, 0x00107e46, 0x00000000,
313 0x00106000, 0x00000000, 0x0100003e,
315 D3D11_SUBRESOURCE_DATA resource_data
;
316 D3D11_TEXTURE2D_DESC texture_desc
;
317 D3D11_SAMPLER_DESC sampler_desc
;
318 D3D11_BUFFER_DESC buffer_desc
;
321 if (engine
->video_frame
.d3d11
.source
)
324 /* Default vertex buffer, updated on first transfer call. */
325 buffer_desc
.ByteWidth
= sizeof(engine
->video_frame
.d3d11
.quad
);
326 buffer_desc
.Usage
= D3D11_USAGE_DEFAULT
;
327 buffer_desc
.BindFlags
= D3D11_BIND_VERTEX_BUFFER
;
328 buffer_desc
.CPUAccessFlags
= 0;
329 buffer_desc
.MiscFlags
= 0;
330 buffer_desc
.StructureByteStride
= 0;
332 resource_data
.pSysMem
= engine
->video_frame
.d3d11
.quad
;
333 resource_data
.SysMemPitch
= 0;
334 resource_data
.SysMemSlicePitch
= 0;
336 if (FAILED(hr
= ID3D11Device_CreateBuffer(device
, &buffer_desc
, &resource_data
, &engine
->video_frame
.d3d11
.vb
)))
338 WARN("Failed to create a vertex buffer, hr %#x.\n", hr
);
342 buffer_desc
.ByteWidth
= sizeof(engine
->video_frame
.d3d11
.cb
);
343 buffer_desc
.BindFlags
= D3D11_BIND_CONSTANT_BUFFER
;
345 if (FAILED(hr
= ID3D11Device_CreateBuffer(device
, &buffer_desc
, NULL
, &engine
->video_frame
.d3d11
.ps_cb
)))
347 WARN("Failed to create a buffer, hr %#x.\n", hr
);
351 /* Source texture. */
352 texture_desc
.Width
= engine
->video_frame
.size
.cx
;
353 texture_desc
.Height
= engine
->video_frame
.size
.cy
;
354 texture_desc
.MipLevels
= 1;
355 texture_desc
.ArraySize
= 1;
356 texture_desc
.Format
= engine
->video_frame
.output_format
;
357 texture_desc
.SampleDesc
.Count
= 1;
358 texture_desc
.SampleDesc
.Quality
= 0;
359 texture_desc
.Usage
= D3D11_USAGE_DEFAULT
;
360 texture_desc
.BindFlags
= D3D11_BIND_SHADER_RESOURCE
;
361 texture_desc
.CPUAccessFlags
= 0;
362 texture_desc
.MiscFlags
= 0;
364 if (FAILED(hr
= ID3D11Device_CreateTexture2D(device
, &texture_desc
, NULL
, &engine
->video_frame
.d3d11
.source
)))
366 WARN("Failed to create source texture, hr %#x.\n", hr
);
370 if (FAILED(hr
= ID3D11Device_CreateShaderResourceView(device
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.source
,
371 NULL
, &engine
->video_frame
.d3d11
.srv
)))
373 WARN("Failed to create SRV, hr %#x.\n", hr
);
378 memset(&sampler_desc
, 0, sizeof(sampler_desc
));
379 sampler_desc
.Filter
= D3D11_FILTER_MIN_MAG_MIP_POINT
;
380 sampler_desc
.AddressU
= D3D11_TEXTURE_ADDRESS_CLAMP
;
381 sampler_desc
.AddressV
= D3D11_TEXTURE_ADDRESS_CLAMP
;
382 sampler_desc
.AddressW
= D3D11_TEXTURE_ADDRESS_CLAMP
;
384 if (FAILED(hr
= ID3D11Device_CreateSamplerState(device
, &sampler_desc
, &engine
->video_frame
.d3d11
.sampler
)))
386 WARN("Failed to create a sampler state, hr %#x.\n", hr
);
391 if (FAILED(hr
= ID3D11Device_CreateInputLayout(device
, layout_desc
, ARRAY_SIZE(layout_desc
), vs_code
, sizeof(vs_code
),
392 &engine
->video_frame
.d3d11
.input_layout
)))
394 WARN("Failed to create input layout, hr %#x.\n", hr
);
399 if (FAILED(hr
= ID3D11Device_CreateVertexShader(device
, vs_code
, sizeof(vs_code
), NULL
, &engine
->video_frame
.d3d11
.vs
)))
401 WARN("Failed to create the vertex shader, hr %#x.\n", hr
);
405 if (FAILED(hr
= ID3D11Device_CreatePixelShader(device
, ps_code
, sizeof(ps_code
), NULL
, &engine
->video_frame
.d3d11
.ps
)))
407 WARN("Failed to create the pixel shader, hr %#x.\n", hr
);
424 IMFMediaTimeRange IMFMediaTimeRange_iface
;
427 struct range
*ranges
;
432 static struct time_range
*impl_from_IMFMediaTimeRange(IMFMediaTimeRange
*iface
)
434 return CONTAINING_RECORD(iface
, struct time_range
, IMFMediaTimeRange_iface
);
439 IMFMediaError IMFMediaError_iface
;
442 HRESULT extended_code
;
445 static struct media_error
*impl_from_IMFMediaError(IMFMediaError
*iface
)
447 return CONTAINING_RECORD(iface
, struct media_error
, IMFMediaError_iface
);
450 static HRESULT WINAPI
media_error_QueryInterface(IMFMediaError
*iface
, REFIID riid
, void **obj
)
452 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
454 if (IsEqualIID(riid
, &IID_IMFMediaError
) ||
455 IsEqualIID(riid
, &IID_IUnknown
))
458 IMFMediaError_AddRef(iface
);
462 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
464 return E_NOINTERFACE
;
467 static ULONG WINAPI
media_error_AddRef(IMFMediaError
*iface
)
469 struct media_error
*me
= impl_from_IMFMediaError(iface
);
470 ULONG refcount
= InterlockedIncrement(&me
->refcount
);
472 TRACE("%p, refcount %u.\n", iface
, refcount
);
477 static ULONG WINAPI
media_error_Release(IMFMediaError
*iface
)
479 struct media_error
*me
= impl_from_IMFMediaError(iface
);
480 ULONG refcount
= InterlockedDecrement(&me
->refcount
);
482 TRACE("%p, refcount %u.\n", iface
, refcount
);
490 static USHORT WINAPI
media_error_GetErrorCode(IMFMediaError
*iface
)
492 struct media_error
*me
= impl_from_IMFMediaError(iface
);
493 TRACE("%p.\n", iface
);
497 static HRESULT WINAPI
media_error_GetExtendedErrorCode(IMFMediaError
*iface
)
499 struct media_error
*me
= impl_from_IMFMediaError(iface
);
500 TRACE("%p.\n", iface
);
501 return me
->extended_code
;
504 static HRESULT WINAPI
media_error_SetErrorCode(IMFMediaError
*iface
, MF_MEDIA_ENGINE_ERR code
)
506 struct media_error
*me
= impl_from_IMFMediaError(iface
);
508 TRACE("%p, %u.\n", iface
, code
);
510 if ((unsigned int)code
> MF_MEDIA_ENGINE_ERR_ENCRYPTED
)
518 static HRESULT WINAPI
media_error_SetExtendedErrorCode(IMFMediaError
*iface
, HRESULT code
)
520 struct media_error
*me
= impl_from_IMFMediaError(iface
);
522 TRACE("%p, %#x.\n", iface
, code
);
524 me
->extended_code
= code
;
529 static const IMFMediaErrorVtbl media_error_vtbl
=
531 media_error_QueryInterface
,
534 media_error_GetErrorCode
,
535 media_error_GetExtendedErrorCode
,
536 media_error_SetErrorCode
,
537 media_error_SetExtendedErrorCode
,
540 static HRESULT
create_media_error(IMFMediaError
**ret
)
542 struct media_error
*object
;
546 if (!(object
= calloc(1, sizeof(*object
))))
547 return E_OUTOFMEMORY
;
549 object
->IMFMediaError_iface
.lpVtbl
= &media_error_vtbl
;
550 object
->refcount
= 1;
552 *ret
= &object
->IMFMediaError_iface
;
557 static HRESULT WINAPI
time_range_QueryInterface(IMFMediaTimeRange
*iface
, REFIID riid
, void **obj
)
559 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
561 if (IsEqualIID(riid
, &IID_IMFMediaTimeRange
) ||
562 IsEqualIID(riid
, &IID_IUnknown
))
565 IMFMediaTimeRange_AddRef(iface
);
569 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
571 return E_NOINTERFACE
;
574 static ULONG WINAPI
time_range_AddRef(IMFMediaTimeRange
*iface
)
576 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
577 ULONG refcount
= InterlockedIncrement(&range
->refcount
);
579 TRACE("%p, refcount %u.\n", iface
, refcount
);
584 static ULONG WINAPI
time_range_Release(IMFMediaTimeRange
*iface
)
586 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
587 ULONG refcount
= InterlockedDecrement(&range
->refcount
);
589 TRACE("%p, refcount %u.\n", iface
, refcount
);
600 static DWORD WINAPI
time_range_GetLength(IMFMediaTimeRange
*iface
)
602 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
604 TRACE("%p.\n", iface
);
609 static HRESULT WINAPI
time_range_GetStart(IMFMediaTimeRange
*iface
, DWORD idx
, double *start
)
611 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
613 TRACE("%p, %u, %p.\n", iface
, idx
, start
);
615 if (idx
>= range
->count
)
618 *start
= range
->ranges
[idx
].start
;
623 static HRESULT WINAPI
time_range_GetEnd(IMFMediaTimeRange
*iface
, DWORD idx
, double *end
)
625 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
627 TRACE("%p, %u, %p.\n", iface
, idx
, end
);
629 if (idx
>= range
->count
)
632 *end
= range
->ranges
[idx
].end
;
637 static BOOL WINAPI
time_range_ContainsTime(IMFMediaTimeRange
*iface
, double time
)
639 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
642 TRACE("%p, %.8e.\n", iface
, time
);
644 for (i
= 0; i
< range
->count
; ++i
)
646 if (time
>= range
->ranges
[i
].start
&& time
<= range
->ranges
[i
].end
)
653 static HRESULT WINAPI
time_range_AddRange(IMFMediaTimeRange
*iface
, double start
, double end
)
655 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
659 TRACE("%p, %.8e, %.8e.\n", iface
, start
, end
);
661 for (i
= 0; i
< range
->count
; ++i
)
663 c
= &range
->ranges
[i
];
665 /* New range is fully contained within existing one. */
666 if (c
->start
<= start
&& c
->end
>= end
)
669 /* New range fully contains existing one. */
670 if (c
->start
>= start
&& c
->end
<= end
)
677 /* Merge if ranges intersect. */
678 if ((start
>= c
->start
&& start
<= c
->end
) ||
679 (end
>= c
->start
&& end
<= c
->end
))
681 c
->start
= min(c
->start
, start
);
682 c
->end
= max(c
->end
, end
);
687 if (!mf_array_reserve((void **)&range
->ranges
, &range
->capacity
, range
->count
+ 1, sizeof(*range
->ranges
)))
688 return E_OUTOFMEMORY
;
690 range
->ranges
[range
->count
].start
= start
;
691 range
->ranges
[range
->count
].end
= end
;
697 static HRESULT WINAPI
time_range_Clear(IMFMediaTimeRange
*iface
)
699 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
701 TRACE("%p.\n", iface
);
708 static const IMFMediaTimeRangeVtbl time_range_vtbl
=
710 time_range_QueryInterface
,
713 time_range_GetLength
,
716 time_range_ContainsTime
,
721 static HRESULT
create_time_range(IMFMediaTimeRange
**range
)
723 struct time_range
*object
;
725 object
= calloc(1, sizeof(*object
));
727 return E_OUTOFMEMORY
;
729 object
->IMFMediaTimeRange_iface
.lpVtbl
= &time_range_vtbl
;
730 object
->refcount
= 1;
732 *range
= &object
->IMFMediaTimeRange_iface
;
737 static void media_engine_set_flag(struct media_engine
*engine
, unsigned int mask
, BOOL value
)
740 engine
->flags
|= mask
;
742 engine
->flags
&= ~mask
;
745 static inline struct media_engine
*impl_from_IMFMediaEngineEx(IMFMediaEngineEx
*iface
)
747 return CONTAINING_RECORD(iface
, struct media_engine
, IMFMediaEngineEx_iface
);
750 static inline struct media_engine
*impl_from_IMFGetService(IMFGetService
*iface
)
752 return CONTAINING_RECORD(iface
, struct media_engine
, IMFGetService_iface
);
755 static struct media_engine
*impl_from_session_events_IMFAsyncCallback(IMFAsyncCallback
*iface
)
757 return CONTAINING_RECORD(iface
, struct media_engine
, session_events
);
760 static struct media_engine
*impl_from_load_handler_IMFAsyncCallback(IMFAsyncCallback
*iface
)
762 return CONTAINING_RECORD(iface
, struct media_engine
, load_handler
);
765 static struct media_engine
*impl_from_IMFSampleGrabberSinkCallback(IMFSampleGrabberSinkCallback
*iface
)
767 return CONTAINING_RECORD(iface
, struct media_engine
, grabber_callback
);
770 static unsigned int get_gcd(unsigned int a
, unsigned int b
)
784 static void media_engine_get_frame_size(struct media_engine
*engine
, IMFTopology
*topology
)
786 IMFMediaTypeHandler
*handler
;
787 IMFMediaType
*media_type
;
788 IMFStreamDescriptor
*sd
;
789 IMFTopologyNode
*node
;
794 engine
->video_frame
.size
.cx
= 0;
795 engine
->video_frame
.size
.cy
= 0;
796 engine
->video_frame
.ratio
.cx
= 1;
797 engine
->video_frame
.ratio
.cy
= 1;
799 if (FAILED(IMFTopology_GetNodeByID(topology
, engine
->video_frame
.node_id
, &node
)))
802 hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_STREAM_DESCRIPTOR
,
803 &IID_IMFStreamDescriptor
, (void **)&sd
);
804 IMFTopologyNode_Release(node
);
808 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
809 IMFStreamDescriptor_Release(sd
);
813 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, &media_type
);
814 IMFMediaTypeHandler_Release(handler
);
817 WARN("Failed to get current media type %#x.\n", hr
);
821 IMFMediaType_GetUINT64(media_type
, &MF_MT_FRAME_SIZE
, &size
);
823 engine
->video_frame
.size
.cx
= size
>> 32;
824 engine
->video_frame
.size
.cy
= size
;
826 if ((gcd
= get_gcd(engine
->video_frame
.size
.cx
, engine
->video_frame
.size
.cy
)))
828 engine
->video_frame
.ratio
.cx
= engine
->video_frame
.size
.cx
/ gcd
;
829 engine
->video_frame
.ratio
.cy
= engine
->video_frame
.size
.cy
/ gcd
;
832 IMFMediaType_Release(media_type
);
835 static HRESULT WINAPI
media_engine_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
837 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
838 IsEqualIID(riid
, &IID_IUnknown
))
841 IMFAsyncCallback_AddRef(iface
);
845 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
847 return E_NOINTERFACE
;
850 static ULONG WINAPI
media_engine_session_events_AddRef(IMFAsyncCallback
*iface
)
852 struct media_engine
*engine
= impl_from_session_events_IMFAsyncCallback(iface
);
853 return IMFMediaEngineEx_AddRef(&engine
->IMFMediaEngineEx_iface
);
856 static ULONG WINAPI
media_engine_session_events_Release(IMFAsyncCallback
*iface
)
858 struct media_engine
*engine
= impl_from_session_events_IMFAsyncCallback(iface
);
859 return IMFMediaEngineEx_Release(&engine
->IMFMediaEngineEx_iface
);
862 static HRESULT WINAPI
media_engine_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
867 static HRESULT WINAPI
media_engine_session_events_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
869 struct media_engine
*engine
= impl_from_session_events_IMFAsyncCallback(iface
);
870 IMFMediaEvent
*event
= NULL
;
871 MediaEventType event_type
;
874 if (FAILED(hr
= IMFMediaSession_EndGetEvent(engine
->session
, result
, &event
)))
876 WARN("Failed to get session event, hr %#x.\n", hr
);
880 if (FAILED(hr
= IMFMediaEvent_GetType(event
, &event_type
)))
882 WARN("Failed to get event type, hr %#x.\n", hr
);
888 case MEBufferingStarted
:
889 case MEBufferingStopped
:
891 IMFMediaEngineNotify_EventNotify(engine
->callback
, event_type
== MEBufferingStarted
?
892 MF_MEDIA_ENGINE_EVENT_BUFFERINGSTARTED
: MF_MEDIA_ENGINE_EVENT_BUFFERINGENDED
, 0, 0);
894 case MESessionTopologyStatus
:
896 UINT32 topo_status
= 0;
897 IMFTopology
*topology
;
900 IMFMediaEvent_GetUINT32(event
, &MF_EVENT_TOPOLOGY_STATUS
, &topo_status
);
901 if (topo_status
!= MF_TOPOSTATUS_READY
)
905 if (FAILED(IMFMediaEvent_GetValue(event
, &value
)))
908 if (value
.vt
!= VT_UNKNOWN
)
910 PropVariantClear(&value
);
914 topology
= (IMFTopology
*)value
.punkVal
;
916 EnterCriticalSection(&engine
->cs
);
918 engine
->ready_state
= MF_MEDIA_ENGINE_READY_HAVE_METADATA
;
920 media_engine_get_frame_size(engine
, topology
);
922 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE
, 0, 0);
923 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA
, 0, 0);
925 engine
->ready_state
= MF_MEDIA_ENGINE_READY_HAVE_ENOUGH_DATA
;
927 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_LOADEDDATA
, 0, 0);
928 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_CANPLAY
, 0, 0);
930 LeaveCriticalSection(&engine
->cs
);
932 PropVariantClear(&value
);
936 case MESessionStarted
:
938 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PLAYING
, 0, 0);
942 EnterCriticalSection(&engine
->cs
);
943 media_engine_set_flag(engine
, FLAGS_ENGINE_FIRST_FRAME
, FALSE
);
944 media_engine_set_flag(engine
, FLAGS_ENGINE_IS_ENDED
, TRUE
);
945 engine
->video_frame
.pts
= MINLONGLONG
;
946 LeaveCriticalSection(&engine
->cs
);
948 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_ENDED
, 0, 0);
955 IMFMediaEvent_Release(event
);
957 if (FAILED(hr
= IMFMediaSession_BeginGetEvent(engine
->session
, iface
, NULL
)))
958 WARN("Failed to subscribe to session events, hr %#x.\n", hr
);
963 static const IMFAsyncCallbackVtbl media_engine_session_events_vtbl
=
965 media_engine_callback_QueryInterface
,
966 media_engine_session_events_AddRef
,
967 media_engine_session_events_Release
,
968 media_engine_callback_GetParameters
,
969 media_engine_session_events_Invoke
,
972 static ULONG WINAPI
media_engine_load_handler_AddRef(IMFAsyncCallback
*iface
)
974 struct media_engine
*engine
= impl_from_load_handler_IMFAsyncCallback(iface
);
975 return IMFMediaEngineEx_AddRef(&engine
->IMFMediaEngineEx_iface
);
978 static ULONG WINAPI
media_engine_load_handler_Release(IMFAsyncCallback
*iface
)
980 struct media_engine
*engine
= impl_from_load_handler_IMFAsyncCallback(iface
);
981 return IMFMediaEngineEx_Release(&engine
->IMFMediaEngineEx_iface
);
984 static HRESULT
media_engine_create_source_node(IMFMediaSource
*source
, IMFPresentationDescriptor
*pd
, IMFStreamDescriptor
*sd
,
985 IMFTopologyNode
**node
)
989 if (FAILED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE
, node
)))
992 IMFTopologyNode_SetUnknown(*node
, &MF_TOPONODE_SOURCE
, (IUnknown
*)source
);
993 IMFTopologyNode_SetUnknown(*node
, &MF_TOPONODE_PRESENTATION_DESCRIPTOR
, (IUnknown
*)pd
);
994 IMFTopologyNode_SetUnknown(*node
, &MF_TOPONODE_STREAM_DESCRIPTOR
, (IUnknown
*)sd
);
999 static HRESULT
media_engine_create_audio_renderer(struct media_engine
*engine
, IMFTopologyNode
**node
)
1001 unsigned int category
, role
;
1002 IMFActivate
*sar_activate
;
1007 if (FAILED(hr
= MFCreateAudioRendererActivate(&sar_activate
)))
1010 /* Configuration attributes keys differ between Engine and SAR. */
1011 if (SUCCEEDED(IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_CATEGORY
, &category
)))
1012 IMFActivate_SetUINT32(sar_activate
, &MF_AUDIO_RENDERER_ATTRIBUTE_STREAM_CATEGORY
, category
);
1013 if (SUCCEEDED(IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE
, &role
)))
1014 IMFActivate_SetUINT32(sar_activate
, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE
, role
);
1016 if (SUCCEEDED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE
, node
)))
1018 IMFTopologyNode_SetObject(*node
, (IUnknown
*)sar_activate
);
1019 IMFTopologyNode_SetUINT32(*node
, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE
, FALSE
);
1022 IMFActivate_Release(sar_activate
);
1027 static HRESULT
media_engine_create_video_renderer(struct media_engine
*engine
, IMFTopologyNode
**node
)
1029 DXGI_FORMAT output_format
;
1030 IMFMediaType
*media_type
;
1031 IMFActivate
*activate
;
1037 if (FAILED(IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT
, &output_format
)))
1039 WARN("Output format was not specified.\n");
1043 memcpy(&subtype
, &MFVideoFormat_Base
, sizeof(subtype
));
1044 if (!(subtype
.Data1
= MFMapDXGIFormatToDX9Format(output_format
)))
1046 WARN("Unrecognized output format %#x.\n", output_format
);
1050 if (FAILED(hr
= MFCreateMediaType(&media_type
)))
1053 IMFMediaType_SetGUID(media_type
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Video
);
1054 IMFMediaType_SetGUID(media_type
, &MF_MT_SUBTYPE
, &subtype
);
1056 hr
= MFCreateSampleGrabberSinkActivate(media_type
, &engine
->grabber_callback
, &activate
);
1057 IMFMediaType_Release(media_type
);
1061 if (SUCCEEDED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE
, node
)))
1063 IMFTopologyNode_SetObject(*node
, (IUnknown
*)activate
);
1064 IMFTopologyNode_SetUINT32(*node
, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE
, FALSE
);
1067 IMFActivate_Release(activate
);
1069 engine
->video_frame
.output_format
= output_format
;
1074 static HRESULT
media_engine_create_topology(struct media_engine
*engine
, IMFMediaSource
*source
)
1076 IMFStreamDescriptor
*sd_audio
= NULL
, *sd_video
= NULL
;
1077 IMFPresentationDescriptor
*pd
;
1078 DWORD stream_count
= 0, i
;
1079 IMFTopology
*topology
;
1083 media_engine_release_video_frame_resources(engine
);
1085 if (FAILED(hr
= IMFMediaSource_CreatePresentationDescriptor(source
, &pd
)))
1088 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(pd
, &stream_count
)))
1089 WARN("Failed to get stream count, hr %#x.\n", hr
);
1091 /* Enable first video stream and first audio stream. */
1093 for (i
= 0; i
< stream_count
; ++i
)
1095 IMFMediaTypeHandler
*type_handler
;
1096 IMFStreamDescriptor
*sd
;
1099 IMFPresentationDescriptor_DeselectStream(pd
, i
);
1101 if (sd_audio
&& sd_video
)
1104 IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd
, i
, &selected
, &sd
);
1106 if (SUCCEEDED(IMFStreamDescriptor_GetMediaTypeHandler(sd
, &type_handler
)))
1110 IMFMediaTypeHandler_GetMajorType(type_handler
, &major
);
1112 if (IsEqualGUID(&major
, &MFMediaType_Audio
) && !sd_audio
)
1115 IMFStreamDescriptor_AddRef(sd_audio
);
1116 IMFPresentationDescriptor_SelectStream(pd
, i
);
1118 else if (IsEqualGUID(&major
, &MFMediaType_Video
) && !sd_video
&& !(engine
->flags
& MF_MEDIA_ENGINE_AUDIOONLY
))
1121 IMFStreamDescriptor_AddRef(sd_video
);
1122 IMFPresentationDescriptor_SelectStream(pd
, i
);
1125 IMFMediaTypeHandler_Release(type_handler
);
1128 IMFStreamDescriptor_Release(sd
);
1131 if (!sd_video
&& !sd_audio
)
1133 IMFPresentationDescriptor_Release(pd
);
1134 return E_UNEXPECTED
;
1137 media_engine_set_flag(engine
, FLAGS_ENGINE_HAS_VIDEO
, !!sd_video
);
1138 media_engine_set_flag(engine
, FLAGS_ENGINE_HAS_AUDIO
, !!sd_audio
);
1140 /* Assume live source if duration was not provided. */
1141 if (SUCCEEDED(IMFPresentationDescriptor_GetUINT64(pd
, &MF_PD_DURATION
, &duration
)))
1143 /* Convert 100ns to seconds. */
1144 engine
->duration
= duration
/ 10000000;
1147 engine
->duration
= INFINITY
;
1149 if (SUCCEEDED(hr
= MFCreateTopology(&topology
)))
1151 IMFTopologyNode
*sar_node
= NULL
, *audio_src
= NULL
;
1152 IMFTopologyNode
*grabber_node
= NULL
, *video_src
= NULL
;
1156 if (FAILED(hr
= media_engine_create_source_node(source
, pd
, sd_audio
, &audio_src
)))
1157 WARN("Failed to create audio source node, hr %#x.\n", hr
);
1159 if (FAILED(hr
= media_engine_create_audio_renderer(engine
, &sar_node
)))
1160 WARN("Failed to create audio renderer node, hr %#x.\n", hr
);
1162 if (sar_node
&& audio_src
)
1164 IMFTopology_AddNode(topology
, audio_src
);
1165 IMFTopology_AddNode(topology
, sar_node
);
1166 IMFTopologyNode_ConnectOutput(audio_src
, 0, sar_node
, 0);
1170 IMFTopologyNode_Release(sar_node
);
1172 IMFTopologyNode_Release(audio_src
);
1175 if (SUCCEEDED(hr
) && sd_video
)
1177 if (FAILED(hr
= media_engine_create_source_node(source
, pd
, sd_video
, &video_src
)))
1178 WARN("Failed to create video source node, hr %#x.\n", hr
);
1180 if (FAILED(hr
= media_engine_create_video_renderer(engine
, &grabber_node
)))
1181 WARN("Failed to create video grabber node, hr %#x.\n", hr
);
1183 if (grabber_node
&& video_src
)
1185 IMFTopology_AddNode(topology
, video_src
);
1186 IMFTopology_AddNode(topology
, grabber_node
);
1187 IMFTopologyNode_ConnectOutput(video_src
, 0, grabber_node
, 0);
1191 IMFTopologyNode_GetTopoNodeID(video_src
, &engine
->video_frame
.node_id
);
1194 IMFTopologyNode_Release(grabber_node
);
1196 IMFTopologyNode_Release(video_src
);
1199 IMFTopology_SetUINT32(topology
, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES
, TRUE
);
1202 hr
= IMFMediaSession_SetTopology(engine
->session
, MFSESSION_SETTOPOLOGY_IMMEDIATE
, topology
);
1206 IMFTopology_Release(topology
);
1209 IMFStreamDescriptor_Release(sd_video
);
1211 IMFStreamDescriptor_Release(sd_audio
);
1213 IMFPresentationDescriptor_Release(pd
);
1218 static void media_engine_start_playback(struct media_engine
*engine
)
1223 IMFMediaSession_Start(engine
->session
, &GUID_NULL
, &var
);
1226 static HRESULT WINAPI
media_engine_load_handler_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1228 struct media_engine
*engine
= impl_from_load_handler_IMFAsyncCallback(iface
);
1229 IUnknown
*object
= NULL
, *state
;
1230 unsigned int start_playback
;
1231 MF_OBJECT_TYPE obj_type
;
1232 IMFMediaSource
*source
;
1235 EnterCriticalSection(&engine
->cs
);
1237 engine
->network_state
= MF_MEDIA_ENGINE_NETWORK_LOADING
;
1238 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_LOADSTART
, 0, 0);
1240 start_playback
= engine
->flags
& FLAGS_ENGINE_PLAY_PENDING
;
1241 media_engine_set_flag(engine
, FLAGS_ENGINE_SOURCE_PENDING
| FLAGS_ENGINE_PLAY_PENDING
, FALSE
);
1243 if (SUCCEEDED(IMFAsyncResult_GetState(result
, &state
)))
1245 hr
= IMFSourceResolver_EndCreateObjectFromByteStream(engine
->resolver
, result
, &obj_type
, &object
);
1246 IUnknown_Release(state
);
1249 hr
= IMFSourceResolver_EndCreateObjectFromURL(engine
->resolver
, result
, &obj_type
, &object
);
1252 WARN("Failed to create source object, hr %#x.\n", hr
);
1256 if (SUCCEEDED(hr
= IUnknown_QueryInterface(object
, &IID_IMFMediaSource
, (void **)&source
)))
1258 hr
= media_engine_create_topology(engine
, source
);
1259 IMFMediaSource_Release(source
);
1261 IUnknown_Release(object
);
1266 engine
->network_state
= MF_MEDIA_ENGINE_NETWORK_IDLE
;
1268 media_engine_start_playback(engine
);
1272 engine
->network_state
= MF_MEDIA_ENGINE_NETWORK_NO_SOURCE
;
1273 engine
->error_code
= MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED
;
1274 engine
->extended_code
= hr
;
1275 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_ERROR
, engine
->error_code
,
1276 engine
->extended_code
);
1279 LeaveCriticalSection(&engine
->cs
);
1284 static const IMFAsyncCallbackVtbl media_engine_load_handler_vtbl
=
1286 media_engine_callback_QueryInterface
,
1287 media_engine_load_handler_AddRef
,
1288 media_engine_load_handler_Release
,
1289 media_engine_callback_GetParameters
,
1290 media_engine_load_handler_Invoke
,
1293 static HRESULT WINAPI
media_engine_QueryInterface(IMFMediaEngineEx
*iface
, REFIID riid
, void **obj
)
1295 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1297 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1299 if (IsEqualIID(riid
, &IID_IMFMediaEngineEx
) ||
1300 IsEqualIID(riid
, &IID_IMFMediaEngine
) ||
1301 IsEqualIID(riid
, &IID_IUnknown
))
1305 else if (IsEqualIID(riid
, &IID_IMFGetService
))
1307 *obj
= &engine
->IMFGetService_iface
;
1311 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
1313 return E_NOINTERFACE
;
1316 IUnknown_AddRef((IUnknown
*)*obj
);
1320 static ULONG WINAPI
media_engine_AddRef(IMFMediaEngineEx
*iface
)
1322 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1323 ULONG refcount
= InterlockedIncrement(&engine
->refcount
);
1325 TRACE("%p, refcount %u.\n", iface
, refcount
);
1330 static void free_media_engine(struct media_engine
*engine
)
1332 if (engine
->callback
)
1333 IMFMediaEngineNotify_Release(engine
->callback
);
1335 IMFPresentationClock_Release(engine
->clock
);
1336 if (engine
->session
)
1337 IMFMediaSession_Release(engine
->session
);
1338 if (engine
->attributes
)
1339 IMFAttributes_Release(engine
->attributes
);
1340 if (engine
->resolver
)
1341 IMFSourceResolver_Release(engine
->resolver
);
1342 media_engine_release_video_frame_resources(engine
);
1343 if (engine
->device_manager
)
1345 IMFDXGIDeviceManager_CloseDeviceHandle(engine
->device_manager
, engine
->device_handle
);
1346 IMFDXGIDeviceManager_Release(engine
->device_manager
);
1348 SysFreeString(engine
->current_source
);
1349 DeleteCriticalSection(&engine
->cs
);
1350 free(engine
->video_frame
.buffer
);
1354 static ULONG WINAPI
media_engine_Release(IMFMediaEngineEx
*iface
)
1356 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1357 ULONG refcount
= InterlockedDecrement(&engine
->refcount
);
1359 TRACE("%p, refcount %u.\n", iface
, refcount
);
1362 free_media_engine(engine
);
1367 static HRESULT WINAPI
media_engine_GetError(IMFMediaEngineEx
*iface
, IMFMediaError
**error
)
1369 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1372 TRACE("%p, %p.\n", iface
, error
);
1376 EnterCriticalSection(&engine
->cs
);
1377 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1379 else if (engine
->error_code
)
1381 if (SUCCEEDED(hr
= create_media_error(error
)))
1383 IMFMediaError_SetErrorCode(*error
, engine
->error_code
);
1384 IMFMediaError_SetExtendedErrorCode(*error
, engine
->extended_code
);
1387 LeaveCriticalSection(&engine
->cs
);
1392 static HRESULT WINAPI
media_engine_SetErrorCode(IMFMediaEngineEx
*iface
, MF_MEDIA_ENGINE_ERR code
)
1394 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1397 TRACE("%p, %u.\n", iface
, code
);
1399 if ((unsigned int)code
> MF_MEDIA_ENGINE_ERR_ENCRYPTED
)
1400 return E_INVALIDARG
;
1402 EnterCriticalSection(&engine
->cs
);
1403 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1406 engine
->error_code
= code
;
1407 LeaveCriticalSection(&engine
->cs
);
1412 static HRESULT WINAPI
media_engine_SetSourceElements(IMFMediaEngineEx
*iface
, IMFMediaEngineSrcElements
*elements
)
1414 FIXME("(%p, %p): stub.\n", iface
, elements
);
1419 static HRESULT
media_engine_set_source(struct media_engine
*engine
, IMFByteStream
*bytestream
, BSTR url
)
1421 IPropertyStore
*props
= NULL
;
1425 SysFreeString(engine
->current_source
);
1426 engine
->current_source
= NULL
;
1428 engine
->current_source
= SysAllocString(url
);
1430 engine
->ready_state
= MF_MEDIA_ENGINE_READY_HAVE_NOTHING
;
1432 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS
, 0, 0);
1434 engine
->network_state
= MF_MEDIA_ENGINE_NETWORK_NO_SOURCE
;
1436 if (url
|| bytestream
)
1438 flags
= MF_RESOLUTION_MEDIASOURCE
;
1439 if (engine
->flags
& MF_MEDIA_ENGINE_DISABLE_LOCAL_PLUGINS
)
1440 flags
|= MF_RESOLUTION_DISABLE_LOCAL_PLUGINS
;
1442 IMFAttributes_GetUnknown(engine
->attributes
, &MF_MEDIA_ENGINE_SOURCE_RESOLVER_CONFIG_STORE
,
1443 &IID_IPropertyStore
, (void **)&props
);
1445 hr
= IMFSourceResolver_BeginCreateObjectFromByteStream(engine
->resolver
, bytestream
, url
, flags
,
1446 props
, NULL
, &engine
->load_handler
, (IUnknown
*)bytestream
);
1448 hr
= IMFSourceResolver_BeginCreateObjectFromURL(engine
->resolver
, url
, flags
, props
, NULL
,
1449 &engine
->load_handler
, NULL
);
1451 media_engine_set_flag(engine
, FLAGS_ENGINE_SOURCE_PENDING
, TRUE
);
1454 IPropertyStore_Release(props
);
1460 static HRESULT WINAPI
media_engine_SetSource(IMFMediaEngineEx
*iface
, BSTR url
)
1462 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1465 TRACE("%p, %s.\n", iface
, debugstr_w(url
));
1467 EnterCriticalSection(&engine
->cs
);
1469 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1472 hr
= media_engine_set_source(engine
, NULL
, url
);
1474 LeaveCriticalSection(&engine
->cs
);
1479 static HRESULT WINAPI
media_engine_GetCurrentSource(IMFMediaEngineEx
*iface
, BSTR
*url
)
1481 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1484 TRACE("%p, %p.\n", iface
, url
);
1488 EnterCriticalSection(&engine
->cs
);
1490 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1492 if (engine
->current_source
)
1494 if (!(*url
= SysAllocString(engine
->current_source
)))
1498 LeaveCriticalSection(&engine
->cs
);
1503 static USHORT WINAPI
media_engine_GetNetworkState(IMFMediaEngineEx
*iface
)
1505 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1507 TRACE("%p.\n", iface
);
1509 return engine
->network_state
;
1512 static MF_MEDIA_ENGINE_PRELOAD WINAPI
media_engine_GetPreload(IMFMediaEngineEx
*iface
)
1514 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1515 MF_MEDIA_ENGINE_PRELOAD preload
;
1517 TRACE("%p.\n", iface
);
1519 EnterCriticalSection(&engine
->cs
);
1520 preload
= engine
->preload
;
1521 LeaveCriticalSection(&engine
->cs
);
1526 static HRESULT WINAPI
media_engine_SetPreload(IMFMediaEngineEx
*iface
, MF_MEDIA_ENGINE_PRELOAD preload
)
1528 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1530 TRACE("%p, %d.\n", iface
, preload
);
1532 EnterCriticalSection(&engine
->cs
);
1533 engine
->preload
= preload
;
1534 LeaveCriticalSection(&engine
->cs
);
1539 static HRESULT WINAPI
media_engine_GetBuffered(IMFMediaEngineEx
*iface
, IMFMediaTimeRange
**range
)
1541 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1544 TRACE("%p, %p.\n", iface
, range
);
1546 if (FAILED(hr
= create_time_range(range
)))
1549 EnterCriticalSection(&engine
->cs
);
1551 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1553 else if (!isnan(engine
->duration
))
1554 hr
= IMFMediaTimeRange_AddRange(*range
, 0.0, engine
->duration
);
1556 LeaveCriticalSection(&engine
->cs
);
1561 static HRESULT WINAPI
media_engine_Load(IMFMediaEngineEx
*iface
)
1563 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1564 HRESULT hr
= E_NOTIMPL
;
1566 FIXME("(%p): stub.\n", iface
);
1568 EnterCriticalSection(&engine
->cs
);
1570 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1573 LeaveCriticalSection(&engine
->cs
);
1578 static HRESULT WINAPI
media_engine_CanPlayType(IMFMediaEngineEx
*iface
, BSTR type
, MF_MEDIA_ENGINE_CANPLAY
*answer
)
1580 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1581 HRESULT hr
= E_NOTIMPL
;
1583 FIXME("(%p, %s, %p): stub.\n", iface
, debugstr_w(type
), answer
);
1585 EnterCriticalSection(&engine
->cs
);
1587 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1590 LeaveCriticalSection(&engine
->cs
);
1595 static USHORT WINAPI
media_engine_GetReadyState(IMFMediaEngineEx
*iface
)
1597 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1598 unsigned short state
;
1600 TRACE("%p.\n", iface
);
1602 EnterCriticalSection(&engine
->cs
);
1603 state
= engine
->ready_state
;
1604 LeaveCriticalSection(&engine
->cs
);
1609 static BOOL WINAPI
media_engine_IsSeeking(IMFMediaEngineEx
*iface
)
1611 FIXME("(%p): stub.\n", iface
);
1616 static double WINAPI
media_engine_GetCurrentTime(IMFMediaEngineEx
*iface
)
1618 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1622 TRACE("%p.\n", iface
);
1624 EnterCriticalSection(&engine
->cs
);
1625 if (engine
->flags
& FLAGS_ENGINE_IS_ENDED
)
1627 ret
= engine
->duration
;
1629 else if (SUCCEEDED(IMFPresentationClock_GetTime(engine
->clock
, &clocktime
)))
1631 ret
= (double)clocktime
/ 10000000.0;
1633 LeaveCriticalSection(&engine
->cs
);
1638 static HRESULT WINAPI
media_engine_SetCurrentTime(IMFMediaEngineEx
*iface
, double time
)
1640 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1641 HRESULT hr
= E_NOTIMPL
;
1643 FIXME("(%p, %f): stub.\n", iface
, time
);
1645 EnterCriticalSection(&engine
->cs
);
1647 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1650 LeaveCriticalSection(&engine
->cs
);
1655 static double WINAPI
media_engine_GetStartTime(IMFMediaEngineEx
*iface
)
1657 FIXME("(%p): stub.\n", iface
);
1662 static double WINAPI
media_engine_GetDuration(IMFMediaEngineEx
*iface
)
1664 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1667 TRACE("%p.\n", iface
);
1669 EnterCriticalSection(&engine
->cs
);
1670 value
= engine
->duration
;
1671 LeaveCriticalSection(&engine
->cs
);
1676 static BOOL WINAPI
media_engine_IsPaused(IMFMediaEngineEx
*iface
)
1678 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1681 TRACE("%p.\n", iface
);
1683 EnterCriticalSection(&engine
->cs
);
1684 value
= !!(engine
->flags
& FLAGS_ENGINE_PAUSED
);
1685 LeaveCriticalSection(&engine
->cs
);
1690 static double WINAPI
media_engine_GetDefaultPlaybackRate(IMFMediaEngineEx
*iface
)
1692 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1695 TRACE("%p.\n", iface
);
1697 EnterCriticalSection(&engine
->cs
);
1698 rate
= engine
->default_playback_rate
;
1699 LeaveCriticalSection(&engine
->cs
);
1704 static HRESULT WINAPI
media_engine_SetDefaultPlaybackRate(IMFMediaEngineEx
*iface
, double rate
)
1706 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1709 TRACE("%p, %f.\n", iface
, rate
);
1711 EnterCriticalSection(&engine
->cs
);
1712 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1714 else if (engine
->default_playback_rate
!= rate
)
1716 engine
->default_playback_rate
= rate
;
1717 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_RATECHANGE
, 0, 0);
1719 LeaveCriticalSection(&engine
->cs
);
1724 static double WINAPI
media_engine_GetPlaybackRate(IMFMediaEngineEx
*iface
)
1726 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1729 TRACE("%p.\n", iface
);
1731 EnterCriticalSection(&engine
->cs
);
1732 rate
= engine
->playback_rate
;
1733 LeaveCriticalSection(&engine
->cs
);
1738 static HRESULT WINAPI
media_engine_SetPlaybackRate(IMFMediaEngineEx
*iface
, double rate
)
1740 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1743 TRACE("%p, %f.\n", iface
, rate
);
1745 EnterCriticalSection(&engine
->cs
);
1746 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1748 else if (engine
->playback_rate
!= rate
)
1750 engine
->playback_rate
= rate
;
1751 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_RATECHANGE
, 0, 0);
1753 LeaveCriticalSection(&engine
->cs
);
1758 static HRESULT WINAPI
media_engine_GetPlayed(IMFMediaEngineEx
*iface
, IMFMediaTimeRange
**played
)
1760 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1761 HRESULT hr
= E_NOTIMPL
;
1763 FIXME("(%p, %p): stub.\n", iface
, played
);
1765 EnterCriticalSection(&engine
->cs
);
1767 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1770 LeaveCriticalSection(&engine
->cs
);
1775 static HRESULT WINAPI
media_engine_GetSeekable(IMFMediaEngineEx
*iface
, IMFMediaTimeRange
**seekable
)
1777 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1778 HRESULT hr
= E_NOTIMPL
;
1780 FIXME("(%p, %p): stub.\n", iface
, seekable
);
1782 EnterCriticalSection(&engine
->cs
);
1784 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1787 LeaveCriticalSection(&engine
->cs
);
1792 static BOOL WINAPI
media_engine_IsEnded(IMFMediaEngineEx
*iface
)
1794 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1797 TRACE("%p.\n", iface
);
1799 EnterCriticalSection(&engine
->cs
);
1800 value
= !!(engine
->flags
& FLAGS_ENGINE_IS_ENDED
);
1801 LeaveCriticalSection(&engine
->cs
);
1806 static BOOL WINAPI
media_engine_GetAutoPlay(IMFMediaEngineEx
*iface
)
1808 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1811 TRACE("%p.\n", iface
);
1813 EnterCriticalSection(&engine
->cs
);
1814 value
= !!(engine
->flags
& FLAGS_ENGINE_AUTO_PLAY
);
1815 LeaveCriticalSection(&engine
->cs
);
1820 static HRESULT WINAPI
media_engine_SetAutoPlay(IMFMediaEngineEx
*iface
, BOOL autoplay
)
1822 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1824 FIXME("(%p, %d): stub.\n", iface
, autoplay
);
1826 EnterCriticalSection(&engine
->cs
);
1827 media_engine_set_flag(engine
, FLAGS_ENGINE_AUTO_PLAY
, autoplay
);
1828 LeaveCriticalSection(&engine
->cs
);
1833 static BOOL WINAPI
media_engine_GetLoop(IMFMediaEngineEx
*iface
)
1835 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1838 TRACE("%p.\n", iface
);
1840 EnterCriticalSection(&engine
->cs
);
1841 value
= !!(engine
->flags
& FLAGS_ENGINE_LOOP
);
1842 LeaveCriticalSection(&engine
->cs
);
1847 static HRESULT WINAPI
media_engine_SetLoop(IMFMediaEngineEx
*iface
, BOOL loop
)
1849 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1851 FIXME("(%p, %d): stub.\n", iface
, loop
);
1853 EnterCriticalSection(&engine
->cs
);
1854 media_engine_set_flag(engine
, FLAGS_ENGINE_LOOP
, loop
);
1855 LeaveCriticalSection(&engine
->cs
);
1860 static HRESULT WINAPI
media_engine_Play(IMFMediaEngineEx
*iface
)
1862 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1865 TRACE("%p.\n", iface
);
1867 EnterCriticalSection(&engine
->cs
);
1869 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1873 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS
, 0, 0);
1875 if (!(engine
->flags
& FLAGS_ENGINE_WAITING
))
1877 media_engine_set_flag(engine
, FLAGS_ENGINE_PAUSED
| FLAGS_ENGINE_IS_ENDED
, FALSE
);
1878 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PLAY
, 0, 0);
1880 if (!(engine
->flags
& FLAGS_ENGINE_SOURCE_PENDING
))
1881 media_engine_start_playback(engine
);
1883 media_engine_set_flag(engine
, FLAGS_ENGINE_PLAY_PENDING
, TRUE
);
1885 media_engine_set_flag(engine
, FLAGS_ENGINE_WAITING
, TRUE
);
1888 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_WAITING
, 0, 0);
1891 LeaveCriticalSection(&engine
->cs
);
1896 static HRESULT WINAPI
media_engine_Pause(IMFMediaEngineEx
*iface
)
1898 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1901 TRACE("%p.\n", iface
);
1903 EnterCriticalSection(&engine
->cs
);
1905 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1909 if (!(engine
->flags
& FLAGS_ENGINE_PAUSED
))
1911 media_engine_set_flag(engine
, FLAGS_ENGINE_WAITING
| FLAGS_ENGINE_IS_ENDED
, FALSE
);
1912 media_engine_set_flag(engine
, FLAGS_ENGINE_PAUSED
, TRUE
);
1914 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_TIMEUPDATE
, 0, 0);
1915 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PAUSE
, 0, 0);
1918 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS
, 0, 0);
1921 LeaveCriticalSection(&engine
->cs
);
1926 static BOOL WINAPI
media_engine_GetMuted(IMFMediaEngineEx
*iface
)
1928 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1931 TRACE("%p.\n", iface
);
1933 EnterCriticalSection(&engine
->cs
);
1934 ret
= !!(engine
->flags
& FLAGS_ENGINE_MUTED
);
1935 LeaveCriticalSection(&engine
->cs
);
1940 static HRESULT WINAPI
media_engine_SetMuted(IMFMediaEngineEx
*iface
, BOOL muted
)
1942 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1945 TRACE("%p, %d.\n", iface
, muted
);
1947 EnterCriticalSection(&engine
->cs
);
1948 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1950 else if (!!(engine
->flags
& FLAGS_ENGINE_MUTED
) ^ !!muted
)
1952 media_engine_set_flag(engine
, FLAGS_ENGINE_MUTED
, muted
);
1953 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE
, 0, 0);
1955 LeaveCriticalSection(&engine
->cs
);
1960 static double WINAPI
media_engine_GetVolume(IMFMediaEngineEx
*iface
)
1962 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1965 TRACE("%p.\n", iface
);
1967 EnterCriticalSection(&engine
->cs
);
1968 volume
= engine
->volume
;
1969 LeaveCriticalSection(&engine
->cs
);
1974 static HRESULT WINAPI
media_engine_SetVolume(IMFMediaEngineEx
*iface
, double volume
)
1976 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1979 TRACE("%p, %f.\n", iface
, volume
);
1981 EnterCriticalSection(&engine
->cs
);
1982 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1984 else if (volume
!= engine
->volume
)
1986 engine
->volume
= volume
;
1987 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE
, 0, 0);
1989 LeaveCriticalSection(&engine
->cs
);
1994 static BOOL WINAPI
media_engine_HasVideo(IMFMediaEngineEx
*iface
)
1996 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1999 TRACE("%p.\n", iface
);
2001 EnterCriticalSection(&engine
->cs
);
2002 value
= !!(engine
->flags
& FLAGS_ENGINE_HAS_VIDEO
);
2003 LeaveCriticalSection(&engine
->cs
);
2008 static BOOL WINAPI
media_engine_HasAudio(IMFMediaEngineEx
*iface
)
2010 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2013 TRACE("%p.\n", iface
);
2015 EnterCriticalSection(&engine
->cs
);
2016 value
= !!(engine
->flags
& FLAGS_ENGINE_HAS_AUDIO
);
2017 LeaveCriticalSection(&engine
->cs
);
2022 static HRESULT WINAPI
media_engine_GetNativeVideoSize(IMFMediaEngineEx
*iface
, DWORD
*cx
, DWORD
*cy
)
2024 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2027 TRACE("%p, %p, %p.\n", iface
, cx
, cy
);
2030 return E_INVALIDARG
;
2032 EnterCriticalSection(&engine
->cs
);
2034 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2036 else if (!engine
->video_frame
.size
.cx
&& !engine
->video_frame
.size
.cy
)
2040 if (cx
) *cx
= engine
->video_frame
.size
.cx
;
2041 if (cy
) *cy
= engine
->video_frame
.size
.cy
;
2044 LeaveCriticalSection(&engine
->cs
);
2049 static HRESULT WINAPI
media_engine_GetVideoAspectRatio(IMFMediaEngineEx
*iface
, DWORD
*cx
, DWORD
*cy
)
2051 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2054 TRACE("%p, %p, %p.\n", iface
, cx
, cy
);
2057 return E_INVALIDARG
;
2059 EnterCriticalSection(&engine
->cs
);
2061 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2063 else if (!engine
->video_frame
.size
.cx
&& !engine
->video_frame
.size
.cy
)
2067 if (cx
) *cx
= engine
->video_frame
.ratio
.cx
;
2068 if (cy
) *cy
= engine
->video_frame
.ratio
.cy
;
2071 LeaveCriticalSection(&engine
->cs
);
2076 static HRESULT WINAPI
media_engine_Shutdown(IMFMediaEngineEx
*iface
)
2078 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2081 FIXME("(%p): stub.\n", iface
);
2083 EnterCriticalSection(&engine
->cs
);
2084 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2088 media_engine_set_flag(engine
, FLAGS_ENGINE_SHUT_DOWN
, TRUE
);
2089 IMFMediaSession_Shutdown(engine
->session
);
2091 LeaveCriticalSection(&engine
->cs
);
2096 static void set_rect(struct rect
*rect
, float left
, float top
, float right
, float bottom
)
2100 rect
->right
= right
;
2101 rect
->bottom
= bottom
;
2104 static void media_engine_adjust_destination_for_ratio(const struct media_engine
*engine
,
2105 struct rect
*src_n
, struct rect
*dst
)
2107 float dst_width
= dst
->right
- dst
->left
, dst_height
= dst
->bottom
- dst
->top
;
2108 D3D11_TEXTURE2D_DESC source_desc
;
2109 float src_width
, src_height
;
2112 ID3D11Texture2D_GetDesc(engine
->video_frame
.d3d11
.source
, &source_desc
);
2113 set_rect(&src
, src_n
->left
* source_desc
.Width
, src_n
->top
* source_desc
.Height
,
2114 src_n
->right
* source_desc
.Width
, src_n
->bottom
* source_desc
.Height
);
2116 src_width
= src
.right
- src
.left
;
2117 src_height
= src
.bottom
- src
.top
;
2119 if (src_width
* dst_height
> dst_width
* src_height
)
2121 /* src is "wider" than dst. */
2122 float dst_center
= (dst
->top
+ dst
->bottom
) / 2.0f
;
2123 float scaled_height
= src_height
* dst_width
/ src_width
;
2125 dst
->top
= dst_center
- scaled_height
/ 2.0f
;
2126 dst
->bottom
= dst
->top
+ scaled_height
;
2128 else if (src_width
* dst_height
< dst_width
* src_height
)
2130 /* src is "taller" than dst. */
2131 float dst_center
= (dst
->left
+ dst
->right
) / 2.0f
;
2132 float scaled_width
= src_width
* dst_height
/ src_height
;
2134 dst
->left
= dst_center
- scaled_width
/ 2.0f
;
2135 dst
->right
= dst
->left
+ scaled_width
;
2139 static void media_engine_update_d3d11_frame_surface(ID3D11DeviceContext
*context
, struct media_engine
*engine
)
2141 D3D11_TEXTURE2D_DESC surface_desc
;
2143 if (!(engine
->flags
& FLAGS_ENGINE_NEW_FRAME
))
2146 ID3D11Texture2D_GetDesc(engine
->video_frame
.d3d11
.source
, &surface_desc
);
2148 switch (surface_desc
.Format
)
2150 case DXGI_FORMAT_B8G8R8A8_UNORM
:
2151 case DXGI_FORMAT_B8G8R8X8_UNORM
:
2152 surface_desc
.Width
*= 4;
2155 FIXME("Unsupported format %#x.\n", surface_desc
.Format
);
2156 surface_desc
.Width
= 0;
2159 if (engine
->video_frame
.buffer_size
== surface_desc
.Width
* surface_desc
.Height
)
2161 ID3D11DeviceContext_UpdateSubresource(context
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.source
,
2162 0, NULL
, engine
->video_frame
.buffer
, surface_desc
.Width
, 0);
2165 media_engine_set_flag(engine
, FLAGS_ENGINE_NEW_FRAME
, FALSE
);
2168 static HRESULT
media_engine_transfer_to_d3d11_texture(struct media_engine
*engine
, ID3D11Texture2D
*texture
,
2169 const MFVideoNormalizedRect
*src_rect
, const RECT
*dst_rect
, const MFARGB
*color
)
2171 static const float black
[] = {0.0f
, 0.0f
, 0.0f
, 0.0f
};
2172 ID3D11Device
*device
, *dst_device
;
2173 ID3D11DeviceContext
*context
;
2174 ID3D11RenderTargetView
*rtv
;
2175 unsigned int stride
, offset
;
2176 D3D11_TEXTURE2D_DESC desc
;
2177 BOOL device_mismatch
;
2178 struct vec3 quad
[4];
2180 struct rect src
, dst
;
2181 struct color backcolor
;
2185 if (FAILED(hr
= media_engine_lock_d3d_device(engine
, &device
)))
2188 if (FAILED(hr
= media_engine_create_d3d11_video_frame_resources(engine
, device
)))
2190 WARN("Failed to create d3d resources, hr %#x.\n", hr
);
2194 ID3D11Texture2D_GetDevice(texture
, &dst_device
);
2195 device_mismatch
= device
!= dst_device
;
2196 ID3D11Device_Release(dst_device
);
2198 if (device_mismatch
)
2200 WARN("Destination target from different device.\n");
2205 ID3D11Texture2D_GetDesc(texture
, &desc
);
2207 if (FAILED(hr
= ID3D11Device_CreateRenderTargetView(device
, (ID3D11Resource
*)texture
, NULL
, &rtv
)))
2209 WARN("Failed to create an rtv, hr %#x.\n", hr
);
2213 ID3D11Device_GetImmediateContext(device
, &context
);
2215 /* Whole destination is cleared, regardless of specified rectangle. */
2216 ID3D11DeviceContext_ClearRenderTargetView(context
, rtv
, black
);
2220 rect
.left
= max(0, dst_rect
->left
);
2221 rect
.top
= max(0, dst_rect
->top
);
2222 rect
.right
= min(desc
.Width
, dst_rect
->right
);
2223 rect
.bottom
= min(desc
.Height
, dst_rect
->bottom
);
2225 quad
[0].x
= 2.0f
* rect
.left
/ desc
.Width
- 1.0f
;
2226 quad
[0].y
= -2.0f
* rect
.bottom
/ desc
.Height
+ 1.0f
;
2229 quad
[1].x
= quad
[0].x
;
2230 quad
[1].y
= -2.0f
* rect
.top
/ desc
.Height
+ 1.0f
;
2233 quad
[2].x
= 2.0f
* rect
.right
/ desc
.Width
- 1.0f
;
2234 quad
[2].y
= quad
[0].y
;
2237 quad
[3].x
= quad
[2].x
;
2238 quad
[3].y
= quad
[1].y
;
2241 set_rect(&dst
, dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
);
2245 memcpy(quad
, fullquad
, sizeof(quad
));
2246 set_rect(&dst
, 0.0f
, 0.0f
, desc
.Width
, desc
.Height
);
2250 memcpy(&src
, src_rect
, sizeof(src
));
2252 set_rect(&src
, 0.0f
, 0.0f
, 1.0f
, 1.0f
);
2254 media_engine_adjust_destination_for_ratio(engine
, &src
, &dst
);
2256 if (memcmp(quad
, engine
->video_frame
.d3d11
.quad
, sizeof(quad
)))
2258 memcpy(engine
->video_frame
.d3d11
.quad
, quad
, sizeof(quad
));
2259 ID3D11DeviceContext_UpdateSubresource(context
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.vb
, 0, NULL
, quad
, 0, 0);
2264 backcolor
.r
= color
->rgbRed
/ 255.0f
;
2265 backcolor
.g
= color
->rgbGreen
/ 255.0f
;
2266 backcolor
.b
= color
->rgbBlue
/ 255.0f
;
2267 backcolor
.a
= color
->rgbAlpha
/ 255.0f
;
2270 memcpy(&backcolor
, black
, sizeof(backcolor
));
2272 if (memcmp(&dst
, &engine
->video_frame
.d3d11
.cb
.dst
, sizeof(dst
)) ||
2273 memcmp(&src
, &engine
->video_frame
.d3d11
.cb
.src
, sizeof(src
)) ||
2274 memcmp(&backcolor
, &engine
->video_frame
.d3d11
.cb
.backcolor
, sizeof(backcolor
)))
2276 memcpy(&engine
->video_frame
.d3d11
.cb
.dst
, &dst
, sizeof(dst
));
2277 memcpy(&engine
->video_frame
.d3d11
.cb
.src
, &src
, sizeof(src
));
2278 memcpy(&engine
->video_frame
.d3d11
.cb
.backcolor
, &backcolor
, sizeof(backcolor
));
2280 ID3D11DeviceContext_UpdateSubresource(context
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.ps_cb
, 0, NULL
,
2281 &engine
->video_frame
.d3d11
.cb
, 0, 0);
2284 /* Update with new frame contents */
2285 media_engine_update_d3d11_frame_surface(context
, engine
);
2289 vp
.Width
= desc
.Width
;
2290 vp
.Height
= desc
.Height
;
2293 ID3D11DeviceContext_RSSetViewports(context
, 1, &vp
);
2295 ID3D11DeviceContext_IASetInputLayout(context
, engine
->video_frame
.d3d11
.input_layout
);
2296 ID3D11DeviceContext_IASetPrimitiveTopology(context
, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP
);
2297 stride
= sizeof(*quad
);
2299 ID3D11DeviceContext_IASetVertexBuffers(context
, 0, 1, &engine
->video_frame
.d3d11
.vb
, &stride
, &offset
);
2300 ID3D11DeviceContext_VSSetShader(context
, engine
->video_frame
.d3d11
.vs
, NULL
, 0);
2301 ID3D11DeviceContext_PSSetShader(context
, engine
->video_frame
.d3d11
.ps
, NULL
, 0);
2302 ID3D11DeviceContext_PSSetShaderResources(context
, 0, 1, &engine
->video_frame
.d3d11
.srv
);
2303 ID3D11DeviceContext_PSSetConstantBuffers(context
, 0, 1, &engine
->video_frame
.d3d11
.ps_cb
);
2304 ID3D11DeviceContext_PSSetSamplers(context
, 0, 1, &engine
->video_frame
.d3d11
.sampler
);
2305 ID3D11DeviceContext_OMSetRenderTargets(context
, 1, &rtv
, NULL
);
2307 ID3D11DeviceContext_Draw(context
, 4, 0);
2309 ID3D11RenderTargetView_Release(rtv
);
2310 ID3D11DeviceContext_Release(context
);
2313 media_engine_unlock_d3d_device(engine
, device
);
2318 static HRESULT WINAPI
media_engine_TransferVideoFrame(IMFMediaEngineEx
*iface
, IUnknown
*surface
,
2319 const MFVideoNormalizedRect
*src_rect
, const RECT
*dst_rect
, const MFARGB
*color
)
2321 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2322 ID3D11Texture2D
*texture
;
2323 HRESULT hr
= E_NOINTERFACE
;
2325 TRACE("%p, %p, %s, %s, %p.\n", iface
, surface
, src_rect
? wine_dbg_sprintf("(%f,%f)-(%f,%f)",
2326 src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
) : "(null)",
2327 wine_dbgstr_rect(dst_rect
), color
);
2329 EnterCriticalSection(&engine
->cs
);
2331 if (SUCCEEDED(IUnknown_QueryInterface(surface
, &IID_ID3D11Texture2D
, (void **)&texture
)))
2333 hr
= media_engine_transfer_to_d3d11_texture(engine
, texture
, src_rect
, dst_rect
, color
);
2334 ID3D11Texture2D_Release(texture
);
2338 FIXME("Unsupported destination type.\n");
2341 LeaveCriticalSection(&engine
->cs
);
2346 static HRESULT WINAPI
media_engine_OnVideoStreamTick(IMFMediaEngineEx
*iface
, LONGLONG
*pts
)
2348 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2351 TRACE("%p, %p.\n", iface
, pts
);
2353 EnterCriticalSection(&engine
->cs
);
2355 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2361 *pts
= engine
->video_frame
.pts
;
2362 hr
= *pts
== MINLONGLONG
? S_FALSE
: S_OK
;
2365 LeaveCriticalSection(&engine
->cs
);
2370 static HRESULT WINAPI
media_engine_SetSourceFromByteStream(IMFMediaEngineEx
*iface
, IMFByteStream
*bytestream
, BSTR url
)
2372 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2375 TRACE("%p, %p, %s.\n", iface
, bytestream
, debugstr_w(url
));
2377 EnterCriticalSection(&engine
->cs
);
2379 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2381 else if (!bytestream
|| !url
)
2384 hr
= media_engine_set_source(engine
, bytestream
, url
);
2386 LeaveCriticalSection(&engine
->cs
);
2391 static HRESULT WINAPI
media_engine_GetStatistics(IMFMediaEngineEx
*iface
, MF_MEDIA_ENGINE_STATISTIC stat_id
, PROPVARIANT
*stat
)
2393 FIXME("%p, %x, %p stub.\n", iface
, stat_id
, stat
);
2398 static HRESULT WINAPI
media_engine_UpdateVideoStream(IMFMediaEngineEx
*iface
, const MFVideoNormalizedRect
*src
,
2399 const RECT
*dst
, const MFARGB
*border_color
)
2401 FIXME("%p, %p, %p, %p stub.\n", iface
, src
, dst
, border_color
);
2406 static double WINAPI
media_engine_GetBalance(IMFMediaEngineEx
*iface
)
2408 FIXME("%p stub.\n", iface
);
2413 static HRESULT WINAPI
media_engine_SetBalance(IMFMediaEngineEx
*iface
, double balance
)
2415 FIXME("%p, %f stub.\n", iface
, balance
);
2420 static BOOL WINAPI
media_engine_IsPlaybackRateSupported(IMFMediaEngineEx
*iface
, double rate
)
2422 FIXME("%p, %f stub.\n", iface
, rate
);
2427 static HRESULT WINAPI
media_engine_FrameStep(IMFMediaEngineEx
*iface
, BOOL forward
)
2429 FIXME("%p, %d stub.\n", iface
, forward
);
2434 static HRESULT WINAPI
media_engine_GetResourceCharacteristics(IMFMediaEngineEx
*iface
, DWORD
*flags
)
2436 FIXME("%p, %p stub.\n", iface
, flags
);
2441 static HRESULT WINAPI
media_engine_GetPresentationAttribute(IMFMediaEngineEx
*iface
, REFGUID attribute
,
2444 FIXME("%p, %s, %p stub.\n", iface
, debugstr_guid(attribute
), value
);
2449 static HRESULT WINAPI
media_engine_GetNumberOfStreams(IMFMediaEngineEx
*iface
, DWORD
*stream_count
)
2451 FIXME("%p, %p stub.\n", iface
, stream_count
);
2456 static HRESULT WINAPI
media_engine_GetStreamAttribute(IMFMediaEngineEx
*iface
, DWORD stream_index
, REFGUID attribute
,
2459 FIXME("%p, %d, %s, %p stub.\n", iface
, stream_index
, debugstr_guid(attribute
), value
);
2464 static HRESULT WINAPI
media_engine_GetStreamSelection(IMFMediaEngineEx
*iface
, DWORD stream_index
, BOOL
*enabled
)
2466 FIXME("%p, %d, %p stub.\n", iface
, stream_index
, enabled
);
2471 static HRESULT WINAPI
media_engine_SetStreamSelection(IMFMediaEngineEx
*iface
, DWORD stream_index
, BOOL enabled
)
2473 FIXME("%p, %d, %d stub.\n", iface
, stream_index
, enabled
);
2478 static HRESULT WINAPI
media_engine_ApplyStreamSelections(IMFMediaEngineEx
*iface
)
2480 FIXME("%p stub.\n", iface
);
2485 static HRESULT WINAPI
media_engine_IsProtected(IMFMediaEngineEx
*iface
, BOOL
*protected)
2487 FIXME("%p, %p stub.\n", iface
, protected);
2492 static HRESULT WINAPI
media_engine_InsertVideoEffect(IMFMediaEngineEx
*iface
, IUnknown
*effect
, BOOL is_optional
)
2494 FIXME("%p, %p, %d stub.\n", iface
, effect
, is_optional
);
2499 static HRESULT WINAPI
media_engine_InsertAudioEffect(IMFMediaEngineEx
*iface
, IUnknown
*effect
, BOOL is_optional
)
2501 FIXME("%p, %p, %d stub.\n", iface
, effect
, is_optional
);
2506 static HRESULT WINAPI
media_engine_RemoveAllEffects(IMFMediaEngineEx
*iface
)
2508 FIXME("%p stub.\n", iface
);
2513 static HRESULT WINAPI
media_engine_SetTimelineMarkerTimer(IMFMediaEngineEx
*iface
, double timeout
)
2515 FIXME("%p, %f stub.\n", iface
, timeout
);
2520 static HRESULT WINAPI
media_engine_GetTimelineMarkerTimer(IMFMediaEngineEx
*iface
, double *timeout
)
2522 FIXME("%p, %p stub.\n", iface
, timeout
);
2527 static HRESULT WINAPI
media_engine_CancelTimelineMarkerTimer(IMFMediaEngineEx
*iface
)
2529 FIXME("%p stub.\n", iface
);
2534 static BOOL WINAPI
media_engine_IsStereo3D(IMFMediaEngineEx
*iface
)
2536 FIXME("%p stub.\n", iface
);
2541 static HRESULT WINAPI
media_engine_GetStereo3DFramePackingMode(IMFMediaEngineEx
*iface
, MF_MEDIA_ENGINE_S3D_PACKING_MODE
*mode
)
2543 FIXME("%p, %p stub.\n", iface
, mode
);
2548 static HRESULT WINAPI
media_engine_SetStereo3DFramePackingMode(IMFMediaEngineEx
*iface
, MF_MEDIA_ENGINE_S3D_PACKING_MODE mode
)
2550 FIXME("%p, %#x stub.\n", iface
, mode
);
2555 static HRESULT WINAPI
media_engine_GetStereo3DRenderMode(IMFMediaEngineEx
*iface
, MF3DVideoOutputType
*output_type
)
2557 FIXME("%p, %p stub.\n", iface
, output_type
);
2562 static HRESULT WINAPI
media_engine_SetStereo3DRenderMode(IMFMediaEngineEx
*iface
, MF3DVideoOutputType output_type
)
2564 FIXME("%p, %#x stub.\n", iface
, output_type
);
2569 static HRESULT WINAPI
media_engine_EnableWindowlessSwapchainMode(IMFMediaEngineEx
*iface
, BOOL enable
)
2571 FIXME("%p, %d stub.\n", iface
, enable
);
2576 static HRESULT WINAPI
media_engine_GetVideoSwapchainHandle(IMFMediaEngineEx
*iface
, HANDLE
*swapchain
)
2578 FIXME("%p, %p stub.\n", iface
, swapchain
);
2583 static HRESULT WINAPI
media_engine_EnableHorizontalMirrorMode(IMFMediaEngineEx
*iface
, BOOL enable
)
2585 FIXME("%p, %d stub.\n", iface
, enable
);
2590 static HRESULT WINAPI
media_engine_GetAudioStreamCategory(IMFMediaEngineEx
*iface
, UINT32
*category
)
2592 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2595 TRACE("%p, %p.\n", iface
, category
);
2597 EnterCriticalSection(&engine
->cs
);
2599 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2602 hr
= IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_CATEGORY
, category
);
2604 LeaveCriticalSection(&engine
->cs
);
2609 static HRESULT WINAPI
media_engine_SetAudioStreamCategory(IMFMediaEngineEx
*iface
, UINT32 category
)
2611 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2614 TRACE("%p, %u.\n", iface
, category
);
2616 EnterCriticalSection(&engine
->cs
);
2618 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2621 hr
= IMFAttributes_SetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_CATEGORY
, category
);
2623 LeaveCriticalSection(&engine
->cs
);
2628 static HRESULT WINAPI
media_engine_GetAudioEndpointRole(IMFMediaEngineEx
*iface
, UINT32
*role
)
2630 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2633 TRACE("%p, %p.\n", iface
, role
);
2635 EnterCriticalSection(&engine
->cs
);
2637 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2640 hr
= IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE
, role
);
2642 LeaveCriticalSection(&engine
->cs
);
2647 static HRESULT WINAPI
media_engine_SetAudioEndpointRole(IMFMediaEngineEx
*iface
, UINT32 role
)
2649 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2652 TRACE("%p, %u.\n", iface
, role
);
2654 EnterCriticalSection(&engine
->cs
);
2656 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2659 hr
= IMFAttributes_SetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE
, role
);
2661 LeaveCriticalSection(&engine
->cs
);
2666 static HRESULT WINAPI
media_engine_GetRealTimeMode(IMFMediaEngineEx
*iface
, BOOL
*enabled
)
2668 FIXME("%p, %p stub.\n", iface
, enabled
);
2673 static HRESULT WINAPI
media_engine_SetRealTimeMode(IMFMediaEngineEx
*iface
, BOOL enable
)
2675 FIXME("%p, %d stub.\n", iface
, enable
);
2680 static HRESULT WINAPI
media_engine_SetCurrentTimeEx(IMFMediaEngineEx
*iface
, double seektime
, MF_MEDIA_ENGINE_SEEK_MODE mode
)
2682 FIXME("%p, %f, %#x stub.\n", iface
, seektime
, mode
);
2687 static HRESULT WINAPI
media_engine_EnableTimeUpdateTimer(IMFMediaEngineEx
*iface
, BOOL enable
)
2689 FIXME("%p, %d stub.\n", iface
, enable
);
2694 static const IMFMediaEngineExVtbl media_engine_vtbl
=
2696 media_engine_QueryInterface
,
2697 media_engine_AddRef
,
2698 media_engine_Release
,
2699 media_engine_GetError
,
2700 media_engine_SetErrorCode
,
2701 media_engine_SetSourceElements
,
2702 media_engine_SetSource
,
2703 media_engine_GetCurrentSource
,
2704 media_engine_GetNetworkState
,
2705 media_engine_GetPreload
,
2706 media_engine_SetPreload
,
2707 media_engine_GetBuffered
,
2709 media_engine_CanPlayType
,
2710 media_engine_GetReadyState
,
2711 media_engine_IsSeeking
,
2712 media_engine_GetCurrentTime
,
2713 media_engine_SetCurrentTime
,
2714 media_engine_GetStartTime
,
2715 media_engine_GetDuration
,
2716 media_engine_IsPaused
,
2717 media_engine_GetDefaultPlaybackRate
,
2718 media_engine_SetDefaultPlaybackRate
,
2719 media_engine_GetPlaybackRate
,
2720 media_engine_SetPlaybackRate
,
2721 media_engine_GetPlayed
,
2722 media_engine_GetSeekable
,
2723 media_engine_IsEnded
,
2724 media_engine_GetAutoPlay
,
2725 media_engine_SetAutoPlay
,
2726 media_engine_GetLoop
,
2727 media_engine_SetLoop
,
2730 media_engine_GetMuted
,
2731 media_engine_SetMuted
,
2732 media_engine_GetVolume
,
2733 media_engine_SetVolume
,
2734 media_engine_HasVideo
,
2735 media_engine_HasAudio
,
2736 media_engine_GetNativeVideoSize
,
2737 media_engine_GetVideoAspectRatio
,
2738 media_engine_Shutdown
,
2739 media_engine_TransferVideoFrame
,
2740 media_engine_OnVideoStreamTick
,
2741 media_engine_SetSourceFromByteStream
,
2742 media_engine_GetStatistics
,
2743 media_engine_UpdateVideoStream
,
2744 media_engine_GetBalance
,
2745 media_engine_SetBalance
,
2746 media_engine_IsPlaybackRateSupported
,
2747 media_engine_FrameStep
,
2748 media_engine_GetResourceCharacteristics
,
2749 media_engine_GetPresentationAttribute
,
2750 media_engine_GetNumberOfStreams
,
2751 media_engine_GetStreamAttribute
,
2752 media_engine_GetStreamSelection
,
2753 media_engine_SetStreamSelection
,
2754 media_engine_ApplyStreamSelections
,
2755 media_engine_IsProtected
,
2756 media_engine_InsertVideoEffect
,
2757 media_engine_InsertAudioEffect
,
2758 media_engine_RemoveAllEffects
,
2759 media_engine_SetTimelineMarkerTimer
,
2760 media_engine_GetTimelineMarkerTimer
,
2761 media_engine_CancelTimelineMarkerTimer
,
2762 media_engine_IsStereo3D
,
2763 media_engine_GetStereo3DFramePackingMode
,
2764 media_engine_SetStereo3DFramePackingMode
,
2765 media_engine_GetStereo3DRenderMode
,
2766 media_engine_SetStereo3DRenderMode
,
2767 media_engine_EnableWindowlessSwapchainMode
,
2768 media_engine_GetVideoSwapchainHandle
,
2769 media_engine_EnableHorizontalMirrorMode
,
2770 media_engine_GetAudioStreamCategory
,
2771 media_engine_SetAudioStreamCategory
,
2772 media_engine_GetAudioEndpointRole
,
2773 media_engine_SetAudioEndpointRole
,
2774 media_engine_GetRealTimeMode
,
2775 media_engine_SetRealTimeMode
,
2776 media_engine_SetCurrentTimeEx
,
2777 media_engine_EnableTimeUpdateTimer
,
2780 static HRESULT WINAPI
media_engine_gs_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
2782 struct media_engine
*engine
= impl_from_IMFGetService(iface
);
2783 return IMFMediaEngineEx_QueryInterface(&engine
->IMFMediaEngineEx_iface
, riid
, obj
);
2786 static ULONG WINAPI
media_engine_gs_AddRef(IMFGetService
*iface
)
2788 struct media_engine
*engine
= impl_from_IMFGetService(iface
);
2789 return IMFMediaEngineEx_AddRef(&engine
->IMFMediaEngineEx_iface
);
2792 static ULONG WINAPI
media_engine_gs_Release(IMFGetService
*iface
)
2794 struct media_engine
*engine
= impl_from_IMFGetService(iface
);
2795 return IMFMediaEngineEx_Release(&engine
->IMFMediaEngineEx_iface
);
2798 static HRESULT WINAPI
media_engine_gs_GetService(IMFGetService
*iface
, REFGUID service
,
2799 REFIID riid
, void **object
)
2801 FIXME("%p, %s, %s, %p stub.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), object
);
2806 static const IMFGetServiceVtbl media_engine_get_service_vtbl
=
2808 media_engine_gs_QueryInterface
,
2809 media_engine_gs_AddRef
,
2810 media_engine_gs_Release
,
2811 media_engine_gs_GetService
,
2814 static HRESULT WINAPI
media_engine_grabber_callback_QueryInterface(IMFSampleGrabberSinkCallback
*iface
,
2815 REFIID riid
, void **obj
)
2817 if (IsEqualIID(riid
, &IID_IMFSampleGrabberSinkCallback
) ||
2818 IsEqualIID(riid
, &IID_IUnknown
))
2821 IMFSampleGrabberSinkCallback_AddRef(iface
);
2826 return E_NOINTERFACE
;
2829 static ULONG WINAPI
media_engine_grabber_callback_AddRef(IMFSampleGrabberSinkCallback
*iface
)
2831 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
2832 return IMFMediaEngineEx_AddRef(&engine
->IMFMediaEngineEx_iface
);
2835 static ULONG WINAPI
media_engine_grabber_callback_Release(IMFSampleGrabberSinkCallback
*iface
)
2837 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
2838 return IMFMediaEngineEx_Release(&engine
->IMFMediaEngineEx_iface
);
2841 static HRESULT WINAPI
media_engine_grabber_callback_OnClockStart(IMFSampleGrabberSinkCallback
*iface
,
2842 MFTIME systime
, LONGLONG start_offset
)
2847 static HRESULT WINAPI
media_engine_grabber_callback_OnClockStop(IMFSampleGrabberSinkCallback
*iface
,
2850 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
2852 EnterCriticalSection(&engine
->cs
);
2853 media_engine_set_flag(engine
, FLAGS_ENGINE_FIRST_FRAME
, FALSE
);
2854 engine
->video_frame
.pts
= MINLONGLONG
;
2855 LeaveCriticalSection(&engine
->cs
);
2860 static HRESULT WINAPI
media_engine_grabber_callback_OnClockPause(IMFSampleGrabberSinkCallback
*iface
,
2866 static HRESULT WINAPI
media_engine_grabber_callback_OnClockRestart(IMFSampleGrabberSinkCallback
*iface
,
2872 static HRESULT WINAPI
media_engine_grabber_callback_OnClockSetRate(IMFSampleGrabberSinkCallback
*iface
,
2873 MFTIME systime
, float rate
)
2878 static HRESULT WINAPI
media_engine_grabber_callback_OnSetPresentationClock(IMFSampleGrabberSinkCallback
*iface
,
2879 IMFPresentationClock
*clock
)
2884 static HRESULT WINAPI
media_engine_grabber_callback_OnProcessSample(IMFSampleGrabberSinkCallback
*iface
,
2885 REFGUID major_type
, DWORD sample_flags
, LONGLONG sample_time
, LONGLONG sample_duration
,
2886 const BYTE
*buffer
, DWORD buffer_size
)
2888 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
2890 EnterCriticalSection(&engine
->cs
);
2892 if (!(engine
->flags
& FLAGS_ENGINE_FIRST_FRAME
))
2894 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY
, 0, 0);
2895 media_engine_set_flag(engine
, FLAGS_ENGINE_FIRST_FRAME
, TRUE
);
2897 engine
->video_frame
.pts
= sample_time
;
2898 if (engine
->video_frame
.buffer_size
< buffer_size
)
2900 free(engine
->video_frame
.buffer
);
2901 if ((engine
->video_frame
.buffer
= malloc(buffer_size
)))
2902 engine
->video_frame
.buffer_size
= buffer_size
;
2904 if (engine
->video_frame
.buffer
)
2906 memcpy(engine
->video_frame
.buffer
, buffer
, buffer_size
);
2907 engine
->flags
|= FLAGS_ENGINE_NEW_FRAME
;
2910 LeaveCriticalSection(&engine
->cs
);
2915 static HRESULT WINAPI
media_engine_grabber_callback_OnShutdown(IMFSampleGrabberSinkCallback
*iface
)
2920 static const IMFSampleGrabberSinkCallbackVtbl media_engine_grabber_callback_vtbl
=
2922 media_engine_grabber_callback_QueryInterface
,
2923 media_engine_grabber_callback_AddRef
,
2924 media_engine_grabber_callback_Release
,
2925 media_engine_grabber_callback_OnClockStart
,
2926 media_engine_grabber_callback_OnClockStop
,
2927 media_engine_grabber_callback_OnClockPause
,
2928 media_engine_grabber_callback_OnClockRestart
,
2929 media_engine_grabber_callback_OnClockSetRate
,
2930 media_engine_grabber_callback_OnSetPresentationClock
,
2931 media_engine_grabber_callback_OnProcessSample
,
2932 media_engine_grabber_callback_OnShutdown
,
2935 static HRESULT WINAPI
media_engine_factory_QueryInterface(IMFMediaEngineClassFactory
*iface
, REFIID riid
, void **obj
)
2937 if (IsEqualIID(riid
, &IID_IMFMediaEngineClassFactory
) ||
2938 IsEqualIID(riid
, &IID_IUnknown
))
2941 IMFMediaEngineClassFactory_AddRef(iface
);
2945 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
2947 return E_NOINTERFACE
;
2950 static ULONG WINAPI
media_engine_factory_AddRef(IMFMediaEngineClassFactory
*iface
)
2955 static ULONG WINAPI
media_engine_factory_Release(IMFMediaEngineClassFactory
*iface
)
2960 static HRESULT
init_media_engine(DWORD flags
, IMFAttributes
*attributes
, struct media_engine
*engine
)
2962 DXGI_FORMAT output_format
;
2963 UINT64 playback_hwnd
;
2967 engine
->IMFMediaEngineEx_iface
.lpVtbl
= &media_engine_vtbl
;
2968 engine
->IMFGetService_iface
.lpVtbl
= &media_engine_get_service_vtbl
;
2969 engine
->session_events
.lpVtbl
= &media_engine_session_events_vtbl
;
2970 engine
->load_handler
.lpVtbl
= &media_engine_load_handler_vtbl
;
2971 engine
->grabber_callback
.lpVtbl
= &media_engine_grabber_callback_vtbl
;
2972 engine
->refcount
= 1;
2973 engine
->flags
= (flags
& MF_MEDIA_ENGINE_CREATEFLAGS_MASK
) | FLAGS_ENGINE_PAUSED
;
2974 engine
->default_playback_rate
= 1.0;
2975 engine
->playback_rate
= 1.0;
2976 engine
->volume
= 1.0;
2977 engine
->duration
= NAN
;
2978 engine
->video_frame
.pts
= MINLONGLONG
;
2979 InitializeCriticalSection(&engine
->cs
);
2981 hr
= IMFAttributes_GetUnknown(attributes
, &MF_MEDIA_ENGINE_CALLBACK
, &IID_IMFMediaEngineNotify
,
2982 (void **)&engine
->callback
);
2986 IMFAttributes_GetUnknown(attributes
, &MF_MEDIA_ENGINE_DXGI_MANAGER
, &IID_IMFDXGIDeviceManager
,
2987 (void **)&engine
->device_manager
);
2989 if (FAILED(hr
= MFCreateMediaSession(NULL
, &engine
->session
)))
2992 if (FAILED(hr
= IMFMediaSession_GetClock(engine
->session
, &clock
)))
2995 hr
= IMFClock_QueryInterface(clock
, &IID_IMFPresentationClock
, (void **)&engine
->clock
);
2996 IMFClock_Release(clock
);
3000 if (FAILED(hr
= IMFMediaSession_BeginGetEvent(engine
->session
, &engine
->session_events
, NULL
)))
3003 if (FAILED(hr
= MFCreateSourceResolver(&engine
->resolver
)))
3006 if (FAILED(hr
= MFCreateAttributes(&engine
->attributes
, 0)))
3009 if (FAILED(hr
= IMFAttributes_CopyAllItems(attributes
, engine
->attributes
)))
3012 /* Set default audio configuration */
3013 if (FAILED(IMFAttributes_GetItem(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_CATEGORY
, NULL
)))
3014 IMFAttributes_SetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_CATEGORY
, AudioCategory_Other
);
3015 if (FAILED(IMFAttributes_GetItem(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE
, NULL
)))
3016 IMFAttributes_SetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE
, eMultimedia
);
3018 IMFAttributes_GetUINT64(attributes
, &MF_MEDIA_ENGINE_PLAYBACK_HWND
, &playback_hwnd
);
3019 hr
= IMFAttributes_GetUINT32(attributes
, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT
, &output_format
);
3020 if (playback_hwnd
) /* FIXME: handle MF_MEDIA_ENGINE_PLAYBACK_VISUAL */
3021 engine
->mode
= MEDIA_ENGINE_RENDERING_MODE
;
3025 engine
->mode
= MEDIA_ENGINE_FRAME_SERVER_MODE
;
3027 engine
->mode
= MEDIA_ENGINE_AUDIO_MODE
;
3033 static HRESULT WINAPI
media_engine_factory_CreateInstance(IMFMediaEngineClassFactory
*iface
, DWORD flags
,
3034 IMFAttributes
*attributes
, IMFMediaEngine
**engine
)
3036 struct media_engine
*object
;
3039 TRACE("%p, %#x, %p, %p.\n", iface
, flags
, attributes
, engine
);
3041 if (!attributes
|| !engine
)
3044 object
= calloc(1, sizeof(*object
));
3046 return E_OUTOFMEMORY
;
3048 hr
= init_media_engine(flags
, attributes
, object
);
3051 free_media_engine(object
);
3055 *engine
= (IMFMediaEngine
*)&object
->IMFMediaEngineEx_iface
;
3060 static HRESULT WINAPI
media_engine_factory_CreateTimeRange(IMFMediaEngineClassFactory
*iface
,
3061 IMFMediaTimeRange
**range
)
3063 TRACE("%p, %p.\n", iface
, range
);
3065 return create_time_range(range
);
3068 static HRESULT WINAPI
media_engine_factory_CreateError(IMFMediaEngineClassFactory
*iface
, IMFMediaError
**error
)
3070 TRACE("%p, %p.\n", iface
, error
);
3072 return create_media_error(error
);
3075 static const IMFMediaEngineClassFactoryVtbl media_engine_factory_vtbl
=
3077 media_engine_factory_QueryInterface
,
3078 media_engine_factory_AddRef
,
3079 media_engine_factory_Release
,
3080 media_engine_factory_CreateInstance
,
3081 media_engine_factory_CreateTimeRange
,
3082 media_engine_factory_CreateError
,
3085 static IMFMediaEngineClassFactory media_engine_factory
= { &media_engine_factory_vtbl
};
3087 static HRESULT WINAPI
classfactory_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **obj
)
3089 TRACE("%s, %p.\n", debugstr_guid(riid
), obj
);
3091 if (IsEqualGUID(riid
, &IID_IClassFactory
) ||
3092 IsEqualGUID(riid
, &IID_IUnknown
))
3094 IClassFactory_AddRef(iface
);
3099 WARN("interface %s not implemented.\n", debugstr_guid(riid
));
3101 return E_NOINTERFACE
;
3104 static ULONG WINAPI
classfactory_AddRef(IClassFactory
*iface
)
3109 static ULONG WINAPI
classfactory_Release(IClassFactory
*iface
)
3114 static HRESULT WINAPI
classfactory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **obj
)
3116 TRACE("%p, %s, %p.\n", outer
, debugstr_guid(riid
), obj
);
3121 return CLASS_E_NOAGGREGATION
;
3123 return IMFMediaEngineClassFactory_QueryInterface(&media_engine_factory
, riid
, obj
);
3126 static HRESULT WINAPI
classfactory_LockServer(IClassFactory
*iface
, BOOL dolock
)
3128 FIXME("(%d): stub.\n", dolock
);
3132 static const IClassFactoryVtbl class_factory_vtbl
=
3134 classfactory_QueryInterface
,
3135 classfactory_AddRef
,
3136 classfactory_Release
,
3137 classfactory_CreateInstance
,
3138 classfactory_LockServer
,
3141 static IClassFactory classfactory
= { &class_factory_vtbl
};
3143 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **obj
)
3145 TRACE("%s, %s, %p.\n", debugstr_guid(clsid
), debugstr_guid(riid
), obj
);
3147 if (IsEqualGUID(clsid
, &CLSID_MFMediaEngineClassFactory
))
3148 return IClassFactory_QueryInterface(&classfactory
, riid
, obj
);
3150 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
3152 return CLASS_E_CLASSNOTAVAILABLE
;