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