filter.cpp 40.9 KB
Newer Older
gbazin's avatar
   
gbazin committed
1
2
3
/*****************************************************************************
 * filter.c : DirectShow access module for vlc
 *****************************************************************************
4
 * Copyright (C) 2002 the VideoLAN team
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
 *
 * 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
dionoea's avatar
dionoea committed
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
gbazin's avatar
   
gbazin committed
22
23
24
25
26
27
28
29
30
31
32
33
34
 *****************************************************************************/

/*****************************************************************************
 * 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
/*****************************************************************************
 * DirectShow GUIDs.
50
 * Easier to define them here as mingw doesn't provide them all.
gbazin's avatar
   
gbazin committed
51
52
53
 *****************************************************************************/
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}};
55
56
//const GUID IID_IPropertyBag = {0x55272A00, 0x42CB, 0x11CE, {0x81, 0x35, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51}};
extern const GUID IID_IPropertyBag;
gbazin's avatar
   
gbazin committed
57
58
59
60
61
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}};

62
63
64
65
//const GUID IID_IUnknown = {0x00000000, 0x0000, 0x0000, {0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46}};
extern const GUID IID_IUnknown;
//const GUID IID_IPersist = {0x0000010c, 0x0000, 0x0000, {0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46}};
extern const GUID IID_IPersist;
gbazin's avatar
   
gbazin committed
66
67
68
69
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}};
70
extern const GUID IID_IMemInputPin;
gbazin's avatar
   
gbazin committed
71
72
73
74

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}};

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

77
78
//const GUID IID_ISpecifyPropertyPages = {0xb196b28b, 0xbab4, 0x101a, {0xb6, 0x9c, 0x00, 0xaa, 0x00, 0x34, 0x1d, 0x07}};
extern const GUID IID_ISpecifyPropertyPages;
gbazin's avatar
   
gbazin committed
79

80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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}};

95
/* Video Format */
96

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

gbazin's avatar
   
gbazin committed
106
107
108
/* 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
109
110
111
112
113
114
115
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
116
/* Packed YUV formats */
gbazin's avatar
   
gbazin committed
117
118
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
119
const GUID MEDIASUBTYPE_Y211 = {0x31313259, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
gbazin's avatar
   
gbazin committed
120
121
122
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
123
124
125

/* Planar YUV formats */
const GUID MEDIASUBTYPE_YVU9 = {0x39555659, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
gbazin's avatar
   
gbazin committed
126
const GUID MEDIASUBTYPE_YV12 = {0x32315659, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
gbazin's avatar
   
gbazin committed
127
128
129
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
130

gbazin's avatar
   
gbazin committed
131
132
133
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}};
134
const GUID MEDIASUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
gbazin's avatar
   
gbazin committed
135

gbazin's avatar
   
gbazin committed
136
137
138
139
140
/* 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
141
142
143
144
145
146
/* 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}};

147
148
149
/* MJPG format */
const GUID MEDIASUBTYPE_MJPG = {0x47504A4D, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};

150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/* 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}};

177
178
//const GUID GUID_NULL = {0x0000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
extern const GUID GUID_NULL;
gbazin's avatar
   
gbazin committed
179

gbazin's avatar
   
gbazin committed
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
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;
199
200
201
202

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

    if( pmtSource->cbFormat && pmtSource->pbFormat )
gbazin's avatar
   
gbazin committed
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
    {
        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
224
int GetFourCCFromMediaType( const AM_MEDIA_TYPE &media_type )
225
226
227
228
229
{
    int i_fourcc = 0;

    if( media_type.majortype == MEDIATYPE_Video )
    {
230
        /* currently only support this type of video info format */
231
        if( 1 /* media_type.formattype == FORMAT_VideoInfo */ )
gbazin's avatar
gbazin committed
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
280
281
282
283
284
285
286
287
        {
            /* 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' );
288
289
290
291
292

            /* MJPEG format */
            else if( media_type.subtype == MEDIASUBTYPE_MJPG )
                i_fourcc = VLC_FOURCC( 'M', 'J', 'P', 'G' );

gbazin's avatar
gbazin committed
293
        }
294
295
296
    }
    else if( media_type.majortype == MEDIATYPE_Audio )
    {
297
        /* currently only support this type of audio info format */
298
299
300
301
302
303
304
305
306
        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
307
    {
308
        if( media_type.subtype == MEDIASUBTYPE_MPEG2_PROGRAM )
gbazin's avatar
gbazin committed
309
            i_fourcc = VLC_FOURCC( 'm', 'p', '2', 'p' );
310
        else if( media_type.subtype == MEDIASUBTYPE_MPEG2_TRANSPORT )
gbazin's avatar
gbazin committed
311
            i_fourcc = VLC_FOURCC( 'm', 'p', '2', 't' );
312
    }
gbazin's avatar
gbazin committed
313

314
315
316
    return i_fourcc;
}

