Add support for enumerating the sources/sinks via the ffmpeg
command line options, as opposed to having to create a real pipeline
and use the "-list_devices" option which does exit() after dumping
out the options.

Note that this patch preserves the existing "-list_devices" option,
but now shares common code for the actual enumeration.

Updated to reflect feedback from Marton Balink <c...@passwd.hu>.

Signed-off-by: Devin Heitmueller <dheitmuel...@ltnglobal.com>
---
 libavdevice/decklink_common.cpp | 89 ++++++++++++++++++++++++++++++++++++++---
 libavdevice/decklink_common.h   |  3 +-
 libavdevice/decklink_dec.cpp    |  8 +++-
 libavdevice/decklink_dec.h      |  1 +
 libavdevice/decklink_dec_c.c    |  1 +
 libavdevice/decklink_enc.cpp    | 10 ++++-
 libavdevice/decklink_enc.h      |  1 +
 libavdevice/decklink_enc_c.c    |  1 +
 8 files changed, 104 insertions(+), 10 deletions(-)

diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.cpp
index c782171f2c..61d8ad86a9 100644
--- a/libavdevice/decklink_common.cpp
+++ b/libavdevice/decklink_common.cpp
@@ -37,6 +37,7 @@ extern "C" {
 #include "libavutil/imgutils.h"
 #include "libavutil/intreadwrite.h"
 #include "libavutil/bswap.h"
+#include "avdevice.h"
 }
 
 #include "decklink_common.h"
@@ -261,24 +262,100 @@ int ff_decklink_set_format(AVFormatContext *avctx, 
decklink_direction_t directio
     return ff_decklink_set_format(avctx, 0, 0, 0, 0, AV_FIELD_UNKNOWN, 
direction, num);
 }
 
-int ff_decklink_list_devices(AVFormatContext *avctx)
+int ff_decklink_list_devices(AVFormatContext *avctx,
+                            struct AVDeviceInfoList *device_list,
+                            int show_inputs, int show_outputs)
 {
     IDeckLink *dl = NULL;
     IDeckLinkIterator *iter = CreateDeckLinkIteratorInstance();
+    int ret = 0;
+
     if (!iter) {
         av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n");
         return AVERROR(EIO);
     }
-    av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink devices:\n");
-    while (iter->Next(&dl) == S_OK) {
+
+    while (ret == 0 && iter->Next(&dl) == S_OK) {
+        IDeckLinkOutput *output_config;
+        IDeckLinkInput *input_config;
         const char *displayName;
+        AVDeviceInfo *new_device = NULL;
+        int add = 0;
+
         ff_decklink_get_display_name(dl, &displayName);
-        av_log(avctx, AV_LOG_INFO, "\t'%s'\n", displayName);
-        av_free((void *) displayName);
+
+        if (show_outputs) {
+            if (dl->QueryInterface(IID_IDeckLinkOutput, (void 
**)&output_config) == S_OK) {
+                output_config->Release();
+                add = 1;
+            }
+        }
+
+        if (show_inputs) {
+            if (dl->QueryInterface(IID_IDeckLinkInput, (void **)&input_config) 
== S_OK) {
+                input_config->Release();
+                add = 1;
+            }
+        }
+
+        if (add == 1) {
+            new_device = (AVDeviceInfo *) av_mallocz(sizeof(AVDeviceInfo));
+            if (!new_device) {
+                ret = AVERROR(ENOMEM);
+                goto next;
+            }
+            new_device->device_name = av_strdup(displayName);
+            if (!new_device->device_name) {
+                ret = AVERROR(ENOMEM);
+                goto next;
+            }
+
+            new_device->device_description = av_strdup(displayName);
+            if (!new_device->device_description) {
+                av_freep(&new_device->device_name);
+                ret = AVERROR(ENOMEM);
+                goto next;
+            }
+
+            if ((ret = av_dynarray_add_nofree(&device_list->devices,
+                                              &device_list->nb_devices, 
new_device)) < 0) {
+                av_freep(&new_device->device_name);
+                av_freep(&new_device->device_description);
+                av_freep(&new_device);
+                goto next;
+            }
+        }
+
+    next:
+        av_freep(&displayName);
         dl->Release();
     }
     iter->Release();
-    return 0;
+    return ret;
+}
+
+/* This is a wrapper around the ff_decklink_list_devices() which dumps the
+   output to av_log() and exits (for backward compatibility with the
+   "-list_devices" argument). */
+void ff_decklink_list_devices_legacy(AVFormatContext *avctx,
+                                     int show_inputs, int show_outputs)
+{
+    struct AVDeviceInfoList *device_list = NULL;
+    int ret;
+
+    device_list = (struct AVDeviceInfoList *) 
av_mallocz(sizeof(AVDeviceInfoList));
+    if (!device_list)
+        return;
+
+    ret = ff_decklink_list_devices(avctx, device_list, show_inputs, 
show_outputs);
+    if (ret == 0) {
+        av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink %s devices:\n",
+               show_inputs ? "input" : "output");
+        for (int i = 0; i < device_list->nb_devices; i++) {
+            av_log(avctx, AV_LOG_INFO, "\t'%s'\n", 
device_list->devices[i]->device_name);
+        }
+    }
+    avdevice_free_list_devices(&device_list);
 }
 
 int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t 
