filter.cpp 41.2 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
 *****************************************************************************/

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

#include <vlc/vlc.h>
zorglub's avatar
zorglub committed
31
#include <vlc_vout.h>
gbazin's avatar
 
gbazin committed
32

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

gbazin's avatar
gbazin committed
38
#include "common.h"
gbazin's avatar
 
gbazin committed
39 40 41 42
#include "filter.h"

#define DEBUG_DSHOW 1

43 44 45
#define FILTER_NAME  L"VideoLAN Capture Filter"
#define PIN_NAME     L"Capture"

gbazin's avatar
 
gbazin committed
46 47
/*****************************************************************************
 * DirectShow GUIDs.
48
 * Easier to define them here as mingw doesn't provide them all.
gbazin's avatar
 
gbazin committed
49 50 51
 *****************************************************************************/
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
52
const GUID CLSID_AudioInputDeviceCategory = {0x33d9a762, 0x90c8, 0x11d0, {0xbd, 0x43, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86}};
53 54
//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
55 56 57 58 59
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}};

60 61 62 63
//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
64 65 66 67
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}};
68
extern const GUID IID_IMemInputPin;
gbazin's avatar
 
gbazin committed
69 70 71 72

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

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

75 76
//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
77

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

93
/* Video Format */
94

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

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

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

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

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

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

148 149 150
/* DivX formats */
const GUID MEDIASUBTYPE_DIVX = {0x58564944, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};

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 177
/* 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}};

178 179
//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
180

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

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

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

    if( media_type.majortype == MEDIATYPE_Video )
    {
231
        /* currently only support this type of video info format */
232
        if( 1 /* media_type.formattype == FORMAT_VideoInfo */ )
