Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/mediatype.c | 98 ++++++++++++++++++++++++++++++++++++++ dlls/mfplat/mfplat.spec | 1 + dlls/mfplat/tests/mfplat.c | 73 ++++++++++++++++++++++++++++ include/mfapi.h | 2 + 4 files changed, 174 insertions(+)
diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index fcaef110038..f3895ca4d49 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3211,3 +3211,101 @@ HRESULT WINAPI MFFrameRateToAverageTimePerFrame(UINT32 numerator, UINT32 denomin
return S_OK; } + +/*********************************************************************** + * MFMapDXGIFormatToDX9Format (mfplat.@) + */ +DWORD WINAPI MFMapDXGIFormatToDX9Format(DXGI_FORMAT dxgi_format) +{ + switch (dxgi_format) + { + case DXGI_FORMAT_R32G32B32A32_FLOAT: + return D3DFMT_A32B32G32R32F; + case DXGI_FORMAT_R16G16B16A16_FLOAT: + return D3DFMT_A16B16G16R16F; + case DXGI_FORMAT_R16G16B16A16_UNORM: + return D3DFMT_A16B16G16R16; + case DXGI_FORMAT_R16G16B16A16_SNORM: + return D3DFMT_Q16W16V16U16; + case DXGI_FORMAT_R32G32_FLOAT: + return D3DFMT_G32R32F; + case DXGI_FORMAT_R10G10B10A2_UNORM: + return D3DFMT_A2B10G10R10; + case DXGI_FORMAT_R8G8B8A8_SNORM: + return D3DFMT_Q8W8V8U8; + case DXGI_FORMAT_R16G16_FLOAT: + return D3DFMT_G16R16F; + case DXGI_FORMAT_R16G16_UNORM: + return D3DFMT_G16R16; + case DXGI_FORMAT_R16G16_SNORM: + return D3DFMT_V16U16; + case DXGI_FORMAT_D32_FLOAT: + return D3DFMT_D32F_LOCKABLE; + case DXGI_FORMAT_R32_FLOAT: + return D3DFMT_R32F; + case DXGI_FORMAT_D24_UNORM_S8_UINT: + return D3DFMT_D24S8; + case DXGI_FORMAT_R8G8_SNORM: + return D3DFMT_V8U8; + case DXGI_FORMAT_R16_FLOAT: + return D3DFMT_R16F; + case DXGI_FORMAT_D16_UNORM: + return D3DFMT_D16_LOCKABLE; + case DXGI_FORMAT_R16_UNORM: + return D3DFMT_L16; + case DXGI_FORMAT_R8_UNORM: + return D3DFMT_L8; + case DXGI_FORMAT_A8_UNORM: + return D3DFMT_A8; + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: + return D3DFMT_DXT1; + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: + return D3DFMT_DXT2; + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: + return D3DFMT_DXT4; + case DXGI_FORMAT_R8G8B8A8_UNORM: + return D3DFMT_A8B8G8R8; + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + return D3DFMT_A8R8G8B8; + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + return D3DFMT_X8R8G8B8; + case DXGI_FORMAT_AYUV: + return MAKEFOURCC('A','Y','U','V'); + case DXGI_FORMAT_Y410: + return MAKEFOURCC('Y','4','1','0'); + case DXGI_FORMAT_Y416: + return MAKEFOURCC('Y','4','1','6'); + case DXGI_FORMAT_NV12: + return MAKEFOURCC('N','V','1','2'); + case DXGI_FORMAT_P010: + return MAKEFOURCC('P','0','1','0'); + case DXGI_FORMAT_P016: + return MAKEFOURCC('P','0','1','6'); + case DXGI_FORMAT_420_OPAQUE: + return MAKEFOURCC('4','2','0','O'); + case DXGI_FORMAT_YUY2: + return D3DFMT_YUY2; + case DXGI_FORMAT_Y210: + return MAKEFOURCC('Y','2','1','0'); + case DXGI_FORMAT_Y216: + return MAKEFOURCC('Y','2','1','6'); + case DXGI_FORMAT_NV11: + return MAKEFOURCC('N','V','1','1'); + case DXGI_FORMAT_AI44: + return MAKEFOURCC('A','I','4','4'); + case DXGI_FORMAT_IA44: + return MAKEFOURCC('I','A','4','4'); + case DXGI_FORMAT_P8: + return D3DFMT_P8; + case DXGI_FORMAT_A8P8: + return D3DFMT_A8P8; + default: + return 0; + } +} diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 36e009c2db9..8ef40dd20c8 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -131,6 +131,7 @@ @ stdcall MFJoinWorkQueue(long long ptr) rtworkq.RtwqJoinWorkQueue @ stdcall MFLockPlatform() rtworkq.RtwqLockPlatform @ stdcall MFLockWorkQueue(long) rtworkq.RtwqLockWorkQueue +@ stdcall MFMapDXGIFormatToDX9Format(long) @ stdcall MFPutWaitingWorkItem(long long ptr ptr) rtworkq.RtwqPutWaitingWorkItem @ stdcall MFPutWorkItem(long ptr ptr) @ stdcall MFPutWorkItem2(long long ptr ptr) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index a6c8a10f777..4f5cf268d2a 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -108,6 +108,7 @@ static HRESULT (WINAPI *pMFCreateMediaBufferFromMediaType)(IMFMediaType *media_t DWORD min_alignment, IMFMediaBuffer **buffer); static HRESULT (WINAPI *pMFCreateDXSurfaceBuffer)(REFIID riid, IUnknown *surface, BOOL bottom_up, IMFMediaBuffer **buffer); static HRESULT (WINAPI *pMFCreateTrackedSample)(IMFTrackedSample **sample); +static DWORD (WINAPI *pMFMapDXGIFormatToDX9Format)(DXGI_FORMAT dxgi_format);
static HWND create_window(void) { @@ -742,6 +743,7 @@ static void init_functions(void) X(MFCreateTransformActivate); X(MFGetPlaneSize); X(MFGetStrideForBitmapInfoHeader); + X(MFMapDXGIFormatToDX9Format); X(MFPutWaitingWorkItem); X(MFRegisterLocalByteStreamHandler); X(MFRegisterLocalSchemeHandler); @@ -5911,6 +5913,76 @@ static void test_MFFrameRateToAverageTimePerFrame(void) } }
+static void test_MFMapDXGIFormatToDX9Format(void) +{ + static const struct format_pair + { + DXGI_FORMAT dxgi_format; + DWORD d3d9_format; + } + formats_map[] = + { + { DXGI_FORMAT_R32G32B32A32_FLOAT, D3DFMT_A32B32G32R32F }, + { DXGI_FORMAT_R16G16B16A16_FLOAT, D3DFMT_A16B16G16R16F }, + { DXGI_FORMAT_R16G16B16A16_UNORM, D3DFMT_A16B16G16R16 }, + { DXGI_FORMAT_R16G16B16A16_SNORM, D3DFMT_Q16W16V16U16 }, + { DXGI_FORMAT_R32G32_FLOAT, D3DFMT_G32R32F }, + { DXGI_FORMAT_R10G10B10A2_UNORM, D3DFMT_A2B10G10R10 }, + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, D3DFMT_A8R8G8B8 }, + { DXGI_FORMAT_R8G8B8A8_SNORM, D3DFMT_Q8W8V8U8 }, + { DXGI_FORMAT_R16G16_FLOAT, D3DFMT_G16R16F }, + { DXGI_FORMAT_R16G16_UNORM, D3DFMT_G16R16 }, + { DXGI_FORMAT_R16G16_SNORM, D3DFMT_V16U16 }, + { DXGI_FORMAT_D32_FLOAT, D3DFMT_D32F_LOCKABLE }, + { DXGI_FORMAT_R32_FLOAT, D3DFMT_R32F }, + { DXGI_FORMAT_D24_UNORM_S8_UINT, D3DFMT_D24S8 }, + { DXGI_FORMAT_R8G8_SNORM, D3DFMT_V8U8 }, + { DXGI_FORMAT_R16_FLOAT, D3DFMT_R16F }, + { DXGI_FORMAT_R16_UNORM, D3DFMT_L16 }, + { DXGI_FORMAT_R8_UNORM, D3DFMT_L8 }, + { DXGI_FORMAT_A8_UNORM, D3DFMT_A8 }, + { DXGI_FORMAT_BC1_UNORM, D3DFMT_DXT1 }, + { DXGI_FORMAT_BC1_UNORM_SRGB, D3DFMT_DXT1 }, + { DXGI_FORMAT_BC2_UNORM, D3DFMT_DXT2 }, + { DXGI_FORMAT_BC2_UNORM_SRGB, D3DFMT_DXT2 }, + { DXGI_FORMAT_BC3_UNORM, D3DFMT_DXT4 }, + { DXGI_FORMAT_BC3_UNORM_SRGB, D3DFMT_DXT4 }, + { DXGI_FORMAT_B8G8R8A8_UNORM, D3DFMT_A8R8G8B8 }, + { DXGI_FORMAT_B8G8R8X8_UNORM, D3DFMT_X8R8G8B8 }, + { DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, D3DFMT_A8R8G8B8 }, + { DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, D3DFMT_X8R8G8B8 }, + { DXGI_FORMAT_AYUV, MAKEFOURCC('A','Y','U','V') }, + { DXGI_FORMAT_Y410, MAKEFOURCC('Y','4','1','0') }, + { DXGI_FORMAT_Y416, MAKEFOURCC('Y','4','1','6') }, + { DXGI_FORMAT_NV12, MAKEFOURCC('N','V','1','2') }, + { DXGI_FORMAT_P010, MAKEFOURCC('P','0','1','0') }, + { DXGI_FORMAT_P016, MAKEFOURCC('P','0','1','6') }, + { DXGI_FORMAT_420_OPAQUE, MAKEFOURCC('4','2','0','O') }, + { DXGI_FORMAT_YUY2, D3DFMT_YUY2 }, + { DXGI_FORMAT_Y210, MAKEFOURCC('Y','2','1','0') }, + { DXGI_FORMAT_Y216, MAKEFOURCC('Y','2','1','6') }, + { DXGI_FORMAT_NV11, MAKEFOURCC('N','V','1','1') }, + { DXGI_FORMAT_AI44, MAKEFOURCC('A','I','4','4') }, + { DXGI_FORMAT_IA44, MAKEFOURCC('I','A','4','4') }, + { DXGI_FORMAT_P8, D3DFMT_P8 }, + { DXGI_FORMAT_A8P8, D3DFMT_A8P8 }, + }; + unsigned int i; + DWORD format; + + if (!pMFMapDXGIFormatToDX9Format) + { + win_skip("MFMapDXGIFormatToDX9Format is not available.\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(formats_map); ++i) + { + format = pMFMapDXGIFormatToDX9Format(formats_map[i].dxgi_format); + ok(format == formats_map[i].d3d9_format, "Unexpected d3d9 format %#x, dxgi format %#x.\n", format, formats_map[i].dxgi_format); + } +} + START_TEST(mfplat) { char **argv; @@ -5970,6 +6042,7 @@ START_TEST(mfplat) test_MFCreateDXSurfaceBuffer(); test_MFCreateTrackedSample(); test_MFFrameRateToAverageTimePerFrame(); + test_MFMapDXGIFormatToDX9Format();
CoUninitialize(); } diff --git a/include/mfapi.h b/include/mfapi.h index 8661b41fc4e..77875486e54 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -22,6 +22,7 @@ #include <mfobjects.h> #include <mmreg.h> #include <avrt.h> +#include <dxgiformat.h>
#if defined(__cplusplus) extern "C" { @@ -549,6 +550,7 @@ HRESULT WINAPI MFInitAttributesFromBlob(IMFAttributes *attributes, const UINT8 * HRESULT WINAPI MFInitMediaTypeFromWaveFormatEx(IMFMediaType *mediatype, const WAVEFORMATEX *format, UINT32 size); HRESULT WINAPI MFInvokeCallback(IMFAsyncResult *result); HRESULT WINAPI MFLockPlatform(void); +DWORD WINAPI MFMapDXGIFormatToDX9Format(DXGI_FORMAT dxgi_format); HRESULT WINAPI MFPutWaitingWorkItem(HANDLE event, LONG priority, IMFAsyncResult *result, MFWORKITEM_KEY *key); HRESULT WINAPI MFPutWorkItem(DWORD queue, IMFAsyncCallback *callback, IUnknown *state); HRESULT WINAPI MFPutWorkItem2(DWORD queue, LONG priority, IMFAsyncCallback *callback, IUnknown *state);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfmediaengine/main.c | 166 +++++++++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 2 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 64f0ae6d2a1..0817c249b27 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -75,6 +75,7 @@ struct media_engine IMFMediaEngine IMFMediaEngine_iface; IMFAsyncCallback session_events; IMFAsyncCallback load_handler; + IMFSampleGrabberSinkCallback grabber_callback; LONG refcount; IMFMediaEngineNotify *callback; IMFAttributes *attributes; @@ -237,6 +238,11 @@ static struct media_engine *impl_from_load_handler_IMFAsyncCallback(IMFAsyncCall return CONTAINING_RECORD(iface, struct media_engine, load_handler); }
+static struct media_engine *impl_from_IMFSampleGrabberSinkCallback(IMFSampleGrabberSinkCallback *iface) +{ + return CONTAINING_RECORD(iface, struct media_engine, grabber_callback); +} + static HRESULT WINAPI media_engine_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IMFAsyncCallback) || @@ -373,6 +379,51 @@ static HRESULT media_engine_create_audio_renderer(struct media_engine *engine, I return hr; }
+static HRESULT media_engine_create_video_renderer(struct media_engine *engine, IMFTopologyNode **node) +{ + DXGI_FORMAT output_format; + IMFMediaType *media_type; + IMFActivate *activate; + GUID subtype; + HRESULT hr; + + *node = NULL; + + if (FAILED(IMFAttributes_GetUINT32(engine->attributes, &MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, &output_format))) + { + WARN("Output format was not specified.\n"); + return E_FAIL; + } + + memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype)); + if (!(subtype.Data1 = MFMapDXGIFormatToDX9Format(output_format))) + { + WARN("Unrecognized output format %#x.\n", output_format); + return E_FAIL; + } + + if (FAILED(hr = MFCreateMediaType(&media_type))) + return hr; + + IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &subtype); + + hr = MFCreateSampleGrabberSinkActivate(media_type, &engine->grabber_callback, &activate); + IMFMediaType_Release(media_type); + if (FAILED(hr)) + return hr; + + if (SUCCEEDED(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, node))) + { + IMFTopologyNode_SetObject(*node, (IUnknown *)activate); + IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE); + } + + IMFActivate_Release(activate); + + return hr; +} + static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMediaSource *source) { IMFStreamDescriptor *sd_audio = NULL, *sd_video = NULL; @@ -455,11 +506,10 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi
IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDDATA, 0, 0);
- /* TODO: set up video stream nodes */ - if (SUCCEEDED(hr = MFCreateTopology(&topology))) { IMFTopologyNode *sar_node = NULL, *audio_src = NULL; + IMFTopologyNode *grabber_node = NULL, *video_src = NULL;
if (sd_audio) { @@ -481,6 +531,27 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi if (audio_src) IMFTopologyNode_Release(audio_src); } + + if (SUCCEEDED(hr) && sd_video) + { + if (FAILED(hr = media_engine_create_source_node(source, pd, sd_video, &video_src))) + WARN("Failed to create video source node, hr %#x.\n", hr); + + if (FAILED(hr = media_engine_create_video_renderer(engine, &grabber_node))) + WARN("Failed to create video grabber node, hr %#x.\n", hr); + + if (grabber_node && video_src) + { + IMFTopology_AddNode(topology, video_src); + IMFTopology_AddNode(topology, grabber_node); + IMFTopologyNode_ConnectOutput(video_src, 0, grabber_node, 0); + } + + if (grabber_node) + IMFTopologyNode_Release(grabber_node); + if (video_src) + IMFTopologyNode_Release(video_src); + } }
if (topology) @@ -1225,6 +1296,96 @@ static const IMFMediaEngineVtbl media_engine_vtbl = media_engine_OnVideoStreamTick, };
+static HRESULT WINAPI media_engine_grabber_callback_QueryInterface(IMFSampleGrabberSinkCallback *iface, + REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFSampleGrabberSinkCallback) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFSampleGrabberSinkCallback_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI media_engine_grabber_callback_AddRef(IMFSampleGrabberSinkCallback *iface) +{ + struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface); + return IMFMediaEngine_AddRef(&engine->IMFMediaEngine_iface); +} + +static ULONG WINAPI media_engine_grabber_callback_Release(IMFSampleGrabberSinkCallback *iface) +{ + struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface); + return IMFMediaEngine_Release(&engine->IMFMediaEngine_iface); +} + +static HRESULT WINAPI media_engine_grabber_callback_OnClockStart(IMFSampleGrabberSinkCallback *iface, + MFTIME systime, LONGLONG start_offset) +{ + return S_OK; +} + +static HRESULT WINAPI media_engine_grabber_callback_OnClockStop(IMFSampleGrabberSinkCallback *iface, + MFTIME systime) +{ + return S_OK; +} + +static HRESULT WINAPI media_engine_grabber_callback_OnClockPause(IMFSampleGrabberSinkCallback *iface, + MFTIME systime) +{ + return S_OK; +} + +static HRESULT WINAPI media_engine_grabber_callback_OnClockRestart(IMFSampleGrabberSinkCallback *iface, + MFTIME systime) +{ + return S_OK; +} + +static HRESULT WINAPI media_engine_grabber_callback_OnClockSetRate(IMFSampleGrabberSinkCallback *iface, + MFTIME systime, float rate) +{ + return S_OK; +} + +static HRESULT WINAPI media_engine_grabber_callback_OnSetPresentationClock(IMFSampleGrabberSinkCallback *iface, + IMFPresentationClock *clock) +{ + return S_OK; +} + +static HRESULT WINAPI media_engine_grabber_callback_OnProcessSample(IMFSampleGrabberSinkCallback *iface, + REFGUID major_type, DWORD sample_flags, LONGLONG sample_time, LONGLONG sample_duration, + const BYTE *buffer, DWORD sample_size) +{ + return S_OK; +} + +static HRESULT WINAPI media_engine_grabber_callback_OnShutdown(IMFSampleGrabberSinkCallback *iface) +{ + return S_OK; +} + +static const IMFSampleGrabberSinkCallbackVtbl media_engine_grabber_callback_vtbl = +{ + media_engine_grabber_callback_QueryInterface, + media_engine_grabber_callback_AddRef, + media_engine_grabber_callback_Release, + media_engine_grabber_callback_OnClockStart, + media_engine_grabber_callback_OnClockStop, + media_engine_grabber_callback_OnClockPause, + media_engine_grabber_callback_OnClockRestart, + media_engine_grabber_callback_OnClockSetRate, + media_engine_grabber_callback_OnSetPresentationClock, + media_engine_grabber_callback_OnProcessSample, + media_engine_grabber_callback_OnShutdown, +}; + static HRESULT WINAPI media_engine_factory_QueryInterface(IMFMediaEngineClassFactory *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IMFMediaEngineClassFactory) || @@ -1259,6 +1420,7 @@ static HRESULT init_media_engine(DWORD flags, IMFAttributes *attributes, struct engine->IMFMediaEngine_iface.lpVtbl = &media_engine_vtbl; engine->session_events.lpVtbl = &media_engine_session_events_vtbl; engine->load_handler.lpVtbl = &media_engine_load_handler_vtbl; + engine->grabber_callback.lpVtbl = &media_engine_grabber_callback_vtbl; engine->refcount = 1; engine->flags = (flags & MF_MEDIA_ENGINE_CREATEFLAGS_MASK) | FLAGS_ENGINE_PAUSED; engine->default_playback_rate = 1.0;
From: Derek Lesho dlesho@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfmediaengine/main.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 0817c249b27..c44a85b7869 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -552,6 +552,9 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi if (video_src) IMFTopologyNode_Release(video_src); } + + if (SUCCEEDED(hr)) + hr = IMFMediaSession_SetTopology(engine->session, MFSESSION_SETTOPOLOGY_IMMEDIATE, topology); }
if (topology)
From: Derek Lesho dlesho@codeweavers.com
Signed-off-by: Derek Lesho dlesho@codeweavers.com Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfmediaengine/main.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index c44a85b7869..d7a25058d2f 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -302,6 +302,14 @@ static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface IMFMediaEngineNotify_EventNotify(engine->callback, event_type == MEBufferingStarted ? MF_MEDIA_ENGINE_EVENT_BUFFERINGSTARTED : MF_MEDIA_ENGINE_EVENT_BUFFERINGENDED, 0, 0); break; + case MESessionTopologyStatus: + { + UINT32 topo_status = 0; + IMFMediaEvent_GetUINT32(event, &MF_EVENT_TOPOLOGY_STATUS, &topo_status); + if (topo_status == MF_TOPOSTATUS_READY) + IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_CANPLAY, 0, 0); + break; + } }
failed:
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=81408
Your paranoid android.
=== debiant (32 bit WoW report) ===
mfplat: Unhandled exception: page fault on execute access to 0x0a2e7823 in 32-bit code (0x0a2e7823).
From: Derek Lesho dlesho@codeweavers.com
Signed-off-by: Derek Lesho dlesho@codeweavers.com Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfmediaengine/main.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index d7a25058d2f..efd9c45165b 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -310,6 +310,10 @@ static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_CANPLAY, 0, 0); break; } + case MESessionStarted: + + IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAYING, 0, 0); + break; }
failed:
From: Derek Lesho dlesho@codeweavers.com
Signed-off-by: Derek Lesho dlesho@codeweavers.com Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfmediaengine/main.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index efd9c45165b..8dbbb889288 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -314,6 +314,10 @@ static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface
IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAYING, 0, 0); break; + case MESessionEnded: + + IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ENDED, 0, 0); + break; }
failed:
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfmediaengine/main.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 8dbbb889288..9da802f0df6 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -68,6 +68,7 @@ enum media_engine_flags FLAGS_ENGINE_MUTED = 0x400, FLAGS_ENGINE_HAS_AUDIO = 0x800, FLAGS_ENGINE_HAS_VIDEO = 0x1000, + FLAGS_ENGINE_FIRST_FRAME = 0x2000, };
struct media_engine @@ -316,6 +317,10 @@ static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface break; case MESessionEnded:
+ EnterCriticalSection(&engine->cs); + media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, FALSE); + LeaveCriticalSection(&engine->cs); + IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ENDED, 0, 0); break; } @@ -1351,6 +1356,12 @@ static HRESULT WINAPI media_engine_grabber_callback_OnClockStart(IMFSampleGrabbe static HRESULT WINAPI media_engine_grabber_callback_OnClockStop(IMFSampleGrabberSinkCallback *iface, MFTIME systime) { + struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface); + + EnterCriticalSection(&engine->cs); + media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, FALSE); + LeaveCriticalSection(&engine->cs); + return S_OK; }
@@ -1382,6 +1393,18 @@ static HRESULT WINAPI media_engine_grabber_callback_OnProcessSample(IMFSampleGra REFGUID major_type, DWORD sample_flags, LONGLONG sample_time, LONGLONG sample_duration, const BYTE *buffer, DWORD sample_size) { + struct media_engine *engine = impl_from_IMFSampleGrabberSinkCallback(iface); + + EnterCriticalSection(&engine->cs); + + if (!(engine->flags & FLAGS_ENGINE_FIRST_FRAME)) + { + IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY, 0, 0); + engine->flags |= FLAGS_ENGINE_FIRST_FRAME; + } + + LeaveCriticalSection(&engine->cs); + return S_OK; }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfmediaengine/main.c | 33 +++++++++++++++++++++--- dlls/mfmediaengine/tests/mfmediaengine.c | 15 +++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-)
diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 9da802f0df6..e126a925b67 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -71,6 +71,11 @@ enum media_engine_flags FLAGS_ENGINE_FIRST_FRAME = 0x2000, };
+struct video_frame +{ + LONGLONG pts; +}; + struct media_engine { IMFMediaEngine IMFMediaEngine_iface; @@ -93,6 +98,7 @@ struct media_engine IMFMediaSession *session; IMFSourceResolver *resolver; BSTR current_source; + struct video_frame video_frame; CRITICAL_SECTION cs; };
@@ -319,6 +325,7 @@ static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface
EnterCriticalSection(&engine->cs); media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, FALSE); + engine->video_frame.pts = MINLONGLONG; LeaveCriticalSection(&engine->cs);
IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_ENDED, 0, 0); @@ -1264,11 +1271,28 @@ static HRESULT WINAPI media_engine_TransferVideoFrame(IMFMediaEngine *iface, IUn return E_NOTIMPL; }
-static HRESULT WINAPI media_engine_OnVideoStreamTick(IMFMediaEngine *iface, LONGLONG *time) +static HRESULT WINAPI media_engine_OnVideoStreamTick(IMFMediaEngine *iface, LONGLONG *pts) { - FIXME("(%p, %p): stub.\n", iface, time); + struct media_engine *engine = impl_from_IMFMediaEngine(iface); + HRESULT hr;
- return E_NOTIMPL; + TRACE("%p, %p.\n", iface, pts); + + EnterCriticalSection(&engine->cs); + + if (engine->flags & FLAGS_ENGINE_SHUT_DOWN) + hr = MF_E_SHUTDOWN; + else if (!pts) + hr = E_POINTER; + else + { + *pts = engine->video_frame.pts; + hr = *pts == MINLONGLONG ? S_FALSE : S_OK; + } + + LeaveCriticalSection(&engine->cs); + + return hr; }
static const IMFMediaEngineVtbl media_engine_vtbl = @@ -1360,6 +1384,7 @@ static HRESULT WINAPI media_engine_grabber_callback_OnClockStop(IMFSampleGrabber
EnterCriticalSection(&engine->cs); media_engine_set_flag(engine, FLAGS_ENGINE_FIRST_FRAME, FALSE); + engine->video_frame.pts = MINLONGLONG; LeaveCriticalSection(&engine->cs);
return S_OK; @@ -1402,6 +1427,7 @@ static HRESULT WINAPI media_engine_grabber_callback_OnProcessSample(IMFSampleGra IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY, 0, 0); engine->flags |= FLAGS_ENGINE_FIRST_FRAME; } + engine->video_frame.pts = sample_time;
LeaveCriticalSection(&engine->cs);
@@ -1469,6 +1495,7 @@ static HRESULT init_media_engine(DWORD flags, IMFAttributes *attributes, struct engine->playback_rate = 1.0; engine->volume = 1.0; engine->duration = NAN; + engine->video_frame.pts = MINLONGLONG; InitializeCriticalSection(&engine->cs);
hr = IMFAttributes_GetUnknown(attributes, &MF_MEDIA_ENGINE_CALLBACK, &IID_IMFMediaEngineNotify, diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index 0394bcf6a0e..21ead1b0afa 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -394,6 +394,7 @@ static void test_Play(void) struct media_engine_notify notify_impl = {{&media_engine_notify_vtbl}, 1}; IMFMediaEngineNotify *callback = ¬ify_impl.IMFMediaEngineNotify_iface; IMFMediaEngine *media_engine; + LONGLONG pts; HRESULT hr; BOOL ret;
@@ -402,6 +403,14 @@ static void test_Play(void) ret = IMFMediaEngine_IsPaused(media_engine); ok(ret, "Unexpected state %d.\n", ret);
+ hr = IMFMediaEngine_OnVideoStreamTick(media_engine, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + pts = 0; + hr = IMFMediaEngine_OnVideoStreamTick(media_engine, &pts); + ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr); + ok(pts == MINLONGLONG, "Unexpected timestamp.\n"); + hr = IMFMediaEngine_Play(media_engine); ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
@@ -414,6 +423,12 @@ static void test_Play(void) hr = IMFMediaEngine_Shutdown(media_engine); ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ hr = IMFMediaEngine_OnVideoStreamTick(media_engine, NULL); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaEngine_OnVideoStreamTick(media_engine, &pts); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr); + ret = IMFMediaEngine_IsPaused(media_engine); ok(!ret, "Unexpected state %d.\n", ret);