push decde5eed3d79f9d889b4d757f73e86ce6ff9241
[wine/hacks.git] / dlls / quartz / tests / avisplitter.c
bloba7461f420c70be2c42490cb07db9ee517d0bb0b1
1 /*
2 * Unit tests for the avi splitter functions
4 * Copyright (C) 2007 Google (Lei Zhang)
5 * Copyright (C) 2008 Google (Maarten Lankhorst)
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
24 #include "wine/test.h"
25 #include "dshow.h"
26 #include "tlhelp32.h"
28 static IUnknown *pAviSplitter = NULL;
30 static int count_threads(void)
32 THREADENTRY32 te;
33 int threads;
34 HANDLE h;
36 h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
37 te.dwSize = sizeof(te);
39 if (h == INVALID_HANDLE_VALUE)
40 return -1;
42 Thread32First(h, &te);
43 if (te.th32OwnerProcessID == GetCurrentProcessId())
44 threads = 1;
45 else
46 threads = 0;
48 while (Thread32Next(h, &te))
49 if (te.th32OwnerProcessID == GetCurrentProcessId())
50 ++threads;
52 CloseHandle(h);
53 return threads;
56 static int create_avisplitter(void)
58 HRESULT hr;
60 hr = CoCreateInstance(&CLSID_AviSplitter, NULL, CLSCTX_INPROC_SERVER,
61 &IID_IUnknown, (LPVOID*)&pAviSplitter);
62 return (hr == S_OK && pAviSplitter != NULL);
65 static void release_avisplitter(void)
67 HRESULT hr;
69 Sleep(1000);
70 hr = IUnknown_Release(pAviSplitter);
72 /* Looks like wine has a reference leak somewhere on test_threads tests,
73 * it passes in windows
75 ok(hr == 0, "IUnknown_Release failed with %d\n", (INT)hr);
77 while (hr > 0)
78 hr = IUnknown_Release(pAviSplitter);
79 pAviSplitter = NULL;
82 static void test_query_interface(void)
84 HRESULT hr;
85 ULONG ref;
86 IUnknown *iface= NULL;
88 hr = IUnknown_QueryInterface(pAviSplitter, &IID_IBaseFilter,
89 (void**)&iface);
91 ok(hr == S_OK,
92 "IID_IBaseFilter should exist, got %08x!\n", GetLastError());
93 if (hr == S_OK)
95 ref = IUnknown_Release(iface);
96 iface = NULL;
97 ok(ref == 1, "Reference is %u, expected 1\n", ref);
100 hr = IUnknown_QueryInterface(pAviSplitter, &IID_IMediaSeeking,
101 (void**)&iface);
102 if (hr == S_OK)
103 ref = IUnknown_Release(iface);
104 iface = NULL;
105 todo_wine ok(hr == E_NOINTERFACE,
106 "Query for IMediaSeeking returned: %08x\n", hr);
108 /* These interfaces should not be present:
109 IID_IKsPropertySet, IID_IMediaPosition, IID_IQualityControl, IID_IQualProp
113 static void test_pin(IPin *pin)
115 IMemInputPin *mpin = NULL;
117 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&mpin);
119 ok(mpin == NULL, "IMemInputPin found!\n");
120 if (mpin)
121 IMemInputPin_Release(mpin);
122 /* TODO */
125 static void test_basefilter(void)
127 IEnumPins *pin_enum = NULL;
128 IBaseFilter *base = NULL;
129 IPin *pins[2];
130 ULONG ref;
131 HRESULT hr;
133 IUnknown_QueryInterface(pAviSplitter, &IID_IBaseFilter, (void *)&base);
134 if (base == NULL)
136 /* test_query_interface handles this case */
137 skip("No IBaseFilter\n");
138 return;
141 hr = IBaseFilter_EnumPins(base, NULL);
142 ok(hr == E_POINTER, "hr = %08x and not E_POINTER\n", hr);
144 hr= IBaseFilter_EnumPins(base, &pin_enum);
145 ok(hr == S_OK, "hr = %08x and not S_OK\n", hr);
147 hr = IEnumPins_Next(pin_enum, 1, NULL, NULL);
148 ok(hr == E_POINTER, "hr = %08x and not E_POINTER\n", hr);
150 hr = IEnumPins_Next(pin_enum, 2, pins, NULL);
151 ok(hr == E_INVALIDARG, "hr = %08x and not E_INVALIDARG\n", hr);
153 pins[0] = (void *)0xdead;
154 pins[1] = (void *)0xdeed;
156 hr = IEnumPins_Next(pin_enum, 2, pins, &ref);
157 ok(hr == S_FALSE, "hr = %08x instead of S_FALSE\n", hr);
158 ok(pins[0] != (void *)0xdead && pins[0] != NULL,
159 "pins[0] = %p\n", pins[0]);
160 if (pins[0] != (void *)0xdead && pins[0] != NULL)
162 test_pin(pins[0]);
163 IPin_Release(pins[0]);
166 ok(pins[1] == (void *)0xdeed, "pins[1] = %p\n", pins[1]);
168 ref = IEnumPins_Release(pin_enum);
169 ok(ref == 0, "ref is %u and not 0!\n", ref);
171 IBaseFilter_Release(base);
174 static const WCHAR wfile[] = {'t','e','s','t','.','a','v','i',0};
175 static const char afile[] = "test.avi";
177 /* This test doesn't use the quartz filtergraph because it makes it impossible
178 * to be certain that a thread is really one owned by the avi splitter
179 * A lot of the decoder filters will also have their own thread, and windows'
180 * filtergraph has a separate thread for start/stop/seeking requests.
181 * By avoiding the filtergraph all together and connecting streams directly to
182 * the null renderer I am sure that this is not the case here.
184 static void test_threads()
186 IFileSourceFilter *pfile = NULL;
187 IBaseFilter *preader = NULL, *pavi = NULL;
188 IEnumPins *enumpins = NULL;
189 IPin *filepin = NULL, *avipin = NULL;
190 HRESULT hr;
191 int baselevel, curlevel, expected;
192 HANDLE file = NULL;
193 PIN_DIRECTION dir = PINDIR_OUTPUT;
194 char buffer[13];
195 DWORD readbytes;
196 FILTER_STATE state;
198 /* Before doing anything */
199 baselevel = count_threads();
200 expected = 1;
201 ok(baselevel == expected,
202 "Basic amount of threads should be %d, not %d!\n", expected, baselevel);
204 file = CreateFileW(wfile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
205 NULL, OPEN_EXISTING, 0, NULL);
206 if (file == INVALID_HANDLE_VALUE)
208 skip("Could not read test file \"%s\", skipping test\n", afile);
209 return;
212 memset(buffer, 0, 13);
213 readbytes = 12;
214 ReadFile(file, buffer, readbytes, &readbytes, NULL);
215 CloseHandle(file);
216 if (strncmp(buffer, "RIFF", 4) || strcmp(buffer + 8, "AVI "))
218 skip("%s is not an avi riff file, not doing the avi splitter test\n",
219 afile);
220 return;
223 hr = IUnknown_QueryInterface(pAviSplitter, &IID_IFileSourceFilter,
224 (void **)&pfile);
225 ok(hr == E_NOINTERFACE,
226 "Avi splitter returns unexpected error: %08x\n", hr);
227 if (pfile)
228 IUnknown_Release(pfile);
229 pfile = NULL;
231 hr = CoCreateInstance(&CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER,
232 &IID_IBaseFilter, (LPVOID*)&preader);
233 ok(hr == S_OK, "Could not create asynchronous reader: %08x\n", hr);
234 if (hr != S_OK)
235 goto fail;
237 hr = IUnknown_QueryInterface(preader, &IID_IFileSourceFilter,
238 (void**)&pfile);
239 ok(hr == S_OK, "Could not get IFileSourceFilter: %08x\n", hr);
240 if (hr != S_OK)
241 goto fail;
243 hr = IUnknown_QueryInterface(pAviSplitter, &IID_IBaseFilter,
244 (void**)&pavi);
245 ok(hr == S_OK, "Could not get base filter: %08x\n", hr);
246 if (hr != S_OK)
247 goto fail;
249 hr = IFileSourceFilter_Load(pfile, wfile, NULL);
250 if (hr != S_OK)
252 trace("Could not load file\n");
253 goto fail;
256 hr = IBaseFilter_EnumPins(preader, &enumpins);
257 ok(hr == S_OK, "No enumpins: %08x\n", hr);
258 if (hr != S_OK)
259 goto fail;
261 hr = IEnumPins_Next(enumpins, 1, &filepin, NULL);
262 ok(hr == S_OK, "No pin: %08x\n", hr);
263 if (hr != S_OK)
264 goto fail;
266 IUnknown_Release(enumpins);
267 enumpins = NULL;
269 hr = IBaseFilter_EnumPins(pavi, &enumpins);
270 ok(hr == S_OK, "No enumpins: %08x\n", hr);
271 if (hr != S_OK)
272 goto fail;
274 hr = IEnumPins_Next(enumpins, 1, &avipin, NULL);
275 ok(hr == S_OK, "No pin: %08x\n", hr);
276 if (hr != S_OK)
277 goto fail;
279 curlevel = count_threads();
280 ok(curlevel == baselevel,
281 "Amount of threads should be %d not %d\n", baselevel, curlevel);
283 hr = IPin_Connect(filepin, avipin, NULL);
284 ok(hr == S_OK, "Could not connect: %08x\n", hr);
285 if (hr != S_OK)
286 goto fail;
288 expected = 1 + baselevel;
289 curlevel = count_threads();
290 ok(curlevel == expected,
291 "Amount of threads should be %d not %d\n", expected, curlevel);
293 IUnknown_Release(avipin);
294 avipin = NULL;
296 IEnumPins_Reset(enumpins);
298 /* Windows puts the pins in the order: Outputpins - Inputpin,
299 * wine does the reverse, just don't test it for now
300 * Hate to admit it, but windows way makes more sense
302 while (IEnumPins_Next(enumpins, 1, &avipin, NULL) == S_OK)
304 ok(hr == S_OK, "hr: %08x\n", hr);
305 IPin_QueryDirection(avipin, &dir);
306 if (dir == PINDIR_OUTPUT)
308 /* Well, connect it to a null renderer! */
309 IBaseFilter *pnull = NULL;
310 IEnumPins *nullenum = NULL;
311 IPin *nullpin = NULL;
313 hr = CoCreateInstance(&CLSID_NullRenderer, NULL,
314 CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pnull);
315 ok(hr == S_OK, "Could not create null renderer: %08x\n", hr);
316 if (hr != S_OK)
317 break;
319 IBaseFilter_EnumPins(pnull, &nullenum);
320 IEnumPins_Next(nullenum, 1, &nullpin, NULL);
321 IEnumPins_Release(nullenum);
322 IPin_QueryDirection(nullpin, &dir);
324 hr = IPin_Connect(avipin, nullpin, NULL);
325 ok(hr == S_OK, "Failed to connect output pin: %08x\n", hr);
326 IPin_Release(nullpin);
327 if (hr != S_OK)
329 IBaseFilter_Release(pnull);
330 break;
332 IBaseFilter_Run(pnull, 0);
333 ++expected;
336 IUnknown_Release(avipin);
337 avipin = NULL;
340 if (avipin)
341 IUnknown_Release(avipin);
342 avipin = NULL;
344 if (hr != S_OK)
345 goto fail2;
346 /* At this point there is a minimalistic connected avi splitter that can
347 * Be used for all sorts of source filter tests, however that still needs
348 * to be written at a later time.
350 * Interesting tests:
351 * - Can you disconnect an output pin while running?
352 * Expecting: Yes
353 * - Can you disconnect the pullpin while running?
354 * Expecting: No
355 * - Is the reference count incremented during playback or when connected?
356 * Does this happen once for every output pin? Or is there something else
357 * going on.
358 * Expecting: You tell me
361 IBaseFilter_Run(preader, 0);
362 IBaseFilter_Run(pavi, 0);
363 IBaseFilter_GetState(pavi, INFINITE, &state);
365 curlevel = count_threads();
366 /* On a 2 stream filter, there are 4 or 5 threads (seems to be 5)
367 * One is the thread we are in. That leaves 3 or 4 for other dark purposes
368 * Wine is 1 thread short!
370 ok(curlevel == expected || curlevel == expected + 1,
371 "Amount of threads should be %d not %d\n", expected, curlevel);
373 IBaseFilter_Pause(pavi);
374 IBaseFilter_Pause(preader);
375 IBaseFilter_Stop(pavi);
376 IBaseFilter_Stop(preader);
377 IBaseFilter_GetState(pavi, INFINITE, &state);
378 IBaseFilter_GetState(preader, INFINITE, &state);
380 fail2:
381 IEnumPins_Reset(enumpins);
382 while (IEnumPins_Next(enumpins, 1, &avipin, NULL) == S_OK)
384 IPin *to = NULL;
386 IPin_QueryDirection(avipin, &dir);
387 IPin_ConnectedTo(avipin, &to);
388 if (to)
390 IPin_Release(to);
392 if (dir == PINDIR_OUTPUT)
394 PIN_INFO info;
395 IPin_QueryPinInfo(to, &info);
397 /* Release twice: Once normal, second from the
398 * previous while loop
400 IBaseFilter_Stop(info.pFilter);
401 IPin_Disconnect(to);
402 IPin_Disconnect(avipin);
403 IBaseFilter_Release(info.pFilter);
404 IBaseFilter_Release(info.pFilter);
406 else
408 IPin_Disconnect(to);
409 IPin_Disconnect(avipin);
412 IPin_Release(avipin);
413 avipin = NULL;
416 fail:
417 if (hr != S_OK)
418 skip("Prerequisites not matched, skipping remainder of test\n");
419 if (enumpins)
420 IUnknown_Release(enumpins);
422 if (avipin)
423 IUnknown_Release(avipin);
424 if (filepin)
426 IPin *to = NULL;
428 IPin_ConnectedTo(filepin, &to);
429 if (to)
431 IPin_Disconnect(filepin);
432 IPin_Disconnect(to);
434 IUnknown_Release(filepin);
437 if (preader)
438 IUnknown_Release(preader);
439 if (pavi)
440 IUnknown_Release(pavi);
441 if (pfile)
442 IUnknown_Release(pfile);
444 ok(baselevel == 1,
445 "Basic amount of threads should be %d, not %d!\n", 1, baselevel);
448 START_TEST(avisplitter)
450 CoInitialize(NULL);
452 if (!create_avisplitter())
454 skip("Could not create avisplitter\n");
455 return;
458 test_query_interface();
459 test_basefilter();
460 test_threads();
462 release_avisplitter();