diff mbox series

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

Message ID 5835AAC9-4ECD-4007-906B-8A9497EF911B@rastageeks.org
State New
Headers show
Series [FFmpeg-devel,v2,01/03] libavdevice/avfoundation.m: use AudioConvert, extend supported formats | expand

Checks

Context Check Description
andriy/configurex86 warning Failed to apply patch
andriy/configureppc warning Failed to apply patch

Commit Message

Romain Beauxis Dec. 13, 2021, 4:40 p.m. UTC
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@rastageeks.org>
---
doc/indevs.texi            |  6 ++--
libavdevice/avfoundation.m | 60 ++++++++++++++++++++++++++++++++++----
2 files changed, 58 insertions(+), 8 deletions(-)

Comments

Marvin Scholz Dec. 13, 2021, 6:25 p.m. UTC | #1
On 13 Dec 2021, at 17:40, Romain Beauxis wrote:

> 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@rastageeks.org>
> ---


Hi,
thanks for the patch, however I fail to see the benefit of it.
You mention that using the name is complicated because it is localized,
but your patch just seems to use the device name and hashes it, which
does not mitigate the issues with the localized name (that could change
when the language is changed) but just hides it behind a hash, making
this problem even more obscure and confusing.
(Correct me if I read your patch wrong, but it seems to just do that.)

Instead I think that you should use the uniqueID property of an 
AVCaptureDevice,
documented here:
https://developer.apple.com/documentation/avfoundation/avcapturedevice/1390477-uniqueid?language=objc

According to the docs, this seems more appropriated, as it does not 
depend on
the localization and does not change when the device is unplugged and 
re-plugged.

Regards,
Marvin Scholz

> 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
> +
> +@interface AvdeviceAvfoundationDigest : NSObject
> ++ (NSString *)fromString:(NSString *)input;
> +@end
> +
> +@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]];
> +}
> +@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)
>
> _______________________________________________
> 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".
Romain Beauxis Dec. 13, 2021, 6:55 p.m. UTC | #2
> On Dec 13, 2021, at 12:25 PM, Marvin Scholz <epirat07@gmail.com> wrote:
> 
> On 13 Dec 2021, at 17:40, Romain Beauxis wrote:
> 
>> 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@rastageeks.org>
>> ---
> 
> 
> Hi,
> thanks for the patch, however I fail to see the benefit of it.
> You mention that using the name is complicated because it is localized,
> but your patch just seems to use the device name and hashes it, which
> does not mitigate the issues with the localized name (that could change
> when the language is changed) but just hides it behind a hash, making
> this problem even more obscure and confusing.
> (Correct me if I read your patch wrong, but it seems to just do that.)
> 
> Instead I think that you should use the uniqueID property of an AVCaptureDevice,
> documented here:
> https://developer.apple.com/documentation/avfoundation/avcapturedevice/1390477-uniqueid?language=objc
> 
> According to the docs, this seems more appropriated, as it does not depend on
> the localization and does not change when the device is unplugged and re-plugged.

Oh great, I totally missed this one. Will submit a new version of the changes soon then, thanks!

> 
>> 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
>> +
>> +@interface AvdeviceAvfoundationDigest : NSObject
>> ++ (NSString *)fromString:(NSString *)input;
>> +@end
>> +
>> +@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]];
>> +}
>> +@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)
>> 
>> _______________________________________________
>> 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".
Romain Beauxis Dec. 15, 2021, 12:22 a.m. UTC | #3
Just sent an updated patch here: http://ffmpeg.org/pipermail/ffmpeg-devel/2021-December/289686.html

> On Dec 13, 2021, at 12:25 PM, Marvin Scholz <epirat07@gmail.com> wrote:
> 
> On 13 Dec 2021, at 17:40, Romain Beauxis wrote:
> 
>> 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@rastageeks.org>
>> ---
> 
> 
> Hi,
> thanks for the patch, however I fail to see the benefit of it.
> You mention that using the name is complicated because it is localized,
> but your patch just seems to use the device name and hashes it, which
> does not mitigate the issues with the localized name (that could change
> when the language is changed) but just hides it behind a hash, making
> this problem even more obscure and confusing.
> (Correct me if I read your patch wrong, but it seems to just do that.)
> 
> Instead I think that you should use the uniqueID property of an AVCaptureDevice,
> documented here:
> https://developer.apple.com/documentation/avfoundation/avcapturedevice/1390477-uniqueid?language=objc <https://developer.apple.com/documentation/avfoundation/avcapturedevice/1390477-uniqueid?language=objc>
> 
> According to the docs, this seems more appropriated, as it does not depend on
> the localization and does not change when the device is unplugged and re-plugged.
> 
> Regards,
> Marvin Scholz
> 
>> 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
>> +
>> +@interface AvdeviceAvfoundationDigest : NSObject
>> ++ (NSString *)fromString:(NSString *)input;
>> +@end
>> +
>> +@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]];
>> +}
>> +@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)
>> 
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org <mailto:ffmpeg-devel@ffmpeg.org>
>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel <https://ffmpeg.org/mailman/listinfo/ffmpeg-devel>
>> 
>> To unsubscribe, visit link above, or email
>> ffmpeg-devel-request@ffmpeg.org <mailto:ffmpeg-devel-request@ffmpeg.org> with subject "unsubscribe".
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org <mailto:ffmpeg-devel@ffmpeg.org>
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel <https://ffmpeg.org/mailman/listinfo/ffmpeg-devel>
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org <mailto:ffmpeg-devel-request@ffmpeg.org> with subject "unsubscribe".
diff mbox series

Patch

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
+
+@interface AvdeviceAvfoundationDigest : NSObject
++ (NSString *)fromString:(NSString *)input;
+@end
+
+@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]];
+}
+@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;
            }