]> git.sesse.net Git - vlc/blob - modules/access/dshow/filter.cpp
* configure.ac, modules/access/dshow/: brand new DirectShow input plugin.
[vlc] / modules / access / dshow / filter.cpp
1 /*****************************************************************************
2  * filter.c : DirectShow access module for vlc
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: filter.cpp,v 1.1 2003/08/24 11:17:39 gbazin Exp $
6  *
7  * Author: Gildas Bazin <gbazin@netcourrier.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/input.h>
33 #include <vlc/vout.h>
34
35 #ifndef _MSC_VER
36 #   include <wtypes.h>
37 #   include <unknwn.h>
38 #   include <ole2.h>
39 #   include <limits.h>
40 #   define _WINGDI_ 1
41 #   define AM_NOVTABLE
42 #   define _OBJBASE_H_
43 #   undef _X86_
44 #   define _I64_MAX LONG_LONG_MAX
45 #   define LONGLONG long long
46 #endif
47
48 #include <dshow.h>
49
50 #include "filter.h"
51
52 #define DEBUG_DSHOW 1
53
54 /*****************************************************************************
55  * DirectShow GUIDs.
56  * Easier to define them hear as mingw doesn't provide them all.
57  *****************************************************************************/
58 const GUID CLSID_SystemDeviceEnum = {0x62be5d10, 0x60eb, 0x11d0, {0xbd, 0x3b, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86}};
59 const GUID CLSID_VideoInputDeviceCategory = {0x860BB310,0x5D01,0x11d0,{0xBD,0x3B,0x00,0xA0,0xC9,0x11,0xCE,0x86}};
60 const GUID IID_IPropertyBag = {0x55272A00, 0x42CB, 0x11CE, {0x81, 0x35, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51}};
61 const GUID IID_ICreateDevEnum = {0x29840822, 0x5b84, 0x11d0, {0xbd, 0x3b, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86}};
62 const GUID IID_IFilterGraph = {0x56a8689f, 0x0ad4, 0x11ce, {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
63 const GUID IID_IMediaControl = {0x56a868b1, 0x0ad4, 0x11ce, {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
64 const GUID CLSID_FilterGraph = {0xe436ebb3, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
65
66 const GUID IID_IUnknown = {0x00000000, 0x0000, 0x0000, {0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46}};
67 const GUID IID_IPersist = {0x0000010c, 0x0000, 0x0000, {0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46}};
68 const GUID IID_IMediaFilter = {0x56a86899, 0x0ad4, 0x11ce, {0xb0,0x3a, 0x00,0x20,0xaf,0x0b,0xa7,0x70}};
69 const GUID IID_IBaseFilter = {0x56a86895, 0x0ad4, 0x11ce, {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
70 const GUID IID_IPin = {0x56a86891, 0x0ad4, 0x11ce, {0xb0,0x3a, 0x00,0x20,0xaf,0x0b,0xa7,0x70}};
71 const GUID IID_IMemInputPin = {0x56a8689d, 0x0ad4, 0x11ce, {0xb0,0x3a, 0x00,0x20,0xaf,0x0b,0xa7,0x70}};
72
73 const GUID IID_IEnumPins = {0x56a86892, 0x0ad4, 0x11ce, {0xb0,0x3a, 0x00,0x20,0xaf,0x0b,0xa7,0x70}};
74 const GUID IID_IEnumMediaTypes = {0x89c31040, 0x846b, 0x11ce, {0x97,0xd3, 0x00,0xaa,0x00,0x55,0x59,0x5a}};
75
76 /*
77  * MEDIATYPEs and MEDIASUBTYPEs
78  */
79 const GUID MEDIATYPE_Video = {0x73646976, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
80
81 const GUID MEDIASUBTYPE_RGB8 = {0xe436eb7a, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
82 const GUID MEDIASUBTYPE_RGB565 = {0xe436eb7b, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
83 const GUID MEDIASUBTYPE_RGB555 = {0xe436eb7c, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
84 const GUID MEDIASUBTYPE_RGB24 = {0xe436eb7d, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
85 const GUID MEDIASUBTYPE_RGB32 = {0xe436eb7e, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
86 const GUID MEDIASUBTYPE_ARGB32 = {0x773c9ac0, 0x3274, 0x11d0, {0xb7, 0x24, 0x0, 0xaa, 0x0, 0x6c, 0x1a, 0x1}};
87
88 const GUID MEDIASUBTYPE_YUYV = {0x56595559, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
89 const GUID MEDIASUBTYPE_Y411 = {0x31313459, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
90 const GUID MEDIASUBTYPE_Y41P = {0x50313459, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
91 const GUID MEDIASUBTYPE_YUY2 = {0x32595559, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
92 const GUID MEDIASUBTYPE_YVYU = {0x55595659, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
93 const GUID MEDIASUBTYPE_UYVY = {0x59565955, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
94 const GUID MEDIASUBTYPE_Y211 = {0x31313259, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
95 const GUID MEDIASUBTYPE_YV12 = {0x32315659, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
96
97 void WINAPI FreeMediaType( AM_MEDIA_TYPE& mt )
98 {
99     if( mt.cbFormat != 0 )
100     {
101         CoTaskMemFree( (PVOID)mt.pbFormat );
102         mt.cbFormat = 0;
103         mt.pbFormat = NULL;
104     }
105     if( mt.pUnk != NULL )
106     {
107         mt.pUnk->Release();
108         mt.pUnk = NULL;
109     }
110 }
111
112 HRESULT WINAPI CopyMediaType( AM_MEDIA_TYPE *pmtTarget,
113                               const AM_MEDIA_TYPE *pmtSource )
114 {
115     *pmtTarget = *pmtSource;
116     if( pmtSource->cbFormat != 0 )
117     {
118         pmtTarget->pbFormat = (PBYTE)CoTaskMemAlloc( pmtSource->cbFormat );
119         if( pmtTarget->pbFormat == NULL )
120         {
121             pmtTarget->cbFormat = 0;
122             return E_OUTOFMEMORY;
123         }
124         else
125         {
126             CopyMemory( (PVOID)pmtTarget->pbFormat, (PVOID)pmtSource->pbFormat,
127                         pmtTarget->cbFormat );
128         }
129     }
130     if( pmtTarget->pUnk != NULL )
131     {
132         pmtTarget->pUnk->AddRef();
133     }
134
135     return S_OK;
136 }
137
138 /****************************************************************************
139  * Implementation of our dummy directshow filter pin class
140  ****************************************************************************/
141
142 CapturePin::CapturePin( input_thread_t * _p_input, CaptureFilter *_p_filter )
143   : p_input( _p_input ), p_filter( _p_filter ), p_connected_pin( NULL ),
144     i_ref( 1 )
145 {
146 }
147
148 CapturePin::~CapturePin()
149 {
150 }
151
152 HRESULT CapturePin::CustomGetSample( VLCMediaSample *vlc_sample )
153 {
154     if( samples_queue.size() )
155     {
156         *vlc_sample = samples_queue.back();
157         samples_queue.pop_back();
158         return S_OK;
159     }
160     return S_FALSE;
161 }
162
163 AM_MEDIA_TYPE CapturePin::CustomGetMediaType()
164 {
165     return media_type;
166 }
167
168 /* IUnknown methods */
169 STDMETHODIMP CapturePin::QueryInterface(REFIID riid, void **ppv)
170 {
171 #ifdef DEBUG_DSHOW
172     msg_Dbg( p_input, "CapturePin::QueryInterface" );
173 #endif
174
175     if( riid == IID_IUnknown ||
176         riid == IID_IPin )
177     {
178         *ppv = (IPin *)this;
179         return NOERROR;
180     }
181     if( riid == IID_IMemInputPin )
182     {
183         *ppv = (IMemInputPin *)this;
184         return NOERROR;
185     }
186     else
187     {
188         *ppv = NULL;
189         return E_NOINTERFACE;
190     }
191 }
192 STDMETHODIMP_(ULONG) CapturePin::AddRef()
193 {
194 #ifdef DEBUG_DSHOW
195     msg_Dbg( p_input, "CapturePin::AddRef" );
196 #endif
197
198     i_ref++;
199     return NOERROR;
200 };
201 STDMETHODIMP_(ULONG) CapturePin::Release()
202 {
203 #ifdef DEBUG_DSHOW
204     msg_Dbg( p_input, "CapturePin::Release" );
205 #endif
206
207     i_ref--;
208     if( !i_ref ) delete this;
209
210     return NOERROR;
211 };
212
213 /* IPin methods */
214 STDMETHODIMP CapturePin::Connect( IPin * pReceivePin,
215                                   const AM_MEDIA_TYPE *pmt )
216 {
217 #ifdef DEBUG_DSHOW
218     msg_Dbg( p_input, "CapturePin::Connect" );
219 #endif
220     return E_NOTIMPL;
221 }
222 STDMETHODIMP CapturePin::ReceiveConnection( IPin * pConnector,
223                                             const AM_MEDIA_TYPE *pmt )
224 {
225 #ifdef DEBUG_DSHOW
226     msg_Dbg( p_input, "CapturePin::ReceiveConnection" );
227 #endif
228
229     p_connected_pin = pConnector;
230     p_connected_pin->AddRef();
231     return CopyMediaType( &media_type, pmt );
232 }
233 STDMETHODIMP CapturePin::Disconnect()
234 {
235 #ifdef DEBUG_DSHOW
236     msg_Dbg( p_input, "CapturePin::Disconnect" );
237 #endif
238
239     p_connected_pin->Release();
240     p_connected_pin = NULL;
241     FreeMediaType( media_type );
242     return S_OK;
243 }
244 STDMETHODIMP CapturePin::ConnectedTo( IPin **pPin )
245 {
246 #ifdef DEBUG_DSHOW
247     msg_Dbg( p_input, "CapturePin::ConnectedTo" );
248 #endif
249
250     p_connected_pin->AddRef();
251     *pPin = p_connected_pin;
252
253     return S_OK;
254 }
255 STDMETHODIMP CapturePin::ConnectionMediaType( AM_MEDIA_TYPE *pmt )
256 {
257 #ifdef DEBUG_DSHOW
258     msg_Dbg( p_input, "CapturePin::ConnectionMediaType" );
259 #endif
260
261     return CopyMediaType( pmt, &media_type );
262 }
263 STDMETHODIMP CapturePin::QueryPinInfo( PIN_INFO * pInfo )
264 {
265 #ifdef DEBUG_DSHOW
266     msg_Dbg( p_input, "CapturePin::QueryPinInfo" );
267 #endif
268
269     pInfo->pFilter = p_filter;
270     if( p_filter ) p_filter->AddRef();
271
272     pInfo->achName[0] = L'\0';
273
274     pInfo->dir = PINDIR_INPUT;
275
276     return NOERROR;
277 }
278 STDMETHODIMP CapturePin::QueryDirection( PIN_DIRECTION * pPinDir )
279 {
280 #ifdef DEBUG_DSHOW
281     msg_Dbg( p_input, "CapturePin::QueryDirection" );
282 #endif
283
284     *pPinDir = PINDIR_INPUT;
285     return NOERROR;
286 }
287 STDMETHODIMP CapturePin::QueryId( LPWSTR * Id )
288 {
289 #ifdef DEBUG_DSHOW
290     msg_Dbg( p_input, "CapturePin::QueryId" );
291 #endif
292     return E_NOTIMPL;
293 }
294 STDMETHODIMP CapturePin::QueryAccept( const AM_MEDIA_TYPE *pmt )
295 {
296 #ifdef DEBUG_DSHOW
297     msg_Dbg( p_input, "CapturePin::QueryAccept" );
298 #endif
299     return E_NOTIMPL;
300 }
301 STDMETHODIMP CapturePin::EnumMediaTypes( IEnumMediaTypes **ppEnum )
302 {
303 #ifdef DEBUG_DSHOW
304     msg_Dbg( p_input, "CapturePin::EnumMediaTypes" );
305 #endif
306
307     *ppEnum = new CaptureEnumMediaTypes( p_input, this, NULL );
308
309     if( *ppEnum == NULL ) return E_OUTOFMEMORY;
310
311     return NOERROR;
312 }
313 STDMETHODIMP CapturePin::QueryInternalConnections( IPin* *apPin, ULONG *nPin )
314 {
315 #ifdef DEBUG_DSHOW
316     msg_Dbg( p_input, "CapturePin::QueryInternalConnections" );
317 #endif
318     return E_NOTIMPL;
319 }
320 STDMETHODIMP CapturePin::EndOfStream( void )
321 {
322 #ifdef DEBUG_DSHOW
323     msg_Dbg( p_input, "CapturePin::EndOfStream" );
324 #endif
325     return E_NOTIMPL;
326 }
327 STDMETHODIMP CapturePin::BeginFlush( void )
328 {
329 #ifdef DEBUG_DSHOW
330     msg_Dbg( p_input, "CapturePin::BeginFlush" );
331 #endif
332     return E_NOTIMPL;
333 }
334 STDMETHODIMP CapturePin::EndFlush( void )
335 {
336 #ifdef DEBUG_DSHOW
337     msg_Dbg( p_input, "CapturePin::EndFlush" );
338 #endif
339     return E_NOTIMPL;
340 }
341 STDMETHODIMP CapturePin::NewSegment( REFERENCE_TIME tStart,
342                                      REFERENCE_TIME tStop,
343                                      double dRate )
344 {
345 #ifdef DEBUG_DSHOW
346     msg_Dbg( p_input, "CapturePin::NewSegment" );
347 #endif
348     return E_NOTIMPL;
349 }
350
351 /* IMemInputPin methods */
352 STDMETHODIMP CapturePin::GetAllocator( IMemAllocator **ppAllocator )
353 {
354 #ifdef DEBUG_DSHOW
355     msg_Dbg( p_input, "CapturePin::GetAllocator" );
356 #endif
357
358     return VFW_E_NO_ALLOCATOR;
359 }
360 STDMETHODIMP CapturePin::NotifyAllocator( IMemAllocator *pAllocator,
361                                           BOOL bReadOnly )
362 {
363 #ifdef DEBUG_DSHOW
364     msg_Dbg( p_input, "CapturePin::NotifyAllocator" );
365 #endif
366
367     return S_OK;
368 }
369 STDMETHODIMP CapturePin::GetAllocatorRequirements( ALLOCATOR_PROPERTIES *pProps )
370 {
371 #ifdef DEBUG_DSHOW
372     msg_Dbg( p_input, "CapturePin::GetAllocatorRequirements" );
373 #endif
374     return E_NOTIMPL;
375 }
376 STDMETHODIMP CapturePin::Receive( IMediaSample *pSample )
377 {
378 #ifdef DEBUG_DSHOW
379     msg_Dbg( p_input, "CapturePin::Receive" );
380 #endif
381
382     //pSample->AddRef();
383     mtime_t i_timestamp = mdate() * 10;
384     VLCMediaSample vlc_sample = {pSample, i_timestamp};
385     samples_queue.push_front( vlc_sample );
386
387     /* Make sure we don't cache too many samples */
388     if( samples_queue.size() > 10 )
389     {
390         vlc_sample = samples_queue.back();
391         samples_queue.pop_back();
392         msg_Dbg( p_input, "CapturePin::Receive trashing late input sample" );
393         // vlc_sample.p_sample->Release();
394     }
395
396     return S_OK;
397 }
398 STDMETHODIMP CapturePin::ReceiveMultiple( IMediaSample **pSamples,
399                                           long nSamples,
400                                           long *nSamplesProcessed )
401 {
402 #ifdef DEBUG_DSHOW
403     msg_Dbg( p_input, "CapturePin::ReceiveMultiple" );
404 #endif
405
406     HRESULT hr = S_OK;
407
408     *nSamplesProcessed = 0;
409     while( nSamples-- > 0 )
410     {
411          hr = Receive( pSamples[*nSamplesProcessed] );
412          if( hr != S_OK ) break;
413          (*nSamplesProcessed)++;
414     }
415     return hr;
416 }
417 STDMETHODIMP CapturePin::ReceiveCanBlock( void )
418 {
419 #ifdef DEBUG_DSHOW
420     msg_Dbg( p_input, "CapturePin::ReceiveCanBlock" );
421 #endif
422
423     return S_FALSE; /* Thou shalt not block */
424 }
425
426 /****************************************************************************
427  * Implementation of our dummy directshow filter class
428  ****************************************************************************/
429
430 CaptureFilter::CaptureFilter( input_thread_t * _p_input )
431   : p_input( _p_input ), p_pin( new CapturePin( _p_input, this ) ),
432     i_ref( 1 )
433 {
434 }
435
436 CaptureFilter::~CaptureFilter()
437 {
438     p_pin->Release();
439 }
440
441 /* IUnknown methods */
442 STDMETHODIMP CaptureFilter::QueryInterface( REFIID riid, void **ppv )
443 {
444 #ifdef DEBUG_DSHOW
445     msg_Dbg( p_input, "CaptureFilter::QueryInterface" );
446 #endif
447
448     if( riid == IID_IUnknown )
449     {
450         *ppv = (IUnknown *)this;
451         return NOERROR;
452     }
453     if( riid == IID_IPersist )
454     {
455         *ppv = (IPersist *)this;
456         return NOERROR;
457     }
458     if( riid == IID_IMediaFilter )
459     {
460         *ppv = (IMediaFilter *)this;
461         return NOERROR;
462     }
463     if( riid == IID_IBaseFilter )
464     {
465         *ppv = (IBaseFilter *)this;
466         return NOERROR;
467     }
468     else
469     {
470         *ppv = NULL;
471         return E_NOINTERFACE;
472     }
473 };
474 STDMETHODIMP_(ULONG) CaptureFilter::AddRef()
475 {
476 #ifdef DEBUG_DSHOW
477     msg_Dbg( p_input, "CaptureFilter::AddRef" );
478 #endif
479
480     i_ref++;
481     return NOERROR;
482 };
483 STDMETHODIMP_(ULONG) CaptureFilter::Release()
484 {
485 #ifdef DEBUG_DSHOW
486     msg_Dbg( p_input, "CaptureFilter::Release" );
487 #endif
488
489     i_ref--;
490     if( !i_ref ) delete this;
491
492     return NOERROR;
493 };
494
495 /* IPersist method */
496 STDMETHODIMP CaptureFilter::GetClassID(CLSID *pClsID)
497 {
498 #ifdef DEBUG_DSHOW
499     msg_Dbg( p_input, "CaptureFilter::GetClassID" );
500 #endif
501     return E_NOTIMPL;
502 };
503
504 /* IMediaFilter methods */
505 STDMETHODIMP CaptureFilter::GetState(DWORD dwMSecs, FILTER_STATE *State)
506 {
507 #ifdef DEBUG_DSHOW
508     msg_Dbg( p_input, "CaptureFilter::GetStat" );
509 #endif
510     return E_NOTIMPL;
511 };
512 STDMETHODIMP CaptureFilter::SetSyncSource(IReferenceClock *pClock)
513 {
514 #ifdef DEBUG_DSHOW
515     msg_Dbg( p_input, "CaptureFilter::SetSyncSource" );
516 #endif
517
518     return NOERROR;
519 };
520 STDMETHODIMP CaptureFilter::GetSyncSource(IReferenceClock **pClock)
521 {
522 #ifdef DEBUG_DSHOW
523     msg_Dbg( p_input, "CaptureFilter::GetSyncSource" );
524 #endif
525     return E_NOTIMPL;
526 };
527 STDMETHODIMP CaptureFilter::Stop()
528 {
529 #ifdef DEBUG_DSHOW
530     msg_Dbg( p_input, "CaptureFilter::Stop" );
531 #endif
532     return E_NOTIMPL;
533 };
534 STDMETHODIMP CaptureFilter::Pause()
535 {
536 #ifdef DEBUG_DSHOW
537     msg_Dbg( p_input, "CaptureFilter::Pause" );
538 #endif
539     return E_NOTIMPL;
540 };
541 STDMETHODIMP CaptureFilter::Run(REFERENCE_TIME tStart)
542 {
543 #ifdef DEBUG_DSHOW
544     msg_Dbg( p_input, "CaptureFilter::Run" );
545 #endif
546     return E_NOTIMPL;
547 };
548
549 /* IBaseFilter methods */
550 STDMETHODIMP CaptureFilter::EnumPins( IEnumPins ** ppEnum )
551 {
552 #ifdef DEBUG_DSHOW
553     msg_Dbg( p_input, "CaptureFilter::EnumPins" );
554 #endif
555
556     /* Create a new ref counted enumerator */
557     *ppEnum = new CaptureEnumPins( p_input, this, NULL );
558     return *ppEnum == NULL ? E_OUTOFMEMORY : NOERROR;
559 };
560 STDMETHODIMP CaptureFilter::FindPin( LPCWSTR Id, IPin ** ppPin )
561 {
562 #ifdef DEBUG_DSHOW
563     msg_Dbg( p_input, "CaptureFilter::FindPin" );
564 #endif
565     return E_NOTIMPL;
566 };
567 STDMETHODIMP CaptureFilter::QueryFilterInfo( FILTER_INFO * pInfo )
568 {
569 #ifdef DEBUG_DSHOW
570     msg_Dbg( p_input, "CaptureFilter::QueryFilterInfo" );
571 #endif
572
573     pInfo->achName[0] = L'\0';
574
575     pInfo->pGraph = p_graph;
576     if( p_graph ) p_graph->AddRef();
577
578     return NOERROR;
579 };
580 STDMETHODIMP CaptureFilter::JoinFilterGraph( IFilterGraph * pGraph,
581                                              LPCWSTR pName )
582 {
583 #ifdef DEBUG_DSHOW
584     msg_Dbg( p_input, "CaptureFilter::JoinFilterGraph" );
585 #endif
586
587     p_graph = pGraph;
588
589     return NOERROR;
590 };
591 STDMETHODIMP CaptureFilter::QueryVendorInfo( LPWSTR* pVendorInfo )
592 {
593 #ifdef DEBUG_DSHOW
594     msg_Dbg( p_input, "CaptureFilter::QueryVendorInfo" );
595 #endif
596     return E_NOTIMPL;
597 };
598
599 /* Custom methods */
600 CapturePin *CaptureFilter::CustomGetPin()
601 {
602     return p_pin;
603 }
604
605 /****************************************************************************
606  * Implementation of our dummy directshow enumpins class
607  ****************************************************************************/
608
609 CaptureEnumPins::CaptureEnumPins( input_thread_t * _p_input,
610                                   CaptureFilter *_p_filter,
611                                   CaptureEnumPins *pEnumPins )
612   : p_input( _p_input ), p_filter( _p_filter ), i_ref( 1 )
613 {
614     /* Hold a reference count on our filter */
615     p_filter->AddRef();
616
617     /* Are we creating a new enumerator */
618
619     if( pEnumPins == NULL )
620     {
621         i_position = 0;
622     }
623     else
624     {
625         i_position = pEnumPins->i_position;
626     }
627 }
628
629 CaptureEnumPins::~CaptureEnumPins()
630 {
631     p_filter->Release();
632 }
633
634 /* IUnknown methods */
635 STDMETHODIMP CaptureEnumPins::QueryInterface( REFIID riid, void **ppv )
636 {
637 #ifdef DEBUG_DSHOW
638     msg_Dbg( p_input, "CaptureEnumPins::QueryInterface" );
639 #endif
640
641     if( riid == IID_IUnknown ||
642         riid == IID_IEnumPins )
643     {
644         *ppv = (IEnumPins *)this;
645         return NOERROR;
646     }
647     else
648     {
649         *ppv = NULL;
650         return E_NOINTERFACE;
651     }
652 };
653 STDMETHODIMP_(ULONG) CaptureEnumPins::AddRef()
654 {
655 #ifdef DEBUG_DSHOW
656     msg_Dbg( p_input, "CaptureEnumPins::AddRef" );
657 #endif
658
659     i_ref++;
660     return NOERROR;
661 };
662 STDMETHODIMP_(ULONG) CaptureEnumPins::Release()
663 {
664 #ifdef DEBUG_DSHOW
665     msg_Dbg( p_input, "CaptureEnumPins::Release" );
666 #endif
667
668     i_ref--;
669     if( !i_ref ) delete this;
670
671     return NOERROR;
672 };
673
674 /* IEnumPins */
675 STDMETHODIMP CaptureEnumPins::Next( ULONG cPins, IPin ** ppPins,
676                                     ULONG * pcFetched )
677 {
678 #ifdef DEBUG_DSHOW
679     msg_Dbg( p_input, "CaptureEnumPins::Next" );
680 #endif
681
682     *pcFetched = 0;
683
684     if( i_position < 1 && cPins > 0 )
685     {
686         IPin *pPin = p_filter->CustomGetPin();
687         *ppPins = pPin;
688         pPin->AddRef();
689         *pcFetched = 1;
690         i_position++;
691         return NOERROR;
692     }
693
694     return S_FALSE;
695 };
696 STDMETHODIMP CaptureEnumPins::Skip( ULONG cPins )
697 {
698 #ifdef DEBUG_DSHOW
699     msg_Dbg( p_input, "CaptureEnumPins::Skip" );
700 #endif
701
702     if( cPins > 1 )
703     {
704         return S_FALSE;
705     }
706
707     i_position += cPins;
708     return NOERROR;
709 };
710 STDMETHODIMP CaptureEnumPins::Reset()
711 {
712 #ifdef DEBUG_DSHOW
713     msg_Dbg( p_input, "CaptureEnumPins::Reset" );
714 #endif
715
716     i_position = 0;
717     return S_OK;
718 };
719 STDMETHODIMP CaptureEnumPins::Clone( IEnumPins **ppEnum )
720 {
721 #ifdef DEBUG_DSHOW
722     msg_Dbg( p_input, "CaptureEnumPins::Clone" );
723 #endif
724
725     *ppEnum = new CaptureEnumPins( p_input, p_filter, this );
726     if( *ppEnum == NULL ) return E_OUTOFMEMORY;
727
728     return NOERROR;
729 };
730
731 /****************************************************************************
732  * Implementation of our dummy directshow enummediatypes class
733  ****************************************************************************/
734
735 CaptureEnumMediaTypes::CaptureEnumMediaTypes( input_thread_t * _p_input,
736                                   CapturePin *_p_pin,
737                                   CaptureEnumMediaTypes *pEnumMediaTypes )
738   : p_input( _p_input ), p_pin( _p_pin ), i_ref( 1 )
739 {
740     /* Hold a reference count on our filter */
741     p_pin->AddRef();
742
743     /* Are we creating a new enumerator */
744
745     if( pEnumMediaTypes == NULL )
746     {
747         i_position = 0;
748     }
749     else
750     {
751         i_position = pEnumMediaTypes->i_position;
752     }
753 }
754
755 CaptureEnumMediaTypes::~CaptureEnumMediaTypes()
756 {
757     p_pin->Release();
758 }
759
760 /* IUnknown methods */
761 STDMETHODIMP CaptureEnumMediaTypes::QueryInterface( REFIID riid, void **ppv )
762 {
763 #ifdef DEBUG_DSHOW
764     msg_Dbg( p_input, "CaptureEnumMediaTypes::QueryInterface" );
765 #endif
766
767     if( riid == IID_IUnknown ||
768         riid == IID_IEnumMediaTypes )
769     {
770         *ppv = (IEnumMediaTypes *)this;
771         return NOERROR;
772     }
773     else
774     {
775         *ppv = NULL;
776         return E_NOINTERFACE;
777     }
778 };
779 STDMETHODIMP_(ULONG) CaptureEnumMediaTypes::AddRef()
780 {
781 #ifdef DEBUG_DSHOW
782     msg_Dbg( p_input, "CaptureEnumMediaTypes::AddRef" );
783 #endif
784
785     i_ref++;
786     return NOERROR;
787 };
788 STDMETHODIMP_(ULONG) CaptureEnumMediaTypes::Release()
789 {
790 #ifdef DEBUG_DSHOW
791     msg_Dbg( p_input, "CaptureEnumMediaTypes::Release" );
792 #endif
793
794     i_ref--;
795     if( !i_ref ) delete this;
796
797     return NOERROR;
798 };
799
800 /* IEnumMediaTypes */
801 STDMETHODIMP CaptureEnumMediaTypes::Next( ULONG cMediaTypes,
802                                           AM_MEDIA_TYPE ** ppMediaTypes,
803                                           ULONG * pcFetched )
804 {
805 #ifdef DEBUG_DSHOW
806     msg_Dbg( p_input, "CaptureEnumMediaTypes::Next" );
807 #endif
808
809     *pcFetched = 0;
810
811 #if 0
812     if( i_position < 1 && cMediaTypes > 0 )
813     {
814         IPin *pPin = p_pin->CustomGetPin();
815         *ppMediaTypes = pPin;
816         pPin->AddRef();
817         *pcFetched = 1;
818         i_position++;
819         return NOERROR;
820     }
821 #endif
822
823     return S_FALSE;
824 };
825 STDMETHODIMP CaptureEnumMediaTypes::Skip( ULONG cMediaTypes )
826 {
827 #ifdef DEBUG_DSHOW
828     msg_Dbg( p_input, "CaptureEnumMediaTypes::Skip" );
829 #endif
830
831     if( cMediaTypes > 1 )
832     {
833         return S_FALSE;
834     }
835
836     i_position += cMediaTypes;
837     return NOERROR;
838 };
839 STDMETHODIMP CaptureEnumMediaTypes::Reset()
840 {
841 #ifdef DEBUG_DSHOW
842     msg_Dbg( p_input, "CaptureEnumMediaTypes::Reset" );
843 #endif
844
845     i_position = 0;
846     return S_OK;
847 };
848 STDMETHODIMP CaptureEnumMediaTypes::Clone( IEnumMediaTypes **ppEnum )
849 {
850 #ifdef DEBUG_DSHOW
851     msg_Dbg( p_input, "CaptureEnumMediaTypes::Clone" );
852 #endif
853
854     *ppEnum = new CaptureEnumMediaTypes( p_input, p_pin, this );
855     if( *ppEnum == NULL ) return E_OUTOFMEMORY;
856
857     return NOERROR;
858 };