Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/sar.c | 131 +++++++++++++++++++++++++++++++++++++++++++-- dlls/mf/tests/mf.c | 54 +++++++++++++++++++ 2 files changed, 181 insertions(+), 4 deletions(-)
diff --git a/dlls/mf/sar.c b/dlls/mf/sar.c index 71fd4ed850..2ef767b787 100644 --- a/dlls/mf/sar.c +++ b/dlls/mf/sar.c @@ -32,9 +32,11 @@ struct audio_renderer { IMFMediaSink IMFMediaSink_iface; IMFMediaSinkPreroll IMFMediaSinkPreroll_iface; + IMFClockStateSink IMFClockStateSink_iface; IMFMediaEventGenerator IMFMediaEventGenerator_iface; LONG refcount; IMFMediaEventQueue *event_queue; + IMFPresentationClock *clock; BOOL is_shut_down; CRITICAL_SECTION cs; }; @@ -49,6 +51,11 @@ static struct audio_renderer *impl_from_IMFMediaSinkPreroll(IMFMediaSinkPreroll return CONTAINING_RECORD(iface, struct audio_renderer, IMFMediaSinkPreroll_iface); }
+static struct audio_renderer *impl_from_IMFClockStateSink(IMFClockStateSink *iface) +{ + return CONTAINING_RECORD(iface, struct audio_renderer, IMFClockStateSink_iface); +} + static struct audio_renderer *impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator *iface) { return CONTAINING_RECORD(iface, struct audio_renderer, IMFMediaEventGenerator_iface); @@ -69,6 +76,10 @@ static HRESULT WINAPI audio_renderer_sink_QueryInterface(IMFMediaSink *iface, RE { *obj = &renderer->IMFMediaSinkPreroll_iface; } + else if (IsEqualIID(riid, &IID_IMFClockStateSink)) + { + *obj = &renderer->IMFClockStateSink_iface; + } else if (IsEqualIID(riid, &IID_IMFMediaEventGenerator)) { *obj = &renderer->IMFMediaEventGenerator_iface; @@ -104,6 +115,8 @@ static ULONG WINAPI audio_renderer_sink_Release(IMFMediaSink *iface) { if (renderer->event_queue) IMFMediaEventQueue_Release(renderer->event_queue); + if (renderer->clock) + IMFPresentationClock_Release(renderer->clock); DeleteCriticalSection(&renderer->cs); heap_free(renderer); } @@ -179,16 +192,60 @@ static HRESULT WINAPI audio_renderer_sink_GetStreamSinkById(IMFMediaSink *iface,
static HRESULT WINAPI audio_renderer_sink_SetPresentationClock(IMFMediaSink *iface, IMFPresentationClock *clock) { - FIXME("%p, %p.\n", iface, clock); + struct audio_renderer *renderer = impl_from_IMFMediaSink(iface); + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %p.\n", iface, clock); + + EnterCriticalSection(&renderer->cs); + + if (renderer->is_shut_down) + hr = MF_E_SHUTDOWN; + else + { + if (renderer->clock) + { + IMFPresentationClock_RemoveClockStateSink(renderer->clock, &renderer->IMFClockStateSink_iface); + IMFPresentationClock_Release(renderer->clock); + } + renderer->clock = clock; + if (renderer->clock) + { + IMFPresentationClock_AddRef(renderer->clock); + IMFPresentationClock_AddClockStateSink(renderer->clock, &renderer->IMFClockStateSink_iface); + } + } + + LeaveCriticalSection(&renderer->cs); + + return hr; }
static HRESULT WINAPI audio_renderer_sink_GetPresentationClock(IMFMediaSink *iface, IMFPresentationClock **clock) { - FIXME("%p, %p.\n", iface, clock); + struct audio_renderer *renderer = impl_from_IMFMediaSink(iface); + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %p.\n", iface, clock); + + if (!clock) + return E_POINTER; + + EnterCriticalSection(&renderer->cs); + + if (renderer->is_shut_down) + hr = MF_E_SHUTDOWN; + else if (renderer->clock) + { + *clock = renderer->clock; + IMFPresentationClock_AddRef(*clock); + } + else + hr = MF_E_NO_CLOCK; + + LeaveCriticalSection(&renderer->cs); + + return hr; }
static HRESULT WINAPI audio_renderer_sink_Shutdown(IMFMediaSink *iface) @@ -325,6 +382,71 @@ static const IMFMediaEventGeneratorVtbl audio_renderer_events_vtbl = audio_renderer_events_QueueEvent, };
+static HRESULT WINAPI audio_renderer_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj) +{ + struct audio_renderer *renderer = impl_from_IMFClockStateSink(iface); + return IMFMediaSink_QueryInterface(&renderer->IMFMediaSink_iface, riid, obj); +} + +static ULONG WINAPI audio_renderer_clock_sink_AddRef(IMFClockStateSink *iface) +{ + struct audio_renderer *renderer = impl_from_IMFClockStateSink(iface); + return IMFMediaSink_AddRef(&renderer->IMFMediaSink_iface); +} + +static ULONG WINAPI audio_renderer_clock_sink_Release(IMFClockStateSink *iface) +{ + struct audio_renderer *renderer = impl_from_IMFClockStateSink(iface); + return IMFMediaSink_Release(&renderer->IMFMediaSink_iface); +} + +static HRESULT WINAPI audio_renderer_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset) +{ + FIXME("%p, %s, %s.\n", iface, debugstr_time(systime), debugstr_time(offset)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI audio_renderer_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime) +{ + FIXME("%p, %s.\n", iface, debugstr_time(systime)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI audio_renderer_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime) +{ + FIXME("%p, %s.\n", iface, debugstr_time(systime)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI audio_renderer_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime) +{ + FIXME("%p, %s.\n", iface, debugstr_time(systime)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI audio_renderer_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate) +{ + FIXME("%p, %s, %f.\n", iface, debugstr_time(systime), rate); + + return E_NOTIMPL; +} + +static const IMFClockStateSinkVtbl audio_renderer_clock_sink_vtbl = +{ + audio_renderer_clock_sink_QueryInterface, + audio_renderer_clock_sink_AddRef, + audio_renderer_clock_sink_Release, + audio_renderer_clock_sink_OnClockStart, + audio_renderer_clock_sink_OnClockStop, + audio_renderer_clock_sink_OnClockPause, + audio_renderer_clock_sink_OnClockRestart, + audio_renderer_clock_sink_OnClockSetRate, +}; + static HRESULT sar_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj) { struct audio_renderer *renderer; @@ -337,6 +459,7 @@ static HRESULT sar_create_object(IMFAttributes *attributes, void *user_context,
renderer->IMFMediaSink_iface.lpVtbl = &audio_renderer_sink_vtbl; renderer->IMFMediaSinkPreroll_iface.lpVtbl = &audio_renderer_preroll_vtbl; + renderer->IMFClockStateSink_iface.lpVtbl = &audio_renderer_clock_sink_vtbl; renderer->IMFMediaEventGenerator_iface.lpVtbl = &audio_renderer_events_vtbl; renderer->refcount = 1; InitializeCriticalSection(&renderer->cs); diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index fcbbde36fb..98e180e453 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -2631,6 +2631,7 @@ static void test_quality_manager(void)
static void test_sar(void) { + IMFPresentationClock *present_clock, *present_clock2; IMFPresentationTimeSource *time_source; IMFClockStateSink *state_sink; IMFMediaSink *sink, *sink2; @@ -2654,6 +2655,12 @@ static void test_sar(void) } ok(hr == S_OK, "Failed to create renderer, hr %#x.\n", hr);
+ hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Startup failure, hr %#x.\n", hr); + + hr = MFCreatePresentationClock(&present_clock); + ok(hr == S_OK, "Failed to create presentation clock, hr %#x.\n", hr); + hr = IMFMediaSink_QueryInterface(sink, &IID_IMFPresentationTimeSource, (void **)&time_source); todo_wine ok(hr == S_OK, "Failed to get time source interface, hr %#x.\n", hr); @@ -2707,6 +2714,36 @@ if (SUCCEEDED(hr)) ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr); IUnknown_Release(unk);
+ /* Clock */ + hr = IMFMediaSink_QueryInterface(sink, &IID_IMFClockStateSink, (void **)&unk); + ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr); + IUnknown_Release(unk); + + hr = IMFMediaSink_SetPresentationClock(sink, NULL); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaSink_SetPresentationClock(sink, present_clock); +todo_wine + ok(hr == MF_E_CLOCK_NO_TIME_SOURCE, "Unexpected hr %#x.\n", hr); + + hr = MFCreateSystemTimeSource(&time_source); + ok(hr == S_OK, "Failed to create time source, hr %#x.\n", hr); + + hr = IMFPresentationClock_SetTimeSource(present_clock, time_source); + ok(hr == S_OK, "Failed to set time source, hr %#x.\n", hr); + IMFPresentationTimeSource_Release(time_source); + + hr = IMFMediaSink_SetPresentationClock(sink, present_clock); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaSink_GetPresentationClock(sink, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaSink_GetPresentationClock(sink, &present_clock2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(present_clock == present_clock2, "Unexpected instance.\n"); + IMFPresentationClock_Release(present_clock2); + /* Shutdown */ hr = IMFMediaSink_Shutdown(sink); ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr); @@ -2729,6 +2766,18 @@ if (SUCCEEDED(hr)) hr = IMFMediaSink_GetCharacteristics(sink, &flags); ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
+ hr = IMFMediaSink_SetPresentationClock(sink, NULL); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaSink_SetPresentationClock(sink, present_clock); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaSink_GetPresentationClock(sink, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaSink_GetPresentationClock(sink, &present_clock2); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr); + IMFMediaSink_Release(sink);
/* Activation */ @@ -2769,6 +2818,11 @@ todo_wine
IMFActivate_Release(activate);
+ IMFPresentationClock_Release(present_clock); + + hr = MFShutdown(); + ok(hr == S_OK, "Shutdown failure, hr %#x.\n", hr); + CoUninitialize(); }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 5 +++++ include/mfidl.idl | 10 ++++++++++ 2 files changed, 15 insertions(+)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 37ea744313..923905399b 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -1647,6 +1647,7 @@ const char *debugstr_attr(const GUID *guid) X(MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES), X(MF_MT_VIDEO_NO_FRAME_ORDERING), X(MF_MT_VIDEO_CHROMA_SITING), + X(MF_AUDIO_RENDERER_ATTRIBUTE_STREAM_CATEGORY), X(MFSampleExtension_3DVideo_SampleFormat), X(MF_MT_H264_RESOLUTION_SCALING), X(MF_MT_MPEG2_LEVEL), @@ -1749,6 +1750,7 @@ const char *debugstr_attr(const GUID *guid) X(MF_MT_SPATIAL_AUDIO_OBJECT_METADATA_FORMAT_ID), X(MF_SAMPLEGRABBERSINK_IGNORE_CLOCK), X(MF_MT_PAN_SCAN_ENABLED), + X(MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID), X(MF_MT_DV_VAUX_CTRL_PACK), X(MFSampleExtension_ForwardedDecodeUnitType), X(MF_MT_AUDIO_AVG_BYTES_PER_SECOND), @@ -1782,6 +1784,8 @@ const char *debugstr_attr(const GUID *guid) X(MF_TOPOLOGY_RESOLUTION_STATUS), X(MF_MT_ORIGINAL_4CC), X(MF_PD_AUDIO_ISVARIABLEBITRATE), + X(MF_AUDIO_RENDERER_ATTRIBUTE_FLAGS), + X(MF_AUDIO_RENDERER_ATTRIBUTE_SESSION_ID), X(MF_MT_MPEG2_CONTENT_PACKET), X(MFT_PROCESS_LOCAL_Attribute), X(MFT_PROCESS_LOCAL_Attribute), @@ -1830,6 +1834,7 @@ const char *debugstr_attr(const GUID *guid) X(MFT_FIELDOFUSE_UNLOCK_Attribute), X(MF_TOPONODE_ERROR_SUBTYPE), X(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE), + X(MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE), X(MF_MT_VIDEO_3D_LEFT_IS_BASE), X(MF_TOPONODE_WORKQUEUE_MMCSS_TASKID), #undef X diff --git a/include/mfidl.idl b/include/mfidl.idl index a5fb8bc0bd..5a7398f290 100644 --- a/include/mfidl.idl +++ b/include/mfidl.idl @@ -967,6 +967,10 @@ cpp_quote(" return attributes->SetUINT64(key, ((UINT64)numerator << 32) | den cpp_quote("}") cpp_quote("#endif")
+cpp_quote("#define MF_AUDIO_RENDERER_ATTRIBUTE_FLAGS_CROSSPROCESS 0x00000001") +cpp_quote("#define MF_AUDIO_RENDERER_ATTRIBUTE_FLAGS_NOPERSIST 0x00000002") +cpp_quote("#define MF_AUDIO_RENDERER_ATTRIBUTE_FLAGS_DONT_ALLOW_FORMAT_CHANGES 0x00000004") + cpp_quote("EXTERN_GUID(MF_ACTIVATE_MFT_LOCKED, 0xc1f6093c, 0x7f65, 0x4fbd, 0x9e, 0x39, 0x5f, 0xae, 0xc3, 0xc4, 0xfb, 0xd7);")
cpp_quote("EXTERN_GUID(MF_SD_LANGUAGE, 0x00af2180, 0xbdc2, 0x423c, 0xab, 0xca, 0xf5, 0x03, 0x59, 0x3b, 0xc1, 0x21);") @@ -1065,4 +1069,10 @@ cpp_quote("EXTERN_GUID(MF_SESSION_REMOTE_SOURCE_MODE, 0xf4033ef4, 0x9bb3, 0x4378 cpp_quote("EXTERN_GUID(MF_SESSION_APPROX_EVENT_OCCURRENCE_TIME, 0x190e852f, 0x6238, 0x42d1, 0xb5, 0xaf, 0x69, 0xea, 0x33, 0x8e, 0xf8, 0x50);") cpp_quote("EXTERN_GUID(MF_PMP_SERVER_CONTEXT, 0x2f00c910, 0xd2cf, 0x4278, 0x8b, 0x6a, 0xd0, 0x77, 0xfa, 0xc3, 0xa2, 0x5f);")
+cpp_quote("EXTERN_GUID(MF_AUDIO_RENDERER_ATTRIBUTE_FLAGS, 0xede4b5e0, 0xf805, 0x4d6c, 0x99, 0xb3, 0xdb, 0x01, 0xbf, 0x95, 0xdf, 0xab);") +cpp_quote("EXTERN_GUID(MF_AUDIO_RENDERER_ATTRIBUTE_SESSION_ID, 0xede4b5e3, 0xf805, 0x4d6c, 0x99, 0xb3, 0xdb, 0x01, 0xbf, 0x95, 0xdf, 0xab);") +cpp_quote("EXTERN_GUID(MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID, 0xb10aaec3, 0xef71, 0x4cc3, 0xb8, 0x73, 0x05, 0xa9, 0xa0, 0x8b, 0x9f, 0x8e);") +cpp_quote("EXTERN_GUID(MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, 0x6ba644ff, 0x27c5, 0x4d02, 0x98, 0x87, 0xc2, 0x86, 0x19, 0xfd, 0xb9, 0x1b);") +cpp_quote("EXTERN_GUID(MF_AUDIO_RENDERER_ATTRIBUTE_STREAM_CATEGORY, 0xa9770471, 0x92ec, 0x4df4, 0x94, 0xfe, 0x81, 0xc3, 0x6f, 0x0c, 0x3a, 0x7a);") + cpp_quote("EXTERN_GUID(CLSID_VideoProcessorMFT, 0x88753b26, 0x5b24, 0x49bd, 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, 0xc9, 0x82);")
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/sar.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ dlls/mf/tests/mf.c | 27 +++++++++++++++++++++++ 2 files changed, 80 insertions(+)
diff --git a/dlls/mf/sar.c b/dlls/mf/sar.c index 2ef767b787..5d74238a91 100644 --- a/dlls/mf/sar.c +++ b/dlls/mf/sar.c @@ -22,6 +22,8 @@ #include "mfidl.h" #include "mferror.h" #include "mf_private.h" +#include "initguid.h" +#include "mmdeviceapi.h"
#include "wine/debug.h" #include "wine/heap.h" @@ -447,9 +449,55 @@ static const IMFClockStateSinkVtbl audio_renderer_clock_sink_vtbl = audio_renderer_clock_sink_OnClockSetRate, };
+static HRESULT sar_create_mmdevice(IMFAttributes *attributes, IMMDevice **device) +{ + WCHAR *endpoint; + unsigned int length, role = eMultimedia; + IMMDeviceEnumerator *devenum; + HRESULT hr; + + if (attributes) + { + /* Mutually exclusive attributes. */ + if (SUCCEEDED(IMFAttributes_GetItem(attributes, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, NULL)) && + SUCCEEDED(IMFAttributes_GetItem(attributes, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID, NULL))) + { + return E_INVALIDARG; + } + } + + if (FAILED(hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, + (void **)&devenum))) + { + return hr; + } + + role = eMultimedia; + if (attributes && SUCCEEDED(IMFAttributes_GetUINT32(attributes, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, &role))) + TRACE("Specified role %d.\n", role); + + if (attributes && SUCCEEDED(IMFAttributes_GetAllocatedString(attributes, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID, + &endpoint, &length))) + { + TRACE("Specified end point %s.\n", debugstr_w(endpoint)); + hr = IMMDeviceEnumerator_GetDevice(devenum, endpoint, device); + CoTaskMemFree(endpoint); + } + else + hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, eRender, role, device); + + if (FAILED(hr)) + hr = MF_E_NO_AUDIO_PLAYBACK_DEVICE; + + IMMDeviceEnumerator_Release(devenum); + + return hr; +} + static HRESULT sar_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj) { struct audio_renderer *renderer; + IMMDevice *device; HRESULT hr;
TRACE("%p, %p, %p.\n", attributes, user_context, obj); @@ -467,6 +515,11 @@ static HRESULT sar_create_object(IMFAttributes *attributes, void *user_context, if (FAILED(hr = MFCreateEventQueue(&renderer->event_queue))) goto failed;
+ if (FAILED(hr = sar_create_mmdevice(attributes, &device))) + goto failed; + + IMMDevice_Release(device); + *obj = (IUnknown *)&renderer->IMFMediaSink_iface;
return S_OK; diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 98e180e453..4f29362102 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -38,6 +38,7 @@ DEFINE_GUID(MFVideoFormat_ABGR32, 0x00000020, 0x0000, 0x0010, 0x80, 0x00, 0x00, #include "mfapi.h" #include "mferror.h" #include "mfidl.h" +#include "mmdeviceapi.h"
#include "wine/test.h"
@@ -2636,6 +2637,7 @@ static void test_sar(void) IMFClockStateSink *state_sink; IMFMediaSink *sink, *sink2; IMFStreamSink *stream_sink; + IMFAttributes *attributes; IMFActivate *activate; MFCLOCK_STATE state; DWORD flags, count; @@ -2823,6 +2825,31 @@ todo_wine hr = MFShutdown(); ok(hr == S_OK, "Shutdown failure, hr %#x.\n", hr);
+ /* SAR attributes */ + hr = MFCreateAttributes(&attributes, 0); + ok(hr == S_OK, "Failed to create attributes, hr %#x.\n", hr); + + /* Specify role. */ + hr = IMFAttributes_SetUINT32(attributes, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, eMultimedia); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + + hr = MFCreateAudioRenderer(attributes, &sink); + ok(hr == S_OK, "Failed to create a sink, hr %#x.\n", hr); + IMFMediaSink_Release(sink); + + /* Invalid endpoint. */ + hr = IMFAttributes_SetString(attributes, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID, L"endpoint"); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + + hr = MFCreateAudioRenderer(attributes, &sink); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = IMFAttributes_DeleteItem(attributes, &MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE); + ok(hr == S_OK, "Failed to remove attribute, hr %#x.\n", hr); + + hr = MFCreateAudioRenderer(attributes, &sink); + ok(hr == MF_E_NO_AUDIO_PLAYBACK_DEVICE, "Failed to create a sink, hr %#x.\n", hr); + CoUninitialize(); }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/sar.c | 249 ++++++++++++++++++++++++++++++++++++++++++++- dlls/mf/tests/mf.c | 60 ++++++++++- 2 files changed, 304 insertions(+), 5 deletions(-)
diff --git a/dlls/mf/sar.c b/dlls/mf/sar.c index 5d74238a91..77025fdc7c 100644 --- a/dlls/mf/sar.c +++ b/dlls/mf/sar.c @@ -30,6 +30,16 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+struct audio_renderer; + +struct audio_renderer_stream +{ + IMFStreamSink IMFStreamSink_iface; + LONG refcount; + struct audio_renderer *sink; + CRITICAL_SECTION cs; +}; + struct audio_renderer { IMFMediaSink IMFMediaSink_iface; @@ -40,6 +50,7 @@ struct audio_renderer IMFMediaEventQueue *event_queue; IMFPresentationClock *clock; BOOL is_shut_down; + struct audio_renderer_stream *stream; CRITICAL_SECTION cs; };
@@ -63,6 +74,11 @@ static struct audio_renderer *impl_from_IMFMediaEventGenerator(IMFMediaEventGene return CONTAINING_RECORD(iface, struct audio_renderer, IMFMediaEventGenerator_iface); }
+static struct audio_renderer_stream *impl_from_IMFStreamSink(IMFStreamSink *iface) +{ + return CONTAINING_RECORD(iface, struct audio_renderer_stream, IMFStreamSink_iface); +} + static HRESULT WINAPI audio_renderer_sink_QueryInterface(IMFMediaSink *iface, REFIID riid, void **obj) { struct audio_renderer *renderer = impl_from_IMFMediaSink(iface); @@ -179,17 +195,54 @@ static HRESULT WINAPI audio_renderer_sink_GetStreamSinkCount(IMFMediaSink *iface static HRESULT WINAPI audio_renderer_sink_GetStreamSinkByIndex(IMFMediaSink *iface, DWORD index, IMFStreamSink **stream) { - FIXME("%p, %u, %p.\n", iface, index, stream); + struct audio_renderer *renderer = impl_from_IMFMediaSink(iface); + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %u, %p.\n", iface, index, stream); + + if (renderer->is_shut_down) + return MF_E_SHUTDOWN; + + EnterCriticalSection(&renderer->cs); + + if (renderer->is_shut_down) + hr = MF_E_SHUTDOWN; + else if (index > 0) + hr = MF_E_INVALIDINDEX; + else + { + *stream = &renderer->stream->IMFStreamSink_iface; + IMFStreamSink_AddRef(*stream); + } + + LeaveCriticalSection(&renderer->cs); + + return hr; }
static HRESULT WINAPI audio_renderer_sink_GetStreamSinkById(IMFMediaSink *iface, DWORD stream_sink_id, IMFStreamSink **stream) { - FIXME("%p, %#x, %p.\n", iface, stream_sink_id, stream); + struct audio_renderer *renderer = impl_from_IMFMediaSink(iface); + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %#x, %p.\n", iface, stream_sink_id, stream); + + EnterCriticalSection(&renderer->cs); + + if (renderer->is_shut_down) + hr = MF_E_SHUTDOWN; + else if (stream_sink_id > 0) + hr = MF_E_INVALIDSTREAMNUMBER; + else + { + *stream = &renderer->stream->IMFStreamSink_iface; + IMFStreamSink_AddRef(*stream); + } + + LeaveCriticalSection(&renderer->cs); + + return hr; }
static HRESULT WINAPI audio_renderer_sink_SetPresentationClock(IMFMediaSink *iface, IMFPresentationClock *clock) @@ -260,8 +313,19 @@ static HRESULT WINAPI audio_renderer_sink_Shutdown(IMFMediaSink *iface) return MF_E_SHUTDOWN;
EnterCriticalSection(&renderer->cs); + renderer->is_shut_down = TRUE; IMFMediaEventQueue_Shutdown(renderer->event_queue); + + /* Detach stream. */ + IMFMediaSink_Release(&renderer->stream->sink->IMFMediaSink_iface); + EnterCriticalSection(&renderer->stream->cs); + renderer->stream->sink = NULL; + LeaveCriticalSection(&renderer->stream->cs); + + IMFStreamSink_Release(&renderer->stream->IMFStreamSink_iface); + renderer->stream = NULL; + LeaveCriticalSection(&renderer->cs);
return S_OK; @@ -494,6 +558,180 @@ static HRESULT sar_create_mmdevice(IMFAttributes *attributes, IMMDevice **device return hr; }
+static HRESULT WINAPI audio_renderer_stream_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFStreamSink) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + } + else + { + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*obj); + + return S_OK; +} + +static ULONG WINAPI audio_renderer_stream_AddRef(IMFStreamSink *iface) +{ + struct audio_renderer_stream *stream = impl_from_IMFStreamSink(iface); + ULONG refcount = InterlockedIncrement(&stream->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI audio_renderer_stream_Release(IMFStreamSink *iface) +{ + struct audio_renderer_stream *stream = impl_from_IMFStreamSink(iface); + ULONG refcount = InterlockedDecrement(&stream->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + if (stream->sink) + IMFMediaSink_Release(&stream->sink->IMFMediaSink_iface); + DeleteCriticalSection(&stream->cs); + heap_free(stream); + } + + return refcount; +} + +static HRESULT WINAPI audio_renderer_stream_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event) +{ + FIXME("%p, %#x, %p.\n", iface, flags, event); + + return E_NOTIMPL; +} + +static HRESULT WINAPI audio_renderer_stream_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback, + IUnknown *state) +{ + FIXME("%p, %p, %p.\n", iface, callback, state); + + return E_NOTIMPL; +} + +static HRESULT WINAPI audio_renderer_stream_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result, + IMFMediaEvent **event) +{ + FIXME("%p, %p, %p.\n", iface, result, event); + + return E_NOTIMPL; +} + +static HRESULT WINAPI audio_renderer_stream_QueueEvent(IMFStreamSink *iface, MediaEventType event_type, + REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) +{ + FIXME("%p, %u, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value); + + return E_NOTIMPL; +} + +static HRESULT WINAPI audio_renderer_stream_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **sink) +{ + struct audio_renderer_stream *stream = impl_from_IMFStreamSink(iface); + + TRACE("%p, %p.\n", iface, sink); + + if (!stream->sink) + return MF_E_STREAMSINK_REMOVED; + + *sink = &stream->sink->IMFMediaSink_iface; + IMFMediaSink_AddRef(*sink); + + return S_OK; +} + +static HRESULT WINAPI audio_renderer_stream_GetIdentifier(IMFStreamSink *iface, DWORD *identifier) +{ + struct audio_renderer_stream *stream = impl_from_IMFStreamSink(iface); + + TRACE("%p, %p.\n", iface, identifier); + + if (!stream->sink) + return MF_E_STREAMSINK_REMOVED; + + *identifier = 0; + + return S_OK; +} + +static HRESULT WINAPI audio_renderer_stream_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler) +{ + FIXME("%p, %p.\n", iface, handler); + + return E_NOTIMPL; +} + +static HRESULT WINAPI audio_renderer_stream_ProcessSample(IMFStreamSink *iface, IMFSample *sample) +{ + FIXME("%p, %p.\n", iface, sample); + + return E_NOTIMPL; +} + +static HRESULT WINAPI audio_renderer_stream_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type, + const PROPVARIANT *marker_value, const PROPVARIANT *context_value) +{ + FIXME("%p, %d, %p, %p.\n", iface, marker_type, marker_value, context_value); + + return E_NOTIMPL; +} + +static HRESULT WINAPI audio_renderer_stream_Flush(IMFStreamSink *iface) +{ + FIXME("%p.\n", iface); + + return E_NOTIMPL; +} + +static const IMFStreamSinkVtbl audio_renderer_stream_vtbl = +{ + audio_renderer_stream_QueryInterface, + audio_renderer_stream_AddRef, + audio_renderer_stream_Release, + audio_renderer_stream_GetEvent, + audio_renderer_stream_BeginGetEvent, + audio_renderer_stream_EndGetEvent, + audio_renderer_stream_QueueEvent, + audio_renderer_stream_GetMediaSink, + audio_renderer_stream_GetIdentifier, + audio_renderer_stream_GetMediaTypeHandler, + audio_renderer_stream_ProcessSample, + audio_renderer_stream_PlaceMarker, + audio_renderer_stream_Flush, +}; + +static HRESULT audio_renderer_create_stream(struct audio_renderer *sink, struct audio_renderer_stream **stream) +{ + struct audio_renderer_stream *object; + + object = heap_alloc_zero(sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + object->IMFStreamSink_iface.lpVtbl = &audio_renderer_stream_vtbl; + object->refcount = 1; + object->sink = sink; + IMFMediaSink_AddRef(&object->sink->IMFMediaSink_iface); + InitializeCriticalSection(&object->cs); + + *stream = object; + + return S_OK; +} + static HRESULT sar_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj) { struct audio_renderer *renderer; @@ -512,6 +750,9 @@ static HRESULT sar_create_object(IMFAttributes *attributes, void *user_context, renderer->refcount = 1; InitializeCriticalSection(&renderer->cs);
+ if (FAILED(hr = audio_renderer_create_stream(renderer, &renderer->stream))) + goto failed; + if (FAILED(hr = MFCreateEventQueue(&renderer->event_queue))) goto failed;
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 4f29362102..3b919d536a 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -38,7 +38,9 @@ DEFINE_GUID(MFVideoFormat_ABGR32, 0x00000020, 0x0000, 0x0010, 0x80, 0x00, 0x00, #include "mfapi.h" #include "mferror.h" #include "mfidl.h" +#include "initguid.h" #include "mmdeviceapi.h" +#include "audioclient.h"
#include "wine/test.h"
@@ -2634,16 +2636,19 @@ static void test_sar(void) { IMFPresentationClock *present_clock, *present_clock2; IMFPresentationTimeSource *time_source; + IMFMediaType *mediatype, *mediatype2; IMFClockStateSink *state_sink; + IMFMediaTypeHandler *handler; IMFMediaSink *sink, *sink2; IMFStreamSink *stream_sink; IMFAttributes *attributes; + DWORD id, flags, count; IMFActivate *activate; MFCLOCK_STATE state; - DWORD flags, count; IMFClock *clock; IUnknown *unk; HRESULT hr; + GUID guid;
hr = CoInitialize(NULL); ok(hr == S_OK, "Failed to initialize, hr %#x.\n", hr); @@ -2746,6 +2751,59 @@ todo_wine ok(present_clock == present_clock2, "Unexpected instance.\n"); IMFPresentationClock_Release(present_clock2);
+ /* Stream */ + hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream_sink); + ok(hr == S_OK, "Failed to get a stream, hr %#x.\n", hr); + + hr = IMFStreamSink_GetIdentifier(stream_sink, &id); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!id, "Unexpected id.\n"); + + hr = IMFStreamSink_GetMediaSink(stream_sink, &sink2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(sink == sink2, "Unexpected object.\n"); + IMFMediaSink_Release(sink2); + + hr = IMFStreamSink_GetMediaTypeHandler(stream_sink, &handler); +todo_wine + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + +if (SUCCEEDED(hr)) +{ + hr = IMFMediaTypeHandler_GetMajorType(handler, &guid); + ok(hr == S_OK, "Failed to get major type, hr %#x.\n", hr); + ok(IsEqualGUID(&guid, &MFMediaType_Audio), "Unexpected type %s.\n", wine_dbgstr_guid(&guid)); + + hr = IMFMediaTypeHandler_GetMediaTypeCount(handler, &count); + ok(hr == S_OK, "Failed to get type count, hr %#x.\n", hr); + ok(count > 0, "Unexpected type count %u.\n", count); + + hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &mediatype); + ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr); + + hr = MFCreateMediaType(&mediatype); + ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr); + + hr = IMFMediaTypeHandler_IsMediaTypeSupported(handler, mediatype, NULL); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#x.\n", hr); + + IMFMediaType_SetGUID(mediatype, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); + hr = IMFMediaTypeHandler_IsMediaTypeSupported(handler, mediatype, NULL); + ok(hr == MF_E_INVALIDMEDIATYPE, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, 0, &mediatype2); + ok(hr == S_OK, "Failed to get media type, hr %#x.\n", hr); + + hr = IMFMediaTypeHandler_IsMediaTypeSupported(handler, mediatype2, NULL); + ok(hr == MF_E_INVALIDMEDIATYPE, "Unexpected hr %#x.\n", hr); + + IMFMediaType_Release(mediatype2); + IMFMediaType_Release(mediatype); + + IMFMediaTypeHandler_Release(handler); +} + IMFStreamSink_Release(stream_sink); + /* Shutdown */ hr = IMFMediaSink_Shutdown(sink); ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/sar.c | 52 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 8 deletions(-)
diff --git a/dlls/mf/sar.c b/dlls/mf/sar.c index 77025fdc7c..0b498b73a7 100644 --- a/dlls/mf/sar.c +++ b/dlls/mf/sar.c @@ -37,6 +37,7 @@ struct audio_renderer_stream IMFStreamSink IMFStreamSink_iface; LONG refcount; struct audio_renderer *sink; + IMFMediaEventQueue *event_queue; CRITICAL_SECTION cs; };
@@ -321,6 +322,7 @@ static HRESULT WINAPI audio_renderer_sink_Shutdown(IMFMediaSink *iface) IMFMediaSink_Release(&renderer->stream->sink->IMFMediaSink_iface); EnterCriticalSection(&renderer->stream->cs); renderer->stream->sink = NULL; + IMFMediaEventQueue_Shutdown(renderer->stream->event_queue); LeaveCriticalSection(&renderer->stream->cs);
IMFStreamSink_Release(&renderer->stream->IMFStreamSink_iface); @@ -600,6 +602,11 @@ static ULONG WINAPI audio_renderer_stream_Release(IMFStreamSink *iface) { if (stream->sink) IMFMediaSink_Release(&stream->sink->IMFMediaSink_iface); + if (stream->event_queue) + { + IMFMediaEventQueue_Shutdown(stream->event_queue); + IMFMediaEventQueue_Release(stream->event_queue); + } DeleteCriticalSection(&stream->cs); heap_free(stream); } @@ -609,33 +616,53 @@ static ULONG WINAPI audio_renderer_stream_Release(IMFStreamSink *iface)
static HRESULT WINAPI audio_renderer_stream_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event) { - FIXME("%p, %#x, %p.\n", iface, flags, event); + struct audio_renderer_stream *stream = impl_from_IMFStreamSink(iface);
- return E_NOTIMPL; + TRACE("%p, %#x, %p.\n", iface, flags, event); + + if (!stream->sink) + return MF_E_STREAMSINK_REMOVED; + + return IMFMediaEventQueue_GetEvent(stream->event_queue, flags, event); }
static HRESULT WINAPI audio_renderer_stream_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback, IUnknown *state) { - FIXME("%p, %p, %p.\n", iface, callback, state); + struct audio_renderer_stream *stream = impl_from_IMFStreamSink(iface);
- return E_NOTIMPL; + TRACE("%p, %p, %p.\n", iface, callback, state); + + if (!stream->sink) + return MF_E_STREAMSINK_REMOVED; + + return IMFMediaEventQueue_BeginGetEvent(stream->event_queue, callback, state); }
static HRESULT WINAPI audio_renderer_stream_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result, IMFMediaEvent **event) { - FIXME("%p, %p, %p.\n", iface, result, event); + struct audio_renderer_stream *stream = impl_from_IMFStreamSink(iface);
- return E_NOTIMPL; + TRACE("%p, %p, %p.\n", iface, result, event); + + if (!stream->sink) + return MF_E_STREAMSINK_REMOVED; + + return IMFMediaEventQueue_EndGetEvent(stream->event_queue, result, event); }
static HRESULT WINAPI audio_renderer_stream_QueueEvent(IMFStreamSink *iface, MediaEventType event_type, REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) { - FIXME("%p, %u, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value); + struct audio_renderer_stream *stream = impl_from_IMFStreamSink(iface);
- return E_NOTIMPL; + TRACE("%p, %u, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value); + + if (!stream->sink) + return MF_E_STREAMSINK_REMOVED; + + return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, event_type, ext_type, hr, value); }
static HRESULT WINAPI audio_renderer_stream_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **sink) @@ -716,6 +743,7 @@ static const IMFStreamSinkVtbl audio_renderer_stream_vtbl = static HRESULT audio_renderer_create_stream(struct audio_renderer *sink, struct audio_renderer_stream **stream) { struct audio_renderer_stream *object; + HRESULT hr;
object = heap_alloc_zero(sizeof(*object)); if (!object) @@ -727,9 +755,17 @@ static HRESULT audio_renderer_create_stream(struct audio_renderer *sink, struct IMFMediaSink_AddRef(&object->sink->IMFMediaSink_iface); InitializeCriticalSection(&object->cs);
+ if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) + goto failed; + *stream = object;
return S_OK; + +failed: + IMFStreamSink_Release(&object->IMFStreamSink_iface); + + return hr; }
static HRESULT sar_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/sar.c | 117 +++++++++++++++++++++++++++++++++++++++++++-- dlls/mf/tests/mf.c | 17 +++++-- 2 files changed, 126 insertions(+), 8 deletions(-)
diff --git a/dlls/mf/sar.c b/dlls/mf/sar.c index 0b498b73a7..4ebd64facf 100644 --- a/dlls/mf/sar.c +++ b/dlls/mf/sar.c @@ -35,6 +35,7 @@ struct audio_renderer; struct audio_renderer_stream { IMFStreamSink IMFStreamSink_iface; + IMFMediaTypeHandler IMFMediaTypeHandler_iface; LONG refcount; struct audio_renderer *sink; IMFMediaEventQueue *event_queue; @@ -80,6 +81,11 @@ static struct audio_renderer_stream *impl_from_IMFStreamSink(IMFStreamSink *ifac return CONTAINING_RECORD(iface, struct audio_renderer_stream, IMFStreamSink_iface); }
+static struct audio_renderer_stream *impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler *iface) +{ + return CONTAINING_RECORD(iface, struct audio_renderer_stream, IMFMediaTypeHandler_iface); +} + static HRESULT WINAPI audio_renderer_sink_QueryInterface(IMFMediaSink *iface, REFIID riid, void **obj) { struct audio_renderer *renderer = impl_from_IMFMediaSink(iface); @@ -562,12 +568,18 @@ static HRESULT sar_create_mmdevice(IMFAttributes *attributes, IMMDevice **device
static HRESULT WINAPI audio_renderer_stream_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj) { + struct audio_renderer_stream *stream = impl_from_IMFStreamSink(iface); + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
if (IsEqualIID(riid, &IID_IMFStreamSink) || IsEqualIID(riid, &IID_IUnknown)) { - *obj = iface; + *obj = &stream->IMFStreamSink_iface; + } + else if (IsEqualIID(riid, &IID_IMFMediaTypeHandler)) + { + *obj = &stream->IMFMediaTypeHandler_iface; } else { @@ -696,9 +708,20 @@ static HRESULT WINAPI audio_renderer_stream_GetIdentifier(IMFStreamSink *iface,
static HRESULT WINAPI audio_renderer_stream_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler) { - FIXME("%p, %p.\n", iface, handler); + struct audio_renderer_stream *stream = impl_from_IMFStreamSink(iface);
- return E_NOTIMPL; + TRACE("%p, %p.\n", iface, handler); + + if (!handler) + return E_POINTER; + + if (!stream->sink) + return MF_E_STREAMSINK_REMOVED; + + *handler = &stream->IMFMediaTypeHandler_iface; + IMFMediaTypeHandler_AddRef(*handler); + + return S_OK; }
static HRESULT WINAPI audio_renderer_stream_ProcessSample(IMFStreamSink *iface, IMFSample *sample) @@ -740,6 +763,93 @@ static const IMFStreamSinkVtbl audio_renderer_stream_vtbl = audio_renderer_stream_Flush, };
+static HRESULT WINAPI audio_renderer_stream_type_handler_QueryInterface(IMFMediaTypeHandler *iface, REFIID riid, + void **obj) +{ + struct audio_renderer_stream *stream = impl_from_IMFMediaTypeHandler(iface); + return IMFStreamSink_QueryInterface(&stream->IMFStreamSink_iface, riid, obj); +} + +static ULONG WINAPI audio_renderer_stream_type_handler_AddRef(IMFMediaTypeHandler *iface) +{ + struct audio_renderer_stream *stream = impl_from_IMFMediaTypeHandler(iface); + return IMFStreamSink_AddRef(&stream->IMFStreamSink_iface); +} + +static ULONG WINAPI audio_renderer_stream_type_handler_Release(IMFMediaTypeHandler *iface) +{ + struct audio_renderer_stream *stream = impl_from_IMFMediaTypeHandler(iface); + return IMFStreamSink_Release(&stream->IMFStreamSink_iface); +} + +static HRESULT WINAPI audio_renderer_stream_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler *iface, + IMFMediaType *in_type, IMFMediaType **out_type) +{ + FIXME("%p, %p, %p.\n", iface, in_type, out_type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI audio_renderer_stream_type_handler_GetMediaTypeCount(IMFMediaTypeHandler *iface, DWORD *count) +{ + FIXME("%p, %p.\n", iface, count); + + return E_NOTIMPL; +} + +static HRESULT WINAPI audio_renderer_stream_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler *iface, DWORD index, + IMFMediaType **media_type) +{ + FIXME("%p, %u, %p.\n", iface, index, media_type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI audio_renderer_stream_type_handler_SetCurrentMediaType(IMFMediaTypeHandler *iface, + IMFMediaType *media_type) +{ + FIXME("%p, %p.\n", iface, media_type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI audio_renderer_stream_type_handler_GetCurrentMediaType(IMFMediaTypeHandler *iface, + IMFMediaType **media_type) +{ + FIXME("%p, %p.\n", iface, media_type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI audio_renderer_stream_type_handler_GetMajorType(IMFMediaTypeHandler *iface, GUID *type) +{ + struct audio_renderer_stream *stream = impl_from_IMFMediaTypeHandler(iface); + + TRACE("%p, %p.\n", iface, type); + + if (!type) + return E_POINTER; + + if (!stream->sink) + return MF_E_STREAMSINK_REMOVED; + + memcpy(type, &MFMediaType_Audio, sizeof(*type)); + return S_OK; +} + +static const IMFMediaTypeHandlerVtbl audio_renderer_stream_type_handler_vtbl = +{ + audio_renderer_stream_type_handler_QueryInterface, + audio_renderer_stream_type_handler_AddRef, + audio_renderer_stream_type_handler_Release, + audio_renderer_stream_type_handler_IsMediaTypeSupported, + audio_renderer_stream_type_handler_GetMediaTypeCount, + audio_renderer_stream_type_handler_GetMediaTypeByIndex, + audio_renderer_stream_type_handler_SetCurrentMediaType, + audio_renderer_stream_type_handler_GetCurrentMediaType, + audio_renderer_stream_type_handler_GetMajorType, +}; + static HRESULT audio_renderer_create_stream(struct audio_renderer *sink, struct audio_renderer_stream **stream) { struct audio_renderer_stream *object; @@ -750,6 +860,7 @@ static HRESULT audio_renderer_create_stream(struct audio_renderer *sink, struct return E_OUTOFMEMORY;
object->IMFStreamSink_iface.lpVtbl = &audio_renderer_stream_vtbl; + object->IMFMediaTypeHandler_iface.lpVtbl = &audio_renderer_stream_type_handler_vtbl; object->refcount = 1; object->sink = sink; IMFMediaSink_AddRef(&object->sink->IMFMediaSink_iface); diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 3b919d536a..72c70fcafe 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -2635,10 +2635,10 @@ static void test_quality_manager(void) static void test_sar(void) { IMFPresentationClock *present_clock, *present_clock2; + IMFMediaTypeHandler *handler, *handler2; IMFPresentationTimeSource *time_source; IMFMediaType *mediatype, *mediatype2; IMFClockStateSink *state_sink; - IMFMediaTypeHandler *handler; IMFMediaSink *sink, *sink2; IMFStreamSink *stream_sink; IMFAttributes *attributes; @@ -2765,19 +2765,26 @@ todo_wine IMFMediaSink_Release(sink2);
hr = IMFStreamSink_GetMediaTypeHandler(stream_sink, &handler); -todo_wine ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
-if (SUCCEEDED(hr)) -{ + hr = IMFStreamSink_QueryInterface(stream_sink, &IID_IMFMediaTypeHandler, (void **)&handler2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(handler2 == handler, "Unexpected instance.\n"); + IMFMediaTypeHandler_Release(handler2); + hr = IMFMediaTypeHandler_GetMajorType(handler, &guid); ok(hr == S_OK, "Failed to get major type, hr %#x.\n", hr); ok(IsEqualGUID(&guid, &MFMediaType_Audio), "Unexpected type %s.\n", wine_dbgstr_guid(&guid));
+ count = 0; hr = IMFMediaTypeHandler_GetMediaTypeCount(handler, &count); +todo_wine { ok(hr == S_OK, "Failed to get type count, hr %#x.\n", hr); - ok(count > 0, "Unexpected type count %u.\n", count); + ok(!!count, "Unexpected type count %u.\n", count); +}
+if (SUCCEEDED(hr)) +{ hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &mediatype); ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/mediatype.c | 71 ++++++++++++++++++++++++++++ dlls/mfplat/mfplat.spec | 2 +- dlls/mfplat/tests/mfplat.c | 97 ++++++++++++++++++++++++++++++++++++++ include/mfapi.h | 1 + 4 files changed, 170 insertions(+), 1 deletion(-)
diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 196d803722..b832e00bdd 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -2089,3 +2089,74 @@ HRESULT WINAPI MFCreateWaveFormatExFromMFMediaType(IMFMediaType *mediatype, WAVE
return S_OK; } + +static void mediatype_set_uint32(IMFMediaType *mediatype, const GUID *attr, unsigned int value, HRESULT *hr) +{ + if (SUCCEEDED(*hr)) + *hr = IMFMediaType_SetUINT32(mediatype, attr, value); +} + +static void mediatype_set_guid(IMFMediaType *mediatype, const GUID *attr, const GUID *value, HRESULT *hr) +{ + if (SUCCEEDED(*hr)) + *hr = IMFMediaType_SetGUID(mediatype, attr, value); +} + +/*********************************************************************** + * MFInitMediaTypeFromWaveFormatEx (mfplat.@) + */ +HRESULT WINAPI MFInitMediaTypeFromWaveFormatEx(IMFMediaType *mediatype, const WAVEFORMATEX *format, UINT32 size) +{ + GUID subtype; + HRESULT hr; + + TRACE("%p, %p, %u.\n", mediatype, format, size); + + if (!mediatype || !format) + return E_POINTER; + + if (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE) + { + FIXME("WAVE_FORMAT_EXTENSIBLE is not supported.\n"); + return E_NOTIMPL; + } + else + { + hr = IMFMediaType_DeleteAllItems(mediatype); + + mediatype_set_guid(mediatype, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio, &hr); + + memcpy(&subtype, &MFAudioFormat_Base, sizeof(subtype)); + subtype.Data1 = format->wFormatTag; + mediatype_set_guid(mediatype, &MF_MT_SUBTYPE, &subtype, &hr); + + if (format->nChannels) + mediatype_set_uint32(mediatype, &MF_MT_AUDIO_NUM_CHANNELS, format->nChannels, &hr); + + if (format->nSamplesPerSec) + mediatype_set_uint32(mediatype, &MF_MT_AUDIO_SAMPLES_PER_SECOND, format->nSamplesPerSec, &hr); + + if (format->nAvgBytesPerSec) + mediatype_set_uint32(mediatype, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, format->nAvgBytesPerSec, &hr); + + if (format->nBlockAlign) + mediatype_set_uint32(mediatype, &MF_MT_AUDIO_BLOCK_ALIGNMENT, format->nBlockAlign, &hr); + + if (format->wBitsPerSample) + mediatype_set_uint32(mediatype, &MF_MT_AUDIO_BITS_PER_SAMPLE, format->wBitsPerSample, &hr); + + mediatype_set_uint32(mediatype, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1, &hr); + } + + switch (subtype.Data1) + { + case WAVE_FORMAT_PCM: + case WAVE_FORMAT_IEEE_FLOAT: + mediatype_set_uint32(mediatype, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1, &hr); + break; + default: + FIXME("Unhandled type %d.\n", subtype.Data1); + } + + return hr; +} diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 25e5f62f21..a1833312fc 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -121,7 +121,7 @@ @ stub MFInitMediaTypeFromMPEG2VideoInfo @ stub MFInitMediaTypeFromVideoInfoHeader2 @ stub MFInitMediaTypeFromVideoInfoHeader -@ stub MFInitMediaTypeFromWaveFormatEx +@ stdcall MFInitMediaTypeFromWaveFormatEx(ptr ptr long) @ stub MFInitVideoFormat @ stub MFInitVideoFormat_RGB @ stdcall MFInvokeCallback(ptr) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 78d73b7580..d9fbff570f 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -5084,6 +5084,102 @@ static void test_MFCreateMediaBufferFromMediaType(void) IMFMediaType_Release(media_type); }
+static void validate_media_type(IMFMediaType *mediatype, const WAVEFORMATEX *format) +{ + GUID guid, subtype; + UINT32 value; + HRESULT hr; + + hr = IMFMediaType_GetMajorType(mediatype, &guid); + ok(hr == S_OK, "Failed to get major type, hr %#x.\n", hr); + ok(IsEqualGUID(&guid, &MFMediaType_Audio), "Unexpected major type %s.\n", wine_dbgstr_guid(&guid)); + + hr = IMFMediaType_GetGUID(mediatype, &MF_MT_SUBTYPE, &guid); + ok(hr == S_OK, "Failed to get subtype, hr %#x.\n", hr); + + if (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE) + { + } + else + { + memcpy(&subtype, &MFAudioFormat_Base, sizeof(subtype)); + subtype.Data1 = format->wFormatTag; + ok(IsEqualGUID(&guid, &subtype), "Unexpected subtype %s.\n", wine_dbgstr_guid(&guid)); + + if (format->nChannels) + { + hr = IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_NUM_CHANNELS, &value); + ok(hr == S_OK, "Failed to get attribute, hr %#x.\n", hr); + ok(value == format->nChannels, "Unexpected NUM_CHANNELS %u.\n", value); + } + + if (format->nSamplesPerSec) + { + hr = IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &value); + ok(hr == S_OK, "Failed to get attribute, hr %#x.\n", hr); + ok(value == format->nSamplesPerSec, "Unexpected SAMPLES_PER_SECOND %u.\n", value); + } + + if (format->nAvgBytesPerSec) + { + hr = IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &value); + ok(hr == S_OK, "Failed to get attribute, hr %#x.\n", hr); + ok(value == format->nAvgBytesPerSec, "Unexpected AVG_BYTES_PER_SECOND %u.\n", value); + } + + if (format->nBlockAlign) + { + hr = IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &value); + ok(hr == S_OK, "Failed to get attribute, hr %#x.\n", hr); + ok(value == format->nBlockAlign, "Unexpected BLOCK_ALIGNMENT %u.\n", value); + } + + if (format->wBitsPerSample) + { + hr = IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_BITS_PER_SAMPLE, &value); + ok(hr == S_OK, "Failed to get attribute, hr %#x.\n", hr); + ok(value == format->wBitsPerSample, "Unexpected BITS_PER_SAMPLE %u.\n", value); + } + + hr = IMFMediaType_GetUINT32(mediatype, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, &value); + ok(hr == S_OK, "Failed to get attribute, hr %#x.\n", hr); + ok(value, "Unexpected value.\n"); + } + + /* Only set for uncompressed formats. */ + if (SUCCEEDED(IMFMediaType_GetUINT32(mediatype, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value))) + ok(value, "Unexpected ALL_SAMPLES_INDEPENDENT value.\n"); +} + +static void test_MFInitMediaTypeFromWaveFormatEx(void) +{ + static const WAVEFORMATEX waveformatex_tests[] = + { + { WAVE_FORMAT_PCM, 2, 44100, 0, 2, 8 }, + { WAVE_FORMAT_PCM, 2, 44100, 1, 2, 8 }, + { WAVE_FORMAT_PCM, 0, 44100, 0, 0, 0 }, + { WAVE_FORMAT_PCM, 0, 0, 0, 0, 0 }, + { 1234, 0, 0, 0, 0, 0 }, + { WAVE_FORMAT_MPEGLAYER3, 0, 0, 0, 0, 0 }, + }; + IMFMediaType *mediatype; + unsigned int i; + HRESULT hr; + + hr = MFCreateMediaType(&mediatype); + ok(hr == S_OK, "Failed to create mediatype, hr %#x.\n", hr); + + for (i = 0; i < ARRAY_SIZE(waveformatex_tests); ++i) + { + hr = MFInitMediaTypeFromWaveFormatEx(mediatype, &waveformatex_tests[i], sizeof(waveformatex_tests[i])); + ok(hr == S_OK, "Failed to initialize media type, hr %#x.\n", hr); + + validate_media_type(mediatype, &waveformatex_tests[i]); + } + + IMFMediaType_Release(mediatype); +} + START_TEST(mfplat) { char **argv; @@ -5138,6 +5234,7 @@ START_TEST(mfplat) test_MFGetStrideForBitmapInfoHeader(); test_MFCreate2DMediaBuffer(); test_MFCreateMediaBufferFromMediaType(); + test_MFInitMediaTypeFromWaveFormatEx();
CoUninitialize(); } diff --git a/include/mfapi.h b/include/mfapi.h index b9383630ab..c8ae665b10 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -532,6 +532,7 @@ HRESULT WINAPI MFTEnumEx(GUID category, UINT32 flags, const MFT_REGISTER_TYPE_IN const MFT_REGISTER_TYPE_INFO *output_type, IMFActivate ***activate, UINT32 *pcount); HRESULT WINAPI MFInitAttributesFromBlob(IMFAttributes *attributes, const UINT8 *buffer, UINT size); +HRESULT WINAPI MFInitMediaTypeFromWaveFormatEx(IMFMediaType *mediatype, const WAVEFORMATEX *format, UINT32 size); HRESULT WINAPI MFInvokeCallback(IMFAsyncResult *result); HRESULT WINAPI MFLockPlatform(void); HRESULT WINAPI MFPutWorkItem(DWORD queue, IMFAsyncCallback *callback, IUnknown *state);