[FFmpeg-devel] [PATCH] Add get_device_list() to AVFoundation input device.

Daniel Ly nalply at gmail.com
Tue Apr 28 16:49:58 CEST 2015


This makes avdevice_list_input_sources() available for
device_name = "avfoundation". avf_read_header is retrofitted
to use the new method.

Signed-off-by: Daniel Ly <nalply at gmail.com>
---
 libavdevice/avfoundation.m | 139 +++++++++++++++++++++++++++++++++------------
 1 file changed, 104 insertions(+), 35 deletions(-)

diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m
index 763e675..a827248 100644
--- a/libavdevice/avfoundation.m
+++ b/libavdevice/avfoundation.m
@@ -34,6 +34,7 @@
 #include "libavformat/internal.h"
 #include "libavutil/internal.h"
 #include "libavutil/parseutils.h"
+#include "libavutil/avstring.h"
 #include "libavutil/time.h"
 #include "avdevice.h"
 
@@ -659,6 +660,98 @@ static int get_audio_config(AVFormatContext *s)
     return 0;
 }
 
+static int avf_add_device_info(AVDeviceInfoList *list, AVFormatContext *s,
+    int index, const char *description, const char *model, int do_log)
+{
+    if (do_log) av_log(s->priv_data, AV_LOG_INFO, "[%d] %s\n", index, description);
+    if (!list) return 0;
+
+    AVDeviceInfo *info = av_mallocz(sizeof(AVDeviceInfo));
+    if (!info) return AVERROR(ENOMEM);
+
+    info->device_name = av_asprintf("[%d] %s: %s", index, description, model);
+    info->device_description = strdup(description);
+    if (!info->device_name || !info->device_description) {
+        av_free(info);
+        return AVERROR(ENOMEM);
+    }
+
+    av_dynarray_add(&list->devices, &list->nb_devices, info);
+    return list ? list->nb_devices : AVERROR(ENOMEM);
+}
+
+/**
+ * List AVFoundation video and audio devices into AVDeviceInfoList.
+ *
+ * @param s      format context.
+ * @param list   device list or NULL (to log only).
+ * @param do_log log the devices if true.
+ */
+static int avf_get_device_list2(struct AVFormatContext *s, struct AVDeviceInfoList *list, int do_log) 
+{
+    int result = 0, index;
+    const char *localizedName, *modelID;
+
+    if (do_log) av_log(s->priv_data, AV_LOG_INFO, "AVFoundation video devices:\n");
+    NSArray *video_devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
+    for (AVCaptureDevice *device in video_devices) {
+        @autoreleasepool {
+            index         = [video_devices indexOfObject:device];
+            localizedName = [[device localizedName] UTF8String];
+            modelID       = [[device modelID] UTF8String];
+
+            result = avf_add_device_info(list, s, index, localizedName, modelID, do_log);
+            if (result < 0) break;
+        }
+    }
+    [video_devices release];
+
+
+#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+    uint32_t num_screens = 0;
+    CGGetActiveDisplayList(0, NULL, &num_screens);
+
+    if (num_screens > 0) {
+        CGDirectDisplayID screens[num_screens];
+        CGGetActiveDisplayList(num_screens, screens, &num_screens);
+        int i;
+        for (i = 0; i < num_screens; i++) {
+            char buf[30];
+            snprintf(buf, 30, "Capture screen %d", i);
+        
+            // No screen name available (as model). Implementation is arcane
+            // and uses deprecated API. See stackoverflow.com/q/24348142/220060
+            result = avf_add_device_info(list, s, index + i + 1, buf, "-", do_log); 
+            if (result < 0) break;
+        }
+    }
+#endif
+
+    if (do_log) av_log(s->priv_data, AV_LOG_INFO, "AVFoundation audio devices:\n");
+    NSArray *audio_devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio];
+    for (AVCaptureDevice *device in audio_devices) {
+        @autoreleasepool {
+            index         = [audio_devices indexOfObject:device];
+            localizedName = [[device localizedName] UTF8String];
+            modelID       = [[device modelID] UTF8String];
+
+            result = avf_add_device_info(list, s, index, localizedName, modelID, do_log);
+            if (result < 0) break;
+        }
+    }
+    [audio_devices release];
+
+    // Make the first device default if it exists.
+    if (list) list->default_device = list->nb_devices > 0 ? 0 : -1;
+
+    return result;
+}
+
+static int avf_get_device_list(struct AVFormatContext *s, struct AVDeviceInfoList *list) 
+{
+   return avf_get_device_list2(s, list, FALSE);
+}
+
 static int avf_read_header(AVFormatContext *s)
 {
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@@ -683,32 +776,8 @@ static int avf_read_header(AVFormatContext *s)
 
     // List devices if requested
     if (ctx->list_devices) {
-        int index = 0;
-        av_log(ctx, AV_LOG_INFO, "AVFoundation video devices:\n");
-        for (AVCaptureDevice *device in devices) {
-            const char *name = [[device localizedName] UTF8String];
-            index            = [devices indexOfObject:device];
-            av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name);
-            index++;
-        }
-#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
-        if (num_screens > 0) {
-            CGDirectDisplayID screens[num_screens];
-            CGGetActiveDisplayList(num_screens, screens, &num_screens);
-            for (int i = 0; i < num_screens; i++) {
-                av_log(ctx, AV_LOG_INFO, "[%d] Capture screen %d\n", index + i, i);
-            }
-        }
-#endif
-
-        av_log(ctx, AV_LOG_INFO, "AVFoundation audio devices:\n");
-        devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio];
-        for (AVCaptureDevice *device in devices) {
-            const char *name = [[device localizedName] UTF8String];
-            int index  = [devices indexOfObject:device];
-            av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name);
-        }
-         goto fail;
+        avf_get_device_list2(s, NULL, TRUE);
+        goto fail;
     }
 
     // parse input filename for video and audio device
@@ -887,7 +956,6 @@ static int avf_read_header(AVFormatContext *s)
     return 0;
 
 fail:
-    [pool release];
     destroy_context(ctx);
     return AVERROR(EIO);
 }
@@ -1038,12 +1106,13 @@ static const AVClass avf_class = {
 };
 
 AVInputFormat ff_avfoundation_demuxer = {
-    .name           = "avfoundation",
-    .long_name      = NULL_IF_CONFIG_SMALL("AVFoundation input device"),
-    .priv_data_size = sizeof(AVFContext),
-    .read_header    = avf_read_header,
-    .read_packet    = avf_read_packet,
-    .read_close     = avf_close,
-    .flags          = AVFMT_NOFILE,
-    .priv_class     = &avf_class,
+    .name            = "avfoundation",
+    .long_name       = NULL_IF_CONFIG_SMALL("AVFoundation input device"),
+    .priv_data_size  = sizeof(AVFContext),
+    .read_header     = avf_read_header,
+    .read_packet     = avf_read_packet,
+    .read_close      = avf_close,
+    .get_device_list = avf_get_device_list,
+    .flags           = AVFMT_NOFILE,
+    .priv_class      = &avf_class,
 };
-- 
1.8.1.4



More information about the ffmpeg-devel mailing list