gbazin's avatar
   
gbazin committed
317
318
319
320
/****************************************************************************
 * Implementation of our dummy directshow filter pin class
 ****************************************************************************/

gbazin's avatar
gbazin committed
321
322
CapturePin::CapturePin( vlc_object_t *_p_input, access_sys_t *_p_sys,
                        CaptureFilter *_p_filter,
323
                        AM_MEDIA_TYPE *mt, size_t mt_count )
gbazin's avatar
gbazin committed
324
325
326
  : 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
327
{
328
329
330
    cx_media_type.majortype = mt[0].majortype;
    cx_media_type.subtype   = GUID_NULL;
    cx_media_type.pbFormat  = NULL;
331
    cx_media_type.cbFormat  = 0;
332
    cx_media_type.pUnk      = NULL;
gbazin's avatar
   
gbazin committed
333
334
335
336
}

CapturePin::~CapturePin()
{
337
338
339
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::~CapturePin" );
#endif
340
341
    for( size_t c=0; c<media_type_count; c++ )
    {
342
        FreeMediaType(media_types[c]);
343
344
    }
    FreeMediaType(cx_media_type);
gbazin's avatar
   
gbazin committed
345
346
347
348
}

HRESULT CapturePin::CustomGetSample( VLCMediaSample *vlc_sample )
{
349
350
351
352
353
#if 0 //def DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::CustomGetSample" );
#endif

    vlc_mutex_lock( &p_sys->lock );
gbazin's avatar
   
gbazin committed
354
355
356
357
    if( samples_queue.size() )
    {
        *vlc_sample = samples_queue.back();
        samples_queue.pop_back();
358
        vlc_mutex_unlock( &p_sys->lock );
gbazin's avatar
   
gbazin committed
359
360
        return S_OK;
    }
361
    vlc_mutex_unlock( &p_sys->lock );
gbazin's avatar
   
gbazin committed
362
363
364
    return S_FALSE;
}

365
AM_MEDIA_TYPE &CapturePin::CustomGetMediaType()
gbazin's avatar
   
gbazin committed
366
{
367
    return cx_media_type;
gbazin's avatar
   
gbazin committed
368
369
370
371
372
}

/* IUnknown methods */
STDMETHODIMP CapturePin::QueryInterface(REFIID riid, void **ppv)
{
damienf's avatar
damienf committed
373
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
374
375
376
377
378
379
    msg_Dbg( p_input, "CapturePin::QueryInterface" );
#endif

    if( riid == IID_IUnknown ||
        riid == IID_IPin )
    {
gbazin's avatar
   
gbazin committed
380
        AddRef();
gbazin's avatar
   
gbazin committed
381
382
383
384
385
        *ppv = (IPin *)this;
        return NOERROR;
    }
    if( riid == IID_IMemInputPin )
    {
gbazin's avatar
   
gbazin committed
386
        AddRef();
gbazin's avatar
   
gbazin committed
387
388
389
390
391
        *ppv = (IMemInputPin *)this;
        return NOERROR;
    }
    else
    {
damienf's avatar
damienf committed
392
#ifdef DEBUG_DSHOW_L1
393
394
395
396
397
398
399
400
        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
401
402
403
404
        *ppv = NULL;
        return E_NOINTERFACE;
    }
}
405

gbazin's avatar
   
gbazin committed
406
407
STDMETHODIMP_(ULONG) CapturePin::AddRef()
{
408
#ifdef DEBUG_DSHOW_L1
409
    msg_Dbg( p_input, "CapturePin::AddRef (ref: %i)", i_ref );
gbazin's avatar
   
gbazin committed
410
411
#endif

gbazin's avatar
   
gbazin committed
412
    return i_ref++;
gbazin's avatar
   
gbazin committed
413
414
415
};
STDMETHODIMP_(ULONG) CapturePin::Release()
{
416
#ifdef DEBUG_DSHOW_L1
417
    msg_Dbg( p_input, "CapturePin::Release (ref: %i)", i_ref );
gbazin's avatar
   
gbazin committed
418
419
#endif

420
    if( !InterlockedDecrement(&i_ref) ) delete this;
gbazin's avatar
   
gbazin committed
421

422
    return 0;
gbazin's avatar
   
gbazin committed
423
424
425
426
427
428
};

