/* This test doesn't use the quartz filtergraph because it makes it impossible * to be certain that a thread is really one owned by the avi splitter. * A lot of the decoder filters will also have their own thread, and Windows' * filtergraph has a separate thread for start/stop/seeking requests. * By avoiding the filtergraph altogether and connecting streams directly to * the null renderer I am sure that this is not the case here. */ static void test_threads(void) { IFileSourceFilter *pfile = NULL; IBaseFilter *preader = NULL, *pavi = NULL; IEnumPins *enumpins = NULL; IPin *filepin = NULL, *avipin = NULL; HRESULT hr; int baselevel, curlevel, expected; HANDLE file = NULL; PIN_DIRECTION dir = PINDIR_OUTPUT; char buffer[13]; DWORD readbytes; FILTER_STATE state; /* We need another way of counting threads on NT4. Skip these tests (for now) */ if (!pCreateToolhelp32Snapshot || !pThread32First || !pThread32Next) { win_skip("Needed thread functions are not available (NT4)\n"); return; } /* Before doing anything (the thread count at the start differs per OS) */ baselevel = count_threads(); file = CreateFileW(wfile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (file == INVALID_HANDLE_VALUE) { skip("Could not read test file \"%s\", skipping test\n", afile); return; } memset(buffer, 0, 13); readbytes = 12; ReadFile(file, buffer, readbytes, &readbytes, NULL); CloseHandle(file); if (strncmp(buffer, "RIFF", 4) || strcmp(buffer + 8, "AVI ")) { skip("%s is not an avi riff file, not doing the avi splitter test\n", afile); return; } hr = IUnknown_QueryInterface(pAviSplitter, &IID_IFileSourceFilter, (void **)&pfile); ok(hr == E_NOINTERFACE, "Avi splitter returns unexpected error: %08x\n", hr); if (pfile) IFileSourceFilter_Release(pfile); pfile = NULL; hr = CoCreateInstance(&CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&preader); ok(hr == S_OK, "Could not create asynchronous reader: %08x\n", hr); if (hr != S_OK) goto fail; hr = IBaseFilter_QueryInterface(preader, &IID_IFileSourceFilter, (void**)&pfile); ok(hr == S_OK, "Could not get IFileSourceFilter: %08x\n", hr); if (hr != S_OK) goto fail; hr = IUnknown_QueryInterface(pAviSplitter, &IID_IBaseFilter, (void**)&pavi); ok(hr == S_OK, "Could not get base filter: %08x\n", hr); if (hr != S_OK) goto fail; hr = IFileSourceFilter_Load(pfile, wfile, NULL); if (hr != S_OK) { trace("Could not load file\n"); goto fail; } hr = IBaseFilter_EnumPins(preader, &enumpins); ok(hr == S_OK, "No enumpins: %08x\n", hr); if (hr != S_OK) goto fail; hr = IEnumPins_Next(enumpins, 1, &filepin, NULL); ok(hr == S_OK, "No pin: %08x\n", hr); if (hr != S_OK) goto fail; IEnumPins_Release(enumpins); enumpins = NULL; hr = IBaseFilter_EnumPins(pavi, &enumpins); ok(hr == S_OK, "No enumpins: %08x\n", hr); if (hr != S_OK) goto fail; hr = IEnumPins_Next(enumpins, 1, &avipin, NULL); ok(hr == S_OK, "No pin: %08x\n", hr); if (hr != S_OK) goto fail; curlevel = count_threads(); ok(curlevel == baselevel, "The thread count should be %d not %d\n", baselevel, curlevel); hr = IPin_Connect(filepin, avipin, NULL); ok(hr == S_OK, "Could not connect: %08x\n", hr); if (hr != S_OK) goto fail; expected = 1 + baselevel; curlevel = count_threads(); ok(curlevel == expected, "The thread count should be %d not %d\n", expected, curlevel); IPin_Release(avipin); avipin = NULL; IEnumPins_Reset(enumpins); /* Windows puts the pins in the order: Outputpins - Inputpin, * wine does the reverse, just don't test it for now * Hate to admit it, but windows way makes more sense */ while (IEnumPins_Next(enumpins, 1, &avipin, NULL) == S_OK) { IPin_QueryDirection(avipin, &dir); if (dir == PINDIR_OUTPUT) { /* Well, connect it to a null renderer! */ IBaseFilter *pnull = NULL; IEnumPins *nullenum = NULL; IPin *nullpin = NULL; hr = CoCreateInstance(&CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pnull); ok(hr == S_OK, "Could not create null renderer: %08x\n", hr); if (hr != S_OK) break; IBaseFilter_EnumPins(pnull, &nullenum); IEnumPins_Next(nullenum, 1, &nullpin, NULL); IEnumPins_Release(nullenum); IPin_QueryDirection(nullpin, &dir); hr = IPin_Connect(avipin, nullpin, NULL); ok(hr == S_OK, "Failed to connect output pin: %08x\n", hr); IPin_Release(nullpin); if (hr != S_OK) { IBaseFilter_Release(pnull); break; } IBaseFilter_Run(pnull, 0); ++expected; } IPin_Release(avipin); avipin = NULL; } if (avipin) IPin_Release(avipin); avipin = NULL; if (hr != S_OK) goto fail2; /* At this point there is a minimalistic connected avi splitter that can * be used for all sorts of source filter tests. However that still needs * to be written at a later time. * * Interesting tests: * - Can you disconnect an output pin while running? * Expecting: Yes * - Can you disconnect the pullpin while running? * Expecting: No * - Is the reference count incremented during playback or when connected? * Does this happen once for every output pin? Or is there something else * going on. * Expecting: You tell me */ IBaseFilter_Run(preader, 0); IBaseFilter_Run(pavi, 0); IBaseFilter_GetState(pavi, INFINITE, &state); curlevel = count_threads(); ok(curlevel == expected, "The thread count should be %d not %d\n", expected, curlevel); IBaseFilter_Pause(pavi); IBaseFilter_Pause(preader); IBaseFilter_Stop(pavi); IBaseFilter_Stop(preader); IBaseFilter_GetState(pavi, INFINITE, &state); IBaseFilter_GetState(preader, INFINITE, &state); fail2: IEnumPins_Reset(enumpins); while (IEnumPins_Next(enumpins, 1, &avipin, NULL) == S_OK) { IPin *to = NULL; IPin_QueryDirection(avipin, &dir); IPin_ConnectedTo(avipin, &to); if (to) { IPin_Release(to); if (dir == PINDIR_OUTPUT) { PIN_INFO info; IPin_QueryPinInfo(to, &info); /* Release twice: Once normal, second from the * previous while loop */ IBaseFilter_Stop(info.pFilter); IPin_Disconnect(to); IPin_Disconnect(avipin); IBaseFilter_Release(info.pFilter); IBaseFilter_Release(info.pFilter); } else { IPin_Disconnect(to); IPin_Disconnect(avipin); } } IPin_Release(avipin); avipin = NULL; } fail: if (hr != S_OK) skip("Prerequisites not matched, skipping remainder of test\n"); if (enumpins) IEnumPins_Release(enumpins); if (avipin) IPin_Release(avipin); if (filepin) { IPin *to = NULL; IPin_ConnectedTo(filepin, &to); if (to) { IPin_Disconnect(filepin); IPin_Disconnect(to); } IPin_Release(filepin); } if (preader) IBaseFilter_Release(preader); if (pavi) IBaseFilter_Release(pavi); if (pfile) IFileSourceFilter_Release(pfile); curlevel = count_threads(); todo_wine ok(curlevel == baselevel, "The thread count should be %d not %d\n", baselevel, curlevel); }
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 = GetFilterInfo(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_UNION(&var, bstrVal)); 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; } 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 (SUCCEEDED(hr)) break; retry: IBaseFilter_Release(splitter); This->splitter = NULL; } IEnumMoniker_Release(filters); if (FAILED(hr)) return hr; return S_OK; }
static void test_AviMux(void) { test_filter source_filter, sink_filter; VIDEOINFOHEADER videoinfoheader; IPin *avimux_in, *avimux_out, *pin; AM_MEDIA_TYPE source_media_type; AM_MEDIA_TYPE *media_type; PIN_DIRECTION dir; IBaseFilter *avimux; IEnumPins *ep; IEnumMediaTypes *emt; HRESULT hr; init_test_filter(&source_filter, PINDIR_OUTPUT, SOURCE_FILTER); init_test_filter(&sink_filter, PINDIR_INPUT, SINK_FILTER); hr = CoCreateInstance(&CLSID_AviDest, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (void**)&avimux); ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG), "couldn't create AVI Mux filter, hr = %08x\n", hr); if(hr != S_OK) { win_skip("AVI Mux filter is not registered\n"); return; } hr = IBaseFilter_EnumPins(avimux, &ep); ok(hr == S_OK, "EnumPins returned %x\n", hr); hr = IEnumPins_Next(ep, 1, &avimux_out, NULL); ok(hr == S_OK, "Next returned %x\n", hr); hr = IPin_QueryDirection(avimux_out, &dir); ok(hr == S_OK, "QueryDirection returned %x\n", hr); ok(dir == PINDIR_OUTPUT, "dir = %d\n", dir); hr = IEnumPins_Next(ep, 1, &avimux_in, NULL); ok(hr == S_OK, "Next returned %x\n", hr); hr = IPin_QueryDirection(avimux_in, &dir); ok(hr == S_OK, "QueryDirection returned %x\n", hr); ok(dir == PINDIR_INPUT, "dir = %d\n", dir); IEnumPins_Release(ep); hr = IPin_EnumMediaTypes(avimux_out, &emt); ok(hr == S_OK, "EnumMediaTypes returned %x\n", hr); hr = IEnumMediaTypes_Next(emt, 1, &media_type, NULL); ok(hr == S_OK, "Next returned %x\n", hr); ok(IsEqualIID(&media_type->majortype, &MEDIATYPE_Stream), "majortype = %s\n", debugstr_guid(&media_type->majortype)); ok(IsEqualIID(&media_type->subtype, &MEDIASUBTYPE_Avi), "subtype = %s\n", debugstr_guid(&media_type->subtype)); ok(media_type->bFixedSizeSamples, "bFixedSizeSamples = %x\n", media_type->bFixedSizeSamples); ok(!media_type->bTemporalCompression, "bTemporalCompression = %x\n", media_type->bTemporalCompression); ok(media_type->lSampleSize == 1, "lSampleSize = %d\n", media_type->lSampleSize); ok(IsEqualIID(&media_type->formattype, &GUID_NULL), "formattype = %s\n", debugstr_guid(&media_type->formattype)); ok(!media_type->pUnk, "pUnk = %p\n", media_type->pUnk); ok(!media_type->cbFormat, "cbFormat = %d\n", media_type->cbFormat); ok(!media_type->pbFormat, "pbFormat = %p\n", media_type->pbFormat); CoTaskMemFree(media_type); hr = IEnumMediaTypes_Next(emt, 1, &media_type, NULL); ok(hr == S_FALSE, "Next returned %x\n", hr); IEnumMediaTypes_Release(emt); hr = IPin_EnumMediaTypes(avimux_in, &emt); ok(hr == S_OK, "EnumMediaTypes returned %x\n", hr); hr = IEnumMediaTypes_Reset(emt); ok(hr == S_OK, "Reset returned %x\n", hr); hr = IEnumMediaTypes_Next(emt, 1, &media_type, NULL); ok(hr == S_FALSE, "Next returned %x\n", hr); IEnumMediaTypes_Release(emt); hr = IPin_ReceiveConnection(avimux_in, &source_filter.IPin_iface, NULL); ok(hr == E_POINTER, "ReceiveConnection returned %x\n", hr); current_calls_list = NULL; memset(&source_media_type, 0, sizeof(AM_MEDIA_TYPE)); memset(&videoinfoheader, 0, sizeof(VIDEOINFOHEADER)); source_media_type.majortype = MEDIATYPE_Video; source_media_type.subtype = MEDIASUBTYPE_RGB32; source_media_type.formattype = FORMAT_VideoInfo; source_media_type.bFixedSizeSamples = TRUE; source_media_type.lSampleSize = 40000; source_media_type.cbFormat = sizeof(VIDEOINFOHEADER); source_media_type.pbFormat = (BYTE*)&videoinfoheader; videoinfoheader.AvgTimePerFrame = 333333; videoinfoheader.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); videoinfoheader.bmiHeader.biWidth = 100; videoinfoheader.bmiHeader.biHeight = 100; videoinfoheader.bmiHeader.biPlanes = 1; videoinfoheader.bmiHeader.biBitCount = 32; videoinfoheader.bmiHeader.biSizeImage = 40000; videoinfoheader.bmiHeader.biClrImportant = 256; hr = IPin_ReceiveConnection(avimux_in, &source_filter.IPin_iface, &source_media_type); ok(hr == S_OK, "ReceiveConnection returned %x\n", hr); hr = IPin_ConnectedTo(avimux_in, &pin); ok(hr == S_OK, "ConnectedTo returned %x\n", hr); ok(pin == &source_filter.IPin_iface, "incorrect pin: %p, expected %p\n", pin, &source_filter.IPin_iface); hr = IPin_Connect(avimux_out, &source_filter.IPin_iface, NULL); todo_wine ok(hr == VFW_E_INVALID_DIRECTION, "Connect returned %x\n", hr); hr = IBaseFilter_JoinFilterGraph(avimux, (IFilterGraph*)&GraphBuilder, NULL); ok(hr == S_OK, "JoinFilterGraph returned %x\n", hr); SET_EXPECT(ReceiveConnection); SET_EXPECT(GetAllocatorRequirements); SET_EXPECT(NotifyAllocator); SET_EXPECT(Reconnect); hr = IPin_Connect(avimux_out, &sink_filter.IPin_iface, NULL); ok(hr == S_OK, "Connect returned %x\n", hr); CHECK_CALLED(ReceiveConnection); CHECK_CALLED(GetAllocatorRequirements); CHECK_CALLED(NotifyAllocator); CHECK_CALLED(Reconnect); hr = IPin_Disconnect(avimux_out); ok(hr == S_OK, "Disconnect returned %x\n", hr); IPin_Release(avimux_in); IPin_Release(avimux_out); IBaseFilter_Release(avimux); }