filter.cpp 40.1 KB
Newer Older
gbazin's avatar
   
gbazin committed
1
2
3
4
/*****************************************************************************
 * filter.c : DirectShow access module for vlc
 *****************************************************************************
 * Copyright (C) 2002 VideoLAN
5
 * $Id$
gbazin's avatar
   
gbazin committed
6
 *
7
 * Author: Gildas Bazin <gbazin@videolan.org>
gbazin's avatar
   
gbazin committed
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/vout.h>

35
36
37
38
39
#ifndef _MSC_VER
    /* Work-around a bug in w32api-2.5 */
#   define QACONTAINERFLAGS QACONTAINERFLAGS_SOMETHINGELSE
#endif

gbazin's avatar
gbazin committed
40
#include "common.h"
gbazin's avatar
   
gbazin committed
41
42
43
44
#include "filter.h"

#define DEBUG_DSHOW 1

45
46
47
#define FILTER_NAME  L"VideoLAN Capture Filter"
#define PIN_NAME     L"Capture"

gbazin's avatar
   
gbazin committed
48
49
50
51
52
53
/*****************************************************************************
 * DirectShow GUIDs.
 * Easier to define them hear as mingw doesn't provide them all.
 *****************************************************************************/
const GUID CLSID_SystemDeviceEnum = {0x62be5d10, 0x60eb, 0x11d0, {0xbd, 0x3b, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86}};
const GUID CLSID_VideoInputDeviceCategory = {0x860BB310,0x5D01,0x11d0,{0xBD,0x3B,0x00,0xA0,0xC9,0x11,0xCE,0x86}};
gbazin's avatar
   
gbazin committed
54
const GUID CLSID_AudioInputDeviceCategory = {0x33d9a762, 0x90c8, 0x11d0, {0xbd, 0x43, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86}};
gbazin's avatar
   
