dshow: some devices only list themselves under "Video sources" but
authorrogerdpack <rogerpack2005@gmail.com>
Fri, 23 Jan 2015 13:54:44 +0000 (06:54 -0700)
committerrogerdpack <rogerpack2005@gmail.com>
Fri, 23 Jan 2015 13:54:48 +0000 (06:54 -0700)
actually have both video and audio output pins, so make the audio pins
accessible by video source name.

Signed-off-by: rogerdpack <rogerpack2005@gmail.com>
libavdevice/dshow.c
libavdevice/dshow_capture.h

index 691250f..e34b77c 100644 (file)
@@ -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) {
index c4f4681..2e64776 100644 (file)
@@ -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)      \