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
96 libAVPin_ConnectionMediaType(libAVPin *this, AM_MEDIA_TYPE *type)
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;
160  new = libAVEnumMediaTypes_Create(type);
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++)
377  libAVMemInputPin_Receive(this, samples[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 }
long WINAPI libAVPin_ReceiveConnection(libAVPin *this, IPin *pin, const AM_MEDIA_TYPE *type)
Definition: dshow_pin.c:40
#define NULL
Definition: coverity.c:32
#define S_OK
Definition: windows2linux.h:40
long WINAPI libAVMemInputPin_GetAllocatorRequirements(libAVMemInputPin *this, ALLOCATOR_PROPERTIES *props)
Definition: dshow_pin.c:306
enum dshowDeviceType type
#define dshowdebug(...)
Definition: dshow_capture.h:50
#define DECLARE_DESTROY(class, func)
unsigned long WINAPI libAVPin_Release(libAVPin *)
dshowDeviceType
Definition: dshow_capture.h:61
GLint GLenum type
Definition: opengl_enc.c:104
long WINAPI libAVPin_QueryAccept(libAVPin *this, const AM_MEDIA_TYPE *type)
Definition: dshow_pin.c:146
#define E_POINTER
Definition: windows2linux.h:43
#define sample
long WINAPI libAVPin_QueryPinInfo(libAVPin *this, PIN_INFO *info)
Definition: dshow_pin.c:108
#define DECLARE_CREATE(class, setup,...)
IReferenceClock * clock
void libAVPin_Destroy(libAVPin *)
Format I/O context.
Definition: avformat.h:1358
long WINAPI libAVPin_QueryId(libAVPin *this, wchar_t **id)
Definition: dshow_pin.c:134
uint8_t
#define av_malloc(s)
long WINAPI libAVPin_Connect(libAVPin *, IPin *, const AM_MEDIA_TYPE *)
long WINAPI libAVMemInputPin_GetAllocator(libAVMemInputPin *this, IMemAllocator **alloc)
Definition: dshow_pin.c:293
DECLARE_QUERYINTERFACE(libAVPin,{{&IID_IUnknown, 0},{&IID_IPin, 0},{&IID_IMemInputPin, imemoffset}})
Definition: dshow_pin.c:27
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
long WINAPI libAVMemInputPin_ReceiveCanBlock(libAVMemInputPin *this)
Definition: dshow_pin.c:383
long WINAPI libAVPin_EnumMediaTypes(libAVPin *this, IEnumMediaTypes **enumtypes)
Definition: dshow_pin.c:152
#define av_log(a,...)
#define DECLARE_RELEASE(class)
long ff_copy_dshow_media_type(AM_MEDIA_TYPE *dst, const AM_MEDIA_TYPE *src)
Definition: dshow_common.c:24
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
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
void(* callback)(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time, enum dshowDeviceType type)
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
long WINAPI libAVPin_NewSegment(libAVPin *this, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
Definition: dshow_pin.c:196
unsigned long WINAPI libAVPin_AddRef(libAVPin *)
void * priv_data
MIPS optimizations info
Definition: mips.txt:2
long WINAPI libAVPin_ConnectedTo(libAVPin *this, IPin **pin)
Definition: dshow_pin.c:82
AVFormatContext * ctx
Definition: movenc.c:48
#define s(width, name)
Definition: cbs_vp9.c:257
int n
Definition: avisynth_c.h:760
static void libAVPin_Free(libAVPin *this)
Definition: dshow_pin.c:254
int dummy
Definition: motion.c:64
#define L(x)
Definition: vp56_arith.h:36
long WINAPI libAVMemInputPin_QueryInterface(libAVMemInputPin *this, const GUID *riid, void **ppvObject)
Definition: dshow_pin.c:271
#define SETVTBL(vtbl, class, fn)
long WINAPI libAVPin_QueryDirection(libAVPin *this, PIN_DIRECTION *dir)
Definition: dshow_pin.c:125
long WINAPI libAVPin_EndOfStream(libAVPin *this)
Definition: dshow_pin.c:175
long WINAPI libAVPin_EndFlush(libAVPin *this)
Definition: dshow_pin.c:189
long WINAPI libAVPin_Disconnect(libAVPin *this)
Definition: dshow_pin.c:68
void * buf
Definition: avisynth_c.h:766
unsigned long WINAPI libAVFilter_AddRef(libAVFilter *)
int index
Definition: gxfenc.c:89
long WINAPI libAVMemInputPin_Receive(libAVMemInputPin *this, IMediaSample *sample)
Definition: dshow_pin.c:313
char * device_name[2]
void libAVMemInputPin_Destroy(libAVMemInputPin *this)
Definition: dshow_pin.c:391
static int libAVPin_Setup(libAVPin *this, libAVFilter *filter)
Definition: dshow_pin.c:205
unsigned long WINAPI libAVMemInputPin_AddRef(libAVMemInputPin *this)
Definition: dshow_pin.c:279
#define E_OUTOFMEMORY
Definition: windows2linux.h:45
int64_t start_time
long WINAPI libAVPin_QueryInterface(libAVPin *, const GUID *, void **)
unsigned long WINAPI libAVMemInputPin_Release(libAVMemInputPin *this)
Definition: dshow_pin.c:286
#define imemoffset
Definition: dshow_pin.c:25
long WINAPI libAVMemInputPin_NotifyAllocator(libAVMemInputPin *this, IMemAllocator *alloc, BOOL rdwr)
Definition: dshow_pin.c:299
long WINAPI libAVMemInputPin_ReceiveMultiple(libAVMemInputPin *this, IMediaSample **samples, long n, long *nproc)
Definition: dshow_pin.c:370
long WINAPI libAVPin_BeginFlush(libAVPin *this)
Definition: dshow_pin.c:182
uint32_t BOOL
#define S_FALSE
Definition: windows2linux.h:41
long WINAPI libAVPin_QueryInternalConnections(libAVPin *this, IPin **pin, unsigned long *npin)
Definition: dshow_pin.c:168
void * priv_data
Format private data.
Definition: avformat.h:1386
libAVEnumMediaTypes * libAVEnumMediaTypes_Create(const AM_MEDIA_TYPE *type)
void ff_print_AM_MEDIA_TYPE(const AM_MEDIA_TYPE *type)
Definition: dshow_common.c:134
long WINAPI libAVPin_ConnectionMediaType(libAVPin *this, AM_MEDIA_TYPE *type)
Definition: dshow_pin.c:96
Filter the word “frame” indicates either a video frame or a group of audio samples
#define av_freep(p)
void INT64 start
Definition: avisynth_c.h:766
struct libAVMemInputPin libAVMemInputPin
#define DECLARE_ADDREF(class)
Definition: dshow_capture.h:94
libAVFilter * filter