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 "libavutil/mem.h"
23 #include "dshow_capture.h"
24 
25 #include <stddef.h>
26 #define imemoffset offsetof(DShowPin, imemvtbl)
27 
29  { {&IID_IUnknown,0}, {&IID_IPin,0}, {&IID_IMemInputPin,imemoffset} })
32 
33 long WINAPI ff_dshow_pin_Connect(DShowPin *this, IPin *pin, const AM_MEDIA_TYPE *type)
34 {
35  dshowdebug("ff_dshow_pin_Connect(%p, %p, %p)\n", this, pin, type);
36  /* Input pins receive connections. */
37  return S_FALSE;
38 }
39 long WINAPI ff_dshow_pin_ReceiveConnection(DShowPin *this, IPin *pin,
40  const AM_MEDIA_TYPE *type)
41 {
42  enum dshowDeviceType devtype = this->filter->type;
43  dshowdebug("ff_dshow_pin_ReceiveConnection(%p)\n", this);
44 
45  if (!pin)
46  return E_POINTER;
47  if (this->connectedto)
48  return VFW_E_ALREADY_CONNECTED;
49 
51  if (devtype == VideoDevice) {
52  if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video))
53  return VFW_E_TYPE_NOT_ACCEPTED;
54  } else {
55  if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Audio))
56  return VFW_E_TYPE_NOT_ACCEPTED;
57  }
58 
59  IPin_AddRef(pin);
60  this->connectedto = pin;
61 
62  ff_copy_dshow_media_type(&this->type, type);
63 
64  return S_OK;
65 }
67 {
68  dshowdebug("ff_dshow_pin_Disconnect(%p)\n", this);
69 
70  if (this->filter->state != State_Stopped)
71  return VFW_E_NOT_STOPPED;
72  if (!this->connectedto)
73  return S_FALSE;
74  IPin_Release(this->connectedto);
75  this->connectedto = NULL;
76 
77  return S_OK;
78 }
79 long WINAPI ff_dshow_pin_ConnectedTo(DShowPin *this, IPin **pin)
80 {
81  dshowdebug("ff_dshow_pin_ConnectedTo(%p)\n", this);
82 
83  if (!pin)
84  return E_POINTER;
85  if (!this->connectedto)
86  return VFW_E_NOT_CONNECTED;
87  IPin_AddRef(this->connectedto);
88  *pin = this->connectedto;
89 
90  return S_OK;
91 }
92 long WINAPI ff_dshow_pin_ConnectionMediaType(DShowPin *this, AM_MEDIA_TYPE *type)
93 {
94  dshowdebug("ff_dshow_pin_ConnectionMediaType(%p)\n", this);
95 
96  if (!type)
97  return E_POINTER;
98  if (!this->connectedto)
99  return VFW_E_NOT_CONNECTED;
100 
101  return ff_copy_dshow_media_type(type, &this->type);
102 }
103 long WINAPI ff_dshow_pin_QueryPinInfo(DShowPin *this, PIN_INFO *info)
104 {
105  dshowdebug("ff_dshow_pin_QueryPinInfo(%p)\n", this);
106 
107  if (!info)
108  return E_POINTER;
109 
110  if (this->filter)
112 
113  info->pFilter = (IBaseFilter *) this->filter;
114  info->dir = PINDIR_INPUT;
115  wcscpy(info->achName, L"Capture");
116 
117  return S_OK;
118 }
119 long WINAPI ff_dshow_pin_QueryDirection(DShowPin *this, PIN_DIRECTION *dir)
120 {
121  dshowdebug("ff_dshow_pin_QueryDirection(%p)\n", this);
122  if (!dir)
123  return E_POINTER;
124  *dir = PINDIR_INPUT;
125  return S_OK;
126 }
127 long WINAPI ff_dshow_pin_QueryId(DShowPin *this, wchar_t **id)
128 {
129  dshowdebug("ff_dshow_pin_QueryId(%p)\n", this);
130 
131  if (!id)
132  return E_POINTER;
133 
134  *id = wcsdup(L"libAV Pin");
135 
136  return S_OK;
137 }
138 long WINAPI ff_dshow_pin_QueryAccept(DShowPin *this, const AM_MEDIA_TYPE *type)
139 {
140  dshowdebug("ff_dshow_pin_QueryAccept(%p)\n", this);
141  return S_FALSE;
142 }
143 long WINAPI ff_dshow_pin_EnumMediaTypes(DShowPin *this, IEnumMediaTypes **enumtypes)
144 {
145  const AM_MEDIA_TYPE *type = NULL;
146  DShowEnumMediaTypes *new;
147  dshowdebug("ff_dshow_pin_EnumMediaTypes(%p)\n", this);
148 
149  if (!enumtypes)
150  return E_POINTER;
152  if (!new)
153  return E_OUTOFMEMORY;
154 
155  *enumtypes = (IEnumMediaTypes *) new;
156  return S_OK;
157 }
158 long WINAPI ff_dshow_pin_QueryInternalConnections(DShowPin *this, IPin **pin,
159  unsigned long *npin)
160 {
161  dshowdebug("ff_dshow_pin_QueryInternalConnections(%p)\n", this);
162  return E_NOTIMPL;
163 }
165 {
166  dshowdebug("ff_dshow_pin_EndOfStream(%p)\n", this);
167  /* I don't care. */
168  return S_OK;
169 }
171 {
172  dshowdebug("ff_dshow_pin_BeginFlush(%p)\n", this);
173  /* I don't care. */
174  return S_OK;
175 }
176 long WINAPI ff_dshow_pin_EndFlush(DShowPin *this)
177 {
178  dshowdebug("ff_dshow_pin_EndFlush(%p)\n", this);
179  /* I don't care. */
180  return S_OK;
181 }
182 long WINAPI ff_dshow_pin_NewSegment(DShowPin *this, REFERENCE_TIME start, REFERENCE_TIME stop,
183  double rate)
184 {
185  dshowdebug("ff_dshow_pin_NewSegment(%p)\n", this);
186  /* I don't care. */
187  return S_OK;
188 }
189 
191 {
192  IPinVtbl *vtbl = this->vtbl;
193  IMemInputPinVtbl *imemvtbl;
194 
195  if (!filter)
196  return 0;
197 
198  imemvtbl = av_malloc(sizeof(IMemInputPinVtbl));
199  if (!imemvtbl)
200  return 0;
201 
202  SETVTBL(imemvtbl, meminputpin, QueryInterface);
203  SETVTBL(imemvtbl, meminputpin, AddRef);
204  SETVTBL(imemvtbl, meminputpin, Release);
205  SETVTBL(imemvtbl, meminputpin, GetAllocator);
206  SETVTBL(imemvtbl, meminputpin, NotifyAllocator);
207  SETVTBL(imemvtbl, meminputpin, GetAllocatorRequirements);
208  SETVTBL(imemvtbl, meminputpin, Receive);
209  SETVTBL(imemvtbl, meminputpin, ReceiveMultiple);
210  SETVTBL(imemvtbl, meminputpin, ReceiveCanBlock);
211 
212  this->imemvtbl = imemvtbl;
213 
214  SETVTBL(vtbl, pin, QueryInterface);
215  SETVTBL(vtbl, pin, AddRef);
216  SETVTBL(vtbl, pin, Release);
217  SETVTBL(vtbl, pin, Connect);
218  SETVTBL(vtbl, pin, ReceiveConnection);
219  SETVTBL(vtbl, pin, Disconnect);
220  SETVTBL(vtbl, pin, ConnectedTo);
221  SETVTBL(vtbl, pin, ConnectionMediaType);
222  SETVTBL(vtbl, pin, QueryPinInfo);
223  SETVTBL(vtbl, pin, QueryDirection);
224  SETVTBL(vtbl, pin, QueryId);
225  SETVTBL(vtbl, pin, QueryAccept);
226  SETVTBL(vtbl, pin, EnumMediaTypes);
227  SETVTBL(vtbl, pin, QueryInternalConnections);
228  SETVTBL(vtbl, pin, EndOfStream);
229  SETVTBL(vtbl, pin, BeginFlush);
230  SETVTBL(vtbl, pin, EndFlush);
231  SETVTBL(vtbl, pin, NewSegment);
232 
233  this->filter = filter;
234 
235  return 1;
236 }
237 
238 static void ff_dshow_pin_Free(DShowPin *this)
239 {
240  if (!this)
241  return;
242  av_freep(&this->imemvtbl);
243  if (this->type.pbFormat) {
244  CoTaskMemFree(this->type.pbFormat);
245  this->type.pbFormat = NULL;
246  }
247 }
250 
251 /*****************************************************************************
252  * DShowMemInputPin
253  ****************************************************************************/
254 long WINAPI ff_dshow_meminputpin_QueryInterface(DShowMemInputPin *this, const GUID *riid,
255  void **ppvObject)
256 {
257  DShowPin *pin = (DShowPin *) ((uint8_t *) this - imemoffset);
258  dshowdebug("ff_dshow_meminputpin_QueryInterface(%p)\n", this);
259  return ff_dshow_pin_QueryInterface(pin, riid, ppvObject);
260 }
262 {
263  DShowPin *pin = (DShowPin *) ((uint8_t *) this - imemoffset);
264  dshowdebug("ff_dshow_meminputpin_AddRef(%p)\n", this);
265  return ff_dshow_pin_AddRef(pin);
266 }
268 {
269  DShowPin *pin = (DShowPin *) ((uint8_t *) this - imemoffset);
270  dshowdebug("ff_dshow_meminputpin_Release(%p)\n", this);
271  return ff_dshow_pin_Release(pin);
272 }
273 long WINAPI ff_dshow_meminputpin_GetAllocator(DShowMemInputPin *this, IMemAllocator **alloc)
274 {
275  dshowdebug("ff_dshow_meminputpin_GetAllocator(%p)\n", this);
276  return VFW_E_NO_ALLOCATOR;
277 }
278 long WINAPI ff_dshow_meminputpin_NotifyAllocator(DShowMemInputPin *this, IMemAllocator *alloc,
279  BOOL rdwr)
280 {
281  dshowdebug("ff_dshow_meminputpin_NotifyAllocator(%p)\n", this);
282  return S_OK;
283 }
285  ALLOCATOR_PROPERTIES *props)
286 {
287  dshowdebug("ff_dshow_meminputpin_GetAllocatorRequirements(%p)\n", this);
288  return E_NOTIMPL;
289 }
290 long WINAPI ff_dshow_meminputpin_Receive(DShowMemInputPin *this, IMediaSample *sample)
291 {
292  DShowPin *pin = (DShowPin *) ((uint8_t *) this - imemoffset);
293  enum dshowDeviceType devtype = pin->filter->type;
294  void *priv_data;
296  uint8_t *buf;
297  int buf_size; /* todo should be a long? */
298  int index;
299  int64_t chosentime = 0;
300  int64_t sampletime = 0;
301  int64_t graphtime = 0;
302  int use_sample_time = 1;
303  const char *devtypename = (devtype == VideoDevice) ? "video" : "audio";
304  IReferenceClock *clock = pin->filter->clock;
305  int64_t dummy;
306  struct dshow_ctx *ctx;
307  HRESULT hr;
308 
309 
310  dshowdebug("ff_dshow_meminputpin_Receive(%p)\n", this);
311 
312  if (!sample)
313  return E_POINTER;
314 
315  priv_data = pin->filter->priv_data;
316  s = priv_data;
317  ctx = s->priv_data;
318 
319  hr = IMediaSample_GetTime(sample, &sampletime, &dummy);
320  IReferenceClock_GetTime(clock, &graphtime);
321  if (devtype == VideoDevice && !ctx->use_video_device_timestamps) {
322  /* PTS from video devices is unreliable. */
323  chosentime = graphtime;
324  use_sample_time = 0;
325  } else {
326  if (hr == VFW_E_SAMPLE_TIME_NOT_SET || sampletime == 0) {
327  chosentime = graphtime;
328  use_sample_time = 0;
330  "frame with missing sample timestamp encountered, falling back to graph timestamp\n");
331  }
332  else if (sampletime > 400000000000000000LL) {
333  /* initial frames sometimes start < 0 (shown as a very large number here,
334  like 437650244077016960 which FFmpeg doesn't like).
335  TODO figure out math. For now just drop them. */
337  "dropping initial (or ending) sample with odd PTS too high %"PRId64"\n", sampletime);
338  return S_OK;
339  } else
340  chosentime = sampletime;
341  }
342  // media sample time is relative to graph start time
343  sampletime += pin->filter->start_time;
344  if (use_sample_time)
345  chosentime += pin->filter->start_time;
346 
347  buf_size = IMediaSample_GetActualDataLength(sample);
348  IMediaSample_GetPointer(sample, &buf);
349  index = pin->filter->stream_index;
350 
351  av_log(s, AV_LOG_VERBOSE, "passing through packet of type %s size %8d "
352  "timestamp %"PRId64" orig timestamp %"PRId64" graph timestamp %"PRId64" diff %"PRId64" %s\n",
353  devtypename, buf_size, chosentime, sampletime, graphtime, graphtime - sampletime, ctx->device_name[devtype]);
354  pin->filter->callback(priv_data, index, buf, buf_size, chosentime, devtype);
355 
356  return S_OK;
357 }
359  IMediaSample **samples, long n, long *nproc)
360 {
361  int i;
362  dshowdebug("ff_dshow_meminputpin_ReceiveMultiple(%p)\n", this);
363 
364  for (i = 0; i < n; i++)
366 
367  *nproc = n;
368  return S_OK;
369 }
371 {
372  dshowdebug("ff_dshow_meminputpin_ReceiveCanBlock(%p)\n", this);
373  /* I swear I will not block. */
374  return S_FALSE;
375 }
376 
378 {
379  DShowPin *pin = (DShowPin *) ((uint8_t *) this - imemoffset);
380  dshowdebug("ff_dshow_meminputpin_Destroy(%p)\n", this);
382 }
ff_dshow_meminputpin_Receive
long WINAPI ff_dshow_meminputpin_Receive(DShowMemInputPin *this, IMediaSample *sample)
Definition: dshow_pin.c:290
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:254
ff_dshow_meminputpin_AddRef
unsigned long WINAPI ff_dshow_meminputpin_AddRef(DShowMemInputPin *this)
Definition: dshow_pin.c:261
DShowPin::filter
DShowFilter * filter
Definition: dshow_capture.h:166
ff_dshow_meminputpin_GetAllocatorRequirements
long WINAPI ff_dshow_meminputpin_GetAllocatorRequirements(DShowMemInputPin *this, ALLOCATOR_PROPERTIES *props)
Definition: dshow_pin.c:284
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
int64_t
long long int64_t
Definition: coverity.c:34
ff_dshow_pin_BeginFlush
long WINAPI ff_dshow_pin_BeginFlush(DShowPin *this)
Definition: dshow_pin.c:170
ff_dshow_pin_QueryInternalConnections
long WINAPI ff_dshow_pin_QueryInternalConnections(DShowPin *this, IPin **pin, unsigned long *npin)
Definition: dshow_pin.c:158
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:225
filter
void(* filter)(uint8_t *src, int stride, int qscale)
Definition: h263dsp.c:29
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:164
ff_dshow_pin_ConnectionMediaType
long WINAPI ff_dshow_pin_ConnectionMediaType(DShowPin *this, AM_MEDIA_TYPE *type)
Definition: dshow_pin.c:92
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:143
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:370
ff_dshow_pin_ConnectedTo
long WINAPI ff_dshow_pin_ConnectedTo(DShowPin *this, IPin **pin)
Definition: dshow_pin.c:79
ff_dshow_pin_Free
static void ff_dshow_pin_Free(DShowPin *this)
Definition: dshow_pin.c:238
dshow_ctx
Definition: dshow_capture.h:287
ff_dshow_pin_EndFlush
long WINAPI ff_dshow_pin_EndFlush(DShowPin *this)
Definition: dshow_pin.c:176
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:230
DShowFilter::type
enum dshowDeviceType type
Definition: dshow_capture.h:260
ctx
AVFormatContext * ctx
Definition: movenc.c:49
DShowFilter
Definition: dshow_capture.h:250
SETVTBL
#define SETVTBL(vtbl, prefix, fn)
Definition: dshow_capture.h:146
AVFormatContext
Format I/O context.
Definition: avformat.h:1300
NULL
#define NULL
Definition: coverity.c:32
DShowEnumMediaTypes
Definition: dshow_capture.h:229
ff_dshow_pin_QueryPinInfo
long WINAPI ff_dshow_pin_QueryPinInfo(DShowPin *this, PIN_INFO *info)
Definition: dshow_pin.c:103
ff_dshow_meminputpin_GetAllocator
long WINAPI ff_dshow_meminputpin_GetAllocator(DShowMemInputPin *this, IMemAllocator **alloc)
Definition: dshow_pin.c:273
index
int index
Definition: gxfenc.c:90
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:182
ff_dshow_pin_ReceiveConnection
long WINAPI ff_dshow_pin_ReceiveConnection(DShowPin *this, IPin *pin, const AM_MEDIA_TYPE *type)
Definition: dshow_pin.c:39
sample
#define sample
Definition: flacdsp_template.c:44
DShowMemInputPin
struct DShowMemInputPin DShowMemInputPin
Definition: dshow_capture.h:153
ff_dshow_pin_QueryDirection
long WINAPI ff_dshow_pin_QueryDirection(DShowPin *this, PIN_DIRECTION *dir)
Definition: dshow_pin.c:119
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:267
ff_dshow_pin_Disconnect
long WINAPI ff_dshow_pin_Disconnect(DShowPin *this)
Definition: dshow_pin.c:66
imemoffset
#define imemoffset
Definition: dshow_pin.c:26
DShowFilter::clock
IReferenceClock * clock
Definition: dshow_capture.h:259
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
ff_dshow_pin_Setup
static int ff_dshow_pin_Setup(DShowPin *this, DShowFilter *filter)
Definition: dshow_pin.c:190
ff_dshow_meminputpin_Destroy
void ff_dshow_meminputpin_Destroy(DShowMemInputPin *this)
Definition: dshow_pin.c:377
DShowFilter::stream_index
int stream_index
Definition: dshow_capture.h:262
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:261
ff_dshow_pin_QueryAccept
long WINAPI ff_dshow_pin_QueryAccept(DShowPin *this, const AM_MEDIA_TYPE *type)
Definition: dshow_pin.c:138
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 *)
mem.h
DECLARE_QUERYINTERFACE
DECLARE_QUERYINTERFACE(pin, DShowPin, { {&IID_IUnknown, 0}, {&IID_IPin, 0}, {&IID_IMemInputPin, imemoffset} })
Definition: dshow_pin.c:28
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:358
ff_dshow_pin_QueryId
long WINAPI ff_dshow_pin_QueryId(DShowPin *this, wchar_t **id)
Definition: dshow_pin.c:127
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:278
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
DShowFilter::start_time
int64_t start_time
Definition: dshow_capture.h:263
DShowPin
Definition: dshow_capture.h:161
dshowDeviceType
dshowDeviceType
Definition: dshow_capture.h:61