/* IPin methods */
STDMETHODIMP CapturePin::Connect( IPin * pReceivePin,
                                  const AM_MEDIA_TYPE *pmt )
{
gbazin's avatar
gbazin committed
429
    if( State_Running == p_filter->state )
430
    {
gbazin's avatar
gbazin committed
431
432
433
434
435
436
437
438
439
440
441
        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;
442
                
gbazin's avatar
gbazin committed
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
    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;
465
        }
466
    }
gbazin's avatar
gbazin committed
467
468
469

    msg_Dbg( p_input, "CapturePin::Connect [OK]" );
    return S_OK;
gbazin's avatar
   
gbazin committed
470
471
472
473
}
STDMETHODIMP CapturePin::ReceiveConnection( IPin * pConnector,
                                            const AM_MEDIA_TYPE *pmt )
{
474
    if( State_Stopped != p_filter->state )
475
    {
gbazin's avatar
gbazin committed
476
        msg_Dbg( p_input, "CapturePin::ReceiveConnection [not stopped]" );
477
        return VFW_E_NOT_STOPPED;
478
    }
gbazin's avatar
   
gbazin committed
479

480
481
    if( !pConnector || !pmt )
    {
gbazin's avatar
gbazin committed
482
        msg_Dbg( p_input, "CapturePin::ReceiveConnection [null pointer]" );
483
        return E_POINTER;
484
    }
gbazin's avatar
   
gbazin committed
485

486
    if( p_connected_pin )
487
    {
gbazin's avatar
gbazin committed
488
        msg_Dbg( p_input, "CapturePin::ReceiveConnection [already connected]");
489
        return VFW_E_ALREADY_CONNECTED;
490
    }
491
492

    if( S_OK != QueryAccept(pmt) )
493
    {
gbazin's avatar
gbazin committed
494
495
        msg_Dbg( p_input, "CapturePin::ReceiveConnection "
                 "[media type not accepted]" );
496
        return VFW_E_TYPE_NOT_ACCEPTED;
497
498
499
    }

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

gbazin's avatar
   
gbazin committed
501
502
    p_connected_pin = pConnector;
    p_connected_pin->AddRef();
gbazin's avatar
   
gbazin committed
503

504
505
    FreeMediaType( cx_media_type );
    return CopyMediaType( &cx_media_type, pmt );
gbazin's avatar
   
gbazin committed
506
507
508
}
STDMETHODIMP CapturePin::Disconnect()
{
509
510
    if( ! p_connected_pin )
    {
gbazin's avatar
gbazin committed
511
512
        msg_Dbg( p_input, "CapturePin::Disconnect [not connected]" );
        return S_FALSE;
513
    }
gbazin's avatar
   
gbazin committed
514

515
    msg_Dbg( p_input, "CapturePin::Disconnect [OK]" );
516

517
    /* samples_queue was already flushed in EndFlush() */
518

519
    p_connected_pin->Release();
gbazin's avatar
   
gbazin committed
520
    p_connected_pin = NULL;
521
522
    //FreeMediaType( cx_media_type );
    //cx_media_type.subtype = GUID_NULL;
523

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

gbazin's avatar
   
gbazin committed
534
535
536
    p_connected_pin->AddRef();
    *pPin = p_connected_pin;

537
538
    msg_Dbg( p_input, "CapturePin::ConnectedTo [OK]" );

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

    return CopyMediaType( pmt, &cx_media_type );
gbazin's avatar
   
gbazin committed
550
551
552
553
554
555
556
557
558
559
}
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();

560
    memcpy(pInfo->achName, PIN_NAME, sizeof(PIN_NAME));
gbazin's avatar
   
gbazin committed
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
    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
579
580
581
582

    *Id = L"VideoLAN Capture Pin";

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

    if( media_types[0].majortype != pmt->majortype )
593
    {
gbazin's avatar
gbazin committed
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
        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) ) )
611
        {
gbazin's avatar
gbazin committed
612
613
            msg_Dbg( p_input, "CapturePin::QueryAccept [video size wxh == 0]");
            return S_FALSE;
614
        }
