From patchwork Tue Jul 6 09:20:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Diederick C. Niehorster" X-Patchwork-Id: 28804 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a5d:965a:0:0:0:0:0 with SMTP id d26csp4923076ios; Tue, 6 Jul 2021 02:27:15 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzNqdaIw6bz4LcXWR7h9Sy9Nga1fj8L44cytYqIhZhvyCqoTm96gvgZJFqPkqwKfd8Bbx4y X-Received: by 2002:a17:906:368e:: with SMTP id a14mr17778968ejc.60.1625563635257; Tue, 06 Jul 2021 02:27:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1625563635; cv=none; d=google.com; s=arc-20160816; b=heI4zSSI08+eDzHE/xTdPvqQzBWcZWwWjT8o3fhat+W6kEK7uDfDZRvdylB4NJusqc jIk0inyCBF9shpDttMBpgcb+pg/v6yHaf73dev9BbQoXo15j9g7D0oSHxhgNDaMa5w+0 B0W2qiLhjC8PBZ6LY0jrBXwyr8iFqA8ooKRy12YkUtT5XGZexfbhIh105z8gr0RVntAS sENcl+PWy2vAAF2MTEnk7YCyKEUWvRMJsW0sPNgfB/7pWNejeBIU8y6gt/GIE1/ByWkG Zw5QT/MIRnjYyjpGP3HwcwI8yjaXdVWHgiaHzYzueZQOdFpmmnNMWM6RDtpKxFh9MeZF Lq9g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=Ov+l6LN72ABgZ1q0m9l7Z0DIdNTE+ehxX4Wv7SlVA48=; b=Wv5aoBptJNiLxCk2eK9cKWdZRrD2NxB2ByjNHW83Pe+QnR6yo9O0vRhVy4DKtLNkvi S1NADeKP1hWd3xOrk6IZFhyfoQw21TeLVELTIHQ7m7Ea3p8wcLinvoq9opz4QouNnmnr wt84eMEf8YDT7+c4Qrc5riViG7rJbGKU2J2ouiV28cjQynH3kgqBSzhf0k3EtPSVH1Ci gKyIek0EjEzJ+xjS0sDkSL0E85YynZdwjKPGJD9WajWBgx6ptCP44mW1esQmiQ6SxWID z4m33ZsB07YmGerxFYCOokSrElC/69X8RF0XraKFcO/Az9lvgR6fFJkNySGec5gyXyuB UpPQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=VBboW4dk; 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; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id v10si7370690edc.102.2021.07.06.02.27.14; Tue, 06 Jul 2021 02:27:15 -0700 (PDT) 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; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=VBboW4dk; 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; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id B32D268A92D; Tue, 6 Jul 2021 12:26:59 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lj1-f178.google.com (mail-lj1-f178.google.com [209.85.208.178]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 9D71A68A942 for ; Tue, 6 Jul 2021 12:26:52 +0300 (EEST) Received: by mail-lj1-f178.google.com with SMTP id p24so28267973ljj.1 for ; Tue, 06 Jul 2021 02:26:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=x5pNMmtBjj7YYadN3yHFja2qtYgfPbldNY7RuVICA8U=; b=VBboW4dk0d0Z0FFNdTOP9ahSwf/0Rl3l5bSz/BCpdY2FkzxIHRP8kVP2ZncIUDYh1O uOBRuwekwtOELYN/stxVlr0GhxFsIGK5//oTaVLHWdMmmx1l/7ahEfHNFBNQIFUhdI1g Drk7m8WYGQakh4a0yf0Hr7bAmnkCRp6v9omOkkob+daoZvP3osya2YItcEn6jmOLxEXv W1RbVaq3xhTQt0pITgV57BMporWR+VBZRWh6WyLy5YKJX5/toYNMMbmzCab+KBxyVckF ow6uVzeVQ3MAxNdgVsGIMOpd48fnu+20gP8t9D8sdoF+bDJDqLOqs7xPfKQPrFka3Pa2 7IKw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=x5pNMmtBjj7YYadN3yHFja2qtYgfPbldNY7RuVICA8U=; b=ZI3qSTWqpJv7kGLNn5Ex26W3zyPoKBsxfSC61VSaXxnmM/Hdot+OxSqIfnGcgBDSLm ZpgsW6Z8SC8K0UypbTwOGxbFaXci3GKndLc9ZIozRhc7Su6bKKqVOFPk9VG406uVW0CT 72VpZyG5CJtx6OabZGwux+MVMHh7D9FJIy7+Bf5WY8px80X2vqCjczCJ4NSQ5It/kaZw NTOWd1fJqJXHr2WIGNAvUEKcvCrOtOktmKWSZgph8DOTA7JzWeW5K4ufhF1J7m3URUN9 9mUVGZtfifEHr8be3Zwtg+1TK8B0v2ysUA3PHkzXMj5GwxMrri69EZkxus/yCw84VqmH 6Fow== X-Gm-Message-State: AOAM531DZq1I3e52E3KnSxdMr1w+8jnypGS96RS/TCCDdX7DUAagP77o h1wwClYiz8MDfVPWgZgloTX+COJH3AA= X-Received: by 2002:a2e:b4b8:: with SMTP id q24mr4062780ljm.241.1625563611665; Tue, 06 Jul 2021 02:26:51 -0700 (PDT) Received: from localhost.localdomain (deedock.humlab.lu.se. [130.235.135.183]) by smtp.gmail.com with ESMTPSA id p15sm226173lfr.88.2021.07.06.02.26.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 Jul 2021 02:26:51 -0700 (PDT) From: Diederick Niehorster To: ffmpeg-devel@ffmpeg.org Date: Tue, 6 Jul 2021 11:20:17 +0200 Message-Id: <20210706092020.1057-32-dcnieho@gmail.com> X-Mailer: git-send-email 2.28.0.windows.1 In-Reply-To: <20210706092020.1057-1-dcnieho@gmail.com> References: <20210706092020.1057-1-dcnieho@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 31/34] doc/examples: adding device_get_capabilities example 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 Cc: Diederick Niehorster Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: f5XOEM/fyXdo This example also shows use of get_device_list API. Also improve capability API doc in avdevice.h: now point to this example instead of rough example code given in the header. Signed-off-by: Diederick Niehorster --- configure | 2 + doc/examples/.gitignore | 1 + doc/examples/Makefile | 1 + doc/examples/Makefile.example | 1 + doc/examples/device_get_capabilities.c | 243 +++++++++++++++++++++++++ libavdevice/avdevice.h | 33 +--- 6 files changed, 249 insertions(+), 32 deletions(-) create mode 100644 doc/examples/device_get_capabilities.c diff --git a/configure b/configure index b124411609..ab5d6fee30 100755 --- a/configure +++ b/configure @@ -1706,6 +1706,7 @@ EXAMPLE_LIST=" decode_audio_example decode_video_example demuxing_decoding_example + device_get_capabilities_example encode_audio_example encode_video_example extract_mvs_example @@ -3716,6 +3717,7 @@ avio_reading_deps="avformat avcodec avutil" decode_audio_example_deps="avcodec avutil" decode_video_example_deps="avcodec avutil" demuxing_decoding_example_deps="avcodec avformat avutil" +device_get_capabilities_example_deps="avdevice avformat avutil" encode_audio_example_deps="avcodec avutil" encode_video_example_deps="avcodec avutil" extract_mvs_example_deps="avcodec avformat avutil" diff --git a/doc/examples/.gitignore b/doc/examples/.gitignore index 44960e1de7..256f33a600 100644 --- a/doc/examples/.gitignore +++ b/doc/examples/.gitignore @@ -3,6 +3,7 @@ /decode_audio /decode_video /demuxing_decoding +/device_get_capabilities /encode_audio /encode_video /extract_mvs diff --git a/doc/examples/Makefile b/doc/examples/Makefile index 81bfd34d5d..de707bb3ca 100644 --- a/doc/examples/Makefile +++ b/doc/examples/Makefile @@ -3,6 +3,7 @@ EXAMPLES-$(CONFIG_AVIO_READING_EXAMPLE) += avio_reading EXAMPLES-$(CONFIG_DECODE_AUDIO_EXAMPLE) += decode_audio EXAMPLES-$(CONFIG_DECODE_VIDEO_EXAMPLE) += decode_video EXAMPLES-$(CONFIG_DEMUXING_DECODING_EXAMPLE) += demuxing_decoding +EXAMPLES-$(CONFIG_DEVICE_GET_CAPABILITIES_EXAMPLE) += device_get_capabilities EXAMPLES-$(CONFIG_ENCODE_AUDIO_EXAMPLE) += encode_audio EXAMPLES-$(CONFIG_ENCODE_VIDEO_EXAMPLE) += encode_video EXAMPLES-$(CONFIG_EXTRACT_MVS_EXAMPLE) += extract_mvs diff --git a/doc/examples/Makefile.example b/doc/examples/Makefile.example index a232d97f98..b861b9cc74 100644 --- a/doc/examples/Makefile.example +++ b/doc/examples/Makefile.example @@ -16,6 +16,7 @@ EXAMPLES= avio_list_dir \ decode_audio \ decode_video \ demuxing_decoding \ + device_get_capabilities \ encode_audio \ encode_video \ extract_mvs \ diff --git a/doc/examples/device_get_capabilities.c b/doc/examples/device_get_capabilities.c new file mode 100644 index 0000000000..45eb2eadf4 --- /dev/null +++ b/doc/examples/device_get_capabilities.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2021 Diederick Niehorster + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/** + * @file + * avdevice getting capabilities example. + * + * Shows how to use the avdevice capabilities API to probe + * device capabilities (supported codecs, pixel formats, sample + * formats, resolutions, channel counts, etc) + * @example device_get_capabilities.c + */ + +#include +#include +#include +#include +#include + +int print_option_ranges(enum AVOptionType type, AVOptionRanges *ranges) +{ + for (int range_index = 0; range_index < ranges->nb_ranges; range_index++) { + int ret; + char *out_val = NULL; + AVBPrint bp; + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); + for (int component_index = 0; component_index < ranges->nb_components; component_index++) + { + AVOptionRange* range = ranges->range[ranges->nb_ranges * component_index + range_index]; + if (component_index > 0) + av_bprintf(&bp, ", "); + av_bprintf(&bp, "%s: ", range->str); + if (range->value_min > range->value_max) + av_bprintf(&bp, ""); + else { + avdevice_capabilities_bprint_num(&bp, range->str, range->value_min); + if (range->is_range) { + av_bprintf(&bp, " -- "); + avdevice_capabilities_bprint_num(&bp, range->str, range->value_max); + } + } + } + if (!av_bprint_is_complete(&bp)) + return AVERROR(ENOMEM); + if ((ret = av_bprint_finalize(&bp, &out_val)) < 0) + return ret; + printf("%s\n", out_val); + av_freep(&out_val); + } + + return 0; +} + +void list_queries() +{ + const AVOption *opt = NULL; + const AVClass *class = avdevice_capabilities_get_class(); + while (opt = av_opt_next(&class, opt)) + fprintf(stderr, " %s\n", opt->name); +} + +void list_device_sources(const AVInputFormat *fmt) +{ + int ret; + AVDeviceInfoList *device_list = NULL; + + if (!fmt || !fmt->priv_class || !AV_IS_INPUT_DEVICE(fmt->priv_class->category)) + return; + + if (!fmt->get_device_list) { + ret = AVERROR(ENOSYS); + fprintf(stderr, " Cannot list sources. Not implemented.\n"); + return; + } + + if ((ret = avdevice_list_input_sources(fmt, NULL, NULL, &device_list)) < 0) { + fprintf(stderr, " Cannot list sources.\n"); + return; + } + + for (int i = 0; i < device_list->nb_devices; i++) { + const AVDeviceInfo *device = device_list->devices[i]; + fprintf(stderr, " %s %s (", device_list->default_device == i ? "*" : " ", device->device_name); + if (device->nb_media_types > 0 && device->media_types) { + for (int j = 0; j < device->nb_media_types; ++j) { + const char* media_type = av_get_media_type_string(device->media_types[j]); + if (j > 0) + fprintf(stderr, ", "); + fprintf(stderr, "%s", media_type ? media_type : "unknown"); + } + } + else { + fprintf(stderr, "none"); + } + fprintf(stderr, ")\n"); + } + + avdevice_free_list_devices(&device_list); +} + + + +int main (int argc, char **argv) +{ + int ret = 0; + const char *device_name = NULL; + const char *input_name = NULL; + const char *query_cap = NULL; + const char *set_cap_name = NULL; + const char *set_cap_value = NULL; + + const AVInputFormat *fmt = NULL; + AVFormatContext *fmt_ctx = NULL; + AVDeviceCapabilitiesQuery *caps = NULL; + AVOptionRanges *ranges = NULL; + const AVOption *opt = NULL; + + if (argc != 6) { + fprintf(stderr, "usage: %s device_name input_name query_cap set_cap_name set_cap_value\n" + "API example program to show how to use the avdevice\n" + "capabilities API to probe device capabilities \n" + "(supported codecs, pixel formats, sample formats,\n" + "resolutions, channel counts, etc).\n\n" + "example invocation: " + "%s dshow video=\"Integrated Webcam\" frame_size pixel_format yuyv422", + argv[0], argv[0]); + exit(1); + } + device_name = argv[1]; + input_name = argv[2]; + query_cap = argv[3]; + set_cap_name = argv[4]; + set_cap_value = argv[5]; + + // make sure avdevices can be found among input and output formats + avdevice_register_all(); + // find specified device + fmt = av_find_input_format(device_name); + if (!fmt) { + fprintf(stderr, "Could not find the device '%s'\n",device_name); + ret = AVERROR(EINVAL); + goto end; + } + + // prepare device format context, and set device to query, + ret = avformat_alloc_input_context(&fmt_ctx, fmt, NULL); + if (ret < 0) { + fprintf(stderr, "Cannot allocate input format context\n"); + goto end; + } + fmt_ctx->url = av_strdup(input_name); + + // prepare query object, setting device options + ret = avdevice_capabilities_create(&caps, fmt_ctx, NULL); + if (ret < 0) { + fprintf(stderr, "avdevice_capabilities_create() failed. Possibly the input name you specified ('%s') is not available for this device ('%s').\n%s can access the following sources:\n", input_name, device_name, device_name); + list_device_sources(fmt); + goto end; + } + + // check capability to query, and get info about the return type + opt = av_opt_find(caps, query_cap, NULL, 0, 0); + if (!opt) { + fprintf(stderr, "Capability '%s' you wish to query is not available.\nYou can query the following capabilities:\n", query_cap); + list_queries(); + ret = AVERROR_OPTION_NOT_FOUND; + goto end; + } + + // query the capability without any filter set + ret = av_opt_query_ranges(&ranges, caps, opt->name, AV_OPT_MULTI_COMPONENT_RANGE); + if (ret < 0) { + fprintf(stderr, "av_opt_query_ranges() failed\n"); + goto end; + } + + // print results + ret = print_option_ranges(opt->type, ranges); + if (ret < 0) { + fprintf(stderr, "printing the AVOptionRanges failed\n"); + goto end; + } + av_opt_freep_ranges(&ranges); + + printf("=============\n"); + + // set one capability, which may filter out some returned capabilities + // (or all, if set to an invalid value) + ret = av_opt_set(caps, set_cap_name, set_cap_value, 0); + if (ret < 0) { + fprintf(stderr, "av_opt_set() failed when trying to set the capability '%s'. Possibly it is not available.\nYou can set the following capabilities:\n", set_cap_name); + list_queries(); + goto end; + } + + // query again + ret = av_opt_query_ranges(&ranges, caps, opt->name, AV_OPT_MULTI_COMPONENT_RANGE); + if (ret < 0) { + fprintf(stderr, "av_opt_query_ranges() failed\n"); + goto end; + } + + // print results + print_option_ranges(opt->type, ranges); + + +end: + if (ranges) + av_opt_freep_ranges(&ranges); + if (caps) + avdevice_capabilities_free(&caps, fmt_ctx); + + if (fmt_ctx) + avformat_free_context(fmt_ctx); + + if (ret < 0) { + char a[AV_ERROR_MAX_STRING_SIZE] = { 0 }; + av_make_error_string(a, AV_ERROR_MAX_STRING_SIZE, ret); + + printf("Error: %s\n", a); + } + + return ret < 0; +} diff --git a/libavdevice/avdevice.h b/libavdevice/avdevice.h index 11d1a6ae12..67572db992 100644 --- a/libavdevice/avdevice.h +++ b/libavdevice/avdevice.h @@ -368,38 +368,7 @@ int avdevice_dev_to_app_control_message(struct AVFormatContext *s, * For example, setting a codec may impact number of formats or fps values * returned during next query. Setting invalid value may limit results to zero. * - * Example of the usage basing on opengl output device: - * - * @code - * AVFormatContext *oc = NULL; - * AVDeviceCapabilitiesQuery *caps = NULL; - * AVOptionRanges *ranges; - * int ret; - * - * if ((ret = avformat_alloc_output_context2(&oc, NULL, "opengl", NULL)) < 0) - * goto fail; - * if (avdevice_capabilities_create(&caps, oc, NULL) < 0) - * goto fail; - * - * //query codecs - * if (av_opt_query_ranges(&ranges, caps, "codec", AV_OPT_MULTI_COMPONENT_RANGE)) < 0) - * goto fail; - * //pick codec here and set it - * av_opt_set(caps, "codec", AV_CODEC_ID_RAWVIDEO, 0); - * - * //query format - * if (av_opt_query_ranges(&ranges, caps, "pixel_format", AV_OPT_MULTI_COMPONENT_RANGE)) < 0) - * goto fail; - * //pick format here and set it - * av_opt_set(caps, "pixel_format", AV_PIX_FMT_YUV420P, 0); - * - * //query and set more capabilities - * - * fail: - * //clean up code - * avdevice_capabilities_free(&query, oc); - * avformat_free_context(oc); - * @endcode + * @see examples/device_get_capabilities.c */ typedef struct AVDeviceCapabilitiesQuery AVDeviceCapabilitiesQuery;