diff mbox series

[FFmpeg-devel,v3,34/34] avdevice/dshow: capabilities query also works on opened device

Message ID 20210706092020.1057-35-dcnieho@gmail.com
State New
Headers show
Series avdevice (mostly dshow) enhancements
Related show

Checks

Context Check Description
andriy/x86_make success Make finished
andriy/x86_make_fate success Make fate finished
andriy/PPC64_make success Make finished
andriy/PPC64_make_fate success Make fate finished

Commit Message

Diederick C. Niehorster July 6, 2021, 9:20 a.m. UTC
While the capabilities API is in principle meant to be used with an
allocated format context belonging to an unopened device, small changes
make it work for an opened dshow device as well. So hereby done.

Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
---
 libavdevice/dshow.c         | 110 +++++++++++++++++++++---------------
 libavdevice/dshow_capture.h |   3 +
 2 files changed, 66 insertions(+), 47 deletions(-)
diff mbox series

Patch

diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
index a66f7b81fd..5c1fadc23d 100644
--- a/libavdevice/dshow.c
+++ b/libavdevice/dshow.c
@@ -858,7 +858,7 @@  dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype,
     void *caps = NULL;
     int i, n, size, r;
     int wait_for_better = 0;
-    int use_default;
+    int use_default, already_opened;
 
     // format parameters requested by user
     // if none are requested by user, the values will below be set to
@@ -884,6 +884,9 @@  dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype,
     if (!caps)
         goto end;
 
+    // get if device is already opened
+    already_opened = ctx->device_name[0] || ctx->device_name[1];
+
     /** 
      * If we should open the device with the default format,
      * then:
@@ -1191,7 +1194,7 @@  dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype,
         // in ranges, try to apply in all cases, and store
         // caps if successfully applied
         if (!wait_for_better || ranges) {
-            if (IAMStreamConfig_SetFormat(config, type) != S_OK)
+            if (!already_opened && IAMStreamConfig_SetFormat(config, type) != S_OK) // skip if device already opened
                 goto next;
             else if (ranges) {
                 // format matched and could be set successfully.
@@ -1516,12 +1519,19 @@  dshow_list_device_options(AVFormatContext *avctx, ICreateDevEnum *devenum,
     char *device_unique_name = NULL;
     int r;
 
-    if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter, &device_unique_name, NULL)) < 0)
-        return r;
-    ctx->device_filter[devtype] = device_filter;
-    ctx->device_unique_name[devtype] = device_unique_name;
+    if (!ctx->device_filter[devtype]) {
+        if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter, &device_unique_name, NULL)) < 0)
+            return r;
+
+        // put them in context so they'll be cleaned up again
+        ctx->device_filter[devtype] = device_filter;
+        ctx->device_unique_name[devtype] = device_unique_name;
+    } else
+        device_filter = ctx->device_filter[devtype];
+
     if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, ranges ? &device_pin : NULL, ranges, query_type)) < 0)
         return r;
+
     return 0;
 }
 
@@ -2344,7 +2354,8 @@  fail1:
     return ret;
 }
 
-// fake class to point av_opt_query_ranges to our query_ranges function
+// fake class to point av_opt functions to capabilities that can be queried,
+// and av_opt_query_ranges to our query_ranges function
 static const AVClass dshow_dev_caps_class = {
     .class_name   = "",
     .item_name    = av_default_item_name,
@@ -2362,49 +2373,51 @@  static int dshow_create_device_capabilities(struct AVFormatContext *avctx, AVDev
     // set class so queries work
     caps->av_class = &dshow_dev_caps_class;
 
-    if (ctx->device_name[0] || ctx->device_name[1]) {
-        av_log(avctx, AV_LOG_ERROR, "You cannot query device capabilities on an opened device\n");
-        ret = AVERROR(EIO);
-        goto fail;
-    }
+    // check if device setup is needed or we will be querying capabilities of an already opened device
+    ctx->cap_query_already_opened = ctx->device_name[0] || ctx->device_name[1];
+    if (ctx->cap_query_already_opened)
+        av_log(avctx, AV_LOG_WARNING, "Querying device capabilities on an opened device: may yield false positives\n");
 
-    if (!parse_device_name(avctx)) {
-        av_log(avctx, AV_LOG_ERROR, "You must set a device name (AVFormatContext url) to specify which device to query capabilities from\n");
-        ret = AVERROR(EINVAL);
-        goto fail;
-    }
-
-    CoInitialize(0);
-    if (CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
-                         &IID_ICreateDevEnum, (void **) &devenum)) {
-        av_log(avctx, AV_LOG_ERROR, "Could not enumerate system devices.\n");
-        ret = AVERROR(EIO);
-        goto fail;
-    }
+    // if device not already opened, check that what user specified can be opened
+    if (!ctx->cap_query_already_opened) {
+        if (!parse_device_name(avctx)) {
+            av_log(avctx, AV_LOG_ERROR, "You must set a device name (AVFormatContext url) to specify which device to query capabilities from\n");
+            ret = AVERROR(EINVAL);
+            goto fail;
+        }
 
-    // check devices can be found
-    if (ctx->device_name[VideoDevice]) {
-        IBaseFilter *device_filter = NULL;
-        char *device_unique_name = NULL;
-        if ((ret = dshow_cycle_devices(avctx, devenum, VideoDevice, VideoSourceDevice, &device_filter, &device_unique_name, NULL)) < 0)
-            return ret;
-
-        if (ret >= 0) {
-            ctx->device_filter[VideoDevice] = device_filter;
-            ctx->device_unique_name[VideoDevice] = device_unique_name;
+        CoInitialize(0);
+        if (CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
+                             &IID_ICreateDevEnum, (void **) &devenum)) {
+            av_log(avctx, AV_LOG_ERROR, "Could not enumerate system devices.\n");
+            ret = AVERROR(EIO);
+            goto fail;
         }
-    }
-    if (ctx->device_name[AudioDevice]) {
-        IBaseFilter *device_filter = NULL;
-        char *device_unique_name = NULL;
-        if (dshow_cycle_devices(avctx, devenum, AudioDevice, AudioSourceDevice, &device_filter, &device_unique_name, NULL) < 0) {
-            /* try to access audio from combined video+audio sources as fallback */
-            if ((ret = dshow_cycle_devices(avctx, devenum, AudioDevice, VideoSourceDevice, &device_filter, &device_unique_name, NULL)) < 0)
-                goto fail;
+
+        // check devices can be found
+        if (ctx->device_name[VideoDevice]) {
+            IBaseFilter *device_filter = NULL;
+            char *device_unique_name = NULL;
+            if ((ret = dshow_cycle_devices(avctx, devenum, VideoDevice, VideoSourceDevice, &device_filter, &device_unique_name, NULL)) < 0)
+                return ret;
+
+            if (ret >= 0) {
+                ctx->device_filter[VideoDevice] = device_filter;
+                ctx->device_unique_name[VideoDevice] = device_unique_name;
+            }
         }