gbazin's avatar
gbazin committed
615
616

        msg_Dbg( p_input, "CapturePin::QueryAccept [OK] "
617
                 "(width=%ld, height=%ld, chroma=%4.4s, fps=%f)",
gbazin's avatar
gbazin committed
618
619
                 ((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biWidth,
                 ((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biHeight,
620
621
                 (char *)&i_fourcc,
		 10000000.0f/((float)((VIDEOINFOHEADER *)pmt->pbFormat)->AvgTimePerFrame) );
622
    }
623
    else if( pmt->majortype == MEDIATYPE_Audio )
gbazin's avatar
gbazin committed
624
625
626
627
628
629
630
631
    {
        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 );
    }   
632
633
634
635
636
    else
    {
        msg_Dbg( p_input, "CapturePin::QueryAccept [OK] (stream format=%4.4s)",
                 (char *)&i_fourcc );
    }
gbazin's avatar
gbazin committed
637
638
639
640
641

    if( p_connected_pin )
    {
        FreeMediaType( cx_media_type );
        CopyMediaType( &cx_media_type, pmt );
642
    }
gbazin's avatar
gbazin committed
643
644

    return S_OK;
gbazin's avatar
   
gbazin committed
645
646
647
}
STDMETHODIMP CapturePin::EnumMediaTypes( IEnumMediaTypes **ppEnum )
{
damienf's avatar
damienf committed
648
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
649
650
651
652
653
654
655
656
657
658
659
    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
660
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
661
662
663
664
665
666
667
668
669
    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
670
    return S_OK;
gbazin's avatar
   
gbazin committed
671
672
673
674
675
676
}
STDMETHODIMP CapturePin::BeginFlush( void )
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::BeginFlush" );
#endif
gbazin's avatar
   
gbazin committed
677
    return S_OK;
gbazin's avatar
   
gbazin committed
678
679
680
681
682
683
}
STDMETHODIMP CapturePin::EndFlush( void )
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::EndFlush" );
#endif
684
685
686
687
688
689
690
691
692
693
694
695

    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 );

gbazin's avatar
   
gbazin committed
696
    return S_OK;
gbazin's avatar
   
gbazin committed
697
698
699
700
701
702
703
704
}
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
705
    return S_OK;
gbazin's avatar
   
gbazin committed
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
}

/* 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
731

gbazin's avatar
   
gbazin committed
732
733
734
735
    return E_NOTIMPL;
}
STDMETHODIMP CapturePin::Receive( IMediaSample *pSample )
{
736
737
#if 0 //def DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::Receive" );
gbazin's avatar
   
gbazin committed
738
739
#endif

gbazin's avatar
   
gbazin committed
740
    pSample->AddRef();
gbazin's avatar
   
gbazin committed
741
742
    mtime_t i_timestamp = mdate() * 10;
    VLCMediaSample vlc_sample = {pSample, i_timestamp};
743
744

    vlc_mutex_lock( &p_sys->lock );
gbazin's avatar
   
gbazin committed
745
746
747
748
749
750
751
752
    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
753
        vlc_sample.p_sample->Release();
gbazin's avatar
   
gbazin committed
754
755
    }

756
757
758
    vlc_cond_signal( &p_sys->wait );
    vlc_mutex_unlock( &p_sys->lock );

gbazin's avatar
   
gbazin committed
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
    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
788
789
790
791
792
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
793
794
795
796
797
{
}

CaptureFilter::~CaptureFilter()
{
798
799
800
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::~CaptureFilter" );
#endif
gbazin's avatar
   
gbazin committed
801
802
803
804
805
806
    p_pin->Release();
}

/* IUnknown methods */
STDMETHODIMP CaptureFilter::QueryInterface( REFIID riid, void **ppv )
{
damienf's avatar
damienf committed
807
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
808
809
810
811
812
    msg_Dbg( p_input, "CaptureFilter::QueryInterface" );
#endif

    if( riid == IID_IUnknown )
    {
gbazin's avatar
   
gbazin committed
813
        AddRef();
gbazin's avatar
   
gbazin committed
814
815
816
817
818
        *ppv = (IUnknown *)this;
        return NOERROR;
    }
    if( riid == IID_IPersist )
    {
gbazin's avatar
   
gbazin committed
819
        AddRef();
gbazin's avatar
   
gbazin committed
820
821
822
823
824
        *ppv = (IPersist *)this;
        return NOERROR;
    }
    if( riid == IID_IMediaFilter )
    {
gbazin's avatar
   
gbazin committed
825
        AddRef();
gbazin's avatar
   
gbazin committed
826
827
828
829
830
        *ppv = (IMediaFilter *)this;
        return NOERROR;
    }
    if( riid == IID_IBaseFilter )
    {
gbazin's avatar
   
gbazin committed
831
        AddRef();
gbazin's avatar
   
gbazin committed
832
833
834
835
836
        *ppv = (IBaseFilter *)this;
        return NOERROR;
    }
    else
    {
damienf's avatar
damienf committed
837
#ifdef DEBUG_DSHOW_L1
838
839
840
841
842
843
844
845
        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
846
847
848
849
850
851
        *ppv = NULL;
        return E_NOINTERFACE;
    }
};
STDMETHODIMP_(ULONG) CaptureFilter::AddRef()
{
852
#ifdef DEBUG_DSHOW_L1
853
    msg_Dbg( p_input, "CaptureFilter::AddRef (ref: %i)", i_ref );
gbazin's avatar
   
gbazin committed
854
855
#endif

gbazin's avatar
   
gbazin committed
856
    return i_ref++;
gbazin's avatar
   
gbazin committed
857
858
859
};
STDMETHODIMP_(ULONG) CaptureFilter::Release()
{
860
#ifdef DEBUG_DSHOW_L1
861
    msg_Dbg( p_input, "CaptureFilter::Release (ref: %i)", i_ref );
gbazin's avatar
   
gbazin committed
862
863
#endif

864
    if( !InterlockedDecrement(&i_ref) ) delete this;
gbazin's avatar
   
gbazin committed
865

866
    return 0;
gbazin's avatar
   
gbazin committed
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
};

