PR #23613 opened by Gabriel Balaich (ninbura)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23613
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23613.patch

# Summary of changes

This PR adds the ability for macOS users to list & select avfoundation 
video/audio inputs via unique ID & serial, where-as previously only name & 
index were the available options.

# Why selecting video/audio inputs via name/index is unreliable.
1. When multiple video/audio inputs of the same model are attached to the same 
system, you cannot uniquely select said inputs via name.
2. Video input indexes can change after hot plugs and system restarts.
3. Audio input indexes can change when connecting/disconnecting audio inputs.
4. When multiple video inputs of the same model are attached to the same 
system, the source selected via index can randomly change from run-to-run (see 
example below).

See attached `index-frame-test.zsh` & `capture.log` for full command & output.
```Zsh
=== frame 1 @ 2026-06-26_20-05-42.877 (index 0, 3840x2160@60) ===
Input #0, avfoundation, from '':
  Duration: N/A, start: 4412.272300, bitrate: N/A
  Stream #0:0: Video: rawvideo (NV12 / 0x3231564E), nv12, 3840x2160, 60 fps, 60 
tbr, 1000k tbn, start 4412.272300
Stream mapping:
  Stream #0:0 -> #0:0 (rawvideo (native) -> mjpeg (native))
Output #0, image2, to 
'index-frame-test/run_2026-06-26_20-05-42_idx0/frame-01_2026-06-26_20-05-42.877.jpg':
  Metadata:
    encoder         : Lavf62.19.101
  Stream #0:0: Video: mjpeg, yuv420p(pc, progressive), 3840x2160, q=2-31, 200 
kb/s, 60 fps, 60 tbn
    Metadata:
      encoder         : Lavc62.36.101 mjpeg
    Side data:
      CPB properties: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: 
N/A
[image2 @ 0xbe1018280] The specified filename 
'index-frame-test/run_2026-06-26_20-05-42_idx0/frame-01_2026-06-26_20-05-42.877.jpg'
 does not contain an image sequence pattern or a pattern is invalid.
[image2 @ 0xbe1018280] Use a pattern such as %03d for an image sequence or use 
the -update option (with -frames:v 1 if needed) to write a single image.
[out#0/image2 @ 0xbe12900c0] video:378KiB audio:0KiB subtitle:0KiB other 
streams:0KiB global headers:0KiB muxing overhead: unknown
frame=    1 fps=0.0 q=12.7 Lsize=N/A time=00:00:00.01 bitrate=N/A speed=0.657x 
elapsed=0:00:00.02    

# Repeated 10 times...
``` 

Output changes despite looping the same FFmpeg command 10x times against the 
same input. As far as I can tell this is due to 1 or many inputs sharing the 
same name (same model).

<img src="/attachments/ed927d62-8258-4797-82eb-49ee014de73c" alt="Screenshot 
2026-06-26 at 23.06.49" width="1200">

# Why unique ID is desirable, and when it's undesirable.
### Desirable 
- Unique ID allows you to select an audio device with an identifier that *never 
changes*.
- Persistent across restarts, hot plugs, and when increasing or decreasing the 
amount of audio I/O attached to you system (index can change in these 
scenarios). 
- Allows for selecting 1 of many audio devices with the same name.
    - ```Zsh
       [AVFoundation indev @ 0xb0cc18180] [4] same-name-test  
uid=com.rogueamoeba.Loopback::F43848CE-D7CE-4C9C-B5F6-04F55190C157  serial=N/A
       [AVFoundation indev @ 0xb0cc18180] [6] same-name-test  
uid=com.rogueamoeba.Loopback::18AAEF28-5258-490C-8DC8-85FB09624E83  serial=N/A
       ```