-        if (ret >= 0) {
-            ctx->device_filter[AudioDevice] = device_filter;
-            ctx->device_unique_name[AudioDevice] = device_unique_name;
+        if (ctx->device_name[AudioDevice]) {
+            IBaseFilter *device_filter = NULL;
+            char *device_unique_name = NULL;
+            if (dshow_cycle_devices(avctx, devenum, AudioDevice, AudioSourceDevice, &device_filter, &device_unique_name, NULL) < 0) {
+                /* try to access audio from combined video+audio sources as fallback */
+                if ((ret = dshow_cycle_devices(avctx, devenum, AudioDevice, VideoSourceDevice, &device_filter, &device_unique_name, NULL)) < 0)
+                    goto fail;
+            }
+            if (ret >= 0) {
+                ctx->device_filter[AudioDevice] = device_filter;
+                ctx->device_unique_name[AudioDevice] = device_unique_name;
+            }
         }
     }
 
@@ -2420,9 +2433,12 @@  fail:
 
 static int dshow_free_device_capabilities(struct AVFormatContext *avctx, AVDeviceCapabilitiesQuery *caps)
 {
+    struct dshow_ctx *ctx = avctx->priv_data;
+
     // clear state variables that may have been set during the querying process
     // (e.g. frees device names, removes device_filters, etc)
-    dshow_read_close(avctx);
+    if (!ctx->cap_query_already_opened)
+        dshow_read_close(avctx);
 
     return 0;
 }
diff --git a/libavdevice/dshow_capture.h b/libavdevice/dshow_capture.h
index 127695a86b..06ac4a6fd6 100644
--- a/libavdevice/dshow_capture.h
+++ b/libavdevice/dshow_capture.h
@@ -345,6 +345,9 @@  struct dshow_ctx {
     int sample_rate;
     int sample_size;
     int channels;
+
+    // for capabilities query
+    int cap_query_already_opened;
 };
 
 /*****************************************************************************