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
24 #include "wine/test.h"
28 static HANDLE (WINAPI
*pCreateToolhelp32Snapshot
)(DWORD
, DWORD
);
29 static BOOL (WINAPI
*pThread32First
)(HANDLE
, LPTHREADENTRY32
);
30 static BOOL (WINAPI
*pThread32Next
)(HANDLE
, LPTHREADENTRY32
);
32 static IUnknown
*pAviSplitter
= NULL
;
34 static int count_threads(void)
40 h
= pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD
, 0);
41 te
.dwSize
= sizeof(te
);
43 if (h
== INVALID_HANDLE_VALUE
)
46 pThread32First(h
, &te
);
47 if (te
.th32OwnerProcessID
== GetCurrentProcessId())
52 while (pThread32Next(h
, &te
))
53 if (te
.th32OwnerProcessID
== GetCurrentProcessId())
60 static int create_avisplitter(void)
64 hr
= CoCreateInstance(&CLSID_AviSplitter
, NULL
, CLSCTX_INPROC_SERVER
,
65 &IID_IUnknown
, (LPVOID
*)&pAviSplitter
);
66 return (hr
== S_OK
&& pAviSplitter
!= NULL
);
69 static void release_avisplitter(void)
74 hr
= IUnknown_Release(pAviSplitter
);
76 /* Looks like wine has a reference leak somewhere on test_threads tests,
77 * it passes in windows
79 ok(hr
== 0, "IUnknown_Release failed with %d\n", (INT
)hr
);
82 hr
= IUnknown_Release(pAviSplitter
);
86 static void test_query_interface(void)
90 IUnknown
*iface
= NULL
;
92 #define TEST_INTERFACE(riid,expected) do { \
93 hr = IUnknown_QueryInterface(pAviSplitter, &riid, (void**)&iface); \
94 ok( hr == expected, #riid" should %s got %08X\n", expected==S_OK ? "exist" : "not be present", GetLastError() ); \
96 ref = IUnknown_Release(iface); \
97 ok(ref == 1, "Reference is %u, expected 1\n", ref); \
102 TEST_INTERFACE(IID_IBaseFilter
,S_OK
);
103 TEST_INTERFACE(IID_IMediaSeeking
,E_NOINTERFACE
);
104 TEST_INTERFACE(IID_IKsPropertySet
,E_NOINTERFACE
);
105 TEST_INTERFACE(IID_IMediaPosition
,E_NOINTERFACE
);
106 TEST_INTERFACE(IID_IQualityControl
,E_NOINTERFACE
);
107 TEST_INTERFACE(IID_IQualProp
,E_NOINTERFACE
);
108 #undef TEST_INTERFACE
111 static void test_pin(IPin
*pin
)
113 IMemInputPin
*mpin
= NULL
;
115 IPin_QueryInterface(pin
, &IID_IMemInputPin
, (void **)&mpin
);
117 ok(mpin
== NULL
, "IMemInputPin found!\n");
119 IMemInputPin_Release(mpin
);
123 static void test_basefilter(void)
125 IEnumPins
*pin_enum
= NULL
;
126 IBaseFilter
*base
= NULL
;
131 IUnknown_QueryInterface(pAviSplitter
, &IID_IBaseFilter
, (void *)&base
);
134 /* test_query_interface handles this case */
135 skip("No IBaseFilter\n");
139 hr
= IBaseFilter_EnumPins(base
, NULL
);
140 ok(hr
== E_POINTER
, "hr = %08x and not E_POINTER\n", hr
);
142 hr
= IBaseFilter_EnumPins(base
, &pin_enum
);
143 ok(hr
== S_OK
, "hr = %08x and not S_OK\n", hr
);
145 hr
= IEnumPins_Next(pin_enum
, 1, NULL
, NULL
);
146 ok(hr
== E_POINTER
, "hr = %08x and not E_POINTER\n", hr
);
148 hr
= IEnumPins_Next(pin_enum
, 2, pins
, NULL
);
149 ok(hr
== E_INVALIDARG
, "hr = %08x and not E_INVALIDARG\n", hr
);
151 pins
[0] = (void *)0xdead;
152 pins
[1] = (void *)0xdeed;
154 hr
= IEnumPins_Next(pin_enum
, 2, pins
, &ref
);
155 ok(hr
== S_FALSE
, "hr = %08x instead of S_FALSE\n", hr
);
156 ok(pins
[0] != (void *)0xdead && pins
[0] != NULL
,
157 "pins[0] = %p\n", pins
[0]);
158 if (pins
[0] != (void *)0xdead && pins
[0] != NULL
)
161 IPin_Release(pins
[0]);
164 ok(pins
[1] == (void *)0xdeed, "pins[1] = %p\n", pins
[1]);
166 ref
= IEnumPins_Release(pin_enum
);
167 ok(ref
== 0, "ref is %u and not 0!\n", ref
);
169 IBaseFilter_Release(base
);
172 static const WCHAR wfile
[] = {'t','e','s','t','.','a','v','i',0};
173 static const char afile
[] = "test.avi";
175 /* This test doesn't use the quartz filtergraph because it makes it impossible
176 * to be certain that a thread is really one owned by the avi splitter.
177 * A lot of the decoder filters will also have their own thread, and Windows'
178 * filtergraph has a separate thread for start/stop/seeking requests.
179 * By avoiding the filtergraph altogether and connecting streams directly to
180 * the null renderer I am sure that this is not the case here.
182 static void test_threads(void)
184 IFileSourceFilter
*pfile
= NULL
;
185 IBaseFilter
*preader
= NULL
, *pavi
= NULL
;
186 IEnumPins
*enumpins
= NULL
;
187 IPin
*filepin
= NULL
, *avipin
= NULL
;
189 int baselevel
, curlevel
, expected
;
191 PIN_DIRECTION dir
= PINDIR_OUTPUT
;
196 /* We need another way of counting threads on NT4. Skip these tests (for now) */
197 if (!pCreateToolhelp32Snapshot
|| !pThread32First
|| !pThread32Next
)
199 win_skip("Needed thread functions are not available (NT4)\n");
203 /* Before doing anything (the thread count at the start differs per OS) */
204 baselevel
= count_threads();
206 file
= CreateFileW(wfile
, GENERIC_READ
, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
207 NULL
, OPEN_EXISTING
, 0, NULL
);
208 if (file
== INVALID_HANDLE_VALUE
)
210 skip("Could not read test file \"%s\", skipping test\n", afile
);
214 memset(buffer
, 0, 13);
216 ReadFile(file
, buffer
, readbytes
, &readbytes
, NULL
);
218 if (strncmp(buffer
, "RIFF", 4) || strcmp(buffer
+ 8, "AVI "))
220 skip("%s is not an avi riff file, not doing the avi splitter test\n",
225 hr
= IUnknown_QueryInterface(pAviSplitter
, &IID_IFileSourceFilter
,
227 ok(hr
== E_NOINTERFACE
,
228 "Avi splitter returns unexpected error: %08x\n", hr
);
230 IUnknown_Release(pfile
);
233 hr
= CoCreateInstance(&CLSID_AsyncReader
, NULL
, CLSCTX_INPROC_SERVER
,
234 &IID_IBaseFilter
, (LPVOID
*)&preader
);
235 ok(hr
== S_OK
, "Could not create asynchronous reader: %08x\n", hr
);
239 hr
= IUnknown_QueryInterface(preader
, &IID_IFileSourceFilter
,
241 ok(hr
== S_OK
, "Could not get IFileSourceFilter: %08x\n", hr
);
245 hr
= IUnknown_QueryInterface(pAviSplitter
, &IID_IBaseFilter
,
247 ok(hr
== S_OK
, "Could not get base filter: %08x\n", hr
);
251 hr
= IFileSourceFilter_Load(pfile
, wfile
, NULL
);
254 trace("Could not load file\n");
258 hr
= IBaseFilter_EnumPins(preader
, &enumpins
);
259 ok(hr
== S_OK
, "No enumpins: %08x\n", hr
);
263 hr
= IEnumPins_Next(enumpins
, 1, &filepin
, NULL
);
264 ok(hr
== S_OK
, "No pin: %08x\n", hr
);
268 IUnknown_Release(enumpins
);
271 hr
= IBaseFilter_EnumPins(pavi
, &enumpins
);
272 ok(hr
== S_OK
, "No enumpins: %08x\n", hr
);
276 hr
= IEnumPins_Next(enumpins
, 1, &avipin
, NULL
);
277 ok(hr
== S_OK
, "No pin: %08x\n", hr
);
281 curlevel
= count_threads();
282 ok(curlevel
== baselevel
,
283 "The thread count should be %d not %d\n", baselevel
, curlevel
);
285 hr
= IPin_Connect(filepin
, avipin
, NULL
);
286 ok(hr
== S_OK
, "Could not connect: %08x\n", hr
);
290 expected
= 1 + baselevel
;
291 curlevel
= count_threads();
292 ok(curlevel
== expected
,
293 "The thread count should be %d not %d\n", expected
, curlevel
);
295 IUnknown_Release(avipin
);
298 IEnumPins_Reset(enumpins
);
300 /* Windows puts the pins in the order: Outputpins - Inputpin,
301 * wine does the reverse, just don't test it for now
302 * Hate to admit it, but windows way makes more sense
304 while (IEnumPins_Next(enumpins
, 1, &avipin
, NULL
) == S_OK
)
306 IPin_QueryDirection(avipin
, &dir
);
307 if (dir
== PINDIR_OUTPUT
)
309 /* Well, connect it to a null renderer! */
310 IBaseFilter
*pnull
= NULL
;
311 IEnumPins
*nullenum
= NULL
;
312 IPin
*nullpin
= NULL
;
314 hr
= CoCreateInstance(&CLSID_NullRenderer
, NULL
,
315 CLSCTX_INPROC_SERVER
, &IID_IBaseFilter
, (LPVOID
*)&pnull
);
316 ok(hr
== S_OK
, "Could not create null renderer: %08x\n", hr
);
320 IBaseFilter_EnumPins(pnull
, &nullenum
);
321 IEnumPins_Next(nullenum
, 1, &nullpin
, NULL
);
322 IEnumPins_Release(nullenum
);
323 IPin_QueryDirection(nullpin
, &dir
);
325 hr
= IPin_Connect(avipin
, nullpin
, NULL
);
326 ok(hr
== S_OK
, "Failed to connect output pin: %08x\n", hr
);
327 IPin_Release(nullpin
);
330 IBaseFilter_Release(pnull
);
333 IBaseFilter_Run(pnull
, 0);
337 IUnknown_Release(avipin
);
342 IUnknown_Release(avipin
);
347 /* At this point there is a minimalistic connected avi splitter that can
348 * be used for all sorts of source filter tests. However that still needs
349 * to be written at a later time.
352 * - Can you disconnect an output pin while running?
354 * - Can you disconnect the pullpin while running?
356 * - Is the reference count incremented during playback or when connected?
357 * Does this happen once for every output pin? Or is there something else
359 * Expecting: You tell me
362 IBaseFilter_Run(preader
, 0);
363 IBaseFilter_Run(pavi
, 0);
364 IBaseFilter_GetState(pavi
, INFINITE
, &state
);
366 curlevel
= count_threads();
367 ok(curlevel
== expected
,
368 "The thread count should be %d not %d\n", expected
, curlevel
);
370 IBaseFilter_Pause(pavi
);
371 IBaseFilter_Pause(preader
);
372 IBaseFilter_Stop(pavi
);
373 IBaseFilter_Stop(preader
);
374 IBaseFilter_GetState(pavi
, INFINITE
, &state
);
375 IBaseFilter_GetState(preader
, INFINITE
, &state
);
378 IEnumPins_Reset(enumpins
);
379 while (IEnumPins_Next(enumpins
, 1, &avipin
, NULL
) == S_OK
)
383 IPin_QueryDirection(avipin
, &dir
);
384 IPin_ConnectedTo(avipin
, &to
);
389 if (dir
== PINDIR_OUTPUT
)
392 IPin_QueryPinInfo(to
, &info
);
394 /* Release twice: Once normal, second from the
395 * previous while loop
397 IBaseFilter_Stop(info
.pFilter
);
399 IPin_Disconnect(avipin
);
400 IBaseFilter_Release(info
.pFilter
);
401 IBaseFilter_Release(info
.pFilter
);
406 IPin_Disconnect(avipin
);
409 IPin_Release(avipin
);
415 skip("Prerequisites not matched, skipping remainder of test\n");
417 IUnknown_Release(enumpins
);
420 IUnknown_Release(avipin
);
425 IPin_ConnectedTo(filepin
, &to
);
428 IPin_Disconnect(filepin
);
431 IUnknown_Release(filepin
);
435 IUnknown_Release(preader
);
437 IUnknown_Release(pavi
);
439 IUnknown_Release(pfile
);
441 curlevel
= count_threads();
443 ok(curlevel
== baselevel
,
444 "The thread count should be %d not %d\n", baselevel
, curlevel
);
447 START_TEST(avisplitter
)
449 HMODULE kernel32
= GetModuleHandleA("kernel32.dll");
451 pCreateToolhelp32Snapshot
= (void*)GetProcAddress(kernel32
, "CreateToolhelp32Snapshot");
452 pThread32First
= (void*)GetProcAddress(kernel32
, "Thread32First");
453 pThread32Next
= (void*)GetProcAddress(kernel32
, "Thread32Next");
457 if (!create_avisplitter())
459 skip("Could not create avisplitter\n");
463 test_query_interface();
467 release_avisplitter();