gbazin's avatar
gbazin committed
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
        {
            /* 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' );

282 283 284 285
	    /* DivX video */
            else if( media_type.subtype == MEDIASUBTYPE_DIVX )
               i_fourcc = VLC_FOURCC( 'D', 'I', 'V', 'X' );

gbazin's avatar
gbazin committed
286 287 288 289 290 291 292
            /* 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' );
293 294 295 296 297

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

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

319 320 321
    return i_fourcc;
}

gbazin's avatar
 
gbazin committed
322 323 324 325
/****************************************************************************
 * Implementation of our dummy directshow filter pin class
 ****************************************************************************/

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

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

HRESULT CapturePin::CustomGetSample( VLCMediaSample *vlc_sample )
{
354 355 356 357 358
#if 0 //def DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::CustomGetSample" );
#endif

    vlc_mutex_lock( &p_sys->lock );
gbazin's avatar
 
gbazin committed
359 360 361 362
    if( samples_queue.size() )
    {
        *vlc_sample = samples_queue.back();
        samples_queue.pop_back();
363
        vlc_mutex_unlock( &p_sys->lock );
gbazin's avatar
 
gbazin committed
364 365
        return S_OK;
    }
366
    vlc_mutex_unlock( &p_sys->lock );
gbazin's avatar
 
gbazin committed
367 368 369
    return S_FALSE;
}

370
AM_MEDIA_TYPE &CapturePin::CustomGetMediaType()
gbazin's avatar
 
gbazin committed
371
{
372
    return cx_media_type;
gbazin's avatar
 
gbazin committed
373 374 375 376 377
}

/* IUnknown methods */
STDMETHODIMP CapturePin::QueryInterface(REFIID riid, void **ppv)
{
damienf's avatar
damienf committed
378
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
 
gbazin committed
379 380 381 382 383 384
    msg_Dbg( p_input, "CapturePin::QueryInterface" );
#endif

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

gbazin's avatar
 
gbazin committed
411 412
STDMETHODIMP_(ULONG) CapturePin::AddRef()
{
413
#ifdef DEBUG_DSHOW_L1
414
    msg_Dbg( p_input, "CapturePin::AddRef (ref: %i)", i_ref );
gbazin's avatar
 
gbazin committed
415 416
#endif

gbazin's avatar
 
gbazin committed
417
    return i_ref++;
gbazin's avatar
 
gbazin committed
418 419 420
};
STDMETHODIMP_(ULONG) CapturePin::Release()
{
421
#ifdef DEBUG_DSHOW_L1
422
    msg_Dbg( p_input, "CapturePin::Release (ref: %i)", i_ref );
gbazin's avatar
 
gbazin committed
423 424
#endif

425
    if( !InterlockedDecrement(&i_ref) ) delete this;
gbazin's avatar
 
gbazin committed
426

427
    return 0;
gbazin's avatar
 
gbazin committed
428 429 430 431 432 433
};

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

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

485 486
    if( !pConnector || !pmt )
    {
gbazin's avatar
gbazin committed
487
        msg_Dbg( p_input, "CapturePin::ReceiveConnection [null pointer]" );
488
        return E_POINTER;
489
    }
gbazin's avatar
 
gbazin committed
490

491
    if( p_connected_pin )
492
    {
gbazin's avatar
gbazin committed
493
        msg_Dbg( p_input, "CapturePin::ReceiveConnection [already connected]");
494
        return VFW_E_ALREADY_CONNECTED;
495
    }
496 497

    if( S_OK != QueryAccept(pmt) )
498
    {
gbazin's avatar
gbazin committed
499 500
        msg_Dbg( p_input, "CapturePin::ReceiveConnection "
                 "[media type not accepted]" );
501
        return VFW_E_TYPE_NOT_ACCEPTED;
502 503 504
    }

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

gbazin's avatar
 
gbazin committed
506 507
    p_connected_pin = pConnector;
    p_connected_pin->AddRef();
gbazin's avatar
 
gbazin committed
508

509 510
    FreeMediaType( cx_media_type );
    return CopyMediaType( &cx_media_type, pmt );
gbazin's avatar
 
gbazin committed
511 512 513
}
STDMETHODIMP CapturePin::Disconnect()
{
514 515
    if( ! p_connected_pin )
    {
gbazin's avatar
gbazin committed
516 517
        msg_Dbg( p_input, "CapturePin::Disconnect [not connected]" );
        return S_FALSE;
518
    }
gbazin's avatar
 
gbazin committed
519

520
    msg_Dbg( p_input, "CapturePin::Disconnect [OK]" );
521

522
    /* samples_queue was already flushed in EndFlush() */
523

524
    p_connected_pin->Release();
gbazin's avatar
 
gbazin committed
525
    p_connected_pin = NULL;
526 527
    //FreeMediaType( cx_media_type );
    //cx_media_type.subtype = GUID_NULL;
528

gbazin's avatar
 
gbazin committed
529 530 531 532
    return S_OK;
}
STDMETHODIMP CapturePin::ConnectedTo( IPin **pPin )
{
533 534
    if( !p_connected_pin )
    {
gbazin's avatar
gbazin committed
535 536
        msg_Dbg( p_input, "CapturePin::ConnectedTo [not connected]" );
        return VFW_E_NOT_CONNECTED;
537
    }
gbazin's avatar
 
gbazin committed
538

gbazin's avatar
 
gbazin committed
539 540 541
    p_connected_pin->AddRef();
    *pPin = p_connected_pin;

542 543
    msg_Dbg( p_input, "CapturePin::ConnectedTo [OK]" );

gbazin's avatar
 
gbazin committed
544 545 546 547
    return S_OK;
}
STDMETHODIMP CapturePin::ConnectionMediaType( AM_MEDIA_TYPE *pmt )
{
548 549
    if( !p_connected_pin )
    {
gbazin's avatar
gbazin committed
550 551
        msg_Dbg( p_input, "CapturePin::ConnectionMediaType [not connected]" );
        return VFW_E_NOT_CONNECTED;
552
    }
553 554

    return CopyMediaType( pmt, &cx_media_type );
gbazin's avatar
 
gbazin committed
555 556 557 558 559 560 561 562 563 564
}
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();

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

    *Id = L"VideoLAN Capture Pin";

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

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

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

    if( p_connected_pin )
    {
        FreeMediaType( cx_media_type );
        CopyMediaType( &cx_media_type, pmt );
647
    }
gbazin's avatar
gbazin committed
648 649

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

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

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

gbazin's avatar
 
gbazin committed
737 738 739 740
    return E_NOTIMPL;
}
STDMETHODIMP CapturePin::Receive( IMediaSample *pSample )
{
741 742
#if 0 //def DEBUG_DSHOW
    msg_Dbg( p_input, "CapturePin::Receive" );
gbazin's avatar
 
gbazin committed
743 744
#endif

gbazin's avatar
 
gbazin committed
745
    pSample->AddRef();
gbazin's avatar
 
gbazin committed
746 747
    mtime_t i_timestamp = mdate() * 10;
    VLCMediaSample vlc_sample = {pSample, i_timestamp};
748 749

    vlc_mutex_lock( &p_sys->lock );
gbazin's avatar
 
gbazin committed
750 751 752 753 754 755 756 757
    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
758
        vlc_sample.p_sample->Release();
gbazin's avatar
 
gbazin committed
759 760
    }

761 762 763
    vlc_cond_signal( &p_sys->wait );
    vlc_mutex_unlock( &p_sys->lock );

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

CaptureFilter::~CaptureFilter()
{
803 804 805
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::~CaptureFilter" );
#endif
gbazin's avatar
 
gbazin committed
806 807 808 809 810 811
    p_pin->Release();
}

