FFmpeg
dshow_pin.c
Go to the documentation of this file.
1 /*
2  * DirectShow capture interface
3  * Copyright (c) 2010 Ramiro Polla
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include "dshow_capture.h"
23 
24 #include <stddef.h>
25 #define imemoffset offsetof(DShowPin, imemvtbl)
26 
28  { {&IID_IUnknown,0}, {&IID_IPin,0}, {&IID_IMemInputPin,imemoffset} })
31 
32 long WINAPI ff_dshow_pin_Connect(DShowPin *this, IPin *pin, const AM_MEDIA_TYPE *type)
33 {
34  dshowdebug("ff_dshow_pin_Connect(%p, %p, %p)\n", this, pin, type);
35  /* Input pins receive connections. */
36  return S_FALSE;
37 }
38 long WINAPI ff_dshow_pin_ReceiveConnection(DShowPin *this, IPin *pin,
39  const AM_MEDIA_TYPE *type)
40 {
41  enum dshowDeviceType devtype = this->filter->type;
42  dshowdebug("ff_dshow_pin_ReceiveConnection(%p)\n", this);
43 
44  if (!pin)
45  return E_POINTER;
46  if (this->connectedto)
47  return VFW_E_ALREADY_CONNECTED;
48 
50  if (devtype == VideoDevice) {
51  if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video))
52  return VFW_E_TYPE_NOT_ACCEPTED;
53  } else {
54  if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Audio))
55  return VFW_E_TYPE_NOT_ACCEPTED;
56  }
57 
58  IPin_AddRef(pin);
59  this->connectedto = pin;
60 
61  ff_copy_dshow_media_type(&this->type, type);
62 
63  return S_OK;
64 }
66 {
67  dshowdebug("ff_dshow_pin_Disconnect(%p)\n", this);
68 
69  if (this->filter->state != State_Stopped)
70  return VFW_E_NOT_STOPPED;
71  if (!this->connectedto)
72  return S_FALSE;
73  IPin_Release(this->connectedto);
74  this->connectedto = NULL;
75 
76  return S_OK;
77 }
78 long WINAPI ff_dshow_pin_ConnectedTo(DShowPin *this, IPin **pin)
79 {
80  dshowdebug("ff_dshow_pin_ConnectedTo(%p)\n", this);
81 
82  if (!pin)
83  return E_POINTER;
84  if (!this->connectedto)
85  return VFW_E_NOT_CONNECTED;
86  IPin_AddRef(this->connectedto);
87  *pin = this->connectedto;
88 
89  return S_OK;
90 }
91 long WINAPI ff_dshow_pin_ConnectionMediaType(DShowPin *this, AM_MEDIA_TYPE *type)
92 {
93  dshowdebug("ff_dshow_pin_ConnectionMediaType(%p)\n", this);
94 
95  if (!type)
96  return E_POINTER;
97  if (!this->connectedto)
98  return VFW_E_NOT_CONNECTED;
99 
100  return ff_copy_dshow_media_type(type, &this->type);
101 }
102 long WINAPI ff_dshow_pin_QueryPinInfo(DShowPin *this, PIN_INFO *info)
103 {
104  dshowdebug("ff_dshow_pin_QueryPinInfo(%p)\n", this);
105 
106  if (!info)
107  return E_POINTER;
108 
109  if (this->filter)
111 
112  info->pFilter = (IBaseFilter *) this->filter;
113  info->dir = PINDIR_INPUT;
114  wcscpy(info->achName, L"Capture");
115 
116  return S_OK;
117 }
118 long WINAPI ff_dshow_pin_QueryDirection(DShowPin *this, PIN_DIRECTION *dir)
119 {
120  dshowdebug("ff_dshow_pin_QueryDirection(%p)\n", this);
121  if (!dir)
122  return E_POINTER;
123  *dir = PINDIR_INPUT;
124  return S_OK;
125 }
126 long WINAPI ff_dshow_pin_QueryId(DShowPin *this, wchar_t **id)
127 {
128  dshowdebug("ff_dshow_pin_QueryId(%p)\n", this);
129 
130  if (!id)
131  return E_POINTER;
132 
133  *id = wcsdup(L"libAV Pin");
134 
135  return S_OK;
136 }
137 long WINAPI ff_dshow_pin_QueryAccept(DShowPin *this, const AM_MEDIA_TYPE *type)
138 {
139  dshowdebug("ff_dshow_pin_QueryAccept(%p)\n", this);
140  return S_FALSE;
141 }
142 long WINAPI ff_dshow_pin_EnumMediaTypes(DShowPin *this, IEnumMediaTypes **enumtypes)
143 {
144  const AM_MEDIA_TYPE *type = NULL;
145  DShowEnumMediaTypes *new;
146  dshowdebug("ff_dshow_pin_EnumMediaTypes(%p)\n", this);
147 
148  if (!enumtypes)
149  return E_POINTER;
151  if (!new)
152  return E_OUTOFMEMORY;
153 
154  *enumtypes = (IEnumMediaTypes *) new;
155  return S_OK;
156 }
157 long WINAPI ff_dshow_pin_QueryInternalConnections(DShowPin *this, IPin **pin,
158  unsigned long *npin)
159 {
160  dshowdebug("ff_dshow_pin_QueryInternalConnections(%p)\n", this);
161  return E_NOTIMPL;
162 }
164 {
165  dshowdebug("ff_dshow_pin_EndOfStream(%p)\n", this);
166  /* I don't care. */
167  return S_OK;
168 }
170 {
171  dshowdebug("ff_dshow_pin_BeginFlush(%p)\n", this);
172  /* I don't care. */
173  return S_OK;
174 }
175 long WINAPI ff_dshow_pin_EndFlush(DShowPin *this)
176 {
177  dshowdebug("ff_dshow_pin_EndFlush(%p)\n", this);
178  /* I don't care. */
179  return S_OK;
180 }
181 long WINAPI ff_dshow_pin_NewSegment(DShowPin *this, REFERENCE_TIME start, REFERENCE_TIME stop,
182  double rate)
183 {
184  dshowdebug("ff_dshow_pin_NewSegment(%p)\n", this);
185  /* I don't care. */
186  return S_OK;
187 }
188 
190 {
191  IPinVtbl *vtbl = this->vtbl;
192  IMemInputPinVtbl *imemvtbl;
193 
194  if (!filter)
195  return 0;
196 
197  imemvtbl = av_malloc(sizeof(IMemInputPinVtbl));
198  if (!imemvtbl)
199  return 0;
200 
201  SETVTBL(imemvtbl, meminputpin, QueryInterface);
202  SETVTBL(imemvtbl, meminputpin, AddRef);
203  SETVTBL(imemvtbl, meminputpin, Release);
204  SETVTBL(imemvtbl, meminputpin, GetAllocator);
205  SETVTBL(imemvtbl, meminputpin, NotifyAllocator);
206  SETVTBL(imemvtbl, meminputpin, GetAllocatorRequirements);
207  SETVTBL(imemvtbl, meminputpin, Receive);
208  SETVTBL(imemvtbl, meminputpin, ReceiveMultiple);
209  SETVTBL(imemvtbl, meminputpin, ReceiveCanBlock);
210 
211  this->imemvtbl = imemvtbl;
212 
213  SETVTBL(vtbl, pin, QueryInterface);
214  SETVTBL(vtbl, pin, AddRef);
215  SETVTBL(vtbl, pin, Release);
216  SETVTBL(vtbl, pin, Connect);
217  SETVTBL(vtbl, pin, ReceiveConnection);
218  SETVTBL(vtbl, pin, Disconnect);
219  SETVTBL(vtbl, pin, ConnectedTo);
220  SETVTBL(vtbl, pin, ConnectionMediaType);
221  SETVTBL(vtbl, pin, QueryPinInfo);
222  SETVTBL(vtbl, pin, QueryDirection);
223  SETVTBL(vtbl, pin, QueryId);
224  SETVTBL(vtbl, pin, QueryAccept);
225  SETVTBL(vtbl, pin, EnumMediaTypes);
226  SETVTBL(vtbl, pin, QueryInternalConnections);
227  SETVTBL(vtbl, pin, EndOfStream);
228  SETVTBL(vtbl, pin, BeginFlush);
229  SETVTBL(vtbl, pin, EndFlush);
230  SETVTBL(vtbl, pin, NewSegment);
231 
232  this->filter = filter;
233 
234  return 1;
235 }
236 
237 static void ff_dshow_pin_Free(DShowPin *this)
238 {
239  if (!this)
240  return;
241  av_freep(&this->imemvtbl);
242  if (this->type.pbFormat) {
243  CoTaskMemFree(this->type.pbFormat);
244  this->type.pbFormat = NULL;
245  }
246 }
249 
250 /*****************************************************************************
251  * DShowMemInputPin
252  ****************************************************************************/
253 long WINAPI ff_dshow_meminputpin_QueryInterface(DShowMemInputPin *this, const GUID *riid,
254  void **ppvObject)
255 {
256  DShowPin *pin = (DShowPin *) ((uint8_t *) this - imemoffset);
257  dshowdebug("ff_dshow_meminputpin_QueryInterface(%p)\n", this);
258  return ff_dshow_pin_QueryInterface(pin, riid, ppvObject);
259 }
261 {
262  DShowPin *pin = (DShowPin *) ((uint8_t *) this - imemoffset);
263  dshowdebug("ff_dshow_meminputpin_AddRef(%p)\n", this);
264  return ff_dshow_pin_AddRef(pin);
265 }
267 {
268  DShowPin *pin = (DShowPin *) ((uint8_t *) this - imemoffset);
269  dshowdebug("ff_dshow_meminputpin_Release(%p)\n", this);
270  return ff_dshow_pin_Release(pin);
271 }
272 long WINAPI ff_dshow_meminputpin_GetAllocator(DShowMemInputPin *this, IMemAllocator **alloc)
273 {
274  dshowdebug("ff_dshow_meminputpin_GetAllocator(%p)\n", this);
275  return VFW_E_NO_ALLOCATOR;
276 }
277 long WINAPI ff_dshow_meminputpin_NotifyAllocator(DShowMemInputPin *this, IMemAllocator *alloc,
278  BOOL rdwr)
279 {
280  dshowdebug("ff_dshow_meminputpin_NotifyAllocator(%p)\n", this);
281  return S_OK;
282 }
284  ALLOCATOR_PROPERTIES *props)
285 {
286  dshowdebug("ff_dshow_meminputpin_GetAllocatorRequirements(%p)\n", this);
287  return E_NOTIMPL;
288 }
289 long WINAPI ff_dshow_meminputpin_Receive(DShowMemInputPin *this, IMediaSample *sample)
290 {
291  DShowPin *pin = (DShowPin *) ((uint8_t *) this - imemoffset);
292  enum dshowDeviceType devtype = pin->filter->type;
293  void *priv_data;
295  uint8_t *buf;
296  int buf_size; /* todo should be a long? */
297  int index;
298  int64_t chosentime = 0;
299  int64_t sampletime = 0;
300  int64_t graphtime = 0;
301  int use_sample_time = 1;
302  const char *devtypename = (devtype == VideoDevice) ? "video" : "audio";
303  IReferenceClock *clock = pin->filter->clock;
304  int64_t dummy;
305  struct dshow_ctx *ctx;
306  HRESULT hr;
307 
308 
309  dshowdebug("ff_dshow_meminputpin_Receive(%p)\n", this);
310 
311  if (!sample)
312  return E_POINTER;
313 
314  priv_data = pin->filter->priv_data;
315  s = priv_data;
316  ctx = s->priv_data;
317 
318  hr = IMediaSample_GetTime(sample, &sampletime, &dummy);
319  IReferenceClock_GetTime(clock, &graphtime);
320  if (devtype == VideoDevice && !ctx->use_video_device_timestamps) {
321  /* PTS from video devices is unreliable. */
322  chosentime = graphtime;
323  use_sample_time = 0;
324  } else {
325  if (hr == VFW_E_SAMPLE_TIME_NOT_SET || sampletime == 0) {
326  chosentime = graphtime;
327  use_sample_time = 0;
329  "frame with missing sample timestamp encountered, falling back to graph timestamp\n");
330  }
331  else if (sampletime > 400000000000000000LL) {
332  /* initial frames sometimes start < 0 (shown as a very large number here,
333  like 437650244077016960 which FFmpeg doesn't like).
334  TODO figure out math. For now just drop them. */
336  "dropping initial (or ending) sample with odd PTS too high %"PRId64"\n", sampletime);
337  return S_OK;
338  } else
339  chosentime = sampletime;
340  }
341  // media sample time is relative to graph start time
342  sampletime += pin->filter->start_time;
343  if (use_sample_time)
344  chosentime += pin->filter->start_time;
345 
346  buf_size = IMediaSample_GetActualDataLength(sample);
347  IMediaSample_GetPointer(sample, &buf);
348  index = pin->filter->stream_index;
349 
350  av_log(s, AV_LOG_VERBOSE, "passing through packet of type %s size %8d "
351  "timestamp %"PRId64" orig timestamp %"PRId64" graph timestamp %"PRId64" diff %"PRId64" %s\n",
352  devtypename, buf_size, chosentime, sampletime, graphtime, graphtime - sampletime, ctx->device_name[devtype]);
353  pin->filter->callback(priv_data, index, buf, buf_size, chosentime, devtype);
354 
355  return S_OK;
356 }
358  IMediaSample **samples, long n, long *nproc)
359 {
360  int i;
361  dshowdebug("ff_dshow_meminputpin_ReceiveMultiple(%p)\n", this);
362 
363  for (i = 0; i < n; i++)
365 
366  *nproc = n;
367  return S_OK;
368 }
370 {
371  dshowdebug("ff_dshow_meminputpin_ReceiveCanBlock(%p)\n", this);
372  /* I swear I will not block. */
373  return S_FALSE;
374 }
375 
377 {
378  DShowPin *pin = (DShowPin *) ((uint8_t *) this - imemoffset);
379  dshowdebug("ff_dshow_meminputpin_Destroy(%p)\n", this);
381 }
ff_dshow_meminputpin_Receive
long WINAPI ff_dshow_meminputpin_Receive(DShowMemInputPin *this, IMediaSample *sample)
Definition: dshow_pin.c:289
DECLARE_CREATE
#define DECLARE_CREATE(prefix, class, setup,...)
Definition: dshow_capture.h:123
ff_dshow_meminputpin_QueryInterface
long WINAPI ff_dshow_meminputpin_QueryInterface(DShowMemInputPin *this, const GUID *riid, void **ppvObject)
Definition: dshow_pin.c:253
ff_dshow_meminputpin_AddRef
unsigned long WINAPI ff_dshow_meminputpin_AddRef(DShowMemInputPin *this)
Definition: dshow_pin.c:260
DShowPin::filter
DShowFilter * filter
Definition: dshow_capture.h:165
ff_dshow_meminputpin_GetAllocatorRequirements
long WINAPI ff_dshow_meminputpin_GetAllocatorRequirements(DShowMemInputPin *this, ALLOCATOR_PROPERTIES *props)
Definition: dshow_pin.c:283
VideoDevice
@ VideoDevice
Definition: dshow_capture.h:62
ff_dshow_pin_QueryInterface
long WINAPI ff_dshow_pin_QueryInterface(DShowPin *, const GUID *, void **)
ff_dshow_pin_Release
unsigned long WINAPI ff_dshow_pin_Release(DShowPin *)
dshow_capture.h
ff_dshow_pin_BeginFlush
long WINAPI ff_dshow_pin_BeginFlush(DShowPin *this)
Definition: dshow_pin.c:169
ff_dshow_pin_QueryInternalConnections
long WINAPI ff_dshow_pin_QueryInternalConnections(DShowPin *this, IPin **pin, unsigned long *npin)
Definition: dshow_pin.c:157
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:196
filter
filter_frame For filters that do not use the this method is called when a frame is pushed to the filter s input It can be called at any time except in a reentrant way If the input frame is enough to produce then the filter should push the output frames on the output link immediately As an exception to the previous rule if the input frame is enough to produce several output frames then the filter needs output only at least one per link The additional frames can be left buffered in the filter
Definition: filter_design.txt:228
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:30
ff_dshow_pin_EndOfStream
long WINAPI ff_dshow_pin_EndOfStream(DShowPin *this)
Definition: dshow_pin.c:163
ff_dshow_pin_ConnectionMediaType
long WINAPI ff_dshow_pin_ConnectionMediaType(DShowPin *this, AM_MEDIA_TYPE *type)
Definition: dshow_pin.c:91
ff_dshow_pin_Destroy
void ff_dshow_pin_Destroy(DShowPin *)
dummy
int dummy
Definition: motion.c:66
ff_dshow_pin_EnumMediaTypes
long WINAPI ff_dshow_pin_EnumMediaTypes(DShowPin *this, IEnumMediaTypes **enumtypes)
Definition: dshow_pin.c:142
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
ff_print_AM_MEDIA_TYPE
void ff_print_AM_MEDIA_TYPE(const AM_MEDIA_TYPE *type)
Definition: dshow_common.c:134
DECLARE_ADDREF
#define DECLARE_ADDREF(prefix, class)
Definition: dshow_capture.h:94
ff_dshow_meminputpin_ReceiveCanBlock
long WINAPI ff_dshow_meminputpin_ReceiveCanBlock(DShowMemInputPin *this)
Definition: dshow_pin.c:369
ff_dshow_pin_ConnectedTo
long WINAPI ff_dshow_pin_ConnectedTo(DShowPin *this, IPin **pin)
Definition: dshow_pin.c:78
ff_dshow_pin_Free
static void ff_dshow_pin_Free(DShowPin *this)
Definition: dshow_pin.c:237
dshow_ctx
Definition: dshow_capture.h:286
ff_dshow_pin_EndFlush
long WINAPI ff_dshow_pin_EndFlush(DShowPin *this)
Definition: dshow_pin.c:175
s
#define s(width, name)
Definition: cbs_vp9.c:198
dshowdebug
#define dshowdebug(...)
Definition: dshow_capture.h:50
info
MIPS optimizations info
Definition: mips.txt:2
ff_copy_dshow_media_type
long ff_copy_dshow_media_type(AM_MEDIA_TYPE *dst, const AM_MEDIA_TYPE *src)
Definition: dshow_common.c:24
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
DShowFilter::type
enum dshowDeviceType type
Definition: dshow_capture.h:259
ctx
AVFormatContext * ctx
Definition: movenc.c:48
DShowFilter
Definition: dshow_capture.h:249
SETVTBL
#define SETVTBL(vtbl, prefix, fn)
Definition: dshow_capture.h:145
AVFormatContext
Format I/O context.
Definition: avformat.h:1255
NULL
#define NULL
Definition: coverity.c:32
DShowEnumMediaTypes
Definition: dshow_capture.h:228
ff_dshow_pin_QueryPinInfo
long WINAPI ff_dshow_pin_QueryPinInfo(DShowPin *this, PIN_INFO *info)
Definition: dshow_pin.c:102
ff_dshow_meminputpin_GetAllocator
long WINAPI ff_dshow_meminputpin_GetAllocator(DShowMemInputPin *this, IMemAllocator **alloc)
Definition: dshow_pin.c:272
index
int index
Definition: gxfenc.c:89
ff_dshow_enummediatypes_Create
DShowEnumMediaTypes * ff_dshow_enummediatypes_Create(const AM_MEDIA_TYPE *type)
ff_dshow_pin_NewSegment
long WINAPI ff_dshow_pin_NewSegment(DShowPin *this, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
Definition: dshow_pin.c:181
ff_dshow_pin_ReceiveConnection
long WINAPI ff_dshow_pin_ReceiveConnection(DShowPin *this, IPin *pin, const AM_MEDIA_TYPE *type)
Definition: dshow_pin.c:38
sample
#define sample
Definition: flacdsp_template.c:44
DShowMemInputPin
struct DShowMemInputPin DShowMemInputPin
Definition: dshow_capture.h:152
ff_dshow_pin_QueryDirection
long WINAPI ff_dshow_pin_QueryDirection(DShowPin *this, PIN_DIRECTION *dir)
Definition: dshow_pin.c:118
DECLARE_DESTROY
#define DECLARE_DESTROY(prefix, class, func)
Definition: dshow_capture.h:112
ff_dshow_meminputpin_Release
unsigned long WINAPI ff_dshow_meminputpin_Release(DShowMemInputPin *this)
Definition: dshow_pin.c:266
ff_dshow_pin_Disconnect
long WINAPI ff_dshow_pin_Disconnect(DShowPin *this)
Definition: dshow_pin.c:65
imemoffset
#define imemoffset
Definition: dshow_pin.c:25
DShowFilter::clock
IReferenceClock * clock
Definition: dshow_capture.h:258
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:255
ff_dshow_pin_Setup
static int ff_dshow_pin_Setup(DShowPin *this, DShowFilter *filter)
Definition: dshow_pin.c:189
ff_dshow_meminputpin_Destroy
void ff_dshow_meminputpin_Destroy(DShowMemInputPin *this)
Definition: dshow_pin.c:376
DShowFilter::stream_index
int stream_index
Definition: dshow_capture.h:261
ff_dshow_filter_AddRef
unsigned long WINAPI ff_dshow_filter_AddRef(DShowFilter *)
DECLARE_RELEASE
#define DECLARE_RELEASE(prefix, class)
Definition: dshow_capture.h:101
DShowFilter::priv_data
void * priv_data
Definition: dshow_capture.h:260
ff_dshow_pin_QueryAccept
long WINAPI ff_dshow_pin_QueryAccept(DShowPin *this, const AM_MEDIA_TYPE *type)
Definition: dshow_pin.c:137
L
#define L(x)
Definition: vpx_arith.h:36
samples
Filter the word “frame” indicates either a video frame or a group of audio samples
Definition: filter_design.txt:8
ff_dshow_pin_AddRef
unsigned long WINAPI ff_dshow_pin_AddRef(DShowPin *)
DECLARE_QUERYINTERFACE
DECLARE_QUERYINTERFACE(pin, DShowPin, { {&IID_IUnknown, 0}, {&IID_IPin, 0}, {&IID_IMemInputPin, imemoffset} })
Definition: dshow_pin.c:27
ff_dshow_pin_Connect
long WINAPI ff_dshow_pin_Connect(DShowPin *, IPin *, const AM_MEDIA_TYPE *)
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
ff_dshow_meminputpin_ReceiveMultiple
long WINAPI ff_dshow_meminputpin_ReceiveMultiple(DShowMemInputPin *this, IMediaSample **samples, long n, long *nproc)
Definition: dshow_pin.c:357
ff_dshow_pin_QueryId
long WINAPI ff_dshow_pin_QueryId(DShowPin *this, wchar_t **id)
Definition: dshow_pin.c:126
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
ff_dshow_meminputpin_NotifyAllocator
long WINAPI ff_dshow_meminputpin_NotifyAllocator(DShowMemInputPin *this, IMemAllocator *alloc, BOOL rdwr)
Definition: dshow_pin.c:277
DShowFilter::callback
void(* callback)(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time, enum dshowDeviceType type)
Definition: dshow_capture.h:263
DShowFilter::start_time
int64_t start_time
Definition: dshow_capture.h:262
DShowPin
Definition: dshow_capture.h:160
dshowDeviceType
dshowDeviceType
Definition: dshow_capture.h:61