/* 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
882
    msg_Dbg( p_input, "CaptureFilter::GetState %i", state );
gbazin's avatar
   
gbazin committed
883
#endif
gbazin's avatar
   
gbazin committed
884
885
886

    *State = state;
    return S_OK;
gbazin's avatar
   
gbazin committed
887
888
889
890
891
892
893
};
STDMETHODIMP CaptureFilter::SetSyncSource(IReferenceClock *pClock)
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::SetSyncSource" );
#endif

gbazin's avatar
   
gbazin committed
894
    return S_OK;
gbazin's avatar
   
gbazin committed
895
896
897
898
899
900
};
STDMETHODIMP CaptureFilter::GetSyncSource(IReferenceClock **pClock)
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::GetSyncSource" );
#endif
gbazin's avatar
   
gbazin committed
901
902
903

    *pClock = NULL;
    return NOERROR;
gbazin's avatar
   
gbazin committed
904
905
906
907
908
909
};
STDMETHODIMP CaptureFilter::Stop()
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::Stop" );
#endif
gbazin's avatar
   
gbazin committed
910

911
912
    p_pin->EndFlush();

gbazin's avatar
   
gbazin committed
913
    state = State_Stopped;
gbazin's avatar
   
gbazin committed
914
    return S_OK;
gbazin's avatar
   
gbazin committed
915
916
917
918
919
920
};
STDMETHODIMP CaptureFilter::Pause()
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::Pause" );
#endif
gbazin's avatar
   
gbazin committed
921
922

    state = State_Paused;
gbazin's avatar
   
gbazin committed
923
    return S_OK;
gbazin's avatar
   
gbazin committed
924
925
926
927
928
929
};
STDMETHODIMP CaptureFilter::Run(REFERENCE_TIME tStart)
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::Run" );
#endif
gbazin's avatar
   
gbazin committed
930
931

    state = State_Running;
gbazin's avatar
   
gbazin committed
932
    return S_OK;
gbazin's avatar
   
gbazin committed
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
};

/* 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

959
    memcpy(pInfo->achName, FILTER_NAME, sizeof(FILTER_NAME));
gbazin's avatar
   
gbazin committed
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994

    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
995
CaptureEnumPins::CaptureEnumPins( vlc_object_t *_p_input,
gbazin's avatar
   
gbazin committed
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
                                  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
1017
#ifdef DEBUG_DSHOW_L1
1018
1019
    msg_Dbg( p_input, "CaptureEnumPins::~CaptureEnumPins" );
#endif
gbazin's avatar
   
gbazin committed
1020
1021
1022
1023
1024
1025
    p_filter->Release();
}

/* IUnknown methods */
STDMETHODIMP CaptureEnumPins::QueryInterface( REFIID riid, void **ppv )
{
damienf's avatar
damienf committed
1026
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
1027
1028
1029
1030
1031
1032
    msg_Dbg( p_input, "CaptureEnumPins::QueryInterface" );
#endif

    if( riid == IID_IUnknown ||
        riid == IID_IEnumPins )
    {
gbazin's avatar
   
gbazin committed
1033
        AddRef();
gbazin's avatar
   
gbazin committed
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
        *ppv = (IEnumPins *)this;
        return NOERROR;
    }
    else
    {
        *ppv = NULL;
        return E_NOINTERFACE;
    }
};
STDMETHODIMP_(ULONG) CaptureEnumPins::AddRef()
{
1045
#ifdef DEBUG_DSHOW_L1
1046
    msg_Dbg( p_input, "CaptureEnumPins::AddRef (ref: %i)", i_ref );
gbazin's avatar
   
gbazin committed
1047
1048
#endif

gbazin's avatar
   
gbazin committed
1049
    return i_ref++;
gbazin's avatar
   
gbazin committed
1050
1051
1052
};
STDMETHODIMP_(ULONG) CaptureEnumPins::Release()
{
1053
#ifdef DEBUG_DSHOW_L1
1054
    msg_Dbg( p_input, "CaptureEnumPins::Release (ref: %i)", i_ref );
gbazin's avatar
   
gbazin committed
1055
1056
#endif

1057
    if( !InterlockedDecrement(&i_ref) ) delete this;
gbazin's avatar
   
gbazin committed
1058

1059
    return 0;
gbazin's avatar
   
gbazin committed
1060
1061
1062
1063
1064
1065
};

