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
;
145 IMFMediaSource
*source
;
146 IMFPresentationDescriptor
*pd
;
156 DXGI_FORMAT output_format
;
162 ID3D11Texture2D
*source
;
163 ID3D11ShaderResourceView
*srv
;
164 ID3D11SamplerState
*sampler
;
165 ID3D11InputLayout
*input_layout
;
166 ID3D11VertexShader
*vs
;
167 ID3D11PixelShader
*ps
;
173 struct color backcolor
;
180 static void media_engine_release_video_frame_resources(struct media_engine
*engine
)
182 if (engine
->video_frame
.d3d11
.vb
)
183 ID3D11Buffer_Release(engine
->video_frame
.d3d11
.vb
);
184 if (engine
->video_frame
.d3d11
.ps_cb
)
185 ID3D11Buffer_Release(engine
->video_frame
.d3d11
.ps_cb
);
186 if (engine
->video_frame
.d3d11
.source
)
187 ID3D11Texture2D_Release(engine
->video_frame
.d3d11
.source
);
188 if (engine
->video_frame
.d3d11
.srv
)
189 ID3D11ShaderResourceView_Release(engine
->video_frame
.d3d11
.srv
);
190 if (engine
->video_frame
.d3d11
.sampler
)
191 ID3D11SamplerState_Release(engine
->video_frame
.d3d11
.sampler
);
192 if (engine
->video_frame
.d3d11
.input_layout
)
193 ID3D11InputLayout_Release(engine
->video_frame
.d3d11
.input_layout
);
194 if (engine
->video_frame
.d3d11
.vs
)
195 ID3D11VertexShader_Release(engine
->video_frame
.d3d11
.vs
);
196 if (engine
->video_frame
.d3d11
.ps
)
197 ID3D11PixelShader_Release(engine
->video_frame
.d3d11
.ps
);
199 memset(&engine
->video_frame
.d3d11
, 0, sizeof(engine
->video_frame
.d3d11
));
200 memcpy(engine
->video_frame
.d3d11
.quad
, fullquad
, sizeof(fullquad
));
203 static HRESULT
media_engine_lock_d3d_device(struct media_engine
*engine
, ID3D11Device
**device
)
207 if (!engine
->device_manager
)
209 FIXME("Device manager wasn't set.\n");
213 if (!engine
->device_handle
)
215 if (FAILED(hr
= IMFDXGIDeviceManager_OpenDeviceHandle(engine
->device_manager
, &engine
->device_handle
)))
217 WARN("Failed to open device handle, hr %#lx.\n", hr
);
222 hr
= IMFDXGIDeviceManager_LockDevice(engine
->device_manager
, engine
->device_handle
, &IID_ID3D11Device
,
223 (void **)device
, TRUE
);
224 if (hr
== MF_E_DXGI_NEW_VIDEO_DEVICE
)
226 IMFDXGIDeviceManager_CloseDeviceHandle(engine
->device_manager
, engine
->device_handle
);
227 engine
->device_handle
= NULL
;
229 media_engine_release_video_frame_resources(engine
);
231 if (FAILED(hr
= IMFDXGIDeviceManager_OpenDeviceHandle(engine
->device_manager
, &engine
->device_handle
)))
233 WARN("Failed to open a device handle, hr %#lx.\n", hr
);
236 hr
= IMFDXGIDeviceManager_LockDevice(engine
->device_manager
, engine
->device_handle
, &IID_ID3D11Device
,
237 (void **)device
, TRUE
);
243 static void media_engine_unlock_d3d_device(struct media_engine
*engine
, ID3D11Device
*device
)
245 ID3D11Device_Release(device
);
246 IMFDXGIDeviceManager_UnlockDevice(engine
->device_manager
, engine
->device_handle
, FALSE
);
249 static HRESULT
media_engine_create_d3d11_video_frame_resources(struct media_engine
*engine
, ID3D11Device
*device
)
251 static const D3D11_INPUT_ELEMENT_DESC layout_desc
[] =
253 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT
, 0, 0, D3D11_INPUT_PER_VERTEX_DATA
, 0 },
255 static const DWORD vs_code
[] =
258 float4
main(float4 position
: POSITION
) : SV_POSITION
263 0x43425844, 0xa7a2f22d, 0x83ff2560, 0xe61638bd, 0x87e3ce90, 0x00000001, 0x000000d8, 0x00000003,
264 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
265 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x49534f50, 0x4e4f4954, 0xababab00,
266 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, 0x00000003,
267 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x52444853, 0x0000003c, 0x00010040,
268 0x0000000f, 0x0300005f, 0x001010f2, 0x00000000, 0x04000067, 0x001020f2, 0x00000000, 0x00000001,
269 0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000000, 0x0100003e,
271 static const DWORD ps_code
[] =
280 float4
main(float4 position
: SV_POSITION
) : SV_TARGET
284 if (position
.x
< dst
.x
|| position
.x
> dst
.z
) return backcolor
;
285 if (position
.y
< dst
.y
|| position
.y
> dst
.w
) return backcolor
;
286 p
.x
= (position
.x
- dst
.x
) / (dst
.z
- dst
.x
);
287 p
.y
= 1.0f
- (position
.y
- dst
.y
) / (dst
.w
- dst
.y
);
288 p
.x
= src
.x
+ p
.x
* (src
.z
- src
.x
);
289 p
.y
= src
.y
+ p
.y
* (src
.w
- src
.y
);
290 return t
.Sample(s
, p
);
293 0x43425844, 0x5892e3b1, 0x24c17f7c, 0x9999f143, 0x49667872, 0x00000001, 0x0000032c, 0x00000003,
294 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
295 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000030f, 0x505f5653, 0x5449534f, 0x004e4f49,
296 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
297 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054, 0x52444853, 0x00000290, 0x00000040,
298 0x000000a4, 0x04000059, 0x00208e46, 0x00000000, 0x00000003, 0x0300005a, 0x00106000, 0x00000000,
299 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x04002064, 0x00101032, 0x00000000, 0x00000001,
300 0x03000065, 0x001020f2, 0x00000000, 0x02000068, 0x00000002, 0x08000031, 0x00100012, 0x00000000,
301 0x0010100a, 0x00000000, 0x0020800a, 0x00000000, 0x00000000, 0x08000031, 0x00100022, 0x00000000,
302 0x0020802a, 0x00000000, 0x00000000, 0x0010100a, 0x00000000, 0x0700003c, 0x00100012, 0x00000000,
303 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a, 0x00000000, 0x06000036,
304 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e, 0x01000015, 0x08000031,
305 0x00100012, 0x00000000, 0x0010101a, 0x00000000, 0x0020801a, 0x00000000, 0x00000000, 0x08000031,
306 0x00100022, 0x00000000, 0x0020803a, 0x00000000, 0x00000000, 0x0010101a, 0x00000000, 0x0700003c,
307 0x00100012, 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a,
308 0x00000000, 0x06000036, 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e,
309 0x01000015, 0x09000000, 0x00100032, 0x00000000, 0x00101046, 0x00000000, 0x80208046, 0x00000041,
310 0x00000000, 0x00000000, 0x0a000000, 0x001000c2, 0x00000000, 0x80208406, 0x00000041, 0x00000000,
311 0x00000000, 0x00208ea6, 0x00000000, 0x00000000, 0x0700000e, 0x00100032, 0x00000000, 0x00100046,
312 0x00000000, 0x00100ae6, 0x00000000, 0x08000000, 0x00100022, 0x00000000, 0x8010001a, 0x00000041,
313 0x00000000, 0x00004001, 0x3f800000, 0x0a000000, 0x001000c2, 0x00000000, 0x80208406, 0x00000041,
314 0x00000000, 0x00000001, 0x00208ea6, 0x00000000, 0x00000001, 0x0a000032, 0x00100012, 0x00000001,
315 0x0010000a, 0x00000000, 0x0010002a, 0x00000000, 0x0020800a, 0x00000000, 0x00000001, 0x0a000032,
316 0x00100022, 0x00000001, 0x0010001a, 0x00000000, 0x0010003a, 0x00000000, 0x0020801a, 0x00000000,
317 0x00000001, 0x09000045, 0x001020f2, 0x00000000, 0x00100046, 0x00000001, 0x00107e46, 0x00000000,
318 0x00106000, 0x00000000, 0x0100003e,
320 D3D11_SUBRESOURCE_DATA resource_data
;
321 D3D11_TEXTURE2D_DESC texture_desc
;
322 D3D11_SAMPLER_DESC sampler_desc
;
323 D3D11_BUFFER_DESC buffer_desc
;
326 if (engine
->video_frame
.d3d11
.source
)
329 /* Default vertex buffer, updated on first transfer call. */
330 buffer_desc
.ByteWidth
= sizeof(engine
->video_frame
.d3d11
.quad
);
331 buffer_desc
.Usage
= D3D11_USAGE_DEFAULT
;
332 buffer_desc
.BindFlags
= D3D11_BIND_VERTEX_BUFFER
;
333 buffer_desc
.CPUAccessFlags
= 0;
334 buffer_desc
.MiscFlags
= 0;
335 buffer_desc
.StructureByteStride
= 0;
337 resource_data
.pSysMem
= engine
->video_frame
.d3d11
.quad
;
338 resource_data
.SysMemPitch
= 0;
339 resource_data
.SysMemSlicePitch
= 0;
341 if (FAILED(hr
= ID3D11Device_CreateBuffer(device
, &buffer_desc
, &resource_data
, &engine
->video_frame
.d3d11
.vb
)))
343 WARN("Failed to create a vertex buffer, hr %#lx.\n", hr
);
347 buffer_desc
.ByteWidth
= sizeof(engine
->video_frame
.d3d11
.cb
);
348 buffer_desc
.BindFlags
= D3D11_BIND_CONSTANT_BUFFER
;
350 if (FAILED(hr
= ID3D11Device_CreateBuffer(device
, &buffer_desc
, NULL
, &engine
->video_frame
.d3d11
.ps_cb
)))
352 WARN("Failed to create a buffer, hr %#lx.\n", hr
);
356 /* Source texture. */
357 texture_desc
.Width
= engine
->video_frame
.size
.cx
;
358 texture_desc
.Height
= engine
->video_frame
.size
.cy
;
359 texture_desc
.MipLevels
= 1;
360 texture_desc
.ArraySize
= 1;
361 texture_desc
.Format
= engine
->video_frame
.output_format
;
362 texture_desc
.SampleDesc
.Count
= 1;
363 texture_desc
.SampleDesc
.Quality
= 0;
364 texture_desc
.Usage
= D3D11_USAGE_DEFAULT
;
365 texture_desc
.BindFlags
= D3D11_BIND_SHADER_RESOURCE
;
366 texture_desc
.CPUAccessFlags
= 0;
367 texture_desc
.MiscFlags
= 0;
369 if (FAILED(hr
= ID3D11Device_CreateTexture2D(device
, &texture_desc
, NULL
, &engine
->video_frame
.d3d11
.source
)))
371 WARN("Failed to create source texture, hr %#lx.\n", hr
);
375 if (FAILED(hr
= ID3D11Device_CreateShaderResourceView(device
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.source
,
376 NULL
, &engine
->video_frame
.d3d11
.srv
)))
378 WARN("Failed to create SRV, hr %#lx.\n", hr
);
383 memset(&sampler_desc
, 0, sizeof(sampler_desc
));
384 sampler_desc
.Filter
= D3D11_FILTER_MIN_MAG_MIP_POINT
;
385 sampler_desc
.AddressU
= D3D11_TEXTURE_ADDRESS_CLAMP
;
386 sampler_desc
.AddressV
= D3D11_TEXTURE_ADDRESS_CLAMP
;
387 sampler_desc
.AddressW
= D3D11_TEXTURE_ADDRESS_CLAMP
;
389 if (FAILED(hr
= ID3D11Device_CreateSamplerState(device
, &sampler_desc
, &engine
->video_frame
.d3d11
.sampler
)))
391 WARN("Failed to create a sampler state, hr %#lx.\n", hr
);
396 if (FAILED(hr
= ID3D11Device_CreateInputLayout(device
, layout_desc
, ARRAY_SIZE(layout_desc
), vs_code
, sizeof(vs_code
),
397 &engine
->video_frame
.d3d11
.input_layout
)))
399 WARN("Failed to create input layout, hr %#lx.\n", hr
);
404 if (FAILED(hr
= ID3D11Device_CreateVertexShader(device
, vs_code
, sizeof(vs_code
), NULL
, &engine
->video_frame
.d3d11
.vs
)))
406 WARN("Failed to create the vertex shader, hr %#lx.\n", hr
);
410 if (FAILED(hr
= ID3D11Device_CreatePixelShader(device
, ps_code
, sizeof(ps_code
), NULL
, &engine
->video_frame
.d3d11
.ps
)))
412 WARN("Failed to create the pixel shader, hr %#lx.\n", hr
);
429 IMFMediaTimeRange IMFMediaTimeRange_iface
;
432 struct range
*ranges
;
437 static struct time_range
*impl_from_IMFMediaTimeRange(IMFMediaTimeRange
*iface
)
439 return CONTAINING_RECORD(iface
, struct time_range
, IMFMediaTimeRange_iface
);
444 IMFMediaError IMFMediaError_iface
;
447 HRESULT extended_code
;
450 static struct media_error
*impl_from_IMFMediaError(IMFMediaError
*iface
)
452 return CONTAINING_RECORD(iface
, struct media_error
, IMFMediaError_iface
);
455 static HRESULT WINAPI
media_error_QueryInterface(IMFMediaError
*iface
, REFIID riid
, void **obj
)
457 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
459 if (IsEqualIID(riid
, &IID_IMFMediaError
) ||
460 IsEqualIID(riid
, &IID_IUnknown
))
463 IMFMediaError_AddRef(iface
);
467 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
469 return E_NOINTERFACE
;
472 static ULONG WINAPI
media_error_AddRef(IMFMediaError
*iface
)
474 struct media_error
*me
= impl_from_IMFMediaError(iface
);
475 ULONG refcount
= InterlockedIncrement(&me
->refcount
);
477 TRACE("%p, refcount %lu.\n", iface
, refcount
);
482 static ULONG WINAPI
media_error_Release(IMFMediaError
*iface
)
484 struct media_error
*me
= impl_from_IMFMediaError(iface
);
485 ULONG refcount
= InterlockedDecrement(&me
->refcount
);
487 TRACE("%p, refcount %lu.\n", iface
, refcount
);
495 static USHORT WINAPI
media_error_GetErrorCode(IMFMediaError
*iface
)
497 struct media_error
*me
= impl_from_IMFMediaError(iface
);
498 TRACE("%p.\n", iface
);
502 static HRESULT WINAPI
media_error_GetExtendedErrorCode(IMFMediaError
*iface
)
504 struct media_error
*me
= impl_from_IMFMediaError(iface
);
505 TRACE("%p.\n", iface
);
506 return me
->extended_code
;
509 static HRESULT WINAPI
media_error_SetErrorCode(IMFMediaError
*iface
, MF_MEDIA_ENGINE_ERR code
)
511 struct media_error
*me
= impl_from_IMFMediaError(iface
);
513 TRACE("%p, %u.\n", iface
, code
);
515 if ((unsigned int)code
> MF_MEDIA_ENGINE_ERR_ENCRYPTED
)
523 static HRESULT WINAPI
media_error_SetExtendedErrorCode(IMFMediaError
*iface
, HRESULT code
)
525 struct media_error
*me
= impl_from_IMFMediaError(iface
);
527 TRACE("%p, %#lx.\n", iface
, code
);
529 me
->extended_code
= code
;
534 static const IMFMediaErrorVtbl media_error_vtbl
=
536 media_error_QueryInterface
,
539 media_error_GetErrorCode
,
540 media_error_GetExtendedErrorCode
,
541 media_error_SetErrorCode
,
542 media_error_SetExtendedErrorCode
,
545 static HRESULT
create_media_error(IMFMediaError
**ret
)
547 struct media_error
*object
;
551 if (!(object
= calloc(1, sizeof(*object
))))
552 return E_OUTOFMEMORY
;
554 object
->IMFMediaError_iface
.lpVtbl
= &media_error_vtbl
;
555 object
->refcount
= 1;
557 *ret
= &object
->IMFMediaError_iface
;
562 static HRESULT WINAPI
time_range_QueryInterface(IMFMediaTimeRange
*iface
, REFIID riid
, void **obj
)
564 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
566 if (IsEqualIID(riid
, &IID_IMFMediaTimeRange
) ||
567 IsEqualIID(riid
, &IID_IUnknown
))
570 IMFMediaTimeRange_AddRef(iface
);
574 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
576 return E_NOINTERFACE
;
579 static ULONG WINAPI
time_range_AddRef(IMFMediaTimeRange
*iface
)
581 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
582 ULONG refcount
= InterlockedIncrement(&range
->refcount
);
584 TRACE("%p, refcount %lu.\n", iface
, refcount
);
589 static ULONG WINAPI
time_range_Release(IMFMediaTimeRange
*iface
)
591 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
592 ULONG refcount
= InterlockedDecrement(&range
->refcount
);
594 TRACE("%p, refcount %lu.\n", iface
, refcount
);
605 static DWORD WINAPI
time_range_GetLength(IMFMediaTimeRange
*iface
)
607 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
609 TRACE("%p.\n", iface
);
614 static HRESULT WINAPI
time_range_GetStart(IMFMediaTimeRange
*iface
, DWORD idx
, double *start
)
616 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
618 TRACE("%p, %lu, %p.\n", iface
, idx
, start
);
620 if (idx
>= range
->count
)
623 *start
= range
->ranges
[idx
].start
;
628 static HRESULT WINAPI
time_range_GetEnd(IMFMediaTimeRange
*iface
, DWORD idx
, double *end
)
630 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
632 TRACE("%p, %lu, %p.\n", iface
, idx
, end
);
634 if (idx
>= range
->count
)
637 *end
= range
->ranges
[idx
].end
;
642 static BOOL WINAPI
time_range_ContainsTime(IMFMediaTimeRange
*iface
, double time
)
644 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
647 TRACE("%p, %.8e.\n", iface
, time
);
649 for (i
= 0; i
< range
->count
; ++i
)
651 if (time
>= range
->ranges
[i
].start
&& time
<= range
->ranges
[i
].end
)
658 static HRESULT WINAPI
time_range_AddRange(IMFMediaTimeRange
*iface
, double start
, double end
)
660 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
664 TRACE("%p, %.8e, %.8e.\n", iface
, start
, end
);
666 for (i
= 0; i
< range
->count
; ++i
)
668 c
= &range
->ranges
[i
];
670 /* New range is fully contained within existing one. */
671 if (c
->start
<= start
&& c
->end
>= end
)
674 /* New range fully contains existing one. */
675 if (c
->start
>= start
&& c
->end
<= end
)
682 /* Merge if ranges intersect. */
683 if ((start
>= c
->start
&& start
<= c
->end
) ||
684 (end
>= c
->start
&& end
<= c
->end
))
686 c
->start
= min(c
->start
, start
);
687 c
->end
= max(c
->end
, end
);
692 if (!mf_array_reserve((void **)&range
->ranges
, &range
->capacity
, range
->count
+ 1, sizeof(*range
->ranges
)))
693 return E_OUTOFMEMORY
;
695 range
->ranges
[range
->count
].start
= start
;
696 range
->ranges
[range
->count
].end
= end
;
702 static HRESULT WINAPI
time_range_Clear(IMFMediaTimeRange
*iface
)
704 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
706 TRACE("%p.\n", iface
);
713 static const IMFMediaTimeRangeVtbl time_range_vtbl
=
715 time_range_QueryInterface
,
718 time_range_GetLength
,
721 time_range_ContainsTime
,
726 static HRESULT
create_time_range(IMFMediaTimeRange
**range
)
728 struct time_range
*object
;
730 object
= calloc(1, sizeof(*object
));
732 return E_OUTOFMEMORY
;
734 object
->IMFMediaTimeRange_iface
.lpVtbl
= &time_range_vtbl
;
735 object
->refcount
= 1;
737 *range
= &object
->IMFMediaTimeRange_iface
;
742 static void media_engine_set_flag(struct media_engine
*engine
, unsigned int mask
, BOOL value
)
745 engine
->flags
|= mask
;
747 engine
->flags
&= ~mask
;
750 static inline struct media_engine
*impl_from_IMFMediaEngineEx(IMFMediaEngineEx
*iface
)
752 return CONTAINING_RECORD(iface
, struct media_engine
, IMFMediaEngineEx_iface
);
755 static inline struct media_engine
*impl_from_IMFGetService(IMFGetService
*iface
)
757 return CONTAINING_RECORD(iface
, struct media_engine
, IMFGetService_iface
);
760 static struct media_engine
*impl_from_session_events_IMFAsyncCallback(IMFAsyncCallback
*iface
)
762 return CONTAINING_RECORD(iface
, struct media_engine
, session_events
);
765 static struct media_engine
*impl_from_load_handler_IMFAsyncCallback(IMFAsyncCallback
*iface
)
767 return CONTAINING_RECORD(iface
, struct media_engine
, load_handler
);
770 static struct media_engine
*impl_from_IMFSampleGrabberSinkCallback(IMFSampleGrabberSinkCallback
*iface
)
772 return CONTAINING_RECORD(iface
, struct media_engine
, grabber_callback
);
775 static unsigned int get_gcd(unsigned int a
, unsigned int b
)
789 static void media_engine_get_frame_size(struct media_engine
*engine
, IMFTopology
*topology
)
791 IMFMediaTypeHandler
*handler
;
792 IMFMediaType
*media_type
;
793 IMFStreamDescriptor
*sd
;
794 IMFTopologyNode
*node
;
799 engine
->video_frame
.size
.cx
= 0;
800 engine
->video_frame
.size
.cy
= 0;
801 engine
->video_frame
.ratio
.cx
= 1;
802 engine
->video_frame
.ratio
.cy
= 1;
804 if (FAILED(IMFTopology_GetNodeByID(topology
, engine
->video_frame
.node_id
, &node
)))
807 hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_STREAM_DESCRIPTOR
,
808 &IID_IMFStreamDescriptor
, (void **)&sd
);
809 IMFTopologyNode_Release(node
);
813 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
814 IMFStreamDescriptor_Release(sd
);
818 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, &media_type
);
819 IMFMediaTypeHandler_Release(handler
);
822 WARN("Failed to get current media type %#lx.\n", hr
);
826 IMFMediaType_GetUINT64(media_type
, &MF_MT_FRAME_SIZE
, &size
);
828 engine
->video_frame
.size
.cx
= size
>> 32;
829 engine
->video_frame
.size
.cy
= size
;
831 if ((gcd
= get_gcd(engine
->video_frame
.size
.cx
, engine
->video_frame
.size
.cy
)))
833 engine
->video_frame
.ratio
.cx
= engine
->video_frame
.size
.cx
/ gcd
;
834 engine
->video_frame
.ratio
.cy
= engine
->video_frame
.size
.cy
/ gcd
;
837 IMFMediaType_Release(media_type
);
840 static HRESULT WINAPI
media_engine_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
842 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
843 IsEqualIID(riid
, &IID_IUnknown
))
846 IMFAsyncCallback_AddRef(iface
);
850 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
852 return E_NOINTERFACE
;
855 static ULONG WINAPI
media_engine_session_events_AddRef(IMFAsyncCallback
*iface
)
857 struct media_engine
*engine
= impl_from_session_events_IMFAsyncCallback(iface
);
858 return IMFMediaEngineEx_AddRef(&engine
->IMFMediaEngineEx_iface
);
861 static ULONG WINAPI
media_engine_session_events_Release(IMFAsyncCallback
*iface
)
863 struct media_engine
*engine
= impl_from_session_events_IMFAsyncCallback(iface
);
864 return IMFMediaEngineEx_Release(&engine
->IMFMediaEngineEx_iface
);
867 static HRESULT WINAPI
media_engine_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
872 static HRESULT WINAPI
media_engine_session_events_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
874 struct media_engine
*engine
= impl_from_session_events_IMFAsyncCallback(iface
);
875 IMFMediaEvent
*event
= NULL
;
876 MediaEventType event_type
;
879 if (FAILED(hr
= IMFMediaSession_EndGetEvent(engine
->session
, result
, &event
)))
881 WARN("Failed to get session event, hr %#lx.\n", hr
);
885 if (FAILED(hr
= IMFMediaEvent_GetType(event
, &event_type
)))
887 WARN("Failed to get event type, hr %#lx.\n", hr
);
893 case MEBufferingStarted
:
894 case MEBufferingStopped
:
896 IMFMediaEngineNotify_EventNotify(engine
->callback
, event_type
== MEBufferingStarted
?
897 MF_MEDIA_ENGINE_EVENT_BUFFERINGSTARTED
: MF_MEDIA_ENGINE_EVENT_BUFFERINGENDED
, 0, 0);
899 case MESessionTopologyStatus
:
901 UINT32 topo_status
= 0;
902 IMFTopology
*topology
;
905 IMFMediaEvent_GetUINT32(event
, &MF_EVENT_TOPOLOGY_STATUS
, &topo_status
);
906 if (topo_status
!= MF_TOPOSTATUS_READY
)
910 if (FAILED(IMFMediaEvent_GetValue(event
, &value
)))
913 if (value
.vt
!= VT_UNKNOWN
)
915 PropVariantClear(&value
);
919 topology
= (IMFTopology
*)value
.punkVal
;
921 EnterCriticalSection(&engine
->cs
);
923 engine
->ready_state
= MF_MEDIA_ENGINE_READY_HAVE_METADATA
;
925 media_engine_get_frame_size(engine
, topology
);
927 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE
, 0, 0);
928 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA
, 0, 0);
930 engine
->ready_state
= MF_MEDIA_ENGINE_READY_HAVE_ENOUGH_DATA
;
932 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_LOADEDDATA
, 0, 0);
933 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_CANPLAY
, 0, 0);
935 LeaveCriticalSection(&engine
->cs
);
937 PropVariantClear(&value
);
941 case MESessionStarted
:
943 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PLAYING
, 0, 0);
947 EnterCriticalSection(&engine
->cs
);
948 media_engine_set_flag(engine
, FLAGS_ENGINE_FIRST_FRAME
, FALSE
);
949 media_engine_set_flag(engine
, FLAGS_ENGINE_IS_ENDED
, TRUE
);
950 engine
->video_frame
.pts
= MINLONGLONG
;
951 LeaveCriticalSection(&engine
->cs
);
953 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_ENDED
, 0, 0);
960 IMFMediaEvent_Release(event
);
962 if (FAILED(hr
= IMFMediaSession_BeginGetEvent(engine
->session
, iface
, NULL
)))
963 WARN("Failed to subscribe to session events, hr %#lx.\n", hr
);
968 static const IMFAsyncCallbackVtbl media_engine_session_events_vtbl
=
970 media_engine_callback_QueryInterface
,
971 media_engine_session_events_AddRef
,
972 media_engine_session_events_Release
,
973 media_engine_callback_GetParameters
,
974 media_engine_session_events_Invoke
,
977 static ULONG WINAPI
media_engine_load_handler_AddRef(IMFAsyncCallback
*iface
)
979 struct media_engine
*engine
= impl_from_load_handler_IMFAsyncCallback(iface
);
980 return IMFMediaEngineEx_AddRef(&engine
->IMFMediaEngineEx_iface
);
983 static ULONG WINAPI
media_engine_load_handler_Release(IMFAsyncCallback
*iface
)
985 struct media_engine
*engine
= impl_from_load_handler_IMFAsyncCallback(iface
);
986 return IMFMediaEngineEx_Release(&engine
->IMFMediaEngineEx_iface
);
989 static HRESULT
media_engine_create_source_node(IMFMediaSource
*source
, IMFPresentationDescriptor
*pd
, IMFStreamDescriptor
*sd
,
990 IMFTopologyNode
**node
)
994 if (FAILED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE
, node
)))
997 IMFTopologyNode_SetUnknown(*node
, &MF_TOPONODE_SOURCE
, (IUnknown
*)source
);
998 IMFTopologyNode_SetUnknown(*node
, &MF_TOPONODE_PRESENTATION_DESCRIPTOR
, (IUnknown
*)pd
);
999 IMFTopologyNode_SetUnknown(*node
, &MF_TOPONODE_STREAM_DESCRIPTOR
, (IUnknown
*)sd
);
1004 static HRESULT
media_engine_create_audio_renderer(struct media_engine
*engine
, IMFTopologyNode
**node
)
1006 unsigned int category
, role
;
1007 IMFActivate
*sar_activate
;
1012 if (FAILED(hr
= MFCreateAudioRendererActivate(&sar_activate
)))
1015 /* Configuration attributes keys differ between Engine and SAR. */
1016 if (SUCCEEDED(IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_CATEGORY
, &category
)))
1017 IMFActivate_SetUINT32(sar_activate
, &MF_AUDIO_RENDERER_ATTRIBUTE_STREAM_CATEGORY
, category
);
1018 if (SUCCEEDED(IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE
, &role
)))
1019 IMFActivate_SetUINT32(sar_activate
, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE
, role
);
1021 if (SUCCEEDED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE
, node
)))
1023 IMFTopologyNode_SetObject(*node
, (IUnknown
*)sar_activate
);
1024 IMFTopologyNode_SetUINT32(*node
, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE
, FALSE
);
1027 IMFActivate_Release(sar_activate
);
1032 static HRESULT
media_engine_create_video_renderer(struct media_engine
*engine
, IMFTopologyNode
**node
)
1034 DXGI_FORMAT output_format
;
1035 IMFMediaType
*media_type
;
1036 IMFActivate
*activate
;
1042 if (FAILED(IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT
, &output_format
)))
1044 WARN("Output format was not specified.\n");
1048 memcpy(&subtype
, &MFVideoFormat_Base
, sizeof(subtype
));
1049 if (!(subtype
.Data1
= MFMapDXGIFormatToDX9Format(output_format
)))
1051 WARN("Unrecognized output format %#x.\n", output_format
);
1055 if (FAILED(hr
= MFCreateMediaType(&media_type
)))
1058 IMFMediaType_SetGUID(media_type
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Video
);
1059 IMFMediaType_SetGUID(media_type
, &MF_MT_SUBTYPE
, &subtype
);
1061 hr
= MFCreateSampleGrabberSinkActivate(media_type
, &engine
->grabber_callback
, &activate
);
1062 IMFMediaType_Release(media_type
);
1066 if (SUCCEEDED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE
, node
)))
1068 IMFTopologyNode_SetObject(*node
, (IUnknown
*)activate
);
1069 IMFTopologyNode_SetUINT32(*node
, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE
, FALSE
);
1072 IMFActivate_Release(activate
);
1074 engine
->video_frame
.output_format
= output_format
;
1079 static void media_engine_clear_presentation(struct media_engine
*engine
)
1081 if (engine
->presentation
.source
)
1083 IMFMediaSource_Shutdown(engine
->presentation
.source
);
1084 IMFMediaSource_Release(engine
->presentation
.source
);
1086 if (engine
->presentation
.pd
)
1087 IMFPresentationDescriptor_Release(engine
->presentation
.pd
);
1088 memset(&engine
->presentation
, 0, sizeof(engine
->presentation
));
1091 static HRESULT
media_engine_create_topology(struct media_engine
*engine
, IMFMediaSource
*source
)
1093 IMFStreamDescriptor
*sd_audio
= NULL
, *sd_video
= NULL
;
1094 IMFPresentationDescriptor
*pd
;
1095 DWORD stream_count
= 0, i
;
1096 IMFTopology
*topology
;
1100 media_engine_release_video_frame_resources(engine
);
1101 media_engine_clear_presentation(engine
);
1103 if (FAILED(hr
= IMFMediaSource_CreatePresentationDescriptor(source
, &pd
)))
1106 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(pd
, &stream_count
)))
1107 WARN("Failed to get stream count, hr %#lx.\n", hr
);
1109 /* Enable first video stream and first audio stream. */
1111 for (i
= 0; i
< stream_count
; ++i
)
1113 IMFMediaTypeHandler
*type_handler
;
1114 IMFStreamDescriptor
*sd
;
1117 IMFPresentationDescriptor_DeselectStream(pd
, i
);
1119 if (sd_audio
&& sd_video
)
1122 IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd
, i
, &selected
, &sd
);
1124 if (SUCCEEDED(IMFStreamDescriptor_GetMediaTypeHandler(sd
, &type_handler
)))
1128 IMFMediaTypeHandler_GetMajorType(type_handler
, &major
);
1130 if (IsEqualGUID(&major
, &MFMediaType_Audio
) && !sd_audio
)
1133 IMFStreamDescriptor_AddRef(sd_audio
);
1134 IMFPresentationDescriptor_SelectStream(pd
, i
);
1136 else if (IsEqualGUID(&major
, &MFMediaType_Video
) && !sd_video
&& !(engine
->flags
& MF_MEDIA_ENGINE_AUDIOONLY
))
1139 IMFStreamDescriptor_AddRef(sd_video
);
1140 IMFPresentationDescriptor_SelectStream(pd
, i
);
1143 IMFMediaTypeHandler_Release(type_handler
);
1146 IMFStreamDescriptor_Release(sd
);
1149 if (!sd_video
&& !sd_audio
)
1151 IMFPresentationDescriptor_Release(pd
);
1152 return E_UNEXPECTED
;
1155 engine
->presentation
.source
= source
;
1156 IMFMediaSource_AddRef(engine
->presentation
.source
);
1157 engine
->presentation
.pd
= pd
;
1158 IMFPresentationDescriptor_AddRef(engine
->presentation
.pd
);
1160 media_engine_set_flag(engine
, FLAGS_ENGINE_HAS_VIDEO
, !!sd_video
);
1161 media_engine_set_flag(engine
, FLAGS_ENGINE_HAS_AUDIO
, !!sd_audio
);
1163 /* Assume live source if duration was not provided. */
1164 if (SUCCEEDED(IMFPresentationDescriptor_GetUINT64(pd
, &MF_PD_DURATION
, &duration
)))
1166 /* Convert 100ns to seconds. */
1167 engine
->duration
= duration
/ 10000000;
1170 engine
->duration
= INFINITY
;
1172 if (SUCCEEDED(hr
= MFCreateTopology(&topology
)))
1174 IMFTopologyNode
*sar_node
= NULL
, *audio_src
= NULL
;
1175 IMFTopologyNode
*grabber_node
= NULL
, *video_src
= NULL
;
1177 if (engine
->flags
& MF_MEDIA_ENGINE_REAL_TIME_MODE
)
1178 IMFTopology_SetUINT32(topology
, &MF_LOW_LATENCY
, TRUE
);
1182 if (FAILED(hr
= media_engine_create_source_node(source
, pd
, sd_audio
, &audio_src
)))
1183 WARN("Failed to create audio source node, hr %#lx.\n", hr
);
1185 if (FAILED(hr
= media_engine_create_audio_renderer(engine
, &sar_node
)))
1186 WARN("Failed to create audio renderer node, hr %#lx.\n", hr
);
1188 if (sar_node
&& audio_src
)
1190 IMFTopology_AddNode(topology
, audio_src
);
1191 IMFTopology_AddNode(topology
, sar_node
);
1192 IMFTopologyNode_ConnectOutput(audio_src
, 0, sar_node
, 0);
1196 IMFTopologyNode_Release(sar_node
);
1198 IMFTopologyNode_Release(audio_src
);
1201 if (SUCCEEDED(hr
) && sd_video
)
1203 if (FAILED(hr
= media_engine_create_source_node(source
, pd
, sd_video
, &video_src
)))
1204 WARN("Failed to create video source node, hr %#lx.\n", hr
);
1206 if (FAILED(hr
= media_engine_create_video_renderer(engine
, &grabber_node
)))
1207 WARN("Failed to create video grabber node, hr %#lx.\n", hr
);
1209 if (grabber_node
&& video_src
)
1211 IMFTopology_AddNode(topology
, video_src
);
1212 IMFTopology_AddNode(topology
, grabber_node
);
1213 IMFTopologyNode_ConnectOutput(video_src
, 0, grabber_node
, 0);
1217 IMFTopologyNode_GetTopoNodeID(video_src
, &engine
->video_frame
.node_id
);
1220 IMFTopologyNode_Release(grabber_node
);
1222 IMFTopologyNode_Release(video_src
);
1225 IMFTopology_SetUINT32(topology
, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES
, TRUE
);
1228 hr
= IMFMediaSession_SetTopology(engine
->session
, MFSESSION_SETTOPOLOGY_IMMEDIATE
, topology
);
1232 IMFTopology_Release(topology
);
1235 IMFStreamDescriptor_Release(sd_video
);
1237 IMFStreamDescriptor_Release(sd_audio
);
1239 IMFPresentationDescriptor_Release(pd
);
1244 static void media_engine_start_playback(struct media_engine
*engine
)
1249 IMFMediaSession_Start(engine
->session
, &GUID_NULL
, &var
);
1252 static HRESULT WINAPI
media_engine_load_handler_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1254 struct media_engine
*engine
= impl_from_load_handler_IMFAsyncCallback(iface
);
1255 IUnknown
*object
= NULL
, *state
;
1256 unsigned int start_playback
;
1257 MF_OBJECT_TYPE obj_type
;
1258 IMFMediaSource
*source
;
1261 EnterCriticalSection(&engine
->cs
);
1263 engine
->network_state
= MF_MEDIA_ENGINE_NETWORK_LOADING
;
1264 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_LOADSTART
, 0, 0);
1266 start_playback
= engine
->flags
& FLAGS_ENGINE_PLAY_PENDING
;
1267 media_engine_set_flag(engine
, FLAGS_ENGINE_SOURCE_PENDING
| FLAGS_ENGINE_PLAY_PENDING
, FALSE
);
1269 if (SUCCEEDED(IMFAsyncResult_GetState(result
, &state
)))
1271 hr
= IMFSourceResolver_EndCreateObjectFromByteStream(engine
->resolver
, result
, &obj_type
, &object
);
1272 IUnknown_Release(state
);
1275 hr
= IMFSourceResolver_EndCreateObjectFromURL(engine
->resolver
, result
, &obj_type
, &object
);
1278 WARN("Failed to create source object, hr %#lx.\n", hr
);
1282 if (SUCCEEDED(hr
= IUnknown_QueryInterface(object
, &IID_IMFMediaSource
, (void **)&source
)))
1284 hr
= media_engine_create_topology(engine
, source
);
1285 IMFMediaSource_Release(source
);
1287 IUnknown_Release(object
);
1292 engine
->network_state
= MF_MEDIA_ENGINE_NETWORK_IDLE
;
1294 media_engine_start_playback(engine
);
1298 engine
->network_state
= MF_MEDIA_ENGINE_NETWORK_NO_SOURCE
;
1299 engine
->error_code
= MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED
;
1300 engine
->extended_code
= hr
;
1301 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_ERROR
, engine
->error_code
,
1302 engine
->extended_code
);
1305 LeaveCriticalSection(&engine
->cs
);
1310 static const IMFAsyncCallbackVtbl media_engine_load_handler_vtbl
=
1312 media_engine_callback_QueryInterface
,
1313 media_engine_load_handler_AddRef
,
1314 media_engine_load_handler_Release
,
1315 media_engine_callback_GetParameters
,
1316 media_engine_load_handler_Invoke
,
1319 static HRESULT WINAPI
media_engine_QueryInterface(IMFMediaEngineEx
*iface
, REFIID riid
, void **obj
)
1321 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1323 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1325 if (IsEqualIID(riid
, &IID_IMFMediaEngineEx
) ||
1326 IsEqualIID(riid
, &IID_IMFMediaEngine
) ||
1327 IsEqualIID(riid
, &IID_IUnknown
))
1331 else if (IsEqualIID(riid
, &IID_IMFGetService
))
1333 *obj
= &engine
->IMFGetService_iface
;
1337 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
1339 return E_NOINTERFACE
;
1342 IUnknown_AddRef((IUnknown
*)*obj
);
1346 static ULONG WINAPI
media_engine_AddRef(IMFMediaEngineEx
*iface
)
1348 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1349 ULONG refcount
= InterlockedIncrement(&engine
->refcount
);
1351 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1356 static void free_media_engine(struct media_engine
*engine
)
1358 if (engine
->callback
)
1359 IMFMediaEngineNotify_Release(engine
->callback
);
1361 IMFPresentationClock_Release(engine
->clock
);
1362 if (engine
->session
)
1363 IMFMediaSession_Release(engine
->session
);
1364 if (engine
->attributes
)
1365 IMFAttributes_Release(engine
->attributes
);
1366 if (engine
->resolver
)
1367 IMFSourceResolver_Release(engine
->resolver
);
1368 media_engine_release_video_frame_resources(engine
);
1369 media_engine_clear_presentation(engine
);
1370 if (engine
->device_manager
)
1372 IMFDXGIDeviceManager_CloseDeviceHandle(engine
->device_manager
, engine
->device_handle
);
1373 IMFDXGIDeviceManager_Release(engine
->device_manager
);
1375 SysFreeString(engine
->current_source
);
1376 DeleteCriticalSection(&engine
->cs
);
1377 free(engine
->video_frame
.buffer
);
1381 static ULONG WINAPI
media_engine_Release(IMFMediaEngineEx
*iface
)
1383 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1384 ULONG refcount
= InterlockedDecrement(&engine
->refcount
);
1386 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1389 free_media_engine(engine
);
1394 static HRESULT WINAPI
media_engine_GetError(IMFMediaEngineEx
*iface
, IMFMediaError
**error
)
1396 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1399 TRACE("%p, %p.\n", iface
, error
);
1403 EnterCriticalSection(&engine
->cs
);
1404 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1406 else if (engine
->error_code
)
1408 if (SUCCEEDED(hr
= create_media_error(error
)))
1410 IMFMediaError_SetErrorCode(*error
, engine
->error_code
);
1411 IMFMediaError_SetExtendedErrorCode(*error
, engine
->extended_code
);
1414 LeaveCriticalSection(&engine
->cs
);
1419 static HRESULT WINAPI
media_engine_SetErrorCode(IMFMediaEngineEx
*iface
, MF_MEDIA_ENGINE_ERR code
)
1421 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1424 TRACE("%p, %u.\n", iface
, code
);
1426 if ((unsigned int)code
> MF_MEDIA_ENGINE_ERR_ENCRYPTED
)
1427 return E_INVALIDARG
;
1429 EnterCriticalSection(&engine
->cs
);
1430 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1433 engine
->error_code
= code
;
1434 LeaveCriticalSection(&engine
->cs
);
1439 static HRESULT WINAPI
media_engine_SetSourceElements(IMFMediaEngineEx
*iface
, IMFMediaEngineSrcElements
*elements
)
1441 FIXME("(%p, %p): stub.\n", iface
, elements
);
1446 static HRESULT
media_engine_set_source(struct media_engine
*engine
, IMFByteStream
*bytestream
, BSTR url
)
1448 IPropertyStore
*props
= NULL
;
1452 SysFreeString(engine
->current_source
);
1453 engine
->current_source
= NULL
;
1455 engine
->current_source
= SysAllocString(url
);
1457 engine
->ready_state
= MF_MEDIA_ENGINE_READY_HAVE_NOTHING
;
1459 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS
, 0, 0);
1461 engine
->network_state
= MF_MEDIA_ENGINE_NETWORK_NO_SOURCE
;
1463 if (url
|| bytestream
)
1465 flags
= MF_RESOLUTION_MEDIASOURCE
| MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE
;
1466 if (engine
->flags
& MF_MEDIA_ENGINE_DISABLE_LOCAL_PLUGINS
)
1467 flags
|= MF_RESOLUTION_DISABLE_LOCAL_PLUGINS
;
1469 IMFAttributes_GetUnknown(engine
->attributes
, &MF_MEDIA_ENGINE_SOURCE_RESOLVER_CONFIG_STORE
,
1470 &IID_IPropertyStore
, (void **)&props
);
1472 hr
= IMFSourceResolver_BeginCreateObjectFromByteStream(engine
->resolver
, bytestream
, url
, flags
,
1473 props
, NULL
, &engine
->load_handler
, (IUnknown
*)bytestream
);
1475 hr
= IMFSourceResolver_BeginCreateObjectFromURL(engine
->resolver
, url
, flags
, props
, NULL
,
1476 &engine
->load_handler
, NULL
);
1478 media_engine_set_flag(engine
, FLAGS_ENGINE_SOURCE_PENDING
, TRUE
);
1481 IPropertyStore_Release(props
);
1487 static HRESULT WINAPI
media_engine_SetSource(IMFMediaEngineEx
*iface
, BSTR url
)
1489 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1492 TRACE("%p, %s.\n", iface
, debugstr_w(url
));
1494 EnterCriticalSection(&engine
->cs
);
1496 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1499 hr
= media_engine_set_source(engine
, NULL
, url
);
1501 LeaveCriticalSection(&engine
->cs
);
1506 static HRESULT WINAPI
media_engine_GetCurrentSource(IMFMediaEngineEx
*iface
, BSTR
*url
)
1508 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1511 TRACE("%p, %p.\n", iface
, url
);
1515 EnterCriticalSection(&engine
->cs
);
1517 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1519 if (engine
->current_source
)
1521 if (!(*url
= SysAllocString(engine
->current_source
)))
1525 LeaveCriticalSection(&engine
->cs
);
1530 static USHORT WINAPI
media_engine_GetNetworkState(IMFMediaEngineEx
*iface
)
1532 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1534 TRACE("%p.\n", iface
);
1536 return engine
->network_state
;
1539 static MF_MEDIA_ENGINE_PRELOAD WINAPI
media_engine_GetPreload(IMFMediaEngineEx
*iface
)
1541 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1542 MF_MEDIA_ENGINE_PRELOAD preload
;
1544 TRACE("%p.\n", iface
);
1546 EnterCriticalSection(&engine
->cs
);
1547 preload
= engine
->preload
;
1548 LeaveCriticalSection(&engine
->cs
);
1553 static HRESULT WINAPI
media_engine_SetPreload(IMFMediaEngineEx
*iface
, MF_MEDIA_ENGINE_PRELOAD preload
)
1555 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1557 TRACE("%p, %d.\n", iface
, preload
);
1559 EnterCriticalSection(&engine
->cs
);
1560 engine
->preload
= preload
;
1561 LeaveCriticalSection(&engine
->cs
);
1566 static HRESULT WINAPI
media_engine_GetBuffered(IMFMediaEngineEx
*iface
, IMFMediaTimeRange
**range
)
1568 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1571 TRACE("%p, %p.\n", iface
, range
);
1573 if (FAILED(hr
= create_time_range(range
)))
1576 EnterCriticalSection(&engine
->cs
);
1578 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1580 else if (!isnan(engine
->duration
))
1581 hr
= IMFMediaTimeRange_AddRange(*range
, 0.0, engine
->duration
);
1583 LeaveCriticalSection(&engine
->cs
);
1588 static HRESULT WINAPI
media_engine_Load(IMFMediaEngineEx
*iface
)
1590 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1591 HRESULT hr
= E_NOTIMPL
;
1593 FIXME("(%p): stub.\n", iface
);
1595 EnterCriticalSection(&engine
->cs
);
1597 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1600 LeaveCriticalSection(&engine
->cs
);
1605 static HRESULT WINAPI
media_engine_CanPlayType(IMFMediaEngineEx
*iface
, BSTR type
, MF_MEDIA_ENGINE_CANPLAY
*answer
)
1607 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1608 HRESULT hr
= E_NOTIMPL
;
1610 FIXME("(%p, %s, %p): stub.\n", iface
, debugstr_w(type
), answer
);
1612 EnterCriticalSection(&engine
->cs
);
1614 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1617 LeaveCriticalSection(&engine
->cs
);
1622 static USHORT WINAPI
media_engine_GetReadyState(IMFMediaEngineEx
*iface
)
1624 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1625 unsigned short state
;
1627 TRACE("%p.\n", iface
);
1629 EnterCriticalSection(&engine
->cs
);
1630 state
= engine
->ready_state
;
1631 LeaveCriticalSection(&engine
->cs
);
1636 static BOOL WINAPI
media_engine_IsSeeking(IMFMediaEngineEx
*iface
)
1638 FIXME("(%p): stub.\n", iface
);
1643 static double WINAPI
media_engine_GetCurrentTime(IMFMediaEngineEx
*iface
)
1645 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1649 TRACE("%p.\n", iface
);
1651 EnterCriticalSection(&engine
->cs
);
1652 if (engine
->flags
& FLAGS_ENGINE_IS_ENDED
)
1654 ret
= engine
->duration
;
1656 else if (SUCCEEDED(IMFPresentationClock_GetTime(engine
->clock
, &clocktime
)))
1658 ret
= (double)clocktime
/ 10000000.0;
1660 LeaveCriticalSection(&engine
->cs
);
1665 static HRESULT WINAPI
media_engine_SetCurrentTime(IMFMediaEngineEx
*iface
, double time
)
1667 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1668 HRESULT hr
= E_NOTIMPL
;
1670 FIXME("(%p, %f): stub.\n", iface
, time
);
1672 EnterCriticalSection(&engine
->cs
);
1674 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1677 LeaveCriticalSection(&engine
->cs
);
1682 static double WINAPI
media_engine_GetStartTime(IMFMediaEngineEx
*iface
)
1684 FIXME("(%p): stub.\n", iface
);
1689 static double WINAPI
media_engine_GetDuration(IMFMediaEngineEx
*iface
)
1691 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1694 TRACE("%p.\n", iface
);
1696 EnterCriticalSection(&engine
->cs
);
1697 value
= engine
->duration
;
1698 LeaveCriticalSection(&engine
->cs
);
1703 static BOOL WINAPI
media_engine_IsPaused(IMFMediaEngineEx
*iface
)
1705 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1708 TRACE("%p.\n", iface
);
1710 EnterCriticalSection(&engine
->cs
);
1711 value
= !!(engine
->flags
& FLAGS_ENGINE_PAUSED
);
1712 LeaveCriticalSection(&engine
->cs
);
1717 static double WINAPI
media_engine_GetDefaultPlaybackRate(IMFMediaEngineEx
*iface
)
1719 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1722 TRACE("%p.\n", iface
);
1724 EnterCriticalSection(&engine
->cs
);
1725 rate
= engine
->default_playback_rate
;
1726 LeaveCriticalSection(&engine
->cs
);
1731 static HRESULT WINAPI
media_engine_SetDefaultPlaybackRate(IMFMediaEngineEx
*iface
, double rate
)
1733 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1736 TRACE("%p, %f.\n", iface
, rate
);
1738 EnterCriticalSection(&engine
->cs
);
1739 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1741 else if (engine
->default_playback_rate
!= rate
)
1743 engine
->default_playback_rate
= rate
;
1744 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_RATECHANGE
, 0, 0);
1746 LeaveCriticalSection(&engine
->cs
);
1751 static double WINAPI
media_engine_GetPlaybackRate(IMFMediaEngineEx
*iface
)
1753 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1756 TRACE("%p.\n", iface
);
1758 EnterCriticalSection(&engine
->cs
);
1759 rate
= engine
->playback_rate
;
1760 LeaveCriticalSection(&engine
->cs
);
1765 static HRESULT WINAPI
media_engine_SetPlaybackRate(IMFMediaEngineEx
*iface
, double rate
)
1767 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1770 TRACE("%p, %f.\n", iface
, rate
);
1772 EnterCriticalSection(&engine
->cs
);
1773 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1775 else if (engine
->playback_rate
!= rate
)
1777 engine
->playback_rate
= rate
;
1778 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_RATECHANGE
, 0, 0);
1780 LeaveCriticalSection(&engine
->cs
);
1785 static HRESULT WINAPI
media_engine_GetPlayed(IMFMediaEngineEx
*iface
, IMFMediaTimeRange
**played
)
1787 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1788 HRESULT hr
= E_NOTIMPL
;
1790 FIXME("(%p, %p): stub.\n", iface
, played
);
1792 EnterCriticalSection(&engine
->cs
);
1794 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1797 LeaveCriticalSection(&engine
->cs
);
1802 static HRESULT WINAPI
media_engine_GetSeekable(IMFMediaEngineEx
*iface
, IMFMediaTimeRange
**seekable
)
1804 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1805 HRESULT hr
= E_NOTIMPL
;
1807 FIXME("(%p, %p): stub.\n", iface
, seekable
);
1809 EnterCriticalSection(&engine
->cs
);
1811 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1814 LeaveCriticalSection(&engine
->cs
);
1819 static BOOL WINAPI
media_engine_IsEnded(IMFMediaEngineEx
*iface
)
1821 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1824 TRACE("%p.\n", iface
);
1826 EnterCriticalSection(&engine
->cs
);
1827 value
= !!(engine
->flags
& FLAGS_ENGINE_IS_ENDED
);
1828 LeaveCriticalSection(&engine
->cs
);
1833 static BOOL WINAPI
media_engine_GetAutoPlay(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_AUTO_PLAY
);
1842 LeaveCriticalSection(&engine
->cs
);
1847 static HRESULT WINAPI
media_engine_SetAutoPlay(IMFMediaEngineEx
*iface
, BOOL autoplay
)
1849 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1851 FIXME("(%p, %d): stub.\n", iface
, autoplay
);
1853 EnterCriticalSection(&engine
->cs
);
1854 media_engine_set_flag(engine
, FLAGS_ENGINE_AUTO_PLAY
, autoplay
);
1855 LeaveCriticalSection(&engine
->cs
);
1860 static BOOL WINAPI
media_engine_GetLoop(IMFMediaEngineEx
*iface
)
1862 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1865 TRACE("%p.\n", iface
);
1867 EnterCriticalSection(&engine
->cs
);
1868 value
= !!(engine
->flags
& FLAGS_ENGINE_LOOP
);
1869 LeaveCriticalSection(&engine
->cs
);
1874 static HRESULT WINAPI
media_engine_SetLoop(IMFMediaEngineEx
*iface
, BOOL loop
)
1876 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1878 FIXME("(%p, %d): stub.\n", iface
, loop
);
1880 EnterCriticalSection(&engine
->cs
);
1881 media_engine_set_flag(engine
, FLAGS_ENGINE_LOOP
, loop
);
1882 LeaveCriticalSection(&engine
->cs
);
1887 static HRESULT WINAPI
media_engine_Play(IMFMediaEngineEx
*iface
)
1889 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1892 TRACE("%p.\n", iface
);
1894 EnterCriticalSection(&engine
->cs
);
1896 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1900 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS
, 0, 0);
1902 if (!(engine
->flags
& FLAGS_ENGINE_WAITING
))
1904 media_engine_set_flag(engine
, FLAGS_ENGINE_PAUSED
| FLAGS_ENGINE_IS_ENDED
, FALSE
);
1905 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PLAY
, 0, 0);
1907 if (!(engine
->flags
& FLAGS_ENGINE_SOURCE_PENDING
))
1908 media_engine_start_playback(engine
);
1910 media_engine_set_flag(engine
, FLAGS_ENGINE_PLAY_PENDING
, TRUE
);
1912 media_engine_set_flag(engine
, FLAGS_ENGINE_WAITING
, TRUE
);
1915 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_WAITING
, 0, 0);
1918 LeaveCriticalSection(&engine
->cs
);
1923 static HRESULT WINAPI
media_engine_Pause(IMFMediaEngineEx
*iface
)
1925 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1928 TRACE("%p.\n", iface
);
1930 EnterCriticalSection(&engine
->cs
);
1932 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1936 if (!(engine
->flags
& FLAGS_ENGINE_PAUSED
))
1938 media_engine_set_flag(engine
, FLAGS_ENGINE_WAITING
| FLAGS_ENGINE_IS_ENDED
, FALSE
);
1939 media_engine_set_flag(engine
, FLAGS_ENGINE_PAUSED
, TRUE
);
1941 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_TIMEUPDATE
, 0, 0);
1942 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PAUSE
, 0, 0);
1945 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS
, 0, 0);
1948 LeaveCriticalSection(&engine
->cs
);
1953 static BOOL WINAPI
media_engine_GetMuted(IMFMediaEngineEx
*iface
)
1955 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1958 TRACE("%p.\n", iface
);
1960 EnterCriticalSection(&engine
->cs
);
1961 ret
= !!(engine
->flags
& FLAGS_ENGINE_MUTED
);
1962 LeaveCriticalSection(&engine
->cs
);
1967 static HRESULT WINAPI
media_engine_SetMuted(IMFMediaEngineEx
*iface
, BOOL muted
)
1969 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1972 TRACE("%p, %d.\n", iface
, muted
);
1974 EnterCriticalSection(&engine
->cs
);
1975 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1977 else if (!!(engine
->flags
& FLAGS_ENGINE_MUTED
) ^ !!muted
)
1979 media_engine_set_flag(engine
, FLAGS_ENGINE_MUTED
, muted
);
1980 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE
, 0, 0);
1982 LeaveCriticalSection(&engine
->cs
);
1987 static double WINAPI
media_engine_GetVolume(IMFMediaEngineEx
*iface
)
1989 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
1992 TRACE("%p.\n", iface
);
1994 EnterCriticalSection(&engine
->cs
);
1995 volume
= engine
->volume
;
1996 LeaveCriticalSection(&engine
->cs
);
2001 static HRESULT WINAPI
media_engine_SetVolume(IMFMediaEngineEx
*iface
, double volume
)
2003 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2006 TRACE("%p, %f.\n", iface
, volume
);
2008 EnterCriticalSection(&engine
->cs
);
2009 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2011 else if (volume
!= engine
->volume
)
2013 engine
->volume
= volume
;
2014 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE
, 0, 0);
2016 LeaveCriticalSection(&engine
->cs
);
2021 static BOOL WINAPI
media_engine_HasVideo(IMFMediaEngineEx
*iface
)
2023 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2026 TRACE("%p.\n", iface
);
2028 EnterCriticalSection(&engine
->cs
);
2029 value
= !!(engine
->flags
& FLAGS_ENGINE_HAS_VIDEO
);
2030 LeaveCriticalSection(&engine
->cs
);
2035 static BOOL WINAPI
media_engine_HasAudio(IMFMediaEngineEx
*iface
)
2037 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2040 TRACE("%p.\n", iface
);
2042 EnterCriticalSection(&engine
->cs
);
2043 value
= !!(engine
->flags
& FLAGS_ENGINE_HAS_AUDIO
);
2044 LeaveCriticalSection(&engine
->cs
);
2049 static HRESULT WINAPI
media_engine_GetNativeVideoSize(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
.size
.cx
;
2068 if (cy
) *cy
= engine
->video_frame
.size
.cy
;
2071 LeaveCriticalSection(&engine
->cs
);
2076 static HRESULT WINAPI
media_engine_GetVideoAspectRatio(IMFMediaEngineEx
*iface
, DWORD
*cx
, DWORD
*cy
)
2078 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2081 TRACE("%p, %p, %p.\n", iface
, cx
, cy
);
2084 return E_INVALIDARG
;
2086 EnterCriticalSection(&engine
->cs
);
2088 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2090 else if (!engine
->video_frame
.size
.cx
&& !engine
->video_frame
.size
.cy
)
2094 if (cx
) *cx
= engine
->video_frame
.ratio
.cx
;
2095 if (cy
) *cy
= engine
->video_frame
.ratio
.cy
;
2098 LeaveCriticalSection(&engine
->cs
);
2103 static HRESULT WINAPI
media_engine_Shutdown(IMFMediaEngineEx
*iface
)
2105 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2108 FIXME("(%p): stub.\n", iface
);
2110 EnterCriticalSection(&engine
->cs
);
2111 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2115 media_engine_set_flag(engine
, FLAGS_ENGINE_SHUT_DOWN
, TRUE
);
2116 media_engine_clear_presentation(engine
);
2117 IMFMediaSession_Shutdown(engine
->session
);
2119 LeaveCriticalSection(&engine
->cs
);
2124 static void set_rect(struct rect
*rect
, float left
, float top
, float right
, float bottom
)
2128 rect
->right
= right
;
2129 rect
->bottom
= bottom
;
2132 static void media_engine_adjust_destination_for_ratio(const struct media_engine
*engine
,
2133 struct rect
*src_n
, struct rect
*dst
)
2135 float dst_width
= dst
->right
- dst
->left
, dst_height
= dst
->bottom
- dst
->top
;
2136 D3D11_TEXTURE2D_DESC source_desc
;
2137 float src_width
, src_height
;
2140 ID3D11Texture2D_GetDesc(engine
->video_frame
.d3d11
.source
, &source_desc
);
2141 set_rect(&src
, src_n
->left
* source_desc
.Width
, src_n
->top
* source_desc
.Height
,
2142 src_n
->right
* source_desc
.Width
, src_n
->bottom
* source_desc
.Height
);
2144 src_width
= src
.right
- src
.left
;
2145 src_height
= src
.bottom
- src
.top
;
2147 if (src_width
* dst_height
> dst_width
* src_height
)
2149 /* src is "wider" than dst. */
2150 float dst_center
= (dst
->top
+ dst
->bottom
) / 2.0f
;
2151 float scaled_height
= src_height
* dst_width
/ src_width
;
2153 dst
->top
= dst_center
- scaled_height
/ 2.0f
;
2154 dst
->bottom
= dst
->top
+ scaled_height
;
2156 else if (src_width
* dst_height
< dst_width
* src_height
)
2158 /* src is "taller" than dst. */
2159 float dst_center
= (dst
->left
+ dst
->right
) / 2.0f
;
2160 float scaled_width
= src_width
* dst_height
/ src_height
;
2162 dst
->left
= dst_center
- scaled_width
/ 2.0f
;
2163 dst
->right
= dst
->left
+ scaled_width
;
2167 static void media_engine_update_d3d11_frame_surface(ID3D11DeviceContext
*context
, struct media_engine
*engine
)
2169 D3D11_TEXTURE2D_DESC surface_desc
;
2171 if (!(engine
->flags
& FLAGS_ENGINE_NEW_FRAME
))
2174 ID3D11Texture2D_GetDesc(engine
->video_frame
.d3d11
.source
, &surface_desc
);
2176 switch (surface_desc
.Format
)
2178 case DXGI_FORMAT_B8G8R8A8_UNORM
:
2179 case DXGI_FORMAT_B8G8R8X8_UNORM
:
2180 surface_desc
.Width
*= 4;
2183 FIXME("Unsupported format %#x.\n", surface_desc
.Format
);
2184 surface_desc
.Width
= 0;
2187 if (engine
->video_frame
.buffer_size
== surface_desc
.Width
* surface_desc
.Height
)
2189 ID3D11DeviceContext_UpdateSubresource(context
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.source
,
2190 0, NULL
, engine
->video_frame
.buffer
, surface_desc
.Width
, 0);
2193 media_engine_set_flag(engine
, FLAGS_ENGINE_NEW_FRAME
, FALSE
);
2196 static HRESULT
media_engine_transfer_to_d3d11_texture(struct media_engine
*engine
, ID3D11Texture2D
*texture
,
2197 const MFVideoNormalizedRect
*src_rect
, const RECT
*dst_rect
, const MFARGB
*color
)
2199 static const float black
[] = {0.0f
, 0.0f
, 0.0f
, 0.0f
};
2200 ID3D11Device
*device
, *dst_device
;
2201 ID3D11DeviceContext
*context
;
2202 ID3D11RenderTargetView
*rtv
;
2203 unsigned int stride
, offset
;
2204 D3D11_TEXTURE2D_DESC desc
;
2205 BOOL device_mismatch
;
2206 struct vec3 quad
[4];
2208 struct rect src
, dst
;
2209 struct color backcolor
;
2213 if (FAILED(hr
= media_engine_lock_d3d_device(engine
, &device
)))
2216 if (FAILED(hr
= media_engine_create_d3d11_video_frame_resources(engine
, device
)))
2218 WARN("Failed to create d3d resources, hr %#lx.\n", hr
);
2222 ID3D11Texture2D_GetDevice(texture
, &dst_device
);
2223 device_mismatch
= device
!= dst_device
;
2224 ID3D11Device_Release(dst_device
);
2226 if (device_mismatch
)
2228 WARN("Destination target from different device.\n");
2233 ID3D11Texture2D_GetDesc(texture
, &desc
);
2235 if (FAILED(hr
= ID3D11Device_CreateRenderTargetView(device
, (ID3D11Resource
*)texture
, NULL
, &rtv
)))
2237 WARN("Failed to create an rtv, hr %#lx.\n", hr
);
2241 ID3D11Device_GetImmediateContext(device
, &context
);
2243 /* Whole destination is cleared, regardless of specified rectangle. */
2244 ID3D11DeviceContext_ClearRenderTargetView(context
, rtv
, black
);
2248 rect
.left
= max(0, dst_rect
->left
);
2249 rect
.top
= max(0, dst_rect
->top
);
2250 rect
.right
= min(desc
.Width
, dst_rect
->right
);
2251 rect
.bottom
= min(desc
.Height
, dst_rect
->bottom
);
2253 quad
[0].x
= 2.0f
* rect
.left
/ desc
.Width
- 1.0f
;
2254 quad
[0].y
= -2.0f
* rect
.bottom
/ desc
.Height
+ 1.0f
;
2257 quad
[1].x
= quad
[0].x
;
2258 quad
[1].y
= -2.0f
* rect
.top
/ desc
.Height
+ 1.0f
;
2261 quad
[2].x
= 2.0f
* rect
.right
/ desc
.Width
- 1.0f
;
2262 quad
[2].y
= quad
[0].y
;
2265 quad
[3].x
= quad
[2].x
;
2266 quad
[3].y
= quad
[1].y
;
2269 set_rect(&dst
, dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
);
2273 memcpy(quad
, fullquad
, sizeof(quad
));
2274 set_rect(&dst
, 0.0f
, 0.0f
, desc
.Width
, desc
.Height
);
2278 memcpy(&src
, src_rect
, sizeof(src
));
2280 set_rect(&src
, 0.0f
, 0.0f
, 1.0f
, 1.0f
);
2282 media_engine_adjust_destination_for_ratio(engine
, &src
, &dst
);
2284 if (memcmp(quad
, engine
->video_frame
.d3d11
.quad
, sizeof(quad
)))
2286 memcpy(engine
->video_frame
.d3d11
.quad
, quad
, sizeof(quad
));
2287 ID3D11DeviceContext_UpdateSubresource(context
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.vb
, 0, NULL
, quad
, 0, 0);
2292 backcolor
.r
= color
->rgbRed
/ 255.0f
;
2293 backcolor
.g
= color
->rgbGreen
/ 255.0f
;
2294 backcolor
.b
= color
->rgbBlue
/ 255.0f
;
2295 backcolor
.a
= color
->rgbAlpha
/ 255.0f
;
2298 memcpy(&backcolor
, black
, sizeof(backcolor
));
2300 if (memcmp(&dst
, &engine
->video_frame
.d3d11
.cb
.dst
, sizeof(dst
)) ||
2301 memcmp(&src
, &engine
->video_frame
.d3d11
.cb
.src
, sizeof(src
)) ||
2302 memcmp(&backcolor
, &engine
->video_frame
.d3d11
.cb
.backcolor
, sizeof(backcolor
)))
2304 memcpy(&engine
->video_frame
.d3d11
.cb
.dst
, &dst
, sizeof(dst
));
2305 memcpy(&engine
->video_frame
.d3d11
.cb
.src
, &src
, sizeof(src
));
2306 memcpy(&engine
->video_frame
.d3d11
.cb
.backcolor
, &backcolor
, sizeof(backcolor
));
2308 ID3D11DeviceContext_UpdateSubresource(context
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.ps_cb
, 0, NULL
,
2309 &engine
->video_frame
.d3d11
.cb
, 0, 0);
2312 /* Update with new frame contents */
2313 media_engine_update_d3d11_frame_surface(context
, engine
);
2317 vp
.Width
= desc
.Width
;
2318 vp
.Height
= desc
.Height
;
2321 ID3D11DeviceContext_RSSetViewports(context
, 1, &vp
);
2323 ID3D11DeviceContext_IASetInputLayout(context
, engine
->video_frame
.d3d11
.input_layout
);
2324 ID3D11DeviceContext_IASetPrimitiveTopology(context
, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP
);
2325 stride
= sizeof(*quad
);
2327 ID3D11DeviceContext_IASetVertexBuffers(context
, 0, 1, &engine
->video_frame
.d3d11
.vb
, &stride
, &offset
);
2328 ID3D11DeviceContext_VSSetShader(context
, engine
->video_frame
.d3d11
.vs
, NULL
, 0);
2329 ID3D11DeviceContext_PSSetShader(context
, engine
->video_frame
.d3d11
.ps
, NULL
, 0);
2330 ID3D11DeviceContext_PSSetShaderResources(context
, 0, 1, &engine
->video_frame
.d3d11
.srv
);
2331 ID3D11DeviceContext_PSSetConstantBuffers(context
, 0, 1, &engine
->video_frame
.d3d11
.ps_cb
);
2332 ID3D11DeviceContext_PSSetSamplers(context
, 0, 1, &engine
->video_frame
.d3d11
.sampler
);
2333 ID3D11DeviceContext_OMSetRenderTargets(context
, 1, &rtv
, NULL
);
2335 ID3D11DeviceContext_Draw(context
, 4, 0);
2337 ID3D11RenderTargetView_Release(rtv
);
2338 ID3D11DeviceContext_Release(context
);
2341 media_engine_unlock_d3d_device(engine
, device
);
2346 static HRESULT WINAPI
media_engine_TransferVideoFrame(IMFMediaEngineEx
*iface
, IUnknown
*surface
,
2347 const MFVideoNormalizedRect
*src_rect
, const RECT
*dst_rect
, const MFARGB
*color
)
2349 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2350 ID3D11Texture2D
*texture
;
2351 HRESULT hr
= E_NOINTERFACE
;
2353 TRACE("%p, %p, %s, %s, %p.\n", iface
, surface
, src_rect
? wine_dbg_sprintf("(%f,%f)-(%f,%f)",
2354 src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
) : "(null)",
2355 wine_dbgstr_rect(dst_rect
), color
);
2357 EnterCriticalSection(&engine
->cs
);
2359 if (SUCCEEDED(IUnknown_QueryInterface(surface
, &IID_ID3D11Texture2D
, (void **)&texture
)))
2361 hr
= media_engine_transfer_to_d3d11_texture(engine
, texture
, src_rect
, dst_rect
, color
);
2362 ID3D11Texture2D_Release(texture
);
2366 FIXME("Unsupported destination type.\n");
2369 LeaveCriticalSection(&engine
->cs
);
2374 static HRESULT WINAPI
media_engine_OnVideoStreamTick(IMFMediaEngineEx
*iface
, LONGLONG
*pts
)
2376 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2379 TRACE("%p, %p.\n", iface
, pts
);
2381 EnterCriticalSection(&engine
->cs
);
2383 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2389 *pts
= engine
->video_frame
.pts
;
2390 hr
= *pts
== MINLONGLONG
? S_FALSE
: S_OK
;
2393 LeaveCriticalSection(&engine
->cs
);
2398 static HRESULT WINAPI
media_engine_SetSourceFromByteStream(IMFMediaEngineEx
*iface
, IMFByteStream
*bytestream
, BSTR url
)
2400 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2403 TRACE("%p, %p, %s.\n", iface
, bytestream
, debugstr_w(url
));
2405 EnterCriticalSection(&engine
->cs
);
2407 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2409 else if (!bytestream
|| !url
)
2412 hr
= media_engine_set_source(engine
, bytestream
, url
);
2414 LeaveCriticalSection(&engine
->cs
);
2419 static HRESULT WINAPI
media_engine_GetStatistics(IMFMediaEngineEx
*iface
, MF_MEDIA_ENGINE_STATISTIC stat_id
, PROPVARIANT
*stat
)
2421 FIXME("%p, %x, %p stub.\n", iface
, stat_id
, stat
);
2426 static HRESULT WINAPI
media_engine_UpdateVideoStream(IMFMediaEngineEx
*iface
, const MFVideoNormalizedRect
*src
,
2427 const RECT
*dst
, const MFARGB
*border_color
)
2429 FIXME("%p, %p, %p, %p stub.\n", iface
, src
, dst
, border_color
);
2434 static double WINAPI
media_engine_GetBalance(IMFMediaEngineEx
*iface
)
2436 FIXME("%p stub.\n", iface
);
2441 static HRESULT WINAPI
media_engine_SetBalance(IMFMediaEngineEx
*iface
, double balance
)
2443 FIXME("%p, %f stub.\n", iface
, balance
);
2448 static BOOL WINAPI
media_engine_IsPlaybackRateSupported(IMFMediaEngineEx
*iface
, double rate
)
2450 FIXME("%p, %f stub.\n", iface
, rate
);
2455 static HRESULT WINAPI
media_engine_FrameStep(IMFMediaEngineEx
*iface
, BOOL forward
)
2457 FIXME("%p, %d stub.\n", iface
, forward
);
2462 static HRESULT WINAPI
media_engine_GetResourceCharacteristics(IMFMediaEngineEx
*iface
, DWORD
*flags
)
2464 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2465 HRESULT hr
= E_FAIL
;
2467 TRACE("%p, %p.\n", iface
, flags
);
2469 EnterCriticalSection(&engine
->cs
);
2470 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2472 else if (engine
->presentation
.source
)
2473 hr
= IMFMediaSource_GetCharacteristics(engine
->presentation
.source
, flags
);
2474 LeaveCriticalSection(&engine
->cs
);
2479 static HRESULT WINAPI
media_engine_GetPresentationAttribute(IMFMediaEngineEx
*iface
, REFGUID attribute
,
2482 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2483 HRESULT hr
= E_FAIL
;
2485 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(attribute
), value
);
2487 EnterCriticalSection(&engine
->cs
);
2488 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2490 else if (engine
->presentation
.pd
)
2491 hr
= IMFPresentationDescriptor_GetItem(engine
->presentation
.pd
, attribute
, value
);
2492 LeaveCriticalSection(&engine
->cs
);
2497 static HRESULT WINAPI
media_engine_GetNumberOfStreams(IMFMediaEngineEx
*iface
, DWORD
*stream_count
)
2499 FIXME("%p, %p stub.\n", iface
, stream_count
);
2504 static HRESULT WINAPI
media_engine_GetStreamAttribute(IMFMediaEngineEx
*iface
, DWORD stream_index
, REFGUID attribute
,
2507 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2508 IMFStreamDescriptor
*sd
;
2509 HRESULT hr
= E_FAIL
;
2512 TRACE("%p, %ld, %s, %p.\n", iface
, stream_index
, debugstr_guid(attribute
), value
);
2514 EnterCriticalSection(&engine
->cs
);
2515 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2517 else if (engine
->presentation
.pd
)
2519 if (SUCCEEDED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(engine
->presentation
.pd
,
2520 stream_index
, &selected
, &sd
)))
2522 hr
= IMFStreamDescriptor_GetItem(sd
, attribute
, value
);
2523 IMFStreamDescriptor_Release(sd
);
2526 LeaveCriticalSection(&engine
->cs
);
2531 static HRESULT WINAPI
media_engine_GetStreamSelection(IMFMediaEngineEx
*iface
, DWORD stream_index
, BOOL
*enabled
)
2533 FIXME("%p, %ld, %p stub.\n", iface
, stream_index
, enabled
);
2538 static HRESULT WINAPI
media_engine_SetStreamSelection(IMFMediaEngineEx
*iface
, DWORD stream_index
, BOOL enabled
)
2540 FIXME("%p, %ld, %d stub.\n", iface
, stream_index
, enabled
);
2545 static HRESULT WINAPI
media_engine_ApplyStreamSelections(IMFMediaEngineEx
*iface
)
2547 FIXME("%p stub.\n", iface
);
2552 static HRESULT WINAPI
media_engine_IsProtected(IMFMediaEngineEx
*iface
, BOOL
*protected)
2554 FIXME("%p, %p stub.\n", iface
, protected);
2559 static HRESULT WINAPI
media_engine_InsertVideoEffect(IMFMediaEngineEx
*iface
, IUnknown
*effect
, BOOL is_optional
)
2561 FIXME("%p, %p, %d stub.\n", iface
, effect
, is_optional
);
2566 static HRESULT WINAPI
media_engine_InsertAudioEffect(IMFMediaEngineEx
*iface
, IUnknown
*effect
, BOOL is_optional
)
2568 FIXME("%p, %p, %d stub.\n", iface
, effect
, is_optional
);
2573 static HRESULT WINAPI
media_engine_RemoveAllEffects(IMFMediaEngineEx
*iface
)
2575 FIXME("%p stub.\n", iface
);
2580 static HRESULT WINAPI
media_engine_SetTimelineMarkerTimer(IMFMediaEngineEx
*iface
, double timeout
)
2582 FIXME("%p, %f stub.\n", iface
, timeout
);
2587 static HRESULT WINAPI
media_engine_GetTimelineMarkerTimer(IMFMediaEngineEx
*iface
, double *timeout
)
2589 FIXME("%p, %p stub.\n", iface
, timeout
);
2594 static HRESULT WINAPI
media_engine_CancelTimelineMarkerTimer(IMFMediaEngineEx
*iface
)
2596 FIXME("%p stub.\n", iface
);
2601 static BOOL WINAPI
media_engine_IsStereo3D(IMFMediaEngineEx
*iface
)
2603 FIXME("%p stub.\n", iface
);
2608 static HRESULT WINAPI
media_engine_GetStereo3DFramePackingMode(IMFMediaEngineEx
*iface
, MF_MEDIA_ENGINE_S3D_PACKING_MODE
*mode
)
2610 FIXME("%p, %p stub.\n", iface
, mode
);
2615 static HRESULT WINAPI
media_engine_SetStereo3DFramePackingMode(IMFMediaEngineEx
*iface
, MF_MEDIA_ENGINE_S3D_PACKING_MODE mode
)
2617 FIXME("%p, %#x stub.\n", iface
, mode
);
2622 static HRESULT WINAPI
media_engine_GetStereo3DRenderMode(IMFMediaEngineEx
*iface
, MF3DVideoOutputType
*output_type
)
2624 FIXME("%p, %p stub.\n", iface
, output_type
);
2629 static HRESULT WINAPI
media_engine_SetStereo3DRenderMode(IMFMediaEngineEx
*iface
, MF3DVideoOutputType output_type
)
2631 FIXME("%p, %#x stub.\n", iface
, output_type
);
2636 static HRESULT WINAPI
media_engine_EnableWindowlessSwapchainMode(IMFMediaEngineEx
*iface
, BOOL enable
)
2638 FIXME("%p, %d stub.\n", iface
, enable
);
2643 static HRESULT WINAPI
media_engine_GetVideoSwapchainHandle(IMFMediaEngineEx
*iface
, HANDLE
*swapchain
)
2645 FIXME("%p, %p stub.\n", iface
, swapchain
);
2650 static HRESULT WINAPI
media_engine_EnableHorizontalMirrorMode(IMFMediaEngineEx
*iface
, BOOL enable
)
2652 FIXME("%p, %d stub.\n", iface
, enable
);
2657 static HRESULT WINAPI
media_engine_GetAudioStreamCategory(IMFMediaEngineEx
*iface
, UINT32
*category
)
2659 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2662 TRACE("%p, %p.\n", iface
, category
);
2664 EnterCriticalSection(&engine
->cs
);
2666 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2669 hr
= IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_CATEGORY
, category
);
2671 LeaveCriticalSection(&engine
->cs
);
2676 static HRESULT WINAPI
media_engine_SetAudioStreamCategory(IMFMediaEngineEx
*iface
, UINT32 category
)
2678 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2681 TRACE("%p, %u.\n", iface
, category
);
2683 EnterCriticalSection(&engine
->cs
);
2685 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2688 hr
= IMFAttributes_SetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_CATEGORY
, category
);
2690 LeaveCriticalSection(&engine
->cs
);
2695 static HRESULT WINAPI
media_engine_GetAudioEndpointRole(IMFMediaEngineEx
*iface
, UINT32
*role
)
2697 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2700 TRACE("%p, %p.\n", iface
, role
);
2702 EnterCriticalSection(&engine
->cs
);
2704 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2707 hr
= IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE
, role
);
2709 LeaveCriticalSection(&engine
->cs
);
2714 static HRESULT WINAPI
media_engine_SetAudioEndpointRole(IMFMediaEngineEx
*iface
, UINT32 role
)
2716 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2719 TRACE("%p, %u.\n", iface
, role
);
2721 EnterCriticalSection(&engine
->cs
);
2723 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2726 hr
= IMFAttributes_SetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE
, role
);
2728 LeaveCriticalSection(&engine
->cs
);
2733 static HRESULT WINAPI
media_engine_GetRealTimeMode(IMFMediaEngineEx
*iface
, BOOL
*enabled
)
2735 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2738 TRACE("%p, %p.\n", iface
, enabled
);
2740 EnterCriticalSection(&engine
->cs
);
2741 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2744 *enabled
= !!(engine
->flags
& MF_MEDIA_ENGINE_REAL_TIME_MODE
);
2745 LeaveCriticalSection(&engine
->cs
);
2750 static HRESULT WINAPI
media_engine_SetRealTimeMode(IMFMediaEngineEx
*iface
, BOOL enable
)
2752 struct media_engine
*engine
= impl_from_IMFMediaEngineEx(iface
);
2755 TRACE("%p, %d.\n", iface
, enable
);
2757 EnterCriticalSection(&engine
->cs
);
2758 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2761 media_engine_set_flag(engine
, MF_MEDIA_ENGINE_REAL_TIME_MODE
, enable
);
2762 LeaveCriticalSection(&engine
->cs
);
2767 static HRESULT WINAPI
media_engine_SetCurrentTimeEx(IMFMediaEngineEx
*iface
, double seektime
, MF_MEDIA_ENGINE_SEEK_MODE mode
)
2769 FIXME("%p, %f, %#x stub.\n", iface
, seektime
, mode
);
2774 static HRESULT WINAPI
media_engine_EnableTimeUpdateTimer(IMFMediaEngineEx
*iface
, BOOL enable
)
2776 FIXME("%p, %d stub.\n", iface
, enable
);
2781 static const IMFMediaEngineExVtbl media_engine_vtbl
=
2783 media_engine_QueryInterface
,
2784 media_engine_AddRef
,
2785 media_engine_Release
,
2786 media_engine_GetError
,
2787 media_engine_SetErrorCode
,
2788 media_engine_SetSourceElements
,
2789 media_engine_SetSource
,
2790 media_engine_GetCurrentSource
,
2791 media_engine_GetNetworkState
,
2792 media_engine_GetPreload
,
2793 media_engine_SetPreload
,
2794 media_engine_GetBuffered
,
2796 media_engine_CanPlayType
,
2797 media_engine_GetReadyState
,
2798 media_engine_IsSeeking
,
2799 media_engine_GetCurrentTime
,
2800 media_engine_SetCurrentTime
,
2801 media_engine_GetStartTime
,
2802 media_engine_GetDuration
,
2803 media_engine_IsPaused
,
2804 media_engine_GetDefaultPlaybackRate
,
2805 media_engine_SetDefaultPlaybackRate
,
2806 media_engine_GetPlaybackRate
,
2807 media_engine_SetPlaybackRate
,
2808 media_engine_GetPlayed
,
2809 media_engine_GetSeekable
,
2810 media_engine_IsEnded
,
2811 media_engine_GetAutoPlay
,
2812 media_engine_SetAutoPlay
,
2813 media_engine_GetLoop
,
2814 media_engine_SetLoop
,
2817 media_engine_GetMuted
,
2818 media_engine_SetMuted
,
2819 media_engine_GetVolume
,
2820 media_engine_SetVolume
,
2821 media_engine_HasVideo
,
2822 media_engine_HasAudio
,
2823 media_engine_GetNativeVideoSize
,
2824 media_engine_GetVideoAspectRatio
,
2825 media_engine_Shutdown
,
2826 media_engine_TransferVideoFrame
,
2827 media_engine_OnVideoStreamTick
,
2828 media_engine_SetSourceFromByteStream
,
2829 media_engine_GetStatistics
,
2830 media_engine_UpdateVideoStream
,
2831 media_engine_GetBalance
,
2832 media_engine_SetBalance
,
2833 media_engine_IsPlaybackRateSupported
,
2834 media_engine_FrameStep
,
2835 media_engine_GetResourceCharacteristics
,
2836 media_engine_GetPresentationAttribute
,
2837 media_engine_GetNumberOfStreams
,
2838 media_engine_GetStreamAttribute
,
2839 media_engine_GetStreamSelection
,
2840 media_engine_SetStreamSelection
,
2841 media_engine_ApplyStreamSelections
,
2842 media_engine_IsProtected
,
2843 media_engine_InsertVideoEffect
,
2844 media_engine_InsertAudioEffect
,
2845 media_engine_RemoveAllEffects
,
2846 media_engine_SetTimelineMarkerTimer
,
2847 media_engine_GetTimelineMarkerTimer
,
2848 media_engine_CancelTimelineMarkerTimer
,
2849 media_engine_IsStereo3D
,
2850 media_engine_GetStereo3DFramePackingMode
,
2851 media_engine_SetStereo3DFramePackingMode
,
2852 media_engine_GetStereo3DRenderMode
,
2853 media_engine_SetStereo3DRenderMode
,
2854 media_engine_EnableWindowlessSwapchainMode
,
2855 media_engine_GetVideoSwapchainHandle
,
2856 media_engine_EnableHorizontalMirrorMode
,
2857 media_engine_GetAudioStreamCategory
,
2858 media_engine_SetAudioStreamCategory
,
2859 media_engine_GetAudioEndpointRole
,
2860 media_engine_SetAudioEndpointRole
,
2861 media_engine_GetRealTimeMode
,
2862 media_engine_SetRealTimeMode
,
2863 media_engine_SetCurrentTimeEx
,
2864 media_engine_EnableTimeUpdateTimer
,
2867 static HRESULT WINAPI
media_engine_gs_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
2869 struct media_engine
*engine
= impl_from_IMFGetService(iface
);
2870 return IMFMediaEngineEx_QueryInterface(&engine
->IMFMediaEngineEx_iface
, riid
, obj
);
2873 static ULONG WINAPI
media_engine_gs_AddRef(IMFGetService
*iface
)
2875 struct media_engine
*engine
= impl_from_IMFGetService(iface
);
2876 return IMFMediaEngineEx_AddRef(&engine
->IMFMediaEngineEx_iface
);
2879 static ULONG WINAPI
media_engine_gs_Release(IMFGetService
*iface
)
2881 struct media_engine
*engine
= impl_from_IMFGetService(iface
);
2882 return IMFMediaEngineEx_Release(&engine
->IMFMediaEngineEx_iface
);
2885 static HRESULT WINAPI
media_engine_gs_GetService(IMFGetService
*iface
, REFGUID service
,
2886 REFIID riid
, void **object
)
2888 FIXME("%p, %s, %s, %p stub.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), object
);
2893 static const IMFGetServiceVtbl media_engine_get_service_vtbl
=
2895 media_engine_gs_QueryInterface
,
2896 media_engine_gs_AddRef
,
2897 media_engine_gs_Release
,
2898 media_engine_gs_GetService
,
2901 static HRESULT WINAPI
media_engine_grabber_callback_QueryInterface(IMFSampleGrabberSinkCallback
*iface
,
2902 REFIID riid
, void **obj
)
2904 if (IsEqualIID(riid
, &IID_IMFSampleGrabberSinkCallback
) ||
2905 IsEqualIID(riid
, &IID_IUnknown
))
2908 IMFSampleGrabberSinkCallback_AddRef(iface
);
2913 return E_NOINTERFACE
;
2916 static ULONG WINAPI
media_engine_grabber_callback_AddRef(IMFSampleGrabberSinkCallback
*iface
)
2918 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
2919 return IMFMediaEngineEx_AddRef(&engine
->IMFMediaEngineEx_iface
);
2922 static ULONG WINAPI
media_engine_grabber_callback_Release(IMFSampleGrabberSinkCallback
*iface
)
2924 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
2925 return IMFMediaEngineEx_Release(&engine
->IMFMediaEngineEx_iface
);
2928 static HRESULT WINAPI
media_engine_grabber_callback_OnClockStart(IMFSampleGrabberSinkCallback
*iface
,
2929 MFTIME systime
, LONGLONG start_offset
)
2934 static HRESULT WINAPI
media_engine_grabber_callback_OnClockStop(IMFSampleGrabberSinkCallback
*iface
,
2937 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
2939 EnterCriticalSection(&engine
->cs
);
2940 media_engine_set_flag(engine
, FLAGS_ENGINE_FIRST_FRAME
, FALSE
);
2941 engine
->video_frame
.pts
= MINLONGLONG
;
2942 LeaveCriticalSection(&engine
->cs
);
2947 static HRESULT WINAPI
media_engine_grabber_callback_OnClockPause(IMFSampleGrabberSinkCallback
*iface
,
2953 static HRESULT WINAPI
media_engine_grabber_callback_OnClockRestart(IMFSampleGrabberSinkCallback
*iface
,
2959 static HRESULT WINAPI
media_engine_grabber_callback_OnClockSetRate(IMFSampleGrabberSinkCallback
*iface
,
2960 MFTIME systime
, float rate
)
2965 static HRESULT WINAPI
media_engine_grabber_callback_OnSetPresentationClock(IMFSampleGrabberSinkCallback
*iface
,
2966 IMFPresentationClock
*clock
)
2971 static HRESULT WINAPI
media_engine_grabber_callback_OnProcessSample(IMFSampleGrabberSinkCallback
*iface
,
2972 REFGUID major_type
, DWORD sample_flags
, LONGLONG sample_time
, LONGLONG sample_duration
,
2973 const BYTE
*buffer
, DWORD buffer_size
)
2975 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
2977 EnterCriticalSection(&engine
->cs
);
2979 if (!(engine
->flags
& FLAGS_ENGINE_FIRST_FRAME
))
2981 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY
, 0, 0);
2982 media_engine_set_flag(engine
, FLAGS_ENGINE_FIRST_FRAME
, TRUE
);
2984 engine
->video_frame
.pts
= sample_time
;
2985 if (engine
->video_frame
.buffer_size
< buffer_size
)
2987 free(engine
->video_frame
.buffer
);
2988 if ((engine
->video_frame
.buffer
= malloc(buffer_size
)))
2989 engine
->video_frame
.buffer_size
= buffer_size
;
2991 if (engine
->video_frame
.buffer
)
2993 memcpy(engine
->video_frame
.buffer
, buffer
, buffer_size
);
2994 engine
->flags
|= FLAGS_ENGINE_NEW_FRAME
;
2997 LeaveCriticalSection(&engine
->cs
);
3002 static HRESULT WINAPI
media_engine_grabber_callback_OnShutdown(IMFSampleGrabberSinkCallback
*iface
)
3007 static const IMFSampleGrabberSinkCallbackVtbl media_engine_grabber_callback_vtbl
=
3009 media_engine_grabber_callback_QueryInterface
,
3010 media_engine_grabber_callback_AddRef
,
3011 media_engine_grabber_callback_Release
,
3012 media_engine_grabber_callback_OnClockStart
,
3013 media_engine_grabber_callback_OnClockStop
,
3014 media_engine_grabber_callback_OnClockPause
,
3015 media_engine_grabber_callback_OnClockRestart
,
3016 media_engine_grabber_callback_OnClockSetRate
,
3017 media_engine_grabber_callback_OnSetPresentationClock
,
3018 media_engine_grabber_callback_OnProcessSample
,
3019 media_engine_grabber_callback_OnShutdown
,
3022 static HRESULT WINAPI
media_engine_factory_QueryInterface(IMFMediaEngineClassFactory
*iface
, REFIID riid
, void **obj
)
3024 if (IsEqualIID(riid
, &IID_IMFMediaEngineClassFactory
) ||
3025 IsEqualIID(riid
, &IID_IUnknown
))
3028 IMFMediaEngineClassFactory_AddRef(iface
);
3032 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
3034 return E_NOINTERFACE
;
3037 static ULONG WINAPI
media_engine_factory_AddRef(IMFMediaEngineClassFactory
*iface
)
3042 static ULONG WINAPI
media_engine_factory_Release(IMFMediaEngineClassFactory
*iface
)
3047 static HRESULT
init_media_engine(DWORD flags
, IMFAttributes
*attributes
, struct media_engine
*engine
)
3049 DXGI_FORMAT output_format
;
3050 UINT64 playback_hwnd
;
3054 engine
->IMFMediaEngineEx_iface
.lpVtbl
= &media_engine_vtbl
;
3055 engine
->IMFGetService_iface
.lpVtbl
= &media_engine_get_service_vtbl
;
3056 engine
->session_events
.lpVtbl
= &media_engine_session_events_vtbl
;
3057 engine
->load_handler
.lpVtbl
= &media_engine_load_handler_vtbl
;
3058 engine
->grabber_callback
.lpVtbl
= &media_engine_grabber_callback_vtbl
;
3059 engine
->refcount
= 1;
3060 engine
->flags
= (flags
& MF_MEDIA_ENGINE_CREATEFLAGS_MASK
) | FLAGS_ENGINE_PAUSED
;
3061 engine
->default_playback_rate
= 1.0;
3062 engine
->playback_rate
= 1.0;
3063 engine
->volume
= 1.0;
3064 engine
->duration
= NAN
;
3065 engine
->video_frame
.pts
= MINLONGLONG
;
3066 InitializeCriticalSection(&engine
->cs
);
3068 hr
= IMFAttributes_GetUnknown(attributes
, &MF_MEDIA_ENGINE_CALLBACK
, &IID_IMFMediaEngineNotify
,
3069 (void **)&engine
->callback
);
3073 IMFAttributes_GetUnknown(attributes
, &MF_MEDIA_ENGINE_DXGI_MANAGER
, &IID_IMFDXGIDeviceManager
,
3074 (void **)&engine
->device_manager
);
3076 if (FAILED(hr
= MFCreateMediaSession(NULL
, &engine
->session
)))
3079 if (FAILED(hr
= IMFMediaSession_GetClock(engine
->session
, &clock
)))
3082 hr
= IMFClock_QueryInterface(clock
, &IID_IMFPresentationClock
, (void **)&engine
->clock
);
3083 IMFClock_Release(clock
);
3087 if (FAILED(hr
= IMFMediaSession_BeginGetEvent(engine
->session
, &engine
->session_events
, NULL
)))
3090 if (FAILED(hr
= MFCreateSourceResolver(&engine
->resolver
)))
3093 if (FAILED(hr
= MFCreateAttributes(&engine
->attributes
, 0)))
3096 if (FAILED(hr
= IMFAttributes_CopyAllItems(attributes
, engine
->attributes
)))
3099 /* Set default audio configuration */
3100 if (FAILED(IMFAttributes_GetItem(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_CATEGORY
, NULL
)))
3101 IMFAttributes_SetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_CATEGORY
, AudioCategory_Other
);
3102 if (FAILED(IMFAttributes_GetItem(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE
, NULL
)))
3103 IMFAttributes_SetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE
, eMultimedia
);
3105 IMFAttributes_GetUINT64(attributes
, &MF_MEDIA_ENGINE_PLAYBACK_HWND
, &playback_hwnd
);
3106 hr
= IMFAttributes_GetUINT32(attributes
, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT
, &output_format
);
3107 if (playback_hwnd
) /* FIXME: handle MF_MEDIA_ENGINE_PLAYBACK_VISUAL */
3108 engine
->mode
= MEDIA_ENGINE_RENDERING_MODE
;
3112 engine
->mode
= MEDIA_ENGINE_FRAME_SERVER_MODE
;
3114 engine
->mode
= MEDIA_ENGINE_AUDIO_MODE
;
3120 static HRESULT WINAPI
media_engine_factory_CreateInstance(IMFMediaEngineClassFactory
*iface
, DWORD flags
,
3121 IMFAttributes
*attributes
, IMFMediaEngine
**engine
)
3123 struct media_engine
*object
;
3126 TRACE("%p, %#lx, %p, %p.\n", iface
, flags
, attributes
, engine
);
3128 if (!attributes
|| !engine
)
3131 object
= calloc(1, sizeof(*object
));
3133 return E_OUTOFMEMORY
;
3135 hr
= init_media_engine(flags
, attributes
, object
);
3138 free_media_engine(object
);
3142 *engine
= (IMFMediaEngine
*)&object
->IMFMediaEngineEx_iface
;
3147 static HRESULT WINAPI
media_engine_factory_CreateTimeRange(IMFMediaEngineClassFactory
*iface
,
3148 IMFMediaTimeRange
**range
)
3150 TRACE("%p, %p.\n", iface
, range
);
3152 return create_time_range(range
);
3155 static HRESULT WINAPI
media_engine_factory_CreateError(IMFMediaEngineClassFactory
*iface
, IMFMediaError
**error
)
3157 TRACE("%p, %p.\n", iface
, error
);
3159 return create_media_error(error
);
3162 static const IMFMediaEngineClassFactoryVtbl media_engine_factory_vtbl
=
3164 media_engine_factory_QueryInterface
,
3165 media_engine_factory_AddRef
,
3166 media_engine_factory_Release
,
3167 media_engine_factory_CreateInstance
,
3168 media_engine_factory_CreateTimeRange
,
3169 media_engine_factory_CreateError
,
3172 static IMFMediaEngineClassFactory media_engine_factory
= { &media_engine_factory_vtbl
};
3174 static HRESULT WINAPI
classfactory_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **obj
)
3176 TRACE("%s, %p.\n", debugstr_guid(riid
), obj
);
3178 if (IsEqualGUID(riid
, &IID_IClassFactory
) ||
3179 IsEqualGUID(riid
, &IID_IUnknown
))
3181 IClassFactory_AddRef(iface
);
3186 WARN("interface %s not implemented.\n", debugstr_guid(riid
));
3188 return E_NOINTERFACE
;
3191 static ULONG WINAPI
classfactory_AddRef(IClassFactory
*iface
)
3196 static ULONG WINAPI
classfactory_Release(IClassFactory
*iface
)
3201 static HRESULT WINAPI
classfactory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **obj
)
3203 TRACE("%p, %s, %p.\n", outer
, debugstr_guid(riid
), obj
);
3208 return CLASS_E_NOAGGREGATION
;
3210 return IMFMediaEngineClassFactory_QueryInterface(&media_engine_factory
, riid
, obj
);
3213 static HRESULT WINAPI
classfactory_LockServer(IClassFactory
*iface
, BOOL dolock
)
3215 FIXME("(%d): stub.\n", dolock
);
3219 static const IClassFactoryVtbl class_factory_vtbl
=
3221 classfactory_QueryInterface
,
3222 classfactory_AddRef
,
3223 classfactory_Release
,
3224 classfactory_CreateInstance
,
3225 classfactory_LockServer
,
3228 static IClassFactory classfactory
= { &class_factory_vtbl
};
3230 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **obj
)
3232 TRACE("%s, %s, %p.\n", debugstr_guid(clsid
), debugstr_guid(riid
), obj
);
3234 if (IsEqualGUID(clsid
, &CLSID_MFMediaEngineClassFactory
))
3235 return IClassFactory_QueryInterface(&classfactory
, riid
, obj
);
3237 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
3239 return CLASS_E_CLASSNOTAVAILABLE
;