direction)
diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h
index 749eb0f8b8..6b2525fb53 100644
--- a/libavdevice/decklink_common.h
+++ b/libavdevice/decklink_common.h
@@ -135,7 +135,8 @@ static const BMDVideoConnection 
decklink_video_connection_map[] = {
 HRESULT ff_decklink_get_display_name(IDeckLink *This, const char 
**displayName);
 int ff_decklink_set_format(AVFormatContext *avctx, int width, int height, int 
tb_num, int tb_den, enum AVFieldOrder field_order, decklink_direction_t 
direction = DIRECTION_OUT, int num = 0);
 int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t 
direction, int num);
-int ff_decklink_list_devices(AVFormatContext *avctx);
+int ff_decklink_list_devices(AVFormatContext *avctx, struct AVDeviceInfoList 
*device_list, int show_inputs, int show_outputs);
+void ff_decklink_list_devices_legacy(AVFormatContext *avctx, int show_inputs, 
int show_outputs);
 int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t 
direction = DIRECTION_OUT);
 void ff_decklink_cleanup(AVFormatContext *avctx);
 int ff_decklink_init_device(AVFormatContext *avctx, const char* name);
diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
index f496a58059..419259e467 100644
--- a/libavdevice/decklink_dec.cpp
+++ b/libavdevice/decklink_dec.cpp
@@ -39,6 +39,7 @@ extern "C" {
 #include "libavutil/time.h"
 #include "libavutil/mathematics.h"
 #include "libavutil/reverse.h"
+#include "avdevice.h"
 #if CONFIG_LIBZVBI
 #include <libzvbi.h>
 #endif
@@ -868,7 +869,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx)
 
     /* List available devices. */
     if (ctx->list_devices) {
-        ff_decklink_list_devices(avctx);
+        ff_decklink_list_devices_legacy(avctx, 1, 0);
         return AVERROR_EXIT;
     }
 
@@ -1063,4 +1064,9 @@ int ff_decklink_read_packet(AVFormatContext *avctx, 
AVPacket *pkt)
     return 0;
 }
 
+int ff_decklink_list_input_devices(AVFormatContext *avctx, struct 
AVDeviceInfoList *device_list)
+{
+    return ff_decklink_list_devices(avctx, device_list, 1, 0);
+}
+
 } /* extern "C" */
