From a35da0920d787d96569171a7c2dff5893144232f Mon Sep 17 00:00:00 2001 From: rogerdpack Date: Fri, 23 Jan 2015 06:54:44 -0700 Subject: [PATCH] dshow: some devices only list themselves under "Video sources" but actually have both video and audio output pins, so make the audio pins accessible by video source name. Signed-off-by: rogerdpack --- libavdevice/dshow.c | 81 ++++++++++++++++++++----------------- libavdevice/dshow_capture.h | 5 +++ 2 files changed, 50 insertions(+), 36 deletions(-) diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c index 691250f3ac..e34b77c084 100644 --- a/libavdevice/dshow.c +++ b/libavdevice/dshow.c @@ -203,7 +203,7 @@ fail: */ static int dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum, - enum dshowDeviceType devtype, IBaseFilter **pfilter) + enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype, IBaseFilter **pfilter) { struct dshow_ctx *ctx = avctx->priv_data; IBaseFilter *device_filter = NULL; @@ -216,12 +216,13 @@ dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum, const GUID *device_guid[2] = { &CLSID_VideoInputDeviceCategory, &CLSID_AudioInputDeviceCategory }; - const char *devtypename = (devtype == VideoDevice) ? "video" : "audio"; + const char *devtypename = (devtype == VideoDevice) ? "video" : "audio only"; + const char *sourcetypename = (sourcetype == VideoSourceDevice) ? "video" : "audio"; - r = ICreateDevEnum_CreateClassEnumerator(devenum, device_guid[devtype], + r = ICreateDevEnum_CreateClassEnumerator(devenum, device_guid[sourcetype], (IEnumMoniker **) &classenum, 0); if (r != S_OK) { - av_log(avctx, AV_LOG_ERROR, "Could not enumerate %s devices.\n", + av_log(avctx, AV_LOG_ERROR, "Could not enumerate %s devices (or none found).\n", devtypename); return AVERROR(EIO); } @@ -253,7 +254,6 @@ dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum, unique_name[i] = '_'; } - r = IMoniker_BindToStorage(m, 0, 0, &IID_IPropertyBag, (void *) &bag); if (r != S_OK) goto fail1; @@ -262,10 +262,9 @@ dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum, r = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL); if (r != S_OK) goto fail1; - friendly_name = dup_wchar_to_utf8(var.bstrVal); - if (pfilter) { + if (pfilter) { if (strcmp(device_name, friendly_name) && strcmp(device_name, unique_name)) goto fail1; @@ -291,15 +290,14 @@ fail1: if (bag) IPropertyBag_Release(bag); IMoniker_Release(m); - } IEnumMoniker_Release(classenum); if (pfilter) { if (!device_filter) { - av_log(avctx, AV_LOG_ERROR, "Could not find %s device.\n", - devtypename); + av_log(avctx, AV_LOG_ERROR, "Could not find %s device with name [%s] among source devices of type %s.\n", + devtypename, device_name, sourcetypename); return AVERROR(EIO); } *pfilter = device_filter; @@ -510,7 +508,7 @@ dshow_show_filter_properties(IBaseFilter *device_filter, AVFormatContext *avctx) ISpecifyPropertyPages *property_pages = NULL; IUnknown *device_filter_iunknown = NULL; HRESULT hr; - FILTER_INFO filter_info = {0}; /* a warning on this line is false positive GCC bug 53119 */ + FILTER_INFO filter_info = {0}; /* a warning on this line is false positive GCC bug 53119 AFAICT */ CAUUID ca_guid = {0}; hr = IBaseFilter_QueryInterface(device_filter, &IID_ISpecifyPropertyPages, (void **)&property_pages); @@ -557,7 +555,7 @@ end: */ static int dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype, - IBaseFilter *device_filter, IPin **ppin) + enum dshowSourceFilterType sourcetype, IBaseFilter *device_filter, IPin **ppin) { struct dshow_ctx *ctx = avctx->priv_data; IEnumPins *pins = 0; @@ -566,7 +564,8 @@ dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype, int r; const GUID *mediatype[2] = { &MEDIATYPE_Video, &MEDIATYPE_Audio }; - const char *devtypename = (devtype == VideoDevice) ? "video" : "audio"; + const char *devtypename = (devtype == VideoDevice) ? "video" : "audio only"; + const char *sourcetypename = (sourcetype == VideoSourceDevice) ? "video" : "audio"; int set_format = (devtype == VideoDevice && (ctx->framerate || (ctx->requested_width && ctx->requested_height) || @@ -586,9 +585,10 @@ dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype, } if (!ppin) { - av_log(avctx, AV_LOG_INFO, "DirectShow %s device options\n", - devtypename); + av_log(avctx, AV_LOG_INFO, "DirectShow %s device options (from %s devices)\n", + devtypename, sourcetypename); } + while (!device_pin && IEnumPins_Next(pins, 1, &pin, NULL) == S_OK) { IKsPropertySet *p = NULL; IEnumMediaTypes *types = NULL; @@ -622,12 +622,12 @@ dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype, } pin_buf = dup_wchar_to_utf8(pin_id); - if (!ppin) { av_log(avctx, AV_LOG_INFO, " Pin \"%s\" (alternative pin name \"%s\")\n", name_buf, pin_buf); dshow_cycle_formats(avctx, devtype, pin, NULL); goto next; } + if (desired_pin_name) { if(strcmp(name_buf, desired_pin_name) && strcmp(pin_buf, desired_pin_name)) { av_log(avctx, AV_LOG_DEBUG, "skipping pin \"%s\" (\"%s\") != requested \"%s\"\n", @@ -694,29 +694,30 @@ next: } /** - * List options for device with type devtype. + * List options for device with type devtype, source filter type sourcetype * * @param devenum device enumerator used for accessing the device */ static int dshow_list_device_options(AVFormatContext *avctx, ICreateDevEnum *devenum, - enum dshowDeviceType devtype) + enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype) { struct dshow_ctx *ctx = avctx->priv_data; IBaseFilter *device_filter = NULL; int r; - if ((r = dshow_cycle_devices(avctx, devenum, devtype, &device_filter)) < 0) + if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter)) < 0) return r; ctx->device_filter[devtype] = device_filter; - if ((r = dshow_cycle_pins(avctx, devtype, device_filter, NULL)) < 0) + if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, NULL)) < 0) return r; return 0; } static int -dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum, enum dshowDeviceType devtype) +dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum, + enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype) { struct dshow_ctx *ctx = avctx->priv_data; IBaseFilter *device_filter = NULL; @@ -730,7 +731,7 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum, enum dshowDev const wchar_t *filter_name[2] = { L"Audio capture filter", L"Video capture filter" }; - if ((r = dshow_cycle_devices(avctx, devenum, devtype, &device_filter)) < 0) { + if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter)) < 0) { ret = r; goto error; } @@ -743,7 +744,7 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum, enum dshowDev goto error; } - if ((r = dshow_cycle_pins(avctx, devtype, device_filter, &device_pin)) < 0) { + if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, &device_pin)) < 0) { ret = r; goto error; } @@ -1010,38 +1011,46 @@ static int dshow_read_header(AVFormatContext *avctx) } if (ctx->list_devices) { - av_log(avctx, AV_LOG_INFO, "DirectShow video devices\n"); - dshow_cycle_devices(avctx, devenum, VideoDevice, NULL); + av_log(avctx, AV_LOG_INFO, "DirectShow video devices (some may be both video and audio devices)\n"); + dshow_cycle_devices(avctx, devenum, VideoDevice, VideoSourceDevice, NULL); av_log(avctx, AV_LOG_INFO, "DirectShow audio devices\n"); - dshow_cycle_devices(avctx, devenum, AudioDevice, NULL); + dshow_cycle_devices(avctx, devenum, AudioDevice, AudioSourceDevice, NULL); ret = AVERROR_EXIT; goto error; } if (ctx->list_options) { if (ctx->device_name[VideoDevice]) - if ((r = dshow_list_device_options(avctx, devenum, VideoDevice))) { + if ((r = dshow_list_device_options(avctx, devenum, VideoDevice, VideoSourceDevice))) { ret = r; goto error; } - if (ctx->device_name[AudioDevice]) - if ((r = dshow_list_device_options(avctx, devenum, AudioDevice))) { - ret = r; - goto error; + if (ctx->device_name[AudioDevice]) { + if (dshow_list_device_options(avctx, devenum, AudioDevice, AudioSourceDevice)) { + /* show audio options from combined video+audio sources as fallback */ + if ((r = dshow_list_device_options(avctx, devenum, AudioDevice, VideoSourceDevice))) { + ret = r; + goto error; + } } + } } - if (ctx->device_name[VideoDevice]) { - if ((r = dshow_open_device(avctx, devenum, VideoDevice)) < 0 || + if ((r = dshow_open_device(avctx, devenum, VideoDevice, VideoSourceDevice)) < 0 || (r = dshow_add_device(avctx, VideoDevice)) < 0) { ret = r; goto error; } } if (ctx->device_name[AudioDevice]) { - if ((r = dshow_open_device(avctx, devenum, AudioDevice)) < 0 || + if ((r = dshow_open_device(avctx, devenum, AudioDevice, AudioSourceDevice)) < 0 || (r = dshow_add_device(avctx, AudioDevice)) < 0) { - ret = r; - goto error; + av_log(avctx, AV_LOG_INFO, "Searching for audio device within video devices %s\n", ctx->device_name[AudioDevice]); + /* see if there's a video source with an audio pin with the given audio name */ + if ((r = dshow_open_device(avctx, devenum, AudioDevice, VideoSourceDevice)) < 0 || + (r = dshow_add_device(avctx, AudioDevice)) < 0) { + ret = r; + goto error; + } } } if (ctx->list_options) { diff --git a/libavdevice/dshow_capture.h b/libavdevice/dshow_capture.h index c4f46812fb..2e64776563 100644 --- a/libavdevice/dshow_capture.h +++ b/libavdevice/dshow_capture.h @@ -65,6 +65,11 @@ enum dshowDeviceType { AudioDevice = 1, }; +enum dshowSourceFilterType { + VideoSourceDevice = 0, + AudioSourceDevice = 1, +}; + #define DECLARE_QUERYINTERFACE(class, ...) \ long WINAPI \ class##_QueryInterface(class *this, const GUID *riid, void **ppvObject) \