* [FFmpeg-devel] [PATCH v4 3/3] libavdevice/avfoundation.m: Allow to select devices by unique ID. @ 2021-12-17 15:12 Romain Beauxis 2021-12-17 21:51 ` Marvin Scholz 0 siblings, 1 reply; 3+ messages in thread From: Romain Beauxis @ 2021-12-17 15:12 UTC (permalink / raw) To: ffmpeg-devel 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. 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. 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". ^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [FFmpeg-devel] [PATCH v4 3/3] libavdevice/avfoundation.m: Allow to select devices by unique ID. 2021-12-17 15:12 [FFmpeg-devel] [PATCH v4 3/3] libavdevice/avfoundation.m: Allow to select devices by unique ID Romain Beauxis @ 2021-12-17 21:51 ` Marvin Scholz 2021-12-18 15:58 ` Romain Beauxis 0 siblings, 1 reply; 3+ messages in thread From: Marvin Scholz @ 2021-12-17 21:51 UTC (permalink / raw) To: FFmpeg development discussions and patches 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". ^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [FFmpeg-devel] [PATCH v4 3/3] libavdevice/avfoundation.m: Allow to select devices by unique ID. 2021-12-17 21:51 ` Marvin Scholz @ 2021-12-18 15:58 ` Romain Beauxis 0 siblings, 0 replies; 3+ messages in thread From: Romain Beauxis @ 2021-12-18 15:58 UTC (permalink / raw) To: FFmpeg development discussions and patches > On Dec 17, 2021, at 3:51 PM, Marvin Scholz <epirat07@gmail.com> wrote: > > > > 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. I was just thinking about this. while that would indeed be possible and a great approach, I realize now that because the implementation needs to otherwise match the filename if it is used, we would still need to iterate through all the devices. The current code, while annoying, at least does one loop to catch both use of filename and unique ID. > 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. Great thanks and thanks for the great reviews! Are you interested just in this patch? In which case, should I repost it rebased on the latest main instead of the previous patch? > >> 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. ACK >> 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". _______________________________________________ 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". ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2021-12-18 15:59 UTC | newest] Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2021-12-17 15:12 [FFmpeg-devel] [PATCH v4 3/3] libavdevice/avfoundation.m: Allow to select devices by unique ID Romain Beauxis 2021-12-17 21:51 ` Marvin Scholz 2021-12-18 15:58 ` Romain Beauxis
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