Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
v3: So since there were quite a few changes to the patch series, I haven't applied all of them yet, since I wasn't sure; but at least we should be able to get the first few patches out of the way now.
I did add a test to show the downstream source is still used with put_Filter. In fact, I even test the filter first to show it has only one pin with MEDIATYPE_Stream, but the detector reports 2 pins (because of the splitter).
But here's the things I did not do. Perhaps they may not be needed now. However, if you think they are still needed to be changed, please let me know again and I'll change them.
I didn't use strmbase on the tests. I didn't split the tests into a separate function. This is needed for proper testing. I kept the QueryFilterInfo for the custom filter since I was uncomfortable otherwise.
Maybe they make more sense now that the tests are split.
Unless I missed something, all the other things should have been changed as suggested.
I also dropped IMediaPosition so it matches Windows more. It can always be added as a separate patch later, if needed.
dlls/qedit/mediadet.c | 18 ++++++++++++++++-- dlls/qedit/tests/mediadet.c | 19 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/dlls/qedit/mediadet.c b/dlls/qedit/mediadet.c index ecfafc4..94bc1be 100644 --- a/dlls/qedit/mediadet.c +++ b/dlls/qedit/mediadet.c @@ -28,6 +28,7 @@ #include "ole2.h"
#include "qedit_private.h" +#include "wine/strmbase.h" #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(qedit); @@ -283,8 +284,21 @@ static HRESULT WINAPI MediaDet_put_CurrentStream(IMediaDet* iface, LONG newVal) static HRESULT WINAPI MediaDet_get_StreamType(IMediaDet* iface, GUID *pVal) { MediaDetImpl *This = impl_from_IMediaDet(iface); - FIXME("(%p)->(%s): not implemented!\n", This, debugstr_guid(pVal)); - return E_NOTIMPL; + AM_MEDIA_TYPE mt; + HRESULT hr; + + TRACE("(%p)->(%p)\n", This, pVal); + + if (!pVal) + return E_POINTER; + + hr = IMediaDet_get_StreamMediaType(&This->IMediaDet_iface, &mt); + if (FAILED(hr)) + return hr; + FreeMediaType(&mt); + + *pVal = mt.majortype; + return hr; }
static HRESULT WINAPI MediaDet_get_StreamTypeB(IMediaDet* iface, BSTR *pVal) diff --git a/dlls/qedit/tests/mediadet.c b/dlls/qedit/tests/mediadet.c index 65f5af7..c92c187 100644 --- a/dlls/qedit/tests/mediadet.c +++ b/dlls/qedit/tests/mediadet.c @@ -192,6 +192,7 @@ static void test_mediadet(void) BSTR filename = NULL; LONG nstrms = 0; LONG strm; + GUID guid; AM_MEDIA_TYPE mt; double fps; int flags; @@ -242,6 +243,12 @@ static void test_mediadet(void) hr = IMediaDet_get_StreamMediaType(pM, NULL); ok(hr == E_POINTER, "IMediaDet_get_StreamMediaType failed: %08x\n", hr);
+ hr = IMediaDet_get_StreamType(pM, &guid); + ok(hr == E_INVALIDARG, "IMediaDet_get_StreamType failed: %08x\n", hr); + + hr = IMediaDet_get_StreamType(pM, NULL); + ok(hr == E_POINTER, "IMediaDet_get_StreamType failed: %08x\n", hr); + filename = SysAllocString(test_avi_filename); hr = IMediaDet_put_Filename(pM, filename); ok(hr == S_OK, "IMediaDet_put_Filename failed: %08x\n", hr); @@ -258,6 +265,10 @@ static void test_mediadet(void) ok(hr == S_OK, "IMediaDet_get_StreamMediaType failed: %08x\n", hr); CoTaskMemFree(mt.pbFormat);
+ hr = IMediaDet_get_StreamType(pM, &guid); + ok(hr == S_OK, "IMediaDet_get_StreamType failed: %08x\n", hr); + ok(IsEqualGUID(&guid, &MEDIATYPE_Video), "Wrong GUID %s\n", wine_dbgstr_guid(&guid)); + /* Even before get_OutputStreams. */ hr = IMediaDet_put_CurrentStream(pM, 1); ok(hr == E_INVALIDARG, "IMediaDet_put_CurrentStream failed: %08x\n", hr); @@ -311,6 +322,10 @@ static void test_mediadet(void) "IMediaDet_get_StreamMediaType\n"); CoTaskMemFree(mt.pbFormat);
+ hr = IMediaDet_get_StreamType(pM, &guid); + ok(hr == S_OK, "IMediaDet_get_StreamType failed: %08x\n", hr); + ok(IsEqualGUID(&guid, &MEDIATYPE_Video), "Wrong GUID %s\n", wine_dbgstr_guid(&guid)); + hr = IMediaDet_get_FrameRate(pM, NULL); ok(hr == E_POINTER, "IMediaDet_get_FrameRate failed: %08x\n", hr);
@@ -370,6 +385,10 @@ static void test_mediadet(void)
if (IsEqualGUID(&mt.majortype, &MEDIATYPE_Audio)) { + hr = IMediaDet_get_StreamType(pM, &guid); + ok(hr == S_OK, "IMediaDet_get_StreamType failed: %08x\n", hr); + ok(IsEqualGUID(&guid, &MEDIATYPE_Audio), "Wrong GUID %s\n", wine_dbgstr_guid(&guid)); + hr = IMediaDet_get_FrameRate(pM, &fps); ok(hr == VFW_E_INVALIDMEDIATYPE, "IMediaDet_get_FrameRate failed: %08x\n", hr); }
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/qedit/mediadet.c | 16 ++++++++++++++-- dlls/qedit/tests/mediadet.c | 22 ++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/dlls/qedit/mediadet.c b/dlls/qedit/mediadet.c index 94bc1be..1883a12 100644 --- a/dlls/qedit/mediadet.c +++ b/dlls/qedit/mediadet.c @@ -304,8 +304,20 @@ static HRESULT WINAPI MediaDet_get_StreamType(IMediaDet* iface, GUID *pVal) static HRESULT WINAPI MediaDet_get_StreamTypeB(IMediaDet* iface, BSTR *pVal) { MediaDetImpl *This = impl_from_IMediaDet(iface); - FIXME("(%p)->(%p): not implemented!\n", This, pVal); - return E_NOTIMPL; + HRESULT hr; + GUID guid; + + TRACE("(%p)->(%p)\n", This, pVal); + + hr = IMediaDet_get_StreamType(&This->IMediaDet_iface, &guid); + if (FAILED(hr)) + return hr; + + if (!(*pVal = SysAllocStringLen(NULL, CHARS_IN_GUID - 1))) + return E_OUTOFMEMORY; + + StringFromGUID2(&guid, *pVal, CHARS_IN_GUID); + return hr; }
static HRESULT WINAPI MediaDet_get_StreamLength(IMediaDet* iface, double *pVal) diff --git a/dlls/qedit/tests/mediadet.c b/dlls/qedit/tests/mediadet.c index c92c187..596171b 100644 --- a/dlls/qedit/tests/mediadet.c +++ b/dlls/qedit/tests/mediadet.c @@ -193,6 +193,7 @@ static void test_mediadet(void) LONG nstrms = 0; LONG strm; GUID guid; + BSTR bstr; AM_MEDIA_TYPE mt; double fps; int flags; @@ -249,6 +250,12 @@ static void test_mediadet(void) hr = IMediaDet_get_StreamType(pM, NULL); ok(hr == E_POINTER, "IMediaDet_get_StreamType failed: %08x\n", hr);
+ hr = IMediaDet_get_StreamTypeB(pM, &bstr); + ok(hr == E_INVALIDARG, "IMediaDet_get_StreamTypeB failed: %08x\n", hr); + + hr = IMediaDet_get_StreamTypeB(pM, NULL); + ok(hr == E_INVALIDARG, "IMediaDet_get_StreamTypeB failed: %08x\n", hr); + filename = SysAllocString(test_avi_filename); hr = IMediaDet_put_Filename(pM, filename); ok(hr == S_OK, "IMediaDet_put_Filename failed: %08x\n", hr); @@ -269,6 +276,11 @@ static void test_mediadet(void) ok(hr == S_OK, "IMediaDet_get_StreamType failed: %08x\n", hr); ok(IsEqualGUID(&guid, &MEDIATYPE_Video), "Wrong GUID %s\n", wine_dbgstr_guid(&guid));
+ hr = IMediaDet_get_StreamTypeB(pM, &bstr); + ok(hr == S_OK, "IMediaDet_get_StreamTypeB failed: %08x\n", hr); + ok(!wcscmp(bstr, L"{73646976-0000-0010-8000-00AA00389B71}"), "Wrong GUID %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + /* Even before get_OutputStreams. */ hr = IMediaDet_put_CurrentStream(pM, 1); ok(hr == E_INVALIDARG, "IMediaDet_put_CurrentStream failed: %08x\n", hr); @@ -326,6 +338,11 @@ static void test_mediadet(void) ok(hr == S_OK, "IMediaDet_get_StreamType failed: %08x\n", hr); ok(IsEqualGUID(&guid, &MEDIATYPE_Video), "Wrong GUID %s\n", wine_dbgstr_guid(&guid));
+ hr = IMediaDet_get_StreamTypeB(pM, &bstr); + ok(hr == S_OK, "IMediaDet_get_StreamTypeB failed: %08x\n", hr); + ok(!wcscmp(bstr, L"{73646976-0000-0010-8000-00AA00389B71}"), "Wrong GUID %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + hr = IMediaDet_get_FrameRate(pM, NULL); ok(hr == E_POINTER, "IMediaDet_get_FrameRate failed: %08x\n", hr);
@@ -389,6 +406,11 @@ static void test_mediadet(void) ok(hr == S_OK, "IMediaDet_get_StreamType failed: %08x\n", hr); ok(IsEqualGUID(&guid, &MEDIATYPE_Audio), "Wrong GUID %s\n", wine_dbgstr_guid(&guid));
+ hr = IMediaDet_get_StreamTypeB(pM, &bstr); + ok(hr == S_OK, "IMediaDet_get_StreamTypeB failed: %08x\n", hr); + ok(!wcscmp(bstr, L"{73647561-0000-0010-8000-00AA00389B71}"), "Wrong GUID %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + hr = IMediaDet_get_FrameRate(pM, &fps); ok(hr == VFW_E_INVALIDMEDIATYPE, "IMediaDet_get_FrameRate failed: %08x\n", hr); }
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/qedit/mediadet.c | 15 ++++++++++-- dlls/qedit/tests/mediadet.c | 48 ++++++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 3 deletions(-)
diff --git a/dlls/qedit/mediadet.c b/dlls/qedit/mediadet.c index 1883a12..c2cc33e 100644 --- a/dlls/qedit/mediadet.c +++ b/dlls/qedit/mediadet.c @@ -147,8 +147,19 @@ static ULONG WINAPI MediaDet_Release(IMediaDet *iface) static HRESULT WINAPI MediaDet_get_Filter(IMediaDet* iface, IUnknown **pVal) { MediaDetImpl *This = impl_from_IMediaDet(iface); - FIXME("(%p)->(%p): not implemented!\n", This, pVal); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, pVal); + + if (!pVal) + return E_POINTER; + + *pVal = (IUnknown*)This->source; + if (*pVal) + IUnknown_AddRef(*pVal); + else + return S_FALSE; + + return S_OK; }
static HRESULT WINAPI MediaDet_put_Filter(IMediaDet* iface, IUnknown *newVal) diff --git a/dlls/qedit/tests/mediadet.c b/dlls/qedit/tests/mediadet.c index 596171b..ccf7f0b 100644 --- a/dlls/qedit/tests/mediadet.c +++ b/dlls/qedit/tests/mediadet.c @@ -188,13 +188,19 @@ static BOOL init_tests(void) static void test_mediadet(void) { HRESULT hr; + FILTER_INFO filter_info; + IEnumMediaTypes *type; IMediaDet *pM = NULL; BSTR filename = NULL; + IBaseFilter *filter; + IEnumPins *pins; LONG nstrms = 0; LONG strm; GUID guid; BSTR bstr; - AM_MEDIA_TYPE mt; + IPin *pin; + AM_MEDIA_TYPE mt, *pmt; + IUnknown *unk; double fps; int flags; int i; @@ -256,6 +262,14 @@ static void test_mediadet(void) hr = IMediaDet_get_StreamTypeB(pM, NULL); ok(hr == E_INVALIDARG, "IMediaDet_get_StreamTypeB failed: %08x\n", hr);
+ hr = IMediaDet_get_Filter(pM, NULL); + ok(hr == E_POINTER, "IMediaDet_get_Filter failed: %08x\n", hr); + + unk = (IUnknown*)0xdeadbeef; + hr = IMediaDet_get_Filter(pM, &unk); + ok(hr == S_FALSE, "IMediaDet_get_Filter failed: %08x\n", hr); + ok(unk == NULL, "Wrong filter %p\n", unk); + filename = SysAllocString(test_avi_filename); hr = IMediaDet_put_Filename(pM, filename); ok(hr == S_OK, "IMediaDet_put_Filename failed: %08x\n", hr); @@ -427,6 +441,38 @@ static void test_mediadet(void) ok(hr == S_OK, "IMediaDet_get_CurrentStream failed: %08x\n", hr); ok(strm == 1, "IMediaDet_get_CurrentStream: strm is %i\n", strm);
+ hr = IMediaDet_get_Filter(pM, &unk); + ok(hr == S_OK, "IMediaDet_get_Filter failed: %08x\n", hr); + ok(unk != NULL, "NULL filter\n"); + hr = IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void**)&filter); + IUnknown_Release(unk); + ok(hr == S_OK, "Could not get IBaseFilter interface: %08x\n", hr); + + hr = IBaseFilter_EnumPins(filter, &pins); + ok(hr == S_OK, "IBaseFilter_EnumPins failed: %08x\n", hr); + hr = IEnumPins_Next(pins, 1, &pin, NULL); + ok(hr == S_OK, "IEnumPins_Next failed: %08x\n", hr); + hr = IPin_EnumMediaTypes(pin, &type); + ok(hr == S_OK, "IPin_EnumMediaTypes failed: %08x\n", hr); + hr = IEnumMediaTypes_Next(type, 1, &pmt, NULL); + ok(hr == S_OK, "IEnumMediaTypes_Next failed: %08x\n", hr); + ok(IsEqualGUID(&pmt->majortype, &MEDIATYPE_Stream), "Wrong GUID %s\n", wine_dbgstr_guid(&pmt->majortype)); + IEnumMediaTypes_Release(type); + CoTaskMemFree(pmt->pbFormat); + CoTaskMemFree(pmt); + IPin_Release(pin); + + hr = IEnumPins_Next(pins, 1, &pin, NULL); + ok(hr == S_FALSE, "IEnumPins_Next failed: %08x\n", hr); + IEnumPins_Release(pins); + + hr = IBaseFilter_QueryFilterInfo(filter, &filter_info); + ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed: %08x\n", hr); +todo_wine + ok(!wcscmp(filter_info.achName, L"Source"), "Wrong filter name: %s\n", wine_dbgstr_w(filter_info.achName)); + IFilterGraph_Release(filter_info.pGraph); + IBaseFilter_Release(filter); + hr = IMediaDet_Release(pM); ok(hr == 0, "IMediaDet_Release returned: %x\n", hr);
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/qedit/mediadet.c | 2 +- dlls/qedit/tests/mediadet.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/dlls/qedit/mediadet.c b/dlls/qedit/mediadet.c index c2cc33e..e5aeefb 100644 --- a/dlls/qedit/mediadet.c +++ b/dlls/qedit/mediadet.c @@ -537,7 +537,7 @@ static HRESULT WINAPI MediaDet_put_Filename(IMediaDet* iface, BSTR newVal) if (FAILED(hr)) return hr;
- if (FAILED(hr = IGraphBuilder_AddSourceFilter(gb, newVal, L"Reader", &bf))) + if (FAILED(hr = IGraphBuilder_AddSourceFilter(gb, newVal, L"Source", &bf))) { IGraphBuilder_Release(gb); return hr; diff --git a/dlls/qedit/tests/mediadet.c b/dlls/qedit/tests/mediadet.c index ccf7f0b..0a7f1cc 100644 --- a/dlls/qedit/tests/mediadet.c +++ b/dlls/qedit/tests/mediadet.c @@ -468,7 +468,6 @@ static void test_mediadet(void)
hr = IBaseFilter_QueryFilterInfo(filter, &filter_info); ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed: %08x\n", hr); -todo_wine ok(!wcscmp(filter_info.achName, L"Source"), "Wrong filter name: %s\n", wine_dbgstr_w(filter_info.achName)); IFilterGraph_Release(filter_info.pGraph); IBaseFilter_Release(filter);
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/qedit/mediadet.c | 70 +++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/dlls/qedit/mediadet.c b/dlls/qedit/mediadet.c index e5aeefb..6f9cd08 100644 --- a/dlls/qedit/mediadet.c +++ b/dlls/qedit/mediadet.c @@ -70,6 +70,40 @@ static void MD_cleanup(MediaDetImpl *This) This->cur_stream = 0; }
+/* From quartz, 2008/04/07 */ +static HRESULT get_filter_info(IMoniker *pMoniker, GUID *pclsid, VARIANT *pvar) +{ + IPropertyBag *pPropBagCat = NULL; + HRESULT hr; + + VariantInit(pvar); + V_VT(pvar) = VT_BSTR; + + hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, + (LPVOID *) &pPropBagCat); + + if (SUCCEEDED(hr)) + hr = IPropertyBag_Read(pPropBagCat, L"CLSID", pvar, NULL); + + if (SUCCEEDED(hr)) + { + hr = CLSIDFromString(V_BSTR(pvar), pclsid); + VariantClear(pvar); + V_VT(pvar) = VT_BSTR; + } + + if (SUCCEEDED(hr)) + hr = IPropertyBag_Read(pPropBagCat, L"FriendlyName", pvar, NULL); + + if (SUCCEEDED(hr)) + TRACE("Moniker = %s - %s\n", debugstr_guid(pclsid), debugstr_w(V_BSTR(pvar))); + + if (pPropBagCat) + IPropertyBag_Release(pPropBagCat); + + return hr; +} + /* MediaDet inner IUnknown */ static HRESULT WINAPI MediaDet_inner_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) { @@ -374,40 +408,6 @@ static HRESULT WINAPI MediaDet_get_Filename(IMediaDet* iface, BSTR *pVal) return S_OK; }
-/* From quartz, 2008/04/07 */ -static HRESULT GetFilterInfo(IMoniker *pMoniker, GUID *pclsid, VARIANT *pvar) -{ - IPropertyBag *pPropBagCat = NULL; - HRESULT hr; - - VariantInit(pvar); - V_VT(pvar) = VT_BSTR; - - hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, - (LPVOID *) &pPropBagCat); - - if (SUCCEEDED(hr)) - hr = IPropertyBag_Read(pPropBagCat, L"CLSID", pvar, NULL); - - if (SUCCEEDED(hr)) - { - hr = CLSIDFromString(V_BSTR(pvar), pclsid); - VariantClear(pvar); - V_VT(pvar) = VT_BSTR; - } - - if (SUCCEEDED(hr)) - hr = IPropertyBag_Read(pPropBagCat, L"FriendlyName", pvar, NULL); - - if (SUCCEEDED(hr)) - TRACE("Moniker = %s - %s\n", debugstr_guid(pclsid), debugstr_w(V_BSTR(pvar))); - - if (pPropBagCat) - IPropertyBag_Release(pPropBagCat); - - return hr; -} - static HRESULT GetSplitter(MediaDetImpl *This) { IFileSourceFilter *file; @@ -460,7 +460,7 @@ static HRESULT GetSplitter(MediaDetImpl *This) hr = E_NOINTERFACE; while (IEnumMoniker_Next(filters, 1, &mon, NULL) == S_OK) { - hr = GetFilterInfo(mon, &clsid, &var); + hr = get_filter_info(mon, &clsid, &var); IMoniker_Release(mon); if (FAILED(hr)) continue;
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/qedit/mediadet.c | 220 +++++++++++++++++++++--------------------- 1 file changed, 110 insertions(+), 110 deletions(-)
diff --git a/dlls/qedit/mediadet.c b/dlls/qedit/mediadet.c index 6f9cd08..193aa3b 100644 --- a/dlls/qedit/mediadet.c +++ b/dlls/qedit/mediadet.c @@ -104,6 +104,115 @@ static HRESULT get_filter_info(IMoniker *pMoniker, GUID *pclsid, VARIANT *pvar) return hr; }
+static HRESULT get_splitter(MediaDetImpl *This) +{ + IFileSourceFilter *file; + LPOLESTR name; + AM_MEDIA_TYPE mt; + GUID type[2]; + IFilterMapper2 *map; + IEnumMoniker *filters; + IMoniker *mon; + VARIANT var; + GUID clsid; + IBaseFilter *splitter; + IEnumPins *pins; + IPin *source_pin, *splitter_pin; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, + &IID_IFilterMapper2, (void **) &map); + if (FAILED(hr)) + return hr; + + hr = IBaseFilter_QueryInterface(This->source, &IID_IFileSourceFilter, + (void **) &file); + if (FAILED(hr)) + { + IFilterMapper2_Release(map); + return hr; + } + + hr = IFileSourceFilter_GetCurFile(file, &name, &mt); + IFileSourceFilter_Release(file); + CoTaskMemFree(name); + if (FAILED(hr)) + { + IFilterMapper2_Release(map); + return hr; + } + type[0] = mt.majortype; + type[1] = mt.subtype; + CoTaskMemFree(mt.pbFormat); + + hr = IFilterMapper2_EnumMatchingFilters(map, &filters, 0, TRUE, + MERIT_UNLIKELY, FALSE, 1, type, + NULL, NULL, FALSE, TRUE, + 0, NULL, NULL, NULL); + IFilterMapper2_Release(map); + if (FAILED(hr)) + return hr; + + hr = E_NOINTERFACE; + while (IEnumMoniker_Next(filters, 1, &mon, NULL) == S_OK) + { + hr = get_filter_info(mon, &clsid, &var); + IMoniker_Release(mon); + if (FAILED(hr)) + continue; + + hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, + &IID_IBaseFilter, (void **) &splitter); + if (FAILED(hr)) + { + VariantClear(&var); + continue; + } + + hr = IGraphBuilder_AddFilter(This->graph, splitter, V_BSTR(&var)); + VariantClear(&var); + This->splitter = splitter; + if (FAILED(hr)) + goto retry; + + hr = IBaseFilter_EnumPins(This->source, &pins); + if (FAILED(hr)) + goto retry; + IEnumPins_Next(pins, 1, &source_pin, NULL); + IEnumPins_Release(pins); + + hr = IBaseFilter_EnumPins(splitter, &pins); + if (FAILED(hr)) + { + IPin_Release(source_pin); + goto retry; + } + if (IEnumPins_Next(pins, 1, &splitter_pin, NULL) != S_OK) + { + IEnumPins_Release(pins); + IPin_Release(source_pin); + goto retry; + } + IEnumPins_Release(pins); + + hr = IPin_Connect(source_pin, splitter_pin, NULL); + IPin_Release(source_pin); + IPin_Release(splitter_pin); + if (SUCCEEDED(hr)) + break; + +retry: + IBaseFilter_Release(splitter); + This->splitter = NULL; + } + + IEnumMoniker_Release(filters); + if (FAILED(hr)) + return hr; + + return S_OK; +} + /* MediaDet inner IUnknown */ static HRESULT WINAPI MediaDet_inner_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) { @@ -408,115 +517,6 @@ static HRESULT WINAPI MediaDet_get_Filename(IMediaDet* iface, BSTR *pVal) return S_OK; }
-static HRESULT GetSplitter(MediaDetImpl *This) -{ - IFileSourceFilter *file; - LPOLESTR name; - AM_MEDIA_TYPE mt; - GUID type[2]; - IFilterMapper2 *map; - IEnumMoniker *filters; - IMoniker *mon; - VARIANT var; - GUID clsid; - IBaseFilter *splitter; - IEnumPins *pins; - IPin *source_pin, *splitter_pin; - HRESULT hr; - - hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, - &IID_IFilterMapper2, (void **) &map); - if (FAILED(hr)) - return hr; - - hr = IBaseFilter_QueryInterface(This->source, &IID_IFileSourceFilter, - (void **) &file); - if (FAILED(hr)) - { - IFilterMapper2_Release(map); - return hr; - } - - hr = IFileSourceFilter_GetCurFile(file, &name, &mt); - IFileSourceFilter_Release(file); - CoTaskMemFree(name); - if (FAILED(hr)) - { - IFilterMapper2_Release(map); - return hr; - } - type[0] = mt.majortype; - type[1] = mt.subtype; - CoTaskMemFree(mt.pbFormat); - - hr = IFilterMapper2_EnumMatchingFilters(map, &filters, 0, TRUE, - MERIT_UNLIKELY, FALSE, 1, type, - NULL, NULL, FALSE, TRUE, - 0, NULL, NULL, NULL); - IFilterMapper2_Release(map); - if (FAILED(hr)) - return hr; - - hr = E_NOINTERFACE; - while (IEnumMoniker_Next(filters, 1, &mon, NULL) == S_OK) - { - hr = get_filter_info(mon, &clsid, &var); - IMoniker_Release(mon); - if (FAILED(hr)) - continue; - - hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, - &IID_IBaseFilter, (void **) &splitter); - if (FAILED(hr)) - { - VariantClear(&var); - continue; - } - - hr = IGraphBuilder_AddFilter(This->graph, splitter, V_BSTR(&var)); - VariantClear(&var); - This->splitter = splitter; - if (FAILED(hr)) - goto retry; - - hr = IBaseFilter_EnumPins(This->source, &pins); - if (FAILED(hr)) - goto retry; - IEnumPins_Next(pins, 1, &source_pin, NULL); - IEnumPins_Release(pins); - - hr = IBaseFilter_EnumPins(splitter, &pins); - if (FAILED(hr)) - { - IPin_Release(source_pin); - goto retry; - } - if (IEnumPins_Next(pins, 1, &splitter_pin, NULL) != S_OK) - { - IEnumPins_Release(pins); - IPin_Release(source_pin); - goto retry; - } - IEnumPins_Release(pins); - - hr = IPin_Connect(source_pin, splitter_pin, NULL); - IPin_Release(source_pin); - IPin_Release(splitter_pin); - if (SUCCEEDED(hr)) - break; - -retry: - IBaseFilter_Release(splitter); - This->splitter = NULL; - } - - IEnumMoniker_Release(filters); - if (FAILED(hr)) - return hr; - - return S_OK; -} - static HRESULT WINAPI MediaDet_put_Filename(IMediaDet* iface, BSTR newVal) { MediaDetImpl *This = impl_from_IMediaDet(iface); @@ -545,7 +545,7 @@ static HRESULT WINAPI MediaDet_put_Filename(IMediaDet* iface, BSTR newVal)
This->graph = gb; This->source = bf; - hr = GetSplitter(This); + hr = get_splitter(This); if (FAILED(hr)) return hr;
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/qedit/mediadet.c | 44 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-)
diff --git a/dlls/qedit/mediadet.c b/dlls/qedit/mediadet.c index 193aa3b..0f9bdee 100644 --- a/dlls/qedit/mediadet.c +++ b/dlls/qedit/mediadet.c @@ -308,8 +308,48 @@ static HRESULT WINAPI MediaDet_get_Filter(IMediaDet* iface, IUnknown **pVal) static HRESULT WINAPI MediaDet_put_Filter(IMediaDet* iface, IUnknown *newVal) { MediaDetImpl *This = impl_from_IMediaDet(iface); - FIXME("(%p)->(%p): not implemented!\n", This, newVal); - return E_NOTIMPL; + IGraphBuilder *gb; + IBaseFilter *bf; + HRESULT hr; + + TRACE("(%p)->(%p)\n", This, newVal); + + if (!newVal) + return E_POINTER; + + hr = IUnknown_QueryInterface(newVal, &IID_IBaseFilter, (void **) &bf); + if (FAILED(hr)) + return hr; + + if (This->graph) + MD_cleanup(This); + + hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, + &IID_IGraphBuilder, (void **) &gb); + if (FAILED(hr)) + { + IBaseFilter_Release(bf); + return hr; + } + + if (FAILED(hr = IGraphBuilder_AddFilter(gb, bf, L"Source"))) + { + IGraphBuilder_Release(gb); + IBaseFilter_Release(bf); + return hr; + } + + This->graph = gb; + This->source = bf; + hr = get_splitter(This); + if (FAILED(hr)) + { + /* No splitter found, use the source directly */ + This->splitter = This->source; + IBaseFilter_AddRef(This->splitter); + } + + return IMediaDet_put_CurrentStream(&This->IMediaDet_iface, 0); }
static HRESULT WINAPI MediaDet_get_OutputStreams(IMediaDet* iface, LONG *pVal)
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/qedit/tests/mediadet.c | 681 +++++++++++++++++++++++++++++++++++- 1 file changed, 680 insertions(+), 1 deletion(-)
diff --git a/dlls/qedit/tests/mediadet.c b/dlls/qedit/tests/mediadet.c index 0a7f1cc..1fa2bb6 100644 --- a/dlls/qedit/tests/mediadet.c +++ b/dlls/qedit/tests/mediadet.c @@ -24,6 +24,7 @@ #include "ole2.h" #include "vfwmsgs.h" #include "uuids.h" +#include "dshow.h" #include "wine/test.h" #include "qedit.h" #include "control.h" @@ -71,6 +72,588 @@ static const IUnknownVtbl outer_vtbl =
static IUnknown test_outer = {&outer_vtbl};
+struct testfilter +{ + IBaseFilter IBaseFilter_iface; + LONG ref; + WCHAR *name; + IFilterGraph *graph; + FILTER_STATE state; + + IEnumPins IEnumPins_iface; + UINT enum_idx; + + IPin IPin_iface; + IPin *peer; + + IEnumMediaTypes IEnumMediaTypes_iface; + UINT mt_enum_idx; +}; + +static inline struct testfilter *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface) +{ + return CONTAINING_RECORD(iface, struct testfilter, IEnumMediaTypes_iface); +} + +static HRESULT WINAPI testenummt_QueryInterface(IEnumMediaTypes *iface, REFIID iid, void **out) +{ + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI testenummt_AddRef(IEnumMediaTypes *iface) +{ + struct testfilter *filter = impl_from_IEnumMediaTypes(iface); + return IBaseFilter_AddRef(&filter->IBaseFilter_iface); +} + +static ULONG WINAPI testenummt_Release(IEnumMediaTypes *iface) +{ + struct testfilter *filter = impl_from_IEnumMediaTypes(iface); + return IBaseFilter_Release(&filter->IBaseFilter_iface); +} + +static HRESULT WINAPI testenummt_Next(IEnumMediaTypes *iface, ULONG count, AM_MEDIA_TYPE **out, ULONG *fetched) +{ + struct testfilter *filter = impl_from_IEnumMediaTypes(iface); + ULONG i = 0; + + if (winetest_debug > 1) trace("IEnumMediaTypes_Next(%u)\n", count); + + if (count && !filter->mt_enum_idx) + { + static const VIDEOINFOHEADER source_format = + { + .bmiHeader.biSize = sizeof(BITMAPINFOHEADER), + .bmiHeader.biWidth = 640, + .bmiHeader.biHeight = 480, + .bmiHeader.biPlanes = 1, + .bmiHeader.biBitCount = 24, + .bmiHeader.biCompression = BI_RGB, + .bmiHeader.biSizeImage = 640 * 480 * 3 + }; + AM_MEDIA_TYPE source_type = + { + .majortype = MEDIATYPE_Video, + .subtype = MEDIASUBTYPE_RGB24, + .bFixedSizeSamples = TRUE, + .lSampleSize = source_format.bmiHeader.biSizeImage, + .formattype = FORMAT_VideoInfo, + .cbFormat = sizeof(source_format) + }; + + source_type.pbFormat = CoTaskMemAlloc(sizeof(source_format)); + memcpy(source_type.pbFormat, &source_format, sizeof(source_format)); + + out[i] = CoTaskMemAlloc(sizeof(*out[i])); + *out[i++] = source_type; + } + + if (fetched) *fetched = i; + filter->mt_enum_idx += i; + + return (i == count) ? S_OK : S_FALSE; +} + +static HRESULT WINAPI testenummt_Skip(IEnumMediaTypes *iface, ULONG count) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI testenummt_Reset(IEnumMediaTypes *iface) +{ + struct testfilter *filter = impl_from_IEnumMediaTypes(iface); + + filter->mt_enum_idx = 0; + return S_OK; +} + +static HRESULT WINAPI testenummt_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **out) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static const IEnumMediaTypesVtbl testenummt_vtbl = +{ + testenummt_QueryInterface, + testenummt_AddRef, + testenummt_Release, + testenummt_Next, + testenummt_Skip, + testenummt_Reset, + testenummt_Clone +}; + +static inline struct testfilter *impl_from_IPin(IPin *iface) +{ + return CONTAINING_RECORD(iface, struct testfilter, IPin_iface); +} + +static HRESULT WINAPI testpin_QueryInterface(IPin *iface, REFIID iid, void **out) +{ + struct testfilter *filter = impl_from_IPin(iface); + if (winetest_debug > 1) trace("IPin_QueryInterface(%s)\n", wine_dbgstr_guid(iid)); + + if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IPin)) + *out = &filter->IPin_iface; + else + { + *out = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static ULONG WINAPI testpin_AddRef(IPin *iface) +{ + struct testfilter *filter = impl_from_IPin(iface); + return IBaseFilter_AddRef(&filter->IBaseFilter_iface); +} + +static ULONG WINAPI testpin_Release(IPin *iface) +{ + struct testfilter *filter = impl_from_IPin(iface); + return IBaseFilter_Release(&filter->IBaseFilter_iface); +} + +static HRESULT WINAPI testpin_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt) +{ + struct testfilter *filter = impl_from_IPin(iface); + IEnumMediaTypes *enummt; + AM_MEDIA_TYPE *pmt; + HRESULT hr; + + if (winetest_debug > 1) trace("IPin_Connect(%p)\n", peer); + + ok(!mt, "Got media type %p\n", mt); + + IPin_EnumMediaTypes(iface, &enummt); + IEnumMediaTypes_Next(enummt, 1, &pmt, NULL); + IEnumMediaTypes_Reset(enummt); + IEnumMediaTypes_Release(enummt); + + hr = IPin_ReceiveConnection(peer, &filter->IPin_iface, pmt); + CoTaskMemFree(pmt->pbFormat); + CoTaskMemFree(pmt); + if (FAILED(hr)) + return hr; + + filter->peer = peer; + IPin_AddRef(peer); + return S_OK; +} + +static HRESULT WINAPI testpin_ReceiveConnection(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI testpin_Disconnect(IPin *iface) +{ + struct testfilter *filter = impl_from_IPin(iface); + if (winetest_debug > 1) trace("IPin_Disconnect()\n"); + + if (filter->peer) + { + IPin_Release(filter->peer); + filter->peer = NULL; + } + return S_OK; +} + +static HRESULT WINAPI testpin_ConnectedTo(IPin *iface, IPin **peer) +{ + struct testfilter *filter = impl_from_IPin(iface); + if (winetest_debug > 1) trace("IPin_ConnectedTo()\n"); + + if (!filter->peer) + return VFW_E_NOT_CONNECTED; + + *peer = filter->peer; + IPin_AddRef(*peer); + return S_OK; +} + +static HRESULT WINAPI testpin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mt) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI testpin_QueryPinInfo(IPin *iface, PIN_INFO *info) +{ + struct testfilter *filter = impl_from_IPin(iface); + if (winetest_debug > 1) trace("IPin_QueryPinInfo()\n"); + + info->pFilter = &filter->IBaseFilter_iface; + IBaseFilter_AddRef(&filter->IBaseFilter_iface); + info->dir = PINDIR_OUTPUT; + wcscpy(info->achName, L"testpin"); + return S_OK; +} + +static HRESULT WINAPI testpin_QueryDirection(IPin *iface, PIN_DIRECTION *dir) +{ + if (winetest_debug > 1) trace("IPin_QueryDirection()\n"); + + *dir = PINDIR_OUTPUT; + return S_OK; +} + +static HRESULT WINAPI testpin_QueryId(IPin *iface, WCHAR **id) +{ + if (winetest_debug > 1) trace("IPin_QueryId()\n"); + + if (!(*id = CoTaskMemAlloc(sizeof(L"deadbeef")))) + return E_OUTOFMEMORY; + + wcscpy(*id, L"deadbeef"); + return S_OK; +} + +static HRESULT WINAPI testpin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mt) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI testpin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **out) +{ + struct testfilter *filter = impl_from_IPin(iface); + if (winetest_debug > 1) trace("IPin_EnumMediaTypes()\n"); + + *out = &filter->IEnumMediaTypes_iface; + IEnumMediaTypes_AddRef(*out); + filter->mt_enum_idx = 0; + return S_OK; +} + +static HRESULT WINAPI testpin_QueryInternalConnections(IPin *iface, IPin **out, ULONG *count) +{ + if (winetest_debug > 1) trace("IPin_QueryInternalConnections()\n"); + + *count = 0; + return S_OK; +} + +static HRESULT WINAPI testpin_EndOfStream(IPin *iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI testpin_BeginFlush(IPin *iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI testpin_EndFlush(IPin *iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI testpin_NewSegment(IPin *iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static const IPinVtbl testpin_vtbl = +{ + testpin_QueryInterface, + testpin_AddRef, + testpin_Release, + testpin_Connect, + testpin_ReceiveConnection, + testpin_Disconnect, + testpin_ConnectedTo, + testpin_ConnectionMediaType, + testpin_QueryPinInfo, + testpin_QueryDirection, + testpin_QueryId, + testpin_QueryAccept, + testpin_EnumMediaTypes, + testpin_QueryInternalConnections, + testpin_EndOfStream, + testpin_BeginFlush, + testpin_EndFlush, + testpin_NewSegment +}; + +static inline struct testfilter *impl_from_IEnumPins(IEnumPins *iface) +{ + return CONTAINING_RECORD(iface, struct testfilter, IEnumPins_iface); +} + +static HRESULT WINAPI testenumpins_QueryInterface(IEnumPins *iface, REFIID iid, void **out) +{ + ok(0, "Unexpected call with iid %s.\n", wine_dbgstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI testenumpins_AddRef(IEnumPins *iface) +{ + struct testfilter *filter = impl_from_IEnumPins(iface); + return IBaseFilter_AddRef(&filter->IBaseFilter_iface); +} + +static ULONG WINAPI testenumpins_Release(IEnumPins *iface) +{ + struct testfilter *filter = impl_from_IEnumPins(iface); + return IBaseFilter_Release(&filter->IBaseFilter_iface); +} + +static HRESULT WINAPI testenumpins_Next(IEnumPins *iface, ULONG count, IPin **out, ULONG *fetched) +{ + struct testfilter *filter = impl_from_IEnumPins(iface); + ULONG i = 0; + + if (winetest_debug > 1) trace("IEnumPins_Next(%u)\n", count); + + /* Only report one pin */ + if (count && !filter->enum_idx) + { + out[i] = &filter->IPin_iface; + IPin_AddRef(out[i++]); + } + + if (fetched) *fetched = i; + filter->enum_idx += i; + + return (i == count) ? S_OK : S_FALSE; +} + +static HRESULT WINAPI testenumpins_Skip(IEnumPins *iface, ULONG count) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI testenumpins_Reset(IEnumPins *iface) +{ + struct testfilter *filter = impl_from_IEnumPins(iface); + + filter->enum_idx = 0; + return S_OK; +} + +static HRESULT WINAPI testenumpins_Clone(IEnumPins *iface, IEnumPins **out) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static const IEnumPinsVtbl testenumpins_vtbl = +{ + testenumpins_QueryInterface, + testenumpins_AddRef, + testenumpins_Release, + testenumpins_Next, + testenumpins_Skip, + testenumpins_Reset, + testenumpins_Clone +}; + +static inline struct testfilter *impl_from_IBaseFilter(IBaseFilter *iface) +{ + return CONTAINING_RECORD(iface, struct testfilter, IBaseFilter_iface); +} + +static HRESULT WINAPI testfilter_QueryInterface(IBaseFilter *iface, REFIID iid, void **out) +{ + struct testfilter *filter = impl_from_IBaseFilter(iface); + + if (winetest_debug > 1) trace("QueryInterface(%s)\n", wine_dbgstr_guid(iid)); + + if (IsEqualGUID(iid, &IID_IUnknown) + || IsEqualGUID(iid, &IID_IPersist) + || IsEqualGUID(iid, &IID_IMediaFilter) + || IsEqualGUID(iid, &IID_IBaseFilter)) + { + *out = &filter->IBaseFilter_iface; + } + else + { + if (IsEqualGUID(iid, &IID_IFileSourceFilter)) todo_wine ok(0, "Filter queried for IFileSourceFilter\n"); + + *out = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static ULONG WINAPI testfilter_AddRef(IBaseFilter *iface) +{ + struct testfilter *filter = impl_from_IBaseFilter(iface); + return InterlockedIncrement(&filter->ref); +} + +static ULONG WINAPI testfilter_Release(IBaseFilter *iface) +{ + struct testfilter *filter = impl_from_IBaseFilter(iface); + LONG ref = InterlockedDecrement(&filter->ref); + + if (!ref) + { + free(filter->name); + free(filter); + } + return ref; +} + +static HRESULT WINAPI testfilter_GetClassID(IBaseFilter *iface, CLSID *clsid) +{ + if (winetest_debug > 1) trace("IBaseFilter_GetClassID()\n"); + + memset(clsid, 0xde, sizeof(*clsid)); + return S_OK; +} + +static HRESULT WINAPI testfilter_Stop(IBaseFilter *iface) +{ + struct testfilter *filter = impl_from_IBaseFilter(iface); + if (winetest_debug > 1) trace("IBaseFilter_Stop()\n"); + + filter->state = State_Stopped; + return S_OK; +} + +static HRESULT WINAPI testfilter_Pause(IBaseFilter *iface) +{ + struct testfilter *filter = impl_from_IBaseFilter(iface); + if (winetest_debug > 1) trace("IBaseFilter_Pause()\n"); + + filter->state = State_Paused; + return S_OK; +} + +static HRESULT WINAPI testfilter_Run(IBaseFilter *iface, REFERENCE_TIME start) +{ + struct testfilter *filter = impl_from_IBaseFilter(iface); + if (winetest_debug > 1) trace("IBaseFilter_Run()\n"); + + filter->state = State_Running; + return S_OK; +} + +static HRESULT WINAPI testfilter_GetState(IBaseFilter *iface, DWORD timeout, FILTER_STATE *state) +{ + struct testfilter *filter = impl_from_IBaseFilter(iface); + if (winetest_debug > 1) trace("IBaseFilter_GetState()\n"); + + *state = filter->state; + return S_OK; +} + +static HRESULT WINAPI testfilter_SetSyncSource(IBaseFilter *iface, IReferenceClock *clock) +{ + if (winetest_debug > 1) trace("IBaseFilter_SetSyncSource()\n"); + return S_OK; +} + +static HRESULT WINAPI testfilter_GetSyncSource(IBaseFilter *iface, IReferenceClock **clock) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI testfilter_EnumPins(IBaseFilter *iface, IEnumPins **out) +{ + struct testfilter *filter = impl_from_IBaseFilter(iface); + if (winetest_debug > 1) trace("IBaseFilter_EnumPins()\n"); + + *out = &filter->IEnumPins_iface; + IEnumPins_AddRef(*out); + filter->enum_idx = 0; + return S_OK; +} + +static HRESULT WINAPI testfilter_FindPin(IBaseFilter *iface, const WCHAR *id, IPin **pin) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI testfilter_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *info) +{ + struct testfilter *filter = impl_from_IBaseFilter(iface); + if (winetest_debug > 1) trace("IBaseFilter_QueryFilterInfo()\n"); + + info->pGraph = filter->graph; + if (filter->graph) + IFilterGraph_AddRef(filter->graph); + if (filter->name) + wcscpy(info->achName, filter->name); + else + info->achName[0] = 0; + return S_OK; +} + +static HRESULT WINAPI testfilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *graph, const WCHAR *name) +{ + struct testfilter *filter = impl_from_IBaseFilter(iface); + if (winetest_debug > 1) trace("IBaseFilter_JoinFilterGraph()\n"); + + filter->graph = graph; + free(filter->name); + if (name) + { + filter->name = malloc((wcslen(name) + 1) * sizeof(WCHAR)); + wcscpy(filter->name, name); + } + else + filter->name = NULL; + return S_OK; +} + +static HRESULT WINAPI testfilter_QueryVendorInfo(IBaseFilter *iface, WCHAR **info) +{ + return E_NOTIMPL; +} + +static const IBaseFilterVtbl testfilter_vtbl = +{ + testfilter_QueryInterface, + testfilter_AddRef, + testfilter_Release, + testfilter_GetClassID, + testfilter_Stop, + testfilter_Pause, + testfilter_Run, + testfilter_GetState, + testfilter_SetSyncSource, + testfilter_GetSyncSource, + testfilter_EnumPins, + testfilter_FindPin, + testfilter_QueryFilterInfo, + testfilter_JoinFilterGraph, + testfilter_QueryVendorInfo +}; + +static IBaseFilter *create_testfilter(void) +{ + struct testfilter *filter = malloc(sizeof(*filter)); + + memset(filter, 0, sizeof(*filter)); + filter->IBaseFilter_iface.lpVtbl = &testfilter_vtbl; + filter->IEnumPins_iface.lpVtbl = &testenumpins_vtbl; + filter->IPin_iface.lpVtbl = &testpin_vtbl; + filter->IEnumMediaTypes_iface.lpVtbl = &testenummt_vtbl; + filter->ref = 1; + filter->state = State_Stopped; + + return &filter->IBaseFilter_iface; +} + static void test_aggregation(void) { IMediaDet *detector, *detector2; @@ -188,11 +771,12 @@ static BOOL init_tests(void) static void test_mediadet(void) { HRESULT hr; + IBaseFilter *filter, *filter2; FILTER_INFO filter_info; IEnumMediaTypes *type; IMediaDet *pM = NULL; BSTR filename = NULL; - IBaseFilter *filter; + IFilterGraph *graph; IEnumPins *pins; LONG nstrms = 0; LONG strm; @@ -270,6 +854,53 @@ static void test_mediadet(void) ok(hr == S_FALSE, "IMediaDet_get_Filter failed: %08x\n", hr); ok(unk == NULL, "Wrong filter %p\n", unk);
+ hr = IMediaDet_put_Filter(pM, NULL); + ok(hr == E_POINTER, "IMediaDet_put_Filter failed: %08x\n", hr); + + filter = create_testfilter(); + hr = IMediaDet_put_Filter(pM, (IUnknown*)filter); + ok(hr == S_OK, "IMediaDet_put_Filter failed: %08x\n", hr); + + hr = IMediaDet_get_Filter(pM, &unk); + ok(hr == S_OK, "IMediaDet_get_Filter failed: %08x\n", hr); + ok(unk != NULL, "NULL filter\n"); + hr = IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void**)&filter2); + IUnknown_Release(unk); + ok(hr == S_OK, "Could not get IBaseFilter interface: %08x\n", hr); + ok(filter == filter2, "Wrong filter\n"); + IBaseFilter_Release(filter2); + + hr = IBaseFilter_QueryFilterInfo(filter, &filter_info); + ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed: %08x\n", hr); + ok(!wcscmp(filter_info.achName, L"Source"), "Wrong filter name: %s\n", wine_dbgstr_w(filter_info.achName)); + IBaseFilter_Release(filter); + graph = filter_info.pGraph; + + filter = create_testfilter(); + hr = IMediaDet_put_Filter(pM, (IUnknown*)filter); + ok(hr == S_OK, "IMediaDet_put_Filter failed: %08x\n", hr); + IBaseFilter_Release(filter); + + hr = IMediaDet_get_Filter(pM, &unk); + ok(hr == S_OK, "IMediaDet_get_Filter failed: %08x\n", hr); + ok(unk != NULL, "NULL filter\n"); + hr = IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void**)&filter); + IUnknown_Release(unk); + ok(hr == S_OK, "Could not get IBaseFilter interface: %08x\n", hr); + + hr = IBaseFilter_QueryFilterInfo(filter, &filter_info); + ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed: %08x\n", hr); + ok(!wcscmp(filter_info.achName, L"Source"), "Wrong filter name: %s\n", wine_dbgstr_w(filter_info.achName)); + ok(graph != filter_info.pGraph, "Same filter graph was used\n"); + IFilterGraph_Release(filter_info.pGraph); + IFilterGraph_Release(graph); + IBaseFilter_Release(filter); + + strm = -1; + hr = IMediaDet_get_CurrentStream(pM, &strm); + ok(hr == S_OK, "IMediaDet_get_CurrentStream failed: %08x\n", hr); + ok(strm == 0, "IMediaDet_get_CurrentStream: strm is %i\n", strm); + filename = SysAllocString(test_avi_filename); hr = IMediaDet_put_Filename(pM, filename); ok(hr == S_OK, "IMediaDet_put_Filename failed: %08x\n", hr); @@ -469,9 +1100,57 @@ static void test_mediadet(void) hr = IBaseFilter_QueryFilterInfo(filter, &filter_info); ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed: %08x\n", hr); ok(!wcscmp(filter_info.achName, L"Source"), "Wrong filter name: %s\n", wine_dbgstr_w(filter_info.achName)); + graph = filter_info.pGraph; + + filter2 = create_testfilter(); + hr = IMediaDet_put_Filter(pM, (IUnknown*)filter2); + ok(hr == S_OK, "IMediaDet_put_Filter failed: %08x\n", hr); + IBaseFilter_Release(filter2); + + hr = IMediaDet_get_Filter(pM, &unk); + ok(hr == S_OK, "IMediaDet_get_Filter failed: %08x\n", hr); + ok(unk != NULL, "NULL filter\n"); + hr = IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void**)&filter2); + IUnknown_Release(unk); + ok(hr == S_OK, "Could not get IBaseFilter interface: %08x\n", hr); + ok(filter != filter2, "Same filter\n"); + + hr = IBaseFilter_QueryFilterInfo(filter2, &filter_info); + ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed: %08x\n", hr); + ok(!wcscmp(filter_info.achName, L"Source"), "Wrong filter name: %s\n", wine_dbgstr_w(filter_info.achName)); + ok(graph != filter_info.pGraph, "Same filter graph was used\n"); IFilterGraph_Release(filter_info.pGraph); + IFilterGraph_Release(graph); + IBaseFilter_Release(filter2); + + filename = NULL; + hr = IMediaDet_get_Filename(pM, &filename); +todo_wine + ok(hr == S_OK, "IMediaDet_get_Filename failed: %08x\n", hr); + ok(!filename, "Expected NULL filename, got %s.\n", debugstr_w(filename)); + SysFreeString(filename); + + hr = IMediaDet_get_OutputStreams(pM, &nstrms); + ok(hr == S_OK, "IMediaDet_get_OutputStreams failed: %08x\n", hr); + ok(nstrms == 1, "IMediaDet_get_OutputStreams: nstrms is %i\n", nstrms); + + /* Now use the filter obtained from put_Filename for put_Filter. */ + hr = IMediaDet_put_Filter(pM, (IUnknown*)filter); + ok(hr == S_OK, "IMediaDet_put_Filter failed: %08x\n", hr); IBaseFilter_Release(filter);
+ filename = NULL; + hr = IMediaDet_get_Filename(pM, &filename); + ok(hr == S_OK, "IMediaDet_get_Filename failed: %08x\n", hr); +todo_wine + ok(!filename, "Expected NULL filename, got %s.\n", debugstr_w(filename)); + SysFreeString(filename); + + /* It still looks for a downstream source and splits it into video+audio in this case. */ + hr = IMediaDet_get_OutputStreams(pM, &nstrms); + ok(hr == S_OK, "IMediaDet_get_OutputStreams failed: %08x\n", hr); + ok(nstrms == 2, "IMediaDet_get_OutputStreams: nstrms is %i\n", nstrms); + hr = IMediaDet_Release(pM); ok(hr == 0, "IMediaDet_Release returned: %x\n", hr);
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/qedit/mediadet.c | 30 ++++++++++++++---------------- dlls/qedit/tests/mediadet.c | 2 -- 2 files changed, 14 insertions(+), 18 deletions(-)
diff --git a/dlls/qedit/mediadet.c b/dlls/qedit/mediadet.c index 0f9bdee..aa9d5ee 100644 --- a/dlls/qedit/mediadet.c +++ b/dlls/qedit/mediadet.c @@ -41,6 +41,7 @@ typedef struct MediaDetImpl { IGraphBuilder *graph; IBaseFilter *source; IBaseFilter *splitter; + WCHAR *filename; LONG num_streams; LONG cur_stream; IPin *cur_pin; @@ -66,6 +67,8 @@ static void MD_cleanup(MediaDetImpl *This) This->splitter = NULL; if (This->graph) IGraphBuilder_Release(This->graph); This->graph = NULL; + if (This->filename) free(This->filename); + This->filename = NULL; This->num_streams = -1; This->cur_stream = 0; } @@ -524,9 +527,6 @@ static HRESULT WINAPI MediaDet_get_StreamLength(IMediaDet* iface, double *pVal) static HRESULT WINAPI MediaDet_get_Filename(IMediaDet* iface, BSTR *pVal) { MediaDetImpl *This = impl_from_IMediaDet(iface); - IFileSourceFilter *file; - LPOLESTR name; - HRESULT hr;
TRACE("(%p)\n", This);
@@ -536,21 +536,10 @@ static HRESULT WINAPI MediaDet_get_Filename(IMediaDet* iface, BSTR *pVal) *pVal = NULL; /* MSDN says it should return E_FAIL if no file is open, but tests show otherwise. */ - if (!This->source) + if (!This->filename) return S_OK;
- hr = IBaseFilter_QueryInterface(This->source, &IID_IFileSourceFilter, - (void **) &file); - if (FAILED(hr)) - return hr; - - hr = IFileSourceFilter_GetCurFile(file, &name, NULL); - IFileSourceFilter_Release(file); - if (FAILED(hr)) - return hr; - - *pVal = SysAllocString(name); - CoTaskMemFree(name); + *pVal = SysAllocString(This->filename); if (!*pVal) return E_OUTOFMEMORY;
@@ -562,6 +551,7 @@ static HRESULT WINAPI MediaDet_put_Filename(IMediaDet* iface, BSTR newVal) MediaDetImpl *This = impl_from_IMediaDet(iface); IGraphBuilder *gb; IBaseFilter *bf; + WCHAR *filename; HRESULT hr;
TRACE("(%p)->(%s)\n", This, debugstr_w(newVal)); @@ -577,14 +567,22 @@ static HRESULT WINAPI MediaDet_put_Filename(IMediaDet* iface, BSTR newVal) if (FAILED(hr)) return hr;
+ if (!(filename = wcsdup(newVal))) + { + IGraphBuilder_Release(gb); + return E_OUTOFMEMORY; + } + if (FAILED(hr = IGraphBuilder_AddSourceFilter(gb, newVal, L"Source", &bf))) { + free(filename); IGraphBuilder_Release(gb); return hr; }
This->graph = gb; This->source = bf; + This->filename = filename; hr = get_splitter(This); if (FAILED(hr)) return hr; diff --git a/dlls/qedit/tests/mediadet.c b/dlls/qedit/tests/mediadet.c index 1fa2bb6..cb2477b 100644 --- a/dlls/qedit/tests/mediadet.c +++ b/dlls/qedit/tests/mediadet.c @@ -1125,7 +1125,6 @@ static void test_mediadet(void)
filename = NULL; hr = IMediaDet_get_Filename(pM, &filename); -todo_wine ok(hr == S_OK, "IMediaDet_get_Filename failed: %08x\n", hr); ok(!filename, "Expected NULL filename, got %s.\n", debugstr_w(filename)); SysFreeString(filename); @@ -1142,7 +1141,6 @@ todo_wine filename = NULL; hr = IMediaDet_get_Filename(pM, &filename); ok(hr == S_OK, "IMediaDet_get_Filename failed: %08x\n", hr); -todo_wine ok(!filename, "Expected NULL filename, got %s.\n", debugstr_w(filename)); SysFreeString(filename);
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/qedit/mediadet.c | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-)
diff --git a/dlls/qedit/mediadet.c b/dlls/qedit/mediadet.c index aa9d5ee..dfafc93 100644 --- a/dlls/qedit/mediadet.c +++ b/dlls/qedit/mediadet.c @@ -73,6 +73,28 @@ static void MD_cleanup(MediaDetImpl *This) This->cur_stream = 0; }
+static HRESULT get_pin_media_type(IPin *pin, AM_MEDIA_TYPE *out) +{ + IEnumMediaTypes *types; + AM_MEDIA_TYPE *pmt; + HRESULT hr; + + hr = IPin_EnumMediaTypes(pin, &types); + if (SUCCEEDED(hr)) + { + hr = IEnumMediaTypes_Next(types, 1, &pmt, NULL) == S_OK ? S_OK : E_NOINTERFACE; + IEnumMediaTypes_Release(types); + } + + if (SUCCEEDED(hr)) + { + *out = *pmt; + CoTaskMemFree(pmt); + } + + return hr; +} + /* From quartz, 2008/04/07 */ static HRESULT get_filter_info(IMoniker *pMoniker, GUID *pclsid, VARIANT *pvar) { @@ -614,9 +636,6 @@ static HRESULT WINAPI MediaDet_get_StreamMediaType(IMediaDet* iface, AM_MEDIA_TYPE *pVal) { MediaDetImpl *This = impl_from_IMediaDet(iface); - IEnumMediaTypes *types; - AM_MEDIA_TYPE *pmt; - HRESULT hr;
TRACE("(%p)\n", This);
@@ -626,22 +645,7 @@ static HRESULT WINAPI MediaDet_get_StreamMediaType(IMediaDet* iface, if (!This->cur_pin) return E_INVALIDARG;
- hr = IPin_EnumMediaTypes(This->cur_pin, &types); - if (SUCCEEDED(hr)) - { - hr = (IEnumMediaTypes_Next(types, 1, &pmt, NULL) == S_OK - ? S_OK - : E_NOINTERFACE); - IEnumMediaTypes_Release(types); - } - - if (SUCCEEDED(hr)) - { - *pVal = *pmt; - CoTaskMemFree(pmt); - } - - return hr; + return get_pin_media_type(This->cur_pin, pVal); }
static HRESULT WINAPI MediaDet_GetSampleGrabber(IMediaDet* iface,
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
The IFileSourceFilter is not queried for filters placed via put_Filter (as shown by tests later), so obtain the media type from the first pin to use for finding a matching splitter.
dlls/qedit/mediadet.c | 45 +++++++++++++++++++++++++++---------- dlls/qedit/tests/mediadet.c | 2 +- 2 files changed, 34 insertions(+), 13 deletions(-)
diff --git a/dlls/qedit/mediadet.c b/dlls/qedit/mediadet.c index dfafc93..7c57722 100644 --- a/dlls/qedit/mediadet.c +++ b/dlls/qedit/mediadet.c @@ -150,22 +150,43 @@ static HRESULT get_splitter(MediaDetImpl *This) if (FAILED(hr)) return hr;
- hr = IBaseFilter_QueryInterface(This->source, &IID_IFileSourceFilter, - (void **) &file); - if (FAILED(hr)) + if (This->filename) { - IFilterMapper2_Release(map); - return hr; - } + hr = IBaseFilter_QueryInterface(This->source, &IID_IFileSourceFilter, + (void **) &file); + if (FAILED(hr)) + { + IFilterMapper2_Release(map); + return hr; + }
- hr = IFileSourceFilter_GetCurFile(file, &name, &mt); - IFileSourceFilter_Release(file); - CoTaskMemFree(name); - if (FAILED(hr)) + hr = IFileSourceFilter_GetCurFile(file, &name, &mt); + IFileSourceFilter_Release(file); + CoTaskMemFree(name); + if (FAILED(hr)) + { + IFilterMapper2_Release(map); + return hr; + } + } + else { - IFilterMapper2_Release(map); - return hr; + mt.majortype = GUID_NULL; + mt.subtype = GUID_NULL; + mt.pbFormat = NULL; + + hr = IBaseFilter_EnumPins(This->source, &pins); + if (SUCCEEDED(hr)) + { + if (IEnumPins_Next(pins, 1, &source_pin, NULL) == S_OK) + { + get_pin_media_type(source_pin, &mt); + IPin_Release(source_pin); + } + IEnumPins_Release(pins); + } } + type[0] = mt.majortype; type[1] = mt.subtype; CoTaskMemFree(mt.pbFormat); diff --git a/dlls/qedit/tests/mediadet.c b/dlls/qedit/tests/mediadet.c index cb2477b..04efc18 100644 --- a/dlls/qedit/tests/mediadet.c +++ b/dlls/qedit/tests/mediadet.c @@ -481,7 +481,7 @@ static HRESULT WINAPI testfilter_QueryInterface(IBaseFilter *iface, REFIID iid, } else { - if (IsEqualGUID(iid, &IID_IFileSourceFilter)) todo_wine ok(0, "Filter queried for IFileSourceFilter\n"); + if (IsEqualGUID(iid, &IID_IFileSourceFilter)) ok(0, "Filter queried for IFileSourceFilter\n");
*out = NULL; return E_NOINTERFACE;
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/qedit/mediadet.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/dlls/qedit/mediadet.c b/dlls/qedit/mediadet.c index 7c57722..8119015 100644 --- a/dlls/qedit/mediadet.c +++ b/dlls/qedit/mediadet.c @@ -219,7 +219,11 @@ static HRESULT get_splitter(MediaDetImpl *This) VariantClear(&var); This->splitter = splitter; if (FAILED(hr)) - goto retry; + { + IBaseFilter_Release(splitter); + This->splitter = NULL; + continue; + }
hr = IBaseFilter_EnumPins(This->source, &pins); if (FAILED(hr)) @@ -248,6 +252,7 @@ static HRESULT get_splitter(MediaDetImpl *This) break;
retry: + IGraphBuilder_RemoveFilter(This->graph, splitter); IBaseFilter_Release(splitter); This->splitter = NULL; }
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/qedit/mediadet.c | 30 +++++- dlls/qedit/tests/mediadet.c | 180 ++++++++++++++++++++++++++++++++++++ 2 files changed, 208 insertions(+), 2 deletions(-)
diff --git a/dlls/qedit/mediadet.c b/dlls/qedit/mediadet.c index 8119015..5ee621b 100644 --- a/dlls/qedit/mediadet.c +++ b/dlls/qedit/mediadet.c @@ -568,8 +568,34 @@ static HRESULT WINAPI MediaDet_get_StreamTypeB(IMediaDet* iface, BSTR *pVal) static HRESULT WINAPI MediaDet_get_StreamLength(IMediaDet* iface, double *pVal) { MediaDetImpl *This = impl_from_IMediaDet(iface); - FIXME("(%p): stub!\n", This); - return VFW_E_INVALIDMEDIATYPE; + IMediaSeeking *seeking; + HRESULT hr; + + TRACE("(%p)\n", This); + + if (!pVal) + return E_POINTER; + + if (!This->cur_pin) + return E_INVALIDARG; + + hr = IPin_QueryInterface(This->cur_pin, &IID_IMediaSeeking, (void **) &seeking); + if (SUCCEEDED(hr)) + { + LONGLONG duration; + + hr = IMediaSeeking_GetDuration(seeking, &duration); + if (SUCCEEDED(hr)) + { + hr = IMediaSeeking_ConvertTimeFormat(seeking, &duration, &TIME_FORMAT_MEDIA_TIME, duration, NULL); + if (SUCCEEDED(hr)) + *pVal = (REFTIME)duration / 10000000; + } + IMediaSeeking_Release(seeking); + return hr; + } + + return hr; }
static HRESULT WINAPI MediaDet_get_Filename(IMediaDet* iface, BSTR *pVal) diff --git a/dlls/qedit/tests/mediadet.c b/dlls/qedit/tests/mediadet.c index 04efc18..95d3208 100644 --- a/dlls/qedit/tests/mediadet.c +++ b/dlls/qedit/tests/mediadet.c @@ -75,6 +75,7 @@ static IUnknown test_outer = {&outer_vtbl}; struct testfilter { IBaseFilter IBaseFilter_iface; + IMediaSeeking IMediaSeeking_iface; LONG ref; WCHAR *name; IFilterGraph *graph; @@ -198,6 +199,8 @@ static HRESULT WINAPI testpin_QueryInterface(IPin *iface, REFIID iid, void **out
if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IPin)) *out = &filter->IPin_iface; + else if (IsEqualGUID(iid, &IID_IMediaSeeking)) + *out = &filter->IMediaSeeking_iface; else { *out = NULL; @@ -461,6 +464,169 @@ static const IEnumPinsVtbl testenumpins_vtbl = testenumpins_Clone };
+static inline struct testfilter *impl_from_IMediaSeeking(IMediaSeeking *iface) +{ + return CONTAINING_RECORD(iface, struct testfilter, IMediaSeeking_iface); +} + +static HRESULT WINAPI testseek_QueryInterface(IMediaSeeking *iface, REFIID iid, void **out) +{ + struct testfilter *filter = impl_from_IMediaSeeking(iface); + return IBaseFilter_QueryInterface(&filter->IBaseFilter_iface, iid, out); +} + +static ULONG WINAPI testseek_AddRef(IMediaSeeking *iface) +{ + struct testfilter *filter = impl_from_IMediaSeeking(iface); + return IBaseFilter_AddRef(&filter->IBaseFilter_iface); +} + +static ULONG WINAPI testseek_Release(IMediaSeeking *iface) +{ + struct testfilter *filter = impl_from_IMediaSeeking(iface); + return IBaseFilter_Release(&filter->IBaseFilter_iface); +} + +static HRESULT WINAPI testseek_GetCapabilities(IMediaSeeking *iface, DWORD *caps) +{ + if (winetest_debug > 1) trace("IMediaSeeking_GetCapabilities()\n"); + + *caps = AM_SEEKING_CanGetDuration; + return S_OK; +} + +static HRESULT WINAPI testseek_CheckCapabilities(IMediaSeeking *iface, DWORD *caps) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI testseek_IsFormatSupported(IMediaSeeking *iface, const GUID *format) +{ + if (winetest_debug > 1) trace("IMediaSeeking_IsFormatSupported(%s)\n", wine_dbgstr_guid(format)); + + return IsEqualGUID(format, &TIME_FORMAT_MEDIA_TIME) ? S_OK : S_FALSE; +} + +static HRESULT WINAPI testseek_QueryPreferredFormat(IMediaSeeking *iface, GUID *format) +{ + if (winetest_debug > 1) trace("IMediaSeeking_QueryPreferredFormat()\n"); + + *format = TIME_FORMAT_MEDIA_TIME; + return S_OK; +} + +static HRESULT WINAPI testseek_GetTimeFormat(IMediaSeeking *iface, GUID *format) +{ + if (winetest_debug > 1) trace("IMediaSeeking_GetTimeFormat()\n"); + + *format = TIME_FORMAT_MEDIA_TIME; + return S_OK; +} + +static HRESULT WINAPI testseek_IsUsingTimeFormat(IMediaSeeking *iface, const GUID *format) +{ + if (winetest_debug > 1) trace("IMediaSeeking_IsUsingTimeFormat(%s)\n", wine_dbgstr_guid(format)); + + return IsEqualGUID(format, &TIME_FORMAT_MEDIA_TIME) ? S_OK : S_FALSE; +} + +static HRESULT WINAPI testseek_SetTimeFormat(IMediaSeeking *iface, const GUID *format) +{ + if (winetest_debug > 1) trace("IMediaSeeking_SetTimeFormat(%s)\n", wine_dbgstr_guid(format)); + + return IsEqualGUID(format, &TIME_FORMAT_MEDIA_TIME) ? S_OK : E_INVALIDARG; +} + +static HRESULT WINAPI testseek_GetDuration(IMediaSeeking *iface, LONGLONG *duration) +{ + if (winetest_debug > 1) trace("IMediaSeeking_GetDuration()\n"); + + *duration = 42000000; + return S_OK; +} + +static HRESULT WINAPI testseek_GetStopPosition(IMediaSeeking *iface, LONGLONG *stop) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI testseek_GetCurrentPosition(IMediaSeeking *iface, LONGLONG *current) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI testseek_ConvertTimeFormat(IMediaSeeking *iface, LONGLONG *target, + const GUID *target_format, LONGLONG source, const GUID *source_format) +{ + if (winetest_debug > 1) + trace("IMediaSeeking_ConvertTimeFormat(%s: %s -> %s)\n", wine_dbgstr_longlong(source), + wine_dbgstr_guid(source_format), wine_dbgstr_guid(target_format)); + + if (source_format && !IsEqualGUID(source_format, &TIME_FORMAT_MEDIA_TIME)) + return E_INVALIDARG; + if (target_format && !IsEqualGUID(target_format, &TIME_FORMAT_MEDIA_TIME)) + return E_INVALIDARG; + + *target = source; + return S_OK; +} + +static HRESULT WINAPI testseek_SetPositions(IMediaSeeking *iface, LONGLONG *current, + DWORD current_flags, LONGLONG *stop, DWORD stop_flags) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI testseek_GetPositions(IMediaSeeking *iface, LONGLONG *current, LONGLONG *stop) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI testseek_GetAvailable(IMediaSeeking *iface, LONGLONG *earliest, LONGLONG *latest) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI testseek_SetRate(IMediaSeeking *iface, double rate) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI testseek_GetRate(IMediaSeeking *iface, double *rate) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI testseek_GetPreroll(IMediaSeeking *iface, LONGLONG *preroll) +{ + return E_NOTIMPL; +} + +static const IMediaSeekingVtbl testseek_vtbl = +{ + testseek_QueryInterface, + testseek_AddRef, + testseek_Release, + testseek_GetCapabilities, + testseek_CheckCapabilities, + testseek_IsFormatSupported, + testseek_QueryPreferredFormat, + testseek_GetTimeFormat, + testseek_IsUsingTimeFormat, + testseek_SetTimeFormat, + testseek_GetDuration, + testseek_GetStopPosition, + testseek_GetCurrentPosition, + testseek_ConvertTimeFormat, + testseek_SetPositions, + testseek_GetPositions, + testseek_GetAvailable, + testseek_SetRate, + testseek_GetRate, + testseek_GetPreroll +}; + static inline struct testfilter *impl_from_IBaseFilter(IBaseFilter *iface) { return CONTAINING_RECORD(iface, struct testfilter, IBaseFilter_iface); @@ -479,6 +645,8 @@ static HRESULT WINAPI testfilter_QueryInterface(IBaseFilter *iface, REFIID iid, { *out = &filter->IBaseFilter_iface; } + else if (IsEqualGUID(iid, &IID_IMediaSeeking)) + *out = &filter->IMediaSeeking_iface; else { if (IsEqualGUID(iid, &IID_IFileSourceFilter)) ok(0, "Filter queried for IFileSourceFilter\n"); @@ -645,6 +813,7 @@ static IBaseFilter *create_testfilter(void)
memset(filter, 0, sizeof(*filter)); filter->IBaseFilter_iface.lpVtbl = &testfilter_vtbl; + filter->IMediaSeeking_iface.lpVtbl = &testseek_vtbl; filter->IEnumPins_iface.lpVtbl = &testenumpins_vtbl; filter->IPin_iface.lpVtbl = &testpin_vtbl; filter->IEnumMediaTypes_iface.lpVtbl = &testenummt_vtbl; @@ -784,6 +953,7 @@ static void test_mediadet(void) BSTR bstr; IPin *pin; AM_MEDIA_TYPE mt, *pmt; + double duration; IUnknown *unk; double fps; int flags; @@ -846,6 +1016,12 @@ static void test_mediadet(void) hr = IMediaDet_get_StreamTypeB(pM, NULL); ok(hr == E_INVALIDARG, "IMediaDet_get_StreamTypeB failed: %08x\n", hr);
+ hr = IMediaDet_get_StreamLength(pM, &duration); + ok(hr == E_INVALIDARG, "IMediaDet_get_StreamLength failed: %08x\n", hr); + + hr = IMediaDet_get_StreamLength(pM, NULL); + ok(hr == E_POINTER, "IMediaDet_get_StreamLength failed: %08x\n", hr); + hr = IMediaDet_get_Filter(pM, NULL); ok(hr == E_POINTER, "IMediaDet_get_Filter failed: %08x\n", hr);
@@ -1133,6 +1309,10 @@ static void test_mediadet(void) ok(hr == S_OK, "IMediaDet_get_OutputStreams failed: %08x\n", hr); ok(nstrms == 1, "IMediaDet_get_OutputStreams: nstrms is %i\n", nstrms);
+ hr = IMediaDet_get_StreamLength(pM, &duration); + ok(hr == S_OK, "IMediaDet_get_StreamLength failed: %08x\n", hr); + ok(duration == 4.2, "Wrong duration %.16e\n", duration); + /* Now use the filter obtained from put_Filename for put_Filter. */ hr = IMediaDet_put_Filter(pM, (IUnknown*)filter); ok(hr == S_OK, "IMediaDet_put_Filter failed: %08x\n", hr);