### Undesirable
- A video source's unique ID *can change* after hotplugs & system restarts.
    - ```Zsh
       # Baseline before hot plug
       [1]  Elgato 4K X  uid=0x232000000fd9009b  serial=A7SNB504219J0R
       [3]  Elgato 4K X  uid=0x222000000fd9009b  serial=A7SNB50423R73R
       [6]  Elgato 4K X  uid=0x252000000fd9009c  serial=A7SNB50424UBQI
       
       # After hot plug (index & uid can change)
       [1]  Elgato 4K X  uid=0x232000000fd9009b  serial=A7SNB504219J0R
       [3]  Elgato 4K X  uid=0x222000000fd9009b  serial=A7SNB50423R73R
       [4]  Elgato 4K X  uid=0x252000000fd9009b  serial=A7SNB50424UBQI
       
       # After restart (index & uid can change)
       [0]  Elgato 4K X  uid=0x232000000fd9009b  serial=A7SNB50424UBQI
       [2]  Elgato 4K X  uid=0x252000000fd9009b  serial=A7SNB504219J0R
       [3]  Elgato 4K X  uid=0x262000000fd9009b  serial=A7SNB50423R73R
       ```

# Why serial is desirable, and its limitations.
### Desirable
- Serial allows you to select video/audio inputs with an identifier that *never 
changes* (tested with hot plugs & restarts).
- Does not suffer from the same behavior as index where feed can randomly 
change run-to-run (tested with loops).
- Unique across multiple units of the same device/model & name.
- Provides a common identifier, like name, for selecting/correlating a pair of 
video/audio inputs from the same device.

### Limitations
- Serial is only available for USB devices, but nearly all consumer-grade 
capture cards for macOS are connected via USB.


>From e4cd3786b7b88e4f36f2278de8e30f94d1ffaa35 Mon Sep 17 00:00:00 2001
From: Gabriel Balaich <[email protected]>
Date: Fri, 26 Jun 2026 21:08:55 -0600
Subject: [PATCH] avdevice/avfoundation: add device selection by USB serial and
 unique ID

A capture device could previously be selected only by index or by name.
Both are unreliable when multiple audio/video devices share a name or
across reboots. AVFoundation reorders the device indices, and the USB
video uniqueID embeds the macOS locationID, which is reassigned on
reboot or replug and can then resolve to a different physical device.

Add four options:
-video_device_serial / -audio_device_serial
-video_device_uid / -audio_device_uid

The USB serial number is the only identifier that stays pegged to a
given physical unit. For video it is resolved to the device's current
locationID via IOKit. For audio it is matched against the uniqueID,
which already embeds it. The unique ID covers devices that have no
serial, such as virtual camera/audio devices.

-list_devices additionally prints each device's uniqueID and USB serial
so the values can be discovered. IOKit is detected in configure and used
only when available.

Signed-off-by: Gabriel Balaich <[email protected]>
---
 Changelog                  |   1 +
 configure                  |   4 +-
 doc/indevs.texi            |  21 ++-
 libavdevice/avfoundation.m | 263 ++++++++++++++++++++++++++++++++++++-
 4 files changed, 281 insertions(+), 8 deletions(-)

diff --git a/Changelog b/Changelog
index 2ad3ee255f..714a45322c 100644
--- a/Changelog
+++ b/Changelog
@@ -18,6 +18,7 @@ version <next>:
 - Remove ogg/celt parsing
 - Bitstream filter to split Dolby Vision multi-layer HEVC
 - Add AMF hardware memory mapping support.
+- AVFoundation input device selection by unique ID and USB serial number
 
 
 version 8.1:
diff --git a/configure b/configure
index a6bbb86807..f594e7c881 100755
--- a/configure
+++ b/configure
@@ -2723,6 +2723,7 @@ HAVE_LIST="
     $TYPES_LIST
     gzip
     ioctl_posix
+    iokit
     libdrm_getfb2
     makeinfo_html
     opencl_d3d11
@@ -4039,7 +4040,7 @@ android_camera_indev_deps="android camera2ndk mediandk 
pthreads"
 alsa_indev_deps="alsa"
 alsa_outdev_deps="alsa"
 avfoundation_indev_deps="avfoundation corevideo coremedia pthreads 
AVCaptureSession"
-avfoundation_indev_suggest="coregraphics applicationservices"
+avfoundation_indev_suggest="coregraphics applicationservices iokit"
 avfoundation_indev_extralibs="-framework Foundation"
 audiotoolbox_outdev_deps="audiotoolbox pthreads AudioObjectPropertyAddress"
 audiotoolbox_outdev_extralibs="-framework AudioToolbox -framework CoreAudio"