/* IEnumPins */
STDMETHODIMP CaptureEnumPins::Next( ULONG cPins, IPin ** ppPins,
                                    ULONG * pcFetched )
{
damienf's avatar
damienf committed
1066
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
1067
1068
1069
    msg_Dbg( p_input, "CaptureEnumPins::Next" );
#endif

gbazin's avatar
gbazin committed
1070
    unsigned int i_fetched = 0;
gbazin's avatar
   
gbazin committed
1071
1072
1073
1074
1075
1076

    if( i_position < 1 && cPins > 0 )
    {
        IPin *pPin = p_filter->CustomGetPin();
        *ppPins = pPin;
        pPin->AddRef();
gbazin's avatar
gbazin committed
1077
        i_fetched = 1;
gbazin's avatar
   
gbazin committed
1078
1079
1080
        i_position++;
    }

gbazin's avatar
gbazin committed
1081
1082
1083
    if( pcFetched ) *pcFetched = i_fetched;

    return (i_fetched == cPins) ? S_OK : S_FALSE;
gbazin's avatar
   
gbazin committed
1084
1085
1086
};
STDMETHODIMP CaptureEnumPins::Skip( ULONG cPins )
{
damienf's avatar
damienf committed
1087
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
1088
1089
1090
    msg_Dbg( p_input, "CaptureEnumPins::Skip" );
#endif

gbazin's avatar
gbazin committed
1091
1092
1093
    i_position += cPins;

    if( i_position > 1 )
gbazin's avatar
   
gbazin committed
1094
1095
1096
1097
    {
        return S_FALSE;
    }

gbazin's avatar
gbazin committed
1098
    return S_OK;
gbazin's avatar
   
gbazin committed
1099
1100
1101
};
STDMETHODIMP CaptureEnumPins::Reset()
{
damienf's avatar
damienf committed
1102
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
1103
1104
1105
1106
1107
1108
1109
1110
    msg_Dbg( p_input, "CaptureEnumPins::Reset" );
#endif

    i_position = 0;
    return S_OK;
};
STDMETHODIMP CaptureEnumPins::Clone( IEnumPins **ppEnum )
{
damienf's avatar
damienf committed
1111
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
    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
1124
CaptureEnumMediaTypes::CaptureEnumMediaTypes( vlc_object_t *_p_input,
1125
    CapturePin *_p_pin, CaptureEnumMediaTypes *pEnumMediaTypes )
gbazin's avatar
   
gbazin committed
1126
1127
1128
1129
1130
1131
1132
1133
  : 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
1134
        CopyMediaType(&cx_media_type, &p_pin->cx_media_type); 
gbazin's avatar
   
gbazin committed
1135
1136
1137
1138
        i_position = 0;
    }
    else
    {
gbazin's avatar
gbazin committed
1139
        CopyMediaType(&cx_media_type, &pEnumMediaTypes->cx_media_type); 
gbazin's avatar
   
gbazin committed
1140
1141
1142
1143
1144
1145
        i_position = pEnumMediaTypes->i_position;
    }
}

