ReactOS  0.4.13-dev-249-gcba1a2f
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 
44 typedef 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 
51 typedef 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
59 typedef struct {
63  int msg_toget;
65  HANDLE msg_event; /* Signaled for no empty queue */
66 } EventsQueue;
67 
68 static int EventsQueue_Init(EventsQueue* omr)
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 {
84  CloseHandle(omr->msg_event);
85  CoTaskMemFree(omr->messages);
86  omr->msg_crst.DebugInfo->Spare[0] = 0;
88  return TRUE;
89 }
90 
91 static BOOL EventsQueue_PutEvent(EventsQueue* omr, const Event* evt)
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 
120 static 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
145 typedef struct _ITF_CACHE_ENTRY {
146  const IID* riid;
150 
151 typedef 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 
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 
218  if (IsEqualGUID(&IID_IUnknown, riid)) {
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 ***/
369  LPCWSTR pName)
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);
425  return VFW_E_DUPLICATE_NAME;
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)
463  return VFW_S_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);
609  return VFW_E_CANNOT_CONNECT;
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 
659 out:
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;
802  IReferenceClock_Release(pClock);
803  }
805 
806  return hr;
807 }
808 
809 static 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 
831 static 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 ***/
894 static 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 
1169 error:
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 
1182 out:
1183  if (pFilterMapper2)
1184  IFilterMapper2_Release(pFilterMapper2);
1185  if (penummt)
1186  IEnumMediaTypes_Release(penummt);
1187  if (mt)
1188  DeleteMediaType(mt);
1189  --This->recursioncount;
1190  LeaveCriticalSection(&This->cs);
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  */
1298  EnterCriticalSection(&This->cs);
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);
1339  LeaveCriticalSection(&This->cs);
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 
1352  LeaveCriticalSection(&This->cs);
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 
1498 error:
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 */
1664  hr = GetClassMediaFile(pReader, pszFileName, NULL, NULL, &clsid);
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 
1727 error:
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 
1814 static const IFilterGraph2Vtbl IFilterGraph2_VTable =
1815 {
1837 };
1838 
1839 static inline IFilterGraphImpl *impl_from_IMediaControl(IMediaControl *iface)
1840 {
1841  return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaControl_iface);
1842 }
1843 
1844 static 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 
1853 static 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 
1862 static 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 ***/
1873 static 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 
1882 static 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 
1892 static HRESULT WINAPI MediaControl_GetIDsOfNames(IMediaControl *iface, REFIID riid,
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 
1903 static 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 
1917 static 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 ***/
2064 static HRESULT WINAPI MediaControl_Run(IMediaControl *iface)
2065 {
2067 
2068  TRACE("(%p/%p)->()\n", This, iface);
2069 
2070  EnterCriticalSection(&This->cs);
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;
2093 out:
2094  LeaveCriticalSection(&This->cs);
2095  return S_FALSE;
2096 }
2097 
2098 static HRESULT WINAPI MediaControl_Pause(IMediaControl *iface)
2099 {
2101 
2102  TRACE("(%p/%p)->()\n", This, iface);
2103 
2104  EnterCriticalSection(&This->cs);
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;
2115 out:
2116  LeaveCriticalSection(&This->cs);
2117  return S_FALSE;
2118 }
2119 
2120 static 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 
2128  EnterCriticalSection(&This->cs);
2129  if (This->state == State_Running) SendFilterMessage(This, SendPause, 0);
2131  This->state = State_Stopped;
2132  LeaveCriticalSection(&This->cs);
2133  return S_OK;
2134 }
2135 
2136 static 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 
2147  EnterCriticalSection(&This->cs);
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 
2165  LeaveCriticalSection(&This->cs);
2166 
2167  return S_OK;
2168 }
2169 
2170 static 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 
2179 static 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 
2189 static 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 
2198 static HRESULT WINAPI MediaControl_get_RegFilterCollection(IMediaControl *iface, IDispatch **ppUnk)
2199 {
2201 
2202  FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
2203 
2204  return S_OK;
2205 }
2206 
2207 static HRESULT WINAPI MediaControl_StopWhenReady(IMediaControl *iface)
2208 {
2210 
2211  FIXME("(%p/%p)->(): stub !!!\n", This, iface);
2212 
2213  return S_OK;
2214 }
2215 
2216 
2217 static 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  {
2281  IMediaSeeking *seek = NULL;
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 
2335  EnterCriticalSection(&This->cs);
2336  *pCapabilities = 0xffffffff;
2337 
2339  LeaveCriticalSection(&This->cs);
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 
2355  EnterCriticalSection(&This->cs);
2356  originalcaps = *pCapabilities;
2358  LeaveCriticalSection(&This->cs);
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 
2473  EnterCriticalSection(&This->cs);
2474  *pDuration = 0;
2476  LeaveCriticalSection(&This->cs);
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 
2504 struct 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 
2526  EnterCriticalSection(&This->cs);
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);
2546  LeaveCriticalSection(&This->cs);
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;
2570  EnterCriticalSection(&This->cs);
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;
2581  LeaveCriticalSection(&This->cs);
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 
2627 static HRESULT WINAPI MediaSeeking_SetRate(IMediaSeeking *iface, double dRate)
2628 {
2630 
2631  FIXME("(%p/%p)->(%f): stub !!!\n", This, iface, dRate);
2632 
2633  return S_OK;
2634 }
2635 
2636 static 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 
2660 static const IMediaSeekingVtbl IMediaSeeking_VTable =
2661 {
2682 };
2683 
2684 static inline IFilterGraphImpl *impl_from_IMediaPosition(IMediaPosition *iface)
2685 {
2686  return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaPosition_iface);
2687 }
2688 
2689 /*** IUnknown methods ***/
2690 static 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 
2699 static 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 
2708 static 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 ***/
2718 static HRESULT WINAPI MediaPosition_GetTypeInfoCount(IMediaPosition *iface, UINT* pctinfo)
2719 {
2720  FIXME("(%p) stub!\n", iface);
2721  return E_NOTIMPL;
2722 }
2723 
2724 static 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 
2730 static 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 
2736 static 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 ***/
2779 static 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 
2789 static 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 
2802 static 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 
2814 static 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 
2824 static 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,
2834  &reftime, AM_SEEKING_AbsolutePositioning);
2835 }
2836 
2837 static HRESULT WINAPI MediaPosition_get_PrerollTime(IMediaPosition * iface, REFTIME *pllTime)
2838 {
2839  FIXME("(%p)->(%p) stub!\n", iface, pllTime);
2840  return E_NOTIMPL;
2841 }
2842 
2843 static HRESULT WINAPI MediaPosition_put_PrerollTime(IMediaPosition * iface, REFTIME llTime)
2844 {
2845  FIXME("(%p)->(%f) stub!\n", iface, llTime);
2846  return E_NOTIMPL;
2847 }
2848 
2849 static HRESULT WINAPI MediaPosition_put_Rate(IMediaPosition * iface, double dRate)
2850 {
2852  return IMediaSeeking_SetRate(&This->IMediaSeeking_iface, dRate);
2853 }
2854 
2855 static HRESULT WINAPI MediaPosition_get_Rate(IMediaPosition * iface, double *pdRate)
2856 {
2858  return IMediaSeeking_GetRate(&This->IMediaSeeking_iface, pdRate);
2859 }
2860 
2861 static HRESULT WINAPI MediaPosition_CanSeekForward(IMediaPosition * iface, LONG *pCanSeekForward)
2862 {
2863  FIXME("(%p)->(%p) stub!\n", iface, pCanSeekForward);
2864  return E_NOTIMPL;
2865 }
2866 
2867 static HRESULT WINAPI MediaPosition_CanSeekBackward(IMediaPosition * iface, LONG *pCanSeekBackward)
2868 {
2869  FIXME("(%p)->(%p) stub!\n", iface, pCanSeekBackward);
2870  return E_NOTIMPL;
2871 }
2872 
2873 
2874 static 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 
2955 static 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 
3009 static inline IFilterGraphImpl *impl_from_IBasicAudio(IBasicAudio *iface)
3010 {
3011  return CONTAINING_RECORD(iface, IFilterGraphImpl, IBasicAudio_iface);
3012 }
3013 
3014 static 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 
3023 static 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 
3032 static 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 ***/
3042 static 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 
3050  EnterCriticalSection(&This->cs);
3051 
3052  hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3053 
3054  if (hr == S_OK)
3055  hr = IBasicAudio_GetTypeInfoCount(pBasicAudio, pctinfo);
3056 
3057  LeaveCriticalSection(&This->cs);
3058 
3059  return hr;
3060 }
3061 
3062 static 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 
3071  EnterCriticalSection(&This->cs);
3072 
3073  hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3074 
3075  if (hr == S_OK)
3076  hr = IBasicAudio_GetTypeInfo(pBasicAudio, iTInfo, lcid, ppTInfo);
3077 
3078  LeaveCriticalSection(&This->cs);
3079 
3080  return hr;
3081 }
3082 
3083 static 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 
3093  EnterCriticalSection(&This->cs);
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 
3100  LeaveCriticalSection(&This->cs);
3101 
3102  return hr;
3103 }
3104 
3105 static 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 
3116  EnterCriticalSection(&This->cs);
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 
3123  LeaveCriticalSection(&This->cs);
3124 
3125  return hr;
3126 }
3127 
3128 /*** IBasicAudio methods ***/
3129 static 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 
3137  EnterCriticalSection(&This->cs);
3138 
3139  hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3140 
3141  if (hr == S_OK)
3142  hr = IBasicAudio_put_Volume(pBasicAudio, lVolume);
3143 
3144  LeaveCriticalSection(&This->cs);
3145 
3146  return hr;
3147 }
3148 
3149 static 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 
3157  EnterCriticalSection(&This->cs);
3158 
3159  hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3160 
3161  if (hr == S_OK)
3162  hr = IBasicAudio_get_Volume(pBasicAudio, plVolume);
3163 
3164  LeaveCriticalSection(&This->cs);
3165 
3166  return hr;
3167 }
3168 
3169 static 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 
3177  EnterCriticalSection(&This->cs);
3178 
3179  hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3180 
3181  if (hr == S_OK)
3182  hr = IBasicAudio_put_Balance(pBasicAudio, lBalance);
3183 
3184  LeaveCriticalSection(&This->cs);
3185 
3186  return hr;
3187 }
3188 
3189 static 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 
3197  EnterCriticalSection(&This->cs);
3198 
3199  hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3200 
3201  if (hr == S_OK)
3202  hr = IBasicAudio_get_Balance(pBasicAudio, plBalance);
3203 
3204  LeaveCriticalSection(&This->cs);
3205 
3206  return hr;
3207 }
3208 
3209 static const IBasicAudioVtbl IBasicAudio_VTable =
3210 {
3222 };
3223 
3224 static inline IFilterGraphImpl *impl_from_IBasicVideo2(IBasicVideo2 *iface)
3225 {
3226  return CONTAINING_RECORD(iface, IFilterGraphImpl, IBasicVideo2_iface);
3227 }
3228 
3229 static 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 
3238 static 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 
3247 static 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 ***/
3257 static 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 
3265  EnterCriticalSection(&This->cs);
3266 
3267  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3268 
3269  if (hr == S_OK)
3270  hr = IBasicVideo_GetTypeInfoCount(pBasicVideo, pctinfo);
3271 
3272  LeaveCriticalSection(&This->cs);
3273 
3274  return hr;
3275 }
3276 
3277 static 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 
3286  EnterCriticalSection(&This->cs);
3287 
3288  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3289 
3290  if (hr == S_OK)
3291  hr = IBasicVideo_GetTypeInfo(pBasicVideo, iTInfo, lcid, ppTInfo);
3292 
3293  LeaveCriticalSection(&This->cs);
3294 
3295  return hr;
3296 }
3297 
3298 static HRESULT WINAPI BasicVideo_GetIDsOfNames(IBasicVideo2 *iface, REFIID riid,
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 
3308  EnterCriticalSection(&This->cs);
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 
3315  LeaveCriticalSection(&This->cs);
3316 
3317  return hr;
3318 }
3319 
3320 static 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 
3331  EnterCriticalSection(&This->cs);
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 
3338  LeaveCriticalSection(&This->cs);
3339 
3340  return hr;
3341 }
3342 
3343 /*** IBasicVideo methods ***/
3344 static 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 
3352  EnterCriticalSection(&This->cs);
3353 
3354  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3355 
3356  if (hr == S_OK)
3357  hr = IBasicVideo_get_AvgTimePerFrame(pBasicVideo, pAvgTimePerFrame);
3358 
3359  LeaveCriticalSection(&This->cs);
3360 
3361  return hr;
3362 }
3363 
3364 static 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 
3372  EnterCriticalSection(&This->cs);
3373 
3374  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3375 
3376  if (hr == S_OK)
3377  hr = IBasicVideo_get_BitRate(pBasicVideo, pBitRate);
3378 
3379  LeaveCriticalSection(&This->cs);
3380 
3381  return hr;
3382 }
3383 
3384 static 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 
3392  EnterCriticalSection(&This->cs);
3393 
3394  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3395 
3396  if (hr == S_OK)
3397  hr = IBasicVideo_get_BitErrorRate(pBasicVideo, pBitErrorRate);
3398 
3399  LeaveCriticalSection(&This->cs);
3400 
3401  return hr;
3402 }
3403 
3404 static 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 
3412  EnterCriticalSection(&This->cs);
3413 
3414  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3415 
3416  if (hr == S_OK)
3417  hr = IBasicVideo_get_VideoWidth(pBasicVideo, pVideoWidth);
3418 
3419  LeaveCriticalSection(&This->cs);
3420 
3421  return hr;
3422 }
3423 
3424 static 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 
3432  EnterCriticalSection(&This->cs);
3433 
3434  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3435 
3436  if (hr == S_OK)
3437  hr = IBasicVideo_get_VideoHeight(pBasicVideo, pVideoHeight);
3438 
3439  LeaveCriticalSection(&This->cs);
3440 
3441  return hr;
3442 }
3443 
3444 static 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 
3452  EnterCriticalSection(&This->cs);
3453 
3454  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3455 
3456  if (hr == S_OK)
3457  hr = IBasicVideo_put_SourceLeft(pBasicVideo, SourceLeft);
3458 
3459  LeaveCriticalSection(&This->cs);
3460 
3461  return hr;
3462 }
3463 
3464 static 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 
3472  EnterCriticalSection(&This->cs);
3473 
3474  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3475 
3476  if (hr == S_OK)
3477  hr = IBasicVideo_get_SourceLeft(pBasicVideo, pSourceLeft);
3478 
3479  LeaveCriticalSection(&This->cs);
3480 
3481  return hr;
3482 }
3483 
3484 static 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 
3492  EnterCriticalSection(&This->cs);
3493 
3494  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3495 
3496  if (hr == S_OK)
3497  hr = IBasicVideo_put_SourceWidth(pBasicVideo, SourceWidth);
3498 
3499  LeaveCriticalSection(&This->cs);
3500 
3501  return hr;
3502 }
3503 
3504 static 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 
3512  EnterCriticalSection(&This->cs);
3513 
3514  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3515 
3516  if (hr == S_OK)
3517  hr = IBasicVideo_get_SourceWidth(pBasicVideo, pSourceWidth);
3518 
3519  LeaveCriticalSection(&This->cs);
3520 
3521  return hr;
3522 }
3523 
3524 static 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 
3532  EnterCriticalSection(&This->cs);
3533 
3534  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3535 
3536  if (hr == S_OK)
3537  hr = IBasicVideo_put_SourceTop(pBasicVideo, SourceTop);
3538 
3539  LeaveCriticalSection(&This->cs);
3540 
3541  return hr;
3542 }
3543 
3544 static 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 
3552  EnterCriticalSection(&This->cs);
3553 
3554  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3555 
3556  if (hr == S_OK)
3557  hr = IBasicVideo_get_SourceTop(pBasicVideo, pSourceTop);
3558 
3559  LeaveCriticalSection(&This->cs);
3560 
3561  return hr;
3562 }
3563 
3564 static 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 
3572  EnterCriticalSection(&This->cs);
3573 
3574  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3575 
3576  if (hr == S_OK)
3577  hr = IBasicVideo_put_SourceHeight(pBasicVideo, SourceHeight);
3578 
3579  LeaveCriticalSection(&This->cs);
3580 
3581  return hr;
3582 }
3583 
3584 static 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 
3592  EnterCriticalSection(&This->cs);
3593 
3594  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3595 
3596  if (hr == S_OK)
3597  hr = IBasicVideo_get_SourceHeight(pBasicVideo, pSourceHeight);
3598 
3599  LeaveCriticalSection(&This->cs);
3600 
3601  return hr;
3602 }
3603 
3604 static 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 
3612  EnterCriticalSection(&This->cs);
3613 
3614  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3615 
3616  if (hr == S_OK)
3617  hr = IBasicVideo_put_DestinationLeft(pBasicVideo, DestinationLeft);
3618 
3619  LeaveCriticalSection(&This->cs);
3620 
3621  return hr;
3622 }
3623 
3624 static 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 
3632  EnterCriticalSection(&This->cs);
3633 
3634  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3635 
3636  if (hr == S_OK)
3637  hr = IBasicVideo_get_DestinationLeft(pBasicVideo, pDestinationLeft);
3638 
3639  LeaveCriticalSection(&This->cs);
3640 
3641  return hr;
3642 }
3643 
3644 static 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 
3652  EnterCriticalSection(&This->cs);
3653 
3654  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3655 
3656  if (hr == S_OK)
3657  hr = IBasicVideo_put_DestinationWidth(pBasicVideo, DestinationWidth);
3658 
3659  LeaveCriticalSection(&This->cs);
3660 
3661  return hr;
3662 }
3663 
3664 static 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 
3672  EnterCriticalSection(&This->cs);
3673 
3674  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3675 
3676  if (hr == S_OK)
3677  hr = IBasicVideo_get_DestinationWidth(pBasicVideo, pDestinationWidth);
3678 
3679  LeaveCriticalSection(&This->cs);
3680 
3681  return hr;
3682 }
3683 
3684 static 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 
3692  EnterCriticalSection(&This->cs);
3693 
3694  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3695 
3696  if (hr == S_OK)
3697  hr = IBasicVideo_put_DestinationTop(pBasicVideo, DestinationTop);
3698 
3699  LeaveCriticalSection(&This->cs);
3700 
3701  return hr;
3702 }
3703 
3704 static 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 
3712  EnterCriticalSection(&This->cs);
3713 
3714  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3715 
3716  if (hr == S_OK)
3717  hr = IBasicVideo_get_DestinationTop(pBasicVideo, pDestinationTop);
3718 
3719  LeaveCriticalSection(&This->cs);
3720 
3721  return hr;
3722 }
3723 
3724 static 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 
3732  EnterCriticalSection(&This->cs);
3733 
3734  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3735 
3736  if (hr == S_OK)
3737  hr = IBasicVideo_put_DestinationHeight(pBasicVideo, DestinationHeight);
3738 
3739  LeaveCriticalSection(&This->cs);
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 
3753  EnterCriticalSection(&This->cs);
3754 
3755  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3756 
3757  if (hr == S_OK)
3758  hr = IBasicVideo_get_DestinationHeight(pBasicVideo, pDestinationHeight);
3759 
3760  LeaveCriticalSection(&This->cs);
3761 
3762  return hr;
3763 }
3764 
3765 static HRESULT WINAPI BasicVideo_SetSourcePosition(IBasicVideo2 *iface, LONG Left, LONG Top,
3766  LONG Width, LONG Height)
3767 {
3769  IBasicVideo *pBasicVideo;
3770  HRESULT hr;
3771 
3772  TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
3773 
3774  EnterCriticalSection(&This->cs);
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 
3781  LeaveCriticalSection(&This->cs);
3782 
3783  return hr;
3784 }
3785 
3786 static 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 
3795  EnterCriticalSection(&This->cs);
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 
3802  LeaveCriticalSection(&This->cs);
3803 
3804  return hr;
3805 }
3806 
3808 {
3810  IBasicVideo *pBasicVideo;
3811  HRESULT hr;
3812 
3813  TRACE("(%p/%p)->()\n", This, iface);
3814 
3815  EnterCriticalSection(&This->cs);
3816 
3817  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3818 
3819  if (hr == S_OK)
3820  hr = IBasicVideo_SetDefaultSourcePosition(pBasicVideo);
3821 
3822  LeaveCriticalSection(&This->cs);
3823 
3824  return hr;
3825 }
3826 
3827 static HRESULT WINAPI BasicVideo_SetDestinationPosition(IBasicVideo2 *iface, LONG Left, LONG Top,
3828  LONG Width, LONG Height)
3829 {
3831  IBasicVideo *pBasicVideo;
3832  HRESULT hr;
3833 
3834  TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
3835 
3836  EnterCriticalSection(&This->cs);
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 
3843  LeaveCriticalSection(&This->cs);
3844 
3845  return hr;
3846 }
3847 
3848 static 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 
3857  EnterCriticalSection(&This->cs);
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 
3864  LeaveCriticalSection(&This->cs);
3865 
3866  return hr;
3867 }
3868 
3870 {
3872  IBasicVideo *pBasicVideo;
3873  HRESULT hr;
3874 
3875  TRACE("(%p/%p)->()\n", This, iface);
3876 
3877  EnterCriticalSection(&This->cs);
3878 
3879  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3880 
3881  if (hr == S_OK)
3882  hr = IBasicVideo_SetDefaultDestinationPosition(pBasicVideo);
3883 
3884  LeaveCriticalSection(&This->cs);
3885 
3886  return hr;
3887 }
3888 
3889 static 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 
3897  EnterCriticalSection(&This->cs);
3898 
3899  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3900 
3901  if (hr == S_OK)
3902  hr = IBasicVideo_GetVideoSize(pBasicVideo, pWidth, pHeight);
3903 
3904  LeaveCriticalSection(&This->cs);
3905 
3906  return hr;
3907 }
3908 
3909 static 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 
3918  EnterCriticalSection(&This->cs);
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 
3925  LeaveCriticalSection(&This->cs);
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 
3939  EnterCriticalSection(&This->cs);
3940 
3941  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3942 
3943  if (hr == S_OK)
3944  hr = IBasicVideo_GetCurrentImage(pBasicVideo, pBufferSize, pDIBImage);
3945 
3946  LeaveCriticalSection(&This->cs);
3947 
3948  return hr;
3949 }
3950 
3952 {
3954  IBasicVideo *pBasicVideo;
3955  HRESULT hr;
3956 
3957  TRACE("(%p/%p)->()\n", This, iface);
3958 
3959  EnterCriticalSection(&This->cs);
3960 
3961  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3962 
3963  if (hr == S_OK)
3964  hr = IBasicVideo_IsUsingDefaultSource(pBasicVideo);
3965 
3966  LeaveCriticalSection(&This->cs);
3967 
3968  return hr;
3969 }
3970 
3972 {
3974  IBasicVideo *pBasicVideo;
3975  HRESULT hr;
3976 
3977  TRACE("(%p/%p)->()\n", This, iface);
3978 
3979  EnterCriticalSection(&This->cs);
3980 
3981  hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3982 
3983  if (hr == S_OK)
3984  hr = IBasicVideo_IsUsingDefaultDestination(pBasicVideo);
3985 
3986  LeaveCriticalSection(&This->cs);
3987 
3988  return hr;
3989 }
3990 
3991 static 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 
4000  EnterCriticalSection(&This->cs);
4001 
4002  hr = GetTargetInterface(This, &IID_IBasicVideo2, (LPVOID*)&pBasicVideo2);
4003 
4004  if (hr == S_OK)
4005  hr = BasicVideo2_GetPreferredAspectRatio(iface, plAspectX, plAspectY);
4006 
4007  LeaveCriticalSection(&This->cs);
4008 
4009  return hr;
4010 }
4011 
4012 static const IBasicVideo2Vtbl IBasicVideo_VTable =
4013 {
4054 };
4055 
4056 static inline IFilterGraphImpl *impl_from_IVideoWindow(IVideoWindow *iface)
4057 {
4058  return CONTAINING_RECORD(iface, IFilterGraphImpl, IVideoWindow_iface);
4059 }
4060 
4061 static 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 
4070 static 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 
4079 static 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 ***/
4089 static 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 
4097  EnterCriticalSection(&This->cs);
4098 
4099  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4100 
4101  if (hr == S_OK)
4102  hr = IVideoWindow_GetTypeInfoCount(pVideoWindow, pctinfo);
4103 
4104  LeaveCriticalSection(&This->cs);
4105 
4106  return hr;
4107 }
4108 
4109 static 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 
4118  EnterCriticalSection(&This->cs);
4119 
4120  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4121 
4122  if (hr == S_OK)
4123  hr = IVideoWindow_GetTypeInfo(pVideoWindow, iTInfo, lcid, ppTInfo);
4124 
4125  LeaveCriticalSection(&This->cs);
4126 
4127  return hr;
4128 }
4129 
4131  LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
4132 {
4134  IVideoWindow *pVideoWindow;
4135  HRESULT hr;
4136 
4137  TRACE("(%p/%p)->(%s, %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), rgszNames, cNames,
4138  lcid, rgDispId);
4139 
4140  EnterCriticalSection(&This->cs);
4141 
4142  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4143 
4144  if (hr == S_OK)
4145  hr = IVideoWindow_GetIDsOfNames(pVideoWindow, riid, rgszNames, cNames, lcid, rgDispId);
4146 
4147  LeaveCriticalSection(&This->cs);
4148 
4149  return hr;
4150 }
4151 
4152 static HRESULT WINAPI VideoWindow_Invoke(IVideoWindow *iface, DISPID dispIdMember, REFIID riid,
4153  LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
4154  UINT*puArgErr)
4155 {
4157  IVideoWindow *pVideoWindow;
4158  HRESULT hr;
4159 
4160  TRACE("(%p/%p)->(%d, %s, %d, %04x, %p, %p, %p, %p)\n", This, iface, dispIdMember,
4161  debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
4162 
4163  EnterCriticalSection(&This->cs);
4164 
4165  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4166 
4167  if (hr == S_OK)
4168  hr = IVideoWindow_Invoke(pVideoWindow, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
4169 
4170  LeaveCriticalSection(&This->cs);
4171 
4172  return hr;
4173 }
4174 
4175 
4176 /*** IVideoWindow methods ***/
4177 static HRESULT WINAPI VideoWindow_put_Caption(IVideoWindow *iface, BSTR strCaption)
4178 {
4180  IVideoWindow *pVideoWindow;
4181  HRESULT hr;
4182 
4183  TRACE("(%p/%p)->(%s (%p))\n", This, iface, debugstr_w(strCaption), strCaption);
4184 
4185  EnterCriticalSection(&This->cs);
4186 
4187  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4188 
4189  if (hr == S_OK)
4190  hr = IVideoWindow_put_Caption(pVideoWindow, strCaption);
4191 
4192  LeaveCriticalSection(&This->cs);
4193 
4194  return hr;
4195 }
4196 
4197 static HRESULT WINAPI VideoWindow_get_Caption(IVideoWindow *iface, BSTR *strCaption)
4198 {
4200  IVideoWindow *pVideoWindow;
4201  HRESULT hr;
4202 
4203  TRACE("(%p/%p)->(%p)\n", This, iface, strCaption);
4204 
4205  EnterCriticalSection(&This->cs);
4206 
4207  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4208 
4209  if (hr == S_OK)
4210  hr = IVideoWindow_get_Caption(pVideoWindow, strCaption);
4211 
4212  LeaveCriticalSection(&This->cs);
4213 
4214  return hr;
4215 }
4216 
4217 static HRESULT WINAPI VideoWindow_put_WindowStyle(IVideoWindow *iface, LONG WindowStyle)
4218 {
4220  IVideoWindow *pVideoWindow;
4221  HRESULT hr;
4222 
4223  TRACE("(%p/%p)->(%d)\n", This, iface, WindowStyle);
4224 
4225  EnterCriticalSection(&This->cs);
4226 
4227  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4228 
4229  if (hr == S_OK)
4230  hr = IVideoWindow_put_WindowStyle(pVideoWindow, WindowStyle);
4231 
4232  LeaveCriticalSection(&This->cs);
4233 
4234  return hr;
4235 }
4236 
4237 static HRESULT WINAPI VideoWindow_get_WindowStyle(IVideoWindow *iface, LONG *WindowStyle)
4238 {
4240  IVideoWindow *pVideoWindow;
4241  HRESULT hr;
4242 
4243  TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyle);
4244 
4245  EnterCriticalSection(&This->cs);
4246 
4247  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4248 
4249  if (hr == S_OK)
4250  hr = IVideoWindow_get_WindowStyle(pVideoWindow, WindowStyle);
4251 
4252  LeaveCriticalSection(&This->cs);
4253 
4254  return hr;
4255 }
4256 
4257 static HRESULT WINAPI VideoWindow_put_WindowStyleEx(IVideoWindow *iface, LONG WindowStyleEx)
4258 {
4260  IVideoWindow *pVideoWindow;
4261  HRESULT hr;
4262 
4263  TRACE("(%p/%p)->(%d)\n", This, iface, WindowStyleEx);
4264 
4265  EnterCriticalSection(&This->cs);
4266 
4267  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4268 
4269  if (hr == S_OK)
4270  hr = IVideoWindow_put_WindowStyleEx(pVideoWindow, WindowStyleEx);
4271 
4272  LeaveCriticalSection(&This->cs);
4273 
4274  return hr;
4275 }
4276 
4277 static HRESULT WINAPI VideoWindow_get_WindowStyleEx(IVideoWindow *iface, LONG *WindowStyleEx)
4278 {
4280  IVideoWindow *pVideoWindow;
4281  HRESULT hr;
4282 
4283  TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyleEx);
4284 
4285  EnterCriticalSection(&This->cs);
4286 
4287  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4288 
4289  if (hr == S_OK)
4290  hr = IVideoWindow_get_WindowStyleEx(pVideoWindow, WindowStyleEx);
4291 
4292  LeaveCriticalSection(&This->cs);
4293 
4294  return hr;
4295 }
4296 
4297 static HRESULT WINAPI VideoWindow_put_AutoShow(IVideoWindow *iface, LONG AutoShow)
4298 {
4300  IVideoWindow *pVideoWindow;
4301  HRESULT hr;
4302 
4303  TRACE("(%p/%p)->(%d)\n", This, iface, AutoShow);
4304 
4305  EnterCriticalSection(&This->cs);
4306 
4307  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4308 
4309  if (hr == S_OK)
4310  hr = IVideoWindow_put_AutoShow(pVideoWindow, AutoShow);
4311 
4312  LeaveCriticalSection(&This->cs);
4313 
4314  return hr;
4315 }
4316 
4317 static HRESULT WINAPI VideoWindow_get_AutoShow(IVideoWindow *iface, LONG *AutoShow)
4318 {
4320  IVideoWindow *pVideoWindow;
4321  HRESULT hr;
4322 
4323  TRACE("(%p/%p)->(%p)\n", This, iface, AutoShow);
4324 
4325  EnterCriticalSection(&This->cs);
4326 
4327  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4328 
4329  if (hr == S_OK)
4330  hr = IVideoWindow_get_AutoShow(pVideoWindow, AutoShow);
4331 
4332  LeaveCriticalSection(&This->cs);
4333 
4334  return hr;
4335 }
4336 
4337 static HRESULT WINAPI VideoWindow_put_WindowState(IVideoWindow *iface, LONG WindowState)
4338 {
4340  IVideoWindow *pVideoWindow;
4341  HRESULT hr;
4342 
4343  TRACE("(%p/%p)->(%d)\n", This, iface, WindowState);
4344 
4345  EnterCriticalSection(&This->cs);
4346 
4347  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4348 
4349  if (hr == S_OK)
4350  hr = IVideoWindow_put_WindowState(pVideoWindow, WindowState);
4351 
4352  LeaveCriticalSection(&This->cs);
4353 
4354  return hr;
4355 }
4356 
4357 static HRESULT WINAPI VideoWindow_get_WindowState(IVideoWindow *iface, LONG *WindowState)
4358 {
4360  IVideoWindow *pVideoWindow;
4361  HRESULT hr;
4362 
4363  TRACE("(%p/%p)->(%p)\n", This, iface, WindowState);
4364 
4365  EnterCriticalSection(&This->cs);
4366 
4367  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4368 
4369  if (hr == S_OK)
4370  hr = IVideoWindow_get_WindowState(pVideoWindow, WindowState);
4371 
4372  LeaveCriticalSection(&This->cs);
4373 
4374  return hr;
4375 }
4376 
4377 static HRESULT WINAPI VideoWindow_put_BackgroundPalette(IVideoWindow *iface, LONG BackgroundPalette)
4378 {
4380  IVideoWindow *pVideoWindow;
4381  HRESULT hr;
4382 
4383  TRACE("(%p/%p)->(%d)\n", This, iface, BackgroundPalette);
4384 
4385  EnterCriticalSection(&This->cs);
4386 
4387  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4388 
4389  if (hr == S_OK)
4390  hr = IVideoWindow_put_BackgroundPalette(pVideoWindow, BackgroundPalette);
4391 
4392  LeaveCriticalSection(&This->cs);
4393 
4394  return hr;
4395 }
4396 
4398  LONG *pBackgroundPalette)
4399 {
4401  IVideoWindow *pVideoWindow;
4402  HRESULT hr;
4403 
4404  TRACE("(%p/%p)->(%p)\n", This, iface, pBackgroundPalette);
4405 
4406  EnterCriticalSection(&This->cs);
4407 
4408  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4409 
4410  if (hr == S_OK)
4411  hr = IVideoWindow_get_BackgroundPalette(pVideoWindow, pBackgroundPalette);
4412 
4413  LeaveCriticalSection(&This->cs);
4414 
4415  return hr;
4416 }
4417 
4418 static HRESULT WINAPI VideoWindow_put_Visible(IVideoWindow *iface, LONG Visible)
4419 {
4421  IVideoWindow *pVideoWindow;
4422  HRESULT hr;
4423 
4424  TRACE("(%p/%p)->(%d)\n", This, iface, Visible);
4425 
4426  EnterCriticalSection(&This->cs);
4427 
4428  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4429 
4430  if (hr == S_OK)
4431  hr = IVideoWindow_put_Visible(pVideoWindow, Visible);
4432 
4433  LeaveCriticalSection(&This->cs);
4434 
4435  return hr;
4436 }
4437 
4438 static HRESULT WINAPI VideoWindow_get_Visible(IVideoWindow *iface, LONG *pVisible)
4439 {
4441  IVideoWindow *pVideoWindow;
4442  HRESULT hr;
4443 
4444  TRACE("(%p/%p)->(%p)\n", This, iface, pVisible);
4445 
4446  EnterCriticalSection(&This->cs);
4447 
4448  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4449 
4450  if (hr == S_OK)
4451  hr = IVideoWindow_get_Visible(pVideoWindow, pVisible);
4452 
4453  LeaveCriticalSection(&This->cs);
4454 
4455  return hr;
4456 }
4457 
4458 static HRESULT WINAPI VideoWindow_put_Left(IVideoWindow *iface, LONG Left)
4459 {
4461  IVideoWindow *pVideoWindow;
4462  HRESULT hr;
4463 
4464  TRACE("(%p/%p)->(%d)\n", This, iface, Left);
4465 
4466  EnterCriticalSection(&This->cs);
4467 
4468  hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4469 
4470  if (hr == S_OK)
4471  hr = IVideoWindow_put_Left(pVideoWindow, Left);
4472 
4473  LeaveCriticalSection(&This->cs);
4474 
4475  return hr;