@@ -7145,6 +7146,7 @@ enabled avfoundation && {
     disable coregraphics applicationservices
     check_lib coregraphics        CoreGraphics/CoreGraphics.h               
CGGetActiveDisplayList "-framework CoreGraphics" ||
     check_lib applicationservices ApplicationServices/ApplicationServices.h 
CGGetActiveDisplayList "-framework ApplicationServices"
+    check_lib iokit               IOKit/IOKitLib.h                          
IOServiceGetMatchingServices "-framework IOKit"
     check_objc_class AVFoundation/AVFoundation.h AVCaptureSession
 }
 
diff --git a/doc/indevs.texi b/doc/indevs.texi
index 8822e070fe..6554203509 100644
--- a/doc/indevs.texi
+++ b/doc/indevs.texi
@@ -148,8 +148,8 @@ AVFoundation supports the following options:
 @table @option
 
 @item -list_devices <TRUE|FALSE>
-If set to true, a list of all available input devices is given showing all
-device names and indices.
+If set to true, a list of all available input devices is given showing their
+index, name, unique ID, and USB serial number (when available).
 
 @item -video_device_index <INDEX>
 Specify the video device by its index. Overrides anything given in the input 
filename.
@@ -157,6 +157,23 @@ Specify the video device by its index. Overrides anything 
given in the input fil
 @item -audio_device_index <INDEX>
 Specify the audio device by its index. Overrides anything given in the input 
filename.
 
+@item -video_device_serial <SERIAL>
+Specify the video device by its USB serial number (USB devices only). Unlike 
the
+index, this is stable across reboots and device reordering. Overrides anything
+given in the input filename.
+
+@item -audio_device_serial <SERIAL>
+Specify the audio device by its USB serial number, matched against the device's
+unique ID on a best-effort basis. See @option{-video_device_serial}.
+
+@item -video_device_uid <UID>
+Specify the video device by its AVFoundation unique ID (as shown by
+@option{-list_devices}). Unique-ID stability is device-dependent and is not
+reliable for USB capture devices; prefer @option{-video_device_serial} for 
those.
+
+@item -audio_device_uid <UID>
+Specify the audio device by its AVFoundation unique ID. See 
@option{-video_device_uid}.
+
 @item -pixel_format <FORMAT>
 Request the video device to use a specific pixel format.
 If the specified format is not supported, a list of available formats is given
diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m
index ebec1ac4f2..2f5988b318 100644
--- a/libavdevice/avfoundation.m
+++ b/libavdevice/avfoundation.m
@@ -25,7 +25,19 @@
  * @author Thilo Borgmann <[email protected]>
  */
 
+#include "config.h"
+
 #import <AVFoundation/AVFoundation.h>
+#if HAVE_IOKIT
+#   import <IOKit/IOKitLib.h>
+    /* kIOMainPortDefault replaced kIOMasterPortDefault in the macOS 12 SDK. */
+#   if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && 
__MAC_OS_X_VERSION_MAX_ALLOWED >= 120000
+#       define AVF_IO_MAIN_PORT_DEFAULT kIOMainPortDefault
+#   else
+#       define AVF_IO_MAIN_PORT_DEFAULT kIOMasterPortDefault
+#   endif
+#endif
+
 #include <pthread.h>
 
 #include "libavutil/channel_layout.h"
@@ -111,6 +123,10 @@ typedef struct
     char            *url;
     char            *video_filename;
     char            *audio_filename;
+    char            *video_device_serial;
+    char            *audio_device_serial;
+    char            *video_device_uid;
+    char            *audio_device_uid;
 
     int             num_video_devices;
 
@@ -821,6 +837,230 @@ static NSArray* getDevicesWithMediaType(AVMediaType 
mediaType) {
 #endif
 }
 
