From: "Marvin Scholz" <epirat07@gmail.com>
To: "FFmpeg development discussions and patches" <ffmpeg-devel@ffmpeg.org>
Subject: Re: [FFmpeg-devel] [PATCH v4 3/3] libavdevice/avfoundation.m: Allow to select devices by unique ID.
Date: Fri, 17 Dec 2021 22:51:59 +0100
Message-ID: <BB48D632-143B-479A-8AFE-25D61A685997@gmail.com> (raw)
In-Reply-To: <b0da2587-6a5b-eb42-c605-03e495e5ca30@rastageeks.org>
On 17 Dec 2021, at 16:12, Romain Beauxis wrote:
> This is the third patch of a series of 3 that cleanup and enhance the
> avfoundation implementation for libavdevice.
>
> Changes:
> v2: None
> v3:
> * Switched unique ID to use system-prodvided unique ID
> * Implemented unique IDs for screen capture
> v4: Cleanup
>
> This patch adds a unique ID to avfoundation devices. 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.
>
> Example of output:
> ./ffmpeg -f avfoundation -list_devices true -i ""
> [...]
> [AVFoundation indev @ 0x158705230] AVFoundation video devices:
> [AVFoundation indev @ 0x158705230] [0] FaceTime HD Camera (ID:
> 47B4B64B70674B9CAD2BAE273A71F4B5)
> [AVFoundation indev @ 0x158705230] [1] Capture screen 0 (ID:
> AvfilterAvfoundationCaptureScreen1)
> [AVFoundation indev @ 0x158705230] AVFoundation audio devices:
> [AVFoundation indev @ 0x158705230] [0] Loopback Audio (ID:
> com.rogueamoeba.Loopback.A5668B36-711E-4DF5-8A8D-7148508C735B)
> [AVFoundation indev @ 0x158705230] [1] MacBook Pro Microphone (ID:
> BuiltInMicrophoneDevice)
>
> Notes:
> * Unique names do not seem to follow any specific pattern. I have used
> one similar to the builtin microphone for screen capture
> * The : substitution is actually required. The loopback device above
> did
> have it in its name.
>
Is there no way to escape the : in the command so that we would not
need to mess with the ID the system gives us?
And if we need to, it would be ideal to have a fully reversible way of
doing so, as then you could just reverse the mangling and use
`deviceWithUniqueID:` instead of iterating all devices.
That said, if thats not easily doable I am fine with the patch as-is,
aside from the minor comments below, thanks for your work on this.
> Signed-off-by: Romain Beauxis <toots@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 5be647f70a..2b55399c8c 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.
This should say ID I think, as hash was never mentioned before.
> There are two device name aliases:
> @table @code
> diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m
> index b602cfbe95..25286507d6 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 const int avf_time_base = 1000000;
> static const AVRational avf_time_base_q = {
> @@ -797,21 +799,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
> @@ -819,9 +823,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;
> }
> @@ -883,14 +888,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;
> @@ -901,10 +921,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;
> @@ -955,7 +988,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)
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next prev parent reply other threads:[~2021-12-17 21:52 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-12-17 15:12 Romain Beauxis
2021-12-17 21:51 ` Marvin Scholz [this message]
2021-12-18 15:58 ` Romain Beauxis
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=BB48D632-143B-479A-8AFE-25D61A685997@gmail.com \
--to=epirat07@gmail.com \
--cc=ffmpeg-devel@ffmpeg.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git