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"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
37 static BOOL
mf_array_reserve(void **elements
, size_t *capacity
, size_t count
, size_t size
)
39 size_t new_capacity
, max_capacity
;
42 if (count
<= *capacity
)
45 max_capacity
= ~(SIZE_T
)0 / size
;
46 if (count
> max_capacity
)
49 new_capacity
= max(4, *capacity
);
50 while (new_capacity
< count
&& new_capacity
<= max_capacity
/ 2)
52 if (new_capacity
< count
)
53 new_capacity
= max_capacity
;
55 if (!(new_elements
= realloc(*elements
, new_capacity
* size
)))
58 *elements
= new_elements
;
59 *capacity
= new_capacity
;
64 enum media_engine_mode
67 MEDIA_ENGINE_AUDIO_MODE
,
68 MEDIA_ENGINE_RENDERING_MODE
,
69 MEDIA_ENGINE_FRAME_SERVER_MODE
,
72 /* Used with create flags. */
73 enum media_engine_flags
75 /* MF_MEDIA_ENGINE_CREATEFLAGS_MASK is 0x1f. */
76 FLAGS_ENGINE_SHUT_DOWN
= 0x20,
77 FLAGS_ENGINE_AUTO_PLAY
= 0x40,
78 FLAGS_ENGINE_LOOP
= 0x80,
79 FLAGS_ENGINE_PAUSED
= 0x100,
80 FLAGS_ENGINE_WAITING
= 0x200,
81 FLAGS_ENGINE_MUTED
= 0x400,
82 FLAGS_ENGINE_HAS_AUDIO
= 0x800,
83 FLAGS_ENGINE_HAS_VIDEO
= 0x1000,
84 FLAGS_ENGINE_FIRST_FRAME
= 0x2000,
85 FLAGS_ENGINE_IS_ENDED
= 0x4000,
86 FLAGS_ENGINE_NEW_FRAME
= 0x8000,
87 FLAGS_ENGINE_SOURCE_PENDING
= 0x10000,
88 FLAGS_ENGINE_PLAY_PENDING
= 0x20000,
101 static const struct vec3 fullquad
[] =
103 {-1.0f
, -1.0f
, 0.0f
},
105 { 1.0f
, -1.0f
, 0.0f
},
111 float left
, top
, right
, bottom
;
116 IMFMediaEngine IMFMediaEngine_iface
;
117 IMFAsyncCallback session_events
;
118 IMFAsyncCallback load_handler
;
119 IMFSampleGrabberSinkCallback grabber_callback
;
121 IMFMediaEngineNotify
*callback
;
122 IMFAttributes
*attributes
;
123 IMFDXGIDeviceManager
*device_manager
;
124 HANDLE device_handle
;
125 enum media_engine_mode mode
;
127 double playback_rate
;
128 double default_playback_rate
;
131 MF_MEDIA_ENGINE_NETWORK network_state
;
132 MF_MEDIA_ENGINE_ERR error_code
;
133 HRESULT extended_code
;
134 MF_MEDIA_ENGINE_READY ready_state
;
135 MF_MEDIA_ENGINE_PRELOAD preload
;
136 IMFMediaSession
*session
;
137 IMFPresentationClock
*clock
;
138 IMFSourceResolver
*resolver
;
148 DXGI_FORMAT output_format
;
154 ID3D11Texture2D
*source
;
155 ID3D11ShaderResourceView
*srv
;
156 ID3D11SamplerState
*sampler
;
157 ID3D11InputLayout
*input_layout
;
158 ID3D11VertexShader
*vs
;
159 ID3D11PixelShader
*ps
;
165 struct color backcolor
;
172 static void media_engine_release_video_frame_resources(struct media_engine
*engine
)
174 if (engine
->video_frame
.d3d11
.vb
)
175 ID3D11Buffer_Release(engine
->video_frame
.d3d11
.vb
);
176 if (engine
->video_frame
.d3d11
.ps_cb
)
177 ID3D11Buffer_Release(engine
->video_frame
.d3d11
.ps_cb
);
178 if (engine
->video_frame
.d3d11
.source
)
179 ID3D11Texture2D_Release(engine
->video_frame
.d3d11
.source
);
180 if (engine
->video_frame
.d3d11
.srv
)
181 ID3D11ShaderResourceView_Release(engine
->video_frame
.d3d11
.srv
);
182 if (engine
->video_frame
.d3d11
.sampler
)
183 ID3D11SamplerState_Release(engine
->video_frame
.d3d11
.sampler
);
184 if (engine
->video_frame
.d3d11
.input_layout
)
185 ID3D11InputLayout_Release(engine
->video_frame
.d3d11
.input_layout
);
186 if (engine
->video_frame
.d3d11
.vs
)
187 ID3D11VertexShader_Release(engine
->video_frame
.d3d11
.vs
);
188 if (engine
->video_frame
.d3d11
.ps
)
189 ID3D11PixelShader_Release(engine
->video_frame
.d3d11
.ps
);
191 memset(&engine
->video_frame
.d3d11
, 0, sizeof(engine
->video_frame
.d3d11
));
192 memcpy(engine
->video_frame
.d3d11
.quad
, fullquad
, sizeof(fullquad
));
195 static HRESULT
media_engine_lock_d3d_device(struct media_engine
*engine
, ID3D11Device
**device
)
199 if (!engine
->device_manager
)
201 FIXME("Device manager wasn't set.\n");
205 if (!engine
->device_handle
)
207 if (FAILED(hr
= IMFDXGIDeviceManager_OpenDeviceHandle(engine
->device_manager
, &engine
->device_handle
)))
209 WARN("Failed to open device handle, hr %#x.\n", hr
);
214 hr
= IMFDXGIDeviceManager_LockDevice(engine
->device_manager
, engine
->device_handle
, &IID_ID3D11Device
,
215 (void **)device
, TRUE
);
216 if (hr
== MF_E_DXGI_NEW_VIDEO_DEVICE
)
218 IMFDXGIDeviceManager_CloseDeviceHandle(engine
->device_manager
, engine
->device_handle
);
219 engine
->device_handle
= NULL
;
221 media_engine_release_video_frame_resources(engine
);
223 if (FAILED(hr
= IMFDXGIDeviceManager_OpenDeviceHandle(engine
->device_manager
, &engine
->device_handle
)))
225 WARN("Failed to open a device handle, hr %#x.\n", hr
);
228 hr
= IMFDXGIDeviceManager_LockDevice(engine
->device_manager
, engine
->device_handle
, &IID_ID3D11Device
,
229 (void **)device
, TRUE
);
235 static void media_engine_unlock_d3d_device(struct media_engine
*engine
, ID3D11Device
*device
)
237 ID3D11Device_Release(device
);
238 IMFDXGIDeviceManager_UnlockDevice(engine
->device_manager
, engine
->device_handle
, FALSE
);
241 static HRESULT
media_engine_create_d3d11_video_frame_resources(struct media_engine
*engine
, ID3D11Device
*device
)
243 static const D3D11_INPUT_ELEMENT_DESC layout_desc
[] =
245 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT
, 0, 0, D3D11_INPUT_PER_VERTEX_DATA
, 0 },
247 static const DWORD vs_code
[] =
250 float4
main(float4 position
: POSITION
) : SV_POSITION
255 0x43425844, 0xa7a2f22d, 0x83ff2560, 0xe61638bd, 0x87e3ce90, 0x00000001, 0x000000d8, 0x00000003,
256 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
257 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x49534f50, 0x4e4f4954, 0xababab00,
258 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, 0x00000003,
259 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x52444853, 0x0000003c, 0x00010040,
260 0x0000000f, 0x0300005f, 0x001010f2, 0x00000000, 0x04000067, 0x001020f2, 0x00000000, 0x00000001,
261 0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000000, 0x0100003e,
263 static const DWORD ps_code
[] =
272 float4
main(float4 position
: SV_POSITION
) : SV_TARGET
276 if (position
.x
< dst
.x
|| position
.x
> dst
.z
) return backcolor
;
277 if (position
.y
< dst
.y
|| position
.y
> dst
.w
) return backcolor
;
278 p
.x
= (position
.x
- dst
.x
) / (dst
.z
- dst
.x
);
279 p
.y
= 1.0f
- (position
.y
- dst
.y
) / (dst
.w
- dst
.y
);
280 p
.x
= src
.x
+ p
.x
* (src
.z
- src
.x
);
281 p
.y
= src
.y
+ p
.y
* (src
.w
- src
.y
);
282 return t
.Sample(s
, p
);
285 0x43425844, 0x5892e3b1, 0x24c17f7c, 0x9999f143, 0x49667872, 0x00000001, 0x0000032c, 0x00000003,
286 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020,
287 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000030f, 0x505f5653, 0x5449534f, 0x004e4f49,
288 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003,
289 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054, 0x52444853, 0x00000290, 0x00000040,
290 0x000000a4, 0x04000059, 0x00208e46, 0x00000000, 0x00000003, 0x0300005a, 0x00106000, 0x00000000,
291 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x04002064, 0x00101032, 0x00000000, 0x00000001,
292 0x03000065, 0x001020f2, 0x00000000, 0x02000068, 0x00000002, 0x08000031, 0x00100012, 0x00000000,
293 0x0010100a, 0x00000000, 0x0020800a, 0x00000000, 0x00000000, 0x08000031, 0x00100022, 0x00000000,
294 0x0020802a, 0x00000000, 0x00000000, 0x0010100a, 0x00000000, 0x0700003c, 0x00100012, 0x00000000,
295 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a, 0x00000000, 0x06000036,
296 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e, 0x01000015, 0x08000031,
297 0x00100012, 0x00000000, 0x0010101a, 0x00000000, 0x0020801a, 0x00000000, 0x00000000, 0x08000031,
298 0x00100022, 0x00000000, 0x0020803a, 0x00000000, 0x00000000, 0x0010101a, 0x00000000, 0x0700003c,
299 0x00100012, 0x00000000, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0304001f, 0x0010000a,
300 0x00000000, 0x06000036, 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000002, 0x0100003e,
301 0x01000015, 0x09000000, 0x00100032, 0x00000000, 0x00101046, 0x00000000, 0x80208046, 0x00000041,
302 0x00000000, 0x00000000, 0x0a000000, 0x001000c2, 0x00000000, 0x80208406, 0x00000041, 0x00000000,
303 0x00000000, 0x00208ea6, 0x00000000, 0x00000000, 0x0700000e, 0x00100032, 0x00000000, 0x00100046,
304 0x00000000, 0x00100ae6, 0x00000000, 0x08000000, 0x00100022, 0x00000000, 0x8010001a, 0x00000041,
305 0x00000000, 0x00004001, 0x3f800000, 0x0a000000, 0x001000c2, 0x00000000, 0x80208406, 0x00000041,
306 0x00000000, 0x00000001, 0x00208ea6, 0x00000000, 0x00000001, 0x0a000032, 0x00100012, 0x00000001,
307 0x0010000a, 0x00000000, 0x0010002a, 0x00000000, 0x0020800a, 0x00000000, 0x00000001, 0x0a000032,
308 0x00100022, 0x00000001, 0x0010001a, 0x00000000, 0x0010003a, 0x00000000, 0x0020801a, 0x00000000,
309 0x00000001, 0x09000045, 0x001020f2, 0x00000000, 0x00100046, 0x00000001, 0x00107e46, 0x00000000,
310 0x00106000, 0x00000000, 0x0100003e,
312 D3D11_SUBRESOURCE_DATA resource_data
;
313 D3D11_TEXTURE2D_DESC texture_desc
;
314 D3D11_SAMPLER_DESC sampler_desc
;
315 D3D11_BUFFER_DESC buffer_desc
;
318 if (engine
->video_frame
.d3d11
.source
)
321 /* Default vertex buffer, updated on first transfer call. */
322 buffer_desc
.ByteWidth
= sizeof(engine
->video_frame
.d3d11
.quad
);
323 buffer_desc
.Usage
= D3D11_USAGE_DEFAULT
;
324 buffer_desc
.BindFlags
= D3D11_BIND_VERTEX_BUFFER
;
325 buffer_desc
.CPUAccessFlags
= 0;
326 buffer_desc
.MiscFlags
= 0;
327 buffer_desc
.StructureByteStride
= 0;
329 resource_data
.pSysMem
= engine
->video_frame
.d3d11
.quad
;
330 resource_data
.SysMemPitch
= 0;
331 resource_data
.SysMemSlicePitch
= 0;
333 if (FAILED(hr
= ID3D11Device_CreateBuffer(device
, &buffer_desc
, &resource_data
, &engine
->video_frame
.d3d11
.vb
)))
335 WARN("Failed to create a vertex buffer, hr %#x.\n", hr
);
339 buffer_desc
.ByteWidth
= sizeof(engine
->video_frame
.d3d11
.cb
);
340 buffer_desc
.BindFlags
= D3D11_BIND_CONSTANT_BUFFER
;
342 if (FAILED(hr
= ID3D11Device_CreateBuffer(device
, &buffer_desc
, NULL
, &engine
->video_frame
.d3d11
.ps_cb
)))
344 WARN("Failed to create a buffer, hr %#x.\n", hr
);
348 /* Source texture. */
349 texture_desc
.Width
= engine
->video_frame
.size
.cx
;
350 texture_desc
.Height
= engine
->video_frame
.size
.cy
;
351 texture_desc
.MipLevels
= 1;
352 texture_desc
.ArraySize
= 1;
353 texture_desc
.Format
= engine
->video_frame
.output_format
;
354 texture_desc
.SampleDesc
.Count
= 1;
355 texture_desc
.SampleDesc
.Quality
= 0;
356 texture_desc
.Usage
= D3D11_USAGE_DEFAULT
;
357 texture_desc
.BindFlags
= D3D11_BIND_SHADER_RESOURCE
;
358 texture_desc
.CPUAccessFlags
= 0;
359 texture_desc
.MiscFlags
= 0;
361 if (FAILED(hr
= ID3D11Device_CreateTexture2D(device
, &texture_desc
, NULL
, &engine
->video_frame
.d3d11
.source
)))
363 WARN("Failed to create source texture, hr %#x.\n", hr
);
367 if (FAILED(hr
= ID3D11Device_CreateShaderResourceView(device
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.source
,
368 NULL
, &engine
->video_frame
.d3d11
.srv
)))
370 WARN("Failed to create SRV, hr %#x.\n", hr
);
375 memset(&sampler_desc
, 0, sizeof(sampler_desc
));
376 sampler_desc
.Filter
= D3D11_FILTER_MIN_MAG_MIP_POINT
;
377 sampler_desc
.AddressU
= D3D11_TEXTURE_ADDRESS_CLAMP
;
378 sampler_desc
.AddressV
= D3D11_TEXTURE_ADDRESS_CLAMP
;
379 sampler_desc
.AddressW
= D3D11_TEXTURE_ADDRESS_CLAMP
;
381 if (FAILED(hr
= ID3D11Device_CreateSamplerState(device
, &sampler_desc
, &engine
->video_frame
.d3d11
.sampler
)))
383 WARN("Failed to create a sampler state, hr %#x.\n", hr
);
388 if (FAILED(hr
= ID3D11Device_CreateInputLayout(device
, layout_desc
, ARRAY_SIZE(layout_desc
), vs_code
, sizeof(vs_code
),
389 &engine
->video_frame
.d3d11
.input_layout
)))
391 WARN("Failed to create input layout, hr %#x.\n", hr
);
396 if (FAILED(hr
= ID3D11Device_CreateVertexShader(device
, vs_code
, sizeof(vs_code
), NULL
, &engine
->video_frame
.d3d11
.vs
)))
398 WARN("Failed to create the vertex shader, hr %#x.\n", hr
);
402 if (FAILED(hr
= ID3D11Device_CreatePixelShader(device
, ps_code
, sizeof(ps_code
), NULL
, &engine
->video_frame
.d3d11
.ps
)))
404 WARN("Failed to create the pixel shader, hr %#x.\n", hr
);
421 IMFMediaTimeRange IMFMediaTimeRange_iface
;
424 struct range
*ranges
;
429 static struct time_range
*impl_from_IMFMediaTimeRange(IMFMediaTimeRange
*iface
)
431 return CONTAINING_RECORD(iface
, struct time_range
, IMFMediaTimeRange_iface
);
436 IMFMediaError IMFMediaError_iface
;
439 HRESULT extended_code
;
442 static struct media_error
*impl_from_IMFMediaError(IMFMediaError
*iface
)
444 return CONTAINING_RECORD(iface
, struct media_error
, IMFMediaError_iface
);
447 static HRESULT WINAPI
media_error_QueryInterface(IMFMediaError
*iface
, REFIID riid
, void **obj
)
449 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
451 if (IsEqualIID(riid
, &IID_IMFMediaError
) ||
452 IsEqualIID(riid
, &IID_IUnknown
))
455 IMFMediaError_AddRef(iface
);
459 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
461 return E_NOINTERFACE
;
464 static ULONG WINAPI
media_error_AddRef(IMFMediaError
*iface
)
466 struct media_error
*me
= impl_from_IMFMediaError(iface
);
467 ULONG refcount
= InterlockedIncrement(&me
->refcount
);
469 TRACE("%p, refcount %u.\n", iface
, refcount
);
474 static ULONG WINAPI
media_error_Release(IMFMediaError
*iface
)
476 struct media_error
*me
= impl_from_IMFMediaError(iface
);
477 ULONG refcount
= InterlockedDecrement(&me
->refcount
);
479 TRACE("%p, refcount %u.\n", iface
, refcount
);
487 static USHORT WINAPI
media_error_GetErrorCode(IMFMediaError
*iface
)
489 struct media_error
*me
= impl_from_IMFMediaError(iface
);
490 TRACE("%p.\n", iface
);
494 static HRESULT WINAPI
media_error_GetExtendedErrorCode(IMFMediaError
*iface
)
496 struct media_error
*me
= impl_from_IMFMediaError(iface
);
497 TRACE("%p.\n", iface
);
498 return me
->extended_code
;
501 static HRESULT WINAPI
media_error_SetErrorCode(IMFMediaError
*iface
, MF_MEDIA_ENGINE_ERR code
)
503 struct media_error
*me
= impl_from_IMFMediaError(iface
);
505 TRACE("%p, %u.\n", iface
, code
);
507 if ((unsigned int)code
> MF_MEDIA_ENGINE_ERR_ENCRYPTED
)
515 static HRESULT WINAPI
media_error_SetExtendedErrorCode(IMFMediaError
*iface
, HRESULT code
)
517 struct media_error
*me
= impl_from_IMFMediaError(iface
);
519 TRACE("%p, %#x.\n", iface
, code
);
521 me
->extended_code
= code
;
526 static const IMFMediaErrorVtbl media_error_vtbl
=
528 media_error_QueryInterface
,
531 media_error_GetErrorCode
,
532 media_error_GetExtendedErrorCode
,
533 media_error_SetErrorCode
,
534 media_error_SetExtendedErrorCode
,
537 static HRESULT
create_media_error(IMFMediaError
**ret
)
539 struct media_error
*object
;
543 if (!(object
= calloc(1, sizeof(*object
))))
544 return E_OUTOFMEMORY
;
546 object
->IMFMediaError_iface
.lpVtbl
= &media_error_vtbl
;
547 object
->refcount
= 1;
549 *ret
= &object
->IMFMediaError_iface
;
554 static HRESULT WINAPI
time_range_QueryInterface(IMFMediaTimeRange
*iface
, REFIID riid
, void **obj
)
556 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
558 if (IsEqualIID(riid
, &IID_IMFMediaTimeRange
) ||
559 IsEqualIID(riid
, &IID_IUnknown
))
562 IMFMediaTimeRange_AddRef(iface
);
566 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
568 return E_NOINTERFACE
;
571 static ULONG WINAPI
time_range_AddRef(IMFMediaTimeRange
*iface
)
573 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
574 ULONG refcount
= InterlockedIncrement(&range
->refcount
);
576 TRACE("%p, refcount %u.\n", iface
, refcount
);
581 static ULONG WINAPI
time_range_Release(IMFMediaTimeRange
*iface
)
583 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
584 ULONG refcount
= InterlockedDecrement(&range
->refcount
);
586 TRACE("%p, refcount %u.\n", iface
, refcount
);
597 static DWORD WINAPI
time_range_GetLength(IMFMediaTimeRange
*iface
)
599 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
601 TRACE("%p.\n", iface
);
606 static HRESULT WINAPI
time_range_GetStart(IMFMediaTimeRange
*iface
, DWORD idx
, double *start
)
608 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
610 TRACE("%p, %u, %p.\n", iface
, idx
, start
);
612 if (idx
>= range
->count
)
615 *start
= range
->ranges
[idx
].start
;
620 static HRESULT WINAPI
time_range_GetEnd(IMFMediaTimeRange
*iface
, DWORD idx
, double *end
)
622 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
624 TRACE("%p, %u, %p.\n", iface
, idx
, end
);
626 if (idx
>= range
->count
)
629 *end
= range
->ranges
[idx
].end
;
634 static BOOL WINAPI
time_range_ContainsTime(IMFMediaTimeRange
*iface
, double time
)
636 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
639 TRACE("%p, %.8e.\n", iface
, time
);
641 for (i
= 0; i
< range
->count
; ++i
)
643 if (time
>= range
->ranges
[i
].start
&& time
<= range
->ranges
[i
].end
)
650 static HRESULT WINAPI
time_range_AddRange(IMFMediaTimeRange
*iface
, double start
, double end
)
652 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
654 TRACE("%p, %.8e, %.8e.\n", iface
, start
, end
);
658 FIXME("Range merging is not implemented.\n");
662 if (!mf_array_reserve((void **)&range
->ranges
, &range
->capacity
, range
->count
+ 1, sizeof(*range
->ranges
)))
663 return E_OUTOFMEMORY
;
665 range
->ranges
[range
->count
].start
= start
;
666 range
->ranges
[range
->count
].end
= end
;
672 static HRESULT WINAPI
time_range_Clear(IMFMediaTimeRange
*iface
)
674 struct time_range
*range
= impl_from_IMFMediaTimeRange(iface
);
676 TRACE("%p.\n", iface
);
683 static const IMFMediaTimeRangeVtbl time_range_vtbl
=
685 time_range_QueryInterface
,
688 time_range_GetLength
,
691 time_range_ContainsTime
,
696 static HRESULT
create_time_range(IMFMediaTimeRange
**range
)
698 struct time_range
*object
;
700 object
= calloc(1, sizeof(*object
));
702 return E_OUTOFMEMORY
;
704 object
->IMFMediaTimeRange_iface
.lpVtbl
= &time_range_vtbl
;
705 object
->refcount
= 1;
707 *range
= &object
->IMFMediaTimeRange_iface
;
712 static void media_engine_set_flag(struct media_engine
*engine
, unsigned int mask
, BOOL value
)
715 engine
->flags
|= mask
;
717 engine
->flags
&= ~mask
;
720 static inline struct media_engine
*impl_from_IMFMediaEngine(IMFMediaEngine
*iface
)
722 return CONTAINING_RECORD(iface
, struct media_engine
, IMFMediaEngine_iface
);
725 static struct media_engine
*impl_from_session_events_IMFAsyncCallback(IMFAsyncCallback
*iface
)
727 return CONTAINING_RECORD(iface
, struct media_engine
, session_events
);
730 static struct media_engine
*impl_from_load_handler_IMFAsyncCallback(IMFAsyncCallback
*iface
)
732 return CONTAINING_RECORD(iface
, struct media_engine
, load_handler
);
735 static struct media_engine
*impl_from_IMFSampleGrabberSinkCallback(IMFSampleGrabberSinkCallback
*iface
)
737 return CONTAINING_RECORD(iface
, struct media_engine
, grabber_callback
);
740 static unsigned int get_gcd(unsigned int a
, unsigned int b
)
754 static void media_engine_get_frame_size(struct media_engine
*engine
, IMFTopology
*topology
)
756 IMFMediaTypeHandler
*handler
;
757 IMFMediaType
*media_type
;
758 IMFStreamDescriptor
*sd
;
759 IMFTopologyNode
*node
;
764 engine
->video_frame
.size
.cx
= 0;
765 engine
->video_frame
.size
.cy
= 0;
766 engine
->video_frame
.ratio
.cx
= 1;
767 engine
->video_frame
.ratio
.cy
= 1;
769 if (FAILED(IMFTopology_GetNodeByID(topology
, engine
->video_frame
.node_id
, &node
)))
772 hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_STREAM_DESCRIPTOR
,
773 &IID_IMFStreamDescriptor
, (void **)&sd
);
774 IMFTopologyNode_Release(node
);
778 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
779 IMFStreamDescriptor_Release(sd
);
783 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, &media_type
);
784 IMFMediaTypeHandler_Release(handler
);
787 WARN("Failed to get current media type %#x.\n", hr
);
791 IMFMediaType_GetUINT64(media_type
, &MF_MT_FRAME_SIZE
, &size
);
793 engine
->video_frame
.size
.cx
= size
>> 32;
794 engine
->video_frame
.size
.cy
= size
;
796 if ((gcd
= get_gcd(engine
->video_frame
.size
.cx
, engine
->video_frame
.size
.cy
)))
798 engine
->video_frame
.ratio
.cx
= engine
->video_frame
.size
.cx
/ gcd
;
799 engine
->video_frame
.ratio
.cy
= engine
->video_frame
.size
.cy
/ gcd
;
802 IMFMediaType_Release(media_type
);
805 static HRESULT WINAPI
media_engine_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
807 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
808 IsEqualIID(riid
, &IID_IUnknown
))
811 IMFAsyncCallback_AddRef(iface
);
815 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
817 return E_NOINTERFACE
;
820 static ULONG WINAPI
media_engine_session_events_AddRef(IMFAsyncCallback
*iface
)
822 struct media_engine
*engine
= impl_from_session_events_IMFAsyncCallback(iface
);
823 return IMFMediaEngine_AddRef(&engine
->IMFMediaEngine_iface
);
826 static ULONG WINAPI
media_engine_session_events_Release(IMFAsyncCallback
*iface
)
828 struct media_engine
*engine
= impl_from_session_events_IMFAsyncCallback(iface
);
829 return IMFMediaEngine_Release(&engine
->IMFMediaEngine_iface
);
832 static HRESULT WINAPI
media_engine_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
837 static HRESULT WINAPI
media_engine_session_events_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
839 struct media_engine
*engine
= impl_from_session_events_IMFAsyncCallback(iface
);
840 IMFMediaEvent
*event
= NULL
;
841 MediaEventType event_type
;
844 if (FAILED(hr
= IMFMediaSession_EndGetEvent(engine
->session
, result
, &event
)))
846 WARN("Failed to get session event, hr %#x.\n", hr
);
850 if (FAILED(hr
= IMFMediaEvent_GetType(event
, &event_type
)))
852 WARN("Failed to get event type, hr %#x.\n", hr
);
858 case MEBufferingStarted
:
859 case MEBufferingStopped
:
861 IMFMediaEngineNotify_EventNotify(engine
->callback
, event_type
== MEBufferingStarted
?
862 MF_MEDIA_ENGINE_EVENT_BUFFERINGSTARTED
: MF_MEDIA_ENGINE_EVENT_BUFFERINGENDED
, 0, 0);
864 case MESessionTopologyStatus
:
866 UINT32 topo_status
= 0;
867 IMFTopology
*topology
;
870 IMFMediaEvent_GetUINT32(event
, &MF_EVENT_TOPOLOGY_STATUS
, &topo_status
);
871 if (topo_status
!= MF_TOPOSTATUS_READY
)
875 if (FAILED(IMFMediaEvent_GetValue(event
, &value
)))
878 if (value
.vt
!= VT_UNKNOWN
)
880 PropVariantClear(&value
);
884 topology
= (IMFTopology
*)value
.punkVal
;
886 EnterCriticalSection(&engine
->cs
);
888 engine
->ready_state
= MF_MEDIA_ENGINE_READY_HAVE_METADATA
;
890 media_engine_get_frame_size(engine
, topology
);
892 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE
, 0, 0);
893 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA
, 0, 0);
895 engine
->ready_state
= MF_MEDIA_ENGINE_READY_HAVE_ENOUGH_DATA
;
897 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_LOADEDDATA
, 0, 0);
898 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_CANPLAY
, 0, 0);
900 LeaveCriticalSection(&engine
->cs
);
902 PropVariantClear(&value
);
906 case MESessionStarted
:
908 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PLAYING
, 0, 0);
912 EnterCriticalSection(&engine
->cs
);
913 media_engine_set_flag(engine
, FLAGS_ENGINE_FIRST_FRAME
, FALSE
);
914 media_engine_set_flag(engine
, FLAGS_ENGINE_IS_ENDED
, TRUE
);
915 engine
->video_frame
.pts
= MINLONGLONG
;
916 LeaveCriticalSection(&engine
->cs
);
918 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_ENDED
, 0, 0);
925 IMFMediaEvent_Release(event
);
927 if (FAILED(hr
= IMFMediaSession_BeginGetEvent(engine
->session
, iface
, NULL
)))
928 WARN("Failed to subscribe to session events, hr %#x.\n", hr
);
933 static const IMFAsyncCallbackVtbl media_engine_session_events_vtbl
=
935 media_engine_callback_QueryInterface
,
936 media_engine_session_events_AddRef
,
937 media_engine_session_events_Release
,
938 media_engine_callback_GetParameters
,
939 media_engine_session_events_Invoke
,
942 static ULONG WINAPI
media_engine_load_handler_AddRef(IMFAsyncCallback
*iface
)
944 struct media_engine
*engine
= impl_from_load_handler_IMFAsyncCallback(iface
);
945 return IMFMediaEngine_AddRef(&engine
->IMFMediaEngine_iface
);
948 static ULONG WINAPI
media_engine_load_handler_Release(IMFAsyncCallback
*iface
)
950 struct media_engine
*engine
= impl_from_load_handler_IMFAsyncCallback(iface
);
951 return IMFMediaEngine_Release(&engine
->IMFMediaEngine_iface
);
954 static HRESULT
media_engine_create_source_node(IMFMediaSource
*source
, IMFPresentationDescriptor
*pd
, IMFStreamDescriptor
*sd
,
955 IMFTopologyNode
**node
)
959 if (FAILED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE
, node
)))
962 IMFTopologyNode_SetUnknown(*node
, &MF_TOPONODE_SOURCE
, (IUnknown
*)source
);
963 IMFTopologyNode_SetUnknown(*node
, &MF_TOPONODE_PRESENTATION_DESCRIPTOR
, (IUnknown
*)pd
);
964 IMFTopologyNode_SetUnknown(*node
, &MF_TOPONODE_STREAM_DESCRIPTOR
, (IUnknown
*)sd
);
969 static HRESULT
media_engine_create_audio_renderer(struct media_engine
*engine
, IMFTopologyNode
**node
)
971 unsigned int category
, role
;
972 IMFActivate
*sar_activate
;
977 if (FAILED(hr
= MFCreateAudioRendererActivate(&sar_activate
)))
980 /* Configuration attributes keys differ between Engine and SAR. */
981 if (SUCCEEDED(IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_CATEGORY
, &category
)))
982 IMFActivate_SetUINT32(sar_activate
, &MF_AUDIO_RENDERER_ATTRIBUTE_STREAM_CATEGORY
, category
);
983 if (SUCCEEDED(IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_AUDIO_ENDPOINT_ROLE
, &role
)))
984 IMFActivate_SetUINT32(sar_activate
, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE
, role
);
986 if (SUCCEEDED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE
, node
)))
988 IMFTopologyNode_SetObject(*node
, (IUnknown
*)sar_activate
);
989 IMFTopologyNode_SetUINT32(*node
, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE
, FALSE
);
992 IMFActivate_Release(sar_activate
);
997 static HRESULT
media_engine_create_video_renderer(struct media_engine
*engine
, IMFTopologyNode
**node
)
999 DXGI_FORMAT output_format
;
1000 IMFMediaType
*media_type
;
1001 IMFActivate
*activate
;
1007 if (FAILED(IMFAttributes_GetUINT32(engine
->attributes
, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT
, &output_format
)))
1009 WARN("Output format was not specified.\n");
1013 memcpy(&subtype
, &MFVideoFormat_Base
, sizeof(subtype
));
1014 if (!(subtype
.Data1
= MFMapDXGIFormatToDX9Format(output_format
)))
1016 WARN("Unrecognized output format %#x.\n", output_format
);
1020 if (FAILED(hr
= MFCreateMediaType(&media_type
)))
1023 IMFMediaType_SetGUID(media_type
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Video
);
1024 IMFMediaType_SetGUID(media_type
, &MF_MT_SUBTYPE
, &subtype
);
1026 hr
= MFCreateSampleGrabberSinkActivate(media_type
, &engine
->grabber_callback
, &activate
);
1027 IMFMediaType_Release(media_type
);
1031 if (SUCCEEDED(hr
= MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE
, node
)))
1033 IMFTopologyNode_SetObject(*node
, (IUnknown
*)activate
);
1034 IMFTopologyNode_SetUINT32(*node
, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE
, FALSE
);
1037 IMFActivate_Release(activate
);
1039 engine
->video_frame
.output_format
= output_format
;
1044 static HRESULT
media_engine_create_topology(struct media_engine
*engine
, IMFMediaSource
*source
)
1046 IMFStreamDescriptor
*sd_audio
= NULL
, *sd_video
= NULL
;
1047 unsigned int stream_count
= 0, i
;
1048 IMFPresentationDescriptor
*pd
;
1049 IMFTopology
*topology
;
1053 media_engine_release_video_frame_resources(engine
);
1055 if (FAILED(hr
= IMFMediaSource_CreatePresentationDescriptor(source
, &pd
)))
1058 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(pd
, &stream_count
)))
1059 WARN("Failed to get stream count, hr %#x.\n", hr
);
1061 /* Enable first video stream and first audio stream. */
1063 for (i
= 0; i
< stream_count
; ++i
)
1065 IMFMediaTypeHandler
*type_handler
;
1066 IMFStreamDescriptor
*sd
;
1069 IMFPresentationDescriptor_DeselectStream(pd
, i
);
1071 if (sd_audio
&& sd_video
)
1074 IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd
, i
, &selected
, &sd
);
1076 if (SUCCEEDED(IMFStreamDescriptor_GetMediaTypeHandler(sd
, &type_handler
)))
1080 IMFMediaTypeHandler_GetMajorType(type_handler
, &major
);
1082 if (IsEqualGUID(&major
, &MFMediaType_Audio
) && !sd_audio
)
1085 IMFStreamDescriptor_AddRef(sd_audio
);
1086 IMFPresentationDescriptor_SelectStream(pd
, i
);
1088 else if (IsEqualGUID(&major
, &MFMediaType_Video
) && !sd_video
&& !(engine
->flags
& MF_MEDIA_ENGINE_AUDIOONLY
))
1091 IMFStreamDescriptor_AddRef(sd_video
);
1092 IMFPresentationDescriptor_SelectStream(pd
, i
);
1095 IMFMediaTypeHandler_Release(type_handler
);
1099 if (!sd_video
&& !sd_audio
)
1101 IMFPresentationDescriptor_Release(pd
);
1102 return E_UNEXPECTED
;
1105 media_engine_set_flag(engine
, FLAGS_ENGINE_HAS_VIDEO
, !!sd_video
);
1106 media_engine_set_flag(engine
, FLAGS_ENGINE_HAS_AUDIO
, !!sd_audio
);
1108 /* Assume live source if duration was not provided. */
1109 if (SUCCEEDED(IMFPresentationDescriptor_GetUINT64(pd
, &MF_PD_DURATION
, &duration
)))
1111 /* Convert 100ns to seconds. */
1112 engine
->duration
= duration
/ 10000000;
1115 engine
->duration
= INFINITY
;
1117 if (SUCCEEDED(hr
= MFCreateTopology(&topology
)))
1119 IMFTopologyNode
*sar_node
= NULL
, *audio_src
= NULL
;
1120 IMFTopologyNode
*grabber_node
= NULL
, *video_src
= NULL
;
1124 if (FAILED(hr
= media_engine_create_source_node(source
, pd
, sd_audio
, &audio_src
)))
1125 WARN("Failed to create audio source node, hr %#x.\n", hr
);
1127 if (FAILED(hr
= media_engine_create_audio_renderer(engine
, &sar_node
)))
1128 WARN("Failed to create audio renderer node, hr %#x.\n", hr
);
1130 if (sar_node
&& audio_src
)
1132 IMFTopology_AddNode(topology
, audio_src
);
1133 IMFTopology_AddNode(topology
, sar_node
);
1134 IMFTopologyNode_ConnectOutput(audio_src
, 0, sar_node
, 0);
1138 IMFTopologyNode_Release(sar_node
);
1140 IMFTopologyNode_Release(audio_src
);
1143 if (SUCCEEDED(hr
) && sd_video
)
1145 if (FAILED(hr
= media_engine_create_source_node(source
, pd
, sd_video
, &video_src
)))
1146 WARN("Failed to create video source node, hr %#x.\n", hr
);
1148 if (FAILED(hr
= media_engine_create_video_renderer(engine
, &grabber_node
)))
1149 WARN("Failed to create video grabber node, hr %#x.\n", hr
);
1151 if (grabber_node
&& video_src
)
1153 IMFTopology_AddNode(topology
, video_src
);
1154 IMFTopology_AddNode(topology
, grabber_node
);
1155 IMFTopologyNode_ConnectOutput(video_src
, 0, grabber_node
, 0);
1159 IMFTopologyNode_GetTopoNodeID(video_src
, &engine
->video_frame
.node_id
);
1162 IMFTopologyNode_Release(grabber_node
);
1164 IMFTopologyNode_Release(video_src
);
1167 IMFTopology_SetUINT32(topology
, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES
, TRUE
);
1170 hr
= IMFMediaSession_SetTopology(engine
->session
, MFSESSION_SETTOPOLOGY_IMMEDIATE
, topology
);
1174 IMFTopology_Release(topology
);
1177 IMFStreamDescriptor_Release(sd_video
);
1179 IMFStreamDescriptor_Release(sd_audio
);
1181 IMFPresentationDescriptor_Release(pd
);
1186 static void media_engine_start_playback(struct media_engine
*engine
)
1191 IMFMediaSession_Start(engine
->session
, &GUID_NULL
, &var
);
1194 static HRESULT WINAPI
media_engine_load_handler_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1196 struct media_engine
*engine
= impl_from_load_handler_IMFAsyncCallback(iface
);
1197 unsigned int start_playback
;
1198 MF_OBJECT_TYPE obj_type
;
1199 IMFMediaSource
*source
;
1200 IUnknown
*object
= NULL
;
1203 EnterCriticalSection(&engine
->cs
);
1205 engine
->network_state
= MF_MEDIA_ENGINE_NETWORK_LOADING
;
1206 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_LOADSTART
, 0, 0);
1208 start_playback
= engine
->flags
& FLAGS_ENGINE_PLAY_PENDING
;
1209 media_engine_set_flag(engine
, FLAGS_ENGINE_SOURCE_PENDING
| FLAGS_ENGINE_PLAY_PENDING
, FALSE
);
1211 if (FAILED(hr
= IMFSourceResolver_EndCreateObjectFromURL(engine
->resolver
, result
, &obj_type
, &object
)))
1212 WARN("Failed to create source object, hr %#x.\n", hr
);
1216 if (SUCCEEDED(hr
= IUnknown_QueryInterface(object
, &IID_IMFMediaSource
, (void **)&source
)))
1218 hr
= media_engine_create_topology(engine
, source
);
1219 IMFMediaSource_Release(source
);
1221 IUnknown_Release(object
);
1226 engine
->network_state
= MF_MEDIA_ENGINE_NETWORK_IDLE
;
1228 media_engine_start_playback(engine
);
1232 engine
->network_state
= MF_MEDIA_ENGINE_NETWORK_NO_SOURCE
;
1233 engine
->error_code
= MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED
;
1234 engine
->extended_code
= hr
;
1235 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_ERROR
, engine
->error_code
,
1236 engine
->extended_code
);
1239 LeaveCriticalSection(&engine
->cs
);
1244 static const IMFAsyncCallbackVtbl media_engine_load_handler_vtbl
=
1246 media_engine_callback_QueryInterface
,
1247 media_engine_load_handler_AddRef
,
1248 media_engine_load_handler_Release
,
1249 media_engine_callback_GetParameters
,
1250 media_engine_load_handler_Invoke
,
1253 static HRESULT WINAPI
media_engine_QueryInterface(IMFMediaEngine
*iface
, REFIID riid
, void **obj
)
1255 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1257 if (IsEqualIID(riid
, &IID_IMFMediaEngine
) ||
1258 IsEqualIID(riid
, &IID_IUnknown
))
1261 IMFMediaEngine_AddRef(iface
);
1265 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
1267 return E_NOINTERFACE
;
1270 static ULONG WINAPI
media_engine_AddRef(IMFMediaEngine
*iface
)
1272 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1273 ULONG refcount
= InterlockedIncrement(&engine
->refcount
);
1275 TRACE("%p, refcount %u.\n", iface
, refcount
);
1280 static void free_media_engine(struct media_engine
*engine
)
1282 if (engine
->callback
)
1283 IMFMediaEngineNotify_Release(engine
->callback
);
1285 IMFPresentationClock_Release(engine
->clock
);
1286 if (engine
->session
)
1287 IMFMediaSession_Release(engine
->session
);
1288 if (engine
->attributes
)
1289 IMFAttributes_Release(engine
->attributes
);
1290 if (engine
->resolver
)
1291 IMFSourceResolver_Release(engine
->resolver
);
1292 media_engine_release_video_frame_resources(engine
);
1293 if (engine
->device_manager
)
1295 IMFDXGIDeviceManager_CloseDeviceHandle(engine
->device_manager
, engine
->device_handle
);
1296 IMFDXGIDeviceManager_Release(engine
->device_manager
);
1298 SysFreeString(engine
->current_source
);
1299 DeleteCriticalSection(&engine
->cs
);
1300 free(engine
->video_frame
.buffer
);
1304 static ULONG WINAPI
media_engine_Release(IMFMediaEngine
*iface
)
1306 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1307 ULONG refcount
= InterlockedDecrement(&engine
->refcount
);
1309 TRACE("%p, refcount %u.\n", iface
, refcount
);
1312 free_media_engine(engine
);
1317 static HRESULT WINAPI
media_engine_GetError(IMFMediaEngine
*iface
, IMFMediaError
**error
)
1319 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1322 TRACE("%p, %p.\n", iface
, error
);
1326 EnterCriticalSection(&engine
->cs
);
1327 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1329 else if (engine
->error_code
)
1331 if (SUCCEEDED(hr
= create_media_error(error
)))
1333 IMFMediaError_SetErrorCode(*error
, engine
->error_code
);
1334 IMFMediaError_SetExtendedErrorCode(*error
, engine
->extended_code
);
1337 LeaveCriticalSection(&engine
->cs
);
1342 static HRESULT WINAPI
media_engine_SetErrorCode(IMFMediaEngine
*iface
, MF_MEDIA_ENGINE_ERR code
)
1344 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1347 TRACE("%p, %u.\n", iface
, code
);
1349 if ((unsigned int)code
> MF_MEDIA_ENGINE_ERR_ENCRYPTED
)
1350 return E_INVALIDARG
;
1352 EnterCriticalSection(&engine
->cs
);
1353 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1356 engine
->error_code
= code
;
1357 LeaveCriticalSection(&engine
->cs
);
1362 static HRESULT WINAPI
media_engine_SetSourceElements(IMFMediaEngine
*iface
, IMFMediaEngineSrcElements
*elements
)
1364 FIXME("(%p, %p): stub.\n", iface
, elements
);
1369 static HRESULT WINAPI
media_engine_SetSource(IMFMediaEngine
*iface
, BSTR url
)
1371 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1374 TRACE("%p, %s.\n", iface
, debugstr_w(url
));
1376 EnterCriticalSection(&engine
->cs
);
1378 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1382 SysFreeString(engine
->current_source
);
1383 engine
->current_source
= NULL
;
1385 engine
->current_source
= SysAllocString(url
);
1387 engine
->ready_state
= MF_MEDIA_ENGINE_READY_HAVE_NOTHING
;
1389 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS
, 0, 0);
1391 engine
->network_state
= MF_MEDIA_ENGINE_NETWORK_NO_SOURCE
;
1395 IPropertyStore
*props
= NULL
;
1398 flags
= MF_RESOLUTION_MEDIASOURCE
;
1399 if (engine
->flags
& MF_MEDIA_ENGINE_DISABLE_LOCAL_PLUGINS
)
1400 flags
|= MF_RESOLUTION_DISABLE_LOCAL_PLUGINS
;
1402 IMFAttributes_GetUnknown(engine
->attributes
, &MF_MEDIA_ENGINE_SOURCE_RESOLVER_CONFIG_STORE
,
1403 &IID_IPropertyStore
, (void **)&props
);
1404 hr
= IMFSourceResolver_BeginCreateObjectFromURL(engine
->resolver
, url
, flags
, props
, NULL
,
1405 &engine
->load_handler
, NULL
);
1407 media_engine_set_flag(engine
, FLAGS_ENGINE_SOURCE_PENDING
, TRUE
);
1410 IPropertyStore_Release(props
);
1414 LeaveCriticalSection(&engine
->cs
);
1419 static HRESULT WINAPI
media_engine_GetCurrentSource(IMFMediaEngine
*iface
, BSTR
*url
)
1421 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1424 TRACE("%p, %p.\n", iface
, url
);
1428 EnterCriticalSection(&engine
->cs
);
1429 if (engine
->current_source
)
1431 if (!(*url
= SysAllocString(engine
->current_source
)))
1434 LeaveCriticalSection(&engine
->cs
);
1439 static USHORT WINAPI
media_engine_GetNetworkState(IMFMediaEngine
*iface
)
1441 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1443 TRACE("%p.\n", iface
);
1445 return engine
->network_state
;
1448 static MF_MEDIA_ENGINE_PRELOAD WINAPI
media_engine_GetPreload(IMFMediaEngine
*iface
)
1450 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1451 MF_MEDIA_ENGINE_PRELOAD preload
;
1453 TRACE("%p.\n", iface
);
1455 EnterCriticalSection(&engine
->cs
);
1456 preload
= engine
->preload
;
1457 LeaveCriticalSection(&engine
->cs
);
1462 static HRESULT WINAPI
media_engine_SetPreload(IMFMediaEngine
*iface
, MF_MEDIA_ENGINE_PRELOAD preload
)
1464 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1466 TRACE("%p, %d.\n", iface
, preload
);
1468 EnterCriticalSection(&engine
->cs
);
1469 engine
->preload
= preload
;
1470 LeaveCriticalSection(&engine
->cs
);
1475 static HRESULT WINAPI
media_engine_GetBuffered(IMFMediaEngine
*iface
, IMFMediaTimeRange
**range
)
1477 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1480 TRACE("%p, %p.\n", iface
, range
);
1482 if (FAILED(hr
= create_time_range(range
)))
1485 EnterCriticalSection(&engine
->cs
);
1486 if (!isnan(engine
->duration
))
1487 hr
= IMFMediaTimeRange_AddRange(*range
, 0.0, engine
->duration
);
1488 LeaveCriticalSection(&engine
->cs
);
1493 static HRESULT WINAPI
media_engine_Load(IMFMediaEngine
*iface
)
1495 FIXME("(%p): stub.\n", iface
);
1500 static HRESULT WINAPI
media_engine_CanPlayType(IMFMediaEngine
*iface
, BSTR type
, MF_MEDIA_ENGINE_CANPLAY
*answer
)
1502 FIXME("(%p, %s, %p): stub.\n", iface
, debugstr_w(type
), answer
);
1507 static USHORT WINAPI
media_engine_GetReadyState(IMFMediaEngine
*iface
)
1509 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1510 unsigned short state
;
1512 TRACE("%p.\n", iface
);
1514 EnterCriticalSection(&engine
->cs
);
1515 state
= engine
->ready_state
;
1516 LeaveCriticalSection(&engine
->cs
);
1521 static BOOL WINAPI
media_engine_IsSeeking(IMFMediaEngine
*iface
)
1523 FIXME("(%p): stub.\n", iface
);
1528 static double WINAPI
media_engine_GetCurrentTime(IMFMediaEngine
*iface
)
1530 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1534 TRACE("%p.\n", iface
);
1536 EnterCriticalSection(&engine
->cs
);
1537 if (engine
->flags
& FLAGS_ENGINE_IS_ENDED
)
1539 ret
= engine
->duration
;
1541 else if (SUCCEEDED(IMFPresentationClock_GetTime(engine
->clock
, &clocktime
)))
1543 ret
= (double)clocktime
/ 10000000.0;
1545 LeaveCriticalSection(&engine
->cs
);
1550 static HRESULT WINAPI
media_engine_SetCurrentTime(IMFMediaEngine
*iface
, double time
)
1552 FIXME("(%p, %f): stub.\n", iface
, time
);
1557 static double WINAPI
media_engine_GetStartTime(IMFMediaEngine
*iface
)
1559 FIXME("(%p): stub.\n", iface
);
1564 static double WINAPI
media_engine_GetDuration(IMFMediaEngine
*iface
)
1566 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1569 TRACE("%p.\n", iface
);
1571 EnterCriticalSection(&engine
->cs
);
1572 value
= engine
->duration
;
1573 LeaveCriticalSection(&engine
->cs
);
1578 static BOOL WINAPI
media_engine_IsPaused(IMFMediaEngine
*iface
)
1580 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1583 TRACE("%p.\n", iface
);
1585 EnterCriticalSection(&engine
->cs
);
1586 value
= !!(engine
->flags
& FLAGS_ENGINE_PAUSED
);
1587 LeaveCriticalSection(&engine
->cs
);
1592 static double WINAPI
media_engine_GetDefaultPlaybackRate(IMFMediaEngine
*iface
)
1594 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1597 TRACE("%p.\n", iface
);
1599 EnterCriticalSection(&engine
->cs
);
1600 rate
= engine
->default_playback_rate
;
1601 LeaveCriticalSection(&engine
->cs
);
1606 static HRESULT WINAPI
media_engine_SetDefaultPlaybackRate(IMFMediaEngine
*iface
, double rate
)
1608 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1611 TRACE("%p, %f.\n", iface
, rate
);
1613 EnterCriticalSection(&engine
->cs
);
1614 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1616 else if (engine
->default_playback_rate
!= rate
)
1618 engine
->default_playback_rate
= rate
;
1619 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_RATECHANGE
, 0, 0);
1621 LeaveCriticalSection(&engine
->cs
);
1626 static double WINAPI
media_engine_GetPlaybackRate(IMFMediaEngine
*iface
)
1628 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1631 TRACE("%p.\n", iface
);
1633 EnterCriticalSection(&engine
->cs
);
1634 rate
= engine
->playback_rate
;
1635 LeaveCriticalSection(&engine
->cs
);
1640 static HRESULT WINAPI
media_engine_SetPlaybackRate(IMFMediaEngine
*iface
, double rate
)
1642 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1645 TRACE("%p, %f.\n", iface
, rate
);
1647 EnterCriticalSection(&engine
->cs
);
1648 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1650 else if (engine
->playback_rate
!= rate
)
1652 engine
->playback_rate
= rate
;
1653 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_RATECHANGE
, 0, 0);
1655 LeaveCriticalSection(&engine
->cs
);
1660 static HRESULT WINAPI
media_engine_GetPlayed(IMFMediaEngine
*iface
, IMFMediaTimeRange
**played
)
1662 FIXME("(%p, %p): stub.\n", iface
, played
);
1667 static HRESULT WINAPI
media_engine_GetSeekable(IMFMediaEngine
*iface
, IMFMediaTimeRange
**seekable
)
1669 FIXME("(%p, %p): stub.\n", iface
, seekable
);
1674 static BOOL WINAPI
media_engine_IsEnded(IMFMediaEngine
*iface
)
1676 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1679 TRACE("%p.\n", iface
);
1681 EnterCriticalSection(&engine
->cs
);
1682 value
= !!(engine
->flags
& FLAGS_ENGINE_IS_ENDED
);
1683 LeaveCriticalSection(&engine
->cs
);
1688 static BOOL WINAPI
media_engine_GetAutoPlay(IMFMediaEngine
*iface
)
1690 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1693 TRACE("%p.\n", iface
);
1695 EnterCriticalSection(&engine
->cs
);
1696 value
= !!(engine
->flags
& FLAGS_ENGINE_AUTO_PLAY
);
1697 LeaveCriticalSection(&engine
->cs
);
1702 static HRESULT WINAPI
media_engine_SetAutoPlay(IMFMediaEngine
*iface
, BOOL autoplay
)
1704 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1706 FIXME("(%p, %d): stub.\n", iface
, autoplay
);
1708 EnterCriticalSection(&engine
->cs
);
1709 media_engine_set_flag(engine
, FLAGS_ENGINE_AUTO_PLAY
, autoplay
);
1710 LeaveCriticalSection(&engine
->cs
);
1715 static BOOL WINAPI
media_engine_GetLoop(IMFMediaEngine
*iface
)
1717 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1720 TRACE("%p.\n", iface
);
1722 EnterCriticalSection(&engine
->cs
);
1723 value
= !!(engine
->flags
& FLAGS_ENGINE_LOOP
);
1724 LeaveCriticalSection(&engine
->cs
);
1729 static HRESULT WINAPI
media_engine_SetLoop(IMFMediaEngine
*iface
, BOOL loop
)
1731 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1733 FIXME("(%p, %d): stub.\n", iface
, loop
);
1735 EnterCriticalSection(&engine
->cs
);
1736 media_engine_set_flag(engine
, FLAGS_ENGINE_LOOP
, loop
);
1737 LeaveCriticalSection(&engine
->cs
);
1742 static HRESULT WINAPI
media_engine_Play(IMFMediaEngine
*iface
)
1744 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1746 TRACE("%p.\n", iface
);
1748 EnterCriticalSection(&engine
->cs
);
1750 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS
, 0, 0);
1752 if (!(engine
->flags
& FLAGS_ENGINE_WAITING
))
1754 media_engine_set_flag(engine
, FLAGS_ENGINE_PAUSED
| FLAGS_ENGINE_IS_ENDED
, FALSE
);
1755 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PLAY
, 0, 0);
1757 if (!(engine
->flags
& FLAGS_ENGINE_SOURCE_PENDING
))
1758 media_engine_start_playback(engine
);
1760 media_engine_set_flag(engine
, FLAGS_ENGINE_PLAY_PENDING
, TRUE
);
1762 media_engine_set_flag(engine
, FLAGS_ENGINE_WAITING
, TRUE
);
1765 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_WAITING
, 0, 0);
1767 LeaveCriticalSection(&engine
->cs
);
1772 static HRESULT WINAPI
media_engine_Pause(IMFMediaEngine
*iface
)
1774 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1776 TRACE("%p.\n", iface
);
1778 EnterCriticalSection(&engine
->cs
);
1780 if (!(engine
->flags
& FLAGS_ENGINE_PAUSED
))
1782 media_engine_set_flag(engine
, FLAGS_ENGINE_WAITING
| FLAGS_ENGINE_IS_ENDED
, FALSE
);
1783 media_engine_set_flag(engine
, FLAGS_ENGINE_PAUSED
, TRUE
);
1785 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_TIMEUPDATE
, 0, 0);
1786 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PAUSE
, 0, 0);
1789 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS
, 0, 0);
1791 LeaveCriticalSection(&engine
->cs
);
1796 static BOOL WINAPI
media_engine_GetMuted(IMFMediaEngine
*iface
)
1798 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1801 TRACE("%p.\n", iface
);
1803 EnterCriticalSection(&engine
->cs
);
1804 ret
= !!(engine
->flags
& FLAGS_ENGINE_MUTED
);
1805 LeaveCriticalSection(&engine
->cs
);
1810 static HRESULT WINAPI
media_engine_SetMuted(IMFMediaEngine
*iface
, BOOL muted
)
1812 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1815 TRACE("%p, %d.\n", iface
, muted
);
1817 EnterCriticalSection(&engine
->cs
);
1818 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1820 else if (!!(engine
->flags
& FLAGS_ENGINE_MUTED
) ^ !!muted
)
1822 media_engine_set_flag(engine
, FLAGS_ENGINE_MUTED
, muted
);
1823 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE
, 0, 0);
1825 LeaveCriticalSection(&engine
->cs
);
1830 static double WINAPI
media_engine_GetVolume(IMFMediaEngine
*iface
)
1832 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1835 TRACE("%p.\n", iface
);
1837 EnterCriticalSection(&engine
->cs
);
1838 volume
= engine
->volume
;
1839 LeaveCriticalSection(&engine
->cs
);
1844 static HRESULT WINAPI
media_engine_SetVolume(IMFMediaEngine
*iface
, double volume
)
1846 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1849 TRACE("%p, %f.\n", iface
, volume
);
1851 EnterCriticalSection(&engine
->cs
);
1852 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1854 else if (volume
!= engine
->volume
)
1856 engine
->volume
= volume
;
1857 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE
, 0, 0);
1859 LeaveCriticalSection(&engine
->cs
);
1864 static BOOL WINAPI
media_engine_HasVideo(IMFMediaEngine
*iface
)
1866 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1869 TRACE("%p.\n", iface
);
1871 EnterCriticalSection(&engine
->cs
);
1872 value
= !!(engine
->flags
& FLAGS_ENGINE_HAS_VIDEO
);
1873 LeaveCriticalSection(&engine
->cs
);
1878 static BOOL WINAPI
media_engine_HasAudio(IMFMediaEngine
*iface
)
1880 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1883 TRACE("%p.\n", iface
);
1885 EnterCriticalSection(&engine
->cs
);
1886 value
= !!(engine
->flags
& FLAGS_ENGINE_HAS_AUDIO
);
1887 LeaveCriticalSection(&engine
->cs
);
1892 static HRESULT WINAPI
media_engine_GetNativeVideoSize(IMFMediaEngine
*iface
, DWORD
*cx
, DWORD
*cy
)
1894 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1897 TRACE("%p, %p, %p.\n", iface
, cx
, cy
);
1900 return E_INVALIDARG
;
1902 EnterCriticalSection(&engine
->cs
);
1904 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1906 else if (!engine
->video_frame
.size
.cx
&& !engine
->video_frame
.size
.cy
)
1910 if (cx
) *cx
= engine
->video_frame
.size
.cx
;
1911 if (cy
) *cy
= engine
->video_frame
.size
.cy
;
1914 LeaveCriticalSection(&engine
->cs
);
1919 static HRESULT WINAPI
media_engine_GetVideoAspectRatio(IMFMediaEngine
*iface
, DWORD
*cx
, DWORD
*cy
)
1921 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1924 TRACE("%p, %p, %p.\n", iface
, cx
, cy
);
1927 return E_INVALIDARG
;
1929 EnterCriticalSection(&engine
->cs
);
1931 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1933 else if (!engine
->video_frame
.size
.cx
&& !engine
->video_frame
.size
.cy
)
1937 if (cx
) *cx
= engine
->video_frame
.ratio
.cx
;
1938 if (cy
) *cy
= engine
->video_frame
.ratio
.cy
;
1941 LeaveCriticalSection(&engine
->cs
);
1946 static HRESULT WINAPI
media_engine_Shutdown(IMFMediaEngine
*iface
)
1948 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
1951 FIXME("(%p): stub.\n", iface
);
1953 EnterCriticalSection(&engine
->cs
);
1954 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
1958 media_engine_set_flag(engine
, FLAGS_ENGINE_SHUT_DOWN
, TRUE
);
1959 IMFMediaSession_Shutdown(engine
->session
);
1961 LeaveCriticalSection(&engine
->cs
);
1966 static void set_rect(struct rect
*rect
, float left
, float top
, float right
, float bottom
)
1970 rect
->right
= right
;
1971 rect
->bottom
= bottom
;
1974 static void media_engine_adjust_destination_for_ratio(const struct media_engine
*engine
,
1975 struct rect
*src_n
, struct rect
*dst
)
1977 float dst_width
= dst
->right
- dst
->left
, dst_height
= dst
->bottom
- dst
->top
;
1978 D3D11_TEXTURE2D_DESC source_desc
;
1979 float src_width
, src_height
;
1982 ID3D11Texture2D_GetDesc(engine
->video_frame
.d3d11
.source
, &source_desc
);
1983 set_rect(&src
, src_n
->left
* source_desc
.Width
, src_n
->top
* source_desc
.Height
,
1984 src_n
->right
* source_desc
.Width
, src_n
->bottom
* source_desc
.Height
);
1986 src_width
= src
.right
- src
.left
;
1987 src_height
= src
.bottom
- src
.top
;
1989 if (src_width
* dst_height
> dst_width
* src_height
)
1991 /* src is "wider" than dst. */
1992 float dst_center
= (dst
->top
+ dst
->bottom
) / 2.0f
;
1993 float scaled_height
= src_height
* dst_width
/ src_width
;
1995 dst
->top
= dst_center
- scaled_height
/ 2.0f
;
1996 dst
->bottom
= dst
->top
+ scaled_height
;
1998 else if (src_width
* dst_height
< dst_width
* src_height
)
2000 /* src is "taller" than dst. */
2001 float dst_center
= (dst
->left
+ dst
->right
) / 2.0f
;
2002 float scaled_width
= src_width
* dst_height
/ src_height
;
2004 dst
->left
= dst_center
- scaled_width
/ 2.0f
;
2005 dst
->right
= dst
->left
+ scaled_width
;
2009 static void media_engine_update_d3d11_frame_surface(ID3D11DeviceContext
*context
, struct media_engine
*engine
)
2011 D3D11_TEXTURE2D_DESC surface_desc
;
2013 if (!(engine
->flags
& FLAGS_ENGINE_NEW_FRAME
))
2016 ID3D11Texture2D_GetDesc(engine
->video_frame
.d3d11
.source
, &surface_desc
);
2018 switch (surface_desc
.Format
)
2020 case DXGI_FORMAT_B8G8R8A8_UNORM
:
2021 surface_desc
.Width
*= 4;
2024 FIXME("Unsupported format %#x.\n", surface_desc
.Format
);
2025 surface_desc
.Width
= 0;
2028 if (engine
->video_frame
.buffer_size
== surface_desc
.Width
* surface_desc
.Height
)
2030 ID3D11DeviceContext_UpdateSubresource(context
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.source
,
2031 0, NULL
, engine
->video_frame
.buffer
, surface_desc
.Width
, 0);
2034 media_engine_set_flag(engine
, FLAGS_ENGINE_NEW_FRAME
, FALSE
);
2037 static HRESULT
media_engine_transfer_to_d3d11_texture(struct media_engine
*engine
, ID3D11Texture2D
*texture
,
2038 const MFVideoNormalizedRect
*src_rect
, const RECT
*dst_rect
, const MFARGB
*color
)
2040 static const float black
[] = {0.0f
, 0.0f
, 0.0f
, 0.0f
};
2041 ID3D11Device
*device
, *dst_device
;
2042 ID3D11DeviceContext
*context
;
2043 ID3D11RenderTargetView
*rtv
;
2044 unsigned int stride
, offset
;
2045 D3D11_TEXTURE2D_DESC desc
;
2046 BOOL device_mismatch
;
2047 struct vec3 quad
[4];
2049 struct rect src
, dst
;
2050 struct color backcolor
;
2054 if (FAILED(hr
= media_engine_lock_d3d_device(engine
, &device
)))
2057 if (FAILED(hr
= media_engine_create_d3d11_video_frame_resources(engine
, device
)))
2059 WARN("Failed to create d3d resources, hr %#x.\n", hr
);
2063 ID3D11Texture2D_GetDevice(texture
, &dst_device
);
2064 device_mismatch
= device
!= dst_device
;
2065 ID3D11Device_Release(dst_device
);
2067 if (device_mismatch
)
2069 WARN("Destination target from different device.\n");
2074 ID3D11Texture2D_GetDesc(texture
, &desc
);
2076 if (FAILED(hr
= ID3D11Device_CreateRenderTargetView(device
, (ID3D11Resource
*)texture
, NULL
, &rtv
)))
2078 WARN("Failed to create an rtv, hr %#x.\n", hr
);
2082 ID3D11Device_GetImmediateContext(device
, &context
);
2084 /* Whole destination is cleared, regardless of specified rectangle. */
2085 ID3D11DeviceContext_ClearRenderTargetView(context
, rtv
, black
);
2089 rect
.left
= max(0, dst_rect
->left
);
2090 rect
.top
= max(0, dst_rect
->top
);
2091 rect
.right
= min(desc
.Width
, dst_rect
->right
);
2092 rect
.bottom
= min(desc
.Height
, dst_rect
->bottom
);
2094 quad
[0].x
= 2.0f
* rect
.left
/ desc
.Width
- 1.0f
;
2095 quad
[0].y
= -2.0f
* rect
.bottom
/ desc
.Height
+ 1.0f
;
2098 quad
[1].x
= quad
[0].x
;
2099 quad
[1].y
= -2.0f
* rect
.top
/ desc
.Height
+ 1.0f
;
2102 quad
[2].x
= 2.0f
* rect
.right
/ desc
.Width
- 1.0f
;
2103 quad
[2].y
= quad
[0].y
;
2106 quad
[3].x
= quad
[2].x
;
2107 quad
[3].y
= quad
[1].y
;
2110 set_rect(&dst
, dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
);
2114 memcpy(quad
, fullquad
, sizeof(quad
));
2115 set_rect(&dst
, 0.0f
, 0.0f
, desc
.Width
, desc
.Height
);
2119 memcpy(&src
, src_rect
, sizeof(src
));
2121 set_rect(&src
, 0.0f
, 0.0f
, 1.0f
, 1.0f
);
2123 media_engine_adjust_destination_for_ratio(engine
, &src
, &dst
);
2125 if (memcmp(quad
, engine
->video_frame
.d3d11
.quad
, sizeof(quad
)))
2127 memcpy(engine
->video_frame
.d3d11
.quad
, quad
, sizeof(quad
));
2128 ID3D11DeviceContext_UpdateSubresource(context
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.vb
, 0, NULL
, quad
, 0, 0);
2133 backcolor
.r
= color
->rgbRed
/ 255.0f
;
2134 backcolor
.g
= color
->rgbGreen
/ 255.0f
;
2135 backcolor
.b
= color
->rgbBlue
/ 255.0f
;
2136 backcolor
.a
= color
->rgbAlpha
/ 255.0f
;
2139 memcpy(&backcolor
, black
, sizeof(backcolor
));
2141 if (memcmp(&dst
, &engine
->video_frame
.d3d11
.cb
.dst
, sizeof(dst
)) ||
2142 memcmp(&src
, &engine
->video_frame
.d3d11
.cb
.src
, sizeof(src
)) ||
2143 memcmp(&backcolor
, &engine
->video_frame
.d3d11
.cb
.backcolor
, sizeof(backcolor
)))
2145 memcpy(&engine
->video_frame
.d3d11
.cb
.dst
, &dst
, sizeof(dst
));
2146 memcpy(&engine
->video_frame
.d3d11
.cb
.src
, &src
, sizeof(src
));
2147 memcpy(&engine
->video_frame
.d3d11
.cb
.backcolor
, &backcolor
, sizeof(backcolor
));
2149 ID3D11DeviceContext_UpdateSubresource(context
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.ps_cb
, 0, NULL
,
2150 &engine
->video_frame
.d3d11
.cb
, 0, 0);
2153 /* Update with new frame contents */
2154 media_engine_update_d3d11_frame_surface(context
, engine
);
2158 vp
.Width
= desc
.Width
;
2159 vp
.Height
= desc
.Height
;
2162 ID3D11DeviceContext_RSSetViewports(context
, 1, &vp
);
2164 ID3D11DeviceContext_IASetInputLayout(context
, engine
->video_frame
.d3d11
.input_layout
);
2165 ID3D11DeviceContext_IASetPrimitiveTopology(context
, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP
);
2166 stride
= sizeof(*quad
);
2168 ID3D11DeviceContext_IASetVertexBuffers(context
, 0, 1, &engine
->video_frame
.d3d11
.vb
, &stride
, &offset
);
2169 ID3D11DeviceContext_VSSetShader(context
, engine
->video_frame
.d3d11
.vs
, NULL
, 0);
2170 ID3D11DeviceContext_PSSetShader(context
, engine
->video_frame
.d3d11
.ps
, NULL
, 0);
2171 ID3D11DeviceContext_PSSetShaderResources(context
, 0, 1, &engine
->video_frame
.d3d11
.srv
);
2172 ID3D11DeviceContext_PSSetConstantBuffers(context
, 0, 1, &engine
->video_frame
.d3d11
.ps_cb
);
2173 ID3D11DeviceContext_PSSetSamplers(context
, 0, 1, &engine
->video_frame
.d3d11
.sampler
);
2174 ID3D11DeviceContext_OMSetRenderTargets(context
, 1, &rtv
, NULL
);
2176 ID3D11DeviceContext_Draw(context
, 4, 0);
2178 ID3D11RenderTargetView_Release(rtv
);
2179 ID3D11DeviceContext_Release(context
);
2182 media_engine_unlock_d3d_device(engine
, device
);
2187 static HRESULT WINAPI
media_engine_TransferVideoFrame(IMFMediaEngine
*iface
, IUnknown
*surface
,
2188 const MFVideoNormalizedRect
*src_rect
, const RECT
*dst_rect
, const MFARGB
*color
)
2190 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
2191 ID3D11Texture2D
*texture
;
2192 HRESULT hr
= E_NOINTERFACE
;
2194 TRACE("%p, %p, %s, %s, %p.\n", iface
, surface
, src_rect
? wine_dbg_sprintf("(%f,%f)-(%f,%f)",
2195 src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
) : "(null)",
2196 wine_dbgstr_rect(dst_rect
), color
);
2198 EnterCriticalSection(&engine
->cs
);
2200 if (SUCCEEDED(IUnknown_QueryInterface(surface
, &IID_ID3D11Texture2D
, (void **)&texture
)))
2202 hr
= media_engine_transfer_to_d3d11_texture(engine
, texture
, src_rect
, dst_rect
, color
);
2203 ID3D11Texture2D_Release(texture
);
2207 FIXME("Unsupported destination type.\n");
2210 LeaveCriticalSection(&engine
->cs
);
2215 static HRESULT WINAPI
media_engine_OnVideoStreamTick(IMFMediaEngine
*iface
, LONGLONG
*pts
)
2217 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
2220 TRACE("%p, %p.\n", iface
, pts
);
2222 EnterCriticalSection(&engine
->cs
);
2224 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2230 *pts
= engine
->video_frame
.pts
;
2231 hr
= *pts
== MINLONGLONG
? S_FALSE
: S_OK
;
2234 LeaveCriticalSection(&engine
->cs
);
2239 static const IMFMediaEngineVtbl media_engine_vtbl
=
2241 media_engine_QueryInterface
,
2242 media_engine_AddRef
,
2243 media_engine_Release
,
2244 media_engine_GetError
,
2245 media_engine_SetErrorCode
,
2246 media_engine_SetSourceElements
,
2247 media_engine_SetSource
,
2248 media_engine_GetCurrentSource
,
2249 media_engine_GetNetworkState
,
2250 media_engine_GetPreload
,
2251 media_engine_SetPreload
,
2252 media_engine_GetBuffered
,
2254 media_engine_CanPlayType
,
2255 media_engine_GetReadyState
,
2256 media_engine_IsSeeking
,
2257 media_engine_GetCurrentTime
,
2258 media_engine_SetCurrentTime
,
2259 media_engine_GetStartTime
,
2260 media_engine_GetDuration
,
2261 media_engine_IsPaused
,
2262 media_engine_GetDefaultPlaybackRate
,
2263 media_engine_SetDefaultPlaybackRate
,
2264 media_engine_GetPlaybackRate
,
2265 media_engine_SetPlaybackRate
,
2266 media_engine_GetPlayed
,
2267 media_engine_GetSeekable
,
2268 media_engine_IsEnded
,
2269 media_engine_GetAutoPlay
,
2270 media_engine_SetAutoPlay
,
2271 media_engine_GetLoop
,
2272 media_engine_SetLoop
,
2275 media_engine_GetMuted
,
2276 media_engine_SetMuted
,
2277 media_engine_GetVolume
,
2278 media_engine_SetVolume
,
2279 media_engine_HasVideo
,
2280 media_engine_HasAudio
,
2281 media_engine_GetNativeVideoSize
,
2282 media_engine_GetVideoAspectRatio
,
2283 media_engine_Shutdown
,
2284 media_engine_TransferVideoFrame
,
2285 media_engine_OnVideoStreamTick
,
2288 static HRESULT WINAPI
media_engine_grabber_callback_QueryInterface(IMFSampleGrabberSinkCallback
*iface
,
2289 REFIID riid
, void **obj
)
2291 if (IsEqualIID(riid
, &IID_IMFSampleGrabberSinkCallback
) ||
2292 IsEqualIID(riid
, &IID_IUnknown
))
2295 IMFSampleGrabberSinkCallback_AddRef(iface
);
2300 return E_NOINTERFACE
;
2303 static ULONG WINAPI
media_engine_grabber_callback_AddRef(IMFSampleGrabberSinkCallback
*iface
)
2305 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
2306 return IMFMediaEngine_AddRef(&engine
->IMFMediaEngine_iface
);
2309 static ULONG WINAPI
media_engine_grabber_callback_Release(IMFSampleGrabberSinkCallback
*iface
)
2311 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
2312 return IMFMediaEngine_Release(&engine
->IMFMediaEngine_iface
);
2315 static HRESULT WINAPI
media_engine_grabber_callback_OnClockStart(IMFSampleGrabberSinkCallback
*iface
,
2316 MFTIME systime
, LONGLONG start_offset
)
2321 static HRESULT WINAPI
media_engine_grabber_callback_OnClockStop(IMFSampleGrabberSinkCallback
*iface
,
2324 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
2326 EnterCriticalSection(&engine
->cs
);
2327 media_engine_set_flag(engine
, FLAGS_ENGINE_FIRST_FRAME
, FALSE
);
2328 engine
->video_frame
.pts
= MINLONGLONG
;
2329 LeaveCriticalSection(&engine
->cs
);
2334 static HRESULT WINAPI
media_engine_grabber_callback_OnClockPause(IMFSampleGrabberSinkCallback
*iface
,
2340 static HRESULT WINAPI
media_engine_grabber_callback_OnClockRestart(IMFSampleGrabberSinkCallback
*iface
,
2346 static HRESULT WINAPI
media_engine_grabber_callback_OnClockSetRate(IMFSampleGrabberSinkCallback
*iface
,
2347 MFTIME systime
, float rate
)
2352 static HRESULT WINAPI
media_engine_grabber_callback_OnSetPresentationClock(IMFSampleGrabberSinkCallback
*iface
,
2353 IMFPresentationClock
*clock
)
2358 static HRESULT WINAPI
media_engine_grabber_callback_OnProcessSample(IMFSampleGrabberSinkCallback
*iface
,
2359 REFGUID major_type
, DWORD sample_flags
, LONGLONG sample_time
, LONGLONG sample_duration
,
2360 const BYTE
*buffer
, DWORD buffer_size
)
2362 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
2364 EnterCriticalSection(&engine
->cs
);
2366 if (!(engine
->flags
& FLAGS_ENGINE_FIRST_FRAME
))
2368 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY
, 0, 0);
2369 media_engine_set_flag(engine
, FLAGS_ENGINE_FIRST_FRAME
, TRUE
);
2371 engine
->video_frame
.pts
= sample_time
;
2372 if (engine
->video_frame
.buffer_size
< buffer_size
)
2374 free(engine
->video_frame
.buffer
);
2375 if ((engine
->video_frame
.buffer
= malloc(buffer_size
)))
2376 engine
->video_frame
.buffer_size
= buffer_size
;
2378 if (engine
->video_frame
.buffer
)
2380 memcpy(engine
->video_frame
.buffer
, buffer
, buffer_size
);
2381 engine
->flags
|= FLAGS_ENGINE_NEW_FRAME
;
2384 LeaveCriticalSection(&engine
->cs
);
2389 static HRESULT WINAPI
media_engine_grabber_callback_OnShutdown(IMFSampleGrabberSinkCallback
*iface
)
2394 static const IMFSampleGrabberSinkCallbackVtbl media_engine_grabber_callback_vtbl
=
2396 media_engine_grabber_callback_QueryInterface
,
2397 media_engine_grabber_callback_AddRef
,
2398 media_engine_grabber_callback_Release
,
2399 media_engine_grabber_callback_OnClockStart
,
2400 media_engine_grabber_callback_OnClockStop
,
2401 media_engine_grabber_callback_OnClockPause
,
2402 media_engine_grabber_callback_OnClockRestart
,
2403 media_engine_grabber_callback_OnClockSetRate
,
2404 media_engine_grabber_callback_OnSetPresentationClock
,
2405 media_engine_grabber_callback_OnProcessSample
,
2406 media_engine_grabber_callback_OnShutdown
,
2409 static HRESULT WINAPI
media_engine_factory_QueryInterface(IMFMediaEngineClassFactory
*iface
, REFIID riid
, void **obj
)
2411 if (IsEqualIID(riid
, &IID_IMFMediaEngineClassFactory
) ||
2412 IsEqualIID(riid
, &IID_IUnknown
))
2415 IMFMediaEngineClassFactory_AddRef(iface
);
2419 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
2421 return E_NOINTERFACE
;
2424 static ULONG WINAPI
media_engine_factory_AddRef(IMFMediaEngineClassFactory
*iface
)
2429 static ULONG WINAPI
media_engine_factory_Release(IMFMediaEngineClassFactory
*iface
)
2434 static HRESULT
init_media_engine(DWORD flags
, IMFAttributes
*attributes
, struct media_engine
*engine
)
2436 DXGI_FORMAT output_format
;
2437 UINT64 playback_hwnd
;
2441 engine
->IMFMediaEngine_iface
.lpVtbl
= &media_engine_vtbl
;
2442 engine
->session_events
.lpVtbl
= &media_engine_session_events_vtbl
;
2443 engine
->load_handler
.lpVtbl
= &media_engine_load_handler_vtbl
;
2444 engine
->grabber_callback
.lpVtbl
= &media_engine_grabber_callback_vtbl
;
2445 engine
->refcount
= 1;
2446 engine
->flags
= (flags
& MF_MEDIA_ENGINE_CREATEFLAGS_MASK
) | FLAGS_ENGINE_PAUSED
;
2447 engine
->default_playback_rate
= 1.0;
2448 engine
->playback_rate
= 1.0;
2449 engine
->volume
= 1.0;
2450 engine
->duration
= NAN
;
2451 engine
->video_frame
.pts
= MINLONGLONG
;
2452 InitializeCriticalSection(&engine
->cs
);
2454 hr
= IMFAttributes_GetUnknown(attributes
, &MF_MEDIA_ENGINE_CALLBACK
, &IID_IMFMediaEngineNotify
,
2455 (void **)&engine
->callback
);
2459 IMFAttributes_GetUnknown(attributes
, &MF_MEDIA_ENGINE_DXGI_MANAGER
, &IID_IMFDXGIDeviceManager
,
2460 (void **)&engine
->device_manager
);
2462 if (FAILED(hr
= MFCreateMediaSession(NULL
, &engine
->session
)))
2465 if (FAILED(hr
= IMFMediaSession_GetClock(engine
->session
, &clock
)))
2468 hr
= IMFClock_QueryInterface(clock
, &IID_IMFPresentationClock
, (void **)&engine
->clock
);
2469 IMFClock_Release(clock
);
2473 if (FAILED(hr
= IMFMediaSession_BeginGetEvent(engine
->session
, &engine
->session_events
, NULL
)))
2476 if (FAILED(hr
= MFCreateSourceResolver(&engine
->resolver
)))
2479 if (FAILED(hr
= MFCreateAttributes(&engine
->attributes
, 0)))
2482 if (FAILED(hr
= IMFAttributes_CopyAllItems(attributes
, engine
->attributes
)))
2485 IMFAttributes_GetUINT64(attributes
, &MF_MEDIA_ENGINE_PLAYBACK_HWND
, &playback_hwnd
);
2486 hr
= IMFAttributes_GetUINT32(attributes
, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT
, &output_format
);
2487 if (playback_hwnd
) /* FIXME: handle MF_MEDIA_ENGINE_PLAYBACK_VISUAL */
2488 engine
->mode
= MEDIA_ENGINE_RENDERING_MODE
;
2492 engine
->mode
= MEDIA_ENGINE_FRAME_SERVER_MODE
;
2494 engine
->mode
= MEDIA_ENGINE_AUDIO_MODE
;
2500 static HRESULT WINAPI
media_engine_factory_CreateInstance(IMFMediaEngineClassFactory
*iface
, DWORD flags
,
2501 IMFAttributes
*attributes
, IMFMediaEngine
**engine
)
2503 struct media_engine
*object
;
2506 TRACE("%p, %#x, %p, %p.\n", iface
, flags
, attributes
, engine
);
2508 if (!attributes
|| !engine
)
2511 object
= calloc(1, sizeof(*object
));
2513 return E_OUTOFMEMORY
;
2515 hr
= init_media_engine(flags
, attributes
, object
);
2518 free_media_engine(object
);
2522 *engine
= &object
->IMFMediaEngine_iface
;
2527 static HRESULT WINAPI
media_engine_factory_CreateTimeRange(IMFMediaEngineClassFactory
*iface
,
2528 IMFMediaTimeRange
**range
)
2530 TRACE("%p, %p.\n", iface
, range
);
2532 return create_time_range(range
);
2535 static HRESULT WINAPI
media_engine_factory_CreateError(IMFMediaEngineClassFactory
*iface
, IMFMediaError
**error
)
2537 TRACE("%p, %p.\n", iface
, error
);
2539 return create_media_error(error
);
2542 static const IMFMediaEngineClassFactoryVtbl media_engine_factory_vtbl
=
2544 media_engine_factory_QueryInterface
,
2545 media_engine_factory_AddRef
,
2546 media_engine_factory_Release
,
2547 media_engine_factory_CreateInstance
,
2548 media_engine_factory_CreateTimeRange
,
2549 media_engine_factory_CreateError
,
2552 static IMFMediaEngineClassFactory media_engine_factory
= { &media_engine_factory_vtbl
};
2554 static HRESULT WINAPI
classfactory_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **obj
)
2556 TRACE("%s, %p.\n", debugstr_guid(riid
), obj
);
2558 if (IsEqualGUID(riid
, &IID_IClassFactory
) ||
2559 IsEqualGUID(riid
, &IID_IUnknown
))
2561 IClassFactory_AddRef(iface
);
2566 WARN("interface %s not implemented.\n", debugstr_guid(riid
));
2568 return E_NOINTERFACE
;
2571 static ULONG WINAPI
classfactory_AddRef(IClassFactory
*iface
)
2576 static ULONG WINAPI
classfactory_Release(IClassFactory
*iface
)
2581 static HRESULT WINAPI
classfactory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **obj
)
2583 TRACE("%p, %s, %p.\n", outer
, debugstr_guid(riid
), obj
);
2588 return CLASS_E_NOAGGREGATION
;
2590 return IMFMediaEngineClassFactory_QueryInterface(&media_engine_factory
, riid
, obj
);
2593 static HRESULT WINAPI
classfactory_LockServer(IClassFactory
*iface
, BOOL dolock
)
2595 FIXME("(%d): stub.\n", dolock
);
2599 static const IClassFactoryVtbl class_factory_vtbl
=
2601 classfactory_QueryInterface
,
2602 classfactory_AddRef
,
2603 classfactory_Release
,
2604 classfactory_CreateInstance
,
2605 classfactory_LockServer
,
2608 static IClassFactory classfactory
= { &class_factory_vtbl
};
2610 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **obj
)
2612 TRACE("%s, %s, %p.\n", debugstr_guid(clsid
), debugstr_guid(riid
), obj
);
2614 if (IsEqualGUID(clsid
, &CLSID_MFMediaEngineClassFactory
))
2615 return IClassFactory_QueryInterface(&classfactory
, riid
, obj
);
2617 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2619 return CLASS_E_CLASSNOTAVAILABLE
;