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