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 case DXGI_FORMAT_B8G8R8X8_UNORM
:
2022 surface_desc
.Width
*= 4;
2025 FIXME("Unsupported format %#x.\n", surface_desc
.Format
);
2026 surface_desc
.Width
= 0;
2029 if (engine
->video_frame
.buffer_size
== surface_desc
.Width
* surface_desc
.Height
)
2031 ID3D11DeviceContext_UpdateSubresource(context
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.source
,
2032 0, NULL
, engine
->video_frame
.buffer
, surface_desc
.Width
, 0);
2035 media_engine_set_flag(engine
, FLAGS_ENGINE_NEW_FRAME
, FALSE
);
2038 static HRESULT
media_engine_transfer_to_d3d11_texture(struct media_engine
*engine
, ID3D11Texture2D
*texture
,
2039 const MFVideoNormalizedRect
*src_rect
, const RECT
*dst_rect
, const MFARGB
*color
)
2041 static const float black
[] = {0.0f
, 0.0f
, 0.0f
, 0.0f
};
2042 ID3D11Device
*device
, *dst_device
;
2043 ID3D11DeviceContext
*context
;
2044 ID3D11RenderTargetView
*rtv
;
2045 unsigned int stride
, offset
;
2046 D3D11_TEXTURE2D_DESC desc
;
2047 BOOL device_mismatch
;
2048 struct vec3 quad
[4];
2050 struct rect src
, dst
;
2051 struct color backcolor
;
2055 if (FAILED(hr
= media_engine_lock_d3d_device(engine
, &device
)))
2058 if (FAILED(hr
= media_engine_create_d3d11_video_frame_resources(engine
, device
)))
2060 WARN("Failed to create d3d resources, hr %#x.\n", hr
);
2064 ID3D11Texture2D_GetDevice(texture
, &dst_device
);
2065 device_mismatch
= device
!= dst_device
;
2066 ID3D11Device_Release(dst_device
);
2068 if (device_mismatch
)
2070 WARN("Destination target from different device.\n");
2075 ID3D11Texture2D_GetDesc(texture
, &desc
);
2077 if (FAILED(hr
= ID3D11Device_CreateRenderTargetView(device
, (ID3D11Resource
*)texture
, NULL
, &rtv
)))
2079 WARN("Failed to create an rtv, hr %#x.\n", hr
);
2083 ID3D11Device_GetImmediateContext(device
, &context
);
2085 /* Whole destination is cleared, regardless of specified rectangle. */
2086 ID3D11DeviceContext_ClearRenderTargetView(context
, rtv
, black
);
2090 rect
.left
= max(0, dst_rect
->left
);
2091 rect
.top
= max(0, dst_rect
->top
);
2092 rect
.right
= min(desc
.Width
, dst_rect
->right
);
2093 rect
.bottom
= min(desc
.Height
, dst_rect
->bottom
);
2095 quad
[0].x
= 2.0f
* rect
.left
/ desc
.Width
- 1.0f
;
2096 quad
[0].y
= -2.0f
* rect
.bottom
/ desc
.Height
+ 1.0f
;
2099 quad
[1].x
= quad
[0].x
;
2100 quad
[1].y
= -2.0f
* rect
.top
/ desc
.Height
+ 1.0f
;
2103 quad
[2].x
= 2.0f
* rect
.right
/ desc
.Width
- 1.0f
;
2104 quad
[2].y
= quad
[0].y
;
2107 quad
[3].x
= quad
[2].x
;
2108 quad
[3].y
= quad
[1].y
;
2111 set_rect(&dst
, dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
);
2115 memcpy(quad
, fullquad
, sizeof(quad
));
2116 set_rect(&dst
, 0.0f
, 0.0f
, desc
.Width
, desc
.Height
);
2120 memcpy(&src
, src_rect
, sizeof(src
));
2122 set_rect(&src
, 0.0f
, 0.0f
, 1.0f
, 1.0f
);
2124 media_engine_adjust_destination_for_ratio(engine
, &src
, &dst
);
2126 if (memcmp(quad
, engine
->video_frame
.d3d11
.quad
, sizeof(quad
)))
2128 memcpy(engine
->video_frame
.d3d11
.quad
, quad
, sizeof(quad
));
2129 ID3D11DeviceContext_UpdateSubresource(context
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.vb
, 0, NULL
, quad
, 0, 0);
2134 backcolor
.r
= color
->rgbRed
/ 255.0f
;
2135 backcolor
.g
= color
->rgbGreen
/ 255.0f
;
2136 backcolor
.b
= color
->rgbBlue
/ 255.0f
;
2137 backcolor
.a
= color
->rgbAlpha
/ 255.0f
;
2140 memcpy(&backcolor
, black
, sizeof(backcolor
));
2142 if (memcmp(&dst
, &engine
->video_frame
.d3d11
.cb
.dst
, sizeof(dst
)) ||
2143 memcmp(&src
, &engine
->video_frame
.d3d11
.cb
.src
, sizeof(src
)) ||
2144 memcmp(&backcolor
, &engine
->video_frame
.d3d11
.cb
.backcolor
, sizeof(backcolor
)))
2146 memcpy(&engine
->video_frame
.d3d11
.cb
.dst
, &dst
, sizeof(dst
));
2147 memcpy(&engine
->video_frame
.d3d11
.cb
.src
, &src
, sizeof(src
));
2148 memcpy(&engine
->video_frame
.d3d11
.cb
.backcolor
, &backcolor
, sizeof(backcolor
));
2150 ID3D11DeviceContext_UpdateSubresource(context
, (ID3D11Resource
*)engine
->video_frame
.d3d11
.ps_cb
, 0, NULL
,
2151 &engine
->video_frame
.d3d11
.cb
, 0, 0);
2154 /* Update with new frame contents */
2155 media_engine_update_d3d11_frame_surface(context
, engine
);
2159 vp
.Width
= desc
.Width
;
2160 vp
.Height
= desc
.Height
;
2163 ID3D11DeviceContext_RSSetViewports(context
, 1, &vp
);
2165 ID3D11DeviceContext_IASetInputLayout(context
, engine
->video_frame
.d3d11
.input_layout
);
2166 ID3D11DeviceContext_IASetPrimitiveTopology(context
, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP
);
2167 stride
= sizeof(*quad
);
2169 ID3D11DeviceContext_IASetVertexBuffers(context
, 0, 1, &engine
->video_frame
.d3d11
.vb
, &stride
, &offset
);
2170 ID3D11DeviceContext_VSSetShader(context
, engine
->video_frame
.d3d11
.vs
, NULL
, 0);
2171 ID3D11DeviceContext_PSSetShader(context
, engine
->video_frame
.d3d11
.ps
, NULL
, 0);
2172 ID3D11DeviceContext_PSSetShaderResources(context
, 0, 1, &engine
->video_frame
.d3d11
.srv
);
2173 ID3D11DeviceContext_PSSetConstantBuffers(context
, 0, 1, &engine
->video_frame
.d3d11
.ps_cb
);
2174 ID3D11DeviceContext_PSSetSamplers(context
, 0, 1, &engine
->video_frame
.d3d11
.sampler
);
2175 ID3D11DeviceContext_OMSetRenderTargets(context
, 1, &rtv
, NULL
);
2177 ID3D11DeviceContext_Draw(context
, 4, 0);
2179 ID3D11RenderTargetView_Release(rtv
);
2180 ID3D11DeviceContext_Release(context
);
2183 media_engine_unlock_d3d_device(engine
, device
);
2188 static HRESULT WINAPI
media_engine_TransferVideoFrame(IMFMediaEngine
*iface
, IUnknown
*surface
,
2189 const MFVideoNormalizedRect
*src_rect
, const RECT
*dst_rect
, const MFARGB
*color
)
2191 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
2192 ID3D11Texture2D
*texture
;
2193 HRESULT hr
= E_NOINTERFACE
;
2195 TRACE("%p, %p, %s, %s, %p.\n", iface
, surface
, src_rect
? wine_dbg_sprintf("(%f,%f)-(%f,%f)",
2196 src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
) : "(null)",
2197 wine_dbgstr_rect(dst_rect
), color
);
2199 EnterCriticalSection(&engine
->cs
);
2201 if (SUCCEEDED(IUnknown_QueryInterface(surface
, &IID_ID3D11Texture2D
, (void **)&texture
)))
2203 hr
= media_engine_transfer_to_d3d11_texture(engine
, texture
, src_rect
, dst_rect
, color
);
2204 ID3D11Texture2D_Release(texture
);
2208 FIXME("Unsupported destination type.\n");
2211 LeaveCriticalSection(&engine
->cs
);
2216 static HRESULT WINAPI
media_engine_OnVideoStreamTick(IMFMediaEngine
*iface
, LONGLONG
*pts
)
2218 struct media_engine
*engine
= impl_from_IMFMediaEngine(iface
);
2221 TRACE("%p, %p.\n", iface
, pts
);
2223 EnterCriticalSection(&engine
->cs
);
2225 if (engine
->flags
& FLAGS_ENGINE_SHUT_DOWN
)
2231 *pts
= engine
->video_frame
.pts
;
2232 hr
= *pts
== MINLONGLONG
? S_FALSE
: S_OK
;
2235 LeaveCriticalSection(&engine
->cs
);
2240 static const IMFMediaEngineVtbl media_engine_vtbl
=
2242 media_engine_QueryInterface
,
2243 media_engine_AddRef
,
2244 media_engine_Release
,
2245 media_engine_GetError
,
2246 media_engine_SetErrorCode
,
2247 media_engine_SetSourceElements
,
2248 media_engine_SetSource
,
2249 media_engine_GetCurrentSource
,
2250 media_engine_GetNetworkState
,
2251 media_engine_GetPreload
,
2252 media_engine_SetPreload
,
2253 media_engine_GetBuffered
,
2255 media_engine_CanPlayType
,
2256 media_engine_GetReadyState
,
2257 media_engine_IsSeeking
,
2258 media_engine_GetCurrentTime
,
2259 media_engine_SetCurrentTime
,
2260 media_engine_GetStartTime
,
2261 media_engine_GetDuration
,
2262 media_engine_IsPaused
,
2263 media_engine_GetDefaultPlaybackRate
,
2264 media_engine_SetDefaultPlaybackRate
,
2265 media_engine_GetPlaybackRate
,
2266 media_engine_SetPlaybackRate
,
2267 media_engine_GetPlayed
,
2268 media_engine_GetSeekable
,
2269 media_engine_IsEnded
,
2270 media_engine_GetAutoPlay
,
2271 media_engine_SetAutoPlay
,
2272 media_engine_GetLoop
,
2273 media_engine_SetLoop
,
2276 media_engine_GetMuted
,
2277 media_engine_SetMuted
,
2278 media_engine_GetVolume
,
2279 media_engine_SetVolume
,
2280 media_engine_HasVideo
,
2281 media_engine_HasAudio
,
2282 media_engine_GetNativeVideoSize
,
2283 media_engine_GetVideoAspectRatio
,
2284 media_engine_Shutdown
,
2285 media_engine_TransferVideoFrame
,
2286 media_engine_OnVideoStreamTick
,
2289 static HRESULT WINAPI
media_engine_grabber_callback_QueryInterface(IMFSampleGrabberSinkCallback
*iface
,
2290 REFIID riid
, void **obj
)
2292 if (IsEqualIID(riid
, &IID_IMFSampleGrabberSinkCallback
) ||
2293 IsEqualIID(riid
, &IID_IUnknown
))
2296 IMFSampleGrabberSinkCallback_AddRef(iface
);
2301 return E_NOINTERFACE
;
2304 static ULONG WINAPI
media_engine_grabber_callback_AddRef(IMFSampleGrabberSinkCallback
*iface
)
2306 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
2307 return IMFMediaEngine_AddRef(&engine
->IMFMediaEngine_iface
);
2310 static ULONG WINAPI
media_engine_grabber_callback_Release(IMFSampleGrabberSinkCallback
*iface
)
2312 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
2313 return IMFMediaEngine_Release(&engine
->IMFMediaEngine_iface
);
2316 static HRESULT WINAPI
media_engine_grabber_callback_OnClockStart(IMFSampleGrabberSinkCallback
*iface
,
2317 MFTIME systime
, LONGLONG start_offset
)
2322 static HRESULT WINAPI
media_engine_grabber_callback_OnClockStop(IMFSampleGrabberSinkCallback
*iface
,
2325 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
2327 EnterCriticalSection(&engine
->cs
);
2328 media_engine_set_flag(engine
, FLAGS_ENGINE_FIRST_FRAME
, FALSE
);
2329 engine
->video_frame
.pts
= MINLONGLONG
;
2330 LeaveCriticalSection(&engine
->cs
);
2335 static HRESULT WINAPI
media_engine_grabber_callback_OnClockPause(IMFSampleGrabberSinkCallback
*iface
,
2341 static HRESULT WINAPI
media_engine_grabber_callback_OnClockRestart(IMFSampleGrabberSinkCallback
*iface
,
2347 static HRESULT WINAPI
media_engine_grabber_callback_OnClockSetRate(IMFSampleGrabberSinkCallback
*iface
,
2348 MFTIME systime
, float rate
)
2353 static HRESULT WINAPI
media_engine_grabber_callback_OnSetPresentationClock(IMFSampleGrabberSinkCallback
*iface
,
2354 IMFPresentationClock
*clock
)
2359 static HRESULT WINAPI
media_engine_grabber_callback_OnProcessSample(IMFSampleGrabberSinkCallback
*iface
,
2360 REFGUID major_type
, DWORD sample_flags
, LONGLONG sample_time
, LONGLONG sample_duration
,
2361 const BYTE
*buffer
, DWORD buffer_size
)
2363 struct media_engine
*engine
= impl_from_IMFSampleGrabberSinkCallback(iface
);
2365 EnterCriticalSection(&engine
->cs
);
2367 if (!(engine
->flags
& FLAGS_ENGINE_FIRST_FRAME
))
2369 IMFMediaEngineNotify_EventNotify(engine
->callback
, MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY
, 0, 0);
2370 media_engine_set_flag(engine
, FLAGS_ENGINE_FIRST_FRAME
, TRUE
);
2372 engine
->video_frame
.pts
= sample_time
;
2373 if (engine
->video_frame
.buffer_size
< buffer_size
)
2375 free(engine
->video_frame
.buffer
);
2376 if ((engine
->video_frame
.buffer
= malloc(buffer_size
)))
2377 engine
->video_frame
.buffer_size
= buffer_size
;
2379 if (engine
->video_frame
.buffer
)
2381 memcpy(engine
->video_frame
.buffer
, buffer
, buffer_size
);
2382 engine
->flags
|= FLAGS_ENGINE_NEW_FRAME
;
2385 LeaveCriticalSection(&engine
->cs
);
2390 static HRESULT WINAPI
media_engine_grabber_callback_OnShutdown(IMFSampleGrabberSinkCallback
*iface
)
2395 static const IMFSampleGrabberSinkCallbackVtbl media_engine_grabber_callback_vtbl
=
2397 media_engine_grabber_callback_QueryInterface
,
2398 media_engine_grabber_callback_AddRef
,
2399 media_engine_grabber_callback_Release
,
2400 media_engine_grabber_callback_OnClockStart
,
2401 media_engine_grabber_callback_OnClockStop
,
2402 media_engine_grabber_callback_OnClockPause
,
2403 media_engine_grabber_callback_OnClockRestart
,
2404 media_engine_grabber_callback_OnClockSetRate
,
2405 media_engine_grabber_callback_OnSetPresentationClock
,
2406 media_engine_grabber_callback_OnProcessSample
,
2407 media_engine_grabber_callback_OnShutdown
,
2410 static HRESULT WINAPI
media_engine_factory_QueryInterface(IMFMediaEngineClassFactory
*iface
, REFIID riid
, void **obj
)
2412 if (IsEqualIID(riid
, &IID_IMFMediaEngineClassFactory
) ||
2413 IsEqualIID(riid
, &IID_IUnknown
))
2416 IMFMediaEngineClassFactory_AddRef(iface
);
2420 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
2422 return E_NOINTERFACE
;
2425 static ULONG WINAPI
media_engine_factory_AddRef(IMFMediaEngineClassFactory
*iface
)
2430 static ULONG WINAPI
media_engine_factory_Release(IMFMediaEngineClassFactory
*iface
)
2435 static HRESULT
init_media_engine(DWORD flags
, IMFAttributes
*attributes
, struct media_engine
*engine
)
2437 DXGI_FORMAT output_format
;
2438 UINT64 playback_hwnd
;
2442 engine
->IMFMediaEngine_iface
.lpVtbl
= &media_engine_vtbl
;
2443 engine
->session_events
.lpVtbl
= &media_engine_session_events_vtbl
;
2444 engine
->load_handler
.lpVtbl
= &media_engine_load_handler_vtbl
;
2445 engine
->grabber_callback
.lpVtbl
= &media_engine_grabber_callback_vtbl
;
2446 engine
->refcount
= 1;
2447 engine
->flags
= (flags
& MF_MEDIA_ENGINE_CREATEFLAGS_MASK
) | FLAGS_ENGINE_PAUSED
;
2448 engine
->default_playback_rate
= 1.0;
2449 engine
->playback_rate
= 1.0;
2450 engine
->volume
= 1.0;
2451 engine
->duration
= NAN
;
2452 engine
->video_frame
.pts
= MINLONGLONG
;
2453 InitializeCriticalSection(&engine
->cs
);
2455 hr
= IMFAttributes_GetUnknown(attributes
, &MF_MEDIA_ENGINE_CALLBACK
, &IID_IMFMediaEngineNotify
,
2456 (void **)&engine
->callback
);
2460 IMFAttributes_GetUnknown(attributes
, &MF_MEDIA_ENGINE_DXGI_MANAGER
, &IID_IMFDXGIDeviceManager
,
2461 (void **)&engine
->device_manager
);
2463 if (FAILED(hr
= MFCreateMediaSession(NULL
, &engine
->session
)))
2466 if (FAILED(hr
= IMFMediaSession_GetClock(engine
->session
, &clock
)))
2469 hr
= IMFClock_QueryInterface(clock
, &IID_IMFPresentationClock
, (void **)&engine
->clock
);
2470 IMFClock_Release(clock
);
2474 if (FAILED(hr
= IMFMediaSession_BeginGetEvent(engine
->session
, &engine
->session_events
, NULL
)))
2477 if (FAILED(hr
= MFCreateSourceResolver(&engine
->resolver
)))
2480 if (FAILED(hr
= MFCreateAttributes(&engine
->attributes
, 0)))
2483 if (FAILED(hr
= IMFAttributes_CopyAllItems(attributes
, engine
->attributes
)))
2486 IMFAttributes_GetUINT64(attributes
, &MF_MEDIA_ENGINE_PLAYBACK_HWND
, &playback_hwnd
);
2487 hr
= IMFAttributes_GetUINT32(attributes
, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT
, &output_format
);
2488 if (playback_hwnd
) /* FIXME: handle MF_MEDIA_ENGINE_PLAYBACK_VISUAL */
2489 engine
->mode
= MEDIA_ENGINE_RENDERING_MODE
;
2493 engine
->mode
= MEDIA_ENGINE_FRAME_SERVER_MODE
;
2495 engine
->mode
= MEDIA_ENGINE_AUDIO_MODE
;
2501 static HRESULT WINAPI
media_engine_factory_CreateInstance(IMFMediaEngineClassFactory
*iface
, DWORD flags
,
2502 IMFAttributes
*attributes
, IMFMediaEngine
**engine
)
2504 struct media_engine
*object
;
2507 TRACE("%p, %#x, %p, %p.\n", iface
, flags
, attributes
, engine
);
2509 if (!attributes
|| !engine
)
2512 object
= calloc(1, sizeof(*object
));
2514 return E_OUTOFMEMORY
;
2516 hr
= init_media_engine(flags
, attributes
, object
);
2519 free_media_engine(object
);
2523 *engine
= &object
->IMFMediaEngine_iface
;
2528 static HRESULT WINAPI
media_engine_factory_CreateTimeRange(IMFMediaEngineClassFactory
*iface
,
2529 IMFMediaTimeRange
**range
)
2531 TRACE("%p, %p.\n", iface
, range
);
2533 return create_time_range(range
);
2536 static HRESULT WINAPI
media_engine_factory_CreateError(IMFMediaEngineClassFactory
*iface
, IMFMediaError
**error
)
2538 TRACE("%p, %p.\n", iface
, error
);
2540 return create_media_error(error
);
2543 static const IMFMediaEngineClassFactoryVtbl media_engine_factory_vtbl
=
2545 media_engine_factory_QueryInterface
,
2546 media_engine_factory_AddRef
,
2547 media_engine_factory_Release
,
2548 media_engine_factory_CreateInstance
,
2549 media_engine_factory_CreateTimeRange
,
2550 media_engine_factory_CreateError
,
2553 static IMFMediaEngineClassFactory media_engine_factory
= { &media_engine_factory_vtbl
};
2555 static HRESULT WINAPI
classfactory_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **obj
)
2557 TRACE("%s, %p.\n", debugstr_guid(riid
), obj
);
2559 if (IsEqualGUID(riid
, &IID_IClassFactory
) ||
2560 IsEqualGUID(riid
, &IID_IUnknown
))
2562 IClassFactory_AddRef(iface
);
2567 WARN("interface %s not implemented.\n", debugstr_guid(riid
));
2569 return E_NOINTERFACE
;
2572 static ULONG WINAPI
classfactory_AddRef(IClassFactory
*iface
)
2577 static ULONG WINAPI
classfactory_Release(IClassFactory
*iface
)
2582 static HRESULT WINAPI
classfactory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **obj
)
2584 TRACE("%p, %s, %p.\n", outer
, debugstr_guid(riid
), obj
);
2589 return CLASS_E_NOAGGREGATION
;
2591 return IMFMediaEngineClassFactory_QueryInterface(&media_engine_factory
, riid
, obj
);
2594 static HRESULT WINAPI
classfactory_LockServer(IClassFactory
*iface
, BOOL dolock
)
2596 FIXME("(%d): stub.\n", dolock
);
2600 static const IClassFactoryVtbl class_factory_vtbl
=
2602 classfactory_QueryInterface
,
2603 classfactory_AddRef
,
2604 classfactory_Release
,
2605 classfactory_CreateInstance
,
2606 classfactory_LockServer
,
2609 static IClassFactory classfactory
= { &class_factory_vtbl
};
2611 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **obj
)
2613 TRACE("%s, %s, %p.\n", debugstr_guid(clsid
), debugstr_guid(riid
), obj
);
2615 if (IsEqualGUID(clsid
, &CLSID_MFMediaEngineClassFactory
))
2616 return IClassFactory_QueryInterface(&classfactory
, riid
, obj
);
2618 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2620 return CLASS_E_CLASSNOTAVAILABLE
;