From patchwork Wed Mar 30 12:18:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Diederick C. Niehorster" X-Patchwork-Id: 35073 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:c05:b0:7a:e998:b410 with SMTP id bw5csp774948pzb; Wed, 30 Mar 2022 05:21:47 -0700 (PDT) X-Google-Smtp-Source: ABdhPJx7OdXBNGM4YfAFzKAIQxuHzcXMEbWov4UoBMYig5Q5CLyUZLPucUc+YiXVE/dq9seDd8yb X-Received: by 2002:aa7:c759:0:b0:419:896:271b with SMTP id c25-20020aa7c759000000b004190896271bmr10194783eds.98.1648642907292; Wed, 30 Mar 2022 05:21:47 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1648642907; cv=none; d=google.com; s=arc-20160816; b=pjMpJxX/oeHqQNm6p+FRvefX0zAbt3Z6TDr48XOYbl7b2t8wWB7ZLK/vbHOZP2uN7+ Rb2N1bE0K8rBT82VOdiAY/dSNXfLf/PdEAwCIY3wPjCyff74StCWC+32BstbcyEKFyEa R0cDGO5gdQS9NbK1pR1g06uXLHIIWlQ1KleO/cr/gyAt00qGx5h8+jVSybYoZsAbwQdv wzhXMcDhKFDct4bQf31ERk5i03spk3mQsvj5Uj8f+8Tu1MSGNZFp8F+ATRUJXY9lAUW0 VctNYlV/MiTMWXnj76rEnpDdhBrsgj388CQYNRTTRibcRGxWvZVP+QER0IYfH/YB6G3K a3vw== 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=dNv3vsHS6Oav+cR5WaqweaFBwvvmKr6e9gBCMaIUXuI=; b=dLwhPSkrdnMLOc6plKCxunERH10nSijkq7AuAMg+GLdLeiz66EMA7hnHvgKEqvMvt7 aEeRRt1QNIXloZvOrfTZlHdn7YUBxMHu9aARGeIqVYS3n1eQ1uwpxNeqrJUPMPL0a+6K xFpcv8l1QXm8l4vy6Z05XyMFoqJ4mGptBNY2tfD3/5VmvawfuIy5cq1ZDn5p/ed5FpVF OlNOh2TqBSnINFeUibAYvYJnO0U/ub0KdgFu8XcO5sBWSc34Yk1Is1JndL9+jtsFyn/O NcyRs8KmtBKvWdSYGMXhR4oXjqktvZKV3lNXL907TbJVEMkKAeHpv2Az2IAnf+h2Y6ri O1ug== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=fdHh12EX; 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 c1-20020a170906924100b006df76385e5bsi19482054ejx.763.2022.03.30.05.21.46; Wed, 30 Mar 2022 05:21:47 -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=20210112 header.b=fdHh12EX; 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 404DF68B21A; Wed, 30 Mar 2022 15:20:28 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lj1-f182.google.com (mail-lj1-f182.google.com [209.85.208.182]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id EFFC468B1E2 for ; Wed, 30 Mar 2022 15:20:25 +0300 (EEST) Received: by mail-lj1-f182.google.com with SMTP id c15so27391757ljr.9 for ; Wed, 30 Mar 2022 05:20:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ruk9BoVt3V2PXiF0fWjSKbmWOBG+NGE61kG4/Yh7IXg=; b=fdHh12EXUzFr7d7P+Wn04sK2thSyUnr4RJKFU0GrXkvJ/kq9Xre1iHKS2XhKQkYQtI 6pvxg49fZZsqOYVdf/NWmOTmMKoJzktG17zJRl/WlAH2KnOToNKk+DI0p4uw7elCn2A3 QPYawTHnKxIhQFiWPNmRKBiqRF/RaWFP/S84HbbTkK/GzzfgUK5JU+/2fOk+08nWaxyN ecllBymPDFgcyDiS2PPssAq924pm5MbJDq/VcydeR0c+6HYHAm1spI2zw55n4kOVp7rB RKTrVmpbJABG6V/TUUv77/ijSvjck40xIZm/RQkJjKLASxmxkM82mXuF+tt+kUjo45Nw bL9A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ruk9BoVt3V2PXiF0fWjSKbmWOBG+NGE61kG4/Yh7IXg=; b=XaeRTkxWOLOkftphSTl9quYfIKkkbeuVS6aYPMjotf+15ckqMqXKNpjR07EZthMLUU RwyqGbTxTsGMtJeDOagNITnZmYe6PlqYVHvOgx8ibnDZa8VB5Cm+KqLy2p+ov17nqWFd 5bX38SldE70yeMFdMvuNy4R7XxM1y++Kxp9vGIe+BI9vU5b4lq/GEYYgOFVD5nWLWm3d sw7Y+psNCzdn7bNUTYmomR/r8ZZCpEYO9sDPuoanVzLYGvMlAvXmtwS6xvTDsWk91Vcx vEXVpQWec6kSNPKo0IIV8isCLKMdMeEIo8AmvjqavDdoIwOcWabxJlpuJstmkiK9bo5E dD4Q== X-Gm-Message-State: AOAM531BjhqGN0JPh5WYvtIhkW8YSdH5KaVWp7IIwwVvsutISiBZmb4r ds35Hz95VVwAf6v3l1jW5GeD/W2U2JU= X-Received: by 2002:a2e:a0c3:0:b0:247:eba1:366b with SMTP id f3-20020a2ea0c3000000b00247eba1366bmr6198787ljm.190.1648642824951; Wed, 30 Mar 2022 05:20:24 -0700 (PDT) Received: from localhost.localdomain (deedock.humlab.lu.se. [130.235.135.183]) by smtp.gmail.com with ESMTPSA id i8-20020a0565123e0800b0044a74e0954dsm1804515lfv.66.2022.03.30.05.20.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Mar 2022 05:20:24 -0700 (PDT) From: Diederick Niehorster To: ffmpeg-devel@ffmpeg.org Date: Wed, 30 Mar 2022 14:18:04 +0200 Message-Id: <20220330121806.822-20-dcnieho@gmail.com> X-Mailer: git-send-email 2.28.0.windows.1 In-Reply-To: <20220330121806.822-1-dcnieho@gmail.com> References: <20220330121806.822-1-dcnieho@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v5 19/21] 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: uRSknAy9m2Ok 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 e4d36aa639..be78a2119e 100755 --- a/configure +++ b/configure @@ -1726,6 +1726,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 @@ -3751,6 +3752,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..1cfbca64eb --- /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 + +static 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; +} + +static void list_queries(void) +{ + const AVOption *opt = NULL; + const AVClass *class = avdevice_capabilities_get_class(); + while (opt = av_opt_next(&class, opt)) + fprintf(stderr, " %s\n", opt->name); +} + +static 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 5f9dfccc34..c29d8940a5 100644 --- a/libavdevice/avdevice.h +++ b/libavdevice/avdevice.h @@ -384,38 +384,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;