[FFmpeg-devel] [PATCH v2 03/03] libavdevice/avfoundation.m: Allow to select devices by digest.

Romain Beauxis toots at rastageeks.org
Mon Dec 13 18:40:31 EET 2021


This is the third patch of a series of 3 that cleanup and enhance the
avfoundation implementation for libavdevice.

This patch adds a digest to avfoundation devices, when available. This
is needed because device index can change while the machine is running when
devices are plugged or unplugged and device names can be tricky to use with localization
and etc.

The only device type that are excluded are screen capture because the logic to select
them seems a little different and I wanted to minimized the changes. Also, for these
devices, the name is localized in english, quite straight forward and should not change.

Signed-off-by: Romain Beauxis <toots at rastageeks.org>
---
doc/indevs.texi            |  6 ++--
libavdevice/avfoundation.m | 60 ++++++++++++++++++++++++++++++++++----
2 files changed, 58 insertions(+), 8 deletions(-)

diff --git a/doc/indevs.texi b/doc/indevs.texi
index 5be647f70a..8345b64a28 100644
--- a/doc/indevs.texi
+++ b/doc/indevs.texi
@@ -114,7 +114,7 @@ The input filename has to be given in the following syntax:
-i "[[VIDEO]:[AUDIO]]"
@end example
The first entry selects the video input while the latter selects the audio input.
-The stream has to be specified by the device name or the device index as shown by the device list.
+The stream has to be specified by the device name, index or digest as shown by the device list.
Alternatively, the video and/or audio input device can be chosen by index using the
@option{
    -video_device_index <INDEX>
@@ -127,7 +127,9 @@ and/or
device name or index given in the input filename.

All available devices can be enumerated by using @option{-list_devices true}, listing
-all device names and corresponding indices.
+all device names, corresponding indices and digests, when available. Device name can be 
+tricky to use when localized and device index can change when devices are plugged or unplugged. A device
+hash, when available, uniquely identifies a device and should not change over time.

There are two device name aliases:
@table @code
diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m
index 95414fd16a..bede51bda0 100644
--- a/libavdevice/avfoundation.m
+++ b/libavdevice/avfoundation.m
@@ -26,6 +26,7 @@
 */

#import <AVFoundation/AVFoundation.h>
+#import <CommonCrypto/CommonDigest.h>

#include "libavutil/channel_layout.h"
#include "libavutil/pixdesc.h"
@@ -79,6 +80,28 @@
    { AV_PIX_FMT_NONE, 0 }
};

+#define DEVICES_DIGEST_LENGTH 8
+
+ at interface AvdeviceAvfoundationDigest : NSObject
++ (NSString *)fromString:(NSString *)input;
+ at end
+
+ at implementation AvdeviceAvfoundationDigest : NSObject
++ (NSString *) fromString:(NSString *)input {
+    const char *cStr = [input UTF8String];
+    unsigned char digest[CC_SHA256_DIGEST_LENGTH];
+    CC_SHA256( cStr, strlen(cStr), digest );
+
+    NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
+
+    for(int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++)
+    [output appendFormat:@"%02x", digest[i]];
+
+    // The "d" prefix makes sure that digest strings are never mistaken for numbers.
+    return [@"d" stringByAppendingString:[output substringToIndex:DEVICES_DIGEST_LENGTH]];
+}
+ at end
+
#define MAX_QUEUED_OBJECTS 10

@interface AvdeviceAvfoundationBuffer : NSObject
@@ -860,13 +883,15 @@ static int avf_read_header(AVFormatContext *s)
        av_log(ctx, AV_LOG_INFO, "AVFoundation video devices:\n");
        for (AVCaptureDevice *device in devices) {
            const char *name = [[device localizedName] UTF8String];
+            NSString *digest = [AvdeviceAvfoundationDigest fromString:[[NSString alloc] initWithUTF8String:name]];
            index            = [devices indexOfObject:device];
-            av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name);
+            av_log(ctx, AV_LOG_INFO, "[%d] %s (digest: %s)\n", index, name, [digest UTF8String]);
        }
        for (AVCaptureDevice *device in devices_muxed) {
            const char *name = [[device localizedName] UTF8String];
+            NSString *digest = [AvdeviceAvfoundationDigest fromString:[[NSString alloc] initWithUTF8String:name]];
            index            = [devices count] + [devices_muxed indexOfObject:device];
-            av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name);
+            av_log(ctx, AV_LOG_INFO, "[%d] %s (digest: %s)\n", index, name, [digest UTF8String]);
        }
#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
        if (num_screens > 0) {
@@ -882,8 +907,9 @@ static int avf_read_header(AVFormatContext *s)
        devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio];
        for (AVCaptureDevice *device in devices) {
            const char *name = [[device localizedName] UTF8String];
+            NSString *digest = [AvdeviceAvfoundationDigest fromString:[[NSString alloc] initWithUTF8String:name]];
            int index  = [devices indexOfObject:device];
-            av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name);
+            av_log(ctx, AV_LOG_INFO, "[%d] %s (digest: %s)\n", index, name, [digest UTF8String]);
        }
         goto fail;
    }
@@ -945,14 +971,29 @@ static int avf_read_header(AVFormatContext *s)
        } else {
        // looking for video inputs
        for (AVCaptureDevice *device in devices) {
-            if (!strncmp(ctx->video_filename, [[device localizedName] UTF8String], strlen(ctx->video_filename))) {
+            const char *name = [[device localizedName] UTF8String];
+            if (!strncmp(ctx->video_filename, name, strlen(ctx->video_filename))) {
+                video_device = device;
+                break;
+            }
+
+            NSString *digest = [AvdeviceAvfoundationDigest fromString:[[NSString alloc] initWithUTF8String:name]];
+            if (!strncmp(ctx->video_filename, [digest UTF8String], strlen(ctx->video_filename))) {
                video_device = device;
                break;
            }
        }
        // looking for muxed inputs
        for (AVCaptureDevice *device in devices_muxed) {
-            if (!strncmp(ctx->video_filename, [[device localizedName] UTF8String], strlen(ctx->video_filename))) {
+            const char *name = [[device localizedName] UTF8String];
+            if (!strncmp(ctx->video_filename, name, strlen(ctx->video_filename))) {
+                video_device = device;
+                ctx->video_is_muxed = 1;
+                break;
+            }
+
+            NSString *digest = [AvdeviceAvfoundationDigest fromString:[[NSString alloc] initWithUTF8String:name]];
+            if (!strncmp(ctx->video_filename, [digest UTF8String], strlen(ctx->video_filename))) {
                video_device = device;
                ctx->video_is_muxed = 1;
                break;
@@ -1017,7 +1058,14 @@ static int avf_read_header(AVFormatContext *s)
        NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio];

        for (AVCaptureDevice *device in devices) {
-            if (!strncmp(ctx->audio_filename, [[device localizedName] UTF8String], strlen(ctx->audio_filename))) {
+            const char *name = [[device localizedName] UTF8String];
+            if (!strncmp(ctx->audio_filename, name, strlen(ctx->audio_filename))) {
+                audio_device = device;
+                break;
+            }
+
+            NSString *digest = [AvdeviceAvfoundationDigest fromString:[[NSString alloc] initWithUTF8String:name]];
+            if (!strncmp(ctx->audio_filename, [digest UTF8String], strlen(ctx->audio_filename))) {
                audio_device = device;
                break;
            }
-- 
2.30.1 (Apple Git-130)



More information about the ffmpeg-devel mailing list