+#if HAVE_IOKIT
+/* Newer macOS exposes USB devices as IOUSBHostDevice; pre-10.11 systems and 
some
+ * devices still use the legacy IOUSBDevice class. Try the modern class first. 
*/
+static const char *const avf_usb_match_classes[] = { "IOUSBHostDevice", 
"IOUSBDevice" };
+
+static int avf_io_get_string(io_service_t service, CFStringRef key, char *buf, 
size_t size)
+{
+    CFTypeRef ref = IORegistryEntryCreateCFProperty(service, key, 
kCFAllocatorDefault, 0);
+    int ok = ref && CFGetTypeID(ref) == CFStringGetTypeID() && 
CFStringGetCString(ref, buf, size, kCFStringEncodingUTF8);
+    if (ref)
+        CFRelease(ref);
+    return ok;
+}
+
+static int avf_io_get_uint32(io_service_t service, CFStringRef key, uint32_t 
*out)
+{
+    CFTypeRef ref = IORegistryEntryCreateCFProperty(service, key, 
kCFAllocatorDefault, 0);
+    int ok = ref && CFGetTypeID(ref) == CFNumberGetTypeID() && 
CFNumberGetValue(ref, kCFNumberSInt32Type, out);
+    if (ref)
+        CFRelease(ref);
+    return ok;
+}
+#endif
+
+static int64_t avf_usb_location_for_serial(const char *serial)
+{
+#if HAVE_IOKIT
+    int64_t location = -1;
+
+    for (size_t i = 0; i < FF_ARRAY_ELEMS(avf_usb_match_classes) && location < 
0; i++) {
+        io_iterator_t iterator = 0;
+        io_service_t service;
+
+        if (IOServiceGetMatchingServices(AVF_IO_MAIN_PORT_DEFAULT,
+                IOServiceMatching(avf_usb_match_classes[i]), &iterator) != 
KERN_SUCCESS)
+            continue;
+
+        while (location < 0 && (service = IOIteratorNext(iterator))) {
+            char found[256];
+            uint32_t loc;
+            if (avf_io_get_string(service, CFSTR("USB Serial Number"), found, 
sizeof(found)) &&
+                !strcmp(found, serial) &&
+                avf_io_get_uint32(service, CFSTR("locationID"), &loc))
+                location = loc;
+            IOObjectRelease(service);
+        }
+        IOObjectRelease(iterator);
+    }
+
+    return location;
+#else
+    return -1;
+#endif
+}
+
+static NSString *avf_usb_serial_for_location(uint32_t location)
+{
+#if HAVE_IOKIT
+    NSString *serial = nil;
+
+    for (size_t i = 0; i < FF_ARRAY_ELEMS(avf_usb_match_classes) && !serial; 
i++) {
+        io_iterator_t iterator = 0;
+        io_service_t service;
+
+        if (IOServiceGetMatchingServices(AVF_IO_MAIN_PORT_DEFAULT,
+                IOServiceMatching(avf_usb_match_classes[i]), &iterator) != 
KERN_SUCCESS)
+            continue;
+
+        while (!serial && (service = IOIteratorNext(iterator))) {
+            char found[256];
+            uint32_t loc;
+            if (avf_io_get_uint32(service, CFSTR("locationID"), &loc) && loc 
== location &&
+                avf_io_get_string(service, CFSTR("USB Serial Number"), found, 
sizeof(found)))
+                serial = [NSString stringWithUTF8String:found];
+            IOObjectRelease(service);
+        }
+        IOObjectRelease(iterator);
+    }
+
+    return serial;
+#else
+    return nil;
+#endif
+}
+
+// USB video uniqueID = locationID<<32 | VID<<16 | PID; match on the 
locationID.
+static AVCaptureDevice *avf_video_device_with_serial(const char *serial,
+    NSArray *devices, NSArray *devices_muxed, int *is_muxed)
+{
+    int64_t location = avf_usb_location_for_serial(serial);
+    NSArray *lists[2] = { devices, devices_muxed };
+
+    if (location < 0)
+        return nil;
+
+    for (int i = 0; i < 2; i++) {
+        for (AVCaptureDevice *device in lists[i]) {
+            NSString *uid = [device uniqueID];
+            if ([uid hasPrefix:@"0x"] &&
+                (uint32_t)(strtoull([uid UTF8String], NULL, 16) >> 32) == 
(uint32_t)location) {
+                *is_muxed = (i == 1);
+                return device;
+            }
+        }
+    }
+
+    return nil;
+}
+
+static AVCaptureDevice *avf_video_device_with_uid(const char *uid,
+    NSArray *devices, NSArray *devices_muxed, int *is_muxed)
+{
+    NSString *want = [NSString stringWithUTF8String:uid];
+    NSArray *lists[2] = { devices, devices_muxed };
+
+    for (int i = 0; i < 2; i++) {
+        for (AVCaptureDevice *device in lists[i]) {
+            if ([[device uniqueID] isEqualToString:want]) {
+                *is_muxed = (i == 1);
+                return device;
+            }
+        }
+    }
+
+    return nil;
+}
+
+// USB audio uniqueID embeds the serial (...:SERIAL:N); match it directly.
+static AVCaptureDevice *avf_audio_device_with_serial(const char *serial, 
NSArray *devices)
+{
+    NSString *needle = [NSString stringWithFormat:@":%s:", serial];
+
+    for (AVCaptureDevice *device in devices) {
+        if ([[device uniqueID] rangeOfString:needle].location != NSNotFound)
+            return device;
+    }
+
+    return nil;
+}
+
+static AVCaptureDevice *avf_audio_device_with_uid(const char *uid, NSArray 
*devices)
+{
+    NSString *want = [NSString stringWithUTF8String:uid];
+
+    for (AVCaptureDevice *device in devices) {
+        if ([[device uniqueID] isEqualToString:want])
+            return device;
+    }
+
+    return nil;
+}
+
+// Best-effort serial string for -list_devices, or "N/A".
+static const char *avf_device_listing_serial(AVCaptureDevice *device)
+{
+    NSString *uid = [device uniqueID];
+
+    if ([uid hasPrefix:@"0x"]) {
+        unsigned long long value = strtoull([uid UTF8String], NULL, 16);
+        NSString *serial = avf_usb_serial_for_location((uint32_t)(value >> 
32));
+        return serial.length ? [serial UTF8String] : "N/A";
+    } else {
+        // Trust the serial field only when the trailing field is the numeric 
engine index.
+        NSArray<NSString *> *fields = [uid componentsSeparatedByString:@":"];
+        if (fields.count >= 2) {
+            NSString *serial = fields[fields.count - 2];
+            NSString *index  = fields[fields.count - 1];
+            if (serial.length && index.length &&
+                [index rangeOfCharacterFromSet:
+                    [[NSCharacterSet decimalDigitCharacterSet] 
invertedSet]].location == NSNotFound)
+                return [serial UTF8String];
+        }
+        return "N/A";
+    }
+}
+
+// Returns 1 if a serial/uid selector was set (*device = match, or nil after 
logging on miss), else 0.
+static int avf_video_device_from_string(AVFContext *ctx, NSArray *devices,
+    NSArray *devices_muxed, AVCaptureDevice **device)
+{
+    if (ctx->video_device_serial && *ctx->video_device_serial) {
+        *device = avf_video_device_with_serial(ctx->video_device_serial,
+            devices, devices_muxed, &ctx->video_is_muxed);
+        if (!*device)
+            av_log(ctx, AV_LOG_ERROR,
+                   "Video capture device with serial number '%s' not found\n",
+                   ctx->video_device_serial);
+        return 1;
+    }
+    if (ctx->video_device_uid && *ctx->video_device_uid) {
+        *device = avf_video_device_with_uid(ctx->video_device_uid,
+            devices, devices_muxed, &ctx->video_is_muxed);
+        if (!*device)
+            av_log(ctx, AV_LOG_ERROR,
+                   "Video capture device with unique ID '%s' not found\n",
+                   ctx->video_device_uid);
+        return 1;
+    }
+    return 0;
+}
+
+static int avf_audio_device_from_string(AVFContext *ctx, AVCaptureDevice 
**device)
+{
+    if (ctx->audio_device_serial && *ctx->audio_device_serial) {
+        NSArray *devices = getDevicesWithMediaType(AVMediaTypeAudio);
+        *device = avf_audio_device_with_serial(ctx->audio_device_serial, 
devices);
+        if (!*device)
+            av_log(ctx, AV_LOG_ERROR,
+                   "Audio capture device with serial number '%s' not found\n",
+                   ctx->audio_device_serial);
+        return 1;
+    }
+    if (ctx->audio_device_uid && *ctx->audio_device_uid) {
+        NSArray *devices = getDevicesWithMediaType(AVMediaTypeAudio);
+        *device = avf_audio_device_with_uid(ctx->audio_device_uid, devices);
+        if (!*device)
+            av_log(ctx, AV_LOG_ERROR,
+                   "Audio capture device with unique ID '%s' not found\n",
+                   ctx->audio_device_uid);
+        return 1;
+    }
+    return 0;
+}
+
 static int avf_read_header(AVFormatContext *s)
 {
     int ret = 0;
@@ -848,12 +1088,14 @@ static int avf_read_header(AVFormatContext *s)
         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);