gbazin committed
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
const GUID IID_IPropertyBag = {0x55272A00, 0x42CB, 0x11CE, {0x81, 0x35, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51}};
const GUID IID_ICreateDevEnum = {0x29840822, 0x5b84, 0x11d0, {0xbd, 0x3b, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86}};
const GUID IID_IFilterGraph = {0x56a8689f, 0x0ad4, 0x11ce, {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
const GUID IID_IMediaControl = {0x56a868b1, 0x0ad4, 0x11ce, {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
const GUID CLSID_FilterGraph = {0xe436ebb3, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};

const GUID IID_IUnknown = {0x00000000, 0x0000, 0x0000, {0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46}};
const GUID IID_IPersist = {0x0000010c, 0x0000, 0x0000, {0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46}};
const GUID IID_IMediaFilter = {0x56a86899, 0x0ad4, 0x11ce, {0xb0,0x3a, 0x00,0x20,0xaf,0x0b,0xa7,0x70}};
const GUID IID_IBaseFilter = {0x56a86895, 0x0ad4, 0x11ce, {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
const GUID IID_IPin = {0x56a86891, 0x0ad4, 0x11ce, {0xb0,0x3a, 0x00,0x20,0xaf,0x0b,0xa7,0x70}};
const GUID IID_IMemInputPin = {0x56a8689d, 0x0ad4, 0x11ce, {0xb0,0x3a, 0x00,0x20,0xaf,0x0b,0xa7,0x70}};

const GUID IID_IEnumPins = {0x56a86892, 0x0ad4, 0x11ce, {0xb0,0x3a, 0x00,0x20,0xaf,0x0b,0xa7,0x70}};
const GUID IID_IEnumMediaTypes = {0x89c31040, 0x846b, 0x11ce, {0x97,0xd3, 0x00,0xaa,0x00,0x55,0x59,0x5a}};

71
72
const GUID IID_IAMBufferNegotiation = {0x56ed71a0, 0xaf5f, 0x11d0, {0xb3, 0xf0, 0x00, 0xaa, 0x00, 0x37, 0x61, 0xc5}};

gbazin's avatar
   
gbazin committed
73
74
const GUID IID_ISpecifyPropertyPages = {0xb196b28b, 0xbab4, 0x101a, {0xb6, 0x9c, 0x00, 0xaa, 0x00, 0x34, 0x1d, 0x07}};

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
const GUID IID_IQualityControl = {0x56a868a5, 0x0ad4, 0x11ce, {0xb, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};

const GUID CLSID_CaptureGraphBuilder2 = {0xBF87B6E1, 0x8C27, 0x11d0, {0xB3, 0xF0, 0x0, 0xAA, 0x00, 0x37, 0x61, 0xC5}};

const GUID IID_IGraphBuilder = {0x56a868a9, 0x0ad4, 0x11ce, {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};

const GUID IID_ICaptureGraphBuilder2 = {0x93E5A4E0, 0x2D50, 0x11d2, {0xAB, 0xFA, 0x00, 0xA0, 0xC9, 0xC6, 0xE3, 0x8D}};

const GUID IID_IAMTVAudio = {0x83EC1C30, 0x23D1, 0x11d1, {0x99, 0xE6, 0x00, 0xA0, 0xC9, 0x56, 0x02, 0x66}};
const GUID IID_IAMStreamConfig = {0xC6E13340, 0x30AC, 0x11d0, {0xA1, 0x8C, 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56}};
const GUID IID_IAMCrossbar = {0xC6E13380, 0x30AC, 0x11d0, {0xA1, 0x8C, 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56}};
const GUID IID_IAMTVTuner = {0x211A8766, 0x03AC, 0x11d1, {0x8D, 0x13, 0x00, 0xAA, 0x00, 0xBD, 0x83, 0x39}};

const GUID IID_IKsPropertySet = {0x31EFAC30, 0x515C, 0x11d0, {0xA9, 0xAA, 0x00, 0xAA, 0x00, 0x61, 0xBE, 0x93}};

90
/* Video Format */
91

92
const GUID FORMAT_VideoInfo  = {0x05589f80, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
gbazin's avatar
   
gbazin committed
93
94
95
96
/*
 * MEDIATYPEs and MEDIASUBTYPEs
 */
const GUID MEDIATYPE_Video = {0x73646976, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
97
const GUID MEDIATYPE_Interleaved = {0x73766169, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
gbazin's avatar
   
gbazin committed
98
const GUID MEDIATYPE_Stream = {0xe436eb83, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
99
const GUID MEDIASUBTYPE_PREVIEW_VIDEO = {0x2859e1da, 0xb81f, 0x4fbd, {0x94, 0x3b, 0xe2, 0x37, 0x24, 0xa1, 0xab, 0xb3}};
gbazin's avatar
   
gbazin committed
100

gbazin's avatar
   
gbazin committed
101
102
103
/* Packed RGB formats */
const GUID MEDIASUBTYPE_RGB1 = {0xe436eb78, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
const GUID MEDIASUBTYPE_RGB4 = {0xe436eb79, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
gbazin's avatar
   
gbazin committed
104
105
106
107
108
109
110
const GUID MEDIASUBTYPE_RGB8 = {0xe436eb7a, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
const GUID MEDIASUBTYPE_RGB565 = {0xe436eb7b, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
const GUID MEDIASUBTYPE_RGB555 = {0xe436eb7c, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
const GUID MEDIASUBTYPE_RGB24 = {0xe436eb7d, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
const GUID MEDIASUBTYPE_RGB32 = {0xe436eb7e, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
const GUID MEDIASUBTYPE_ARGB32 = {0x773c9ac0, 0x3274, 0x11d0, {0xb7, 0x24, 0x0, 0xaa, 0x0, 0x6c, 0x1a, 0x1}};

gbazin's avatar
   
gbazin committed
111
/* Packed YUV formats */
gbazin's avatar
   
gbazin committed
112
113
const GUID MEDIASUBTYPE_YUYV = {0x56595559, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
const GUID MEDIASUBTYPE_Y411 = {0x31313459, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
gbazin's avatar
   
gbazin committed
114
const GUID MEDIASUBTYPE_Y211 = {0x31313259, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
gbazin's avatar
   
gbazin committed
115
116
117
const GUID MEDIASUBTYPE_YUY2 = {0x32595559, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
const GUID MEDIASUBTYPE_YVYU = {0x55595659, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
const GUID MEDIASUBTYPE_UYVY = {0x59565955, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
gbazin's avatar
   
gbazin committed
118
119
120

/* Planar YUV formats */
const GUID MEDIASUBTYPE_YVU9 = {0x39555659, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
gbazin's avatar
   
gbazin committed
121
const GUID MEDIASUBTYPE_YV12 = {0x32315659, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
gbazin's avatar
   
gbazin committed
122
123
124
const GUID MEDIASUBTYPE_IYUV = {0x56555949, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; /* identical to YV12 */
const GUID MEDIASUBTYPE_Y41P = {0x50313459, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
const GUID MEDIASUBTYPE_I420 = {0x30323449, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
gbazin's avatar
   
gbazin committed
125

gbazin's avatar
   
gbazin committed
126
127
128
const GUID MEDIATYPE_Audio = {0x73647561, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
const GUID FORMAT_WaveFormatEx = {0x05589f81, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
const GUID MEDIASUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
129
const GUID MEDIASUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
gbazin's avatar
   
gbazin committed
130

gbazin's avatar
   
gbazin committed
131
132
133
134
135
/* DV formats */
const GUID MEDIASUBTYPE_dvsd = {0x64737664, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
const GUID MEDIASUBTYPE_dvhd = {0x64687664, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
const GUID MEDIASUBTYPE_dvsl = {0x6c737664, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};

gbazin's avatar
   
gbazin committed
136
137
138
139
140
141
/* MPEG2 formats */
const GUID MEDIASUBTYPE_MPEG2_VIDEO = {0xe06d8026, 0xdb46, 0x11cf, {0xb4, 0xd1, 0x00, 0x80, 0x5f, 0x6c, 0xbb, 0xea}};
const GUID MEDIASUBTYPE_MPEG2_PROGRAM = {0xe06d8022, 0xdb46, 0x11cf, {0xb4, 0xd1, 0x00, 0x80, 0x5f, 0x6c, 0xbb, 0xea}};
const GUID MEDIASUBTYPE_MPEG2_TRANSPORT = {0xe06d8023, 0xdb46, 0x11cf, {0xb4, 0xd1, 0x00, 0x80, 0x5f, 0x6c, 0xbb, 0xea}};
const GUID FORMAT_MPEG2Video = {0xe06d80e3, 0xdb46, 0x11cf, {0xb4, 0xd1, 0x00, 0x80, 0x5f, 0x6c, 0xbb, 0xea}};

142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/* Analog Video */
const GUID FORMAT_AnalogVideo = {0x482dde0, 0x7817, 0x11cf, {0x8a, 0x3, 0x0, 0xaa, 0x0, 0x6e, 0xcb, 0x65}};

const GUID MEDIATYPE_AnalogVideo = {0x482dde1, 0x7817, 0x11cf, {0x8a, 0x3, 0x0, 0xab, 0x0, 0x6e, 0xcb, 0x65}};

const GUID MEDIASUBTYPE_AnalogVideo_NTSC_M = {0x482dde2, 0x7817, 0x11cf, {0x8a, 0x3, 0x0, 0xaa, 0x0, 0x6e, 0xcb, 0x65}};
const GUID MEDIASUBTYPE_AnalogVideo_PAL_B = {0x482dde5, 0x7817, 0x11cf, {0x8a, 0x3, 0x0, 0xaa, 0x0, 0x6e, 0xcb, 0x65}};
const GUID MEDIASUBTYPE_AnalogVideo_PAL_D = {0x482dde6, 0x7817, 0x11cf, {0x8a, 0x3, 0x0, 0xaa, 0x0, 0x6e, 0xcb, 0x65}};
const GUID MEDIASUBTYPE_AnalogVideo_PAL_G = {0x482dde7, 0x7817, 0x11cf, {0x8a, 0x3, 0x0, 0xaa, 0x0, 0x6e, 0xcb, 0x65}};
const GUID MEDIASUBTYPE_AnalogVideo_PAL_H = {0x482dde8, 0x7817, 0x11cf, {0x8a, 0x3, 0x0, 0xaa, 0x0, 0x6e, 0xcb, 0x65}};
const GUID MEDIASUBTYPE_AnalogVideo_PAL_I = {0x482dde9, 0x7817, 0x11cf, {0x8a, 0x3, 0x0, 0xaa, 0x0, 0x6e, 0xcb, 0x65}};
const GUID MEDIASUBTYPE_AnalogVideo_PAL_M = {0x482ddea, 0x7817, 0x11cf, {0x8a, 0x3, 0x0, 0xaa, 0x0, 0x6e, 0xcb, 0x65}};
const GUID MEDIASUBTYPE_AnalogVideo_PAL_N = {0x482ddeb, 0x7817, 0x11cf, {0x8a, 0x3, 0x0, 0xaa, 0x0, 0x6e, 0xcb, 0x65}};
const GUID MEDIASUBTYPE_AnalogVideo_PAL_N_COMBO = {0x482ddec, 0x7817, 0x11cf, {0x8a, 0x3, 0x0, 0xaa, 0x0, 0x6e, 0xcb, 0x65}};
const GUID MEDIASUBTYPE_AnalogVideo_SECAM_B = {0x482ddf0, 0x7817, 0x11cf, {0x8a, 0x3, 0x0, 0xaa, 0x0, 0x6e, 0xcb, 0x65}};
const GUID MEDIASUBTYPE_AnalogVideo_SECAM_D = {0x482ddf1, 0x7817, 0x11cf, {0x8a, 0x3, 0x0, 0xaa, 0x0, 0x6e, 0xcb, 0x65}};
const GUID MEDIASUBTYPE_AnalogVideo_SECAM_G = {0x482ddf2, 0x7817, 0x11cf, {0x8a, 0x3, 0x0, 0xaa, 0x0, 0x6e, 0xcb, 0x65}};
const GUID MEDIASUBTYPE_AnalogVideo_SECAM_H = {0x482ddf3, 0x7817, 0x11cf, {0x8a, 0x3, 0x0, 0xaa, 0x0, 0x6e, 0xcb, 0x65}};
const GUID MEDIASUBTYPE_AnalogVideo_SECAM_K = {0x482ddf4, 0x7817, 0x11cf, {0x8a, 0x3, 0x0, 0xaa, 0x0, 0x6e, 0xcb, 0x65}};
const GUID MEDIASUBTYPE_AnalogVideo_SECAM_K1 = {0x482ddf5, 0x7817, 0x11cf, {0x8a, 0x3, 0x0, 0xaa, 0x0, 0x6e, 0xcb, 0x65}};
const GUID MEDIASUBTYPE_AnalogVideo_SECAM_L = {0x482ddf6, 0x7817, 0x11cf, {0x8a, 0x3, 0x0, 0xaa, 0x0, 0x6e, 0xcb, 0x65}};

const GUID AMPROPSETID_Pin= {0x9b00f101, 0x1567, 0x11d1, {0xb3, 0xf1, 0x0, 0xaa, 0x0, 0x37, 0x61, 0xc5}};
const GUID PIN_CATEGORY_ANALOGVIDEOIN= {0xfb6c4283, 0x0353, 0x11d1, {0x90, 0x5f, 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba}};
const GUID PIN_CATEGORY_CAPTURE= {0xfb6c4281, 0x0353, 0x11d1, {0x90, 0x5f, 0x0, 0x0, 0xc0, 0xcc, 0x16, 0xba}};
const GUID LOOK_UPSTREAM_ONLY= {0xac798be0, 0x98e3, 0x11d1, {0xb3, 0xf1, 0x0, 0xaa, 0x0, 0x37, 0x61, 0xc}};

gbazin's avatar
   
gbazin committed
169
170
const GUID GUID_NULL = {0x0000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};

gbazin's avatar
   
gbazin committed
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
void WINAPI FreeMediaType( AM_MEDIA_TYPE& mt )
{
    if( mt.cbFormat != 0 )
    {
        CoTaskMemFree( (PVOID)mt.pbFormat );
        mt.cbFormat = 0;
        mt.pbFormat = NULL;
    }
    if( mt.pUnk != NULL )
    {
        mt.pUnk->Release();
        mt.pUnk = NULL;
    }
}

HRESULT WINAPI CopyMediaType( AM_MEDIA_TYPE *pmtTarget,
                              const AM_MEDIA_TYPE *pmtSource )
{
    *pmtTarget = *pmtSource;
190
191
192
193

    if( !pmtSource || !pmtTarget ) return S_FALSE;

    if( pmtSource->cbFormat && pmtSource->pbFormat )
gbazin's avatar
   
gbazin committed
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
    {
        pmtTarget->pbFormat = (PBYTE)CoTaskMemAlloc( pmtSource->cbFormat );
        if( pmtTarget->pbFormat == NULL )
        {
            pmtTarget->cbFormat = 0;
            return E_OUTOFMEMORY;
        }
        else
        {
            CopyMemory( (PVOID)pmtTarget->pbFormat, (PVOID)pmtSource->pbFormat,
                        pmtTarget->cbFormat );
        }
    }
    if( pmtTarget->pUnk != NULL )
    {
        pmtTarget->pUnk->AddRef();
    }

    return S_OK;
}

gbazin's avatar
gbazin committed
215
int GetFourCCFromMediaType( const AM_MEDIA_TYPE &media_type )
216
217
218
219
220
{
    int i_fourcc = 0;

    if( media_type.majortype == MEDIATYPE_Video )
    {
221
        /* currently only support this type of video info format */
gbazin's avatar
gbazin committed
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
        if( media_type.formattype == FORMAT_VideoInfo )
        {
            /* Packed RGB formats */
            if( media_type.subtype == MEDIASUBTYPE_RGB1 )
               i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '1' );
            else if( media_type.subtype == MEDIASUBTYPE_RGB4 )
               i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '4' );
            else if( media_type.subtype == MEDIASUBTYPE_RGB8 )
               i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '8' );
            else if( media_type.subtype == MEDIASUBTYPE_RGB555 )
               i_fourcc = VLC_FOURCC( 'R', 'V', '1', '5' );
            else if( media_type.subtype == MEDIASUBTYPE_RGB565 )
               i_fourcc = VLC_FOURCC( 'R', 'V', '1', '6' );
            else if( media_type.subtype == MEDIASUBTYPE_RGB24 )
               i_fourcc = VLC_FOURCC( 'R', 'V', '2', '4' );
            else if( media_type.subtype == MEDIASUBTYPE_RGB32 )
               i_fourcc = VLC_FOURCC( 'R', 'V', '3', '2' );
            else if( media_type.subtype == MEDIASUBTYPE_ARGB32 )
               i_fourcc = VLC_FOURCC( 'R', 'G', 'B', 'A' );

            /* Planar YUV formats */
            else if( media_type.subtype == MEDIASUBTYPE_I420 )
               i_fourcc = VLC_FOURCC( 'I', '4', '2', '0' );
            else if( media_type.subtype == MEDIASUBTYPE_Y41P )
               i_fourcc = VLC_FOURCC( 'I', '4', '1', '1' );
            else if( media_type.subtype == MEDIASUBTYPE_YV12 )
               i_fourcc = VLC_FOURCC( 'Y', 'V', '1', '2' );
            else if( media_type.subtype == MEDIASUBTYPE_IYUV )
               i_fourcc = VLC_FOURCC( 'Y', 'V', '1', '2' );
            else if( media_type.subtype == MEDIASUBTYPE_YVU9 )
               i_fourcc = VLC_FOURCC( 'Y', 'V', 'U', '9' );

            /* Packed YUV formats */
            else if( media_type.subtype == MEDIASUBTYPE_YVYU )
               i_fourcc = VLC_FOURCC( 'Y', 'V', 'Y', 'U' );
            else if( media_type.subtype == MEDIASUBTYPE_YUYV )
               i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', '2' );
            else if( media_type.subtype == MEDIASUBTYPE_Y411 )
               i_fourcc = VLC_FOURCC( 'I', '4', '1', 'N' );
            else if( media_type.subtype == MEDIASUBTYPE_Y211 )
               i_fourcc = VLC_FOURCC( 'Y', '2', '1', '1' );
            else if( media_type.subtype == MEDIASUBTYPE_YUY2 )
               i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', '2' );
            else if( media_type.subtype == MEDIASUBTYPE_UYVY )
               i_fourcc = VLC_FOURCC( 'U', 'Y', 'V', 'Y' );

            /* MPEG2 video elementary stream */
            else if( media_type.subtype == MEDIASUBTYPE_MPEG2_VIDEO )
               i_fourcc = VLC_FOURCC( 'm', 'p', '2', 'v' );

            /* DV formats */
            else if( media_type.subtype == MEDIASUBTYPE_dvsl )
               i_fourcc = VLC_FOURCC( 'd', 'v', 's', 'l' );
            else if( media_type.subtype == MEDIASUBTYPE_dvsd )
               i_fourcc = VLC_FOURCC( 'd', 'v', 's', 'd' );
            else if( media_type.subtype == MEDIASUBTYPE_dvhd )
               i_fourcc = VLC_FOURCC( 'd', 'v', 'h', 'd' );
        }
280
281
282
    }
    else if( media_type.majortype == MEDIATYPE_Audio )
    {
283
        /* currently only support this type of audio info format */
284
285
286
287
288
289
290
291
292
        if( media_type.formattype == FORMAT_WaveFormatEx )
        {
            if( media_type.subtype == MEDIASUBTYPE_PCM )
                i_fourcc = VLC_FOURCC( 'a', 'r', 'a', 'w' );
            else if( media_type.subtype == MEDIASUBTYPE_IEEE_FLOAT )
                i_fourcc = VLC_FOURCC( 'f', 'l', '3', '2' );
        }
    }
    else if( media_type.majortype == MEDIATYPE_Stream )
gbazin's avatar
gbazin committed
293
    {
294
        if( media_type.subtype == MEDIASUBTYPE_MPEG2_PROGRAM )
gbazin's avatar
gbazin committed
295
            i_fourcc = VLC_FOURCC( 'm', 'p', '2', 'p' );
296
        else if( media_type.subtype == MEDIASUBTYPE_MPEG2_TRANSPORT )
gbazin's avatar
gbazin committed
297
            i_fourcc = VLC_FOURCC( 'm', 'p', '2', 't' );
298
    }
gbazin's avatar
gbazin committed
299

300
301
302
    return i_fourcc;
}

gbazin's avatar
   
gbazin committed
303
304
305
306
/****************************************************************************
 * Implementation of our dummy directshow filter pin class
 ****************************************************************************/

gbazin's avatar
gbazin committed
307
308
CapturePin::CapturePin( vlc_object_t *_p_input, access_sys_t *_p_sys,
                        CaptureFilter *_p_filter,
309
                        AM_MEDIA_TYPE *mt, size_t mt_count )
gbazin's avatar
gbazin committed
310
311
312
  : p_input( _p_input ), p_sys( _p_sys ), p_filter( _p_filter ),
    p_connected_pin( NULL ),  media_types(mt), media_type_count(mt_count),
    i_ref( 1 )
gbazin's avatar
   
gbazin committed
313
{
314
315
316
317
    cx_media_type.majortype = mt[0].majortype;
    cx_media_type.subtype   = GUID_NULL;
    cx_media_type.pbFormat  = NULL;
    cx_media_type.pUnk      = NULL;
gbazin's avatar
   
gbazin committed
318
319
320
321
}

CapturePin::~CapturePin()
{
322
323
324
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::~CapturePin" );
#endif
325
326
    for( size_t c=0; c<media_type_count; c++ )
    {
327
        FreeMediaType(media_types[c]);
328
329
    }
    FreeMediaType(cx_media_type);
gbazin's avatar
   
gbazin committed
330
331
332
333
}

HRESULT CapturePin::CustomGetSample( VLCMediaSample *vlc_sample )
{
334
335
336
337
338
#if 0 //def DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::CustomGetSample" );
#endif

    vlc_mutex_lock( &p_sys->lock );
gbazin's avatar
   
gbazin committed
339
340
341
342
    if( samples_queue.size() )
    {
        *vlc_sample = samples_queue.back();
        samples_queue.pop_back();
343
        vlc_mutex_unlock( &p_sys->lock );
gbazin's avatar
   
gbazin committed
344
345
        return S_OK;
    }
346
    vlc_mutex_unlock( &p_sys->lock );
gbazin's avatar
   
gbazin committed
347
348
349
    return S_FALSE;
}

350
AM_MEDIA_TYPE &CapturePin::CustomGetMediaType()
gbazin's avatar
   
gbazin committed
351
{
352
    return cx_media_type;
gbazin's avatar
   
gbazin committed
353
354
355
356
357
}

/* IUnknown methods */
STDMETHODIMP CapturePin::QueryInterface(REFIID riid, void **ppv)
{
damienf's avatar
damienf committed
358
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
359
360
361
362
363
364
    msg_Dbg( p_input, "CapturePin::QueryInterface" );
#endif

    if( riid == IID_IUnknown ||
        riid == IID_IPin )
    {
gbazin's avatar
   
gbazin committed
365
        AddRef();
gbazin's avatar
   
gbazin committed
366
367
368
369
370
        *ppv = (IPin *)this;
        return NOERROR;
    }
    if( riid == IID_IMemInputPin )
    {
gbazin's avatar
   
gbazin committed
371
        AddRef();
gbazin's avatar
   
gbazin committed
372
373
374
375
376
        *ppv = (IMemInputPin *)this;
        return NOERROR;
    }
    else
    {
damienf's avatar
damienf committed
377
#ifdef DEBUG_DSHOW_L1
378
379
380
381
382
383
384
385
        msg_Dbg( p_input, "CapturePin::QueryInterface() failed for: "
                 "%04X-%02X-%02X-%02X%02X%02X%02X%02X%02X%02X%02X",
                 (int)riid.Data1, (int)riid.Data2, (int)riid.Data3,
                 static_cast<int>(riid.Data4[0]), (int)riid.Data4[1],
                 (int)riid.Data4[2], (int)riid.Data4[3],
                 (int)riid.Data4[4], (int)riid.Data4[5],
                 (int)riid.Data4[6], (int)riid.Data4[7] );
#endif
gbazin's avatar
   
gbazin committed
386
387
388
389
        *ppv = NULL;
        return E_NOINTERFACE;
    }
}
390

gbazin's avatar
   
gbazin committed
391
392
STDMETHODIMP_(ULONG) CapturePin::AddRef()
{
393
#ifdef DEBUG_DSHOW_L1
394
    msg_Dbg( p_input, "CapturePin::AddRef (ref: %i)", i_ref );
gbazin's avatar
   
gbazin committed
395
396
#endif

gbazin's avatar
   
gbazin committed
397
    return i_ref++;
gbazin's avatar
   
gbazin committed
398
399
400
};
STDMETHODIMP_(ULONG) CapturePin::Release()
{
401
#ifdef DEBUG_DSHOW_L1
402
    msg_Dbg( p_input, "CapturePin::Release (ref: %i)", i_ref );
gbazin's avatar
   
gbazin committed
403
404
#endif

405
    if( !InterlockedDecrement(&i_ref) ) delete this;
gbazin's avatar
   
gbazin committed
406

407
    return 0;
gbazin's avatar
   
gbazin committed
408
409
410
411
412
413
};

/* IPin methods */
STDMETHODIMP CapturePin::Connect( IPin * pReceivePin,
                                  const AM_MEDIA_TYPE *pmt )
{
gbazin's avatar
gbazin committed
414
    if( State_Running == p_filter->state )
415
    {
gbazin's avatar
gbazin committed
416
417
418
419
420
421
422
423
424
425
426
        msg_Dbg( p_input, "CapturePin::Connect [not stopped]" );
        return VFW_E_NOT_STOPPED;
    }

    if( p_connected_pin )
    {
        msg_Dbg( p_input, "CapturePin::Connect [already connected]" );
        return VFW_E_ALREADY_CONNECTED;
    }

    if( !pmt ) return S_OK;
427
                
gbazin's avatar
gbazin committed
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
    if( GUID_NULL != pmt->majortype &&
        media_types[0].majortype != pmt->majortype )
    {
        msg_Dbg( p_input, "CapturePin::Connect [media major type mismatch]" );
        return S_FALSE;
    }

    if( GUID_NULL != pmt->subtype && !GetFourCCFromMediaType(*pmt) )
    {
        msg_Dbg( p_input, "CapturePin::Connect [media subtype type "
                 "not supported]" );
        return S_FALSE;
    }

    if( pmt->pbFormat && pmt->majortype == MEDIATYPE_Video  )
    {
        if( !((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biHeight ||
            !((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biWidth )
        {
            msg_Dbg( p_input, "CapturePin::Connect "
                     "[video width/height == 0 ]" );
            return S_FALSE;
450
        }
451
    }
gbazin's avatar
gbazin committed
452
453
454

    msg_Dbg( p_input, "CapturePin::Connect [OK]" );
    return S_OK;
gbazin's avatar
   
gbazin committed
455
456
457
458
}
STDMETHODIMP CapturePin::ReceiveConnection( IPin * pConnector,
                                            const AM_MEDIA_TYPE *pmt )
{
459
    if( State_Stopped != p_filter->state )
460
    {
gbazin's avatar
gbazin committed
461
        msg_Dbg( p_input, "CapturePin::ReceiveConnection [not stopped]" );
462
        return VFW_E_NOT_STOPPED;
463
    }
gbazin's avatar
   
gbazin committed
464

465
466
    if( !pConnector || !pmt )
    {
gbazin's avatar
gbazin committed
467
        msg_Dbg( p_input, "CapturePin::ReceiveConnection [null pointer]" );
468
        return E_POINTER;
469
    }
gbazin's avatar
   
gbazin committed
470

471
    if( p_connected_pin )
472
    {
gbazin's avatar
gbazin committed
473
        msg_Dbg( p_input, "CapturePin::ReceiveConnection [already connected]");
474
        return VFW_E_ALREADY_CONNECTED;
475
    }
476
477

    if( S_OK != QueryAccept(pmt) )
478
    {
gbazin's avatar
gbazin committed
479
480
        msg_Dbg( p_input, "CapturePin::ReceiveConnection "
                 "[media type not accepted]" );
481
        return VFW_E_TYPE_NOT_ACCEPTED;
482
483
484
    }

    msg_Dbg( p_input, "CapturePin::ReceiveConnection [OK]" );
gbazin's avatar
   
gbazin committed
485

gbazin's avatar
   
gbazin committed
486
487
    p_connected_pin = pConnector;
    p_connected_pin->AddRef();
gbazin's avatar
   
gbazin committed
488

489
490
    FreeMediaType( cx_media_type );
    return CopyMediaType( &cx_media_type, pmt );
gbazin's avatar
   
gbazin committed
491
492
493
}
STDMETHODIMP CapturePin::Disconnect()
{
494
495
    if( ! p_connected_pin )
    {
gbazin's avatar
gbazin committed
496
497
        msg_Dbg( p_input, "CapturePin::Disconnect [not connected]" );
        return S_FALSE;
498
    }
gbazin's avatar
   
gbazin committed
499

500
    msg_Dbg( p_input, "CapturePin::Disconnect [OK]" );
501

502
#if 0 // FIXME: This does seem to create crashes sometimes
503
504
505
506
507
508
509
510
511
512
513
514
    VLCMediaSample vlc_sample;

    vlc_mutex_lock( &p_sys->lock );
    while( samples_queue.size() )
    {
        vlc_sample = samples_queue.back();
        samples_queue.pop_back();
        vlc_sample.p_sample->Release();
    }
    vlc_mutex_unlock( &p_sys->lock );
#endif

515
    p_connected_pin->Release();
gbazin's avatar
   
gbazin committed
516
    p_connected_pin = NULL;
517
518
    //FreeMediaType( cx_media_type );
    //cx_media_type.subtype = GUID_NULL;
519

gbazin's avatar
   
gbazin committed
520
521
522
523
    return S_OK;
}
STDMETHODIMP CapturePin::ConnectedTo( IPin **pPin )
{
524
525
    if( !p_connected_pin )
    {
gbazin's avatar
gbazin committed
526
527
        msg_Dbg( p_input, "CapturePin::ConnectedTo [not connected]" );
        return VFW_E_NOT_CONNECTED;
528
    }
gbazin's avatar
   
gbazin committed
529

gbazin's avatar
   
gbazin committed
530
531
532
    p_connected_pin->AddRef();
    *pPin = p_connected_pin;

533
534
    msg_Dbg( p_input, "CapturePin::ConnectedTo [OK]" );

gbazin's avatar
   
gbazin committed
535
536
537
538
    return S_OK;
}
STDMETHODIMP CapturePin::ConnectionMediaType( AM_MEDIA_TYPE *pmt )
{
539
540
    if( !p_connected_pin )
    {
gbazin's avatar
gbazin committed
541
542
        msg_Dbg( p_input, "CapturePin::ConnectionMediaType [not connected]" );
        return VFW_E_NOT_CONNECTED;
543
    }
544
545

    return CopyMediaType( pmt, &cx_media_type );
gbazin's avatar
   
gbazin committed
546
547
548
549
550
551
552
553
554
555
}
STDMETHODIMP CapturePin::QueryPinInfo( PIN_INFO * pInfo )
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::QueryPinInfo" );
#endif

    pInfo->pFilter = p_filter;
    if( p_filter ) p_filter->AddRef();

556
    memcpy(pInfo->achName, PIN_NAME, sizeof(PIN_NAME));
gbazin's avatar
   
gbazin committed
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
    pInfo->dir = PINDIR_INPUT;

    return NOERROR;
}
STDMETHODIMP CapturePin::QueryDirection( PIN_DIRECTION * pPinDir )
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::QueryDirection" );
#endif

    *pPinDir = PINDIR_INPUT;
    return NOERROR;
}
STDMETHODIMP CapturePin::QueryId( LPWSTR * Id )
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::QueryId" );
#endif
575
576
577
578

    *Id = L"VideoLAN Capture Pin";

    return S_OK;
gbazin's avatar
   
gbazin committed
579
580
581
}
STDMETHODIMP CapturePin::QueryAccept( const AM_MEDIA_TYPE *pmt )
{
gbazin's avatar
gbazin committed
582
583
584
585
586
587
588
    if( State_Stopped != p_filter->state )
    {
        msg_Dbg( p_input, "CapturePin::QueryAccept [not stopped]" );
        return S_FALSE;
    }

    if( media_types[0].majortype != pmt->majortype )
589
    {
gbazin's avatar
gbazin committed
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
        msg_Dbg( p_input, "CapturePin::QueryAccept [media type mismatch]" );
        return S_FALSE;
    }

    int i_fourcc = GetFourCCFromMediaType(*pmt);
    if( !i_fourcc )
    {   
        msg_Dbg( p_input, "CapturePin::QueryAccept "
                 "[media type not supported]" );
        return S_FALSE;
    }

    if( pmt->majortype == MEDIATYPE_Video )
    {
        if( pmt->pbFormat &&
            ( (((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biHeight == 0) ||
              (((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biWidth == 0) ) )
607
        {
gbazin's avatar
gbazin committed
608
609
            msg_Dbg( p_input, "CapturePin::QueryAccept [video size wxh == 0]");
            return S_FALSE;
610
        }
gbazin's avatar
gbazin committed
611
612
613
614
615
616

        msg_Dbg( p_input, "CapturePin::QueryAccept [OK] "
                 "(width=%ld, height=%ld, chroma=%4.4s)",
                 ((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biWidth,
                 ((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biHeight,
                 (char *)&i_fourcc );
617
    }
gbazin's avatar
gbazin committed
618
619
620
621
622
623
624
625
626
627
628
629
630
631
    else
    {
        msg_Dbg( p_input, "CapturePin::QueryAccept [OK] (channels=%d, "
                 "samples/sec=%lu, bits/samples=%d, format=%4.4s)",
                 ((WAVEFORMATEX *)pmt->pbFormat)->nChannels,
                 ((WAVEFORMATEX *)pmt->pbFormat)->nSamplesPerSec,
                 ((WAVEFORMATEX *)pmt->pbFormat)->wBitsPerSample,
                 (char *)&i_fourcc );
    }   

    if( p_connected_pin )
    {
        FreeMediaType( cx_media_type );
        CopyMediaType( &cx_media_type, pmt );
632
    }
gbazin's avatar
gbazin committed
633
634

    return S_OK;
gbazin's avatar
   
gbazin committed
635
636
637
}
STDMETHODIMP CapturePin::EnumMediaTypes( IEnumMediaTypes **ppEnum )
{
damienf's avatar
damienf committed
638
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
639
640
641
642
643
644
645
646
647
648
649
    msg_Dbg( p_input, "CapturePin::EnumMediaTypes" );
#endif

    *ppEnum = new CaptureEnumMediaTypes( p_input, this, NULL );

    if( *ppEnum == NULL ) return E_OUTOFMEMORY;

    return NOERROR;
}
STDMETHODIMP CapturePin::QueryInternalConnections( IPin* *apPin, ULONG *nPin )
{
damienf's avatar
damienf committed
650
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
651
652
653
654
655
656
657
658
659
    msg_Dbg( p_input, "CapturePin::QueryInternalConnections" );
#endif
    return E_NOTIMPL;
}
STDMETHODIMP CapturePin::EndOfStream( void )
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::EndOfStream" );
#endif
gbazin's avatar
   
gbazin committed
660
    return S_OK;
gbazin's avatar
   
gbazin committed
661
662
663
664
665
666
}
STDMETHODIMP CapturePin::BeginFlush( void )
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::BeginFlush" );
#endif
gbazin's avatar
   
gbazin committed
667
    return S_OK;
gbazin's avatar
   
gbazin committed
668
669
670
671
672
673
}
STDMETHODIMP CapturePin::EndFlush( void )
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::EndFlush" );
#endif
gbazin's avatar
   
gbazin committed
674
    return S_OK;
gbazin's avatar
   
gbazin committed
675
676
677
678
679
680
681
682
}
STDMETHODIMP CapturePin::NewSegment( REFERENCE_TIME tStart,
                                     REFERENCE_TIME tStop,
                                     double dRate )
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::NewSegment" );
#endif
gbazin's avatar
   
gbazin committed
683
    return S_OK;
gbazin's avatar
   
gbazin committed
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
}

/* IMemInputPin methods */
STDMETHODIMP CapturePin::GetAllocator( IMemAllocator **ppAllocator )
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::GetAllocator" );
#endif

    return VFW_E_NO_ALLOCATOR;
}
STDMETHODIMP CapturePin::NotifyAllocator( IMemAllocator *pAllocator,
                                          BOOL bReadOnly )
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::NotifyAllocator" );
#endif

    return S_OK;
}
STDMETHODIMP CapturePin::GetAllocatorRequirements( ALLOCATOR_PROPERTIES *pProps )
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::GetAllocatorRequirements" );
#endif
709

gbazin's avatar
   
gbazin committed
710
711
712
713
    return E_NOTIMPL;
}
STDMETHODIMP CapturePin::Receive( IMediaSample *pSample )
{
714
715
#if 0 //def DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::Receive" );
gbazin's avatar
   
gbazin committed
716
717
#endif

gbazin's avatar
   
gbazin committed
718
    pSample->AddRef();
gbazin's avatar
   
gbazin committed
719
720
    mtime_t i_timestamp = mdate() * 10;
    VLCMediaSample vlc_sample = {pSample, i_timestamp};
721
722

    vlc_mutex_lock( &p_sys->lock );
gbazin's avatar
   
gbazin committed
723
724
725
726
727
728
729
730
    samples_queue.push_front( vlc_sample );

    /* Make sure we don't cache too many samples */
    if( samples_queue.size() > 10 )
    {
        vlc_sample = samples_queue.back();
        samples_queue.pop_back();
        msg_Dbg( p_input, "CapturePin::Receive trashing late input sample" );
gbazin's avatar
   
gbazin committed
731
        vlc_sample.p_sample->Release();
gbazin's avatar
   
gbazin committed
732
733
    }

734
735
736
    vlc_cond_signal( &p_sys->wait );
    vlc_mutex_unlock( &p_sys->lock );

gbazin's avatar
   
gbazin committed
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
    return S_OK;
}
STDMETHODIMP CapturePin::ReceiveMultiple( IMediaSample **pSamples,
                                          long nSamples,
                                          long *nSamplesProcessed )
{
    HRESULT hr = S_OK;

    *nSamplesProcessed = 0;
    while( nSamples-- > 0 )
    {
         hr = Receive( pSamples[*nSamplesProcessed] );
         if( hr != S_OK ) break;
         (*nSamplesProcessed)++;
    }
    return hr;
}
STDMETHODIMP CapturePin::ReceiveCanBlock( void )
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::ReceiveCanBlock" );
#endif

    return S_FALSE; /* Thou shalt not block */
}

/****************************************************************************
 * Implementation of our dummy directshow filter class
 ****************************************************************************/
gbazin's avatar
gbazin committed
766
767
768
769
770
CaptureFilter::CaptureFilter( vlc_object_t *_p_input, access_sys_t *p_sys,
                              AM_MEDIA_TYPE *mt, size_t mt_count )
  : p_input( _p_input ),
    p_pin( new CapturePin( _p_input, p_sys, this, mt, mt_count ) ),
    state( State_Stopped ), i_ref( 1 ) 
gbazin's avatar
   
gbazin committed
771
772
773
774
775
{
}

CaptureFilter::~CaptureFilter()
{
776
777
778
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::~CaptureFilter" );
#endif
gbazin's avatar
   
gbazin committed
779
780
781
782
783
784
    p_pin->Release();
}

/* IUnknown methods */
STDMETHODIMP CaptureFilter::QueryInterface( REFIID riid, void **ppv )
{
damienf's avatar
damienf committed
785
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
786
787
788
789
790
    msg_Dbg( p_input, "CaptureFilter::QueryInterface" );
#endif

    if( riid == IID_IUnknown )
    {
gbazin's avatar
   
gbazin committed
791
        AddRef();
gbazin's avatar
   
gbazin committed
792
793
794
795
796
        *ppv = (IUnknown *)this;
        return NOERROR;
    }
    if( riid == IID_IPersist )
    {
gbazin's avatar
   
gbazin committed
797
        AddRef();
gbazin's avatar
   
gbazin committed
798
799
800
801
802
        *ppv = (IPersist *)this;
        return NOERROR;
    }
    if( riid == IID_IMediaFilter )
    {
gbazin's avatar
   
gbazin committed
803
        AddRef();
gbazin's avatar
   
gbazin committed
804
805
806
807
808
        *ppv = (IMediaFilter *)this;
        return NOERROR;
    }
    if( riid == IID_IBaseFilter )
    {
gbazin's avatar
   
gbazin committed
809
        AddRef();
gbazin's avatar
   
gbazin committed
810
811
812
813
814
        *ppv = (IBaseFilter *)this;
        return NOERROR;
    }
    else
    {
damienf's avatar
damienf committed
815
#ifdef DEBUG_DSHOW_L1
816
817
818
819
820
821
822
823
        msg_Dbg( p_input, "CaptureFilter::QueryInterface() failed for: "
                 "%04X-%02X-%02X-%02X%02X%02X%02X%02X%02X%02X%02X",
                 (int)riid.Data1, (int)riid.Data2, (int)riid.Data3,
                 static_cast<int>(riid.Data4[0]), (int)riid.Data4[1],
                 (int)riid.Data4[2], (int)riid.Data4[3],
                 (int)riid.Data4[4], (int)riid.Data4[5],
                 (int)riid.Data4[6], (int)riid.Data4[7] );
#endif
gbazin's avatar
   
gbazin committed
824
825
826
827
828
829
        *ppv = NULL;
        return E_NOINTERFACE;
    }
};
STDMETHODIMP_(ULONG) CaptureFilter::AddRef()
{
830
#ifdef DEBUG_DSHOW_L1
831
    msg_Dbg( p_input, "CaptureFilter::AddRef (ref: %i)", i_ref );
gbazin's avatar
   
gbazin committed
832
833
#endif

gbazin's avatar
   
gbazin committed
834
    return i_ref++;
gbazin's avatar
   
gbazin committed
835
836
837
};
STDMETHODIMP_(ULONG) CaptureFilter::Release()
{
838
#ifdef DEBUG_DSHOW_L1
839
    msg_Dbg( p_input, "CaptureFilter::Release (ref: %i)", i_ref );
gbazin's avatar
   
gbazin committed
840
841
#endif

842
    if( !InterlockedDecrement(&i_ref) ) delete this;
gbazin's avatar
   
gbazin committed
843

844
    return 0;
gbazin's avatar
   
gbazin committed
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
};

/* IPersist method */
STDMETHODIMP CaptureFilter::GetClassID(CLSID *pClsID)
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::GetClassID" );
#endif
    return E_NOTIMPL;
};

/* IMediaFilter methods */
STDMETHODIMP CaptureFilter::GetState(DWORD dwMSecs, FILTER_STATE *State)
{
#ifdef DEBUG_DSHOW
gbazin's avatar
   
gbazin committed
860
    msg_Dbg( p_input, "CaptureFilter::GetState %i", state );
gbazin's avatar
   
gbazin committed
861
#endif
gbazin's avatar
   
gbazin committed
862
863
864

    *State = state;
    return S_OK;
gbazin's avatar
   
gbazin committed
865
866
867
868
869
870
871
};
STDMETHODIMP CaptureFilter::SetSyncSource(IReferenceClock *pClock)
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::SetSyncSource" );
#endif

gbazin's avatar
   
gbazin committed
872
    return S_OK;
gbazin's avatar
   
gbazin committed
873
874
875
876
877
878
};
STDMETHODIMP CaptureFilter::GetSyncSource(IReferenceClock **pClock)
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::GetSyncSource" );
#endif
gbazin's avatar
   
gbazin committed
879
880
881

    *pClock = NULL;
    return NOERROR;
gbazin's avatar
   
gbazin committed
882
883
884
885
886
887
};
STDMETHODIMP CaptureFilter::Stop()
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::Stop" );
#endif
gbazin's avatar
   
gbazin committed
888
889

    state = State_Stopped;
gbazin's avatar
   
gbazin committed
890
    return S_OK;
gbazin's avatar
   
gbazin committed
891
892
893
894
895
896
};
STDMETHODIMP CaptureFilter::Pause()
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::Pause" );
#endif
gbazin's avatar
   
gbazin committed
897
898

    state = State_Paused;
gbazin's avatar
   
gbazin committed
899
    return S_OK;
gbazin's avatar
   
gbazin committed
900
901
902
903
904
905
};
STDMETHODIMP CaptureFilter::Run(REFERENCE_TIME tStart)
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::Run" );
#endif
gbazin's avatar
   
gbazin committed
906
907

    state = State_Running;
gbazin's avatar
   
gbazin committed
908
    return S_OK;
gbazin's avatar
   
gbazin committed
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
};

/* IBaseFilter methods */
STDMETHODIMP CaptureFilter::EnumPins( IEnumPins ** ppEnum )
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::EnumPins" );
#endif

    /* Create a new ref counted enumerator */
    *ppEnum = new CaptureEnumPins( p_input, this, NULL );
    return *ppEnum == NULL ? E_OUTOFMEMORY : NOERROR;
};
STDMETHODIMP CaptureFilter::FindPin( LPCWSTR Id, IPin ** ppPin )
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::FindPin" );
#endif
    return E_NOTIMPL;
};
STDMETHODIMP CaptureFilter::QueryFilterInfo( FILTER_INFO * pInfo )
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::QueryFilterInfo" );
#endif

935
    memcpy(pInfo->achName, FILTER_NAME, sizeof(FILTER_NAME));
gbazin's avatar
   
gbazin committed
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970

    pInfo->pGraph = p_graph;
    if( p_graph ) p_graph->AddRef();

    return NOERROR;
};
STDMETHODIMP CaptureFilter::JoinFilterGraph( IFilterGraph * pGraph,
                                             LPCWSTR pName )
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::JoinFilterGraph" );
#endif

    p_graph = pGraph;

    return NOERROR;
};
STDMETHODIMP CaptureFilter::QueryVendorInfo( LPWSTR* pVendorInfo )
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::QueryVendorInfo" );
#endif
    return E_NOTIMPL;
};

/* Custom methods */
CapturePin *CaptureFilter::CustomGetPin()
{
    return p_pin;
}

/****************************************************************************
 * Implementation of our dummy directshow enumpins class
 ****************************************************************************/

gbazin's avatar
gbazin committed
971
CaptureEnumPins::CaptureEnumPins( vlc_object_t *_p_input,
gbazin's avatar
   
gbazin committed
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
                                  CaptureFilter *_p_filter,
                                  CaptureEnumPins *pEnumPins )
  : p_input( _p_input ), p_filter( _p_filter ), i_ref( 1 )
{
    /* Hold a reference count on our filter */
    p_filter->AddRef();

    /* Are we creating a new enumerator */

    if( pEnumPins == NULL )
    {
        i_position = 0;
    }
    else
    {
        i_position = pEnumPins->i_position;
    }
}

CaptureEnumPins::~CaptureEnumPins()
{
damienf's avatar
damienf committed
993
#ifdef DEBUG_DSHOW_L1
994
995
    msg_Dbg( p_input, "CaptureEnumPins::~CaptureEnumPins" );
#endif
gbazin's avatar
   
gbazin committed
996
997
998
999
1000
1001
    p_filter->Release();
}

/* IUnknown methods */
STDMETHODIMP CaptureEnumPins::QueryInterface( REFIID riid, void **ppv )
{
damienf's avatar
damienf committed
1002
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
1003
1004
1005
1006
1007
1008
    msg_Dbg( p_input, "CaptureEnumPins::QueryInterface" );
#endif

    if( riid == IID_IUnknown ||
        riid == IID_IEnumPins )
    {
gbazin's avatar
   
gbazin committed
1009
        AddRef();
gbazin's avatar
   
gbazin committed
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
        *ppv = (IEnumPins *)this;
        return NOERROR;
    }
    else
    {
        *ppv = NULL;
        return E_NOINTERFACE;
    }
};
STDMETHODIMP_(ULONG) CaptureEnumPins::AddRef()
{
1021
#ifdef DEBUG_DSHOW_L1
1022
    msg_Dbg( p_input, "CaptureEnumPins::AddRef (ref: %i)", i_ref );
gbazin's avatar
   
gbazin committed
1023
1024
#endif

gbazin's avatar
   
gbazin committed
1025
    return i_ref++;
gbazin's avatar
   
gbazin committed
1026
1027
1028
};
STDMETHODIMP_(ULONG) CaptureEnumPins::Release()
{
1029
#ifdef DEBUG_DSHOW_L1
1030
    msg_Dbg( p_input, "CaptureEnumPins::Release (ref: %i)", i_ref );
gbazin's avatar
   
gbazin committed
1031
1032
#endif

1033
    if( !InterlockedDecrement(&i_ref) ) delete this;
gbazin's avatar
   
gbazin committed
1034

1035
    return 0;
gbazin's avatar
   
gbazin committed
1036
1037
1038
1039
1040
1041
};

/* IEnumPins */
STDMETHODIMP CaptureEnumPins::Next( ULONG cPins, IPin ** ppPins,
                                    ULONG * pcFetched )
{
damienf's avatar
damienf committed
1042
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
1043
1044
1045
    msg_Dbg( p_input, "CaptureEnumPins::Next" );
#endif

gbazin's avatar
gbazin committed
1046
    unsigned int i_fetched = 0;
gbazin's avatar
   
gbazin committed
1047
1048
1049
1050
1051
1052

    if( i_position < 1 && cPins > 0 )
    {
        IPin *pPin = p_filter->CustomGetPin();
        *ppPins = pPin;
        pPin->AddRef();
gbazin's avatar
gbazin committed
1053
        i_fetched = 1;
gbazin's avatar
   
gbazin committed
1054
1055
1056
        i_position++;
    }

gbazin's avatar
gbazin committed
1057
1058
1059
    if( pcFetched ) *pcFetched = i_fetched;

    return (i_fetched == cPins) ? S_OK : S_FALSE;
gbazin's avatar
   
gbazin committed
1060
1061
1062
};
STDMETHODIMP CaptureEnumPins::Skip( ULONG cPins )
{
damienf's avatar
damienf committed
1063
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
1064
1065
1066
    msg_Dbg( p_input, "CaptureEnumPins::Skip" );
#endif

gbazin's avatar
gbazin committed
1067
1068
1069
    i_position += cPins;

    if( i_position > 1 )
gbazin's avatar
   
gbazin committed
1070
1071
1072
1073
    {
        return S_FALSE;
    }

gbazin's avatar
gbazin committed
1074
    return S_OK;
gbazin's avatar
   
gbazin committed
1075
1076
1077
};
STDMETHODIMP CaptureEnumPins::Reset()
{
damienf's avatar
damienf committed
1078
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
1079
1080
1081
1082
1083
1084
1085
1086
    msg_Dbg( p_input, "CaptureEnumPins::Reset" );
#endif

    i_position = 0;
    return S_OK;
};
STDMETHODIMP CaptureEnumPins::Clone( IEnumPins **ppEnum )
{
damienf's avatar
damienf committed
1087
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
    msg_Dbg( p_input, "CaptureEnumPins::Clone" );
#endif

    *ppEnum = new CaptureEnumPins( p_input, p_filter, this );
    if( *ppEnum == NULL ) return E_OUTOFMEMORY;

    return NOERROR;
};

/****************************************************************************
 * Implementation of our dummy directshow enummediatypes class
 ****************************************************************************/
gbazin's avatar
gbazin committed
1100
CaptureEnumMediaTypes::CaptureEnumMediaTypes( vlc_object_t *_p_input,
1101
    CapturePin *_p_pin, CaptureEnumMediaTypes *pEnumMediaTypes )
gbazin's avatar
   
gbazin committed
1102
1103
1104
1105
1106
1107
1108
1109
  : p_input( _p_input ), p_pin( _p_pin ), i_ref( 1 )
{
    /* Hold a reference count on our filter */
    p_pin->AddRef();

    /* Are we creating a new enumerator */
    if( pEnumMediaTypes == NULL )
    {
gbazin's avatar
gbazin committed
1110
        CopyMediaType(&cx_media_type, &p_pin->cx_media_type); 
gbazin's avatar
   
gbazin committed
1111
1112
1113
1114
        i_position = 0;
    }
    else
    {
gbazin's avatar
gbazin committed
1115
        CopyMediaType(&cx_media_type, &pEnumMediaTypes->cx_media_type); 
gbazin's avatar
   
gbazin committed
1116
1117
1118
1119
1120
1121
        i_position = pEnumMediaTypes->i_position;
    }
}

CaptureEnumMediaTypes::~CaptureEnumMediaTypes()
{
damienf's avatar
damienf committed
1122
#ifdef DEBUG_DSHOW_L1
1123
1124
    msg_Dbg( p_input, "CaptureEnumMediaTypes::~CaptureEnumMediaTypes" );
#endif
1125
    FreeMediaType(cx_media_type);
gbazin's avatar
   
gbazin committed
1126
1127
1128
1129
1130
1131
    p_pin->Release();
}

/* IUnknown methods */
STDMETHODIMP CaptureEnumMediaTypes::QueryInterface( REFIID riid, void **ppv )
{
damienf's avatar
damienf committed
1132
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
1133
1134
1135
1136
1137
1138
    msg_Dbg( p_input, "CaptureEnumMediaTypes::QueryInterface" );
#endif

    if( riid == IID_IUnknown ||
        riid == IID_IEnumMediaTypes )
    {
gbazin's avatar
   
gbazin committed
1139
        AddRef();
gbazin's avatar
   
gbazin committed
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
        *ppv = (IEnumMediaTypes *)this;
        return NOERROR;
    }
    else
    {
        *ppv = NULL;
        return E_NOINTERFACE;
    }
};
STDMETHODIMP_(ULONG) CaptureEnumMediaTypes::AddRef()
{
1151
#ifdef DEBUG_DSHOW_L1
1152
    msg_Dbg( p_input, "CaptureEnumMediaTypes::AddRef (ref: %i)", i_ref );
gbazin's avatar
   
gbazin committed
1153
1154
#endif

gbazin's avatar
   
gbazin committed
1155
    return i_ref++;
gbazin's avatar
   
gbazin committed
1156
1157
1158
};
STDMETHODIMP_(ULONG) CaptureEnumMediaTypes::Release()
{
1159
#ifdef DEBUG_DSHOW_L1
1160
    msg_Dbg( p_input, "CaptureEnumMediaTypes::Release (ref: %i)", i_ref );
gbazin's avatar
   
gbazin committed
1161
1162
#endif

1163
    if( !InterlockedDecrement(&i_ref) ) delete this;
gbazin's avatar
   
gbazin committed
1164

1165
    return 0;
gbazin's avatar
   
gbazin committed
1166
1167
1168
1169
1170
1171
1172
};

/* IEnumMediaTypes */
STDMETHODIMP CaptureEnumMediaTypes::Next( ULONG cMediaTypes,
                                          AM_MEDIA_TYPE ** ppMediaTypes,
                                          ULONG * pcFetched )
{
damienf's avatar
damienf committed
1173
#ifdef DEBUG_DSHOW_L1
1174
    msg_Dbg( p_input, "CaptureEnumMediaTypes::Next " );
gbazin's avatar
   
gbazin committed
1175
#endif
1176
1177
1178
    ULONG copied = 0;
    ULONG offset = 0;
    ULONG max = p_pin->media_type_count;
gbazin's avatar
   
gbazin committed
1179

1180
    if( ! ppMediaTypes ) 
1181
        return E_POINTER;
1182

1183
1184
1185
    if( (! pcFetched)  && (cMediaTypes > 1) )
       return E_POINTER;

1186
1187
1188
1189
    /*
    ** use connection media type as first entry in iterator if it exists
    */
    copied = 0;
gbazin's avatar
gbazin committed
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
    if( cx_media_type.subtype != GUID_NULL )
    {
        ++max;
        if( i_position == 0 )
        {
            ppMediaTypes[copied] =
                (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
            if( CopyMediaType(ppMediaTypes[copied], &cx_media_type) != S_OK )
                return E_OUTOFMEMORY;
            ++i_position; 
            ++copied;
        }
1202
    }
1203

1204
    while( (copied < cMediaTypes) && (i_position < max)  )
1205
    {
gbazin's avatar
gbazin committed
1206
1207
1208
1209
        ppMediaTypes[copied] =
            (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
        if( CopyMediaType( ppMediaTypes[copied],
                           &p_pin->media_types[i_position-offset]) != S_OK )
1210
            return E_OUTOFMEMORY;
1211

gbazin's avatar
gbazin committed
1212
        ++copied;
1213
        ++i_position; 
1214
    }
1215

gbazin's avatar
gbazin committed
1216
    if( pcFetched )  *pcFetched = copied;
1217

1218
    return (copied == cMediaTypes) ? S_OK : S_FALSE;
gbazin's avatar
   
gbazin committed
1219
1220
1221
};
STDMETHODIMP CaptureEnumMediaTypes::Skip( ULONG cMediaTypes )
{
1222
1223
1224
    ULONG max =  p_pin->media_type_count;
    if( cx_media_type.subtype != GUID_NULL )
    {
gbazin's avatar
gbazin committed
1225
        max = 1;
1226
    }
damienf's avatar
damienf committed
1227
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
1228
1229
1230
    msg_Dbg( p_input, "CaptureEnumMediaTypes::Skip" );
#endif

1231
    i_position += cMediaTypes;
1232
    return (i_position < max) ? S_OK : S_FALSE;
gbazin's avatar
   
gbazin committed
1233
1234
1235
};
STDMETHODIMP CaptureEnumMediaTypes::Reset()
{
damienf's avatar
damienf committed
1236
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
1237
1238
1239
    msg_Dbg( p_input, "CaptureEnumMediaTypes::Reset" );
#endif

1240
1241
    FreeMediaType(cx_media_type);
    CopyMediaType(&cx_media_type, &p_pin->cx_media_type); 
gbazin's avatar
   
gbazin committed
1242
1243
1244
1245
1246
    i_position = 0;
    return S_OK;
};
STDMETHODIMP CaptureEnumMediaTypes::Clone( IEnumMediaTypes **ppEnum )
{
damienf's avatar
damienf committed
1247
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed