From patchwork Wed Dec 15 00:20:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Romain Beauxis X-Patchwork-Id: 32507 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a6b:cd86:0:0:0:0:0 with SMTP id d128csp7680985iog; Tue, 14 Dec 2021 16:20:33 -0800 (PST) X-Google-Smtp-Source: ABdhPJyGG2B4IMJKx0ZrYuSoI0FcvZ4iwBjm6wruRMtwXhCKK6lsUmUmsbG+BmtPxtR0atsNH6mM X-Received: by 2002:a17:907:2d10:: with SMTP id gs16mr8759909ejc.353.1639527633718; Tue, 14 Dec 2021 16:20:33 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1639527633; cv=none; d=google.com; s=arc-20160816; b=McEXtt/Vcx1WDd3MXiMsszamEwLk5mjsZpAUmWX2IW1Tx4RC43rN6wGiK0+1BmD+wy DFzJ70RuoET/eViTKWvivD3AU7oDTEAAw9OO0tSZ7z7wqA5pVt9P4GXfB8qMjkha4eXu y7YrFYmmBnmGtis1wHmdVMnCce1eJcJOXgMfjOaKic1jE2nHvB9mNYxwQKJLwlX9kIpz 9hFiDbqjLvpIINwrtPSsz+fa67GJvgFh0obBG7JG18jkKg5/vi/Qn49SzSFz3F6mpoJX dHw63Skn2I6Mq4oDkJiTbcJ2R+Zfl+65wqtCVVgPrL3NOQmkOx4kTaOz4RcHfQpTxa0c U/hw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:to:date:message-id:mime-version:from :delivered-to; bh=vkayG1eLuMUI8Mc/jvLXeVkiOFpdbp6C37D9LxHCryU=; b=xoT1x5Jj2ItxqENatgKInUhdD1Rw8YzJdz3/bSW7onUPPx1M63jszyaZDgcfm//lUR J0hK6ZS88E+w0p9uZTqOQZLYDYJ1KGvQMn8LUSPxOtdEIkRwtki44Muv8TMC5isWRdvZ vHEYGuaDW8/1Z8gjB3A54Pt/xgwIozUqKRiKSgGAxpj0bpKG7ZMUCMhQgXfJymniJXWI O94V0QTXsbK1gZkYBMCa49kBNvf84Fy0yZ1lXQVJ4FMKx3JK1eAWUDsRo2ebPZqBA4xV Ia7DNPXQSSSzm/osVinsw6y5eNDp0EtckcFYpptYTRWzmswAr9gruzQBSDSjXS6sp7WV LEJA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id cs21si168539ejc.275.2021.12.14.16.20.32; Tue, 14 Dec 2021 16:20:33 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 993BC68AFFF; Wed, 15 Dec 2021 02:20:30 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-qk1-f178.google.com (mail-qk1-f178.google.com [209.85.222.178]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 4E4F768AF55 for ; Wed, 15 Dec 2021 02:20:24 +0200 (EET) Received: by mail-qk1-f178.google.com with SMTP id p4so18469003qkm.7 for ; Tue, 14 Dec 2021 16:20:24 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:content-transfer-encoding:mime-version :subject:message-id:date:to; bh=1GCKWQzZuNfrbcVAocl5uAyL2RvpNRjYzsVw3A2sNbQ=; b=WkIL0GtDgu66URZH61sqEkZVtkS2ldGoiDOw+AfbqBegIr4iL1JOBVh8Zh30776VIL Q4JnLqDTE3c6B2Yc2FNj9858F1xavteGAefzro6uAxZKhAGPgyzbKoKgBFrv1+Ig4q/G TnmAqKJXc9pO8SUdL+gM3U3i7Fk46oMH9lHSwNwHv5Dc8WHtzPY6yeyqysntf8oOZkzx EpGxMzaipHq181oPzo1Chq2YDrj329CAqYb3CpX0PlXxTmCoWN9rilMX0URU0KSiKZ+H kBwtrCFDph97x9l3JTSFYhBRt0JGC0Jwqmvx5ySjPxoAnvwehZj8I2pl+IpbWL4f/Uq+ Fc+w== X-Gm-Message-State: AOAM530ZkD4EvDom0LUt4fd9JimSkB7BdZ6oK3kq0OfAsWvnNpze8rfy G63R/OfoCTvxcEytU3WKsaDdHlFibAE= X-Received: by 2002:a05:620a:2995:: with SMTP id r21mr7098371qkp.100.1639527622091; Tue, 14 Dec 2021 16:20:22 -0800 (PST) Received: from smtpclient.apple ([2607:fb90:25d0:a095:84ff:682b:30ce:d185]) by smtp.gmail.com with ESMTPSA id bq43sm215352qkb.32.2021.12.14.16.20.21 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 14 Dec 2021 16:20:21 -0800 (PST) From: Romain Beauxis Mime-Version: 1.0 (Mac OS X Mail 14.0 \(3654.100.0.2.22\)) Message-Id: <93813544-8D82-4F98-B7AD-001BF88EBB75@rastageeks.org> Date: Tue, 14 Dec 2021 18:20:19 -0600 To: ffmpeg-devel@ffmpeg.org X-Mailer: Apple Mail (2.3654.100.0.2.22) Subject: [FFmpeg-devel] [PATCH v3 03/03] libavdevice/avfoundation.m: Allow to select devices by unique ID. X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: YDFe/vgIfVus This is the third patch of a series of 3 that cleanup and enhance the avfoundation implementation for libavdevice. Changes since last version: * Switched unique ID to use system-prodvided unique ID * Implemented unique IDs for screen capture 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. Signed-off-by: Romain Beauxis --- doc/indevs.texi | 6 ++-- libavdevice/avfoundation.m | 73 +++++++++++++++++++++++++++++--------- 2 files changed, 61 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 @@ -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..036fb57568 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: AvfilterAvfoundationCptureScreen%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,30 @@ 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]); +printf("uniqueID: %s, filename: %s\n", uniqueId, ctx->video_filename); + 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 +922,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, "AvfilterAvfoundationCptureScreen%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 +989,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; }