CaptureEnumMediaTypes::~CaptureEnumMediaTypes()
{
damienf's avatar
damienf committed
1146
#ifdef DEBUG_DSHOW_L1
1147
1148
    msg_Dbg( p_input, "CaptureEnumMediaTypes::~CaptureEnumMediaTypes" );
#endif
1149
    FreeMediaType(cx_media_type);
gbazin's avatar
   
gbazin committed
1150
1151
1152
1153
1154
1155
    p_pin->Release();
}

/* IUnknown methods */
STDMETHODIMP CaptureEnumMediaTypes::QueryInterface( REFIID riid, void **ppv )
{
damienf's avatar
damienf committed
1156
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
   
gbazin committed
1157
1158
1159
1160
1161
1162
    msg_Dbg( p_input, "CaptureEnumMediaTypes::QueryInterface" );
#endif

    if( riid == IID_IUnknown ||
        riid == IID_IEnumMediaTypes )
    {
gbazin's avatar
   
gbazin committed
1163
        AddRef();
gbazin's avatar
   
gbazin committed
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
        *ppv = (IEnumMediaTypes *)this;
        return NOERROR;
    }
    else
    {
        *ppv = NULL;
        return E_NOINTERFACE;
    }
};
STDMETHODIMP_(ULONG) CaptureEnumMediaTypes::AddRef()
{
1175
#ifdef DEBUG_DSHOW_L1
1176
    msg_Dbg( p_input, "CaptureEnumMediaTypes::AddRef (ref: %i)", i_ref );
gbazin's avatar
   
gbazin committed
1177
1178
#endif

gbazin's avatar
   
gbazin committed
1179
    return i_ref++;
gbazin's avatar
   
gbazin committed
1180
1181
1182
};
STDMETHODIMP_(ULONG) CaptureEnumMediaTypes::Release()
{
1183
#ifdef DEBUG_DSHOW_L1
1184
    msg_Dbg( p_input, "CaptureEnumMediaTypes::Release (ref: %i)", i_ref );
gbazin's avatar
   
gbazin committed
1185
1186
#endif

1187
    if( !InterlockedDecrement(&i_ref) ) delete this;
gbazin's avatar
   
gbazin committed
1188

1189
    return 0;
gbazin's avatar
   
gbazin committed
1190
1191
1192
1193
1194
1195
1196
};

/* IEnumMediaTypes */
STDMETHODIMP CaptureEnumMediaTypes::Next( ULONG cMediaTypes,
                                          AM_MEDIA_TYPE ** ppMediaTypes,
                                          ULONG * pcFetched )
{
damienf's avatar
damienf committed
1197
#ifdef DEBUG_DSHOW_L1
1198
    msg_Dbg( p_input, "CaptureEnumMediaTypes::Next " );
gbazin's avatar
   
gbazin committed
1199
#endif
1200
1201
1202
    ULONG copied = 0;
    ULONG offset = 0;
    ULONG max = p_pin->media_type_count;
gbazin's avatar
   
gbazin committed
1203

1204
    if( ! ppMediaTypes ) 
1205
        return E_POINTER;
1206

1207
1208
1209
    if( (! pcFetched)  && (cMediaTypes > 1) )
       return E_POINTER;

1210
1211
1212
1213
    /*
    ** use connection media type as first entry in iterator if it exists
    */
    copied = 0;
gbazin's avatar
gbazin committed
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
    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;
        }
1226
    }
1227

1228
    while( (copied < cMediaTypes) && (i_position < max)  )
1229
    {
gbazin's avatar
gbazin committed
1230
1231
1232
1233
        ppMediaTypes[copied] =
            (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
        if( CopyMediaType( ppMediaTypes[copied],
                           &p_pin->media_types[i_position-offset]) != S_OK )
1234
            return E_OUTOFMEMORY;
1235

gbazin's avatar
gbazin committed
1236
        ++copied;
1237
        ++i_position; 
1238
    }
1239

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