+            av_log(ctx, AV_LOG_INFO, "[%d] %s  uid=%s  serial=%s\n", index, 
name,
+                   [[device uniqueID] UTF8String], 
avf_device_listing_serial(device));
         }
         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);
+            av_log(ctx, AV_LOG_INFO, "[%d] %s  uid=%s  serial=%s\n", index, 
name,
+                   [[device uniqueID] UTF8String], 
avf_device_listing_serial(device));
         }
 #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
         if (num_screens > 0) {
@@ -870,7 +1112,8 @@ static int avf_read_header(AVFormatContext *s)
         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);
+            av_log(ctx, AV_LOG_INFO, "[%d] %s  uid=%s  serial=%s\n", index, 
name,
+                   [[device uniqueID] UTF8String], 
avf_device_listing_serial(device));
         }
          goto fail;
     }
@@ -888,7 +1131,10 @@ static int avf_read_header(AVFormatContext *s)
         sscanf(ctx->audio_filename, "%d", &ctx->audio_device_index);
     }
 
-    if (ctx->video_device_index >= 0) {
+    if (avf_video_device_from_string(ctx, devices, devices_muxed, 
&video_device)) {
+        if (!video_device)
+            goto fail;
+    } else if (ctx->video_device_index >= 0) {
         if (ctx->video_device_index < ctx->num_video_devices) {
             if (ctx->video_device_index < [devices count]) {
                 video_device = [devices objectAtIndex:ctx->video_device_index];
@@ -989,7 +1235,10 @@ static int avf_read_header(AVFormatContext *s)
     }
 
     // get audio device
-    if (ctx->audio_device_index >= 0) {
+    if (avf_audio_device_from_string(ctx, &audio_device)) {
+        if (!audio_device)
+            goto fail;
+    } else if (ctx->audio_device_index >= 0) {
         NSArray *devices = getDevicesWithMediaType(AVMediaTypeAudio);
 
         if (ctx->audio_device_index >= [devices count]) {
@@ -1278,6 +1527,10 @@ static const AVOption options[] = {
     { "list_devices", "list available devices", offsetof(AVFContext, 
list_devices), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
     { "video_device_index", "select video device by index for devices with 
same name (starts at 0)", offsetof(AVFContext, video_device_index), 
AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
     { "audio_device_index", "select audio device by index for devices with 
same name (starts at 0)", offsetof(AVFContext, audio_device_index), 
AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
+    { "video_device_serial", "select video device by USB serial number (stable 
across reboots and reordering)", offsetof(AVFContext, video_device_serial), 
AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
+    { "audio_device_serial", "select audio device by USB serial number 
(best-effort match within its unique ID)", offsetof(AVFContext, 
audio_device_serial), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, 
AV_OPT_FLAG_DECODING_PARAM },
+    { "video_device_uid", "select video device by its AVFoundation unique ID", 
offsetof(AVFContext, video_device_uid), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 
0, AV_OPT_FLAG_DECODING_PARAM },
+    { "audio_device_uid", "select audio device by its AVFoundation unique ID", 
offsetof(AVFContext, audio_device_uid), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 
0, AV_OPT_FLAG_DECODING_PARAM },
     { "pixel_format", "set pixel format", offsetof(AVFContext, pixel_format), 
AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_YUV420P}, 0, INT_MAX, 
AV_OPT_FLAG_DECODING_PARAM},
     { "framerate", "set frame rate", offsetof(AVFContext, framerate), 
AV_OPT_TYPE_VIDEO_RATE, {.str = "ntsc"}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM 
},
     { "video_size", "set video size", offsetof(AVFContext, width), 
AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to