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 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 }
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 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 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 }
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 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 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 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 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 }
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 }
176 {
177  dshowdebug("ff_dshow_pin_EndFlush(%p)\n", this);
178  /* I don't care. */
179  return S_OK;
180 }
181 long 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  ****************************************************************************/
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 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 }
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 }
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 curtime;
299  int64_t orig_curtime;
300  int64_t graphtime;
301  const char *devtypename = (devtype == VideoDevice) ? "video" : "audio";
302  IReferenceClock *clock = pin->filter->clock;
303  int64_t dummy;
304  struct dshow_ctx *ctx;
305 
306 
307  dshowdebug("ff_dshow_meminputpin_Receive(%p)\n", this);
308 
309  if (!sample)
310  return E_POINTER;
311 
312  IMediaSample_GetTime(sample, &orig_curtime, &dummy);
313  orig_curtime += pin->filter->start_time;
314  IReferenceClock_GetTime(clock, &graphtime);
315  if (devtype == VideoDevice) {
316  /* PTS from video devices is unreliable. */
317  IReferenceClock_GetTime(clock, &curtime);
318  } else {
319  IMediaSample_GetTime(sample, &curtime, &dummy);
320  if(curtime > 400000000000000000LL) {
321  /* initial frames sometimes start < 0 (shown as a very large number here,
322  like 437650244077016960 which FFmpeg doesn't like.
323  TODO figure out math. For now just drop them. */
325  "dshow dropping initial (or ending) audio frame with odd PTS too high %"PRId64"\n", curtime);
326  return S_OK;
327  }
328  curtime += pin->filter->start_time;
329  }
330 
331  buf_size = IMediaSample_GetActualDataLength(sample);
332  IMediaSample_GetPointer(sample, &buf);
333  priv_data = pin->filter->priv_data;
334  s = priv_data;
335  ctx = s->priv_data;
336  index = pin->filter->stream_index;
337 
338  av_log(NULL, AV_LOG_VERBOSE, "dshow passing through packet of type %s size %8d "
339  "timestamp %"PRId64" orig timestamp %"PRId64" graph timestamp %"PRId64" diff %"PRId64" %s\n",
340  devtypename, buf_size, curtime, orig_curtime, graphtime, graphtime - orig_curtime, ctx->device_name[devtype]);
341  pin->filter->callback(priv_data, index, buf, buf_size, curtime, devtype);
342 
343  return S_OK;
344 }
346  IMediaSample **samples, long n, long *nproc)
347 {
348  int i;
349  dshowdebug("ff_dshow_meminputpin_ReceiveMultiple(%p)\n", this);
350 
351  for (i = 0; i < n; i++)
353 
354  *nproc = n;
355  return S_OK;
356 }
358 {
359  dshowdebug("ff_dshow_meminputpin_ReceiveCanBlock(%p)\n", this);
360  /* I swear I will not block. */
361  return S_FALSE;
362 }
363 
365 {
366  DShowPin *pin = (DShowPin *) ((uint8_t *) this - imemoffset);
367  dshowdebug("ff_dshow_meminputpin_Destroy(%p)\n", this);
369 }
DECLARE_CREATE
#define DECLARE_CREATE(prefix, class, setup,...)
Definition: dshow_capture.h:124
DShowPin::filter
DShowFilter * filter
Definition: dshow_capture.h:166
ff_dshow_pin_QueryDirection
long ff_dshow_pin_QueryDirection(DShowPin *this, PIN_DIRECTION *dir)
Definition: dshow_pin.c:118
ff_dshow_pin_QueryAccept
long ff_dshow_pin_QueryAccept(DShowPin *this, const AM_MEDIA_TYPE *type)
Definition: dshow_pin.c:137
VideoDevice
@ VideoDevice
Definition: dshow_capture.h:63
dshow_capture.h
index
fg index
Definition: ffmpeg_filter.c:168
ff_dshow_pin_QueryId
long ff_dshow_pin_QueryId(DShowPin *this, wchar_t **id)
Definition: dshow_pin.c:126
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:197
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
ff_dshow_meminputpin_QueryInterface
long ff_dshow_meminputpin_QueryInterface(DShowMemInputPin *this, const GUID *riid, void **ppvObject)
Definition: dshow_pin.c:253
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
ff_dshow_pin_Destroy
void ff_dshow_pin_Destroy(DShowPin *)
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:95
ff_dshow_pin_AddRef
unsigned long ff_dshow_pin_AddRef(DShowPin *)
ff_dshow_pin_Free
static void ff_dshow_pin_Free(DShowPin *this)
Definition: dshow_pin.c:237
ff_dshow_meminputpin_Release
unsigned long ff_dshow_meminputpin_Release(DShowMemInputPin *this)
Definition: dshow_pin.c:266
dshow_ctx
Definition: dshow_capture.h:287
ff_dshow_meminputpin_Receive
long ff_dshow_meminputpin_Receive(DShowMemInputPin *this, IMediaSample *sample)
Definition: dshow_pin.c:289
s
#define s(width, name)
Definition: cbs_vp9.c:257
dshowdebug
#define dshowdebug(...)
Definition: dshow_capture.h:51
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:202
DShowFilter::type
enum dshowDeviceType type
Definition: dshow_capture.h:260
ctx
AVFormatContext * ctx
Definition: movenc.c:48
ff_dshow_pin_QueryInterface
long ff_dshow_pin_QueryInterface(DShowPin *, const GUID *, void **)
DShowFilter
Definition: dshow_capture.h:250
SETVTBL
#define SETVTBL(vtbl, prefix, fn)
Definition: dshow_capture.h:146
ff_dshow_pin_Connect
long ff_dshow_pin_Connect(DShowPin *, IPin *, const AM_MEDIA_TYPE *)
AVFormatContext
Format I/O context.
Definition: avformat.h:1106
NULL
#define NULL
Definition: coverity.c:32
ff_dshow_meminputpin_NotifyAllocator
long ff_dshow_meminputpin_NotifyAllocator(DShowMemInputPin *this, IMemAllocator *alloc, BOOL rdwr)
Definition: dshow_pin.c:277
DShowEnumMediaTypes
Definition: dshow_capture.h:229
ff_dshow_pin_Disconnect
long ff_dshow_pin_Disconnect(DShowPin *this)
Definition: dshow_pin.c:65
ff_dshow_pin_BeginFlush
long ff_dshow_pin_BeginFlush(DShowPin *this)
Definition: dshow_pin.c:169
ff_dshow_meminputpin_GetAllocatorRequirements
long ff_dshow_meminputpin_GetAllocatorRequirements(DShowMemInputPin *this, ALLOCATOR_PROPERTIES *props)
Definition: dshow_pin.c:283
ff_dshow_enummediatypes_Create
DShowEnumMediaTypes * ff_dshow_enummediatypes_Create(const AM_MEDIA_TYPE *type)
ff_dshow_meminputpin_GetAllocator
long ff_dshow_meminputpin_GetAllocator(DShowMemInputPin *this, IMemAllocator **alloc)
Definition: dshow_pin.c:272
ff_dshow_pin_EnumMediaTypes
long ff_dshow_pin_EnumMediaTypes(DShowPin *this, IEnumMediaTypes **enumtypes)
Definition: dshow_pin.c:142
sample
#define sample
Definition: flacdsp_template.c:44
ff_dshow_pin_EndFlush
long ff_dshow_pin_EndFlush(DShowPin *this)
Definition: dshow_pin.c:175
DShowMemInputPin
struct DShowMemInputPin DShowMemInputPin
Definition: dshow_capture.h:153
ff_dshow_pin_ReceiveConnection
long ff_dshow_pin_ReceiveConnection(DShowPin *this, IPin *pin, const AM_MEDIA_TYPE *type)
Definition: dshow_pin.c:38
DECLARE_DESTROY
#define DECLARE_DESTROY(prefix, class, func)
Definition: dshow_capture.h:113
ff_dshow_filter_AddRef
unsigned long ff_dshow_filter_AddRef(DShowFilter *)
ff_dshow_pin_QueryInternalConnections
long ff_dshow_pin_QueryInternalConnections(DShowPin *this, IPin **pin, unsigned long *npin)
Definition: dshow_pin.c:157
ff_dshow_pin_NewSegment
long ff_dshow_pin_NewSegment(DShowPin *this, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
Definition: dshow_pin.c:181
imemoffset
#define imemoffset
Definition: dshow_pin.c:25
DShowFilter::clock
IReferenceClock * clock
Definition: dshow_capture.h:259
i
int i
Definition: input.c:407
ff_dshow_pin_Setup
static int ff_dshow_pin_Setup(DShowPin *this, DShowFilter *filter)
Definition: dshow_pin.c:189
ff_dshow_pin_Release
unsigned long ff_dshow_pin_Release(DShowPin *)
ff_dshow_meminputpin_Destroy
void ff_dshow_meminputpin_Destroy(DShowMemInputPin *this)
Definition: dshow_pin.c:364
DShowFilter::stream_index
int stream_index
Definition: dshow_capture.h:262
DECLARE_RELEASE
#define DECLARE_RELEASE(prefix, class)
Definition: dshow_capture.h:102
ff_dshow_pin_ConnectionMediaType
long ff_dshow_pin_ConnectionMediaType(DShowPin *this, AM_MEDIA_TYPE *type)
Definition: dshow_pin.c:91
L
#define L(x)
Definition: vp56_arith.h:36
DShowFilter::priv_data
void * priv_data
Definition: dshow_capture.h:261
dummy
int dummy
Definition: motion.c:64
ff_dshow_pin_QueryPinInfo
long ff_dshow_pin_QueryPinInfo(DShowPin *this, PIN_INFO *info)
Definition: dshow_pin.c:102
samples
Filter the word “frame” indicates either a video frame or a group of audio samples
Definition: filter_design.txt:8
ff_dshow_pin_EndOfStream
long ff_dshow_pin_EndOfStream(DShowPin *this)
Definition: dshow_pin.c:163
DECLARE_QUERYINTERFACE
DECLARE_QUERYINTERFACE(pin, DShowPin, { {&IID_IUnknown, 0}, {&IID_IPin, 0}, {&IID_IMemInputPin, imemoffset} })
Definition: dshow_pin.c:27
ff_dshow_meminputpin_ReceiveCanBlock
long ff_dshow_meminputpin_ReceiveCanBlock(DShowMemInputPin *this)
Definition: dshow_pin.c:357
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
ff_dshow_meminputpin_ReceiveMultiple
long ff_dshow_meminputpin_ReceiveMultiple(DShowMemInputPin *this, IMediaSample **samples, long n, long *nproc)
Definition: dshow_pin.c:345
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
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:264
ff_dshow_pin_ConnectedTo
long ff_dshow_pin_ConnectedTo(DShowPin *this, IPin **pin)
Definition: dshow_pin.c:78
DShowFilter::start_time
int64_t start_time
Definition: dshow_capture.h:263
DShowPin
Definition: dshow_capture.h:161
dshowDeviceType
dshowDeviceType
Definition: dshow_capture.h:62
ff_dshow_meminputpin_AddRef
unsigned long ff_dshow_meminputpin_AddRef(DShowMemInputPin *this)
Definition: dshow_pin.c:260