]> git.sesse.net Git - vlc/blob - modules/access/dshow/filter.cpp
ALSA: rewrite capture plugin
[vlc] / modules / access / dshow / filter.cpp
1 /*****************************************************************************
2  * filter.cpp : DirectShow access module for vlc
3  *****************************************************************************
4  * Copyright (C) 2002-2010 the VideoLAN team
5  * $Id$
6  *
7  * Author: Gildas Bazin <gbazin@videolan.org>
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_fourcc.h>
34
35 #ifndef _MSC_VER
36     /* Work-around a bug in w32api-2.5 */
37 #   define QACONTAINERFLAGS QACONTAINERFLAGS_SOMETHINGELSE
38 #endif
39
40 #include "access.h"
41 #include "filter.h"
42 #include "vlc_dshow.h"
43
44 #include <initguid.h>
45 DEFINE_GUID(MEDIASUBTYPE_HDYC ,0x43594448 /* CYDH */ , 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
46 DEFINE_GUID(MEDIASUBTYPE_DIVX ,0x58564944 /* XVID */ , 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
47
48
49 #define DEBUG_DSHOW 1
50
51 #define FILTER_NAME  L"VideoLAN Capture Filter"
52 #define PIN_NAME     L"Capture"
53
54 void WINAPI FreeMediaType( AM_MEDIA_TYPE& mt )
55 {
56     if( mt.cbFormat != 0 )
57     {
58         CoTaskMemFree( (PVOID)mt.pbFormat );
59         mt.cbFormat = 0;
60         mt.pbFormat = NULL;
61     }
62     if( mt.pUnk != NULL )
63     {
64         mt.pUnk->Release();
65         mt.pUnk = NULL;
66     }
67 }
68
69 HRESULT WINAPI CopyMediaType( AM_MEDIA_TYPE *pmtTarget,
70                               const AM_MEDIA_TYPE *pmtSource )
71 {
72     *pmtTarget = *pmtSource;
73
74     if( !pmtSource || !pmtTarget ) return S_FALSE;
75
76     if( pmtSource->cbFormat && pmtSource->pbFormat )
77     {
78         pmtTarget->pbFormat = (PBYTE)CoTaskMemAlloc( pmtSource->cbFormat );
79         if( pmtTarget->pbFormat == NULL )
80         {
81             pmtTarget->cbFormat = 0;
82             return E_OUTOFMEMORY;
83         }
84         else
85         {
86             CopyMemory( (PVOID)pmtTarget->pbFormat, (PVOID)pmtSource->pbFormat,
87                         pmtTarget->cbFormat );
88         }
89     }
90     if( pmtTarget->pUnk != NULL )
91     {
92         pmtTarget->pUnk->AddRef();
93     }
94
95     return S_OK;
96 }
97
98 int GetFourCCFromMediaType( const AM_MEDIA_TYPE &media_type )
99 {
100     int i_fourcc = 0;
101
102     if( media_type.majortype == MEDIATYPE_Video )
103     {
104         /* currently only support this type of video info format */
105         if( 1 /* media_type.formattype == FORMAT_VideoInfo */ )
106         {
107             /* Packed RGB formats */
108             if( media_type.subtype == MEDIASUBTYPE_RGB1 )
109                i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '1' );
110             else if( media_type.subtype == MEDIASUBTYPE_RGB4 )
111                i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '4' );
112             else if( media_type.subtype == MEDIASUBTYPE_RGB8 )
113                i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '8' );
114             else if( media_type.subtype == MEDIASUBTYPE_RGB555 )
115                i_fourcc = VLC_CODEC_RGB15;
116             else if( media_type.subtype == MEDIASUBTYPE_RGB565 )
117                i_fourcc = VLC_CODEC_RGB16;
118             else if( media_type.subtype == MEDIASUBTYPE_RGB24 )
119                i_fourcc = VLC_CODEC_RGB24;
120             else if( media_type.subtype == MEDIASUBTYPE_RGB32 )
121                i_fourcc = VLC_CODEC_RGB32;
122             else if( media_type.subtype == MEDIASUBTYPE_ARGB32 )
123                i_fourcc = VLC_CODEC_RGBA;
124
125             /* Planar YUV formats */
126             else if( media_type.subtype == MEDIASUBTYPE_I420 )
127                i_fourcc = VLC_CODEC_I420;
128             else if( media_type.subtype == MEDIASUBTYPE_Y41P )
129                i_fourcc = VLC_CODEC_I411;
130             else if( media_type.subtype == MEDIASUBTYPE_YV12 )
131                i_fourcc = VLC_CODEC_YV12;
132             else if( media_type.subtype == MEDIASUBTYPE_IYUV )
133                i_fourcc = VLC_CODEC_YV12;
134             else if( media_type.subtype == MEDIASUBTYPE_YVU9 )
135                i_fourcc = VLC_CODEC_I410;
136
137             /* Packed YUV formats */
138             else if( media_type.subtype == MEDIASUBTYPE_YVYU )
139                i_fourcc = VLC_CODEC_YVYU;
140             else if( media_type.subtype == MEDIASUBTYPE_YUYV )
141                i_fourcc = VLC_CODEC_YUYV;
142             else if( media_type.subtype == MEDIASUBTYPE_Y411 )
143                i_fourcc = VLC_FOURCC( 'I', '4', '1', 'N' );
144             else if( media_type.subtype == MEDIASUBTYPE_Y211 )
145                i_fourcc = VLC_CODEC_Y211;
146             else if( media_type.subtype == MEDIASUBTYPE_YUY2 )
147                i_fourcc = VLC_CODEC_YUYV;
148             else if( media_type.subtype == MEDIASUBTYPE_UYVY )
149                i_fourcc = VLC_CODEC_UYVY;
150             /* HDYC uses UYVY sample positions but Rec709 colourimetry */
151             /* FIXME: When VLC understands colourspace, something will need
152              * to be added / changed here. Until then, just make it behave
153              * like UYVY */
154             else if( media_type.subtype == MEDIASUBTYPE_HDYC )
155                 i_fourcc = VLC_CODEC_UYVY;
156
157             /* MPEG2 video elementary stream */
158             else if( media_type.subtype == MEDIASUBTYPE_MPEG2_VIDEO )
159                i_fourcc = VLC_CODEC_MPGV;
160
161             /* DivX video */
162             else if( media_type.subtype == MEDIASUBTYPE_DIVX )
163                i_fourcc = VLC_CODEC_MP4V;
164
165             /* DV formats */
166             else if( media_type.subtype == MEDIASUBTYPE_dvsl )
167                i_fourcc = VLC_CODEC_DV;
168             else if( media_type.subtype == MEDIASUBTYPE_dvsd )
169                i_fourcc = VLC_CODEC_DV;
170             else if( media_type.subtype == MEDIASUBTYPE_dvhd )
171                i_fourcc = VLC_CODEC_DV;
172
173             /* MJPEG format */
174             else if( media_type.subtype == MEDIASUBTYPE_MJPG )
175                 i_fourcc = VLC_CODEC_MJPG;
176
177         }
178     }
179     else if( media_type.majortype == MEDIATYPE_Audio )
180     {
181         /* currently only support this type of audio info format */
182         if( media_type.formattype == FORMAT_WaveFormatEx )
183         {
184             if( media_type.subtype == MEDIASUBTYPE_PCM )
185                 i_fourcc = VLC_FOURCC( 'a', 'r', 'a', 'w' );
186             else if( media_type.subtype == MEDIASUBTYPE_IEEE_FLOAT )
187                 i_fourcc = VLC_CODEC_FL32;
188         }
189     }
190     else if( media_type.majortype == MEDIATYPE_Stream )
191     {
192         if( media_type.subtype == MEDIASUBTYPE_MPEG2_PROGRAM )
193             i_fourcc = VLC_FOURCC( 'm', 'p', '2', 'p' );
194         else if( media_type.subtype == MEDIASUBTYPE_MPEG2_TRANSPORT )
195             i_fourcc = VLC_FOURCC( 'm', 'p', '2', 't' );
196     }
197
198     return i_fourcc;
199 }
200
201 /****************************************************************************
202  * Implementation of our dummy directshow filter pin class
203  ****************************************************************************/
204
205 CapturePin::CapturePin( vlc_object_t *_p_input, access_sys_t *_p_sys,
206                         CaptureFilter *_p_filter,
207                         AM_MEDIA_TYPE *mt, size_t mt_count )
208   : p_input( _p_input ), p_sys( _p_sys ), p_filter( _p_filter ),
209     p_connected_pin( NULL ),  media_types(mt), media_type_count(mt_count),
210     i_ref( 1 )
211 {
212     cx_media_type.majortype = mt[0].majortype;
213     cx_media_type.subtype   = GUID_NULL;
214     cx_media_type.pbFormat  = NULL;
215     cx_media_type.cbFormat  = 0;
216     cx_media_type.pUnk      = NULL;
217 }
218
219 CapturePin::~CapturePin()
220 {
221 #ifdef DEBUG_DSHOW
222     msg_Dbg( p_input, "CapturePin::~CapturePin" );
223 #endif
224     for( size_t c=0; c<media_type_count; c++ )
225     {
226         FreeMediaType(media_types[c]);
227     }
228     FreeMediaType(cx_media_type);
229 }
230
231 /**
232  * Returns the complete queue of samples that have been received so far.
233  * Lock the p_sys->lock before calling this function.
234  * @param samples_queue [out] Empty queue that will get all elements from
235  * the pin queue.
236  * @return S_OK if a sample was available, S_FALSE if no sample was
237  * available
238  */
239 HRESULT CapturePin::CustomGetSamples( deque<VLCMediaSample> &external_queue )
240 {
241 #if 0 //def DEBUG_DSHOW
242     msg_Dbg( p_input, "CapturePin::CustomGetSamples: %d samples in the queue", samples_queue.size());
243 #endif
244
245     if( !samples_queue.empty() )
246     {
247         external_queue.swap(samples_queue);
248         return S_OK;
249     }
250     return S_FALSE;
251 }
252
253 /**
254  * Returns a sample from its sample queue. Proper locking must be done prior
255  * to this call. Current dshow code protects the access to any sample queue
256  * (audio and video) with the p_sys->lock
257  * @param vlc_sample [out] Address of a sample if sucessfull. Undefined
258  * otherwise.
259  * @return S_OK if a sample was available, S_FALSE if no sample was
260  * available
261  */
262 HRESULT CapturePin::CustomGetSample( VLCMediaSample *vlc_sample )
263 {
264 #if 0 //def DEBUG_DSHOW
265     msg_Dbg( p_input, "CapturePin::CustomGetSample" );
266 #endif
267
268     if( !samples_queue.empty() )
269     {
270         *vlc_sample = samples_queue.back();
271         samples_queue.pop_back();
272         return S_OK;
273     }
274     return S_FALSE;
275 }
276
277 AM_MEDIA_TYPE &CapturePin::CustomGetMediaType()
278 {
279     return cx_media_type;
280 }
281
282 /* IUnknown methods */
283 STDMETHODIMP CapturePin::QueryInterface(REFIID riid, void **ppv)
284 {
285 #ifdef DEBUG_DSHOW_L1
286     msg_Dbg( p_input, "CapturePin::QueryInterface" );
287 #endif
288
289     if( riid == IID_IUnknown ||
290         riid == IID_IPin )
291     {
292         AddRef();
293         *ppv = (IPin *)this;
294         return NOERROR;
295     }
296     if( riid == IID_IMemInputPin )
297     {
298         AddRef();
299         *ppv = (IMemInputPin *)this;
300         return NOERROR;
301     }
302     else
303     {
304 #ifdef DEBUG_DSHOW_L1
305         msg_Dbg( p_input, "CapturePin::QueryInterface() failed for: "
306                  "%04X-%02X-%02X-%02X%02X%02X%02X%02X%02X%02X%02X",
307                  (int)riid.Data1, (int)riid.Data2, (int)riid.Data3,
308                  static_cast<int>(riid.Data4[0]), (int)riid.Data4[1],
309                  (int)riid.Data4[2], (int)riid.Data4[3],
310                  (int)riid.Data4[4], (int)riid.Data4[5],
311                  (int)riid.Data4[6], (int)riid.Data4[7] );
312 #endif
313         *ppv = NULL;
314         return E_NOINTERFACE;
315     }
316 }
317
318 STDMETHODIMP_(ULONG) CapturePin::AddRef()
319 {
320 #ifdef DEBUG_DSHOW_L1
321     msg_Dbg( p_input, "CapturePin::AddRef (ref: %i)", i_ref );
322 #endif
323
324     return i_ref++;
325 };
326 STDMETHODIMP_(ULONG) CapturePin::Release()
327 {
328 #ifdef DEBUG_DSHOW_L1
329     msg_Dbg( p_input, "CapturePin::Release (ref: %i)", i_ref );
330 #endif
331
332     if( !InterlockedDecrement(&i_ref) ) delete this;
333
334     return 0;
335 };
336
337 /* IPin methods */
338 STDMETHODIMP CapturePin::Connect( IPin *,
339                                   const AM_MEDIA_TYPE *pmt )
340 {
341     if( State_Running == p_filter->state )
342     {
343         msg_Dbg( p_input, "CapturePin::Connect [not stopped]" );
344         return VFW_E_NOT_STOPPED;
345     }
346
347     if( p_connected_pin )
348     {
349         msg_Dbg( p_input, "CapturePin::Connect [already connected]" );
350         return VFW_E_ALREADY_CONNECTED;
351     }
352
353     if( !pmt ) return S_OK;
354  
355     if( GUID_NULL != pmt->majortype &&
356         media_types[0].majortype != pmt->majortype )
357     {
358         msg_Dbg( p_input, "CapturePin::Connect [media major type mismatch]" );
359         return S_FALSE;
360     }
361
362     if( GUID_NULL != pmt->subtype && !GetFourCCFromMediaType(*pmt) )
363     {
364         msg_Dbg( p_input, "CapturePin::Connect [media subtype type "
365                  "not supported]" );
366         return S_FALSE;
367     }
368
369     if( pmt->pbFormat && pmt->majortype == MEDIATYPE_Video  )
370     {
371         if( !((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biHeight ||
372             !((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biWidth )
373         {
374             msg_Dbg( p_input, "CapturePin::Connect "
375                      "[video width/height == 0 ]" );
376             return S_FALSE;
377         }
378     }
379
380     msg_Dbg( p_input, "CapturePin::Connect [OK]" );
381     return S_OK;
382 }
383 STDMETHODIMP CapturePin::ReceiveConnection( IPin * pConnector,
384                                             const AM_MEDIA_TYPE *pmt )
385 {
386     if( State_Stopped != p_filter->state )
387     {
388         msg_Dbg( p_input, "CapturePin::ReceiveConnection [not stopped]" );
389         return VFW_E_NOT_STOPPED;
390     }
391
392     if( !pConnector || !pmt )
393     {
394         msg_Dbg( p_input, "CapturePin::ReceiveConnection [null pointer]" );
395         return E_POINTER;
396     }
397
398     if( p_connected_pin )
399     {
400         msg_Dbg( p_input, "CapturePin::ReceiveConnection [already connected]");
401         return VFW_E_ALREADY_CONNECTED;
402     }
403
404     if( S_OK != QueryAccept(pmt) )
405     {
406         msg_Dbg( p_input, "CapturePin::ReceiveConnection "
407                  "[media type not accepted]" );
408         return VFW_E_TYPE_NOT_ACCEPTED;
409     }
410
411     msg_Dbg( p_input, "CapturePin::ReceiveConnection [OK]" );
412
413     p_connected_pin = pConnector;
414     p_connected_pin->AddRef();
415
416     FreeMediaType( cx_media_type );
417     return CopyMediaType( &cx_media_type, pmt );
418 }
419 STDMETHODIMP CapturePin::Disconnect()
420 {
421     if( ! p_connected_pin )
422     {
423         msg_Dbg( p_input, "CapturePin::Disconnect [not connected]" );
424         return S_FALSE;
425     }
426
427     msg_Dbg( p_input, "CapturePin::Disconnect [OK]" );
428
429     /* samples_queue was already flushed in EndFlush() */
430
431     p_connected_pin->Release();
432     p_connected_pin = NULL;
433     //FreeMediaType( cx_media_type );
434     //cx_media_type.subtype = GUID_NULL;
435
436     return S_OK;
437 }
438 STDMETHODIMP CapturePin::ConnectedTo( IPin **pPin )
439 {
440     if( !p_connected_pin )
441     {
442         msg_Dbg( p_input, "CapturePin::ConnectedTo [not connected]" );
443         return VFW_E_NOT_CONNECTED;
444     }
445
446     p_connected_pin->AddRef();
447     *pPin = p_connected_pin;
448
449     msg_Dbg( p_input, "CapturePin::ConnectedTo [OK]" );
450
451     return S_OK;
452 }
453 STDMETHODIMP CapturePin::ConnectionMediaType( AM_MEDIA_TYPE *pmt )
454 {
455     if( !p_connected_pin )
456     {
457         msg_Dbg( p_input, "CapturePin::ConnectionMediaType [not connected]" );
458         return VFW_E_NOT_CONNECTED;
459     }
460
461     return CopyMediaType( pmt, &cx_media_type );
462 }
463 STDMETHODIMP CapturePin::QueryPinInfo( PIN_INFO * pInfo )
464 {
465 #ifdef DEBUG_DSHOW
466     msg_Dbg( p_input, "CapturePin::QueryPinInfo" );
467 #endif
468
469     pInfo->pFilter = p_filter;
470     if( p_filter ) p_filter->AddRef();
471
472     memcpy(pInfo->achName, PIN_NAME, sizeof(PIN_NAME));
473     pInfo->dir = PINDIR_INPUT;
474
475     return NOERROR;
476 }
477 STDMETHODIMP CapturePin::QueryDirection( PIN_DIRECTION * pPinDir )
478 {
479 #ifdef DEBUG_DSHOW
480     msg_Dbg( p_input, "CapturePin::QueryDirection" );
481 #endif
482
483     *pPinDir = PINDIR_INPUT;
484     return NOERROR;
485 }
486 STDMETHODIMP CapturePin::QueryId( LPWSTR * Id )
487 {
488 #ifdef DEBUG_DSHOW
489     msg_Dbg( p_input, "CapturePin::QueryId" );
490 #endif
491
492     *Id = (LPWSTR)L"VLC Capture Pin";
493
494     return S_OK;
495 }
496 STDMETHODIMP CapturePin::QueryAccept( const AM_MEDIA_TYPE *pmt )
497 {
498     if( State_Stopped != p_filter->state )
499     {
500         msg_Dbg( p_input, "CapturePin::QueryAccept [not stopped]" );
501         return S_FALSE;
502     }
503
504     if( media_types[0].majortype != pmt->majortype )
505     {
506         msg_Dbg( p_input, "CapturePin::QueryAccept [media type mismatch]" );
507         return S_FALSE;
508     }
509
510     int i_fourcc = GetFourCCFromMediaType(*pmt);
511     if( !i_fourcc )
512     {
513         msg_Dbg( p_input, "CapturePin::QueryAccept "
514                  "[media type not supported]" );
515         return S_FALSE;
516     }
517
518     if( pmt->majortype == MEDIATYPE_Video )
519     {
520         if( pmt->pbFormat &&
521             ( (((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biHeight == 0) ||
522               (((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biWidth == 0) ) )
523         {
524             msg_Dbg( p_input, "CapturePin::QueryAccept [video size wxh == 0]");
525             return S_FALSE;
526         }
527
528         msg_Dbg( p_input, "CapturePin::QueryAccept [OK] "
529                  "(width=%ld, height=%ld, chroma=%4.4s, fps=%f)",
530                  ((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biWidth,
531                  ((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biHeight,
532                  (char *)&i_fourcc,
533          10000000.0f/((float)((VIDEOINFOHEADER *)pmt->pbFormat)->AvgTimePerFrame) );
534     }
535     else if( pmt->majortype == MEDIATYPE_Audio )
536     {
537         msg_Dbg( p_input, "CapturePin::QueryAccept [OK] (channels=%d, "
538                  "samples/sec=%lu, bits/samples=%d, format=%4.4s)",
539                  ((WAVEFORMATEX *)pmt->pbFormat)->nChannels,
540                  ((WAVEFORMATEX *)pmt->pbFormat)->nSamplesPerSec,
541                  ((WAVEFORMATEX *)pmt->pbFormat)->wBitsPerSample,
542                  (char *)&i_fourcc );
543     }
544     else
545     {
546         msg_Dbg( p_input, "CapturePin::QueryAccept [OK] (stream format=%4.4s)",
547                  (char *)&i_fourcc );
548     }
549
550     if( p_connected_pin )
551     {
552         FreeMediaType( cx_media_type );
553         CopyMediaType( &cx_media_type, pmt );
554     }
555
556     return S_OK;
557 }
558 STDMETHODIMP CapturePin::EnumMediaTypes( IEnumMediaTypes **ppEnum )
559 {
560 #ifdef DEBUG_DSHOW_L1
561     msg_Dbg( p_input, "CapturePin::EnumMediaTypes" );
562 #endif
563
564     *ppEnum = new CaptureEnumMediaTypes( p_input, this, NULL );
565
566     if( *ppEnum == NULL ) return E_OUTOFMEMORY;
567
568     return NOERROR;
569 }
570 STDMETHODIMP CapturePin::QueryInternalConnections( IPin**, ULONG * )
571 {
572 #ifdef DEBUG_DSHOW_L1
573     msg_Dbg( p_input, "CapturePin::QueryInternalConnections" );
574 #endif
575     return E_NOTIMPL;
576 }
577 STDMETHODIMP CapturePin::EndOfStream( void )
578 {
579 #ifdef DEBUG_DSHOW
580     msg_Dbg( p_input, "CapturePin::EndOfStream" );
581 #endif
582     return S_OK;
583 }
584 STDMETHODIMP CapturePin::BeginFlush( void )
585 {
586 #ifdef DEBUG_DSHOW
587     msg_Dbg( p_input, "CapturePin::BeginFlush" );
588 #endif
589     return S_OK;
590 }
591 STDMETHODIMP CapturePin::EndFlush( void )
592 {
593 #ifdef DEBUG_DSHOW
594     msg_Dbg( p_input, "CapturePin::EndFlush" );
595 #endif
596
597     VLCMediaSample vlc_sample;
598
599     vlc_mutex_lock( &p_sys->lock );
600     while( !samples_queue.empty() )
601     {
602         vlc_sample = samples_queue.back();
603         samples_queue.pop_back();
604         vlc_sample.p_sample->Release();
605     }
606     vlc_mutex_unlock( &p_sys->lock );
607
608     return S_OK;
609 }
610 STDMETHODIMP CapturePin::NewSegment( REFERENCE_TIME, REFERENCE_TIME, double )
611 {
612 #ifdef DEBUG_DSHOW
613     msg_Dbg( p_input, "CapturePin::NewSegment" );
614 #endif
615     return S_OK;
616 }
617
618 /* IMemInputPin methods */
619 STDMETHODIMP CapturePin::GetAllocator( IMemAllocator ** )
620 {
621 #ifdef DEBUG_DSHOW
622     msg_Dbg( p_input, "CapturePin::GetAllocator" );
623 #endif
624
625     return VFW_E_NO_ALLOCATOR;
626 }
627 STDMETHODIMP CapturePin::NotifyAllocator( IMemAllocator *, BOOL )
628 {
629 #ifdef DEBUG_DSHOW
630     msg_Dbg( p_input, "CapturePin::NotifyAllocator" );
631 #endif
632
633     return S_OK;
634 }
635 STDMETHODIMP CapturePin::GetAllocatorRequirements( ALLOCATOR_PROPERTIES * )
636 {
637 #ifdef DEBUG_DSHOW
638     msg_Dbg( p_input, "CapturePin::GetAllocatorRequirements" );
639 #endif
640
641     return E_NOTIMPL;
642 }
643 STDMETHODIMP CapturePin::Receive( IMediaSample *pSample )
644 {
645 #if 0 //def DEBUG_DSHOW
646     msg_Dbg( p_input, "CapturePin::Receive" );
647 #endif
648
649     pSample->AddRef();
650     mtime_t i_timestamp = mdate() * 10;
651     VLCMediaSample vlc_sample = {pSample, i_timestamp};
652
653     vlc_mutex_lock( &p_sys->lock );
654     samples_queue.push_front( vlc_sample );
655
656     /* Make sure we don't cache too many samples */
657     if( samples_queue.size() > 10 )
658     {
659         vlc_sample = samples_queue.back();
660         samples_queue.pop_back();
661         msg_Dbg( p_input, "CapturePin::Receive trashing late input sample" );
662         vlc_sample.p_sample->Release();
663     }
664
665     vlc_cond_signal( &p_sys->wait );
666     vlc_mutex_unlock( &p_sys->lock );
667
668     return S_OK;
669 }
670 STDMETHODIMP CapturePin::ReceiveMultiple( IMediaSample **pSamples,
671                                           long nSamples,
672                                           long *nSamplesProcessed )
673 {
674     HRESULT hr = S_OK;
675
676     *nSamplesProcessed = 0;
677     while( nSamples-- > 0 )
678     {
679          hr = Receive( pSamples[*nSamplesProcessed] );
680          if( hr != S_OK ) break;
681          (*nSamplesProcessed)++;
682     }
683     return hr;
684 }
685 STDMETHODIMP CapturePin::ReceiveCanBlock( void )
686 {
687 #ifdef DEBUG_DSHOW
688     msg_Dbg( p_input, "CapturePin::ReceiveCanBlock" );
689 #endif
690
691     return S_FALSE; /* Thou shalt not block */
692 }
693
694 /****************************************************************************
695  * Implementation of our dummy directshow filter class
696  ****************************************************************************/
697 CaptureFilter::CaptureFilter( vlc_object_t *_p_input, access_sys_t *p_sys,
698                               AM_MEDIA_TYPE *mt, size_t mt_count )
699   : p_input( _p_input ),
700     p_pin( new CapturePin( _p_input, p_sys, this, mt, mt_count ) ),
701     state( State_Stopped ), i_ref( 1 )
702 {
703 }
704
705 CaptureFilter::~CaptureFilter()
706 {
707 #ifdef DEBUG_DSHOW
708     msg_Dbg( p_input, "CaptureFilter::~CaptureFilter" );
709 #endif
710     p_pin->Release();
711 }
712
713 /* IUnknown methods */
714 STDMETHODIMP CaptureFilter::QueryInterface( REFIID riid, void **ppv )
715 {
716 #ifdef DEBUG_DSHOW_L1
717     msg_Dbg( p_input, "CaptureFilter::QueryInterface" );
718 #endif
719
720     if( riid == IID_IUnknown )
721     {
722         AddRef();
723         *ppv = (IUnknown *)this;
724         return NOERROR;
725     }
726     if( riid == IID_IPersist )
727     {
728         AddRef();
729         *ppv = (IPersist *)this;
730         return NOERROR;
731     }
732     if( riid == IID_IMediaFilter )
733     {
734         AddRef();
735         *ppv = (IMediaFilter *)this;
736         return NOERROR;
737     }
738     if( riid == IID_IBaseFilter )
739     {
740         AddRef();
741         *ppv = (IBaseFilter *)this;
742         return NOERROR;
743     }
744     else
745     {
746 #ifdef DEBUG_DSHOW_L1
747         msg_Dbg( p_input, "CaptureFilter::QueryInterface() failed for: "
748                  "%04X-%02X-%02X-%02X%02X%02X%02X%02X%02X%02X%02X",
749                  (int)riid.Data1, (int)riid.Data2, (int)riid.Data3,
750                  static_cast<int>(riid.Data4[0]), (int)riid.Data4[1],
751                  (int)riid.Data4[2], (int)riid.Data4[3],
752                  (int)riid.Data4[4], (int)riid.Data4[5],
753                  (int)riid.Data4[6], (int)riid.Data4[7] );
754 #endif
755         *ppv = NULL;
756         return E_NOINTERFACE;
757     }
758 };
759 STDMETHODIMP_(ULONG) CaptureFilter::AddRef()
760 {
761 #ifdef DEBUG_DSHOW_L1
762     msg_Dbg( p_input, "CaptureFilter::AddRef (ref: %i)", i_ref );
763 #endif
764
765     return i_ref++;
766 };
767 STDMETHODIMP_(ULONG) CaptureFilter::Release()
768 {
769 #ifdef DEBUG_DSHOW_L1
770     msg_Dbg( p_input, "CaptureFilter::Release (ref: %i)", i_ref );
771 #endif
772
773     if( !InterlockedDecrement(&i_ref) ) delete this;
774
775     return 0;
776 };
777
778 /* IPersist method */
779 STDMETHODIMP CaptureFilter::GetClassID(CLSID *)
780 {
781 #ifdef DEBUG_DSHOW
782     msg_Dbg( p_input, "CaptureFilter::GetClassID" );
783 #endif
784     return E_NOTIMPL;
785 };
786
787 /* IMediaFilter methods */
788 STDMETHODIMP CaptureFilter::GetState(DWORD, FILTER_STATE *State)
789 {
790 #ifdef DEBUG_DSHOW
791     msg_Dbg( p_input, "CaptureFilter::GetState %i", state );
792 #endif
793
794     *State = state;
795     return S_OK;
796 };
797 STDMETHODIMP CaptureFilter::SetSyncSource(IReferenceClock *)
798 {
799 #ifdef DEBUG_DSHOW
800     msg_Dbg( p_input, "CaptureFilter::SetSyncSource" );
801 #endif
802
803     return S_OK;
804 };
805 STDMETHODIMP CaptureFilter::GetSyncSource(IReferenceClock **pClock)
806 {
807 #ifdef DEBUG_DSHOW
808     msg_Dbg( p_input, "CaptureFilter::GetSyncSource" );
809 #endif
810
811     *pClock = NULL;
812     return NOERROR;
813 };
814 STDMETHODIMP CaptureFilter::Stop()
815 {
816 #ifdef DEBUG_DSHOW
817     msg_Dbg( p_input, "CaptureFilter::Stop" );
818 #endif
819
820     p_pin->EndFlush();
821
822     state = State_Stopped;
823     return S_OK;
824 };
825 STDMETHODIMP CaptureFilter::Pause()
826 {
827 #ifdef DEBUG_DSHOW
828     msg_Dbg( p_input, "CaptureFilter::Pause" );
829 #endif
830
831     state = State_Paused;
832     return S_OK;
833 };
834 STDMETHODIMP CaptureFilter::Run(REFERENCE_TIME)
835 {
836 #ifdef DEBUG_DSHOW
837     msg_Dbg( p_input, "CaptureFilter::Run" );
838 #endif
839
840     state = State_Running;
841     return S_OK;
842 };
843
844 /* IBaseFilter methods */
845 STDMETHODIMP CaptureFilter::EnumPins( IEnumPins ** ppEnum )
846 {
847 #ifdef DEBUG_DSHOW
848     msg_Dbg( p_input, "CaptureFilter::EnumPins" );
849 #endif
850
851     /* Create a new ref counted enumerator */
852     *ppEnum = new CaptureEnumPins( p_input, this, NULL );
853     return *ppEnum == NULL ? E_OUTOFMEMORY : NOERROR;
854 };
855 STDMETHODIMP CaptureFilter::FindPin( LPCWSTR, IPin ** )
856 {
857 #ifdef DEBUG_DSHOW
858     msg_Dbg( p_input, "CaptureFilter::FindPin" );
859 #endif
860     return E_NOTIMPL;
861 };
862 STDMETHODIMP CaptureFilter::QueryFilterInfo( FILTER_INFO * pInfo )
863 {
864 #ifdef DEBUG_DSHOW
865     msg_Dbg( p_input, "CaptureFilter::QueryFilterInfo" );
866 #endif
867
868     memcpy(pInfo->achName, FILTER_NAME, sizeof(FILTER_NAME));
869
870     pInfo->pGraph = p_graph;
871     if( p_graph ) p_graph->AddRef();
872
873     return NOERROR;
874 };
875 STDMETHODIMP CaptureFilter::JoinFilterGraph( IFilterGraph * pGraph,
876                                              LPCWSTR )
877 {
878 #ifdef DEBUG_DSHOW
879     msg_Dbg( p_input, "CaptureFilter::JoinFilterGraph" );
880 #endif
881
882     p_graph = pGraph;
883
884     return NOERROR;
885 };
886 STDMETHODIMP CaptureFilter::QueryVendorInfo( LPWSTR* )
887 {
888 #ifdef DEBUG_DSHOW
889     msg_Dbg( p_input, "CaptureFilter::QueryVendorInfo" );
890 #endif
891     return E_NOTIMPL;
892 };
893
894 /* Custom methods */
895 CapturePin *CaptureFilter::CustomGetPin()
896 {
897     return p_pin;
898 }
899
900 /****************************************************************************
901  * Implementation of our dummy directshow enumpins class
902  ****************************************************************************/
903
904 CaptureEnumPins::CaptureEnumPins( vlc_object_t *_p_input,
905                                   CaptureFilter *_p_filter,
906                                   CaptureEnumPins *pEnumPins )
907   : p_input( _p_input ), p_filter( _p_filter ), i_ref( 1 )
908 {
909     /* Hold a reference count on our filter */
910     p_filter->AddRef();
911
912     /* Are we creating a new enumerator */
913
914     if( pEnumPins == NULL )
915     {
916         i_position = 0;
917     }
918     else
919     {
920         i_position = pEnumPins->i_position;
921     }
922 }
923
924 CaptureEnumPins::~CaptureEnumPins()
925 {
926 #ifdef DEBUG_DSHOW_L1
927     msg_Dbg( p_input, "CaptureEnumPins::~CaptureEnumPins" );
928 #endif
929     p_filter->Release();
930 }
931
932 /* IUnknown methods */
933 STDMETHODIMP CaptureEnumPins::QueryInterface( REFIID riid, void **ppv )
934 {
935 #ifdef DEBUG_DSHOW_L1
936     msg_Dbg( p_input, "CaptureEnumPins::QueryInterface" );
937 #endif
938
939     if( riid == IID_IUnknown ||
940         riid == IID_IEnumPins )
941     {
942         AddRef();
943         *ppv = (IEnumPins *)this;
944         return NOERROR;
945     }
946     else
947     {
948         *ppv = NULL;
949         return E_NOINTERFACE;
950     }
951 };
952 STDMETHODIMP_(ULONG) CaptureEnumPins::AddRef()
953 {
954 #ifdef DEBUG_DSHOW_L1
955     msg_Dbg( p_input, "CaptureEnumPins::AddRef (ref: %i)", i_ref );
956 #endif
957
958     return i_ref++;
959 };
960 STDMETHODIMP_(ULONG) CaptureEnumPins::Release()
961 {
962 #ifdef DEBUG_DSHOW_L1
963     msg_Dbg( p_input, "CaptureEnumPins::Release (ref: %i)", i_ref );
964 #endif
965
966     if( !InterlockedDecrement(&i_ref) ) delete this;
967
968     return 0;
969 };
970
971 /* IEnumPins */
972 STDMETHODIMP CaptureEnumPins::Next( ULONG cPins, IPin ** ppPins,
973                                     ULONG * pcFetched )
974 {
975 #ifdef DEBUG_DSHOW_L1
976     msg_Dbg( p_input, "CaptureEnumPins::Next" );
977 #endif
978
979     unsigned int i_fetched = 0;
980
981     if( i_position < 1 && cPins > 0 )
982     {
983         IPin *pPin = p_filter->CustomGetPin();
984         *ppPins = pPin;
985         pPin->AddRef();
986         i_fetched = 1;
987         i_position++;
988     }
989
990     if( pcFetched ) *pcFetched = i_fetched;
991
992     return (i_fetched == cPins) ? S_OK : S_FALSE;
993 };
994 STDMETHODIMP CaptureEnumPins::Skip( ULONG cPins )
995 {
996 #ifdef DEBUG_DSHOW_L1
997     msg_Dbg( p_input, "CaptureEnumPins::Skip" );
998 #endif
999
1000     i_position += cPins;
1001
1002     if( i_position > 1 )
1003     {
1004         return S_FALSE;
1005     }
1006
1007     return S_OK;
1008 };
1009 STDMETHODIMP CaptureEnumPins::Reset()
1010 {
1011 #ifdef DEBUG_DSHOW_L1
1012     msg_Dbg( p_input, "CaptureEnumPins::Reset" );
1013 #endif
1014
1015     i_position = 0;
1016     return S_OK;
1017 };
1018 STDMETHODIMP CaptureEnumPins::Clone( IEnumPins **ppEnum )
1019 {
1020 #ifdef DEBUG_DSHOW_L1
1021     msg_Dbg( p_input, "CaptureEnumPins::Clone" );
1022 #endif
1023
1024     *ppEnum = new CaptureEnumPins( p_input, p_filter, this );
1025     if( *ppEnum == NULL ) return E_OUTOFMEMORY;
1026
1027     return NOERROR;
1028 };
1029
1030 /****************************************************************************
1031  * Implementation of our dummy directshow enummediatypes class
1032  ****************************************************************************/
1033 CaptureEnumMediaTypes::CaptureEnumMediaTypes( vlc_object_t *_p_input,
1034     CapturePin *_p_pin, CaptureEnumMediaTypes *pEnumMediaTypes )
1035   : p_input( _p_input ), p_pin( _p_pin ), i_ref( 1 )
1036 {
1037     /* Hold a reference count on our filter */
1038     p_pin->AddRef();
1039
1040     /* Are we creating a new enumerator */
1041     if( pEnumMediaTypes == NULL )
1042     {
1043         CopyMediaType(&cx_media_type, &p_pin->cx_media_type);
1044         i_position = 0;
1045     }
1046     else
1047     {
1048         CopyMediaType(&cx_media_type, &pEnumMediaTypes->cx_media_type);
1049         i_position = pEnumMediaTypes->i_position;
1050     }
1051 }
1052
1053 CaptureEnumMediaTypes::~CaptureEnumMediaTypes()
1054 {
1055 #ifdef DEBUG_DSHOW_L1
1056     msg_Dbg( p_input, "CaptureEnumMediaTypes::~CaptureEnumMediaTypes" );
1057 #endif
1058     FreeMediaType(cx_media_type);
1059     p_pin->Release();
1060 }
1061
1062 /* IUnknown methods */
1063 STDMETHODIMP CaptureEnumMediaTypes::QueryInterface( REFIID riid, void **ppv )
1064 {
1065 #ifdef DEBUG_DSHOW_L1
1066     msg_Dbg( p_input, "CaptureEnumMediaTypes::QueryInterface" );
1067 #endif
1068
1069     if( riid == IID_IUnknown ||
1070         riid == IID_IEnumMediaTypes )
1071     {
1072         AddRef();
1073         *ppv = (IEnumMediaTypes *)this;
1074         return NOERROR;
1075     }
1076     else
1077     {
1078         *ppv = NULL;
1079         return E_NOINTERFACE;
1080     }
1081 };
1082 STDMETHODIMP_(ULONG) CaptureEnumMediaTypes::AddRef()
1083 {
1084 #ifdef DEBUG_DSHOW_L1
1085     msg_Dbg( p_input, "CaptureEnumMediaTypes::AddRef (ref: %i)", i_ref );
1086 #endif
1087
1088     return i_ref++;
1089 };
1090 STDMETHODIMP_(ULONG) CaptureEnumMediaTypes::Release()
1091 {
1092 #ifdef DEBUG_DSHOW_L1
1093     msg_Dbg( p_input, "CaptureEnumMediaTypes::Release (ref: %i)", i_ref );
1094 #endif
1095
1096     if( !InterlockedDecrement(&i_ref) ) delete this;
1097
1098     return 0;
1099 };
1100
1101 /* IEnumMediaTypes */
1102 STDMETHODIMP CaptureEnumMediaTypes::Next( ULONG cMediaTypes,
1103                                           AM_MEDIA_TYPE ** ppMediaTypes,
1104                                           ULONG * pcFetched )
1105 {
1106 #ifdef DEBUG_DSHOW_L1
1107     msg_Dbg( p_input, "CaptureEnumMediaTypes::Next " );
1108 #endif
1109     ULONG copied = 0;
1110     ULONG offset = 0;
1111     ULONG max = p_pin->media_type_count;
1112
1113     if( ! ppMediaTypes )
1114         return E_POINTER;
1115
1116     if( (! pcFetched)  && (cMediaTypes > 1) )
1117        return E_POINTER;
1118
1119     /*
1120     ** use connection media type as first entry in iterator if it exists
1121     */
1122     copied = 0;
1123     if( cx_media_type.subtype != GUID_NULL )
1124     {
1125         ++max;
1126         if( i_position == 0 )
1127         {
1128             ppMediaTypes[copied] =
1129                 (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
1130             if( CopyMediaType(ppMediaTypes[copied], &cx_media_type) != S_OK )
1131                 return E_OUTOFMEMORY;
1132             ++i_position;
1133             ++copied;
1134         }
1135     }
1136
1137     while( (copied < cMediaTypes) && (i_position < max)  )
1138     {
1139         ppMediaTypes[copied] =
1140             (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
1141         if( CopyMediaType( ppMediaTypes[copied],
1142                            &p_pin->media_types[i_position-offset]) != S_OK )
1143             return E_OUTOFMEMORY;
1144
1145         ++copied;
1146         ++i_position;
1147     }
1148
1149     if( pcFetched )  *pcFetched = copied;
1150
1151     return (copied == cMediaTypes) ? S_OK : S_FALSE;
1152 };
1153 STDMETHODIMP CaptureEnumMediaTypes::Skip( ULONG cMediaTypes )
1154 {
1155     ULONG max =  p_pin->media_type_count;
1156     if( cx_media_type.subtype != GUID_NULL )
1157     {
1158         max = 1;
1159     }
1160 #ifdef DEBUG_DSHOW_L1
1161     msg_Dbg( p_input, "CaptureEnumMediaTypes::Skip" );
1162 #endif
1163
1164     i_position += cMediaTypes;
1165     return (i_position < max) ? S_OK : S_FALSE;
1166 };
1167 STDMETHODIMP CaptureEnumMediaTypes::Reset()
1168 {
1169 #ifdef DEBUG_DSHOW_L1
1170     msg_Dbg( p_input, "CaptureEnumMediaTypes::Reset" );
1171 #endif
1172
1173     FreeMediaType(cx_media_type);
1174     CopyMediaType(&cx_media_type, &p_pin->cx_media_type);
1175     i_position = 0;
1176     return S_OK;
1177 };
1178 STDMETHODIMP CaptureEnumMediaTypes::Clone( IEnumMediaTypes **ppEnum )
1179 {
1180 #ifdef DEBUG_DSHOW_L1
1181     msg_Dbg( p_input, "CaptureEnumMediaTypes::Clone" );
1182 #endif
1183
1184     *ppEnum = new CaptureEnumMediaTypes( p_input, p_pin, this );
1185     if( *ppEnum == NULL ) return E_OUTOFMEMORY;
1186
1187     return NOERROR;
1188 };