FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dshow.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 #include "libavutil/parseutils.h"
24 #include "libavutil/pixdesc.h"
25 #include "libavutil/opt.h"
26 #include "libavformat/internal.h"
27 #include "libavformat/riff.h"
28 #include "avdevice.h"
29 #include "libavcodec/raw.h"
30 
31 
32 static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
33 {
34  switch(biCompression) {
35  case BI_BITFIELDS:
36  case BI_RGB:
37  switch(biBitCount) { /* 1-8 are untested */
38  case 1:
39  return AV_PIX_FMT_MONOWHITE;
40  case 4:
41  return AV_PIX_FMT_RGB4;
42  case 8:
43  return AV_PIX_FMT_RGB8;
44  case 16:
45  return AV_PIX_FMT_RGB555;
46  case 24:
47  return AV_PIX_FMT_BGR24;
48  case 32:
49  return AV_PIX_FMT_0RGB32;
50  }
51  }
52  return avpriv_find_pix_fmt(avpriv_get_raw_pix_fmt_tags(), biCompression); // all others
53 }
54 
55 static int
57 {
58  struct dshow_ctx *ctx = s->priv_data;
60 
61  if (ctx->control) {
62  IMediaControl_Stop(ctx->control);
63  IMediaControl_Release(ctx->control);
64  }
65 
66  if (ctx->media_event)
67  IMediaEvent_Release(ctx->media_event);
68 
69  if (ctx->graph) {
70  IEnumFilters *fenum;
71  int r;
72  r = IGraphBuilder_EnumFilters(ctx->graph, &fenum);
73  if (r == S_OK) {
74  IBaseFilter *f;
75  IEnumFilters_Reset(fenum);
76  while (IEnumFilters_Next(fenum, 1, &f, NULL) == S_OK) {
77  if (IGraphBuilder_RemoveFilter(ctx->graph, f) == S_OK)
78  IEnumFilters_Reset(fenum); /* When a filter is removed,
79  * the list must be reset. */
80  IBaseFilter_Release(f);
81  }
82  IEnumFilters_Release(fenum);
83  }
84  IGraphBuilder_Release(ctx->graph);
85  }
86 
87  if (ctx->capture_pin[VideoDevice])
89  if (ctx->capture_pin[AudioDevice])
91  if (ctx->capture_filter[VideoDevice])
93  if (ctx->capture_filter[AudioDevice])
95 
96  if (ctx->device_pin[VideoDevice])
97  IPin_Release(ctx->device_pin[VideoDevice]);
98  if (ctx->device_pin[AudioDevice])
99  IPin_Release(ctx->device_pin[AudioDevice]);
100  if (ctx->device_filter[VideoDevice])
101  IBaseFilter_Release(ctx->device_filter[VideoDevice]);
102  if (ctx->device_filter[AudioDevice])
103  IBaseFilter_Release(ctx->device_filter[AudioDevice]);
104 
105  if (ctx->device_name[0])
106  av_freep(&ctx->device_name[0]);
107  if (ctx->device_name[1])
108  av_freep(&ctx->device_name[1]);
109 
110  if(ctx->mutex)
111  CloseHandle(ctx->mutex);
112  if(ctx->event[0])
113  CloseHandle(ctx->event[0]);
114  if(ctx->event[1])
115  CloseHandle(ctx->event[1]);
116 
117  pktl = ctx->pktl;
118  while (pktl) {
119  AVPacketList *next = pktl->next;
120  av_free_packet(&pktl->pkt);
121  av_free(pktl);
122  pktl = next;
123  }
124 
125  CoUninitialize();
126 
127  return 0;
128 }
129 
130 static char *dup_wchar_to_utf8(wchar_t *w)
131 {
132  char *s = NULL;
133  int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
134  s = av_malloc(l);
135  if (s)
136  WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
137  return s;
138 }
139 
140 static int shall_we_drop(AVFormatContext *s, int index, enum dshowDeviceType devtype)
141 {
142  struct dshow_ctx *ctx = s->priv_data;
143  static const uint8_t dropscore[] = {62, 75, 87, 100};
144  const int ndropscores = FF_ARRAY_ELEMS(dropscore);
145  unsigned int buffer_fullness = (ctx->curbufsize[index]*100)/s->max_picture_buffer;
146  const char *devtypename = (devtype == VideoDevice) ? "video" : "audio";
147 
148  if(dropscore[++ctx->video_frame_num%ndropscores] <= buffer_fullness) {
149  av_log(s, AV_LOG_ERROR,
150  "real-time buffer [%s] [%s input] too full or near too full (%d%% of size: %d [rtbufsize parameter])! frame dropped!\n",
151  ctx->device_name[devtype], devtypename, buffer_fullness, s->max_picture_buffer);
152  return 1;
153  }
154 
155  return 0;
156 }
157 
158 static void
159 callback(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time, enum dshowDeviceType devtype)
160 {
161  AVFormatContext *s = priv_data;
162  struct dshow_ctx *ctx = s->priv_data;
163  AVPacketList **ppktl, *pktl_next;
164 
165 // dump_videohdr(s, vdhdr);
166 
167  WaitForSingleObject(ctx->mutex, INFINITE);
168 
169  if(shall_we_drop(s, index, devtype))
170  goto fail;
171 
172  pktl_next = av_mallocz(sizeof(AVPacketList));
173  if(!pktl_next)
174  goto fail;
175 
176  if(av_new_packet(&pktl_next->pkt, buf_size) < 0) {
177  av_free(pktl_next);
178  goto fail;
179  }
180 
181  pktl_next->pkt.stream_index = index;
182  pktl_next->pkt.pts = time;
183  memcpy(pktl_next->pkt.data, buf, buf_size);
184 
185  for(ppktl = &ctx->pktl ; *ppktl ; ppktl = &(*ppktl)->next);
186  *ppktl = pktl_next;
187  ctx->curbufsize[index] += buf_size;
188 
189  SetEvent(ctx->event[1]);
190  ReleaseMutex(ctx->mutex);
191 
192  return;
193 fail:
194  ReleaseMutex(ctx->mutex);
195  return;
196 }
197 
198 /**
199  * Cycle through available devices using the device enumerator devenum,
200  * retrieve the device with type specified by devtype and return the
201  * pointer to the object found in *pfilter.
202  * If pfilter is NULL, list all device names.
203  */
204 static int
205 dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum,
206  enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype, IBaseFilter **pfilter)
207 {
208  struct dshow_ctx *ctx = avctx->priv_data;
209  IBaseFilter *device_filter = NULL;
210  IEnumMoniker *classenum = NULL;
211  IMoniker *m = NULL;
212  const char *device_name = ctx->device_name[devtype];
213  int skip = (devtype == VideoDevice) ? ctx->video_device_number
214  : ctx->audio_device_number;
215  int r;
216 
217  const GUID *device_guid[2] = { &CLSID_VideoInputDeviceCategory,
218  &CLSID_AudioInputDeviceCategory };
219  const char *devtypename = (devtype == VideoDevice) ? "video" : "audio only";
220  const char *sourcetypename = (sourcetype == VideoSourceDevice) ? "video" : "audio";
221 
222  r = ICreateDevEnum_CreateClassEnumerator(devenum, device_guid[sourcetype],
223  (IEnumMoniker **) &classenum, 0);
224  if (r != S_OK) {
225  av_log(avctx, AV_LOG_ERROR, "Could not enumerate %s devices (or none found).\n",
226  devtypename);
227  return AVERROR(EIO);
228  }
229 
230  while (!device_filter && IEnumMoniker_Next(classenum, 1, &m, NULL) == S_OK) {
231  IPropertyBag *bag = NULL;
232  char *friendly_name = NULL;
233  char *unique_name = NULL;
234  VARIANT var;
235  IBindCtx *bind_ctx = NULL;
236  LPOLESTR olestr = NULL;
237  LPMALLOC co_malloc = NULL;
238  int i;
239 
240  r = CoGetMalloc(1, &co_malloc);
241  if (r = S_OK)
242  goto fail1;
243  r = CreateBindCtx(0, &bind_ctx);
244  if (r != S_OK)
245  goto fail1;
246  /* GetDisplayname works for both video and audio, DevicePath doesn't */
247  r = IMoniker_GetDisplayName(m, bind_ctx, NULL, &olestr);
248  if (r != S_OK)
249  goto fail1;
250  unique_name = dup_wchar_to_utf8(olestr);
251  /* replace ':' with '_' since we use : to delineate between sources */
252  for (i = 0; i < strlen(unique_name); i++) {
253  if (unique_name[i] == ':')
254  unique_name[i] = '_';
255  }
256 
257  r = IMoniker_BindToStorage(m, 0, 0, &IID_IPropertyBag, (void *) &bag);
258  if (r != S_OK)
259  goto fail1;
260 
261  var.vt = VT_BSTR;
262  r = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL);
263  if (r != S_OK)
264  goto fail1;
265  friendly_name = dup_wchar_to_utf8(var.bstrVal);
266 
267  if (pfilter) {
268  if (strcmp(device_name, friendly_name) && strcmp(device_name, unique_name))
269  goto fail1;
270 
271  if (!skip--) {
272  r = IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (void *) &device_filter);
273  if (r != S_OK) {
274  av_log(avctx, AV_LOG_ERROR, "Unable to BindToObject for %s\n", device_name);
275  goto fail1;
276  }
277  }
278  } else {
279  av_log(avctx, AV_LOG_INFO, " \"%s\"\n", friendly_name);
280  av_log(avctx, AV_LOG_INFO, " Alternative name \"%s\"\n", unique_name);
281  }
282 
283 fail1:
284  if (olestr && co_malloc)
285  IMalloc_Free(co_malloc, olestr);
286  if (bind_ctx)
287  IBindCtx_Release(bind_ctx);
288  av_free(friendly_name);
289  av_free(unique_name);
290  if (bag)
291  IPropertyBag_Release(bag);
292  IMoniker_Release(m);
293  }
294 
295  IEnumMoniker_Release(classenum);
296 
297  if (pfilter) {
298  if (!device_filter) {
299  av_log(avctx, AV_LOG_ERROR, "Could not find %s device with name [%s] among source devices of type %s.\n",
300  devtypename, device_name, sourcetypename);
301  return AVERROR(EIO);
302  }
303  *pfilter = device_filter;
304  }
305 
306  return 0;
307 }
308 
309 /**
310  * Cycle through available formats using the specified pin,
311  * try to set parameters specified through AVOptions and if successful
312  * return 1 in *pformat_set.
313  * If pformat_set is NULL, list all pin capabilities.
314  */
315 static void
317  IPin *pin, int *pformat_set)
318 {
319  struct dshow_ctx *ctx = avctx->priv_data;
320  IAMStreamConfig *config = NULL;
321  AM_MEDIA_TYPE *type = NULL;
322  int format_set = 0;
323  void *caps = NULL;
324  int i, n, size, r;
325 
326  if (IPin_QueryInterface(pin, &IID_IAMStreamConfig, (void **) &config) != S_OK)
327  return;
328  if (IAMStreamConfig_GetNumberOfCapabilities(config, &n, &size) != S_OK)
329  goto end;
330 
331  caps = av_malloc(size);
332  if (!caps)
333  goto end;
334 
335  for (i = 0; i < n && !format_set; i++) {
336  r = IAMStreamConfig_GetStreamCaps(config, i, &type, (void *) caps);
337  if (r != S_OK)
338  goto next;
339 #if DSHOWDEBUG
341 #endif
342 
343  if (devtype == VideoDevice) {
344  VIDEO_STREAM_CONFIG_CAPS *vcaps = caps;
345  BITMAPINFOHEADER *bih;
346  int64_t *fr;
347  const AVCodecTag *const tags[] = { avformat_get_riff_video_tags(), NULL };
348 #if DSHOWDEBUG
350 #endif
351  if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo)) {
352  VIDEOINFOHEADER *v = (void *) type->pbFormat;
353  fr = &v->AvgTimePerFrame;
354  bih = &v->bmiHeader;
355  } else if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo2)) {
356  VIDEOINFOHEADER2 *v = (void *) type->pbFormat;
357  fr = &v->AvgTimePerFrame;
358  bih = &v->bmiHeader;
359  } else {
360  goto next;
361  }
362  if (!pformat_set) {
363  enum AVPixelFormat pix_fmt = dshow_pixfmt(bih->biCompression, bih->biBitCount);
364  if (pix_fmt == AV_PIX_FMT_NONE) {
365  enum AVCodecID codec_id = av_codec_get_id(tags, bih->biCompression);
366  AVCodec *codec = avcodec_find_decoder(codec_id);
367  if (codec_id == AV_CODEC_ID_NONE || !codec) {
368  av_log(avctx, AV_LOG_INFO, " unknown compression type 0x%X", (int) bih->biCompression);
369  } else {
370  av_log(avctx, AV_LOG_INFO, " vcodec=%s", codec->name);
371  }
372  } else {
373  av_log(avctx, AV_LOG_INFO, " pixel_format=%s", av_get_pix_fmt_name(pix_fmt));
374  }
375  av_log(avctx, AV_LOG_INFO, " min s=%ldx%ld fps=%g max s=%ldx%ld fps=%g\n",
376  vcaps->MinOutputSize.cx, vcaps->MinOutputSize.cy,
377  1e7 / vcaps->MaxFrameInterval,
378  vcaps->MaxOutputSize.cx, vcaps->MaxOutputSize.cy,
379  1e7 / vcaps->MinFrameInterval);
380  continue;
381  }
382  if (ctx->video_codec_id != AV_CODEC_ID_RAWVIDEO) {
383  if (ctx->video_codec_id != av_codec_get_id(tags, bih->biCompression))
384  goto next;
385  }
386  if (ctx->pixel_format != AV_PIX_FMT_NONE &&
387  ctx->pixel_format != dshow_pixfmt(bih->biCompression, bih->biBitCount)) {
388  goto next;
389  }
390  if (ctx->framerate) {
391  int64_t framerate = ((int64_t) ctx->requested_framerate.den*10000000)
392  / ctx->requested_framerate.num;
393  if (framerate > vcaps->MaxFrameInterval ||
394  framerate < vcaps->MinFrameInterval)
395  goto next;
396  *fr = framerate;
397  }
398  if (ctx->requested_width && ctx->requested_height) {
399  if (ctx->requested_width > vcaps->MaxOutputSize.cx ||
400  ctx->requested_width < vcaps->MinOutputSize.cx ||
401  ctx->requested_height > vcaps->MaxOutputSize.cy ||
402  ctx->requested_height < vcaps->MinOutputSize.cy)
403  goto next;
404  bih->biWidth = ctx->requested_width;
405  bih->biHeight = ctx->requested_height;
406  }
407  } else {
408  AUDIO_STREAM_CONFIG_CAPS *acaps = caps;
409  WAVEFORMATEX *fx;
410 #if DSHOWDEBUG
412 #endif
413  if (IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx)) {
414  fx = (void *) type->pbFormat;
415  } else {
416  goto next;
417  }
418  if (!pformat_set) {
419  av_log(avctx, AV_LOG_INFO, " min ch=%lu bits=%lu rate=%6lu max ch=%lu bits=%lu rate=%6lu\n",
420  acaps->MinimumChannels, acaps->MinimumBitsPerSample, acaps->MinimumSampleFrequency,
421  acaps->MaximumChannels, acaps->MaximumBitsPerSample, acaps->MaximumSampleFrequency);
422  continue;
423  }
424  if (ctx->sample_rate) {
425  if (ctx->sample_rate > acaps->MaximumSampleFrequency ||
426  ctx->sample_rate < acaps->MinimumSampleFrequency)
427  goto next;
428  fx->nSamplesPerSec = ctx->sample_rate;
429  }
430  if (ctx->sample_size) {
431  if (ctx->sample_size > acaps->MaximumBitsPerSample ||
432  ctx->sample_size < acaps->MinimumBitsPerSample)
433  goto next;
434  fx->wBitsPerSample = ctx->sample_size;
435  }
436  if (ctx->channels) {
437  if (ctx->channels > acaps->MaximumChannels ||
438  ctx->channels < acaps->MinimumChannels)
439  goto next;
440  fx->nChannels = ctx->channels;
441  }
442  }
443  if (IAMStreamConfig_SetFormat(config, type) != S_OK)
444  goto next;
445  format_set = 1;
446 next:
447  if (type->pbFormat)
448  CoTaskMemFree(type->pbFormat);
449  CoTaskMemFree(type);
450  }
451 end:
452  IAMStreamConfig_Release(config);
453  av_free(caps);
454  if (pformat_set)
455  *pformat_set = format_set;
456 }
457 
458 /**
459  * Set audio device buffer size in milliseconds (which can directly impact
460  * latency, depending on the device).
461  */
462 static int
464 {
465  struct dshow_ctx *ctx = avctx->priv_data;
466  IAMBufferNegotiation *buffer_negotiation = NULL;
467  ALLOCATOR_PROPERTIES props = { -1, -1, -1, -1 };
468  IAMStreamConfig *config = NULL;
469  AM_MEDIA_TYPE *type = NULL;
470  int ret = AVERROR(EIO);
471 
472  if (IPin_QueryInterface(pin, &IID_IAMStreamConfig, (void **) &config) != S_OK)
473  goto end;
474  if (IAMStreamConfig_GetFormat(config, &type) != S_OK)
475  goto end;
476  if (!IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx))
477  goto end;
478 
479  props.cbBuffer = (((WAVEFORMATEX *) type->pbFormat)->nAvgBytesPerSec)
480  * ctx->audio_buffer_size / 1000;
481 
482  if (IPin_QueryInterface(pin, &IID_IAMBufferNegotiation, (void **) &buffer_negotiation) != S_OK)
483  goto end;
484  if (IAMBufferNegotiation_SuggestAllocatorProperties(buffer_negotiation, &props) != S_OK)
485  goto end;
486 
487  ret = 0;
488 
489 end:
490  if (buffer_negotiation)
491  IAMBufferNegotiation_Release(buffer_negotiation);
492  if (type) {
493  if (type->pbFormat)
494  CoTaskMemFree(type->pbFormat);
495  CoTaskMemFree(type);
496  }
497  if (config)
498  IAMStreamConfig_Release(config);
499 
500  return ret;
501 }
502 
503 /**
504  * Pops up a user dialog allowing them to adjust properties for the given filter, if possible.
505  */
506 void
508  ISpecifyPropertyPages *property_pages = NULL;
509  IUnknown *device_filter_iunknown = NULL;
510  HRESULT hr;
511  FILTER_INFO filter_info = {0}; /* a warning on this line is false positive GCC bug 53119 AFAICT */
512  CAUUID ca_guid = {0};
513 
514  hr = IBaseFilter_QueryInterface(device_filter, &IID_ISpecifyPropertyPages, (void **)&property_pages);
515  if (hr != S_OK) {
516  av_log(avctx, AV_LOG_WARNING, "requested filter does not have a property page to show");
517  goto end;
518  }
519  hr = IBaseFilter_QueryFilterInfo(device_filter, &filter_info);
520  if (hr != S_OK) {
521  goto fail;
522  }
523  hr = IBaseFilter_QueryInterface(device_filter, &IID_IUnknown, (void **)&device_filter_iunknown);
524  if (hr != S_OK) {
525  goto fail;
526  }
527  hr = ISpecifyPropertyPages_GetPages(property_pages, &ca_guid);
528  if (hr != S_OK) {
529  goto fail;
530  }
531  hr = OleCreatePropertyFrame(NULL, 0, 0, filter_info.achName, 1, &device_filter_iunknown, ca_guid.cElems,
532  ca_guid.pElems, 0, 0, NULL);
533  if (hr != S_OK) {
534  goto fail;
535  }
536  goto end;
537 fail:
538  av_log(avctx, AV_LOG_ERROR, "Failure showing property pages for filter");
539 end:
540  if (property_pages)
541  ISpecifyPropertyPages_Release(property_pages);
542  if (device_filter_iunknown)
543  IUnknown_Release(device_filter_iunknown);
544  if (filter_info.pGraph)
545  IFilterGraph_Release(filter_info.pGraph);
546  if (ca_guid.pElems)
547  CoTaskMemFree(ca_guid.pElems);
548 }
549 
550 /**
551  * Cycle through available pins using the device_filter device, of type
552  * devtype, retrieve the first output pin and return the pointer to the
553  * object found in *ppin.
554  * If ppin is NULL, cycle through all pins listing audio/video capabilities.
555  */
556 static int
558  enum dshowSourceFilterType sourcetype, IBaseFilter *device_filter, IPin **ppin)
559 {
560  struct dshow_ctx *ctx = avctx->priv_data;
561  IEnumPins *pins = 0;
562  IPin *device_pin = NULL;
563  IPin *pin;
564  int r;
565 
566  const GUID *mediatype[2] = { &MEDIATYPE_Video, &MEDIATYPE_Audio };
567  const char *devtypename = (devtype == VideoDevice) ? "video" : "audio only";
568  const char *sourcetypename = (sourcetype == VideoSourceDevice) ? "video" : "audio";
569 
570  int set_format = (devtype == VideoDevice && (ctx->framerate ||
571  (ctx->requested_width && ctx->requested_height) ||
572  ctx->pixel_format != AV_PIX_FMT_NONE ||
574  || (devtype == AudioDevice && (ctx->channels || ctx->sample_rate));
575  int format_set = 0;
576  int should_show_properties = (devtype == VideoDevice) ? ctx->show_video_device_dialog : ctx->show_audio_device_dialog;
577 
578  if (should_show_properties)
579  dshow_show_filter_properties(device_filter, avctx);
580 
581  r = IBaseFilter_EnumPins(device_filter, &pins);
582  if (r != S_OK) {
583  av_log(avctx, AV_LOG_ERROR, "Could not enumerate pins.\n");
584  return AVERROR(EIO);
585  }
586 
587  if (!ppin) {
588  av_log(avctx, AV_LOG_INFO, "DirectShow %s device options (from %s devices)\n",
589  devtypename, sourcetypename);
590  }
591 
592  while (!device_pin && IEnumPins_Next(pins, 1, &pin, NULL) == S_OK) {
593  IKsPropertySet *p = NULL;
594  IEnumMediaTypes *types = NULL;
595  PIN_INFO info = {0};
596  AM_MEDIA_TYPE *type;
597  GUID category;
598  DWORD r2;
599  char *name_buf = NULL;
600  wchar_t *pin_id = NULL;
601  char *pin_buf = NULL;
602  char *desired_pin_name = devtype == VideoDevice ? ctx->video_pin_name : ctx->audio_pin_name;
603 
604  IPin_QueryPinInfo(pin, &info);
605  IBaseFilter_Release(info.pFilter);
606 
607  if (info.dir != PINDIR_OUTPUT)
608  goto next;
609  if (IPin_QueryInterface(pin, &IID_IKsPropertySet, (void **) &p) != S_OK)
610  goto next;
611  if (IKsPropertySet_Get(p, &AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY,
612  NULL, 0, &category, sizeof(GUID), &r2) != S_OK)
613  goto next;
614  if (!IsEqualGUID(&category, &PIN_CATEGORY_CAPTURE))
615  goto next;
616  name_buf = dup_wchar_to_utf8(info.achName);
617 
618  r = IPin_QueryId(pin, &pin_id);
619  if (r != S_OK) {
620  av_log(avctx, AV_LOG_ERROR, "Could not query pin id\n");
621  return AVERROR(EIO);
622  }
623  pin_buf = dup_wchar_to_utf8(pin_id);
624 
625  if (!ppin) {
626  av_log(avctx, AV_LOG_INFO, " Pin \"%s\" (alternative pin name \"%s\")\n", name_buf, pin_buf);
627  dshow_cycle_formats(avctx, devtype, pin, NULL);
628  goto next;
629  }
630 
631  if (desired_pin_name) {
632  if(strcmp(name_buf, desired_pin_name) && strcmp(pin_buf, desired_pin_name)) {
633  av_log(avctx, AV_LOG_DEBUG, "skipping pin \"%s\" (\"%s\") != requested \"%s\"\n",
634  name_buf, pin_buf, desired_pin_name);
635  goto next;
636  }
637  }
638 
639  if (set_format) {
640  dshow_cycle_formats(avctx, devtype, pin, &format_set);
641  if (!format_set) {
642  goto next;
643  }
644  }
645  if (devtype == AudioDevice && ctx->audio_buffer_size) {
646  if (dshow_set_audio_buffer_size(avctx, pin) < 0) {
647  av_log(avctx, AV_LOG_ERROR, "unable to set audio buffer size %d to pin, using pin anyway...", ctx->audio_buffer_size);
648  }
649  }
650 
651  if (IPin_EnumMediaTypes(pin, &types) != S_OK)
652  goto next;
653 
654  IEnumMediaTypes_Reset(types);
655  /* in case format_set was not called, just verify the majortype */
656  while (!device_pin && IEnumMediaTypes_Next(types, 1, &type, NULL) == S_OK) {
657  if (IsEqualGUID(&type->majortype, mediatype[devtype])) {
658  device_pin = pin;
659  av_log(avctx, AV_LOG_DEBUG, "Selecting pin %s on %s\n", name_buf, devtypename);
660  goto next;
661  }
662  CoTaskMemFree(type);
663  }
664 
665 next:
666  if (types)
667  IEnumMediaTypes_Release(types);
668  if (p)
669  IKsPropertySet_Release(p);
670  if (device_pin != pin)
671  IPin_Release(pin);
672  av_free(name_buf);
673  av_free(pin_buf);
674  if (pin_id)
675  CoTaskMemFree(pin_id);
676  }
677 
678  IEnumPins_Release(pins);
679 
680  if (ppin) {
681  if (set_format && !format_set) {
682  av_log(avctx, AV_LOG_ERROR, "Could not set %s options\n", devtypename);
683  return AVERROR(EIO);
684  }
685  if (!device_pin) {
686  av_log(avctx, AV_LOG_ERROR,
687  "Could not find output pin from %s capture device.\n", devtypename);
688  return AVERROR(EIO);
689  }
690  *ppin = device_pin;
691  }
692 
693  return 0;
694 }
695 
696 /**
697  * List options for device with type devtype, source filter type sourcetype
698  *
699  * @param devenum device enumerator used for accessing the device
700  */
701 static int
702 dshow_list_device_options(AVFormatContext *avctx, ICreateDevEnum *devenum,
703  enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype)
704 {
705  struct dshow_ctx *ctx = avctx->priv_data;
706  IBaseFilter *device_filter = NULL;
707  int r;
708 
709  if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter)) < 0)
710  return r;
711  ctx->device_filter[devtype] = device_filter;
712  if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, NULL)) < 0)
713  return r;
714 
715  return 0;
716 }
717 
718 static int
719 dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
720  enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype)
721 {
722  struct dshow_ctx *ctx = avctx->priv_data;
723  IBaseFilter *device_filter = NULL;
724  IGraphBuilder *graph = ctx->graph;
725  IPin *device_pin = NULL;
728  ICaptureGraphBuilder2 *graph_builder2 = NULL;
729  int ret = AVERROR(EIO);
730  int r;
731 
732  const wchar_t *filter_name[2] = { L"Audio capture filter", L"Video capture filter" };
733 
734  if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter)) < 0) {
735  ret = r;
736  goto error;
737  }
738 
739  ctx->device_filter [devtype] = device_filter;
740 
741  r = IGraphBuilder_AddFilter(graph, device_filter, NULL);
742  if (r != S_OK) {
743  av_log(avctx, AV_LOG_ERROR, "Could not add device filter to graph.\n");
744  goto error;
745  }
746 
747  if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, &device_pin)) < 0) {
748  ret = r;
749  goto error;
750  }
751 
752  ctx->device_pin[devtype] = device_pin;
753 
754  capture_filter = libAVFilter_Create(avctx, callback, devtype);
755  if (!capture_filter) {
756  av_log(avctx, AV_LOG_ERROR, "Could not create grabber filter.\n");
757  goto error;
758  }
759  ctx->capture_filter[devtype] = capture_filter;
760 
761  r = IGraphBuilder_AddFilter(graph, (IBaseFilter *) capture_filter,
762  filter_name[devtype]);
763  if (r != S_OK) {
764  av_log(avctx, AV_LOG_ERROR, "Could not add capture filter to graph\n");
765  goto error;
766  }
767 
768  libAVPin_AddRef(capture_filter->pin);
769  capture_pin = capture_filter->pin;
770  ctx->capture_pin[devtype] = capture_pin;
771 
772  r = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER,
773  &IID_ICaptureGraphBuilder2, (void **) &graph_builder2);
774  if (r != S_OK) {
775  av_log(avctx, AV_LOG_ERROR, "Could not create CaptureGraphBuilder2\n");
776  goto error;
777  }
778  ICaptureGraphBuilder2_SetFiltergraph(graph_builder2, graph);
779  if (r != S_OK) {
780  av_log(avctx, AV_LOG_ERROR, "Could not set graph for CaptureGraphBuilder2\n");
781  goto error;
782  }
783 
784  r = ICaptureGraphBuilder2_RenderStream(graph_builder2, NULL, NULL, (IUnknown *) device_pin, NULL /* no intermediate filter */,
785  (IBaseFilter *) capture_filter); /* connect pins, optionally insert intermediate filters like crossbar if necessary */
786 
787  if (r != S_OK) {
788  av_log(avctx, AV_LOG_ERROR, "Could not RenderStream to connect pins\n");
789  goto error;
790  }
791 
792  r = dshow_try_setup_crossbar_options(graph_builder2, device_filter, devtype, avctx);
793 
794  if (r != S_OK) {
795  av_log(avctx, AV_LOG_ERROR, "Could not setup CrossBar\n");
796  goto error;
797  }
798 
799  ret = 0;
800 
801 error:
802  if (graph_builder2 != NULL)
803  ICaptureGraphBuilder2_Release(graph_builder2);
804 
805  return ret;
806 }
807 
808 static enum AVCodecID waveform_codec_id(enum AVSampleFormat sample_fmt)
809 {
810  switch (sample_fmt) {
814  default: return AV_CODEC_ID_NONE; /* Should never happen. */
815  }
816 }
817 
819 {
820  switch (bits) {
821  case 8: return AV_SAMPLE_FMT_U8;
822  case 16: return AV_SAMPLE_FMT_S16;
823  case 32: return AV_SAMPLE_FMT_S32;
824  default: return AV_SAMPLE_FMT_NONE; /* Should never happen. */
825  }
826 }
827 
828 static int
830  enum dshowDeviceType devtype)
831 {
832  struct dshow_ctx *ctx = avctx->priv_data;
833  AM_MEDIA_TYPE type;
834  AVCodecContext *codec;
835  AVStream *st;
836  int ret = AVERROR(EIO);
837 
838  st = avformat_new_stream(avctx, NULL);
839  if (!st) {
840  ret = AVERROR(ENOMEM);
841  goto error;
842  }
843  st->id = devtype;
844 
845  ctx->capture_filter[devtype]->stream_index = st->index;
846 
847  libAVPin_ConnectionMediaType(ctx->capture_pin[devtype], &type);
848 
849  codec = st->codec;
850  if (devtype == VideoDevice) {
851  BITMAPINFOHEADER *bih = NULL;
852  AVRational time_base;
853 
854  if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo)) {
855  VIDEOINFOHEADER *v = (void *) type.pbFormat;
856  time_base = (AVRational) { v->AvgTimePerFrame, 10000000 };
857  bih = &v->bmiHeader;
858  } else if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo2)) {
859  VIDEOINFOHEADER2 *v = (void *) type.pbFormat;
860  time_base = (AVRational) { v->AvgTimePerFrame, 10000000 };
861  bih = &v->bmiHeader;
862  }
863  if (!bih) {
864  av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
865  goto error;
866  }
867 
868  codec->time_base = time_base;
870  codec->width = bih->biWidth;
871  codec->height = bih->biHeight;
872  codec->codec_tag = bih->biCompression;
873  codec->pix_fmt = dshow_pixfmt(bih->biCompression, bih->biBitCount);
874  if (bih->biCompression == MKTAG('H', 'D', 'Y', 'C')) {
875  av_log(avctx, AV_LOG_DEBUG, "attempt to use full range for HDYC...\n");
876  codec->color_range = AVCOL_RANGE_MPEG; // just in case it needs this...
877  }
878  if (codec->pix_fmt == AV_PIX_FMT_NONE) {
879  const AVCodecTag *const tags[] = { avformat_get_riff_video_tags(), NULL };
880  codec->codec_id = av_codec_get_id(tags, bih->biCompression);
881  if (codec->codec_id == AV_CODEC_ID_NONE) {
882  av_log(avctx, AV_LOG_ERROR, "Unknown compression type. "
883  "Please report type 0x%X.\n", (int) bih->biCompression);
884  return AVERROR_PATCHWELCOME;
885  }
886  codec->bits_per_coded_sample = bih->biBitCount;
887  } else {
889  if (bih->biCompression == BI_RGB || bih->biCompression == BI_BITFIELDS) {
890  codec->bits_per_coded_sample = bih->biBitCount;
892  if (codec->extradata) {
893  codec->extradata_size = 9;
894  memcpy(codec->extradata, "BottomUp", 9);
895  }
896  }
897  }
898  } else {
899  WAVEFORMATEX *fx = NULL;
900 
901  if (IsEqualGUID(&type.formattype, &FORMAT_WaveFormatEx)) {
902  fx = (void *) type.pbFormat;
903  }
904  if (!fx) {
905  av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
906  goto error;
907  }
908 
910  codec->sample_fmt = sample_fmt_bits_per_sample(fx->wBitsPerSample);
911  codec->codec_id = waveform_codec_id(codec->sample_fmt);
912  codec->sample_rate = fx->nSamplesPerSec;
913  codec->channels = fx->nChannels;
914  }
915 
916  avpriv_set_pts_info(st, 64, 1, 10000000);
917 
918  ret = 0;
919 
920 error:
921  return ret;
922 }
923 
925 {
926  struct dshow_ctx *ctx = avctx->priv_data;
927  char **device_name = ctx->device_name;
928  char *name = av_strdup(avctx->filename);
929  char *tmp = name;
930  int ret = 1;
931  char *type;
932 
933  while ((type = strtok(tmp, "="))) {
934  char *token = strtok(NULL, ":");
935  tmp = NULL;
936 
937  if (!strcmp(type, "video")) {
938  device_name[0] = token;
939  } else if (!strcmp(type, "audio")) {
940  device_name[1] = token;
941  } else {
942  device_name[0] = NULL;
943  device_name[1] = NULL;
944  break;
945  }
946  }
947 
948  if (!device_name[0] && !device_name[1]) {
949  ret = 0;
950  } else {
951  if (device_name[0])
952  device_name[0] = av_strdup(device_name[0]);
953  if (device_name[1])
954  device_name[1] = av_strdup(device_name[1]);
955  }
956 
957  av_free(name);
958  return ret;
959 }
960 
962 {
963  struct dshow_ctx *ctx = avctx->priv_data;
964  IGraphBuilder *graph = NULL;
965  ICreateDevEnum *devenum = NULL;
966  IMediaControl *control = NULL;
967  IMediaEvent *media_event = NULL;
968  HANDLE media_event_handle;
969  HANDLE proc;
970  int ret = AVERROR(EIO);
971  int r;
972 
973  CoInitialize(0);
974 
975  if (!ctx->list_devices && !parse_device_name(avctx)) {
976  av_log(avctx, AV_LOG_ERROR, "Malformed dshow input string.\n");
977  goto error;
978  }
979 
980  ctx->video_codec_id = avctx->video_codec_id ? avctx->video_codec_id
982  if (ctx->pixel_format != AV_PIX_FMT_NONE) {
983  if (ctx->video_codec_id != AV_CODEC_ID_RAWVIDEO) {
984  av_log(avctx, AV_LOG_ERROR, "Pixel format may only be set when "
985  "video codec is not set or set to rawvideo\n");
986  ret = AVERROR(EINVAL);
987  goto error;
988  }
989  }
990  if (ctx->framerate) {
992  if (r < 0) {
993  av_log(avctx, AV_LOG_ERROR, "Could not parse framerate '%s'.\n", ctx->framerate);
994  goto error;
995  }
996  }
997 
998  r = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
999  &IID_IGraphBuilder, (void **) &graph);
1000  if (r != S_OK) {
1001  av_log(avctx, AV_LOG_ERROR, "Could not create capture graph.\n");
1002  goto error;
1003  }
1004  ctx->graph = graph;
1005 
1006  r = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
1007  &IID_ICreateDevEnum, (void **) &devenum);
1008  if (r != S_OK) {
1009  av_log(avctx, AV_LOG_ERROR, "Could not enumerate system devices.\n");
1010  goto error;
1011  }
1012 
1013  if (ctx->list_devices) {
1014  av_log(avctx, AV_LOG_INFO, "DirectShow video devices (some may be both video and audio devices)\n");
1016  av_log(avctx, AV_LOG_INFO, "DirectShow audio devices\n");
1018  ret = AVERROR_EXIT;
1019  goto error;
1020  }
1021  if (ctx->list_options) {
1022  if (ctx->device_name[VideoDevice])
1023  if ((r = dshow_list_device_options(avctx, devenum, VideoDevice, VideoSourceDevice))) {
1024  ret = r;
1025  goto error;
1026  }
1027  if (ctx->device_name[AudioDevice]) {
1029  /* show audio options from combined video+audio sources as fallback */
1030  if ((r = dshow_list_device_options(avctx, devenum, AudioDevice, VideoSourceDevice))) {
1031  ret = r;
1032  goto error;
1033  }
1034  }
1035  }
1036  }
1037  if (ctx->device_name[VideoDevice]) {
1038  if ((r = dshow_open_device(avctx, devenum, VideoDevice, VideoSourceDevice)) < 0 ||
1039  (r = dshow_add_device(avctx, VideoDevice)) < 0) {
1040  ret = r;
1041  goto error;
1042  }
1043  }
1044  if (ctx->device_name[AudioDevice]) {
1045  if ((r = dshow_open_device(avctx, devenum, AudioDevice, AudioSourceDevice)) < 0 ||
1046  (r = dshow_add_device(avctx, AudioDevice)) < 0) {
1047  av_log(avctx, AV_LOG_INFO, "Searching for audio device within video devices for %s\n", ctx->device_name[AudioDevice]);
1048  /* see if there's a video source with an audio pin with the given audio name */
1049  if ((r = dshow_open_device(avctx, devenum, AudioDevice, VideoSourceDevice)) < 0 ||
1050  (r = dshow_add_device(avctx, AudioDevice)) < 0) {
1051  ret = r;
1052  goto error;
1053  }
1054  }
1055  }
1056  if (ctx->list_options) {
1057  /* allow it to list crossbar options in dshow_open_device */
1058  ret = AVERROR_EXIT;
1059  goto error;
1060  }
1061  ctx->curbufsize[0] = 0;
1062  ctx->curbufsize[1] = 0;
1063  ctx->mutex = CreateMutex(NULL, 0, NULL);
1064  if (!ctx->mutex) {
1065  av_log(avctx, AV_LOG_ERROR, "Could not create Mutex\n");
1066  goto error;
1067  }
1068  ctx->event[1] = CreateEvent(NULL, 1, 0, NULL);
1069  if (!ctx->event[1]) {
1070  av_log(avctx, AV_LOG_ERROR, "Could not create Event\n");
1071  goto error;
1072  }
1073 
1074  r = IGraphBuilder_QueryInterface(graph, &IID_IMediaControl, (void **) &control);
1075  if (r != S_OK) {
1076  av_log(avctx, AV_LOG_ERROR, "Could not get media control.\n");
1077  goto error;
1078  }
1079  ctx->control = control;
1080 
1081  r = IGraphBuilder_QueryInterface(graph, &IID_IMediaEvent, (void **) &media_event);
1082  if (r != S_OK) {
1083  av_log(avctx, AV_LOG_ERROR, "Could not get media event.\n");
1084  goto error;
1085  }
1086  ctx->media_event = media_event;
1087 
1088  r = IMediaEvent_GetEventHandle(media_event, (void *) &media_event_handle);
1089  if (r != S_OK) {
1090  av_log(avctx, AV_LOG_ERROR, "Could not get media event handle.\n");
1091  goto error;
1092  }
1093  proc = GetCurrentProcess();
1094  r = DuplicateHandle(proc, media_event_handle, proc, &ctx->event[0],
1095  0, 0, DUPLICATE_SAME_ACCESS);
1096  if (!r) {
1097  av_log(avctx, AV_LOG_ERROR, "Could not duplicate media event handle.\n");
1098  goto error;
1099  }
1100 
1101  r = IMediaControl_Run(control);
1102  if (r == S_FALSE) {
1103  OAFilterState pfs;
1104  r = IMediaControl_GetState(control, 0, &pfs);
1105  }
1106  if (r != S_OK) {
1107  av_log(avctx, AV_LOG_ERROR, "Could not run graph (sometimes caused by a device already in use by other application)\n");
1108  goto error;
1109  }
1110 
1111  ret = 0;
1112 
1113 error:
1114 
1115  if (devenum)
1116  ICreateDevEnum_Release(devenum);
1117 
1118  if (ret < 0)
1119  dshow_read_close(avctx);
1120 
1121  return ret;
1122 }
1123 
1124 /**
1125  * Checks media events from DirectShow and returns -1 on error or EOF. Also
1126  * purges all events that might be in the event queue to stop the trigger
1127  * of event notification.
1128  */
1129 static int dshow_check_event_queue(IMediaEvent *media_event)
1130 {
1131  LONG_PTR p1, p2;
1132  long code;
1133  int ret = 0;
1134 
1135  while (IMediaEvent_GetEvent(media_event, &code, &p1, &p2, 0) != E_ABORT) {
1136  if (code == EC_COMPLETE || code == EC_DEVICE_LOST || code == EC_ERRORABORT)
1137  ret = -1;
1138  IMediaEvent_FreeEventParams(media_event, code, p1, p2);
1139  }
1140 
1141  return ret;
1142 }
1143 
1145 {
1146  struct dshow_ctx *ctx = s->priv_data;
1147  AVPacketList *pktl = NULL;
1148 
1149  while (!ctx->eof && !pktl) {
1150  WaitForSingleObject(ctx->mutex, INFINITE);
1151  pktl = ctx->pktl;
1152  if (pktl) {
1153  *pkt = pktl->pkt;
1154  ctx->pktl = ctx->pktl->next;
1155  av_free(pktl);
1156  ctx->curbufsize[pkt->stream_index] -= pkt->size;
1157  }
1158  ResetEvent(ctx->event[1]);
1159  ReleaseMutex(ctx->mutex);
1160  if (!pktl) {
1161  if (dshow_check_event_queue(ctx->media_event) < 0) {
1162  ctx->eof = 1;
1163  } else if (s->flags & AVFMT_FLAG_NONBLOCK) {
1164  return AVERROR(EAGAIN);
1165  } else {
1166  WaitForMultipleObjects(2, ctx->event, 0, INFINITE);
1167  }
1168  }
1169  }
1170 
1171  return ctx->eof ? AVERROR(EIO) : pkt->size;
1172 }
1173 
1174 #define OFFSET(x) offsetof(struct dshow_ctx, x)
1175 #define DEC AV_OPT_FLAG_DECODING_PARAM
1176 static const AVOption options[] = {
1177  { "video_size", "set video size given a string such as 640x480 or hd720.", OFFSET(requested_width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
1178  { "pixel_format", "set video pixel format", OFFSET(pixel_format), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_NONE}, -1, INT_MAX, DEC },
1179  { "framerate", "set video frame rate", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
1180  { "sample_rate", "set audio sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
1181  { "sample_size", "set audio sample size", OFFSET(sample_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 16, DEC },
1182  { "channels", "set number of audio channels, such as 1 or 2", OFFSET(channels), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
1183  { "audio_buffer_size", "set audio device buffer latency size in milliseconds (default is the device's default)", OFFSET(audio_buffer_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
1184  { "list_devices", "list available devices", OFFSET(list_devices), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, DEC, "list_devices" },
1185  { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "list_devices" },
1186  { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "list_devices" },
1187  { "list_options", "list available options for specified device", OFFSET(list_options), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, DEC, "list_options" },
1188  { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "list_options" },
1189  { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "list_options" },
1190  { "video_device_number", "set video device number for devices with same name (starts at 0)", OFFSET(video_device_number), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
1191  { "audio_device_number", "set audio device number for devices with same name (starts at 0)", OFFSET(audio_device_number), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
1192  { "video_pin_name", "select video capture pin by name", OFFSET(video_pin_name),AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
1193  { "audio_pin_name", "select audio capture pin by name", OFFSET(audio_pin_name),AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
1194  { "crossbar_video_input_pin_number", "set video input pin number for crossbar device", OFFSET(crossbar_video_input_pin_number), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, DEC },
1195  { "crossbar_audio_input_pin_number", "set audio input pin number for crossbar device", OFFSET(crossbar_audio_input_pin_number), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, DEC },
1196  { "show_video_device_dialog", "display property dialog for video capture device", OFFSET(show_video_device_dialog), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC, "show_video_device_dialog" },
1197  { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "show_video_device_dialog" },
1198  { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "show_video_device_dialog" },
1199  { "show_audio_device_dialog", "display property dialog for audio capture device", OFFSET(show_audio_device_dialog), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC, "show_audio_device_dialog" },
1200  { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "show_audio_device_dialog" },
1201  { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "show_audio_device_dialog" },
1202  { "show_video_crossbar_connection_dialog", "display property dialog for crossbar connecting pins filter on video device", OFFSET(show_video_crossbar_connection_dialog), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC, "show_video_crossbar_connection_dialog" },
1203  { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "show_video_crossbar_connection_dialog" },
1204  { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "show_video_crossbar_connection_dialog" },
1205  { "show_audio_crossbar_connection_dialog", "display property dialog for crossbar connecting pins filter on audio device", OFFSET(show_audio_crossbar_connection_dialog), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC, "show_audio_crossbar_connection_dialog" },
1206  { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "show_audio_crossbar_connection_dialog" },
1207  { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "show_audio_crossbar_connection_dialog" },
1208  { "show_analog_tv_tuner_dialog", "display property dialog for analog tuner filter", OFFSET(show_analog_tv_tuner_dialog), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC, "show_analog_tv_tuner_dialog" },
1209  { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "show_analog_tv_tuner_dialog" },
1210  { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "show_analog_tv_tuner_dialog" },
1211  { "show_analog_tv_tuner_audio_dialog", "display property dialog for analog tuner audio filter", OFFSET(show_analog_tv_tuner_audio_dialog), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC, "show_analog_tv_tuner_dialog" },
1212  { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "show_analog_tv_tuner_audio_dialog" },
1213  { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "show_analog_tv_tuner_audio_dialog" },
1214  { NULL },
1215 };
1216 
1217 static const AVClass dshow_class = {
1218  .class_name = "dshow indev",
1219  .item_name = av_default_item_name,
1220  .option = options,
1221  .version = LIBAVUTIL_VERSION_INT,
1223 };
1224 
1226  .name = "dshow",
1227  .long_name = NULL_IF_CONFIG_SMALL("DirectShow capture"),
1228  .priv_data_size = sizeof(struct dshow_ctx),
1229  .read_header = dshow_read_header,
1230  .read_packet = dshow_read_packet,
1231  .read_close = dshow_read_close,
1232  .flags = AVFMT_NOFILE,
1233  .priv_class = &dshow_class,
1234 };