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(libAVPin, imemvtbl)
26 
28  { {&IID_IUnknown,0}, {&IID_IPin,0}, {&IID_IMemInputPin,imemoffset} })
31 
32 long WINAPI
33 libAVPin_Connect(libAVPin *this, IPin *pin, const AM_MEDIA_TYPE *type)
34 {
35  dshowdebug("libAVPin_Connect(%p, %p, %p)\n", this, pin, type);
36  /* Input pins receive connections. */
37  return S_FALSE;
38 }
39 long WINAPI
41  const AM_MEDIA_TYPE *type)
42 {
43  enum dshowDeviceType devtype = this->filter->type;
44  dshowdebug("libAVPin_ReceiveConnection(%p)\n", this);
45 
46  if (!pin)
47  return E_POINTER;
48  if (this->connectedto)
49  return VFW_E_ALREADY_CONNECTED;
50 
52  if (devtype == VideoDevice) {
53  if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video))
54  return VFW_E_TYPE_NOT_ACCEPTED;
55  } else {
56  if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Audio))
57  return VFW_E_TYPE_NOT_ACCEPTED;
58  }
59 
60  IPin_AddRef(pin);
61  this->connectedto = pin;
62 
63  ff_copy_dshow_media_type(&this->type, type);
64 
65  return S_OK;
66 }
67 long WINAPI
69 {
70  dshowdebug("libAVPin_Disconnect(%p)\n", this);
71 
72  if (this->filter->state != State_Stopped)
73  return VFW_E_NOT_STOPPED;
74  if (!this->connectedto)
75  return S_FALSE;
76  IPin_Release(this->connectedto);
77  this->connectedto = NULL;
78 
79  return S_OK;
80 }
81 long WINAPI
82 libAVPin_ConnectedTo(libAVPin *this, IPin **pin)
83 {
84  dshowdebug("libAVPin_ConnectedTo(%p)\n", this);
85 
86  if (!pin)
87  return E_POINTER;
88  if (!this->connectedto)
89  return VFW_E_NOT_CONNECTED;
90  IPin_AddRef(this->connectedto);
91  *pin = this->connectedto;
92 
93  return S_OK;
94 }
95 long WINAPI
97 {
98  dshowdebug("libAVPin_ConnectionMediaType(%p)\n", this);
99 
100  if (!type)
101  return E_POINTER;
102  if (!this->connectedto)
103  return VFW_E_NOT_CONNECTED;
104 
105  return ff_copy_dshow_media_type(type, &this->type);
106 }
107 long WINAPI
109 {
110  dshowdebug("libAVPin_QueryPinInfo(%p)\n", this);
111 
112  if (!info)
113  return E_POINTER;
114 
115  if (this->filter)
116  libAVFilter_AddRef(this->filter);
117 
118  info->pFilter = (IBaseFilter *) this->filter;
119  info->dir = PINDIR_INPUT;
120  wcscpy(info->achName, L"Capture");
121 
122  return S_OK;
123 }
124 long WINAPI
125 libAVPin_QueryDirection(libAVPin *this, PIN_DIRECTION *dir)
126 {
127  dshowdebug("libAVPin_QueryDirection(%p)\n", this);
128  if (!dir)
129  return E_POINTER;
130  *dir = PINDIR_INPUT;
131  return S_OK;
132 }
133 long WINAPI
134 libAVPin_QueryId(libAVPin *this, wchar_t **id)
135 {
136  dshowdebug("libAVPin_QueryId(%p)\n", this);
137 
138  if (!id)
139  return E_POINTER;
140 
141  *id = wcsdup(L"libAV Pin");
142 
143  return S_OK;
144 }
145 long WINAPI
146 libAVPin_QueryAccept(libAVPin *this, const AM_MEDIA_TYPE *type)
147 {
148  dshowdebug("libAVPin_QueryAccept(%p)\n", this);
149  return S_FALSE;
150 }
151 long WINAPI
152 libAVPin_EnumMediaTypes(libAVPin *this, IEnumMediaTypes **enumtypes)
153 {
154  const AM_MEDIA_TYPE *type = NULL;
155  libAVEnumMediaTypes *new;
156  dshowdebug("libAVPin_EnumMediaTypes(%p)\n", this);
157 
158  if (!enumtypes)
159  return E_POINTER;
161  if (!new)
162  return E_OUTOFMEMORY;
163 
164  *enumtypes = (IEnumMediaTypes *) new;
165  return S_OK;
166 }
167 long WINAPI
169  unsigned long *npin)
170 {
171  dshowdebug("libAVPin_QueryInternalConnections(%p)\n", this);
172  return E_NOTIMPL;
173 }
174 long WINAPI
176 {
177  dshowdebug("libAVPin_EndOfStream(%p)\n", this);
178  /* I don't care. */
179  return S_OK;
180 }
181 long WINAPI
183 {
184  dshowdebug("libAVPin_BeginFlush(%p)\n", this);
185  /* I don't care. */
186  return S_OK;
187 }
188 long WINAPI
190 {
191  dshowdebug("libAVPin_EndFlush(%p)\n", this);
192  /* I don't care. */
193  return S_OK;
194 }
195 long WINAPI
196 libAVPin_NewSegment(libAVPin *this, REFERENCE_TIME start, REFERENCE_TIME stop,
197  double rate)
198 {
199  dshowdebug("libAVPin_NewSegment(%p)\n", this);
200  /* I don't care. */
201  return S_OK;
202 }
203 
204 static int
206 {
207  IPinVtbl *vtbl = this->vtbl;
208  IMemInputPinVtbl *imemvtbl;
209 
210  if (!filter)
211  return 0;
212 
213  imemvtbl = av_malloc(sizeof(IMemInputPinVtbl));
214  if (!imemvtbl)
215  return 0;
216 
217  SETVTBL(imemvtbl, libAVMemInputPin, QueryInterface);
218  SETVTBL(imemvtbl, libAVMemInputPin, AddRef);
219  SETVTBL(imemvtbl, libAVMemInputPin, Release);
220  SETVTBL(imemvtbl, libAVMemInputPin, GetAllocator);
221  SETVTBL(imemvtbl, libAVMemInputPin, NotifyAllocator);
222  SETVTBL(imemvtbl, libAVMemInputPin, GetAllocatorRequirements);
223  SETVTBL(imemvtbl, libAVMemInputPin, Receive);
224  SETVTBL(imemvtbl, libAVMemInputPin, ReceiveMultiple);
225  SETVTBL(imemvtbl, libAVMemInputPin, ReceiveCanBlock);
226 
227  this->imemvtbl = imemvtbl;
228 
229  SETVTBL(vtbl, libAVPin, QueryInterface);
230  SETVTBL(vtbl, libAVPin, AddRef);
231  SETVTBL(vtbl, libAVPin, Release);
232  SETVTBL(vtbl, libAVPin, Connect);
233  SETVTBL(vtbl, libAVPin, ReceiveConnection);
234  SETVTBL(vtbl, libAVPin, Disconnect);
235  SETVTBL(vtbl, libAVPin, ConnectedTo);
236  SETVTBL(vtbl, libAVPin, ConnectionMediaType);
237  SETVTBL(vtbl, libAVPin, QueryPinInfo);
238  SETVTBL(vtbl, libAVPin, QueryDirection);
239  SETVTBL(vtbl, libAVPin, QueryId);
240  SETVTBL(vtbl, libAVPin, QueryAccept);
241  SETVTBL(vtbl, libAVPin, EnumMediaTypes);
242  SETVTBL(vtbl, libAVPin, QueryInternalConnections);
243  SETVTBL(vtbl, libAVPin, EndOfStream);
244  SETVTBL(vtbl, libAVPin, BeginFlush);
245  SETVTBL(vtbl, libAVPin, EndFlush);
246  SETVTBL(vtbl, libAVPin, NewSegment);
247 
248  this->filter = filter;
249 
250  return 1;
251 }
252 
253 static void
255 {
256  if (!this)
257  return;
258  av_freep(&this->imemvtbl);
259  if (this->type.pbFormat) {
260  CoTaskMemFree(this->type.pbFormat);
261  this->type.pbFormat = NULL;
262  }
263 }
266 
267 /*****************************************************************************
268  * libAVMemInputPin
269  ****************************************************************************/
270 long WINAPI
272  void **ppvObject)
273 {
274  libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
275  dshowdebug("libAVMemInputPin_QueryInterface(%p)\n", this);
276  return libAVPin_QueryInterface(pin, riid, ppvObject);
277 }
278 unsigned long WINAPI
280 {
281  libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
282  dshowdebug("libAVMemInputPin_AddRef(%p)\n", this);
283  return libAVPin_AddRef(pin);
284 }
285 unsigned long WINAPI
287 {
288  libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
289  dshowdebug("libAVMemInputPin_Release(%p)\n", this);
290  return libAVPin_Release(pin);
291 }
292 long WINAPI
293 libAVMemInputPin_GetAllocator(libAVMemInputPin *this, IMemAllocator **alloc)
294 {
295  dshowdebug("libAVMemInputPin_GetAllocator(%p)\n", this);
296  return VFW_E_NO_ALLOCATOR;
297 }
298 long WINAPI
300  BOOL rdwr)
301 {
302  dshowdebug("libAVMemInputPin_NotifyAllocator(%p)\n", this);
303  return S_OK;
304 }
305 long WINAPI
307  ALLOCATOR_PROPERTIES *props)
308 {
309  dshowdebug("libAVMemInputPin_GetAllocatorRequirements(%p)\n", this);
310  return E_NOTIMPL;
311 }
312 long WINAPI
314 {
315  libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
316  enum dshowDeviceType devtype = pin->filter->type;
317  void *priv_data;
319  uint8_t *buf;
320  int buf_size; /* todo should be a long? */
321  int index;
322  int64_t curtime;
323  int64_t orig_curtime;
324  int64_t graphtime;
325  const char *devtypename = (devtype == VideoDevice) ? "video" : "audio";
326  IReferenceClock *clock = pin->filter->clock;
327  int64_t dummy;
328  struct dshow_ctx *ctx;
329 
330 
331  dshowdebug("libAVMemInputPin_Receive(%p)\n", this);
332 
333  if (!sample)
334  return E_POINTER;
335 
336  IMediaSample_GetTime(sample, &orig_curtime, &dummy);
337  orig_curtime += pin->filter->start_time;
338  IReferenceClock_GetTime(clock, &graphtime);
339  if (devtype == VideoDevice) {
340  /* PTS from video devices is unreliable. */
341  IReferenceClock_GetTime(clock, &curtime);
342  } else {
343  IMediaSample_GetTime(sample, &curtime, &dummy);
344  if(curtime > 400000000000000000LL) {
345  /* initial frames sometimes start < 0 (shown as a very large number here,
346  like 437650244077016960 which FFmpeg doesn't like.
347  TODO figure out math. For now just drop them. */
349  "dshow dropping initial (or ending) audio frame with odd PTS too high %"PRId64"\n", curtime);
350  return S_OK;
351  }
352  curtime += pin->filter->start_time;
353  }
354 
355  buf_size = IMediaSample_GetActualDataLength(sample);
356  IMediaSample_GetPointer(sample, &buf);
357  priv_data = pin->filter->priv_data;
358  s = priv_data;
359  ctx = s->priv_data;
360  index = pin->filter->stream_index;
361 
362  av_log(NULL, AV_LOG_VERBOSE, "dshow passing through packet of type %s size %8d "
363  "timestamp %"PRId64" orig timestamp %"PRId64" graph timestamp %"PRId64" diff %"PRId64" %s\n",
364  devtypename, buf_size, curtime, orig_curtime, graphtime, graphtime - orig_curtime, ctx->device_name[devtype]);
365  pin->filter->callback(priv_data, index, buf, buf_size, curtime, devtype);
366 
367  return S_OK;
368 }
369 long WINAPI
371  IMediaSample **samples, long n, long *nproc)
372 {
373  int i;
374  dshowdebug("libAVMemInputPin_ReceiveMultiple(%p)\n", this);
375 
376  for (i = 0; i < n; i++)
378 
379  *nproc = n;
380  return S_OK;
381 }
382 long WINAPI
384 {
385  dshowdebug("libAVMemInputPin_ReceiveCanBlock(%p)\n", this);
386  /* I swear I will not block. */
387  return S_FALSE;
388 }
389 
390 void
392 {
393  libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
394  dshowdebug("libAVMemInputPin_Destroy(%p)\n", this);
395  libAVPin_Destroy(pin);
396 }
VideoDevice
@ VideoDevice
Definition: dshow_capture.h:62
libAVPin_QueryPinInfo
long WINAPI libAVPin_QueryPinInfo(libAVPin *this, PIN_INFO *info)
Definition: dshow_pin.c:108
libAVPin_AddRef
unsigned long WINAPI libAVPin_AddRef(libAVPin *)
dshow_capture.h
DECLARE_RELEASE
#define DECLARE_RELEASE(class)
Definition: dshow_capture.h:101
libAVMemInputPin_GetAllocatorRequirements
long WINAPI libAVMemInputPin_GetAllocatorRequirements(libAVMemInputPin *this, ALLOCATOR_PROPERTIES *props)
Definition: dshow_pin.c:306
libAVMemInputPin
struct libAVMemInputPin libAVMemInputPin
Definition: dshow_capture.h:152
libAVEnumMediaTypes_Create
libAVEnumMediaTypes * libAVEnumMediaTypes_Create(const AM_MEDIA_TYPE *type)
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
libAVPin_QueryAccept
long WINAPI libAVPin_QueryAccept(libAVPin *this, const AM_MEDIA_TYPE *type)
Definition: dshow_pin.c:146
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
libAVFilter::clock
IReferenceClock * clock
Definition: dshow_capture.h:258
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
libAVPin_Destroy
void libAVPin_Destroy(libAVPin *)
DECLARE_QUERYINTERFACE
DECLARE_QUERYINTERFACE(libAVPin, { {&IID_IUnknown, 0}, {&IID_IPin, 0}, {&IID_IMemInputPin, imemoffset} })
Definition: dshow_pin.c:27
libAVPin_QueryId
long WINAPI libAVPin_QueryId(libAVPin *this, wchar_t **id)
Definition: dshow_pin.c:134
libAVFilter::type
enum dshowDeviceType type
Definition: dshow_capture.h:259
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
libAVMemInputPin_GetAllocator
long WINAPI libAVMemInputPin_GetAllocator(libAVMemInputPin *this, IMemAllocator **alloc)
Definition: dshow_pin.c:293
dshow_ctx
Definition: dshow_capture.h:286
libAVFilter::stream_index
int stream_index
Definition: dshow_capture.h:261
DECLARE_ADDREF
#define DECLARE_ADDREF(class)
Definition: dshow_capture.h:94
libAVPin
Definition: dshow_capture.h:160
libAVPin_EnumMediaTypes
long WINAPI libAVPin_EnumMediaTypes(libAVPin *this, IEnumMediaTypes **enumtypes)
Definition: dshow_pin.c:152
s
#define s(width, name)
Definition: cbs_vp9.c:257
DECLARE_CREATE
#define DECLARE_CREATE(class, setup,...)
Definition: dshow_capture.h:123
dshowdebug
#define dshowdebug(...)
Definition: dshow_capture.h:50
info
MIPS optimizations info
Definition: mips.txt:2
libAVPin_Connect
long WINAPI libAVPin_Connect(libAVPin *, IPin *, const AM_MEDIA_TYPE *)
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:197
ctx
AVFormatContext * ctx
Definition: movenc.c:48
AVFormatContext
Format I/O context.
Definition: avformat.h:1335
NULL
#define NULL
Definition: coverity.c:32
libAVPin_Release
unsigned long WINAPI libAVPin_Release(libAVPin *)
libAVPin_Setup
static int libAVPin_Setup(libAVPin *this, libAVFilter *filter)
Definition: dshow_pin.c:205
SETVTBL
#define SETVTBL(vtbl, class, fn)
Definition: dshow_capture.h:145
index
int index
Definition: gxfenc.c:89
libAVPin_ConnectedTo
long WINAPI libAVPin_ConnectedTo(libAVPin *this, IPin **pin)
Definition: dshow_pin.c:82
libAVFilter::start_time
int64_t start_time
Definition: dshow_capture.h:262
libAVMemInputPin_ReceiveCanBlock
long WINAPI libAVMemInputPin_ReceiveCanBlock(libAVMemInputPin *this)
Definition: dshow_pin.c:383
libAVPin_NewSegment
long WINAPI libAVPin_NewSegment(libAVPin *this, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
Definition: dshow_pin.c:196
sample
#define sample
Definition: flacdsp_template.c:44
libAVFilter::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
libAVPin_QueryInternalConnections
long WINAPI libAVPin_QueryInternalConnections(libAVPin *this, IPin **pin, unsigned long *npin)
Definition: dshow_pin.c:168
libAVPin_Disconnect
long WINAPI libAVPin_Disconnect(libAVPin *this)
Definition: dshow_pin.c:68
imemoffset
#define imemoffset
Definition: dshow_pin.c:25
libAVPin_QueryDirection
long WINAPI libAVPin_QueryDirection(libAVPin *this, PIN_DIRECTION *dir)
Definition: dshow_pin.c:125
libAVPin_BeginFlush
long WINAPI libAVPin_BeginFlush(libAVPin *this)
Definition: dshow_pin.c:182
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
libAVMemInputPin_Receive
long WINAPI libAVMemInputPin_Receive(libAVMemInputPin *this, IMediaSample *sample)
Definition: dshow_pin.c:313
libAVFilter::priv_data
void * priv_data
Definition: dshow_capture.h:260
libAVMemInputPin_Destroy
void libAVMemInputPin_Destroy(libAVMemInputPin *this)
Definition: dshow_pin.c:391
libAVPin_QueryInterface
long WINAPI libAVPin_QueryInterface(libAVPin *, const GUID *, void **)
uint8_t
uint8_t
Definition: audio_convert.c:194
libAVMemInputPin_AddRef
unsigned long WINAPI libAVMemInputPin_AddRef(libAVMemInputPin *this)
Definition: dshow_pin.c:279
libAVMemInputPin_NotifyAllocator
long WINAPI libAVMemInputPin_NotifyAllocator(libAVMemInputPin *this, IMemAllocator *alloc, BOOL rdwr)
Definition: dshow_pin.c:299
libAVPin::filter
libAVFilter * filter
Definition: dshow_capture.h:165
L
#define L(x)
Definition: vp56_arith.h:36
libAVPin_ConnectionMediaType
long WINAPI libAVPin_ConnectionMediaType(libAVPin *this, AM_MEDIA_TYPE *type)
Definition: dshow_pin.c:96
libAVMemInputPin_Release
unsigned long WINAPI libAVMemInputPin_Release(libAVMemInputPin *this)
Definition: dshow_pin.c:286
libAVPin_Free
static void libAVPin_Free(libAVPin *this)
Definition: dshow_pin.c:254
dummy
int dummy
Definition: motion.c:64
libAVPin_EndOfStream
long WINAPI libAVPin_EndOfStream(libAVPin *this)
Definition: dshow_pin.c:175
libAVMemInputPin_QueryInterface
long WINAPI libAVMemInputPin_QueryInterface(libAVMemInputPin *this, const GUID *riid, void **ppvObject)
Definition: dshow_pin.c:271
libAVFilter
Definition: dshow_capture.h:249
DECLARE_DESTROY
#define DECLARE_DESTROY(class, func)
Definition: dshow_capture.h:112
samples
Filter the word “frame” indicates either a video frame or a group of audio samples
Definition: filter_design.txt:8
libAVPin_ReceiveConnection
long WINAPI libAVPin_ReceiveConnection(libAVPin *this, IPin *pin, const AM_MEDIA_TYPE *type)
Definition: dshow_pin.c:40
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
libAVPin_EndFlush
long WINAPI libAVPin_EndFlush(libAVPin *this)
Definition: dshow_pin.c:189
libAVEnumMediaTypes
Definition: dshow_capture.h:228
dshowDeviceType
dshowDeviceType
Definition: dshow_capture.h:61
libAVFilter_AddRef
unsigned long WINAPI libAVFilter_AddRef(libAVFilter *)
libAVMemInputPin_ReceiveMultiple
long WINAPI libAVMemInputPin_ReceiveMultiple(libAVMemInputPin *this, IMediaSample **samples, long n, long *nproc)
Definition: dshow_pin.c:370