2 * Directshow capture interface
3 * Copyright (c) 2010 Ramiro Polla
5 * This file is part of FFmpeg.
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.
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.
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
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"
29 #include "libavcodec/raw.h"
34 static enum AVPixelFormat
dshow_pixfmt(DWORD biCompression
, WORD biBitCount
)
36 switch(biCompression
) {
39 switch(biBitCount
) { /* 1-8 are untested */
41 return AV_PIX_FMT_MONOWHITE
;
43 return AV_PIX_FMT_RGB4
;
45 return AV_PIX_FMT_RGB8
;
47 return AV_PIX_FMT_RGB555
;
49 return AV_PIX_FMT_BGR24
;
51 return AV_PIX_FMT_0RGB32
;
54 return avpriv_find_pix_fmt(avpriv_get_raw_pix_fmt_tags(), biCompression
); // all others
58 dshow_read_close(AVFormatContext
*s
)
60 struct dshow_ctx
*ctx
= s
->priv_data
;
64 IMediaControl_Stop(ctx
->control
);
65 IMediaControl_Release(ctx
->control
);
69 IMediaEvent_Release(ctx
->media_event
);
74 r
= IGraphBuilder_EnumFilters(ctx
->graph
, &fenum
);
77 IEnumFilters_Reset(fenum
);
78 while (IEnumFilters_Next(fenum
, 1, &f
, NULL
) == S_OK
) {
79 if (IGraphBuilder_RemoveFilter(ctx
->graph
, f
) == S_OK
)
80 IEnumFilters_Reset(fenum
); /* When a filter is removed,
81 * the list must be reset. */
82 IBaseFilter_Release(f
);
84 IEnumFilters_Release(fenum
);
86 IGraphBuilder_Release(ctx
->graph
);
89 if (ctx
->capture_pin
[VideoDevice
])
90 libAVPin_Release(ctx
->capture_pin
[VideoDevice
]);
91 if (ctx
->capture_pin
[AudioDevice
])
92 libAVPin_Release(ctx
->capture_pin
[AudioDevice
]);
93 if (ctx
->capture_filter
[VideoDevice
])
94 libAVFilter_Release(ctx
->capture_filter
[VideoDevice
]);
95 if (ctx
->capture_filter
[AudioDevice
])
96 libAVFilter_Release(ctx
->capture_filter
[AudioDevice
]);
98 if (ctx
->device_pin
[VideoDevice
])
99 IPin_Release(ctx
->device_pin
[VideoDevice
]);
100 if (ctx
->device_pin
[AudioDevice
])
101 IPin_Release(ctx
->device_pin
[AudioDevice
]);
102 if (ctx
->device_filter
[VideoDevice
])
103 IBaseFilter_Release(ctx
->device_filter
[VideoDevice
]);
104 if (ctx
->device_filter
[AudioDevice
])
105 IBaseFilter_Release(ctx
->device_filter
[AudioDevice
]);
107 av_freep(&ctx
->device_name
[0]);
108 av_freep(&ctx
->device_name
[1]);
109 av_freep(&ctx
->device_unique_name
[0]);
110 av_freep(&ctx
->device_unique_name
[1]);
113 CloseHandle(ctx
->mutex
);
115 CloseHandle(ctx
->event
[0]);
117 CloseHandle(ctx
->event
[1]);
121 AVPacketList
*next
= pktl
->next
;
122 av_packet_unref(&pktl
->pkt
);
132 static char *dup_wchar_to_utf8(wchar_t *w
)
135 int l
= WideCharToMultiByte(CP_UTF8
, 0, w
, -1, 0, 0, 0, 0);
138 WideCharToMultiByte(CP_UTF8
, 0, w
, -1, s
, l
, 0, 0);
142 static int shall_we_drop(AVFormatContext
*s
, int index
, enum dshowDeviceType devtype
)
144 struct dshow_ctx
*ctx
= s
->priv_data
;
145 static const uint8_t dropscore
[] = {62, 75, 87, 100};
146 const int ndropscores
= FF_ARRAY_ELEMS(dropscore
);
147 unsigned int buffer_fullness
= (ctx
->curbufsize
[index
]*100)/s
->max_picture_buffer
;
148 const char *devtypename
= (devtype
== VideoDevice
) ? "video" : "audio";
150 if(dropscore
[++ctx
->video_frame_num
%ndropscores
] <= buffer_fullness
) {
151 av_log(s
, AV_LOG_ERROR
,
152 "real-time buffer [%s] [%s input] too full or near too full (%d%% of size: %d [rtbufsize parameter])! frame dropped!\n",
153 ctx
->device_name
[devtype
], devtypename
, buffer_fullness
, s
->max_picture_buffer
);
161 callback(void *priv_data
, int index
, uint8_t *buf
, int buf_size
, int64_t time
, enum dshowDeviceType devtype
)
163 AVFormatContext
*s
= priv_data
;
164 struct dshow_ctx
*ctx
= s
->priv_data
;
165 AVPacketList
**ppktl
, *pktl_next
;
167 // dump_videohdr(s, vdhdr);
169 WaitForSingleObject(ctx
->mutex
, INFINITE
);
171 if(shall_we_drop(s
, index
, devtype
))
174 pktl_next
= av_mallocz(sizeof(AVPacketList
));
178 if(av_new_packet(&pktl_next
->pkt
, buf_size
) < 0) {
183 pktl_next
->pkt
.stream_index
= index
;
184 pktl_next
->pkt
.pts
= time
;
185 memcpy(pktl_next
->pkt
.data
, buf
, buf_size
);
187 for(ppktl
= &ctx
->pktl
; *ppktl
; ppktl
= &(*ppktl
)->next
);
189 ctx
->curbufsize
[index
] += buf_size
;
191 SetEvent(ctx
->event
[1]);
192 ReleaseMutex(ctx
->mutex
);
196 ReleaseMutex(ctx
->mutex
);
201 * Cycle through available devices using the device enumerator devenum,
202 * retrieve the device with type specified by devtype and return the
203 * pointer to the object found in *pfilter.
204 * If pfilter is NULL, list all device names.
207 dshow_cycle_devices(AVFormatContext
*avctx
, ICreateDevEnum
*devenum
,
208 enum dshowDeviceType devtype
, enum dshowSourceFilterType sourcetype
,
209 IBaseFilter
**pfilter
, char **device_unique_name
)
211 struct dshow_ctx
*ctx
= avctx
->priv_data
;
212 IBaseFilter
*device_filter
= NULL
;
213 IEnumMoniker
*classenum
= NULL
;
215 const char *device_name
= ctx
->device_name
[devtype
];
216 int skip
= (devtype
== VideoDevice
) ? ctx
->video_device_number
217 : ctx
->audio_device_number
;
220 const GUID
*device_guid
[2] = { &CLSID_VideoInputDeviceCategory
,
221 &CLSID_AudioInputDeviceCategory
};
222 const char *devtypename
= (devtype
== VideoDevice
) ? "video" : "audio only";
223 const char *sourcetypename
= (sourcetype
== VideoSourceDevice
) ? "video" : "audio";
225 r
= ICreateDevEnum_CreateClassEnumerator(devenum
, device_guid
[sourcetype
],
226 (IEnumMoniker
**) &classenum
, 0);
228 av_log(avctx
, AV_LOG_ERROR
, "Could not enumerate %s devices (or none found).\n",
233 while (!device_filter
&& IEnumMoniker_Next(classenum
, 1, &m
, NULL
) == S_OK
) {
234 IPropertyBag
*bag
= NULL
;
235 char *friendly_name
= NULL
;
236 char *unique_name
= NULL
;
238 IBindCtx
*bind_ctx
= NULL
;
239 LPOLESTR olestr
= NULL
;
240 LPMALLOC co_malloc
= NULL
;
243 r
= CoGetMalloc(1, &co_malloc
);
246 r
= CreateBindCtx(0, &bind_ctx
);
249 /* GetDisplayname works for both video and audio, DevicePath doesn't */
250 r
= IMoniker_GetDisplayName(m
, bind_ctx
, NULL
, &olestr
);
253 unique_name
= dup_wchar_to_utf8(olestr
);
254 /* replace ':' with '_' since we use : to delineate between sources */
255 for (i
= 0; i
< strlen(unique_name
); i
++) {
256 if (unique_name
[i
] == ':')
257 unique_name
[i
] = '_';
260 r
= IMoniker_BindToStorage(m
, 0, 0, &IID_IPropertyBag
, (void *) &bag
);
265 r
= IPropertyBag_Read(bag
, L
"FriendlyName", &var
, NULL
);
268 friendly_name
= dup_wchar_to_utf8(var
.bstrVal
);
271 if (strcmp(device_name
, friendly_name
) && strcmp(device_name
, unique_name
))
275 r
= IMoniker_BindToObject(m
, 0, 0, &IID_IBaseFilter
, (void *) &device_filter
);
277 av_log(avctx
, AV_LOG_ERROR
, "Unable to BindToObject for %s\n", device_name
);
280 *device_unique_name
= unique_name
;
282 // success, loop will end now
285 av_log(avctx
, AV_LOG_INFO
, " \"%s\"\n", friendly_name
);
286 av_log(avctx
, AV_LOG_INFO
, " Alternative name \"%s\"\n", unique_name
);
290 if (olestr
&& co_malloc
)
291 IMalloc_Free(co_malloc
, olestr
);
293 IBindCtx_Release(bind_ctx
);
294 av_freep(&friendly_name
);
295 av_freep(&unique_name
);
297 IPropertyBag_Release(bag
);
301 IEnumMoniker_Release(classenum
);
304 if (!device_filter
) {
305 av_log(avctx
, AV_LOG_ERROR
, "Could not find %s device with name [%s] among source devices of type %s.\n",
306 devtypename
, device_name
, sourcetypename
);
309 *pfilter
= device_filter
;
316 * Cycle through available formats using the specified pin,
317 * try to set parameters specified through AVOptions and if successful
318 * return 1 in *pformat_set.
319 * If pformat_set is NULL, list all pin capabilities.
322 dshow_cycle_formats(AVFormatContext
*avctx
, enum dshowDeviceType devtype
,
323 IPin
*pin
, int *pformat_set
)
325 struct dshow_ctx
*ctx
= avctx
->priv_data
;
326 IAMStreamConfig
*config
= NULL
;
327 AM_MEDIA_TYPE
*type
= NULL
;
332 if (IPin_QueryInterface(pin
, &IID_IAMStreamConfig
, (void **) &config
) != S_OK
)
334 if (IAMStreamConfig_GetNumberOfCapabilities(config
, &n
, &size
) != S_OK
)
337 caps
= av_malloc(size
);
341 for (i
= 0; i
< n
&& !format_set
; i
++) {
342 r
= IAMStreamConfig_GetStreamCaps(config
, i
, &type
, (void *) caps
);
346 ff_print_AM_MEDIA_TYPE(type
);
349 if (devtype
== VideoDevice
) {
350 VIDEO_STREAM_CONFIG_CAPS
*vcaps
= caps
;
351 BITMAPINFOHEADER
*bih
;
353 const AVCodecTag
*const tags
[] = { avformat_get_riff_video_tags(), NULL
};
355 ff_print_VIDEO_STREAM_CONFIG_CAPS(vcaps
);
357 if (IsEqualGUID(&type
->formattype
, &FORMAT_VideoInfo
)) {
358 VIDEOINFOHEADER
*v
= (void *) type
->pbFormat
;
359 fr
= &v
->AvgTimePerFrame
;
361 } else if (IsEqualGUID(&type
->formattype
, &FORMAT_VideoInfo2
)) {
362 VIDEOINFOHEADER2
*v
= (void *) type
->pbFormat
;
363 fr
= &v
->AvgTimePerFrame
;
369 enum AVPixelFormat pix_fmt
= dshow_pixfmt(bih
->biCompression
, bih
->biBitCount
);
370 if (pix_fmt
== AV_PIX_FMT_NONE
) {
371 enum AVCodecID codec_id
= av_codec_get_id(tags
, bih
->biCompression
);
372 AVCodec
*codec
= avcodec_find_decoder(codec_id
);
373 if (codec_id
== AV_CODEC_ID_NONE
|| !codec
) {
374 av_log(avctx
, AV_LOG_INFO
, " unknown compression type 0x%X", (int) bih
->biCompression
);
376 av_log(avctx
, AV_LOG_INFO
, " vcodec=%s", codec
->name
);
379 av_log(avctx
, AV_LOG_INFO
, " pixel_format=%s", av_get_pix_fmt_name(pix_fmt
));
381 av_log(avctx
, AV_LOG_INFO
, " min s=%ldx%ld fps=%g max s=%ldx%ld fps=%g\n",
382 vcaps
->MinOutputSize
.cx
, vcaps
->MinOutputSize
.cy
,
383 1e7
/ vcaps
->MaxFrameInterval
,
384 vcaps
->MaxOutputSize
.cx
, vcaps
->MaxOutputSize
.cy
,
385 1e7
/ vcaps
->MinFrameInterval
);
388 if (ctx
->video_codec_id
!= AV_CODEC_ID_RAWVIDEO
) {
389 if (ctx
->video_codec_id
!= av_codec_get_id(tags
, bih
->biCompression
))
392 if (ctx
->pixel_format
!= AV_PIX_FMT_NONE
&&
393 ctx
->pixel_format
!= dshow_pixfmt(bih
->biCompression
, bih
->biBitCount
)) {
396 if (ctx
->framerate
) {
397 int64_t framerate
= ((int64_t) ctx
->requested_framerate
.den
*10000000)
398 / ctx
->requested_framerate
.num
;
399 if (framerate
> vcaps
->MaxFrameInterval
||
400 framerate
< vcaps
->MinFrameInterval
)
404 if (ctx
->requested_width
&& ctx
->requested_height
) {
405 if (ctx
->requested_width
> vcaps
->MaxOutputSize
.cx
||
406 ctx
->requested_width
< vcaps
->MinOutputSize
.cx
||
407 ctx
->requested_height
> vcaps
->MaxOutputSize
.cy
||
408 ctx
->requested_height
< vcaps
->MinOutputSize
.cy
)
410 bih
->biWidth
= ctx
->requested_width
;
411 bih
->biHeight
= ctx
->requested_height
;
414 AUDIO_STREAM_CONFIG_CAPS
*acaps
= caps
;
417 ff_print_AUDIO_STREAM_CONFIG_CAPS(acaps
);
419 if (IsEqualGUID(&type
->formattype
, &FORMAT_WaveFormatEx
)) {
420 fx
= (void *) type
->pbFormat
;
425 av_log(avctx
, AV_LOG_INFO
, " min ch=%lu bits=%lu rate=%6lu max ch=%lu bits=%lu rate=%6lu\n",
426 acaps
->MinimumChannels
, acaps
->MinimumBitsPerSample
, acaps
->MinimumSampleFrequency
,
427 acaps
->MaximumChannels
, acaps
->MaximumBitsPerSample
, acaps
->MaximumSampleFrequency
);
430 if (ctx
->sample_rate
) {
431 if (ctx
->sample_rate
> acaps
->MaximumSampleFrequency
||
432 ctx
->sample_rate
< acaps
->MinimumSampleFrequency
)
434 fx
->nSamplesPerSec
= ctx
->sample_rate
;
436 if (ctx
->sample_size
) {
437 if (ctx
->sample_size
> acaps
->MaximumBitsPerSample
||
438 ctx
->sample_size
< acaps
->MinimumBitsPerSample
)
440 fx
->wBitsPerSample
= ctx
->sample_size
;
443 if (ctx
->channels
> acaps
->MaximumChannels
||
444 ctx
->channels
< acaps
->MinimumChannels
)
446 fx
->nChannels
= ctx
->channels
;
449 if (IAMStreamConfig_SetFormat(config
, type
) != S_OK
)
454 CoTaskMemFree(type
->pbFormat
);
458 IAMStreamConfig_Release(config
);
461 *pformat_set
= format_set
;
465 * Set audio device buffer size in milliseconds (which can directly impact
466 * latency, depending on the device).
469 dshow_set_audio_buffer_size(AVFormatContext
*avctx
, IPin
*pin
)
471 struct dshow_ctx
*ctx
= avctx
->priv_data
;
472 IAMBufferNegotiation
*buffer_negotiation
= NULL
;
473 ALLOCATOR_PROPERTIES props
= { -1, -1, -1, -1 };
474 IAMStreamConfig
*config
= NULL
;
475 AM_MEDIA_TYPE
*type
= NULL
;
476 int ret
= AVERROR(EIO
);
478 if (IPin_QueryInterface(pin
, &IID_IAMStreamConfig
, (void **) &config
) != S_OK
)
480 if (IAMStreamConfig_GetFormat(config
, &type
) != S_OK
)
482 if (!IsEqualGUID(&type
->formattype
, &FORMAT_WaveFormatEx
))
485 props
.cbBuffer
= (((WAVEFORMATEX
*) type
->pbFormat
)->nAvgBytesPerSec
)
486 * ctx
->audio_buffer_size
/ 1000;
488 if (IPin_QueryInterface(pin
, &IID_IAMBufferNegotiation
, (void **) &buffer_negotiation
) != S_OK
)
490 if (IAMBufferNegotiation_SuggestAllocatorProperties(buffer_negotiation
, &props
) != S_OK
)
496 if (buffer_negotiation
)
497 IAMBufferNegotiation_Release(buffer_negotiation
);
500 CoTaskMemFree(type
->pbFormat
);
504 IAMStreamConfig_Release(config
);
510 * Pops up a user dialog allowing them to adjust properties for the given filter, if possible.
513 dshow_show_filter_properties(IBaseFilter
*device_filter
, AVFormatContext
*avctx
) {
514 ISpecifyPropertyPages
*property_pages
= NULL
;
515 IUnknown
*device_filter_iunknown
= NULL
;
517 FILTER_INFO filter_info
= {0}; /* a warning on this line is false positive GCC bug 53119 AFAICT */
518 CAUUID ca_guid
= {0};
520 hr
= IBaseFilter_QueryInterface(device_filter
, &IID_ISpecifyPropertyPages
, (void **)&property_pages
);
522 av_log(avctx
, AV_LOG_WARNING
, "requested filter does not have a property page to show");
525 hr
= IBaseFilter_QueryFilterInfo(device_filter
, &filter_info
);
529 hr
= IBaseFilter_QueryInterface(device_filter
, &IID_IUnknown
, (void **)&device_filter_iunknown
);
533 hr
= ISpecifyPropertyPages_GetPages(property_pages
, &ca_guid
);
537 hr
= OleCreatePropertyFrame(NULL
, 0, 0, filter_info
.achName
, 1, &device_filter_iunknown
, ca_guid
.cElems
,
538 ca_guid
.pElems
, 0, 0, NULL
);
544 av_log(avctx
, AV_LOG_ERROR
, "Failure showing property pages for filter");
547 ISpecifyPropertyPages_Release(property_pages
);
548 if (device_filter_iunknown
)
549 IUnknown_Release(device_filter_iunknown
);
550 if (filter_info
.pGraph
)
551 IFilterGraph_Release(filter_info
.pGraph
);
553 CoTaskMemFree(ca_guid
.pElems
);
557 * Cycle through available pins using the device_filter device, of type
558 * devtype, retrieve the first output pin and return the pointer to the
559 * object found in *ppin.
560 * If ppin is NULL, cycle through all pins listing audio/video capabilities.
563 dshow_cycle_pins(AVFormatContext
*avctx
, enum dshowDeviceType devtype
,
564 enum dshowSourceFilterType sourcetype
, IBaseFilter
*device_filter
, IPin
**ppin
)
566 struct dshow_ctx
*ctx
= avctx
->priv_data
;
568 IPin
*device_pin
= NULL
;
572 const GUID
*mediatype
[2] = { &MEDIATYPE_Video
, &MEDIATYPE_Audio
};
573 const char *devtypename
= (devtype
== VideoDevice
) ? "video" : "audio only";
574 const char *sourcetypename
= (sourcetype
== VideoSourceDevice
) ? "video" : "audio";
576 int set_format
= (devtype
== VideoDevice
&& (ctx
->framerate
||
577 (ctx
->requested_width
&& ctx
->requested_height
) ||
578 ctx
->pixel_format
!= AV_PIX_FMT_NONE
||
579 ctx
->video_codec_id
!= AV_CODEC_ID_RAWVIDEO
))
580 || (devtype
== AudioDevice
&& (ctx
->channels
|| ctx
->sample_rate
));
582 int should_show_properties
= (devtype
== VideoDevice
) ? ctx
->show_video_device_dialog
: ctx
->show_audio_device_dialog
;
584 if (should_show_properties
)
585 dshow_show_filter_properties(device_filter
, avctx
);
587 r
= IBaseFilter_EnumPins(device_filter
, &pins
);
589 av_log(avctx
, AV_LOG_ERROR
, "Could not enumerate pins.\n");
594 av_log(avctx
, AV_LOG_INFO
, "DirectShow %s device options (from %s devices)\n",
595 devtypename
, sourcetypename
);
598 while (!device_pin
&& IEnumPins_Next(pins
, 1, &pin
, NULL
) == S_OK
) {
599 IKsPropertySet
*p
= NULL
;
600 IEnumMediaTypes
*types
= NULL
;
605 char *name_buf
= NULL
;
606 wchar_t *pin_id
= NULL
;
607 char *pin_buf
= NULL
;
608 char *desired_pin_name
= devtype
== VideoDevice
? ctx
->video_pin_name
: ctx
->audio_pin_name
;
610 IPin_QueryPinInfo(pin
, &info
);
611 IBaseFilter_Release(info
.pFilter
);
613 if (info
.dir
!= PINDIR_OUTPUT
)
615 if (IPin_QueryInterface(pin
, &IID_IKsPropertySet
, (void **) &p
) != S_OK
)
617 if (IKsPropertySet_Get(p
, &ROPSETID_Pin
, AMPROPERTY_PIN_CATEGORY
,
618 NULL
, 0, &category
, sizeof(GUID
), &r2
) != S_OK
)
620 if (!IsEqualGUID(&category
, &PIN_CATEGORY_CAPTURE
))
622 name_buf
= dup_wchar_to_utf8(info
.achName
);
624 r
= IPin_QueryId(pin
, &pin_id
);
626 av_log(avctx
, AV_LOG_ERROR
, "Could not query pin id\n");
629 pin_buf
= dup_wchar_to_utf8(pin_id
);
632 av_log(avctx
, AV_LOG_INFO
, " Pin \"%s\" (alternative pin name \"%s\")\n", name_buf
, pin_buf
);
633 dshow_cycle_formats(avctx
, devtype
, pin
, NULL
);
637 if (desired_pin_name
) {
638 if(strcmp(name_buf
, desired_pin_name
) && strcmp(pin_buf
, desired_pin_name
)) {
639 av_log(avctx
, AV_LOG_DEBUG
, "skipping pin \"%s\" (\"%s\") != requested \"%s\"\n",
640 name_buf
, pin_buf
, desired_pin_name
);
646 dshow_cycle_formats(avctx
, devtype
, pin
, &format_set
);
651 if (devtype
== AudioDevice
&& ctx
->audio_buffer_size
) {
652 if (dshow_set_audio_buffer_size(avctx
, pin
) < 0) {
653 av_log(avctx
, AV_LOG_ERROR
, "unable to set audio buffer size %d to pin, using pin anyway...", ctx
->audio_buffer_size
);
657 if (IPin_EnumMediaTypes(pin
, &types
) != S_OK
)
660 IEnumMediaTypes_Reset(types
);
661 /* in case format_set was not called, just verify the majortype */
662 while (!device_pin
&& IEnumMediaTypes_Next(types
, 1, &type
, NULL
) == S_OK
) {
663 if (IsEqualGUID(&type
->majortype
, mediatype
[devtype
])) {
665 av_log(avctx
, AV_LOG_DEBUG
, "Selecting pin %s on %s\n", name_buf
, devtypename
);
673 IEnumMediaTypes_Release(types
);
675 IKsPropertySet_Release(p
);
676 if (device_pin
!= pin
)
681 CoTaskMemFree(pin_id
);
684 IEnumPins_Release(pins
);
687 if (set_format
&& !format_set
) {
688 av_log(avctx
, AV_LOG_ERROR
, "Could not set %s options\n", devtypename
);
692 av_log(avctx
, AV_LOG_ERROR
,
693 "Could not find output pin from %s capture device.\n", devtypename
);
703 * List options for device with type devtype, source filter type sourcetype
705 * @param devenum device enumerator used for accessing the device
708 dshow_list_device_options(AVFormatContext
*avctx
, ICreateDevEnum
*devenum
,
709 enum dshowDeviceType devtype
, enum dshowSourceFilterType sourcetype
)
711 struct dshow_ctx
*ctx
= avctx
->priv_data
;
712 IBaseFilter
*device_filter
= NULL
;
713 char *device_unique_name
= NULL
;
716 if ((r
= dshow_cycle_devices(avctx
, devenum
, devtype
, sourcetype
, &device_filter
, &device_unique_name
)) < 0)
718 ctx
->device_filter
[devtype
] = device_filter
;
719 if ((r
= dshow_cycle_pins(avctx
, devtype
, sourcetype
, device_filter
, NULL
)) < 0)
721 av_freep(&device_unique_name
);
726 dshow_open_device(AVFormatContext
*avctx
, ICreateDevEnum
*devenum
,
727 enum dshowDeviceType devtype
, enum dshowSourceFilterType sourcetype
)
729 struct dshow_ctx
*ctx
= avctx
->priv_data
;
730 IBaseFilter
*device_filter
= NULL
;
731 char *device_filter_unique_name
= NULL
;
732 IGraphBuilder
*graph
= ctx
->graph
;
733 IPin
*device_pin
= NULL
;
734 libAVPin
*capture_pin
= NULL
;
735 libAVFilter
*capture_filter
= NULL
;
736 ICaptureGraphBuilder2
*graph_builder2
= NULL
;
737 int ret
= AVERROR(EIO
);
739 IStream
*ifile_stream
= NULL
;
740 IStream
*ofile_stream
= NULL
;
741 IPersistStream
*pers_stream
= NULL
;
742 enum dshowDeviceType otherDevType
= (devtype
== VideoDevice
) ? AudioDevice
: VideoDevice
;
744 const wchar_t *filter_name
[2] = { L
"Audio capture filter", L
"Video capture filter" };
747 if ( ((ctx
->audio_filter_load_file
) && (strlen(ctx
->audio_filter_load_file
)>0) && (sourcetype
== AudioSourceDevice
)) ||
748 ((ctx
->video_filter_load_file
) && (strlen(ctx
->video_filter_load_file
)>0) && (sourcetype
== VideoSourceDevice
)) ) {
750 char *filename
= NULL
;
752 if (sourcetype
== AudioSourceDevice
)
753 filename
= ctx
->audio_filter_load_file
;
755 filename
= ctx
->video_filter_load_file
;
757 hr
= SHCreateStreamOnFile ((LPCSTR
) filename
, STGM_READ
, &ifile_stream
);
759 av_log(avctx
, AV_LOG_ERROR
, "Could not open capture filter description file.\n");
763 hr
= OleLoadFromStream(ifile_stream
, &IID_IBaseFilter
, (void **) &device_filter
);
765 av_log(avctx
, AV_LOG_ERROR
, "Could not load capture filter from file.\n");
769 if (sourcetype
== AudioSourceDevice
)
770 av_log(avctx
, AV_LOG_INFO
, "Audio-");
772 av_log(avctx
, AV_LOG_INFO
, "Video-");
773 av_log(avctx
, AV_LOG_INFO
, "Capture filter loaded successfully from file \"%s\".\n", filename
);
776 if ((r
= dshow_cycle_devices(avctx
, devenum
, devtype
, sourcetype
, &device_filter
, &device_filter_unique_name
)) < 0) {
781 if (ctx
->device_filter
[otherDevType
]) {
782 // avoid adding add two instances of the same device to the graph, one for video, one for audio
783 // a few devices don't support this (could also do this check earlier to avoid double crossbars, etc. but they seem OK)
784 if (!device_filter_unique_name
|| strcmp(device_filter_unique_name
, ctx
->device_unique_name
[otherDevType
]) == 0) {
785 av_log(avctx
, AV_LOG_DEBUG
, "reusing previous graph capture filter... %s\n", device_filter_unique_name
);
786 IBaseFilter_Release(device_filter
);
787 device_filter
= ctx
->device_filter
[otherDevType
];
788 IBaseFilter_AddRef(ctx
->device_filter
[otherDevType
]);
790 av_log(avctx
, AV_LOG_DEBUG
, "not reusing previous graph capture filter %s != %s\n", device_filter_unique_name
, ctx
->device_unique_name
[otherDevType
]);
794 ctx
->device_filter
[devtype
] = device_filter
;
795 ctx
->device_unique_name
[devtype
] = device_filter_unique_name
;
797 r
= IGraphBuilder_AddFilter(graph
, device_filter
, NULL
);
799 av_log(avctx
, AV_LOG_ERROR
, "Could not add device filter to graph.\n");
803 if ((r
= dshow_cycle_pins(avctx
, devtype
, sourcetype
, device_filter
, &device_pin
)) < 0) {
808 ctx
->device_pin
[devtype
] = device_pin
;
810 capture_filter
= libAVFilter_Create(avctx
, callback
, devtype
);
811 if (!capture_filter
) {
812 av_log(avctx
, AV_LOG_ERROR
, "Could not create grabber filter.\n");
815 ctx
->capture_filter
[devtype
] = capture_filter
;
817 if ( ((ctx
->audio_filter_save_file
) && (strlen(ctx
->audio_filter_save_file
)>0) && (sourcetype
== AudioSourceDevice
)) ||
818 ((ctx
->video_filter_save_file
) && (strlen(ctx
->video_filter_save_file
)>0) && (sourcetype
== VideoSourceDevice
)) ) {
821 char *filename
= NULL
;
823 if (sourcetype
== AudioSourceDevice
)
824 filename
= ctx
->audio_filter_save_file
;
826 filename
= ctx
->video_filter_save_file
;
828 hr
= SHCreateStreamOnFile ((LPCSTR
) filename
, STGM_CREATE
| STGM_READWRITE
, &ofile_stream
);
830 av_log(avctx
, AV_LOG_ERROR
, "Could not create capture filter description file.\n");
834 hr
= IBaseFilter_QueryInterface(device_filter
, &IID_IPersistStream
, (void **) &pers_stream
);
836 av_log(avctx
, AV_LOG_ERROR
, "Query for IPersistStream failed.\n");
840 hr
= OleSaveToStream(pers_stream
, ofile_stream
);
842 av_log(avctx
, AV_LOG_ERROR
, "Could not save capture filter \n");
846 hr
= IStream_Commit(ofile_stream
, STGC_DEFAULT
);
848 av_log(avctx
, AV_LOG_ERROR
, "Could not commit capture filter data to file.\n");
852 if (sourcetype
== AudioSourceDevice
)
853 av_log(avctx
, AV_LOG_INFO
, "Audio-");
855 av_log(avctx
, AV_LOG_INFO
, "Video-");
856 av_log(avctx
, AV_LOG_INFO
, "Capture filter saved successfully to file \"%s\".\n", filename
);
859 r
= IGraphBuilder_AddFilter(graph
, (IBaseFilter
*) capture_filter
,
860 filter_name
[devtype
]);
862 av_log(avctx
, AV_LOG_ERROR
, "Could not add capture filter to graph\n");
866 libAVPin_AddRef(capture_filter
->pin
);
867 capture_pin
= capture_filter
->pin
;
868 ctx
->capture_pin
[devtype
] = capture_pin
;
870 r
= CoCreateInstance(&CLSID_CaptureGraphBuilder2
, NULL
, CLSCTX_INPROC_SERVER
,
871 &IID_ICaptureGraphBuilder2
, (void **) &graph_builder2
);
873 av_log(avctx
, AV_LOG_ERROR
, "Could not create CaptureGraphBuilder2\n");
876 r
= ICaptureGraphBuilder2_SetFiltergraph(graph_builder2
, graph
);
878 av_log(avctx
, AV_LOG_ERROR
, "Could not set graph for CaptureGraphBuilder2\n");
882 r
= ICaptureGraphBuilder2_RenderStream(graph_builder2
, NULL
, NULL
, (IUnknown
*) device_pin
, NULL
/* no intermediate filter */,
883 (IBaseFilter
*) capture_filter
); /* connect pins, optionally insert intermediate filters like crossbar if necessary */
886 av_log(avctx
, AV_LOG_ERROR
, "Could not RenderStream to connect pins\n");
890 r
= dshow_try_setup_crossbar_options(graph_builder2
, device_filter
, devtype
, avctx
);
893 av_log(avctx
, AV_LOG_ERROR
, "Could not setup CrossBar\n");
900 if (graph_builder2
!= NULL
)
901 ICaptureGraphBuilder2_Release(graph_builder2
);
904 IPersistStream_Release(pers_stream
);
907 IStream_Release(ifile_stream
);
910 IStream_Release(ofile_stream
);
915 static enum AVCodecID
waveform_codec_id(enum AVSampleFormat sample_fmt
)
917 switch (sample_fmt
) {
918 case AV_SAMPLE_FMT_U8
: return AV_CODEC_ID_PCM_U8
;
919 case AV_SAMPLE_FMT_S16
: return AV_CODEC_ID_PCM_S16LE
;
920 case AV_SAMPLE_FMT_S32
: return AV_CODEC_ID_PCM_S32LE
;
921 default: return AV_CODEC_ID_NONE
; /* Should never happen. */
925 static enum AVSampleFormat
sample_fmt_bits_per_sample(int bits
)
928 case 8: return AV_SAMPLE_FMT_U8
;
929 case 16: return AV_SAMPLE_FMT_S16
;
930 case 32: return AV_SAMPLE_FMT_S32
;
931 default: return AV_SAMPLE_FMT_NONE
; /* Should never happen. */
936 dshow_add_device(AVFormatContext
*avctx
,
937 enum dshowDeviceType devtype
)
939 struct dshow_ctx
*ctx
= avctx
->priv_data
;
941 AVCodecParameters
*par
;
943 int ret
= AVERROR(EIO
);
945 type
.pbFormat
= NULL
;
947 st
= avformat_new_stream(avctx
, NULL
);
949 ret
= AVERROR(ENOMEM
);
954 ctx
->capture_filter
[devtype
]->stream_index
= st
->index
;
956 libAVPin_ConnectionMediaType(ctx
->capture_pin
[devtype
], &type
);
959 if (devtype
== VideoDevice
) {
960 BITMAPINFOHEADER
*bih
= NULL
;
961 AVRational time_base
;
963 if (IsEqualGUID(&type
.formattype
, &FORMAT_VideoInfo
)) {
964 VIDEOINFOHEADER
*v
= (void *) type
.pbFormat
;
965 time_base
= (AVRational
) { v
->AvgTimePerFrame
, 10000000 };
967 } else if (IsEqualGUID(&type
.formattype
, &FORMAT_VideoInfo2
)) {
968 VIDEOINFOHEADER2
*v
= (void *) type
.pbFormat
;
969 time_base
= (AVRational
) { v
->AvgTimePerFrame
, 10000000 };
973 av_log(avctx
, AV_LOG_ERROR
, "Could not get media type.\n");
977 st
->avg_frame_rate
= av_inv_q(time_base
);
978 st
->r_frame_rate
= av_inv_q(time_base
);
980 par
->codec_type
= AVMEDIA_TYPE_VIDEO
;
981 par
->width
= bih
->biWidth
;
982 par
->height
= bih
->biHeight
;
983 par
->codec_tag
= bih
->biCompression
;
984 par
->format
= dshow_pixfmt(bih
->biCompression
, bih
->biBitCount
);
985 if (bih
->biCompression
== MKTAG('H', 'D', 'Y', 'C')) {
986 av_log(avctx
, AV_LOG_DEBUG
, "attempt to use full range for HDYC...\n");
987 par
->color_range
= AVCOL_RANGE_MPEG
; // just in case it needs this...
989 if (par
->format
== AV_PIX_FMT_NONE
) {
990 const AVCodecTag
*const tags
[] = { avformat_get_riff_video_tags(), NULL
};
991 par
->codec_id
= av_codec_get_id(tags
, bih
->biCompression
);
992 if (par
->codec_id
== AV_CODEC_ID_NONE
) {
993 av_log(avctx
, AV_LOG_ERROR
, "Unknown compression type. "
994 "Please report type 0x%X.\n", (int) bih
->biCompression
);
995 ret
= AVERROR_PATCHWELCOME
;
998 par
->bits_per_coded_sample
= bih
->biBitCount
;
1000 par
->codec_id
= AV_CODEC_ID_RAWVIDEO
;
1001 if (bih
->biCompression
== BI_RGB
|| bih
->biCompression
== BI_BITFIELDS
) {
1002 par
->bits_per_coded_sample
= bih
->biBitCount
;
1003 if (par
->height
< 0) {
1006 par
->extradata
= av_malloc(9 + AV_INPUT_BUFFER_PADDING_SIZE
);
1007 if (par
->extradata
) {
1008 par
->extradata_size
= 9;
1009 memcpy(par
->extradata
, "BottomUp", 9);
1015 WAVEFORMATEX
*fx
= NULL
;
1017 if (IsEqualGUID(&type
.formattype
, &FORMAT_WaveFormatEx
)) {
1018 fx
= (void *) type
.pbFormat
;
1021 av_log(avctx
, AV_LOG_ERROR
, "Could not get media type.\n");
1025 par
->codec_type
= AVMEDIA_TYPE_AUDIO
;
1026 par
->format
= sample_fmt_bits_per_sample(fx
->wBitsPerSample
);
1027 par
->codec_id
= waveform_codec_id(par
->format
);
1028 par
->sample_rate
= fx
->nSamplesPerSec
;
1029 par
->channels
= fx
->nChannels
;
1032 avpriv_set_pts_info(st
, 64, 1, 10000000);
1038 CoTaskMemFree(type
.pbFormat
);
1042 static int parse_device_name(AVFormatContext
*avctx
)
1044 struct dshow_ctx
*ctx
= avctx
->priv_data
;
1045 char **device_name
= ctx
->device_name
;
1046 char *name
= av_strdup(avctx
->url
);
1051 while ((type
= strtok(tmp
, "="))) {
1052 char *token
= strtok(NULL
, ":");
1055 if (!strcmp(type
, "video")) {
1056 device_name
[0] = token
;
1057 } else if (!strcmp(type
, "audio")) {
1058 device_name
[1] = token
;
1060 device_name
[0] = NULL
;
1061 device_name
[1] = NULL
;
1066 if (!device_name
[0] && !device_name
[1]) {
1070 device_name
[0] = av_strdup(device_name
[0]);
1072 device_name
[1] = av_strdup(device_name
[1]);
1079 static int dshow_read_header(AVFormatContext
*avctx
)
1081 struct dshow_ctx
*ctx
= avctx
->priv_data
;
1082 IGraphBuilder
*graph
= NULL
;
1083 ICreateDevEnum
*devenum
= NULL
;
1084 IMediaControl
*control
= NULL
;
1085 IMediaEvent
*media_event
= NULL
;
1086 HANDLE media_event_handle
;
1088 int ret
= AVERROR(EIO
);
1093 if (!ctx
->list_devices
&& !parse_device_name(avctx
)) {
1094 av_log(avctx
, AV_LOG_ERROR
, "Malformed dshow input string.\n");
1098 ctx
->video_codec_id
= avctx
->video_codec_id
? avctx
->video_codec_id
1099 : AV_CODEC_ID_RAWVIDEO
;
1100 if (ctx
->pixel_format
!= AV_PIX_FMT_NONE
) {
1101 if (ctx
->video_codec_id
!= AV_CODEC_ID_RAWVIDEO
) {
1102 av_log(avctx
, AV_LOG_ERROR
, "Pixel format may only be set when "
1103 "video codec is not set or set to rawvideo\n");
1104 ret
= AVERROR(EINVAL
);
1108 if (ctx
->framerate
) {
1109 r
= av_parse_video_rate(&ctx
->requested_framerate
, ctx
->framerate
);
1111 av_log(avctx
, AV_LOG_ERROR
, "Could not parse framerate '%s'.\n", ctx
->framerate
);
1116 r
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
,
1117 &IID_IGraphBuilder
, (void **) &graph
);
1119 av_log(avctx
, AV_LOG_ERROR
, "Could not create capture graph.\n");
1124 r
= CoCreateInstance(&CLSID_SystemDeviceEnum
, NULL
, CLSCTX_INPROC_SERVER
,
1125 &IID_ICreateDevEnum
, (void **) &devenum
);
1127 av_log(avctx
, AV_LOG_ERROR
, "Could not enumerate system devices.\n");
1131 if (ctx
->list_devices
) {
1132 av_log(avctx
, AV_LOG_INFO
, "DirectShow video devices (some may be both video and audio devices)\n");
1133 dshow_cycle_devices(avctx
, devenum
, VideoDevice
, VideoSourceDevice
, NULL
, NULL
);
1134 av_log(avctx
, AV_LOG_INFO
, "DirectShow audio devices\n");
1135 dshow_cycle_devices(avctx
, devenum
, AudioDevice
, AudioSourceDevice
, NULL
, NULL
);
1139 if (ctx
->list_options
) {
1140 if (ctx
->device_name
[VideoDevice
])
1141 if ((r
= dshow_list_device_options(avctx
, devenum
, VideoDevice
, VideoSourceDevice
))) {
1145 if (ctx
->device_name
[AudioDevice
]) {
1146 if (dshow_list_device_options(avctx
, devenum
, AudioDevice
, AudioSourceDevice
)) {
1147 /* show audio options from combined video+audio sources as fallback */
1148 if ((r
= dshow_list_device_options(avctx
, devenum
, AudioDevice
, VideoSourceDevice
))) {
1155 if (ctx
->device_name
[VideoDevice
]) {
1156 if ((r
= dshow_open_device(avctx
, devenum
, VideoDevice
, VideoSourceDevice
)) < 0 ||
1157 (r
= dshow_add_device(avctx
, VideoDevice
)) < 0) {
1162 if (ctx
->device_name
[AudioDevice
]) {
1163 if ((r
= dshow_open_device(avctx
, devenum
, AudioDevice
, AudioSourceDevice
)) < 0 ||
1164 (r
= dshow_add_device(avctx
, AudioDevice
)) < 0) {
1165 av_log(avctx
, AV_LOG_INFO
, "Searching for audio device within video devices for %s\n", ctx
->device_name
[AudioDevice
]);
1166 /* see if there's a video source with an audio pin with the given audio name */
1167 if ((r
= dshow_open_device(avctx
, devenum
, AudioDevice
, VideoSourceDevice
)) < 0 ||
1168 (r
= dshow_add_device(avctx
, AudioDevice
)) < 0) {
1174 if (ctx
->list_options
) {
1175 /* allow it to list crossbar options in dshow_open_device */
1179 ctx
->curbufsize
[0] = 0;
1180 ctx
->curbufsize
[1] = 0;
1181 ctx
->mutex
= CreateMutex(NULL
, 0, NULL
);
1183 av_log(avctx
, AV_LOG_ERROR
, "Could not create Mutex\n");
1186 ctx
->event
[1] = CreateEvent(NULL
, 1, 0, NULL
);
1187 if (!ctx
->event
[1]) {
1188 av_log(avctx
, AV_LOG_ERROR
, "Could not create Event\n");
1192 r
= IGraphBuilder_QueryInterface(graph
, &IID_IMediaControl
, (void **) &control
);
1194 av_log(avctx
, AV_LOG_ERROR
, "Could not get media control.\n");
1197 ctx
->control
= control
;
1199 r
= IGraphBuilder_QueryInterface(graph
, &IID_IMediaEvent
, (void **) &media_event
);
1201 av_log(avctx
, AV_LOG_ERROR
, "Could not get media event.\n");
1204 ctx
->media_event
= media_event
;
1206 r
= IMediaEvent_GetEventHandle(media_event
, (void *) &media_event_handle
);
1208 av_log(avctx
, AV_LOG_ERROR
, "Could not get media event handle.\n");
1211 proc
= GetCurrentProcess();
1212 r
= DuplicateHandle(proc
, media_event_handle
, proc
, &ctx
->event
[0],
1213 0, 0, DUPLICATE_SAME_ACCESS
);
1215 av_log(avctx
, AV_LOG_ERROR
, "Could not duplicate media event handle.\n");
1219 r
= IMediaControl_Run(control
);
1222 r
= IMediaControl_GetState(control
, 0, &pfs
);
1225 av_log(avctx
, AV_LOG_ERROR
, "Could not run graph (sometimes caused by a device already in use by other application)\n");
1234 ICreateDevEnum_Release(devenum
);
1237 dshow_read_close(avctx
);
1243 * Checks media events from DirectShow and returns -1 on error or EOF. Also
1244 * purges all events that might be in the event queue to stop the trigger
1245 * of event notification.
1247 static int dshow_check_event_queue(IMediaEvent
*media_event
)
1253 while (IMediaEvent_GetEvent(media_event
, &code
, &p1
, &p2
, 0) != E_ABORT
) {
1254 if (code
== EC_COMPLETE
|| code
== EC_DEVICE_LOST
|| code
== EC_ERRORABORT
)
1256 IMediaEvent_FreeEventParams(media_event
, code
, p1
, p2
);
1262 static int dshow_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
1264 struct dshow_ctx
*ctx
= s
->priv_data
;
1265 AVPacketList
*pktl
= NULL
;
1267 while (!ctx
->eof
&& !pktl
) {
1268 WaitForSingleObject(ctx
->mutex
, INFINITE
);
1272 ctx
->pktl
= ctx
->pktl
->next
;
1274 ctx
->curbufsize
[pkt
->stream_index
] -= pkt
->size
;
1276 ResetEvent(ctx
->event
[1]);
1277 ReleaseMutex(ctx
->mutex
);
1279 if (dshow_check_event_queue(ctx
->media_event
) < 0) {
1281 } else if (s
->flags
& AVFMT_FLAG_NONBLOCK
) {
1282 return AVERROR(EAGAIN
);
1284 WaitForMultipleObjects(2, ctx
->event
, 0, INFINITE
);
1289 return ctx
->eof
? AVERROR(EIO
) : pkt
->size
;
1292 #define OFFSET(x) offsetof(struct dshow_ctx, x)
1293 #define DEC AV_OPT_FLAG_DECODING_PARAM
1294 static const AVOption options
[] = {
1295 { "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
},
1296 { "pixel_format", "set video pixel format", OFFSET(pixel_format
), AV_OPT_TYPE_PIXEL_FMT
, {.i64
= AV_PIX_FMT_NONE
}, -1, INT_MAX
, DEC
},
1297 { "framerate", "set video frame rate", OFFSET(framerate
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, DEC
},
1298 { "sample_rate", "set audio sample rate", OFFSET(sample_rate
), AV_OPT_TYPE_INT
, {.i64
= 0}, 0, INT_MAX
, DEC
},
1299 { "sample_size", "set audio sample size", OFFSET(sample_size
), AV_OPT_TYPE_INT
, {.i64
= 0}, 0, 16, DEC
},
1300 { "channels", "set number of audio channels, such as 1 or 2", OFFSET(channels
), AV_OPT_TYPE_INT
, {.i64
= 0}, 0, INT_MAX
, DEC
},
1301 { "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
},
1302 { "list_devices", "list available devices", OFFSET(list_devices
), AV_OPT_TYPE_BOOL
, {.i64
=0}, 0, 1, DEC
},
1303 { "list_options", "list available options for specified device", OFFSET(list_options
), AV_OPT_TYPE_BOOL
, {.i64
=0}, 0, 1, DEC
},
1304 { "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
},
1305 { "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
},
1306 { "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
},
1307 { "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
},
1308 { "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
},
1309 { "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
},
1310 { "show_video_device_dialog", "display property dialog for video capture device", OFFSET(show_video_device_dialog
), AV_OPT_TYPE_BOOL
, {.i64
= 0}, 0, 1, DEC
},
1311 { "show_audio_device_dialog", "display property dialog for audio capture device", OFFSET(show_audio_device_dialog
), AV_OPT_TYPE_BOOL
, {.i64
= 0}, 0, 1, DEC
},
1312 { "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_BOOL
, {.i64
= 0}, 0, 1, DEC
},
1313 { "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_BOOL
, {.i64
= 0}, 0, 1, DEC
},
1314 { "show_analog_tv_tuner_dialog", "display property dialog for analog tuner filter", OFFSET(show_analog_tv_tuner_dialog
), AV_OPT_TYPE_BOOL
, {.i64
= 0}, 0, 1, DEC
},
1315 { "show_analog_tv_tuner_audio_dialog", "display property dialog for analog tuner audio filter", OFFSET(show_analog_tv_tuner_audio_dialog
), AV_OPT_TYPE_BOOL
, {.i64
= 0}, 0, 1, DEC
},
1316 { "audio_device_load", "load audio capture filter device (and properties) from file", OFFSET(audio_filter_load_file
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, DEC
},
1317 { "audio_device_save", "save audio capture filter device (and properties) to file", OFFSET(audio_filter_save_file
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, DEC
},
1318 { "video_device_load", "load video capture filter device (and properties) from file", OFFSET(video_filter_load_file
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, DEC
},
1319 { "video_device_save", "save video capture filter device (and properties) to file", OFFSET(video_filter_save_file
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, DEC
},
1323 static const AVClass dshow_class
= {
1324 .class_name
= "dshow indev",
1325 .item_name
= av_default_item_name
,
1327 .version
= LIBAVUTIL_VERSION_INT
,
1328 .category
= AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT
,
1331 AVInputFormat ff_dshow_demuxer
= {
1333 .long_name
= NULL_IF_CONFIG_SMALL("DirectShow capture"),
1334 .priv_data_size
= sizeof(struct dshow_ctx
),
1335 .read_header
= dshow_read_header
,
1336 .read_packet
= dshow_read_packet
,
1337 .read_close
= dshow_read_close
,
1338 .flags
= AVFMT_NOFILE
,
1339 .priv_class
= &dshow_class
,