/* IUnknown methods */
STDMETHODIMP CaptureFilter::QueryInterface( REFIID riid, void **ppv )
{
damienf's avatar
damienf committed
812
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
 
gbazin committed
813 814 815 816 817
    msg_Dbg( p_input, "CaptureFilter::QueryInterface" );
#endif

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

gbazin's avatar
 
gbazin committed
861
    return i_ref++;
gbazin's avatar
 
gbazin committed
862 863 864
};
STDMETHODIMP_(ULONG) CaptureFilter::Release()
{
865
#ifdef DEBUG_DSHOW_L1
866
    msg_Dbg( p_input, "CaptureFilter::Release (ref: %i)", i_ref );
gbazin's avatar
 
gbazin committed
867 868
#endif

869
    if( !InterlockedDecrement(&i_ref) ) delete this;
gbazin's avatar
 
gbazin committed
870

871
    return 0;
gbazin's avatar
 
gbazin committed
872 873 874 875 876 877 878 879 880 881 882 883 884 885 886
};

/* 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
887
    msg_Dbg( p_input, "CaptureFilter::GetState %i", state );
gbazin's avatar
 
gbazin committed
888
#endif
gbazin's avatar
 
gbazin committed
889 890 891

    *State = state;
    return S_OK;
gbazin's avatar
 
gbazin committed
892 893 894 895 896 897 898
};
STDMETHODIMP CaptureFilter::SetSyncSource(IReferenceClock *pClock)
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::SetSyncSource" );
#endif

gbazin's avatar
 
gbazin committed
899
    return S_OK;
gbazin's avatar
 
gbazin committed
900 901 902 903 904 905
};
STDMETHODIMP CaptureFilter::GetSyncSource(IReferenceClock **pClock)
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::GetSyncSource" );
#endif
gbazin's avatar
 
gbazin committed
906 907 908

    *pClock = NULL;
    return NOERROR;
gbazin's avatar
 
gbazin committed
909 910 911 912 913 914
};
STDMETHODIMP CaptureFilter::Stop()
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::Stop" );
#endif
gbazin's avatar
 
gbazin committed
915

916 917
    p_pin->EndFlush();

gbazin's avatar
 
gbazin committed
918
    state = State_Stopped;
gbazin's avatar
 
gbazin committed
919
    return S_OK;
gbazin's avatar
 
gbazin committed
920 921 922 923 924 925
};
STDMETHODIMP CaptureFilter::Pause()
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::Pause" );
#endif
gbazin's avatar
 
gbazin committed
926 927

    state = State_Paused;
gbazin's avatar
 
gbazin committed
928
    return S_OK;
gbazin's avatar
 
gbazin committed
929 930 931 932 933 934
};
STDMETHODIMP CaptureFilter::Run(REFERENCE_TIME tStart)
{
#ifdef DEBUG_DSHOW
    msg_Dbg( p_input, "CaptureFilter::Run" );
#endif
gbazin's avatar
 
gbazin committed
935 936

    state = State_Running;
gbazin's avatar
 
gbazin committed
937
    return S_OK;
gbazin's avatar
 
gbazin committed
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
};

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

964
    memcpy(pInfo->achName, FILTER_NAME, sizeof(FILTER_NAME));
gbazin's avatar
 
gbazin committed
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 995 996 997 998 999

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

/* IUnknown methods */
STDMETHODIMP CaptureEnumPins::QueryInterface( REFIID riid, void **ppv )
{
damienf's avatar
damienf committed
1031
#ifdef DEBUG_DSHOW_L1
gbazin's avatar
 
gbazin committed
1032 1033 1034 1035 1036 1037
    msg_Dbg( p_input, "CaptureEnumPins::QueryInterface" );
#endif

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

gbazin's avatar
 
gbazin committed
1054
    return i_ref++;
gbazin's avatar
 
gbazin committed
1055 1056 1057
};
STDMETHODIMP_(ULONG) CaptureEnumPins::Release()
{
1058
#ifdef DEBUG_DSHOW_L1
1059
    msg_Dbg( p_input, "CaptureEnumPins::Release (ref: %i)", i_ref );
gbazin's avatar
 
gbazin committed
1060 1061
#endif

1062
    if( !InterlockedDecrement(&i_ref) ) delete this;
gbazin's avatar
 
gbazin committed
1063

1064
    return 0;
gbazin's avatar
 
gbazin committed
1065 1066 1067 1068 1069 1070
};

/* IEnumPins */
STDMETHODIMP CaptureEnumPins::Next( ULONG cPins, IPin ** ppPins,
                                    ULONG * pcFetched )
{
damienf's avatar
damienf committed
1071
#ifdef DEBUG_DSHOW_L1
gbazin's avatar