diff --git a/libavdevice/decklink_dec.h b/libavdevice/decklink_dec.h
index 9b71870deb..fbfbe6280e 100644
--- a/libavdevice/decklink_dec.h
+++ b/libavdevice/decklink_dec.h
@@ -29,6 +29,7 @@ extern "C" {
 int ff_decklink_read_header(AVFormatContext *avctx);
 int ff_decklink_read_packet(AVFormatContext *avctx, AVPacket *pkt);
 int ff_decklink_read_close(AVFormatContext *avctx);
+int ff_decklink_list_input_devices(AVFormatContext *avctx, struct 
AVDeviceInfoList *device_list);
 
 #ifdef __cplusplus
 } /* extern "C" */
diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c
index 8b6ff067bc..1127d23ada 100644
--- a/libavdevice/decklink_dec_c.c
+++ b/libavdevice/decklink_dec_c.c
@@ -89,6 +89,7 @@ AVInputFormat ff_decklink_demuxer = {
     .flags          = AVFMT_NOFILE,
     .priv_class     = &decklink_demuxer_class,
     .priv_data_size = sizeof(struct decklink_cctx),
+    .get_device_list = ff_decklink_list_input_devices,
     .read_header   = ff_decklink_read_header,
     .read_packet   = ff_decklink_read_packet,
     .read_close    = ff_decklink_read_close,
diff --git a/libavdevice/decklink_enc.cpp b/libavdevice/decklink_enc.cpp
index 25ce7d026c..0776741812 100644
--- a/libavdevice/decklink_enc.cpp
+++ b/libavdevice/decklink_enc.cpp
@@ -33,6 +33,7 @@ extern "C" {
 extern "C" {
 #include "libavformat/avformat.h"
 #include "libavutil/imgutils.h"
+#include "avdevice.h"
 }
 
 #include "decklink_common.h"
@@ -335,9 +336,9 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx)
     ctx->preroll      = cctx->preroll;
     cctx->ctx = ctx;
 
-    /* List available devices. */
+    /* List available devices and exit. */
     if (ctx->list_devices) {
-        ff_decklink_list_devices(avctx);
+        ff_decklink_list_devices_legacy(avctx, 0, 1);
         return AVERROR_EXIT;
     }
 
@@ -400,4 +401,9 @@ int ff_decklink_write_packet(AVFormatContext *avctx, 
AVPacket *pkt)
     return AVERROR(EIO);
 }
 
+int ff_decklink_list_output_devices(AVFormatContext *avctx, struct 
AVDeviceInfoList *device_list)
+{
+    return ff_decklink_list_devices(avctx, device_list, 0, 1);
+}
+
 } /* extern "C" */
diff --git a/libavdevice/decklink_enc.h b/libavdevice/decklink_enc.h
index 5ffc05cd68..39237673b4 100644
--- a/libavdevice/decklink_enc.h
+++ b/libavdevice/decklink_enc.h
@@ -29,6 +29,7 @@ extern "C" {
 int ff_decklink_write_header(AVFormatContext *avctx);
 int ff_decklink_write_packet(AVFormatContext *avctx, AVPacket *pkt);
 int ff_decklink_write_trailer(AVFormatContext *avctx);
+int ff_decklink_list_output_devices(AVFormatContext *avctx, struct 
AVDeviceInfoList *device_list);
 
 #ifdef __cplusplus
 } /* extern "C" */
diff --git a/libavdevice/decklink_enc_c.c b/libavdevice/decklink_enc_c.c
index 03734f8507..360535cfda 100644
--- a/libavdevice/decklink_enc_c.c
+++ b/libavdevice/decklink_enc_c.c
@@ -49,6 +49,7 @@ AVOutputFormat ff_decklink_muxer = {
     .video_codec    = AV_CODEC_ID_WRAPPED_AVFRAME,
     .subtitle_codec = AV_CODEC_ID_NONE,
     .flags          = AVFMT_NOFILE,
+    .get_device_list = ff_decklink_list_output_devices,
     .priv_class     = &decklink_muxer_class,
     .priv_data_size = sizeof(struct decklink_cctx),
     .write_header   = ff_decklink_write_header,
-- 
2.13.2

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to