diff --git a/dlls/qedit/mediadet.c b/dlls/qedit/mediadet.c index 062c105490d..3a7cc1b4b9d 100644 --- a/dlls/qedit/mediadet.c +++ b/dlls/qedit/mediadet.c @@ -36,12 +36,15 @@ typedef struct MediaDetImpl { LONG refCount; IGraphBuilder *graph; IBaseFilter *source; + IBaseFilter *splitter; } MediaDetImpl; static void MD_cleanup(MediaDetImpl *This) { if (This->source) IBaseFilter_Release(This->source); This->source = NULL; + if (This->splitter) IBaseFilter_Release(This->splitter); + This->splitter = NULL; if (This->graph) IGraphBuilder_Release(This->graph); This->graph = NULL; } @@ -104,8 +107,38 @@ static HRESULT WINAPI MediaDet_put_Filter(IMediaDet* iface, IUnknown *newVal) static HRESULT WINAPI MediaDet_get_OutputStreams(IMediaDet* iface, long *pVal) { MediaDetImpl *This = (MediaDetImpl *)iface; - FIXME("(%p)->(%p): not implemented!\n", This, pVal); - return E_NOTIMPL; + IEnumPins *pins; + IPin *pin; + HRESULT hr; + + TRACE("(%p)\n", This); + + if (!This->splitter) + return E_INVALIDARG; + + *pVal = 0; + + hr = IBaseFilter_EnumPins(This->splitter, &pins); + if (FAILED(hr)) + return hr; + + while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK) + { + PIN_DIRECTION dir; + hr = IPin_QueryDirection(pin, &dir); + IPin_Release(pin); + if (FAILED(hr)) + { + IEnumPins_Release(pins); + return hr; + } + + if (dir == PINDIR_OUTPUT) + ++*pVal; + } + IEnumPins_Release(pins); + + return S_OK; } static HRESULT WINAPI MediaDet_get_CurrentStream(IMediaDet* iface, long *pVal) @@ -179,6 +212,136 @@ 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) +{ + static const WCHAR wszClsidName[] = {'C','L','S','I','D',0}; + static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0}; + 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, wszClsidName, pvar, NULL); + + if (SUCCEEDED(hr)) + hr = CLSIDFromString(V_UNION(pvar, bstrVal), pclsid); + + if (SUCCEEDED(hr)) + hr = IPropertyBag_Read(pPropBagCat, wszFriendlyName, pvar, NULL); + + if (SUCCEEDED(hr)) + TRACE("Moniker = %s - %s\n", debugstr_guid(pclsid), + debugstr_w(V_UNION(pvar, bstrVal))); + + if (pPropBagCat) + IPropertyBag_Release(pPropBagCat); + + return hr; +} + +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 = IEnumMoniker_Next(filters, 1, &mon, NULL); + IEnumMoniker_Release(filters); + if (hr != S_OK) /* No matches, what do we do? */ + return E_NOINTERFACE; + + hr = GetFilterInfo(mon, &clsid, &var); + IMoniker_Release(mon); + if (FAILED(hr)) + return hr; + + hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, + &IID_IBaseFilter, (void **) &splitter); + if (FAILED(hr)) + return hr; + + hr = IGraphBuilder_AddFilter(This->graph, splitter, + V_UNION(&var, bstrVal)); + if (FAILED(hr)) + { + IBaseFilter_Release(splitter); + return hr; + } + This->splitter = splitter; + + hr = IBaseFilter_EnumPins(This->source, &pins); + if (FAILED(hr)) + return hr; + IEnumPins_Next(pins, 1, &source_pin, NULL); + IEnumPins_Release(pins); + + hr = IBaseFilter_EnumPins(splitter, &pins); + if (FAILED(hr)) + { + IPin_Release(source_pin); + return hr; + } + IEnumPins_Next(pins, 1, &splitter_pin, NULL); + IEnumPins_Release(pins); + + hr = IPin_Connect(source_pin, splitter_pin, NULL); + IPin_Release(source_pin); + IPin_Release(splitter_pin); + if (FAILED(hr)) + return hr; + + return S_OK; +} + static HRESULT WINAPI MediaDet_put_Filename(IMediaDet* iface, BSTR newVal) { static const WCHAR reader[] = {'R','e','a','d','e','r',0}; @@ -209,7 +372,7 @@ static HRESULT WINAPI MediaDet_put_Filename(IMediaDet* iface, BSTR newVal) This->graph = gb; This->source = bf; - return S_OK; + return GetSplitter(This); } static HRESULT WINAPI MediaDet_GetBitmapBits(IMediaDet* iface, @@ -305,6 +468,7 @@ HRESULT MediaDet_create(IUnknown * pUnkOuter, LPVOID * ppv) { obj->MediaDet_Vtbl = &IMediaDet_VTable; obj->graph = NULL; obj->source = NULL; + obj->splitter = NULL; *ppv = obj; return S_OK; diff --git a/dlls/qedit/tests/mediadet.c b/dlls/qedit/tests/mediadet.c index 3e6e48f464e..237dfb9c65d 100644 --- a/dlls/qedit/tests/mediadet.c +++ b/dlls/qedit/tests/mediadet.c @@ -26,10 +26,12 @@ #include "uuids.h" #include "wine/test.h" #include "qedit.h" +#include "rc.h" static WCHAR test_avi_filename[MAX_PATH]; +static WCHAR test_sound_avi_filename[MAX_PATH]; -static BOOL init_tests(void) +static BOOL unpack_avi_file(int id, WCHAR name[MAX_PATH]) { static WCHAR temp_path[MAX_PATH]; static WCHAR prefix[] = {'D','E','S',0}; @@ -40,7 +42,7 @@ static BOOL init_tests(void) DWORD size, written; HANDLE fh; - res = FindResourceW(NULL, (LPWSTR) 1, (LPWSTR) 256); + res = FindResourceW(NULL, (LPWSTR) id, (LPWSTR) AVI_RES_TYPE); if (!res) return FALSE; @@ -60,14 +62,14 @@ static BOOL init_tests(void) return FALSE; /* We might end up relying on the extension here, so .TMP is no good. */ - if (!GetTempFileNameW(temp_path, prefix, 0, test_avi_filename)) + if (!GetTempFileNameW(temp_path, prefix, 0, name)) return FALSE; - DeleteFileW(test_avi_filename); - lstrcpyW(test_avi_filename + lstrlenW(test_avi_filename) - 3, avi); + DeleteFileW(name); + lstrcpyW(name + lstrlenW(name) - 3, avi); - fh = CreateFileW(test_avi_filename, GENERIC_WRITE, 0, NULL, - CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + fh = CreateFileW(name, GENERIC_WRITE, 0, NULL, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, NULL); if (fh == INVALID_HANDLE_VALUE) return FALSE; @@ -79,6 +81,12 @@ static BOOL init_tests(void) return TRUE; } +static BOOL init_tests(void) +{ + return unpack_avi_file(TEST_AVI_RES, test_avi_filename) + && unpack_avi_file(TEST_SOUND_AVI_RES, test_sound_avi_filename); +} + static void test_mediadet(void) { HRESULT hr; @@ -87,7 +95,9 @@ static void test_mediadet(void) long nstrms = 0; long strm; AM_MEDIA_TYPE mt; + int flags; + /* test.avi has one video stream. */ hr = CoCreateInstance(&CLSID_MediaDet, NULL, CLSCTX_INPROC_SERVER, &IID_IMediaDet, (LPVOID*)&pM); ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr); @@ -105,14 +115,19 @@ static void test_mediadet(void) ok(hr == S_OK, "IMediaDet_get_Filename\n"); ok(filename == NULL, "IMediaDet_get_Filename\n"); + nstrms = -1; + hr = IMediaDet_get_OutputStreams(pM, &nstrms); + ok(hr == E_INVALIDARG, "IMediaDet_get_OutputStreams\n"); + ok(nstrms == -1, "IMediaDet_get_OutputStreams\n"); + filename = SysAllocString(test_avi_filename); hr = IMediaDet_put_Filename(pM, filename); ok(hr == S_OK, "IMediaDet_put_Filename -> %x\n", hr); SysFreeString(filename); hr = IMediaDet_get_OutputStreams(pM, &nstrms); - todo_wine ok(hr == S_OK, "IMediaDet_get_OutputStreams\n"); - todo_wine ok(nstrms == 1, "IMediaDet_get_OutputStreams\n"); + ok(hr == S_OK, "IMediaDet_get_OutputStreams\n"); + ok(nstrms == 1, "IMediaDet_get_OutputStreams\n"); filename = NULL; hr = IMediaDet_get_Filename(pM, &filename); @@ -142,6 +157,63 @@ static void test_mediadet(void) ok(hr == 0, "IMediaDet_Release returned: %x\n", hr); DeleteFileW(test_avi_filename); + + /* test_sound.avi has one video stream and one audio stream. */ + hr = CoCreateInstance(&CLSID_MediaDet, NULL, CLSCTX_INPROC_SERVER, + &IID_IMediaDet, (LPVOID*)&pM); + ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr); + ok(pM != NULL, "pM is NULL\n"); + + filename = SysAllocString(test_sound_avi_filename); + hr = IMediaDet_put_Filename(pM, filename); + ok(hr == S_OK, "IMediaDet_put_Filename -> %x\n", hr); + SysFreeString(filename); + + hr = IMediaDet_get_OutputStreams(pM, &nstrms); + ok(hr == S_OK, "IMediaDet_get_OutputStreams\n"); + ok(nstrms == 2, "IMediaDet_get_OutputStreams\n"); + + filename = NULL; + hr = IMediaDet_get_Filename(pM, &filename); + ok(hr == S_OK, "IMediaDet_get_Filename\n"); + ok(lstrcmpW(filename, test_sound_avi_filename) == 0, + "IMediaDet_get_Filename\n"); + SysFreeString(filename); + + /* I don't know if the stream order is deterministic. Just check + for both an audio and video stream. */ + flags = 0; + + hr = IMediaDet_put_CurrentStream(pM, 0); + todo_wine ok(hr == S_OK, "IMediaDet_put_CurrentStream\n"); + + ZeroMemory(&mt, sizeof mt); + hr = IMediaDet_get_StreamMediaType(pM, &mt); + todo_wine ok(hr == S_OK, "IMediaDet_get_StreamMediaType\n"); + flags += (IsEqualGUID(&mt.majortype, &MEDIATYPE_Video) + ? 1 + : (IsEqualGUID(&mt.majortype, &MEDIATYPE_Audio) + ? 2 + : 0)); + + hr = IMediaDet_put_CurrentStream(pM, 1); + todo_wine ok(hr == S_OK, "IMediaDet_put_CurrentStream\n"); + + ZeroMemory(&mt, sizeof mt); + hr = IMediaDet_get_StreamMediaType(pM, &mt); + todo_wine ok(hr == S_OK, "IMediaDet_get_StreamMediaType\n"); + flags += (IsEqualGUID(&mt.majortype, &MEDIATYPE_Video) + ? 1 + : (IsEqualGUID(&mt.majortype, &MEDIATYPE_Audio) + ? 2 + : 0)); + + todo_wine ok(flags == 3, "IMediaDet_get_StreamMediaType\n"); + + hr = IMediaDet_Release(pM); + ok(hr == 0, "IMediaDet_Release returned: %x\n", hr); + + DeleteFileW(test_sound_avi_filename); } START_TEST(mediadet) diff --git a/dlls/qedit/tests/qedit.rc b/dlls/qedit/tests/qedit.rc index b138624eaa6..a0b8b80746e 100644 --- a/dlls/qedit/tests/qedit.rc +++ b/dlls/qedit/tests/qedit.rc @@ -18,5 +18,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "rc.h" + /* @makedep: test.avi */ -1 256 test.avi +TEST_AVI_RES AVI_RES_TYPE test.avi +/* @makedep: sound_test.avi */ +TEST_SOUND_AVI_RES AVI_RES_TYPE test_sound.avi diff --git a/dlls/qedit/tests/rc.h b/dlls/qedit/tests/rc.h new file mode 100644 index 00000000000..1de98d96b07 --- /dev/null +++ b/dlls/qedit/tests/rc.h @@ -0,0 +1,29 @@ +/* + * Resource identifiers for qedit tests. + * + * Copyright 2008 Google (Dan Hipschman) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef QEDIT_TESTS_RC_INCLUDED +#define QEDIT_TESTS_RC_INCLUDED + +#define TEST_AVI_RES 1 +#define TEST_SOUND_AVI_RES 2 + +#define AVI_RES_TYPE 256 + +#endif /* QEDIT_TESTS_RC_INCLUDED */ diff --git a/dlls/qedit/tests/test_sound.avi b/dlls/qedit/tests/test_sound.avi new file mode 100644 index 00000000000..9edbb8de7f8 Binary files /dev/null and b/dlls/qedit/tests/test_sound.avi differ