--- Begin Message ---
From bf72d48c846f5116866ec588fc0ee54a2c354e87 Mon Sep 17 00:00:00 2001
From: Romain Beauxis <to...@rastageeks.org>
Date: Mon, 13 Dec 2021 09:14:50 -0600
Subject: [PATCH] libavdevice/avfoundation.m: Allow to select devices by unique
ID
X-Unsent: 1
To: ffmpeg-devel@ffmpeg.org
Signed-off-by: Romain Beauxis <to...@rastageeks.org>
---
doc/indevs.texi | 6 ++--
libavdevice/avfoundation.m | 72 +++++++++++++++++++++++++++++---------
2 files changed, 60 insertions(+), 18 deletions(-)
diff --git a/doc/indevs.texi b/doc/indevs.texi
index 9d8020311a..858c0fa4e4 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 ID 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 IDs, 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 e6f64b35b8..5d013cc0eb 100644
--- a/libavdevice/avfoundation.m
+++ b/libavdevice/avfoundation.m
@@ -39,6 +39,8 @@
#include "libavutil/imgutils.h"
#include "avdevice.h"
+#define CLEANUP_DEVICE_ID(s) [[s stringByReplacingOccurrencesOfString:@":"
withString:@"."] UTF8String]
+
static void av_log_avfoundation(void *s, int lvl, const char *str, OSStatus
err) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
av_log(s, lvl, "AVFoundation: %s, %s\n", str,
@@ -710,21 +712,23 @@ static int avf_read_header(AVFormatContext *s)
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);
+ const char *name = [[device localizedName] UTF8String];
+ const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]);
+ index = [devices indexOfObject:device];
+ av_log(ctx, AV_LOG_INFO, "[%d] %s (ID: %s)\n", index, name,
uniqueId);
}
for (AVCaptureDevice *device in devices_muxed) {
- const char *name = [[device localizedName] UTF8String];
- index = [devices count] + [devices_muxed
indexOfObject:device];
- av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name);
+ const char *name = [[device localizedName] UTF8String];
+ const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]);
+ index = [devices count] + [devices_muxed
indexOfObject:device];
+ av_log(ctx, AV_LOG_INFO, "[%d] %s (ID: %s)\n", index, name,
uniqueId);
}
#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",
ctx->num_video_devices + i, i);
+ av_log(ctx, AV_LOG_INFO, "[%d] Capture screen %d (ID:
AvfilterAvfoundationCaptureScreen%d)\n", ctx->num_video_devices + i, i,
screens[i]);
}
}
#endif
@@ -732,9 +736,10 @@ static int avf_read_header(AVFormatContext *s)
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);
+ const char *name = [[device localizedName] UTF8String];
+ const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]);
+ int index = [devices indexOfObject:device];
+ av_log(ctx, AV_LOG_INFO, "[%d] %s (ID: %s)\n", index, name,
uniqueId);
}
goto fail;
}
@@ -796,14 +801,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;
+ }
+
+ const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]);
+ if (!strncmp(ctx->video_filename, uniqueId,
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;
+ }
+
+ const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]);
+ if (!strncmp(ctx->video_filename, uniqueId,
strlen(ctx->video_filename))) {
video_device = device;
ctx->video_is_muxed = 1;
break;
@@ -814,10 +834,23 @@ static int avf_read_header(AVFormatContext *s)
// looking for screen inputs
if (!video_device) {
int idx;
+ CGDirectDisplayID screens[num_screens];
+ CGGetActiveDisplayList(num_screens, screens, &num_screens);
+ AVCaptureScreenInput* capture_screen_input = NULL;
+
if(sscanf(ctx->video_filename, "Capture screen %d", &idx) && idx <
num_screens) {
- CGDirectDisplayID screens[num_screens];
- CGGetActiveDisplayList(num_screens, screens, &num_screens);
- AVCaptureScreenInput* capture_screen_input =
[[[AVCaptureScreenInput alloc] initWithDisplayID:screens[idx]] autorelease];
+ capture_screen_input = [[[AVCaptureScreenInput alloc]
initWithDisplayID:screens[idx]] autorelease];
+ }
+
+ if(sscanf(ctx->video_filename,
"AvfilterAvfoundationCaptureScreen%d", &idx)) {
+ for (int i = 0; i < num_screens; i++) {
+ if (screens[i] == idx) {
+ capture_screen_input = [[[AVCaptureScreenInput alloc]
initWithDisplayID:idx] autorelease];
+ }
+ }
+ }
+
+ if (capture_screen_input) {
video_device = (AVCaptureDevice*) capture_screen_input;
ctx->video_device_index = ctx->num_video_devices + idx;
ctx->video_is_screen = 1;
@@ -868,7 +901,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;
+ }
+
+ const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]);
+ if (!strncmp(ctx->audio_filename, uniqueId,
strlen(ctx->audio_filename))) {
audio_device = device;
break;
}
--
2.32.0 (Apple Git-132)
--- End Message ---