ReactOS 0.4.15-dev-7906-g1b85a5f
filtergraph.c
Go to the documentation of this file.
1/* DirectShow FilterGraph object (QUARTZ.DLL)
2 *
3 * Copyright 2002 Lionel Ulmer
4 * Copyright 2004 Christian Costa
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21#include "config.h"
22#include <stdarg.h>
23
24#define COBJMACROS
25
26#include "windef.h"
27#include "winbase.h"
28#include "winuser.h"
29#include "winreg.h"
30#include "shlwapi.h"
31#include "dshow.h"
32#include "wine/debug.h"
33#include "quartz_private.h"
34#include "ole2.h"
35#include "olectl.h"
36#include "strmif.h"
37#include "vfwmsgs.h"
38#include "evcode.h"
39#include "wine/unicode.h"
40
41
43
44typedef struct {
45 HWND hWnd; /* Target window */
46 UINT msg; /* User window message */
47 LONG_PTR instance; /* User data */
48 int disabled; /* Disabled messages posting */
49} WndNotify;
50
51typedef struct {
52 LONG lEventCode; /* Event code */
53 LONG_PTR lParam1; /* Param1 */
54 LONG_PTR lParam2; /* Param2 */
55} Event;
56
57/* messages ring implementation for queuing events (taken from winmm) */
58#define EVENTS_RING_BUFFER_INCREMENT 64
59typedef struct {
65 HANDLE msg_event; /* Signaled for no empty queue */
67
69{
70 omr->msg_toget = 0;
71 omr->msg_tosave = 0;
74 omr->messages = CoTaskMemAlloc(omr->ring_buffer_size * sizeof(Event));
75 ZeroMemory(omr->messages, omr->ring_buffer_size * sizeof(Event));
76
78 omr->msg_crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": EventsQueue.msg_crst");
79 return TRUE;
80}
81
83{
86 omr->msg_crst.DebugInfo->Spare[0] = 0;
88 return TRUE;
89}
90
92{
94 if (omr->msg_toget == ((omr->msg_tosave + 1) % omr->ring_buffer_size))
95 {
96 int old_ring_buffer_size = omr->ring_buffer_size;
98 TRACE("omr->ring_buffer_size=%d\n",omr->ring_buffer_size);
99 omr->messages = CoTaskMemRealloc(omr->messages, omr->ring_buffer_size * sizeof(Event));
100 /* Now we need to rearrange the ring buffer so that the new
101 buffers just allocated are in between omr->msg_tosave and
102 omr->msg_toget.
103 */
104 if (omr->msg_tosave < omr->msg_toget)
105 {
107 &(omr->messages[omr->msg_toget]),
108 sizeof(Event)*(old_ring_buffer_size - omr->msg_toget)
109 );
111 }
112 }
113 omr->messages[omr->msg_tosave] = *evt;
114 SetEvent(omr->msg_event);
115 omr->msg_tosave = (omr->msg_tosave + 1) % omr->ring_buffer_size;
117 return TRUE;
118}
119
120static BOOL EventsQueue_GetEvent(EventsQueue* omr, Event* evt, LONG msTimeOut)
121{
122 if (WaitForSingleObject(omr->msg_event, msTimeOut) != WAIT_OBJECT_0)
123 return FALSE;
124
126
127 if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
128 {
130 return FALSE;
131 }
132
133 *evt = omr->messages[omr->msg_toget];
134 omr->msg_toget = (omr->msg_toget + 1) % omr->ring_buffer_size;
135
136 /* Mark the buffer as empty if needed */
137 if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
138 ResetEvent(omr->msg_event);
139
141 return TRUE;
142}
143
144#define MAX_ITF_CACHE_ENTRIES 3
145typedef struct _ITF_CACHE_ENTRY {
146 const IID* riid;
150
151typedef struct _IFilterGraphImpl {
154 IMediaControl IMediaControl_iface;
156 IBasicAudio IBasicAudio_iface;
157 IBasicVideo2 IBasicVideo2_iface;
158 IVideoWindow IVideoWindow_iface;
159 IMediaEventEx IMediaEventEx_iface;
163 IMediaPosition IMediaPosition_iface;
166 /* IAMGraphStreams */
167 /* IAMStats */
168 /* IFilterChain */
169 /* IFilterMapper2 */
170 /* IQueueCommand */
171 /* IRegisterServiceProvider */
172 /* IResourceMananger */
173 /* IServiceProvider */
174 /* IVideoFrameStep */
175
195 OAFilterState state;
207
209{
210 return CONTAINING_RECORD(iface, IFilterGraphImpl, IUnknown_inner);
211}
212
214{
216 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObj);
217
219 *ppvObj = &This->IUnknown_inner;
220 TRACE(" returning IUnknown interface (%p)\n", *ppvObj);
221 } else if (IsEqualGUID(&IID_IFilterGraph, riid) ||
222 IsEqualGUID(&IID_IFilterGraph2, riid) ||
223 IsEqualGUID(&IID_IGraphBuilder, riid)) {
224 *ppvObj = &This->IFilterGraph2_iface;
225 TRACE(" returning IGraphBuilder interface (%p)\n", *ppvObj);
226 } else if (IsEqualGUID(&IID_IMediaControl, riid)) {
227 *ppvObj = &This->IMediaControl_iface;
228 TRACE(" returning IMediaControl interface (%p)\n", *ppvObj);
229 } else if (IsEqualGUID(&IID_IMediaSeeking, riid)) {
230 *ppvObj = &This->IMediaSeeking_iface;
231 TRACE(" returning IMediaSeeking interface (%p)\n", *ppvObj);
232 } else if (IsEqualGUID(&IID_IBasicAudio, riid)) {
233 *ppvObj = &This->IBasicAudio_iface;
234 TRACE(" returning IBasicAudio interface (%p)\n", *ppvObj);
235 } else if (IsEqualGUID(&IID_IBasicVideo, riid) ||
236 IsEqualGUID(&IID_IBasicVideo2, riid)) {
237 *ppvObj = &This->IBasicVideo2_iface;
238 TRACE(" returning IBasicVideo2 interface (%p)\n", *ppvObj);
239 } else if (IsEqualGUID(&IID_IVideoWindow, riid)) {
240 *ppvObj = &This->IVideoWindow_iface;
241 TRACE(" returning IVideoWindow interface (%p)\n", *ppvObj);
242 } else if (IsEqualGUID(&IID_IMediaEvent, riid) ||
243 IsEqualGUID(&IID_IMediaEventEx, riid)) {
244 *ppvObj = &This->IMediaEventEx_iface;
245 TRACE(" returning IMediaEvent(Ex) interface (%p)\n", *ppvObj);
246 } else if (IsEqualGUID(&IID_IMediaFilter, riid) ||
248 *ppvObj = &This->IMediaFilter_iface;
249 TRACE(" returning IMediaFilter interface (%p)\n", *ppvObj);
250 } else if (IsEqualGUID(&IID_IMediaEventSink, riid)) {
251 *ppvObj = &This->IMediaEventSink_iface;
252 TRACE(" returning IMediaEventSink interface (%p)\n", *ppvObj);
253 } else if (IsEqualGUID(&IID_IGraphConfig, riid)) {
254 *ppvObj = &This->IGraphConfig_iface;
255 TRACE(" returning IGraphConfig interface (%p)\n", *ppvObj);
256 } else if (IsEqualGUID(&IID_IMediaPosition, riid)) {
257 *ppvObj = &This->IMediaPosition_iface;
258 TRACE(" returning IMediaPosition interface (%p)\n", *ppvObj);
259 } else if (IsEqualGUID(&IID_IObjectWithSite, riid)) {
260 *ppvObj = &This->IObjectWithSite_iface;
261 TRACE(" returning IObjectWithSite interface (%p)\n", *ppvObj);
262 } else if (IsEqualGUID(&IID_IFilterMapper, riid)) {
263 TRACE(" requesting IFilterMapper interface from aggregated filtermapper (%p)\n", *ppvObj);
264 return IUnknown_QueryInterface(This->punkFilterMapper2, riid, ppvObj);
265 } else if (IsEqualGUID(&IID_IFilterMapper2, riid)) {
266 TRACE(" returning IFilterMapper2 interface from aggregated filtermapper (%p)\n", *ppvObj);
267 return IUnknown_QueryInterface(This->punkFilterMapper2, riid, ppvObj);
268 } else if (IsEqualGUID(&IID_IFilterMapper3, riid)) {
269 TRACE(" returning IFilterMapper3 interface from aggregated filtermapper (%p)\n", *ppvObj);
270 return IUnknown_QueryInterface(This->punkFilterMapper2, riid, ppvObj);
271 } else if (IsEqualGUID(&IID_IGraphVersion, riid)) {
272 *ppvObj = &This->IGraphConfig_iface;
273 TRACE(" returning IGraphConfig interface (%p)\n", *ppvObj);
274 } else {
275 *ppvObj = NULL;
276 FIXME("unknown interface %s\n", debugstr_guid(riid));
277 return E_NOINTERFACE;
278 }
279
280 IUnknown_AddRef((IUnknown *)*ppvObj);
281 return S_OK;
282}
283
285{
288
289 TRACE("(%p)->(): new ref = %d\n", This, ref);
290
291 return ref;
292}
293
295{
298
299 TRACE("(%p)->(): new ref = %d\n", This, ref);
300
301 if (ref == 0) {
302 int i;
303
304 This->ref = 1; /* guard against reentrancy (aggregation). */
305
306 IMediaControl_Stop(&This->IMediaControl_iface);
307
308 while (This->nFilters)
309 IFilterGraph2_RemoveFilter(&This->IFilterGraph2_iface, This->ppFiltersInGraph[0]);
310
311 if (This->refClock)
312 IReferenceClock_Release(This->refClock);
313
314 for (i = 0; i < This->nItfCacheEntries; i++)
315 {
316 if (This->ItfCacheEntries[i].iface)
317 IUnknown_Release(This->ItfCacheEntries[i].iface);
318 }
319
320 IUnknown_Release(This->punkFilterMapper2);
321
322 if (This->pSite) IUnknown_Release(This->pSite);
323
324 CloseHandle(This->hEventCompletion);
325 EventsQueue_Destroy(&This->evqueue);
326 This->cs.DebugInfo->Spare[0] = 0;
328 CoTaskMemFree(This->ppFiltersInGraph);
329 CoTaskMemFree(This->pFilterNames);
331 }
332 return ref;
333}
334
336{
337 return CONTAINING_RECORD(iface, IFilterGraphImpl, IFilterGraph2_iface);
338}
339
341{
343
344 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj);
345
346 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
347}
348
350{
352
353 TRACE("(%p/%p)->()\n", This, iface);
354
355 return IUnknown_AddRef(This->outer_unk);
356}
357
359{
361
362 TRACE("(%p/%p)->()\n", This, iface);
363
364 return IUnknown_Release(This->outer_unk);
365}
366
367/*** IFilterGraph methods ***/
370{
372 HRESULT hr;
373 int i,j;
374 WCHAR* wszFilterName = NULL;
375 BOOL duplicate_name = FALSE;
376
377 TRACE("(%p/%p)->(%p, %s (%p))\n", This, iface, pFilter, debugstr_w(pName), pName);
378
379 if (!pFilter)
380 return E_POINTER;
381
382 wszFilterName = CoTaskMemAlloc( (pName ? strlenW(pName) + 6 : 5) * sizeof(WCHAR) );
383
384 if (pName)
385 {
386 /* Check if name already exists */
387 for(i = 0; i < This->nFilters; i++)
388 if (!strcmpW(This->pFilterNames[i], pName))
389 {
390 duplicate_name = TRUE;
391 break;
392 }
393 }
394
395 /* If no name given or name already existing, generate one */
396 if (!pName || duplicate_name)
397 {
398 static const WCHAR wszFmt1[] = {'%','s',' ','%','0','4','d',0};
399 static const WCHAR wszFmt2[] = {'%','0','4','d',0};
400
401 for (j = 0; j < 10000 ; j++)
402 {
403 /* Create name */
404 if (pName)
405 sprintfW(wszFilterName, wszFmt1, pName, This->nameIndex);
406 else
407 sprintfW(wszFilterName, wszFmt2, This->nameIndex);
408 TRACE("Generated name %s\n", debugstr_w(wszFilterName));
409
410 /* Check if the generated name already exists */
411 for(i = 0; i < This->nFilters; i++)
412 if (!strcmpW(This->pFilterNames[i], wszFilterName))
413 break;
414
415 /* Compute next index and exit if generated name is suitable */
416 if (This->nameIndex++ == 10000)
417 This->nameIndex = 1;
418 if (i == This->nFilters)
419 break;
420 }
421 /* Unable to find a suitable name */
422 if (j == 10000)
423 {
424 CoTaskMemFree(wszFilterName);
426 }
427 }
428 else
429 memcpy(wszFilterName, pName, (strlenW(pName) + 1) * sizeof(WCHAR));
430
431 if (This->nFilters + 1 > This->filterCapacity)
432 {
433 int newCapacity = This->filterCapacity ? 2 * This->filterCapacity : 1;
434 IBaseFilter ** ppNewFilters = CoTaskMemAlloc(newCapacity * sizeof(IBaseFilter*));
435 LPWSTR * pNewNames = CoTaskMemAlloc(newCapacity * sizeof(LPWSTR));
436 memcpy(ppNewFilters, This->ppFiltersInGraph, This->nFilters * sizeof(IBaseFilter*));
437 memcpy(pNewNames, This->pFilterNames, This->nFilters * sizeof(LPWSTR));
438 if (This->filterCapacity)
439 {
440 CoTaskMemFree(This->ppFiltersInGraph);
441 CoTaskMemFree(This->pFilterNames);
442 }
443 This->ppFiltersInGraph = ppNewFilters;
444 This->pFilterNames = pNewNames;
445 This->filterCapacity = newCapacity;
446 }
447
448 hr = IBaseFilter_JoinFilterGraph(pFilter, (IFilterGraph *)&This->IFilterGraph2_iface, wszFilterName);
449
450 if (SUCCEEDED(hr))
451 {
452 IBaseFilter_AddRef(pFilter);
453 This->ppFiltersInGraph[This->nFilters] = pFilter;
454 This->pFilterNames[This->nFilters] = wszFilterName;
455 This->nFilters++;
456 This->version++;
457 IBaseFilter_SetSyncSource(pFilter, This->refClock);
458 }
459 else
460 CoTaskMemFree(wszFilterName);
461
462 if (SUCCEEDED(hr) && duplicate_name)
464
465 return hr;
466}
467
469{
471 int i;
472 HRESULT hr = E_FAIL;
473
474 TRACE("(%p/%p)->(%p)\n", This, iface, pFilter);
475
476 /* FIXME: check graph is stopped */
477
478 for (i = 0; i < This->nFilters; i++)
479 {
480 if (This->ppFiltersInGraph[i] == pFilter)
481 {
482 IEnumPins *penumpins = NULL;
483 FILTER_STATE state;
484
485 if (This->defaultclock && This->refClockProvider == pFilter)
486 {
487 IMediaFilter_SetSyncSource(&This->IMediaFilter_iface, NULL);
488 This->defaultclock = TRUE;
489 }
490
491 TRACE("Removing filter %s\n", debugstr_w(This->pFilterNames[i]));
492 IBaseFilter_GetState(pFilter, 0, &state);
493 if (state == State_Running)
494 IBaseFilter_Pause(pFilter);
495 if (state != State_Stopped)
496 IBaseFilter_Stop(pFilter);
497
498 hr = IBaseFilter_EnumPins(pFilter, &penumpins);
499 if (SUCCEEDED(hr)) {
500 IPin *ppin;
501 while(IEnumPins_Next(penumpins, 1, &ppin, NULL) == S_OK)
502 {
503 IPin *victim = NULL;
504 HRESULT h;
505 IPin_ConnectedTo(ppin, &victim);
506 if (victim)
507 {
508 h = IPin_Disconnect(victim);
509 TRACE("Disconnect other side: %08x\n", h);
510 if (h == VFW_E_NOT_STOPPED)
511 {
512 PIN_INFO pinfo;
513 IPin_QueryPinInfo(victim, &pinfo);
514
515 IBaseFilter_GetState(pinfo.pFilter, 0, &state);
516 if (state == State_Running)
517 IBaseFilter_Pause(pinfo.pFilter);
518 IBaseFilter_Stop(pinfo.pFilter);
519 IBaseFilter_Release(pinfo.pFilter);
520 h = IPin_Disconnect(victim);
521 TRACE("Disconnect retry: %08x\n", h);
522 }
523 IPin_Release(victim);
524 }
525 h = IPin_Disconnect(ppin);
526 TRACE("Disconnect 2: %08x\n", h);
527
528 IPin_Release(ppin);
529 }
530 IEnumPins_Release(penumpins);
531 }
532
533 hr = IBaseFilter_JoinFilterGraph(pFilter, NULL, This->pFilterNames[i]);
534 if (SUCCEEDED(hr))
535 {
536 IBaseFilter_SetSyncSource(pFilter, NULL);
537 IBaseFilter_Release(pFilter);
538 CoTaskMemFree(This->pFilterNames[i]);
539 memmove(This->ppFiltersInGraph+i, This->ppFiltersInGraph+i+1, sizeof(IBaseFilter*)*(This->nFilters - 1 - i));
540 memmove(This->pFilterNames+i, This->pFilterNames+i+1, sizeof(LPWSTR)*(This->nFilters - 1 - i));
541 This->nFilters--;
542 This->version++;
543 /* Invalidate interfaces in the cache */
544 for (i = 0; i < This->nItfCacheEntries; i++)
545 if (pFilter == This->ItfCacheEntries[i].filter)
546 {
547 IUnknown_Release(This->ItfCacheEntries[i].iface);
548 This->ItfCacheEntries[i].iface = NULL;
549 This->ItfCacheEntries[i].filter = NULL;
550 }
551 return S_OK;
552 }
553 break;
554 }
555 }
556
557 return hr; /* FIXME: check this error code */
558}
559
561{
563
564 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
565
566 return IEnumFiltersImpl_Construct(&This->IGraphVersion_iface, &This->ppFiltersInGraph, &This->nFilters, ppEnum);
567}
568
570 IBaseFilter **ppFilter)
571{
573 int i;
574
575 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_w(pName), pName, ppFilter);
576
577 if (!ppFilter)
578 return E_POINTER;
579
580 for (i = 0; i < This->nFilters; i++)
581 {
582 if (!strcmpW(pName, This->pFilterNames[i]))
583 {
584 *ppFilter = This->ppFiltersInGraph[i];
585 IBaseFilter_AddRef(*ppFilter);
586 return S_OK;
587 }
588 }
589
590 *ppFilter = NULL;
591 return VFW_E_NOT_FOUND;
592}
593
594/* Don't allow a circular connection to form, return VFW_E_CIRCULAR_GRAPH if this would be the case.
595 * A circular connection will be formed if from the filter of the output pin, the input pin can be reached
596 */
598{
599#if 1
600 HRESULT hr;
601 PIN_INFO info_out, info_in;
602
603 hr = IPin_QueryPinInfo(out, &info_out);
604 if (FAILED(hr))
605 return hr;
606 if (info_out.dir != PINDIR_OUTPUT)
607 {
608 IBaseFilter_Release(info_out.pFilter);
610 }
611
612 hr = IPin_QueryPinInfo(in, &info_in);
613 if (SUCCEEDED(hr))
614 IBaseFilter_Release(info_in.pFilter);
615 if (FAILED(hr))
616 goto out;
617 if (info_in.dir != PINDIR_INPUT)
618 {
620 goto out;
621 }
622
623 if (info_out.pFilter == info_in.pFilter)
625 else
626 {
627 IEnumPins *enumpins;
628 IPin *test;
629
630 hr = IBaseFilter_EnumPins(info_out.pFilter, &enumpins);
631 if (FAILED(hr))
632 goto out;
633
634 IEnumPins_Reset(enumpins);
635 while ((hr = IEnumPins_Next(enumpins, 1, &test, NULL)) == S_OK)
636 {
638 IPin_QueryDirection(test, &dir);
639 if (dir == PINDIR_INPUT)
640 {
641 IPin *victim = NULL;
642 IPin_ConnectedTo(test, &victim);
643 if (victim)
644 {
645 hr = CheckCircularConnection(This, victim, in);
646 IPin_Release(victim);
647 if (FAILED(hr))
648 {
649 IPin_Release(test);
650 break;
651 }
652 }
653 }
654 IPin_Release(test);
655 }
656 IEnumPins_Release(enumpins);
657 }
658
659out:
660 IBaseFilter_Release(info_out.pFilter);
661 if (FAILED(hr))
662 ERR("Checking filtergraph returned %08x, something's not right!\n", hr);
663 return hr;
664#else
665 /* Debugging filtergraphs not enabled */
666 return S_OK;
667#endif
668}
669
670
671/* NOTE: despite the implication, it doesn't matter which
672 * way round you put in the input and output pins */
674 const AM_MEDIA_TYPE *pmt)
675{
678 HRESULT hr;
679
680 TRACE("(%p/%p)->(%p, %p, %p)\n", This, iface, ppinIn, ppinOut, pmt);
681
682 /* FIXME: check pins are in graph */
683
684 if (TRACE_ON(quartz))
685 {
686 PIN_INFO PinInfo;
687
688 hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
689 if (FAILED(hr))
690 return hr;
691
692 TRACE("Filter owning ppinIn(%p) => %p\n", ppinIn, PinInfo.pFilter);
693 IBaseFilter_Release(PinInfo.pFilter);
694
695 hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
696 if (FAILED(hr))
697 return hr;
698
699 TRACE("Filter owning ppinOut(%p) => %p\n", ppinOut, PinInfo.pFilter);
700 IBaseFilter_Release(PinInfo.pFilter);
701 }
702
703 hr = IPin_QueryDirection(ppinIn, &dir);
704 if (SUCCEEDED(hr))
705 {
706 if (dir == PINDIR_INPUT)
707 {
708 hr = CheckCircularConnection(This, ppinOut, ppinIn);
709 if (SUCCEEDED(hr))
710 hr = IPin_Connect(ppinOut, ppinIn, pmt);
711 }
712 else
713 {
714 hr = CheckCircularConnection(This, ppinIn, ppinOut);
715 if (SUCCEEDED(hr))
716 hr = IPin_Connect(ppinIn, ppinOut, pmt);
717 }
718 }
719
720 return hr;
721}
722
724{
726 IPin *pConnectedTo = NULL;
727 HRESULT hr;
728 PIN_DIRECTION pindir;
729
730 IPin_QueryDirection(ppin, &pindir);
731 hr = IPin_ConnectedTo(ppin, &pConnectedTo);
732
733 TRACE("(%p/%p)->(%p) -- %p\n", This, iface, ppin, pConnectedTo);
734
735 if (FAILED(hr)) {
736 TRACE("Querying connected to failed: %x\n", hr);
737 return hr;
738 }
739 IPin_Disconnect(ppin);
740 IPin_Disconnect(pConnectedTo);
741 if (pindir == PINDIR_INPUT)
742 hr = IPin_Connect(pConnectedTo, ppin, NULL);
743 else
744 hr = IPin_Connect(ppin, pConnectedTo, NULL);
745 IPin_Release(pConnectedTo);
746 if (FAILED(hr))
747 WARN("Reconnecting pins failed, pins are not connected now..\n");
748 TRACE("-> %08x\n", hr);
749 return hr;
750}
751
753{
755
756 TRACE("(%p/%p)->(%p)\n", This, iface, ppin);
757
758 if (!ppin)
759 return E_POINTER;
760
761 return IPin_Disconnect(ppin);
762}
763
765{
767 IReferenceClock *pClock = NULL;
768 HRESULT hr = S_OK;
769 int i;
770
771 TRACE("(%p/%p)->() live sources not handled properly!\n", This, iface);
772
774
775 for (i = 0; i < This->nFilters; ++i)
776 {
777 DWORD miscflags;
779 IBaseFilter_QueryInterface(This->ppFiltersInGraph[i], &IID_IAMFilterMiscFlags, (void**)&flags);
780 if (!flags)
781 continue;
782 miscflags = IAMFilterMiscFlags_GetMiscFlags(flags);
783 IAMFilterMiscFlags_Release(flags);
784 if (miscflags == AM_FILTER_MISC_FLAGS_IS_RENDERER)
785 IBaseFilter_QueryInterface(This->ppFiltersInGraph[i], &IID_IReferenceClock, (void**)&pClock);
786 if (pClock)
787 break;
788 }
789
790 if (!pClock)
791 {
792 hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, &IID_IReferenceClock, (LPVOID*)&pClock);
793 This->refClockProvider = NULL;
794 }
795 else
796 This->refClockProvider = This->ppFiltersInGraph[i];
797
798 if (SUCCEEDED(hr))
799 {
800 hr = IMediaFilter_SetSyncSource(&This->IMediaFilter_iface, pClock);
801 This->defaultclock = TRUE;
803 }
805
806 return hr;
807}
808
809static HRESULT GetFilterInfo(IMoniker* pMoniker, VARIANT* pvar)
810{
811 static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
812 IPropertyBag * pPropBagCat = NULL;
813 HRESULT hr;
814
815 VariantInit(pvar);
816
817 hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBagCat);
818
819 if (SUCCEEDED(hr))
820 hr = IPropertyBag_Read(pPropBagCat, wszFriendlyName, pvar, NULL);
821
822 if (SUCCEEDED(hr))
823 TRACE("Moniker = %s\n", debugstr_w(V_BSTR(pvar)));
824
825 if (pPropBagCat)
826 IPropertyBag_Release(pPropBagCat);
827
828 return hr;
829}
830
831static HRESULT GetInternalConnections(IBaseFilter* pfilter, IPin* pinputpin, IPin*** pppins, ULONG* pnb)
832{
833 HRESULT hr;
834 ULONG nb = 0;
835
836 TRACE("(%p, %p, %p, %p)\n", pfilter, pinputpin, pppins, pnb);
837 hr = IPin_QueryInternalConnections(pinputpin, NULL, &nb);
838 if (hr == S_OK) {
839 /* Rendered input */
840 } else if (hr == S_FALSE) {
841 *pppins = CoTaskMemAlloc(sizeof(IPin*)*nb);
842 hr = IPin_QueryInternalConnections(pinputpin, *pppins, &nb);
843 if (hr != S_OK) {
844 WARN("Error (%x)\n", hr);
845 }
846 } else if (hr == E_NOTIMPL) {
847 /* Input connected to all outputs */
848 IEnumPins* penumpins;
849 IPin* ppin;
850 int i = 0;
851 TRACE("E_NOTIMPL\n");
852 hr = IBaseFilter_EnumPins(pfilter, &penumpins);
853 if (FAILED(hr)) {
854 WARN("filter Enumpins failed (%x)\n", hr);
855 return hr;
856 }
857 i = 0;
858 /* Count output pins */
859 while(IEnumPins_Next(penumpins, 1, &ppin, &nb) == S_OK) {
860 PIN_DIRECTION pindir;
861 IPin_QueryDirection(ppin, &pindir);
862 if (pindir == PINDIR_OUTPUT)
863 i++;
864 IPin_Release(ppin);
865 }
866 *pppins = CoTaskMemAlloc(sizeof(IPin*)*i);
867 /* Retrieve output pins */
868 IEnumPins_Reset(penumpins);
869 i = 0;
870 while(IEnumPins_Next(penumpins, 1, &ppin, &nb) == S_OK) {
871 PIN_DIRECTION pindir;
872 IPin_QueryDirection(ppin, &pindir);
873 if (pindir == PINDIR_OUTPUT)
874 (*pppins)[i++] = ppin;
875 else
876 IPin_Release(ppin);
877 }
878 IEnumPins_Release(penumpins);
879 nb = i;
880 if (FAILED(hr)) {
881 WARN("Next failed (%x)\n", hr);
882 return hr;
883 }
884 } else if (FAILED(hr)) {
885 WARN("Cannot get internal connection (%x)\n", hr);
886 return hr;
887 }
888
889 *pnb = nb;
890 return S_OK;
891}
892
893/*** IGraphBuilder methods ***/
894static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *ppinOut, IPin *ppinIn)
895{
897 HRESULT hr;
898 AM_MEDIA_TYPE* mt = NULL;
899 IEnumMediaTypes* penummt = NULL;
900 ULONG nbmt;
901 IEnumPins* penumpins;
902 IEnumMoniker* pEnumMoniker;
903 GUID tab[2];
904 ULONG nb = 0;
905 IMoniker* pMoniker;
906 ULONG pin;
907 PIN_INFO PinInfo;
908 CLSID FilterCLSID;
910 unsigned int i = 0;
911 IFilterMapper2 *pFilterMapper2 = NULL;
912
913 TRACE("(%p/%p)->(%p, %p)\n", This, iface, ppinOut, ppinIn);
914
915 if(!ppinOut || !ppinIn)
916 return E_POINTER;
917
918 if (TRACE_ON(quartz))
919 {
920 hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
921 if (FAILED(hr))
922 return hr;
923
924 TRACE("Filter owning ppinIn(%p) => %p\n", ppinIn, PinInfo.pFilter);
925 IBaseFilter_Release(PinInfo.pFilter);
926
927 hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
928 if (FAILED(hr))
929 return hr;
930
931 TRACE("Filter owning ppinOut(%p) => %p\n", ppinOut, PinInfo.pFilter);
932 IBaseFilter_Release(PinInfo.pFilter);
933 }
934
936 ++This->recursioncount;
937 if (This->recursioncount >= 5)
938 {
939 WARN("Recursion count has reached %d\n", This->recursioncount);
941 goto out;
942 }
943
944 hr = IPin_QueryDirection(ppinOut, &dir);
945 if (FAILED(hr))
946 goto out;
947
948 if (dir == PINDIR_INPUT)
949 {
950 IPin *temp;
951
952 TRACE("Directions seem backwards, swapping pins\n");
953
954 temp = ppinIn;
955 ppinIn = ppinOut;
956 ppinOut = temp;
957 }
958
959 hr = CheckCircularConnection(This, ppinOut, ppinIn);
960 if (FAILED(hr))
961 goto out;
962
963 /* Try direct connection first */
964 hr = IPin_Connect(ppinOut, ppinIn, NULL);
965 if (SUCCEEDED(hr))
966 goto out;
967
968 TRACE("Direct connection failed, trying to render using extra filters\n");
969
970 hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
971 if (FAILED(hr))
972 goto out;
973
974 hr = IBaseFilter_GetClassID(PinInfo.pFilter, &FilterCLSID);
975 IBaseFilter_Release(PinInfo.pFilter);
976 if (FAILED(hr))
977 goto out;
978
979 /* Find the appropriate transform filter than can transform the minor media type of output pin of the upstream
980 * filter to the minor mediatype of input pin of the renderer */
981 hr = IPin_EnumMediaTypes(ppinOut, &penummt);
982 if (FAILED(hr))
983 {
984 WARN("EnumMediaTypes (%x)\n", hr);
985 goto out;
986 }
987
988 hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
989 if (FAILED(hr)) {
990 WARN("IEnumMediaTypes_Next (%x)\n", hr);
991 goto out;
992 }
993
994 if (!nbmt)
995 {
996 WARN("No media type found!\n");
998 goto out;
999 }
1000 TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
1001 TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
1002
1003 hr = IUnknown_QueryInterface(This->punkFilterMapper2, &IID_IFilterMapper2, (void**)&pFilterMapper2);
1004 if (FAILED(hr)) {
1005 WARN("Unable to get IFilterMapper2 (%x)\n", hr);
1006 goto out;
1007 }
1008
1009 /* Try to find a suitable filter that can connect to the pin to render */
1010 tab[0] = mt->majortype;
1011 tab[1] = mt->subtype;
1012 hr = IFilterMapper2_EnumMatchingFilters(pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
1013 if (FAILED(hr)) {
1014 WARN("Unable to enum filters (%x)\n", hr);
1015 goto out;
1016 }
1017
1019 while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
1020 {
1021 VARIANT var;
1022 GUID clsid;
1023 IPin** ppins = NULL;
1024 IPin* ppinfilter = NULL;
1025 IBaseFilter* pfilter = NULL;
1027
1028 hr = GetFilterInfo(pMoniker, &var);
1029 if (FAILED(hr)) {
1030 WARN("Unable to retrieve filter info (%x)\n", hr);
1031 goto error;
1032 }
1033
1034 hr = IMoniker_BindToObject(pMoniker, NULL, NULL, &IID_IBaseFilter, (LPVOID*)&pfilter);
1035 IMoniker_Release(pMoniker);
1036 if (FAILED(hr)) {
1037 WARN("Unable to create filter (%x), trying next one\n", hr);
1038 goto error;
1039 }
1040
1041 hr = IBaseFilter_GetClassID(pfilter, &clsid);
1042 if (FAILED(hr))
1043 {
1044 IBaseFilter_Release(pfilter);
1045 goto error;
1046 }
1047
1048 if (IsEqualGUID(&clsid, &FilterCLSID)) {
1049 /* Skip filter (same as the one the output pin belongs to) */
1050 IBaseFilter_Release(pfilter);
1051 pfilter = NULL;
1052 goto error;
1053 }
1054
1055 if (This->pSite)
1056 {
1057 IUnknown_QueryInterface(This->pSite, &IID_IAMGraphBuilderCallback, (LPVOID*)&callback);
1058 if (callback)
1059 {
1060 HRESULT rc;
1061 rc = IAMGraphBuilderCallback_SelectedFilter(callback, pMoniker);
1062 if (FAILED(rc))
1063 {
1064 TRACE("Filter rejected by IAMGraphBuilderCallback_SelectedFilter\n");
1065 IAMGraphBuilderCallback_Release(callback);
1066 goto error;
1067 }
1068 }
1069 }
1070
1071 if (callback)
1072 {
1073 HRESULT rc;
1074 rc = IAMGraphBuilderCallback_CreatedFilter(callback, pfilter);
1075 IAMGraphBuilderCallback_Release(callback);
1076 if (FAILED(rc))
1077 {
1078 IBaseFilter_Release(pfilter);
1079 pfilter = NULL;
1080 TRACE("Filter rejected by IAMGraphBuilderCallback_CreatedFilter\n");
1081 goto error;
1082 }
1083 }
1084
1085 hr = IFilterGraph2_AddFilter(iface, pfilter, V_BSTR(&var));
1086 if (FAILED(hr)) {
1087 WARN("Unable to add filter (%x)\n", hr);
1088 IBaseFilter_Release(pfilter);
1089 pfilter = NULL;
1090 goto error;
1091 }
1092
1093 VariantClear(&var);
1094
1095 hr = IBaseFilter_EnumPins(pfilter, &penumpins);
1096 if (FAILED(hr)) {
1097 WARN("Enumpins (%x)\n", hr);
1098 goto error;
1099 }
1100
1101 hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin);
1102 IEnumPins_Release(penumpins);
1103
1104 if (FAILED(hr)) {
1105 WARN("Obtaining next pin: (%x)\n", hr);
1106 goto error;
1107 }
1108 if (pin == 0) {
1109 WARN("Cannot use this filter: no pins\n");
1110 goto error;
1111 }
1112
1113 hr = IPin_Connect(ppinOut, ppinfilter, NULL);
1114 if (FAILED(hr)) {
1115 TRACE("Cannot connect to filter (%x), trying next one\n", hr);
1116 goto error;
1117 }
1118 TRACE("Successfully connected to filter, follow chain...\n");
1119
1120 /* Render all output pins of the filter by calling IFilterGraph2_Connect on each of them */
1121 hr = GetInternalConnections(pfilter, ppinfilter, &ppins, &nb);
1122
1123 if (SUCCEEDED(hr)) {
1124 if (nb == 0) {
1125 IPin_Disconnect(ppinfilter);
1126 IPin_Disconnect(ppinOut);
1127 goto error;
1128 }
1129 TRACE("pins to consider: %d\n", nb);
1130 for(i = 0; i < nb; i++)
1131 {
1132 LPWSTR pinname = NULL;
1133
1134 TRACE("Processing pin %u\n", i);
1135
1136 hr = IPin_QueryId(ppins[i], &pinname);
1137 if (SUCCEEDED(hr))
1138 {
1139 if (pinname[0] == '~')
1140 {
1141 TRACE("Pinname=%s, skipping\n", debugstr_w(pinname));
1142 hr = E_FAIL;
1143 }
1144 else
1145 hr = IFilterGraph2_Connect(iface, ppins[i], ppinIn);
1146 CoTaskMemFree(pinname);
1147 }
1148
1149 if (FAILED(hr)) {
1150 TRACE("Cannot connect pin %p (%x)\n", ppinfilter, hr);
1151 }
1152 IPin_Release(ppins[i]);
1153 if (SUCCEEDED(hr)) break;
1154 }
1155 while (++i < nb) IPin_Release(ppins[i]);
1156 CoTaskMemFree(ppins);
1157 IPin_Release(ppinfilter);
1158 IBaseFilter_Release(pfilter);
1159 if (FAILED(hr))
1160 {
1161 IPin_Disconnect(ppinfilter);
1162 IPin_Disconnect(ppinOut);
1163 IFilterGraph2_RemoveFilter(iface, pfilter);
1164 continue;
1165 }
1166 break;
1167 }
1168
1169error:
1170 VariantClear(&var);
1171 if (ppinfilter) IPin_Release(ppinfilter);
1172 if (pfilter) {
1173 IFilterGraph2_RemoveFilter(iface, pfilter);
1174 IBaseFilter_Release(pfilter);
1175 }
1176 while (++i < nb) IPin_Release(ppins[i]);
1177 CoTaskMemFree(ppins);
1178 }
1179
1180 IEnumMoniker_Release(pEnumMoniker);
1181
1182out:
1183 if (pFilterMapper2)
1184 IFilterMapper2_Release(pFilterMapper2);
1185 if (penummt)
1186 IEnumMediaTypes_Release(penummt);
1187 if (mt)
1188 DeleteMediaType(mt);
1189 --This->recursioncount;
1191 TRACE("--> %08x\n", hr);
1192 return SUCCEEDED(hr) ? S_OK : hr;
1193}
1194
1196{
1197 /* This pin has been connected now, try to call render on all pins that aren't connected */
1198 IPin *to = NULL;
1199 PIN_INFO info;
1200 IEnumPins *enumpins = NULL;
1201 BOOL renderany = FALSE;
1202 BOOL renderall = TRUE;
1203
1204 IPin_QueryPinInfo(ppinOut, &info);
1205
1206 IBaseFilter_EnumPins(info.pFilter, &enumpins);
1207 /* Don't need to hold a reference, IEnumPins does */
1208 IBaseFilter_Release(info.pFilter);
1209
1210 IEnumPins_Reset(enumpins);
1211 while (IEnumPins_Next(enumpins, 1, &to, NULL) == S_OK)
1212 {
1214
1215 IPin_QueryDirection(to, &dir);
1216
1217 if (dir == PINDIR_OUTPUT)
1218 {
1219 IPin *out = NULL;
1220
1221 IPin_ConnectedTo(to, &out);
1222 if (!out)
1223 {
1224 HRESULT hr;
1225 hr = IFilterGraph2_Render(&This->IFilterGraph2_iface, to);
1226 if (SUCCEEDED(hr))
1227 renderany = TRUE;
1228 else
1229 renderall = FALSE;
1230 }
1231 else
1232 IPin_Release(out);
1233 }
1234
1235 IPin_Release(to);
1236 }
1237
1238 IEnumPins_Release(enumpins);
1239
1240 if (renderall)
1241 return S_OK;
1242
1243 if (renderany)
1244 return VFW_S_PARTIAL_RENDER;
1245
1246 return VFW_E_CANNOT_RENDER;
1247}
1248
1249/* Ogg hates me if I create a direct rendering method
1250 *
1251 * It can only connect to a pin properly once, so use a recursive method that does
1252 *
1253 * +----+ --- (PIN 1) (Render is called on this pin)
1254 * | |
1255 * +----+ --- (PIN 2)
1256 *
1257 * Enumerate possible renderers that EXACTLY match the requested type
1258 *
1259 * If none is available, try to add intermediate filters that can connect to the input pin
1260 * then call Render on that intermediate pin's output pins
1261 * if it succeeds: Render returns success, if it doesn't, the intermediate filter is removed,
1262 * and another filter that can connect to the input pin is tried
1263 * if we run out of filters that can, give up and return VFW_E_CANNOT_RENDER
1264 * It's recursive, but fun!
1265 */
1266
1268{
1270 IEnumMediaTypes* penummt;
1271 AM_MEDIA_TYPE* mt;
1272 ULONG nbmt;
1273 HRESULT hr;
1274
1275 IEnumMoniker* pEnumMoniker;
1276 GUID tab[4];
1277 ULONG nb;
1278 IMoniker* pMoniker;
1279 INT x;
1280 IFilterMapper2 *pFilterMapper2 = NULL;
1281
1282 TRACE("(%p/%p)->(%p)\n", This, iface, ppinOut);
1283
1284 if (TRACE_ON(quartz))
1285 {
1286 PIN_INFO PinInfo;
1287
1288 hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
1289 if (FAILED(hr))
1290 return hr;
1291
1292 TRACE("Filter owning pin => %p\n", PinInfo.pFilter);
1293 IBaseFilter_Release(PinInfo.pFilter);
1294 }
1295
1296 /* Try to find out if there is a renderer for the specified subtype already, and use that
1297 */
1299 for (x = 0; x < This->nFilters; ++x)
1300 {
1301 IEnumPins *enumpins = NULL;
1302 IPin *pin = NULL;
1303
1304 hr = IBaseFilter_EnumPins(This->ppFiltersInGraph[x], &enumpins);
1305
1306 if (FAILED(hr) || !enumpins)
1307 continue;
1308
1309 IEnumPins_Reset(enumpins);
1310 while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
1311 {
1312 IPin *to = NULL;
1314
1315 IPin_QueryDirection(pin, &dir);
1316 if (dir != PINDIR_INPUT)
1317 {
1318 IPin_Release(pin);
1319 continue;
1320 }
1321 IPin_ConnectedTo(pin, &to);
1322
1323 if (to == NULL)
1324 {
1325 hr = FilterGraph2_ConnectDirect(iface, ppinOut, pin, NULL);
1326 if (SUCCEEDED(hr))
1327 {
1328 TRACE("Connected successfully %p/%p, %08x look if we should render more!\n", ppinOut, pin, hr);
1329 IPin_Release(pin);
1330
1332 if (FAILED(hr))
1333 {
1334 IPin_Disconnect(ppinOut);
1335 IPin_Disconnect(pin);
1336 continue;
1337 }
1338 IEnumPins_Release(enumpins);
1340 return hr;
1341 }
1342 WARN("Could not connect!\n");
1343 }
1344 else
1345 IPin_Release(to);
1346
1347 IPin_Release(pin);
1348 }
1349 IEnumPins_Release(enumpins);
1350 }
1351
1353
1354 hr = IPin_EnumMediaTypes(ppinOut, &penummt);
1355 if (FAILED(hr)) {
1356 WARN("EnumMediaTypes (%x)\n", hr);
1357 return hr;
1358 }
1359
1360 IEnumMediaTypes_Reset(penummt);
1361
1362 /* Looks like no existing renderer of the kind exists
1363 * Try adding new ones
1364 */
1365 tab[0] = tab[1] = GUID_NULL;
1366 while (SUCCEEDED(hr))
1367 {
1368 hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
1369 if (FAILED(hr)) {
1370 WARN("IEnumMediaTypes_Next (%x)\n", hr);
1371 break;
1372 }
1373 if (!nbmt)
1374 {
1376 break;
1377 }
1378 else
1379 {
1380 TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
1381 TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
1382
1383 /* Only enumerate once, this doesn't account for all previous ones, but this should be enough nonetheless */
1384 if (IsEqualIID(&tab[0], &mt->majortype) && IsEqualIID(&tab[1], &mt->subtype))
1385 {
1386 DeleteMediaType(mt);
1387 continue;
1388 }
1389
1390 if (pFilterMapper2 == NULL)
1391 {
1392 hr = IUnknown_QueryInterface(This->punkFilterMapper2, &IID_IFilterMapper2, (void**)&pFilterMapper2);
1393 if (FAILED(hr))
1394 {
1395 WARN("Unable to query IFilterMapper2 (%x)\n", hr);
1396 break;
1397 }
1398 }
1399
1400 /* Try to find a suitable renderer with the same media type */
1401 tab[0] = mt->majortype;
1402 tab[1] = mt->subtype;
1403 hr = IFilterMapper2_EnumMatchingFilters(pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
1404 if (FAILED(hr))
1405 {
1406 WARN("Unable to enum filters (%x)\n", hr);
1407 break;
1408 }
1409 }
1410 hr = E_FAIL;
1411
1412 while (IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
1413 {
1414 VARIANT var;
1415 IPin* ppinfilter;
1416 IBaseFilter* pfilter = NULL;
1417 IEnumPins* penumpins = NULL;
1418 ULONG pin;
1419
1420 hr = GetFilterInfo(pMoniker, &var);
1421 if (FAILED(hr)) {
1422 WARN("Unable to retrieve filter info (%x)\n", hr);
1423 goto error;
1424 }
1425
1426 hr = IMoniker_BindToObject(pMoniker, NULL, NULL, &IID_IBaseFilter, (LPVOID*)&pfilter);
1427 IMoniker_Release(pMoniker);
1428 if (FAILED(hr))
1429 {
1430 WARN("Unable to create filter (%x), trying next one\n", hr);
1431 goto error;
1432 }
1433
1434 hr = IFilterGraph2_AddFilter(iface, pfilter, V_BSTR(&var));
1435 if (FAILED(hr)) {
1436 WARN("Unable to add filter (%x)\n", hr);
1437 IBaseFilter_Release(pfilter);
1438 pfilter = NULL;
1439 goto error;
1440 }
1441
1442 hr = IBaseFilter_EnumPins(pfilter, &penumpins);
1443 if (FAILED(hr)) {
1444 WARN("Splitter Enumpins (%x)\n", hr);
1445 goto error;
1446 }
1447
1448 while ((hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin)) == S_OK)
1449 {
1451
1452 if (pin == 0) {
1453 WARN("No Pin\n");
1454 hr = E_FAIL;
1455 goto error;
1456 }
1457
1458 hr = IPin_QueryDirection(ppinfilter, &dir);
1459 if (FAILED(hr)) {
1460 IPin_Release(ppinfilter);
1461 WARN("QueryDirection failed (%x)\n", hr);
1462 goto error;
1463 }
1464 if (dir != PINDIR_INPUT) {
1465 IPin_Release(ppinfilter);
1466 continue; /* Wrong direction */
1467 }
1468
1469 /* Connect the pin to the "Renderer" */
1470 hr = IPin_Connect(ppinOut, ppinfilter, NULL);
1471 IPin_Release(ppinfilter);
1472
1473 if (FAILED(hr)) {
1474 WARN("Unable to connect %s to renderer (%x)\n", debugstr_w(V_BSTR(&var)), hr);
1475 goto error;
1476 }
1477 TRACE("Connected, recursing %s\n", debugstr_w(V_BSTR(&var)));
1478
1479 VariantClear(&var);
1480
1481 hr = FilterGraph2_RenderRecurse(This, ppinfilter);
1482 if (FAILED(hr)) {
1483 WARN("Unable to connect recursively (%x)\n", hr);
1484 goto error;
1485 }
1486 IBaseFilter_Release(pfilter);
1487 break;
1488 }
1489 if (SUCCEEDED(hr)) {
1490 IEnumPins_Release(penumpins);
1491 break; /* out of IEnumMoniker_Next loop */
1492 }
1493
1494 /* IEnumPins_Next failed, all other failure case caught by goto error */
1495 WARN("IEnumPins_Next (%x)\n", hr);
1496 /* goto error */
1497
1498error:
1499 VariantClear(&var);
1500 if (penumpins)
1501 IEnumPins_Release(penumpins);
1502 if (pfilter) {
1503 IFilterGraph2_RemoveFilter(iface, pfilter);
1504 IBaseFilter_Release(pfilter);
1505 }
1506 if (SUCCEEDED(hr)) DebugBreak();
1507 }
1508
1509 IEnumMoniker_Release(pEnumMoniker);
1510 if (nbmt)
1511 DeleteMediaType(mt);
1512 if (SUCCEEDED(hr))
1513 break;
1514 hr = S_OK;
1515 }
1516
1517 if (pFilterMapper2)
1518 IFilterMapper2_Release(pFilterMapper2);
1519
1520 IEnumMediaTypes_Release(penummt);
1521 return hr;
1522}
1523
1525 LPCWSTR lpcwstrPlayList)
1526{
1528 static const WCHAR string[] = {'R','e','a','d','e','r',0};
1529 IBaseFilter* preader = NULL;
1530 IPin* ppinreader = NULL;
1531 IEnumPins* penumpins = NULL;
1532 HRESULT hr;
1533 BOOL partial = FALSE;
1534 BOOL any = FALSE;
1535
1536 TRACE("(%p/%p)->(%s, %s)\n", This, iface, debugstr_w(lpcwstrFile), debugstr_w(lpcwstrPlayList));
1537
1538 if (lpcwstrPlayList != NULL)
1539 return E_INVALIDARG;
1540
1541 hr = IFilterGraph2_AddSourceFilter(iface, lpcwstrFile, string, &preader);
1542 if (FAILED(hr))
1543 return hr;
1544
1545 hr = IBaseFilter_EnumPins(preader, &penumpins);
1546 if (SUCCEEDED(hr))
1547 {
1548 while (IEnumPins_Next(penumpins, 1, &ppinreader, NULL) == S_OK)
1549 {
1551
1552 IPin_QueryDirection(ppinreader, &dir);
1553 if (dir == PINDIR_OUTPUT)
1554 {
1555 INT i;
1556
1557 hr = IFilterGraph2_Render(iface, ppinreader);
1558 TRACE("Render %08x\n", hr);
1559
1560 for (i = 0; i < This->nFilters; ++i)
1561 TRACE("Filters in chain: %s\n", debugstr_w(This->pFilterNames[i]));
1562
1563 if (SUCCEEDED(hr))
1564 any = TRUE;
1565 if (hr != S_OK)
1566 partial = TRUE;
1567 }
1568 IPin_Release(ppinreader);
1569 }
1570 IEnumPins_Release(penumpins);
1571
1572 if (!any)
1574 else if (partial)
1576 else
1577 hr = S_OK;
1578 }
1579 IBaseFilter_Release(preader);
1580
1581 TRACE("--> %08x\n", hr);
1582 return hr;
1583}
1584
1586{
1588 HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)filter);
1589 TRACE("CLSID: %s\n", debugstr_guid(clsid));
1590 if (FAILED(hr))
1591 return hr;
1592
1593 hr = IBaseFilter_QueryInterface(*filter, &IID_IFileSourceFilter, (LPVOID*)&source);
1594 if (FAILED(hr))
1595 {
1596 IBaseFilter_Release(*filter);
1597 return hr;
1598 }
1599
1600 /* Load the file in the file source filter */
1601 hr = IFileSourceFilter_Load(source, pszFileName, NULL);
1602 IFileSourceFilter_Release(source);
1603 if (FAILED(hr)) {
1604 WARN("Load (%x)\n", hr);
1605 IBaseFilter_Release(*filter);
1606 return hr;
1607 }
1608
1609 return hr;
1610}
1611
1612/* Some filters implement their own asynchronous reader (Theoretically they all should, try to load it first */
1614{
1615 HRESULT hr;
1616 GUID clsid;
1617 IAsyncReader * pReader = NULL;
1618 IFileSourceFilter* pSource = NULL;
1619 IPin * pOutputPin = NULL;
1620 static const WCHAR wszOutputPinName[] = { 'O','u','t','p','u','t',0 };
1621
1622 /* Try to find a match without reading the file first */
1624
1625 if (hr == S_OK)
1627
1628 /* Now create a AyncReader instance, to check for signature bytes in the file */
1629 hr = CoCreateInstance(&CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)filter);
1630 if (FAILED(hr))
1631 return hr;
1632
1633 hr = IBaseFilter_QueryInterface(*filter, &IID_IFileSourceFilter, (LPVOID *)&pSource);
1634 if (FAILED(hr))
1635 {
1636 IBaseFilter_Release(*filter);
1637 return hr;
1638 }
1639
1640 hr = IFileSourceFilter_Load(pSource, pszFileName, NULL);
1641 IFileSourceFilter_Release(pSource);
1642 if (FAILED(hr))
1643 {
1644 IBaseFilter_Release(*filter);
1645 return hr;
1646 }
1647
1648 hr = IBaseFilter_FindPin(*filter, wszOutputPinName, &pOutputPin);
1649 if (FAILED(hr))
1650 {
1651 IBaseFilter_Release(*filter);
1652 return hr;
1653 }
1654
1655 hr = IPin_QueryInterface(pOutputPin, &IID_IAsyncReader, (LPVOID *)&pReader);
1656 IPin_Release(pOutputPin);
1657 if (FAILED(hr))
1658 {
1659 IBaseFilter_Release(*filter);
1660 return hr;
1661 }
1662
1663 /* Try again find a match */
1665 IAsyncReader_Release(pReader);
1666
1667 if (hr == S_OK)
1668 {
1669 /* Release the AsyncReader filter and create the matching one */
1670 IBaseFilter_Release(*filter);
1672 }
1673
1674 /* Return the AsyncReader filter */
1675 return S_OK;
1676}
1677
1679 LPCWSTR lpcwstrFilterName, IBaseFilter **ppFilter)
1680{
1682 HRESULT hr;
1683 IBaseFilter* preader;
1684 IFileSourceFilter* pfile = NULL;
1685 AM_MEDIA_TYPE mt;
1686 WCHAR* filename;
1687
1688 TRACE("(%p/%p)->(%s, %s, %p)\n", This, iface, debugstr_w(lpcwstrFileName), debugstr_w(lpcwstrFilterName), ppFilter);
1689
1690 /* Try from file name first, then fall back to default asynchronous reader */
1691 hr = GetFileSourceFilter(lpcwstrFileName, &preader);
1692 if (FAILED(hr)) {
1693 WARN("Unable to create file source filter (%x)\n", hr);
1694 return hr;
1695 }
1696
1697 hr = IFilterGraph2_AddFilter(iface, preader, lpcwstrFilterName);
1698 if (FAILED(hr)) {
1699 WARN("Unable add filter (%x)\n", hr);
1700 IBaseFilter_Release(preader);
1701 return hr;
1702 }
1703
1704 hr = IBaseFilter_QueryInterface(preader, &IID_IFileSourceFilter, (LPVOID*)&pfile);
1705 if (FAILED(hr)) {
1706 WARN("Unable to get IFileSourceInterface (%x)\n", hr);
1707 goto error;
1708 }
1709
1710 /* The file has been already loaded */
1711 hr = IFileSourceFilter_GetCurFile(pfile, &filename, &mt);
1712 if (FAILED(hr)) {
1713 WARN("GetCurFile (%x)\n", hr);
1714 goto error;
1715 }
1716
1717 TRACE("File %s\n", debugstr_w(filename));
1718 TRACE("MajorType %s\n", debugstr_guid(&mt.majortype));
1719 TRACE("SubType %s\n", debugstr_guid(&mt.subtype));
1720
1721 if (ppFilter)
1722 *ppFilter = preader;
1723 IFileSourceFilter_Release(pfile);
1724
1725 return S_OK;
1726
1727error:
1728 if (pfile)
1729 IFileSourceFilter_Release(pfile);
1730 IFilterGraph2_RemoveFilter(iface, preader);
1731 IBaseFilter_Release(preader);
1732
1733 return hr;
1734}
1735
1737{
1739
1740 TRACE("(%p/%p)->(%08x): stub !!!\n", This, iface, (DWORD) hFile);
1741
1742 return S_OK;
1743}
1744
1746{
1748
1749 TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1750
1751 return S_OK;
1752}
1753
1755{
1757
1758 TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1759
1760 return S_OK;
1761}
1762
1763/*** IFilterGraph2 methods ***/
1765 IMoniker *pMoniker, IBindCtx *pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter **ppFilter)
1766{
1768 HRESULT hr;
1769 IBaseFilter* pfilter;
1770
1771 TRACE("(%p/%p)->(%p %p %s %p)\n", This, iface, pMoniker, pCtx, debugstr_w(lpcwstrFilterName), ppFilter);
1772
1773 hr = IMoniker_BindToObject(pMoniker, pCtx, NULL, &IID_IBaseFilter, (void**)&pfilter);
1774 if(FAILED(hr)) {
1775 WARN("Unable to bind moniker to filter object (%x)\n", hr);
1776 return hr;
1777 }
1778
1779 hr = IFilterGraph2_AddFilter(iface, pfilter, lpcwstrFilterName);
1780 if (FAILED(hr)) {
1781 WARN("Unable to add filter (%x)\n", hr);
1782 IBaseFilter_Release(pfilter);
1783 return hr;
1784 }
1785
1786 if(ppFilter)
1787 *ppFilter = pfilter;
1788 else IBaseFilter_Release(pfilter);
1789
1790 return S_OK;
1791}
1792
1794 const AM_MEDIA_TYPE *pmt)
1795{
1797
1798 TRACE("(%p/%p)->(%p %p): stub !!!\n", This, iface, ppin, pmt);
1799
1800 return S_OK;
1801}
1802
1804 DWORD *pvContext)
1805{
1807
1808 TRACE("(%p/%p)->(%p %08x %p): stub !!!\n", This, iface, pPinOut, dwFlags, pvContext);
1809
1810 return S_OK;
1811}
1812
1813
1814static const IFilterGraph2Vtbl IFilterGraph2_VTable =
1815{
1837};
1838
1839static inline IFilterGraphImpl *impl_from_IMediaControl(IMediaControl *iface)
1840{
1841 return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaControl_iface);
1842}
1843
1844static HRESULT WINAPI MediaControl_QueryInterface(IMediaControl *iface, REFIID riid, void **ppvObj)
1845{
1847
1848 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj);
1849
1850 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
1851}
1852
1853static ULONG WINAPI MediaControl_AddRef(IMediaControl *iface)
1854{
1856
1857 TRACE("(%p/%p)->()\n", This, iface);
1858
1859 return IUnknown_AddRef(This->outer_unk);
1860}
1861
1862static ULONG WINAPI MediaControl_Release(IMediaControl *iface)
1863{
1865
1866 TRACE("(%p/%p)->()\n", This, iface);
1867
1868 return IUnknown_Release(This->outer_unk);
1869
1870}
1871
1872/*** IDispatch methods ***/
1873static HRESULT WINAPI MediaControl_GetTypeInfoCount(IMediaControl *iface, UINT *pctinfo)
1874{
1876
1877 TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1878
1879 return S_OK;
1880}
1881
1882static HRESULT WINAPI MediaControl_GetTypeInfo(IMediaControl *iface, UINT iTInfo, LCID lcid,
1883 ITypeInfo **ppTInfo)
1884{
1886
1887 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1888
1889 return S_OK;
1890}
1891
1893 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1894{
1896
1897 TRACE("(%p/%p)->(%s, %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), rgszNames,
1898 cNames, lcid, rgDispId);
1899
1900 return S_OK;
1901}
1902
1903static HRESULT WINAPI MediaControl_Invoke(IMediaControl *iface, DISPID dispIdMember, REFIID riid,
1904 LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
1905 UINT *puArgErr)
1906{
1908
1909 TRACE("(%p/%p)->(%d, %s, %d, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember,
1910 debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
1911
1912 return S_OK;
1913}
1914
1916
1917static HRESULT ExploreGraph(IFilterGraphImpl* pGraph, IPin* pOutputPin, fnFoundFilter FoundFilter, DWORD_PTR data)
1918{
1919 HRESULT hr;
1920 IPin* pInputPin;
1921 IPin** ppPins;
1922 ULONG nb;
1923 ULONG i;
1924 PIN_INFO PinInfo;
1925
1926 TRACE("%p %p\n", pGraph, pOutputPin);
1927 PinInfo.pFilter = NULL;
1928
1929 hr = IPin_ConnectedTo(pOutputPin, &pInputPin);
1930
1931 if (SUCCEEDED(hr))
1932 {
1933 hr = IPin_QueryPinInfo(pInputPin, &PinInfo);
1934 if (SUCCEEDED(hr))
1935 hr = GetInternalConnections(PinInfo.pFilter, pInputPin, &ppPins, &nb);
1936 IPin_Release(pInputPin);
1937 }
1938
1939 if (SUCCEEDED(hr))
1940 {
1941 if (nb == 0)
1942 {
1943 TRACE("Reached a renderer\n");
1944 /* Count renderers for end of stream notification */
1945 pGraph->nRenderers++;
1946 }
1947 else
1948 {
1949 for(i = 0; i < nb; i++)
1950 {
1951 /* Explore the graph downstream from this pin
1952 * FIXME: We should prevent exploring from a pin more than once. This can happens when
1953 * several input pins are connected to the same output (a MUX for instance). */
1954 ExploreGraph(pGraph, ppPins[i], FoundFilter, data);
1955 IPin_Release(ppPins[i]);
1956 }
1957
1958 CoTaskMemFree(ppPins);
1959 }
1960 TRACE("Doing stuff with filter %p\n", PinInfo.pFilter);
1961
1962 FoundFilter(PinInfo.pFilter, data);
1963 }
1964
1965 if (PinInfo.pFilter) IBaseFilter_Release(PinInfo.pFilter);
1966 return hr;
1967}
1968
1970{
1972 return IBaseFilter_Run(pFilter, time);
1973}
1974
1976{
1977 return IBaseFilter_Pause(pFilter);
1978}
1979
1981{
1982 return IBaseFilter_Stop(pFilter);
1983}
1984
1986{
1987 FILTER_STATE state;
1988 DWORD time_end = data;
1989 DWORD time_now = GetTickCount();
1990 LONG wait;
1991
1992 if (time_end == INFINITE)
1993 {
1994 wait = INFINITE;
1995 }
1996 else if (time_end > time_now)
1997 {
1998 wait = time_end - time_now;
1999 }
2000 else
2001 wait = 0;
2002
2003 return IBaseFilter_GetState(pFilter, wait, &state);
2004}
2005
2006
2008{
2009 int i;
2010 IBaseFilter* pfilter;
2011 IEnumPins* pEnum;
2012 HRESULT hr;
2013 IPin* pPin;
2014 DWORD dummy;
2016
2017 TRACE("(%p)->()\n", This);
2018
2019 /* Explorer the graph from source filters to renderers, determine renderers
2020 * number and run filters from renderers to source filters */
2021 This->nRenderers = 0;
2022 ResetEvent(This->hEventCompletion);
2023
2024 for(i = 0; i < This->nFilters; i++)
2025 {
2026 BOOL source = TRUE;
2027 pfilter = This->ppFiltersInGraph[i];
2028 hr = IBaseFilter_EnumPins(pfilter, &pEnum);
2029 if (hr != S_OK)
2030 {
2031 WARN("Enum pins failed %x\n", hr);
2032 continue;
2033 }
2034 /* Check if it is a source filter */
2035 while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
2036 {
2037 IPin_QueryDirection(pPin, &dir);
2038 IPin_Release(pPin);
2039 if (dir == PINDIR_INPUT)
2040 {
2041 source = FALSE;
2042 break;
2043 }
2044 }
2045 if (source)
2046 {
2047 TRACE("Found a source filter %p\n", pfilter);
2048 IEnumPins_Reset(pEnum);
2049 while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
2050 {
2051 /* Explore the graph downstream from this pin */
2052 ExploreGraph(This, pPin, FoundFilter, data);
2053 IPin_Release(pPin);
2054 }
2055 FoundFilter(pfilter, data);
2056 }
2057 IEnumPins_Release(pEnum);
2058 }
2059
2060 return S_FALSE;
2061}
2062
2063/*** IMediaControl methods ***/
2064static HRESULT WINAPI MediaControl_Run(IMediaControl *iface)
2065{
2067
2068 TRACE("(%p/%p)->()\n", This, iface);
2069
2071 if (This->state == State_Running)
2072 goto out;
2073 This->EcCompleteCount = 0;
2074
2075 if (This->defaultclock && !This->refClock)
2076 IFilterGraph2_SetDefaultSyncSource(&This->IFilterGraph2_iface);
2077
2078 if (This->refClock)
2079 {
2081 IReferenceClock_GetTime(This->refClock, &now);
2082 if (This->state == State_Stopped)
2083 This->start_time = now + 500000;
2084 else if (This->pause_time >= 0)
2085 This->start_time += now - This->pause_time;
2086 else
2087 This->start_time = now;
2088 }
2089 else This->start_time = 0;
2090
2091 SendFilterMessage(This, SendRun, (DWORD_PTR)&This->start_time);
2092 This->state = State_Running;
2093out:
2095 return S_FALSE;
2096}
2097
2098static HRESULT WINAPI MediaControl_Pause(IMediaControl *iface)
2099{
2101
2102 TRACE("(%p/%p)->()\n", This, iface);
2103
2105 if (This->state == State_Paused)
2106 goto out;
2107
2108 if (This->state == State_Running && This->refClock && This->start_time >= 0)
2109 IReferenceClock_GetTime(This->refClock, &This->pause_time);
2110 else
2111 This->pause_time = -1;
2112
2114 This->state = State_Paused;
2115out:
2117 return S_FALSE;
2118}
2119
2120static HRESULT WINAPI MediaControl_Stop(IMediaControl *iface)
2121{
2123
2124 TRACE("(%p/%p)->()\n", This, iface);
2125
2126 if (This->state == State_Stopped) return S_OK;
2127
2129 if (This->state == State_Running) SendFilterMessage(This, SendPause, 0);
2131 This->state = State_Stopped;
2133 return S_OK;
2134}
2135
2136static HRESULT WINAPI MediaControl_GetState(IMediaControl *iface, LONG msTimeout,
2137 OAFilterState *pfs)
2138{
2140 DWORD end;
2141
2142 TRACE("(%p/%p)->(%d, %p)\n", This, iface, msTimeout, pfs);
2143
2144 if (!pfs)
2145 return E_POINTER;
2146
2148
2149 *pfs = This->state;
2150 if (msTimeout > 0)
2151 {
2152 end = GetTickCount() + msTimeout;
2153 }
2154 else if (msTimeout < 0)
2155 {
2156 end = INFINITE;
2157 }
2158 else
2159 {
2160 end = 0;
2161 }
2162 if (end)
2164
2166
2167 return S_OK;
2168}
2169
2170static HRESULT WINAPI MediaControl_RenderFile(IMediaControl *iface, BSTR strFilename)
2171{
2173
2174 TRACE("(%p/%p)->(%s (%p))\n", This, iface, debugstr_w(strFilename), strFilename);
2175
2176 return IFilterGraph2_RenderFile(&This->IFilterGraph2_iface, strFilename, NULL);
2177}
2178
2179static HRESULT WINAPI MediaControl_AddSourceFilter(IMediaControl *iface, BSTR strFilename,
2180 IDispatch **ppUnk)
2181{
2183
2184 FIXME("(%p/%p)->(%s (%p), %p): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename, ppUnk);
2185
2186 return S_OK;
2187}
2188
2189static HRESULT WINAPI MediaControl_get_FilterCollection(IMediaControl *iface, IDispatch **ppUnk)
2190{
2192
2193 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
2194
2195 return S_OK;
2196}
2197
2199{
2201
2202 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
2203
2204 return S_OK;
2205}
2206
2207static HRESULT WINAPI MediaControl_StopWhenReady(IMediaControl *iface)
2208{
2210
2211 FIXME("(%p/%p)->(): stub !!!\n", This, iface);
2212
2213 return S_OK;
2214}
2215
2216
2217static const IMediaControlVtbl IMediaControl_VTable =
2218{
2235};
2236
2238{
2239 return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaSeeking_iface);
2240}
2241
2243{
2245
2246 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj);
2247
2248 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
2249}
2250
2252{
2254
2255 TRACE("(%p/%p)->()\n", This, iface);
2256
2257 return IUnknown_AddRef(This->outer_unk);
2258}
2259
2261{
2263
2264 TRACE("(%p/%p)->()\n", This, iface);
2265
2266 return IUnknown_Release(This->outer_unk);
2267}
2268
2270
2272 BOOL allnotimpl = TRUE;
2273 int i;
2274 HRESULT hr, hr_return = S_OK;
2275
2276 TRACE("(%p)->(%p %08lx)\n", This, FoundSeek, arg);
2277 /* Send a message to all renderers, they are responsible for broadcasting it further */
2278
2279 for(i = 0; i < This->nFilters; i++)
2280 {
2282 IBaseFilter* pfilter = This->ppFiltersInGraph[i];
2284 ULONG filterflags;
2285 IBaseFilter_QueryInterface(pfilter, &IID_IAMFilterMiscFlags, (void**)&flags);
2286 if (!flags)
2287 continue;
2288 filterflags = IAMFilterMiscFlags_GetMiscFlags(flags);
2289 IAMFilterMiscFlags_Release(flags);
2290 if (filterflags != AM_FILTER_MISC_FLAGS_IS_RENDERER)
2291 continue;
2292
2293 IBaseFilter_QueryInterface(pfilter, &IID_IMediaSeeking, (void**)&seek);
2294 if (!seek)
2295 continue;
2296 hr = FoundSeek(This, seek, arg);
2297 IMediaSeeking_Release(seek);
2298 if (hr_return != E_NOTIMPL)
2299 allnotimpl = FALSE;
2300 if (hr_return == S_OK || (FAILED(hr) && hr != E_NOTIMPL && SUCCEEDED(hr_return)))
2301 hr_return = hr;
2302 }
2303
2304 if (allnotimpl)
2305 return E_NOTIMPL;
2306 return hr_return;
2307}
2308
2310{
2311 HRESULT hr;
2312 DWORD caps = 0;
2313
2314 hr = IMediaSeeking_GetCapabilities(seek, &caps);
2315 if (FAILED(hr))
2316 return hr;
2317
2318 /* Only add common capabilities everything supports */
2319 *(DWORD*)pcaps &= caps;
2320
2321 return hr;
2322}
2323
2324/*** IMediaSeeking methods ***/
2326{
2328 HRESULT hr;
2329
2330 TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
2331
2332 if (!pCapabilities)
2333 return E_POINTER;
2334
2336 *pCapabilities = 0xffffffff;
2337
2340
2341 return hr;
2342}
2343
2345{
2347 DWORD originalcaps;
2348 HRESULT hr;
2349
2350 TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
2351
2352 if (!pCapabilities)
2353 return E_POINTER;
2354
2356 originalcaps = *pCapabilities;
2359
2360 if (FAILED(hr))
2361 return hr;
2362
2363 if (!*pCapabilities)
2364 return E_FAIL;
2365 if (*pCapabilities != originalcaps)
2366 return S_FALSE;
2367 return S_OK;
2368}
2369
2371{
2373
2374 if (!pFormat)
2375 return E_POINTER;
2376
2377 TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
2378
2379 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
2380 {
2381 WARN("Unhandled time format %s\n", debugstr_guid(pFormat));
2382 return S_FALSE;
2383 }
2384
2385 return S_OK;
2386}
2387
2389{
2391
2392 if (!pFormat)
2393 return E_POINTER;
2394
2395 FIXME("(%p/%p)->(%p): semi-stub !!!\n", This, iface, pFormat);
2396 memcpy(pFormat, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID));
2397
2398 return S_OK;
2399}
2400
2402{
2404
2405 if (!pFormat)
2406 return E_POINTER;
2407
2408 TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
2409 memcpy(pFormat, &This->timeformatseek, sizeof(GUID));
2410
2411 return S_OK;
2412}
2413
2415{
2417
2418 TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
2419 if (!pFormat)
2420 return E_POINTER;
2421
2422 if (memcmp(pFormat, &This->timeformatseek, sizeof(GUID)))
2423 return S_FALSE;
2424
2425 return S_OK;
2426}
2427
2429{
2431
2432 if (!pFormat)
2433 return E_POINTER;
2434
2435 TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
2436
2437 if (This->state != State_Stopped)
2438 return VFW_E_WRONG_STATE;
2439
2440 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
2441 {
2442 FIXME("Unhandled time format %s\n", debugstr_guid(pFormat));
2443 return E_INVALIDARG;
2444 }
2445
2446 return S_OK;
2447}
2448
2450{
2451 HRESULT hr;
2452 LONGLONG duration = 0, *pdur = (LONGLONG*)pduration;
2453
2454 hr = IMediaSeeking_GetDuration(seek, &duration);
2455 if (FAILED(hr))
2456 return hr;
2457
2458 if (*pdur < duration)
2459 *pdur = duration;
2460 return hr;
2461}
2462
2464{
2466 HRESULT hr;
2467
2468 TRACE("(%p/%p)->(%p)\n", This, iface, pDuration);
2469
2470 if (!pDuration)
2471 return E_POINTER;
2472
2474 *pDuration = 0;
2477
2478 TRACE("--->%08x\n", hr);
2479 return hr;
2480}
2481
2483 const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat)
2484{
2486
2487 TRACE("(%p/%p)->(%p, %s, 0x%s, %s)\n", This, iface, pTarget,
2488 debugstr_guid(pTargetFormat), wine_dbgstr_longlong(Source), debugstr_guid(pSourceFormat));
2489
2490 if (!pSourceFormat)
2491 pSourceFormat = &This->timeformatseek;
2492
2493 if (!pTargetFormat)
2494 pTargetFormat = &This->timeformatseek;
2495
2496 if (IsEqualGUID(pTargetFormat, pSourceFormat))
2497 *pTarget = Source;
2498 else
2499 FIXME("conversion %s->%s not supported\n", debugstr_guid(pSourceFormat), debugstr_guid(pTargetFormat));
2500
2501 return S_OK;
2502}
2503
2504struct pos_args {
2507};
2508
2510{
2511 struct pos_args *args = (void*)pargs;
2512
2513 return IMediaSeeking_SetPositions(seek, args->current, args->curflags, args->stop, args->stopflags);
2514}
2515
2517 DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags)
2518{
2520 HRESULT hr = S_OK;
2521 FILTER_STATE state;
2522 struct pos_args args;
2523
2524 TRACE("(%p/%p)->(%p, %08x, %p, %08x)\n", This, iface, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
2525
2527 state = This->state;
2528 TRACE("State: %s\n", state == State_Running ? "Running" : (state == State_Paused ? "Paused" : (state == State_Stopped ? "Stopped" : "UNKNOWN")));
2529
2530 if ((dwCurrentFlags & 0x7) != AM_SEEKING_AbsolutePositioning &&
2531 (dwCurrentFlags & 0x7) != AM_SEEKING_NoPositioning)
2532 FIXME("Adjust method %x not handled yet!\n", dwCurrentFlags & 0x7);
2533
2534 if (state == State_Running && !(dwCurrentFlags & AM_SEEKING_NoFlush))
2535 IMediaControl_Pause(&This->IMediaControl_iface);
2536 args.current = pCurrent;
2537 args.stop = pStop;
2538 args.curflags = dwCurrentFlags;
2539 args.stopflags = dwStopFlags;
2541
2542 if ((dwCurrentFlags & 0x7) != AM_SEEKING_NoPositioning)
2543 This->pause_time = This->start_time = -1;
2544 if (state == State_Running && !(dwCurrentFlags & AM_SEEKING_NoFlush))
2545 IMediaControl_Run(&This->IMediaControl_iface);
2547
2548 return hr;
2549}
2550
2552{
2553 struct pos_args *args = (void*)pargs;
2554
2555 return IMediaSeeking_GetPositions(seek, args->current, args->stop);
2556}
2557
2559 LONGLONG *pStop)
2560{
2562 struct pos_args args;
2563 LONGLONG time = 0;
2564 HRESULT hr;
2565
2566 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pCurrent, pStop);
2567
2568 args.current = pCurrent;
2569 args.stop = pStop;
2572 if (This->state == State_Running && This->refClock && This->start_time >= 0)
2573 {
2574 IReferenceClock_GetTime(This->refClock, &time);
2575 if (time)
2576 time -= This->start_time;
2577 }
2578 if (This->pause_time > 0)
2579 time += This->pause_time;
2580 *pCurrent += time;
2582
2583 return hr;
2584}
2585
2587{
2588 LONGLONG time;
2589 HRESULT hr;
2590
2591 if (!pCurrent)
2592 return E_POINTER;
2593
2594 hr = MediaSeeking_GetPositions(iface, pCurrent, &time);
2595
2596 TRACE("Time: %u.%03u\n", (DWORD)(*pCurrent / 10000000), (DWORD)((*pCurrent / 10000)%1000));
2597
2598 return hr;
2599}
2600
2602{
2604 LONGLONG time;
2605 HRESULT hr;
2606
2607 TRACE("(%p/%p)->(%p)\n", This, iface, pStop);
2608
2609 if (!pStop)
2610 return E_POINTER;
2611
2612 hr = MediaSeeking_GetPositions(iface, &time, pStop);
2613
2614 return hr;
2615}
2616
2618 LONGLONG *pLatest)
2619{
2621
2622 FIXME("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pEarliest, pLatest);
2623
2624 return S_OK;
2625}
2626
2628{
2630
2631 FIXME("(%p/%p)->(%f): stub !!!\n", This, iface, dRate);
2632
2633 return S_OK;
2634}
2635
2636static HRESULT WINAPI MediaSeeking_GetRate(IMediaSeeking *iface, double *pdRate)
2637{
2639
2640 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pdRate);
2641
2642 if (!pdRate)
2643 return E_POINTER;
2644
2645 *pdRate = 1.0;
2646
2647 return S_OK;
2648}
2649
2651{
2653
2654 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pllPreroll);
2655
2656 return S_OK;
2657}
2658
2659
2660static const IMediaSeekingVtbl IMediaSeeking_VTable =
2661{
2682};
2683
2684static inline IFilterGraphImpl *impl_from_IMediaPosition(IMediaPosition *iface)
2685{
2686 return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaPosition_iface);
2687}
2688
2689/*** IUnknown methods ***/
2690static HRESULT WINAPI MediaPosition_QueryInterface(IMediaPosition* iface, REFIID riid, void** ppvObj)
2691{
2693
2694 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj);
2695
2696 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
2697}
2698
2699static ULONG WINAPI MediaPosition_AddRef(IMediaPosition *iface)
2700{
2702
2703 TRACE("(%p/%p)->()\n", This, iface);
2704
2705 return IUnknown_AddRef(This->outer_unk);
2706}
2707
2708static ULONG WINAPI MediaPosition_Release(IMediaPosition *iface)
2709{
2711
2712 TRACE("(%p/%p)->()\n", This, iface);
2713
2714 return IUnknown_Release(This->outer_unk);
2715}
2716
2717/*** IDispatch methods ***/
2718static HRESULT WINAPI MediaPosition_GetTypeInfoCount(IMediaPosition *iface, UINT* pctinfo)
2719{
2720 FIXME("(%p) stub!\n", iface);
2721 return E_NOTIMPL;
2722}
2723
2724static HRESULT WINAPI MediaPosition_GetTypeInfo(IMediaPosition *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
2725{
2726 FIXME("(%p) stub!\n", iface);
2727 return E_NOTIMPL;
2728}
2729
2730static HRESULT WINAPI MediaPosition_GetIDsOfNames(IMediaPosition* iface, REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId)
2731{
2732 FIXME("(%p) stub!\n", iface);
2733 return E_NOTIMPL;
2734}
2735
2736static HRESULT WINAPI MediaPosition_Invoke(IMediaPosition* iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
2737{
2738 FIXME("(%p) stub!\n", iface);
2739 return E_NOTIMPL;
2740}
2741
2743{
2744 GUID time_format;
2745 HRESULT hr;
2746
2747 hr = MediaSeeking_GetTimeFormat(seek, &time_format);
2748 if (FAILED(hr))
2749 return hr;
2750 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, &time_format))
2751 {
2752 FIXME("Unsupported time format.\n");
2753 return E_NOTIMPL;
2754 }
2755
2756 *time_out = (LONGLONG) (time_in * 10000000); /* convert from 1 second intervals to 100 ns intervals */
2757 return S_OK;
2758}
2759
2761{
2762 GUID time_format;
2763 HRESULT hr;
2764
2765 hr = MediaSeeking_GetTimeFormat(seek, &time_format);
2766 if (FAILED(hr))
2767 return hr;
2768 if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, &time_format))
2769 {
2770 FIXME("Unsupported time format.\n");
2771 return E_NOTIMPL;
2772 }
2773
2774 *time_out = (REFTIME)time_in / 10000000; /* convert from 100 ns intervals to 1 second intervals */
2775 return S_OK;
2776}
2777
2778/*** IMediaPosition methods ***/
2779static HRESULT WINAPI MediaPosition_get_Duration(IMediaPosition * iface, REFTIME *plength)
2780{
2781 LONGLONG duration;
2783 HRESULT hr = IMediaSeeking_GetDuration(&This->IMediaSeeking_iface, &duration);
2784 if (FAILED(hr))
2785 return hr;
2786 return ConvertToREFTIME(&This->IMediaSeeking_iface, duration, plength);
2787}
2788
2789static HRESULT WINAPI MediaPosition_put_CurrentPosition(IMediaPosition * iface, REFTIME llTime)
2790{
2792 LONGLONG reftime;
2793 HRESULT hr;
2794
2795 hr = ConvertFromREFTIME(&This->IMediaSeeking_iface, llTime, &reftime);
2796 if (FAILED(hr))
2797 return hr;
2798 return IMediaSeeking_SetPositions(&This->IMediaSeeking_iface, &reftime,
2800}
2801
2802static HRESULT WINAPI MediaPosition_get_CurrentPosition(IMediaPosition * iface, REFTIME *pllTime)
2803{
2805 LONGLONG pos;
2806 HRESULT hr;
2807
2808 hr = IMediaSeeking_GetCurrentPosition(&This->IMediaSeeking_iface, &pos);
2809 if (FAILED(hr))
2810 return hr;
2811 return ConvertToREFTIME(&This->IMediaSeeking_iface, pos, pllTime);
2812}
2813
2814static HRESULT WINAPI MediaPosition_get_StopTime(IMediaPosition * iface, REFTIME *pllTime)
2815{
2817 LONGLONG pos;
2818 HRESULT hr = IMediaSeeking_GetStopPosition(&This->IMediaSeeking_iface, &pos);
2819 if (FAILED(hr))
2820 return hr;
2821 return ConvertToREFTIME(&This->IMediaSeeking_iface, pos, pllTime);
2822}
2823
2824static HRESULT WINAPI MediaPosition_put_StopTime(IMediaPosition * iface, REFTIME llTime)
2825{
2827 LONGLONG reftime;
2828 HRESULT hr;
2829
2830 hr = ConvertFromREFTIME(&This->IMediaSeeking_iface, llTime, &reftime);
2831 if (FAILED(hr))
2832 return hr;
2833 return IMediaSeeking_SetPositions(&This->IMediaSeeking_iface, NULL, AM_SEEKING_NoPositioning,
2835}
2836
2837static HRESULT WINAPI MediaPosition_get_PrerollTime(IMediaPosition * iface, REFTIME *pllTime)
2838{
2839 FIXME("(%p)->(%p) stub!\n", iface, pllTime);
2840 return E_NOTIMPL;
2841}
2842
2843static HRESULT WINAPI MediaPosition_put_PrerollTime(IMediaPosition * iface, REFTIME llTime)
2844{
2845 FIXME("(%p)->(%f) stub!\n", iface, llTime);
2846 return E_NOTIMPL;
2847}
2848
2849static HRESULT WINAPI MediaPosition_put_Rate(IMediaPosition * iface, double dRate)
2850{
2852 return IMediaSeeking_SetRate(&This->IMediaSeeking_iface, dRate);
2853}
2854
2855static HRESULT WINAPI MediaPosition_get_Rate(IMediaPosition * iface, double *pdRate)
2856{
2858 return IMediaSeeking_GetRate(&This->IMediaSeeking_iface, pdRate);
2859}
2860
2861static HRESULT WINAPI MediaPosition_CanSeekForward(IMediaPosition * iface, LONG *pCanSeekForward)
2862{
2863 FIXME("(%p)->(%p) stub!\n", iface, pCanSeekForward);
2864 return E_NOTIMPL;
2865}
2866
2867static HRESULT WINAPI MediaPosition_CanSeekBackward(IMediaPosition * iface, LONG *pCanSeekBackward)
2868{
2869 FIXME("(%p)->(%p) stub!\n", iface, pCanSeekBackward);
2870 return E_NOTIMPL;
2871}
2872
2873
2874static const IMediaPositionVtbl IMediaPosition_VTable =
2875{
2894};
2895
2897{
2898 return CONTAINING_RECORD(iface, IFilterGraphImpl, IObjectWithSite_iface);
2899}
2900
2901/*** IUnknown methods ***/
2903{
2905
2906 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj);
2907
2908 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
2909}
2910
2912{
2914
2915 TRACE("(%p/%p)->()\n", This, iface);
2916
2917 return IUnknown_AddRef(This->outer_unk);
2918}
2919
2921{
2923
2924 TRACE("(%p/%p)->()\n", This, iface);
2925
2926 return IUnknown_Release(This->outer_unk);
2927}
2928
2929/*** IObjectWithSite methods ***/
2930
2932{
2934
2935 TRACE("(%p/%p)->()\n", This, iface);
2936 if (This->pSite) IUnknown_Release(This->pSite);
2937 This->pSite = pUnkSite;
2938 IUnknown_AddRef(This->pSite);
2939 return S_OK;
2940}
2941
2943{
2945
2946 TRACE("(%p/%p)->(%s)\n", This, iface,debugstr_guid(riid));
2947
2948 *ppvSite = NULL;
2949 if (!This->pSite)
2950 return E_FAIL;
2951 else
2952 return IUnknown_QueryInterface(This->pSite, riid, ppvSite);
2953}
2954
2955static const IObjectWithSiteVtbl IObjectWithSite_VTable =
2956{
2962};
2963
2965{
2967 int i;
2968 int entry;
2969
2970 /* Check if the interface type is already registered */
2971 for (entry = 0; entry < pGraph->nItfCacheEntries; entry++)
2972 if (riid == pGraph->ItfCacheEntries[entry].riid)
2973 {
2974 if (pGraph->ItfCacheEntries[entry].iface)
2975 {
2976 /* Return the interface if available */
2977 *ppvObj = pGraph->ItfCacheEntries[entry].iface;
2978 return S_OK;
2979 }
2980 break;
2981 }
2982
2984 {
2985 FIXME("Not enough space to store interface in the cache\n");
2986 return E_OUTOFMEMORY;
2987 }
2988
2989 /* Find a filter supporting the requested interface */
2990 for (i = 0; i < pGraph->nFilters; i++)
2991 {
2992 hr = IBaseFilter_QueryInterface(pGraph->ppFiltersInGraph[i], riid, ppvObj);
2993 if (hr == S_OK)
2994 {
2995 pGraph->ItfCacheEntries[entry].riid = riid;
2996 pGraph->ItfCacheEntries[entry].filter = pGraph->ppFiltersInGraph[i];
2997 pGraph->ItfCacheEntries[entry].iface = *ppvObj;
2998 if (entry >= pGraph->nItfCacheEntries)
2999 pGraph->nItfCacheEntries++;
3000 return S_OK;
3001 }
3002 if (hr != E_NOINTERFACE)
3003 return hr;
3004 }
3005
3006 return hr;
3007}
3008
3009static inline IFilterGraphImpl *impl_from_IBasicAudio(IBasicAudio *iface)
3010{
3011 return CONTAINING_RECORD(iface, IFilterGraphImpl, IBasicAudio_iface);
3012}
3013
3014static HRESULT WINAPI BasicAudio_QueryInterface(IBasicAudio *iface, REFIID riid, void **ppvObj)
3015{
3017
3018 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj);
3019
3020 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
3021}
3022
3023static ULONG WINAPI BasicAudio_AddRef(IBasicAudio *iface)
3024{
3026
3027 TRACE("(%p/%p)->()\n", This, iface);
3028
3029 return IUnknown_AddRef(This->outer_unk);
3030}
3031
3032static ULONG WINAPI BasicAudio_Release(IBasicAudio *iface)
3033{
3035
3036 TRACE("(%p/%p)->()\n", This, iface);
3037
3038 return IUnknown_Release(This->outer_unk);
3039}
3040
3041/*** IDispatch methods ***/
3042static HRESULT WINAPI BasicAudio_GetTypeInfoCount(IBasicAudio *iface, UINT *pctinfo)
3043{
3045 IBasicAudio* pBasicAudio;
3046 HRESULT hr;
3047
3048 TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
3049
3051
3052 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3053
3054 if (hr == S_OK)
3055 hr = IBasicAudio_GetTypeInfoCount(pBasicAudio, pctinfo);
3056
3058
3059 return hr;
3060}
3061
3062static HRESULT WINAPI BasicAudio_GetTypeInfo(IBasicAudio *iface, UINT iTInfo, LCID lcid,
3063 ITypeInfo **ppTInfo)
3064{
3066 IBasicAudio* pBasicAudio;
3067 HRESULT hr;
3068
3069 TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
3070
3072
3073 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3074
3075 if (hr == S_OK)
3076 hr = IBasicAudio_GetTypeInfo(pBasicAudio, iTInfo, lcid, ppTInfo);
3077
3079
3080 return hr;
3081}
3082
3083static HRESULT WINAPI BasicAudio_GetIDsOfNames(IBasicAudio *iface, REFIID riid, LPOLESTR *rgszNames,
3084 UINT cNames, LCID lcid, DISPID *rgDispId)
3085{
3087 IBasicAudio* pBasicAudio;
3088 HRESULT hr;
3089
3090 TRACE("(%p/%p)->(%s, %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), rgszNames, cNames,
3091 lcid, rgDispId);
3092
3094
3095 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3096
3097 if (hr == S_OK)
3098 hr = IBasicAudio_GetIDsOfNames(pBasicAudio, riid, rgszNames, cNames, lcid, rgDispId);
3099
3101
3102 return hr;
3103}
3104
3105static HRESULT WINAPI BasicAudio_Invoke(IBasicAudio *iface, DISPID dispIdMember, REFIID riid,
3106 LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
3107 UINT *puArgErr)
3108{
3110 IBasicAudio* pBasicAudio;
3111 HRESULT hr;
3112
3113 TRACE("(%p/%p)->(%d, %s, %d, %04x, %p, %p, %p, %p)\n", This, iface, dispIdMember,
3114 debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
3115
3117
3118 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3119
3120 if (hr == S_OK)
3121 hr = IBasicAudio_Invoke(pBasicAudio, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
3122
3124
3125 return hr;
3126}
3127
3128/*** IBasicAudio methods ***/
3129static HRESULT WINAPI BasicAudio_put_Volume(IBasicAudio *iface, LONG lVolume)
3130{
3132 IBasicAudio* pBasicAudio;
3133 HRESULT hr;
3134
3135 TRACE("(%p/%p)->(%d)\n", This, iface, lVolume);
3136
3138
3139 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3140
3141 if (hr == S_OK)
3142 hr = IBasicAudio_put_Volume(pBasicAudio, lVolume);
3143
3145
3146 return hr;
3147}
3148
3149static HRESULT WINAPI BasicAudio_get_Volume(IBasicAudio *iface, LONG *plVolume)
3150{
3152 IBasicAudio* pBasicAudio;
3153 HRESULT hr;
3154
3155 TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
3156
3158
3159 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3160
3161 if (hr == S_OK)
3162 hr = IBasicAudio_get_Volume(pBasicAudio, plVolume);
3163
3165
3166 return hr;
3167}
3168
3169static HRESULT WINAPI BasicAudio_put_Balance(IBasicAudio *iface, LONG lBalance)
3170{
3172 IBasicAudio* pBasicAudio;
3173 HRESULT hr;
3174
3175 TRACE("(%p/%p)->(%d)\n", This, iface, lBalance);
3176
3178
3179 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3180
3181 if (hr == S_OK)
3182 hr = IBasicAudio_put_Balance(pBasicAudio, lBalance);
3183
3185
3186 return hr;
3187}
3188
3189static HRESULT WINAPI BasicAudio_get_Balance(IBasicAudio *iface, LONG *plBalance)
3190{
3192 IBasicAudio* pBasicAudio;
3193 HRESULT hr;
3194
3195 TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
3196
3198
3199 hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3200
3201 if (hr == S_OK)
3202 hr = IBasicAudio_get_Balance(pBasicAudio, plBalance);
3203
3205
3206 return hr;
3207}
3208
3209static const IBasicAudioVtbl IBasicAudio_VTable =
3210{
3222};
3223
3224static inline IFilterGraphImpl *impl_from_IBasicVideo2(IBasicVideo2 *iface)
3225{
3226 return CONTAINING_RECORD(iface, IFilterGraphImpl, IBasicVideo2_iface);
3227}
3228
3229static HRESULT WINAPI BasicVideo_QueryInterface(IBasicVideo2 *iface, REFIID riid, void **ppvObj)
3230{
3232
3233 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj);
3234
3235 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
3236}
3237
3238static ULONG WINAPI BasicVideo_AddRef(IBasicVideo2 *iface)
3239{
3241
3242 TRACE("(%p/%p)->()\n", This, iface);
3243
3244 return IUnknown_AddRef(This->outer_unk);
3245}
3246
3247static ULONG WINAPI BasicVideo_Release(IBasicVideo2 *iface)
3248{
3250
3251 TRACE("(%p/%p)->()\n", This, iface);
3252
3253 return IUnknown_Release(This->outer_unk);
3254}
3255
3256/*** IDispatch methods ***/
3257static HRESULT WINAPI BasicVideo_GetTypeInfoCount(IBasicVideo2 *iface, UINT *pctinfo)
3258{
3260 IBasicVideo *pBasicVideo;
3261 HRESULT hr;
3262
3263 TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
3264
3266
3267 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3268
3269 if (hr == S_OK)
3270 hr = IBasicVideo_GetTypeInfoCount(pBasicVideo, pctinfo);
3271
3273
3274 return hr;
3275}
3276
3277static HRESULT WINAPI BasicVideo_GetTypeInfo(IBasicVideo2 *iface, UINT iTInfo, LCID lcid,
3278 ITypeInfo **ppTInfo)
3279{
3281 IBasicVideo *pBasicVideo;
3282 HRESULT hr;
3283
3284 TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
3285
3287
3288 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3289
3290 if (hr == S_OK)
3291 hr = IBasicVideo_GetTypeInfo(pBasicVideo, iTInfo, lcid, ppTInfo);
3292
3294
3295 return hr;
3296}
3297
3299 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
3300{
3302 IBasicVideo *pBasicVideo;
3303 HRESULT hr;
3304
3305 TRACE("(%p/%p)->(%s, %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), rgszNames, cNames,
3306 lcid, rgDispId);
3307
3309
3310 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3311
3312 if (hr == S_OK)
3313 hr = IBasicVideo_GetIDsOfNames(pBasicVideo, riid, rgszNames, cNames, lcid, rgDispId);
3314
3316
3317 return hr;
3318}
3319
3320static HRESULT WINAPI BasicVideo_Invoke(IBasicVideo2 *iface, DISPID dispIdMember, REFIID riid,
3321 LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
3322 UINT *puArgErr)
3323{
3325 IBasicVideo *pBasicVideo;
3326 HRESULT hr;
3327
3328 TRACE("(%p/%p)->(%d, %s, %d, %04x, %p, %p, %p, %p)\n", This, iface, dispIdMember,
3329 debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
3330
3332
3333 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3334
3335 if (hr == S_OK)
3336 hr = IBasicVideo_Invoke(pBasicVideo, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
3337
3339
3340 return hr;
3341}
3342
3343/*** IBasicVideo methods ***/
3344static HRESULT WINAPI BasicVideo_get_AvgTimePerFrame(IBasicVideo2 *iface, REFTIME *pAvgTimePerFrame)
3345{
3347 IBasicVideo *pBasicVideo;
3348 HRESULT hr;
3349
3350 TRACE("(%p/%p)->(%p)\n", This, iface, pAvgTimePerFrame);
3351
3353
3354 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3355
3356 if (hr == S_OK)
3357 hr = IBasicVideo_get_AvgTimePerFrame(pBasicVideo, pAvgTimePerFrame);
3358
3360
3361 return hr;
3362}
3363
3364static HRESULT WINAPI BasicVideo_get_BitRate(IBasicVideo2 *iface, LONG *pBitRate)
3365{
3367 IBasicVideo *pBasicVideo;
3368 HRESULT hr;
3369
3370 TRACE("(%p/%p)->(%p)\n", This, iface, pBitRate);
3371
3373
3374 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3375
3376 if (hr == S_OK)
3377 hr = IBasicVideo_get_BitRate(pBasicVideo, pBitRate);
3378
3380
3381 return hr;
3382}
3383
3384static HRESULT WINAPI BasicVideo_get_BitErrorRate(IBasicVideo2 *iface, LONG *pBitErrorRate)
3385{
3387 IBasicVideo *pBasicVideo;
3388 HRESULT hr;
3389
3390 TRACE("(%p/%p)->(%p)\n", This, iface, pBitErrorRate);
3391
3393
3394 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3395
3396 if (hr == S_OK)
3397 hr = IBasicVideo_get_BitErrorRate(pBasicVideo, pBitErrorRate);
3398
3400
3401 return hr;
3402}
3403
3404static HRESULT WINAPI BasicVideo_get_VideoWidth(IBasicVideo2 *iface, LONG *pVideoWidth)
3405{
3407 IBasicVideo *pBasicVideo;
3408 HRESULT hr;
3409
3410 TRACE("(%p/%p)->(%p)\n", This, iface, pVideoWidth);
3411
3413
3414 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3415
3416 if (hr == S_OK)
3417 hr = IBasicVideo_get_VideoWidth(pBasicVideo, pVideoWidth);
3418
3420
3421 return hr;
3422}
3423
3424static HRESULT WINAPI BasicVideo_get_VideoHeight(IBasicVideo2 *iface, LONG *pVideoHeight)
3425{
3427 IBasicVideo *pBasicVideo;
3428 HRESULT hr;
3429
3430 TRACE("(%p/%p)->(%p)\n", This, iface, pVideoHeight);
3431
3433
3434 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3435
3436 if (hr == S_OK)
3437 hr = IBasicVideo_get_VideoHeight(pBasicVideo, pVideoHeight);
3438
3440
3441 return hr;
3442}
3443
3444static HRESULT WINAPI BasicVideo_put_SourceLeft(IBasicVideo2 *iface, LONG SourceLeft)
3445{
3447 IBasicVideo *pBasicVideo;
3448 HRESULT hr;
3449
3450 TRACE("(%p/%p)->(%d)\n", This, iface, SourceLeft);
3451
3453
3454 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3455
3456 if (hr == S_OK)
3457 hr = IBasicVideo_put_SourceLeft(pBasicVideo, SourceLeft);
3458
3460
3461 return hr;
3462}
3463
3464static HRESULT WINAPI BasicVideo_get_SourceLeft(IBasicVideo2 *iface, LONG *pSourceLeft)
3465{
3467 IBasicVideo *pBasicVideo;
3468 HRESULT hr;
3469
3470 TRACE("(%p/%p)->(%p)\n", This, iface, pSourceLeft);
3471
3473
3474 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3475
3476 if (hr == S_OK)
3477 hr = IBasicVideo_get_SourceLeft(pBasicVideo, pSourceLeft);
3478
3480
3481 return hr;
3482}
3483
3484static HRESULT WINAPI BasicVideo_put_SourceWidth(IBasicVideo2 *iface, LONG SourceWidth)
3485{
3487 IBasicVideo *pBasicVideo;
3488 HRESULT hr;
3489
3490 TRACE("(%p/%p)->(%d)\n", This, iface, SourceWidth);
3491
3493
3494 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3495
3496 if (hr == S_OK)
3497 hr = IBasicVideo_put_SourceWidth(pBasicVideo, SourceWidth);
3498
3500
3501 return hr;
3502}
3503
3504static HRESULT WINAPI BasicVideo_get_SourceWidth(IBasicVideo2 *iface, LONG *pSourceWidth)
3505{
3507 IBasicVideo *pBasicVideo;
3508 HRESULT hr;
3509
3510 TRACE("(%p/%p)->(%p)\n", This, iface, pSourceWidth);
3511
3513
3514 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3515
3516 if (hr == S_OK)
3517 hr = IBasicVideo_get_SourceWidth(pBasicVideo, pSourceWidth);
3518
3520
3521 return hr;
3522}
3523
3524static HRESULT WINAPI BasicVideo_put_SourceTop(IBasicVideo2 *iface, LONG SourceTop)
3525{
3527 IBasicVideo *pBasicVideo;
3528 HRESULT hr;
3529
3530 TRACE("(%p/%p)->(%d)\n", This, iface, SourceTop);
3531
3533
3534 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3535
3536 if (hr == S_OK)
3537 hr = IBasicVideo_put_SourceTop(pBasicVideo, SourceTop);
3538
3540
3541 return hr;
3542}
3543
3544static HRESULT WINAPI BasicVideo_get_SourceTop(IBasicVideo2 *iface, LONG *pSourceTop)
3545{
3547 IBasicVideo *pBasicVideo;
3548 HRESULT hr;
3549
3550 TRACE("(%p/%p)->(%p)\n", This, iface, pSourceTop);
3551
3553
3554 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3555
3556 if (hr == S_OK)
3557 hr = IBasicVideo_get_SourceTop(pBasicVideo, pSourceTop);
3558
3560
3561 return hr;
3562}
3563
3564static HRESULT WINAPI BasicVideo_put_SourceHeight(IBasicVideo2 *iface, LONG SourceHeight)
3565{
3567 IBasicVideo *pBasicVideo;
3568 HRESULT hr;
3569
3570 TRACE("(%p/%p)->(%d)\n", This, iface, SourceHeight);
3571
3573
3574 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3575
3576 if (hr == S_OK)
3577 hr = IBasicVideo_put_SourceHeight(pBasicVideo, SourceHeight);
3578
3580
3581 return hr;
3582}
3583
3584static HRESULT WINAPI BasicVideo_get_SourceHeight(IBasicVideo2 *iface, LONG *pSourceHeight)
3585{
3587 IBasicVideo *pBasicVideo;
3588 HRESULT hr;
3589
3590 TRACE("(%p/%p)->(%p)\n", This, iface, pSourceHeight);
3591
3593
3594 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3595
3596 if (hr == S_OK)
3597 hr = IBasicVideo_get_SourceHeight(pBasicVideo, pSourceHeight);
3598
3600
3601 return hr;
3602}
3603
3604static HRESULT WINAPI BasicVideo_put_DestinationLeft(IBasicVideo2 *iface, LONG DestinationLeft)
3605{
3607 IBasicVideo *pBasicVideo;
3608 HRESULT hr;
3609
3610 TRACE("(%p/%p)->(%d)\n", This, iface, DestinationLeft);
3611
3613
3614 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3615
3616 if (hr == S_OK)
3617 hr = IBasicVideo_put_DestinationLeft(pBasicVideo, DestinationLeft);
3618
3620
3621 return hr;
3622}
3623
3624static HRESULT WINAPI BasicVideo_get_DestinationLeft(IBasicVideo2 *iface, LONG *pDestinationLeft)
3625{
3627 IBasicVideo *pBasicVideo;
3628 HRESULT hr;
3629
3630 TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationLeft);
3631
3633
3634 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3635
3636 if (hr == S_OK)
3637 hr = IBasicVideo_get_DestinationLeft(pBasicVideo, pDestinationLeft);
3638
3640
3641 return hr;
3642}
3643
3644static HRESULT WINAPI BasicVideo_put_DestinationWidth(IBasicVideo2 *iface, LONG DestinationWidth)
3645{
3647 IBasicVideo *pBasicVideo;
3648 HRESULT hr;
3649
3650 TRACE("(%p/%p)->(%d)\n", This, iface, DestinationWidth);
3651
3653
3654 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3655
3656 if (hr == S_OK)
3657 hr = IBasicVideo_put_DestinationWidth(pBasicVideo, DestinationWidth);
3658
3660
3661 return hr;
3662}
3663
3664static HRESULT WINAPI BasicVideo_get_DestinationWidth(IBasicVideo2 *iface, LONG *pDestinationWidth)
3665{
3667 IBasicVideo *pBasicVideo;
3668 HRESULT hr;
3669
3670 TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationWidth);
3671
3673
3674 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3675
3676 if (hr == S_OK)
3677 hr = IBasicVideo_get_DestinationWidth(pBasicVideo, pDestinationWidth);
3678
3680
3681 return hr;
3682}
3683
3684static HRESULT WINAPI BasicVideo_put_DestinationTop(IBasicVideo2 *iface, LONG DestinationTop)
3685{
3687 IBasicVideo *pBasicVideo;
3688 HRESULT hr;
3689
3690 TRACE("(%p/%p)->(%d)\n", This, iface, DestinationTop);
3691
3693
3694 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3695
3696 if (hr == S_OK)
3697 hr = IBasicVideo_put_DestinationTop(pBasicVideo, DestinationTop);
3698
3700
3701 return hr;
3702}
3703
3704static HRESULT WINAPI BasicVideo_get_DestinationTop(IBasicVideo2 *iface, LONG *pDestinationTop)
3705{
3707 IBasicVideo *pBasicVideo;
3708 HRESULT hr;
3709
3710 TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationTop);
3711
3713
3714 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3715
3716 if (hr == S_OK)
3717 hr = IBasicVideo_get_DestinationTop(pBasicVideo, pDestinationTop);
3718
3720
3721 return hr;
3722}
3723
3724static HRESULT WINAPI BasicVideo_put_DestinationHeight(IBasicVideo2 *iface, LONG DestinationHeight)
3725{
3727 IBasicVideo *pBasicVideo;
3728 HRESULT hr;
3729
3730 TRACE("(%p/%p)->(%d)\n", This, iface, DestinationHeight);
3731
3733
3734 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3735
3736 if (hr == S_OK)
3737 hr = IBasicVideo_put_DestinationHeight(pBasicVideo, DestinationHeight);
3738
3740
3741 return hr;
3742}
3743
3745 LONG *pDestinationHeight)
3746{
3748 IBasicVideo *pBasicVideo;
3749 HRESULT hr;
3750
3751 TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationHeight);
3752
3754
3755 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3756
3757 if (hr == S_OK)
3758 hr = IBasicVideo_get_DestinationHeight(pBasicVideo, pDestinationHeight);
3759
3761
3762 return hr;
3763}
3764
3765static HRESULT WINAPI BasicVideo_SetSourcePosition(IBasicVideo2 *iface, LONG Left, LONG Top,
3767{
3769 IBasicVideo *pBasicVideo;
3770 HRESULT hr;
3771
3772 TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
3773
3775
3776 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3777
3778 if (hr == S_OK)
3779 hr = IBasicVideo_SetSourcePosition(pBasicVideo, Left, Top, Width, Height);
3780
3782
3783 return hr;
3784}
3785
3786static HRESULT WINAPI BasicVideo_GetSourcePosition(IBasicVideo2 *iface, LONG *pLeft, LONG *pTop,
3787 LONG *pWidth, LONG *pHeight)
3788{
3790 IBasicVideo *pBasicVideo;
3791 HRESULT hr;
3792
3793 TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
3794
3796
3797 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3798
3799 if (hr == S_OK)
3800 hr = IBasicVideo_GetSourcePosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
3801
3803
3804 return hr;
3805}
3806
3808{
3810 IBasicVideo *pBasicVideo;
3811 HRESULT hr;
3812
3813 TRACE("(%p/%p)->()\n", This, iface);
3814
3816
3817 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3818
3819 if (hr == S_OK)
3820 hr = IBasicVideo_SetDefaultSourcePosition(pBasicVideo);
3821
3823
3824 return hr;
3825}
3826
3829{
3831 IBasicVideo *pBasicVideo;
3832 HRESULT hr;
3833
3834 TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
3835
3837
3838 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3839
3840 if (hr == S_OK)
3841 hr = IBasicVideo_SetDestinationPosition(pBasicVideo, Left, Top, Width, Height);
3842
3844
3845 return hr;
3846}
3847
3848static HRESULT WINAPI BasicVideo_GetDestinationPosition(IBasicVideo2 *iface, LONG *pLeft,
3849 LONG *pTop, LONG *pWidth, LONG *pHeight)
3850{
3852 IBasicVideo *pBasicVideo;
3853 HRESULT hr;
3854
3855 TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
3856
3858
3859 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3860
3861 if (hr == S_OK)
3862 hr = IBasicVideo_GetDestinationPosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
3863
3865
3866 return hr;
3867}
3868
3870{
3872 IBasicVideo *pBasicVideo;
3873 HRESULT hr;
3874
3875 TRACE("(%p/%p)->()\n", This, iface);
3876
3878
3879 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3880
3881 if (hr == S_OK)
3882 hr = IBasicVideo_SetDefaultDestinationPosition(pBasicVideo);
3883
3885
3886 return hr;
3887}
3888
3889static HRESULT WINAPI BasicVideo_GetVideoSize(IBasicVideo2 *iface, LONG *pWidth, LONG *pHeight)
3890{
3892 IBasicVideo *pBasicVideo;
3893 HRESULT hr;
3894
3895 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
3896
3898
3899 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3900
3901 if (hr == S_OK)
3902 hr = IBasicVideo_GetVideoSize(pBasicVideo, pWidth, pHeight);
3903
3905
3906 return hr;
3907}
3908
3909static HRESULT WINAPI BasicVideo_GetVideoPaletteEntries(IBasicVideo2 *iface, LONG StartIndex,
3910 LONG Entries, LONG *pRetrieved, LONG *pPalette)
3911{
3913 IBasicVideo *pBasicVideo;
3914 HRESULT hr;
3915
3916 TRACE("(%p/%p)->(%d, %d, %p, %p)\n", This, iface, StartIndex, Entries, pRetrieved, pPalette);
3917
3919
3920 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3921
3922 if (hr == S_OK)
3923 hr = IBasicVideo_GetVideoPaletteEntries(pBasicVideo, StartIndex, Entries, pRetrieved, pPalette);
3924
3926
3927 return hr;
3928}
3929
3931 LONG *pDIBImage)
3932{
3934 IBasicVideo *pBasicVideo;
3935 HRESULT hr;
3936
3937 TRACE("(%p/%p)->(%p, %p)\n", This, iface, pBufferSize, pDIBImage);
3938
3940
3941 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3942
3943 if (hr == S_OK)
3944 hr = IBasicVideo_GetCurrentImage(pBasicVideo, pBufferSize, pDIBImage);
3945
3947
3948 return hr;
3949}
3950
3952{
3954 IBasicVideo *pBasicVideo;
3955 HRESULT hr;
3956
3957 TRACE("(%p/%p)->()\n", This, iface);
3958
3960
3961 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3962
3963 if (hr == S_OK)
3964 hr = IBasicVideo_IsUsingDefaultSource(pBasicVideo);
3965
3967
3968 return hr;
3969}
3970
3972{
3974 IBasicVideo *pBasicVideo;
3975 HRESULT hr;
3976
3977 TRACE("(%p/%p)->()\n", This, iface);
3978
3980
3981 hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3982
3983 if (hr == S_OK)
3984 hr = IBasicVideo_IsUsingDefaultDestination(pBasicVideo);
3985
3987
3988 return hr;
3989}
3990
3991static HRESULT WINAPI BasicVideo2_GetPreferredAspectRatio(IBasicVideo2 *iface, LONG *plAspectX,
3992 LONG *plAspectY)
3993{
3995 IBasicVideo2 *pBasicVideo2;
3996 HRESULT hr;
3997
3998 TRACE("(%p/%p)->()\n", This, iface);
3999
4001
4002 hr = GetTargetInterface(This, &IID_IBasicVideo2, (LPVOID*)&pBasicVideo2);
4003
4004 if (hr == S_OK)
4005 hr = BasicVideo2_GetPreferredAspectRatio(iface, plAspectX, plAspectY);
4006
4008
4009 return hr;
4010}
4011
4012static const IBasicVideo2Vtbl IBasicVideo_VTable =
4013{
4054};
4055
4056static inline IFilterGraphImpl *impl_from_IVideoWindow(IVideoWindow *iface)
4057{
4058 return CONTAINING_RECORD(iface, IFilterGraphImpl, IVideoWindow_iface);
4059}
4060
4061static HRESULT WINAPI VideoWindow_QueryInterface(IVideoWindow *iface, REFIID riid, void **ppvObj)
4062{
4064
4065 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj);
4066
4067 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
4068}
4069
4070static ULONG WINAPI VideoWindow_AddRef(IVideoWindow *iface)
4071{
4073
4074 TRACE("(%p/%p)->()\n", This, iface);
4075
4076 return IUnknown_AddRef(This->outer_unk);
4077}
4078
4079static ULONG WINAPI VideoWindow_Release(IVideoWindow *iface)
4080{
4082
4083 TRACE("(%p/%p)->()\n", This, iface);
4084
4085 return IUnknown_Release(This->outer_unk);
4086}
4087
4088/*** IDispatch methods ***/
4089static HRESULT WINAPI VideoWindow_GetTypeInfoCount(IVideoWindow *iface, UINT *pctinfo)
4090{
4092 IVideoWindow *pVideoWindow;
4093 HRESULT hr;
4094
4095 TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
4096
4098
4099 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4100
4101 if (hr == S_OK)
4102 hr = IVideoWindow_GetTypeInfoCount(pVideoWindow, pctinfo);
4103
4105
4106 return hr;
4107}
4108
4109static HRESULT WINAPI VideoWindow_GetTypeInfo(IVideoWindow *iface, UINT iTInfo, LCID lcid,
4110 ITypeInfo **ppTInfo)
4111{
4113 IVideoWindow *pVideoWindow;
4114 HRESULT hr;
4115
4116 TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
4117
4119
4120 hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4121
4122 if (hr == S_OK)
4123 hr = IVideoWindow_GetTypeInfo(pVideoWindow, iTInfo, lcid, ppTInfo);
4124
4126
4127 return