From patchwork Thu Jun 3 22:45:49 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: 28072 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a6b:b214:0:0:0:0:0 with SMTP id b20csp537830iof; Thu, 3 Jun 2021 15:46:41 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwbvVSUDyCLemftjrKeopQF/fwTQmFZlnhqr+BaLqBThhn7aoZnCx6dJ4uZoAcENxoLnj3A X-Received: by 2002:a17:906:394e:: with SMTP id g14mr1377042eje.3.1622760401108; Thu, 03 Jun 2021 15:46:41 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1622760401; cv=none; d=google.com; s=arc-20160816; b=fbNI6k8PtE9A70w5OayNtzEpBKDvTaqmX/3jM2wHcGybOSDW3DGFEmwrhn/6BBH1Vl 94t+OJ8G+tUSSUf4XYlxzRi8+dIKt/ZUvbfRH++uHuoFGiH/rsA8Zda7YKTn5ZsJndF8 KcwaGh7FtEldTNc7nozyEao4RnDOAZESYMnEie2nOTrZmy9hDnKAC/QzQXbiuwGV9nqi gvRdnOm4CRKUOP7OY7KZdPuxX3QSYRxH5yFc8hFnPP3jSLtcMaRgPATJO9krDfXD1GT3 2nOUalX2ojy8mH7GWt7vU9sAX2k/7+vbRpeD+ySQNIvDiQLvlFRtWI3V+p/DiWwUoTrh Ve9g== 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=9h5LEh02A5QKiIdko5CyhLQ0xipVhXpOIEmNR1JRTIc=; b=TBWqKbIqn7Pp3MrwlwLhaXwqgumYmkQ+hWmRy6tmvI6lgj5qbJ6+zNBrQc3hU1ajG2 tDjdvzytd3AxKTRTECLNZ2+uPe3tL4E4CHm8NBNoMlilivTrjeR1ZMbPL6jr8AHZZp6X YNcV84HlkYIqSPH2uux4BNILnRXJxbUtTudoaLEjWg2rAQKs6H9vf2jF4zzsOJq77SRN d6JUQauWVMLVg5AFH/PvO7KQjRBjrbsjPHCD9zcE3JobedGctPfmBbpvrwbOh1WV+xbX is3DVmhn7gJIbxF81hhD81aub76VxonX5t2doSdrHdCoKLTtCTx+NYSJqUSSbKF8zgig PPSQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=gjwHgJA4; 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 mp18si2867557ejc.543.2021.06.03.15.46.40; Thu, 03 Jun 2021 15:46:41 -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=gjwHgJA4; 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 8AE1968A2B3; Fri, 4 Jun 2021 01:46:30 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lf1-f46.google.com (mail-lf1-f46.google.com [209.85.167.46]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id C9EFB68921B for ; Fri, 4 Jun 2021 01:46:23 +0300 (EEST) Received: by mail-lf1-f46.google.com with SMTP id f30so11225988lfj.1 for ; Thu, 03 Jun 2021 15:46:23 -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=Alnixg7Ry7smcJazqYVdR3Ws88UD/RXxXTCKnlxa1XA=; b=gjwHgJA42iCmA9EX0JnOdyrZmzrmkkbFwDMEHg21/N2H4HqwDk8W0tkX3JSev7hOxM PEr3WKph6ny6KC0dwYTPbw1Sm8plJmDYCHBsoxgoHdYdCekPgulN8NJoBOfR/6iWK34m e0jG30z9I5agkBQDIVCniOg3m+CQhmjlUkSpPifct2hpH4OX0XGWQIt5iw4XRH4Eiqtt 35jcwjh9lxGAyPC+Y8PaT60mlQkJvF7lxhGr7HpXyEJ3YOLCZko0q975T22XH8rSILYH YQEGlA9JLjvV9aeObPnBkab9HbU5OJtS7pFkJucki3EIlEArFvxE1q5tE31AyIJBhVKx cilw== 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=Alnixg7Ry7smcJazqYVdR3Ws88UD/RXxXTCKnlxa1XA=; b=cvzDcAR2dPzGvaVz4UcbAln20Z1w3NN/Sc94xLFbcf1r4mFN4ZaNvg/8lLUdrjHjcn 3I4ezJaFrKSCVRlXwfh/Kluvmee1/WjzdQ+tLLvdSIQcL2R7REfHAYFWYNu89jcVSVhK 4r5vkgizpPGRFI/yqD34MidUWO7N+2cP1HUup3jtPqO65JVAGpMggK+Mgt978eqX0GCG IXfNMjGiJbGzTyQ1ZLKZfV6Zmlrmdye3CCX2y/TZY/7Jua3ZVbaUVhVcIiC17EZYJ0uy HDn2Watr4uBNo7at9wzQYt5mrMkvFivk3vhqC5BibZr8/AeQvLyY/aYJeeJgPTTB/+wP 5VAg== X-Gm-Message-State: AOAM533sktxAJcO66v7BYo/oFDtsOgS/9TNcvVyYJdQ/ILYvVxQ/uezF wt8irAenLAVE3hUmwmVWoqUH7acmQtQ= X-Received: by 2002:a05:6512:3990:: with SMTP id j16mr737184lfu.367.1622760382728; Thu, 03 Jun 2021 15:46:22 -0700 (PDT) Received: from localhost.localdomain (84-217-56-54.customers.ownit.se. [84.217.56.54]) by smtp.gmail.com with ESMTPSA id t15sm82373lfp.176.2021.06.03.15.46.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jun 2021 15:46:22 -0700 (PDT) From: Diederick Niehorster To: ffmpeg-devel@ffmpeg.org Date: Fri, 4 Jun 2021 00:45:49 +0200 Message-Id: <20210603224552.1218-2-dcnieho@gmail.com> X-Mailer: git-send-email 2.28.0.windows.1 In-Reply-To: <20210603224552.1218-1-dcnieho@gmail.com> References: <20210603224552.1218-1-dcnieho@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 1/4] avdevice/avdevice: Revert "Deprecate AVDevice Capabilities API" 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: j8iWGKYM5gGH This reverts commit 4f49ca7bbc75a9db4cdf93f27f95a668c751f160. This patch series will implement this capability for avdevice/dshow, enabling configuration discovery of DirectShow devices through the API, which is important for my use case. It enables making proper GUIs presenting users with options, instead of asking them to discover a dshow devices capabilities through the list_options option with an ffmpeg tool, and listing what they want to configure in text boxes. Signed-off-by: Diederick Niehorster --- doc/APIchanges | 4 +++ libavdevice/avdevice.c | 71 ++++++++++++++++++++++++++++++++++++++---- libavdevice/avdevice.h | 5 --- libavdevice/version.h | 5 +-- libavformat/avformat.h | 21 +++++++++++++ 5 files changed, 91 insertions(+), 15 deletions(-) diff --git a/doc/APIchanges b/doc/APIchanges index c46f4d5304..30c0e7bf3f 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -14,6 +14,10 @@ libavutil: 2021-04-27 API changes, most recent first: +2021-xx-xx - xxxxxxxxxx - lavd 58.xx.100 - avdevice.h + Un-deprecated avdevice_capabilities_create() and + avdevice_capabilities_free(). + 2021-04-27 - cb3ac722f4 - lavc 59.0.100 - avcodec.h Constified AVCodecParserContext.parser. diff --git a/libavdevice/avdevice.c b/libavdevice/avdevice.c index 22b7595ab1..371ec17d02 100644 --- a/libavdevice/avdevice.c +++ b/libavdevice/avdevice.c @@ -27,11 +27,39 @@ #include "libavutil/ffversion.h" const char av_device_ffversion[] = "FFmpeg version " FFMPEG_VERSION; -#if FF_API_DEVICE_CAPABILITIES +#define E AV_OPT_FLAG_ENCODING_PARAM +#define D AV_OPT_FLAG_DECODING_PARAM +#define A AV_OPT_FLAG_AUDIO_PARAM +#define V AV_OPT_FLAG_VIDEO_PARAM +#define OFFSET(x) offsetof(AVDeviceCapabilitiesQuery, x) + const AVOption av_device_capabilities[] = { + { "codec", "codec", OFFSET(codec), AV_OPT_TYPE_INT, + {.i64 = AV_CODEC_ID_NONE}, AV_CODEC_ID_NONE, INT_MAX, E|D|A|V }, + { "sample_format", "sample format", OFFSET(sample_format), AV_OPT_TYPE_SAMPLE_FMT, + {.i64 = AV_SAMPLE_FMT_NONE}, AV_SAMPLE_FMT_NONE, INT_MAX, E|D|A }, + { "sample_rate", "sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, + {.i64 = -1}, -1, INT_MAX, E|D|A }, + { "channels", "channels", OFFSET(channels), AV_OPT_TYPE_INT, + {.i64 = -1}, -1, INT_MAX, E|D|A }, + { "channel_layout", "channel layout", OFFSET(channel_layout), AV_OPT_TYPE_CHANNEL_LAYOUT, + {.i64 = -1}, -1, INT_MAX, E|D|A }, + { "pixel_format", "pixel format", OFFSET(pixel_format), AV_OPT_TYPE_PIXEL_FMT, + {.i64 = AV_PIX_FMT_NONE}, AV_PIX_FMT_NONE, INT_MAX, E|D|V }, + { "window_size", "window size", OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE, + {.str = NULL}, -1, INT_MAX, E|D|V }, + { "frame_size", "frame size", OFFSET(frame_width), AV_OPT_TYPE_IMAGE_SIZE, + {.str = NULL}, -1, INT_MAX, E|D|V }, + { "fps", "fps", OFFSET(fps), AV_OPT_TYPE_RATIONAL, + {.dbl = -1}, -1, INT_MAX, E|D|V }, { NULL } }; -#endif + +#undef E +#undef D +#undef A +#undef V +#undef OFFSET unsigned avdevice_version(void) { @@ -66,18 +94,49 @@ int avdevice_dev_to_app_control_message(struct AVFormatContext *s, enum AVDevToA return s->control_message_cb(s, type, data, data_size); } -#if FF_API_DEVICE_CAPABILITIES int avdevice_capabilities_create(AVDeviceCapabilitiesQuery **caps, AVFormatContext *s, AVDictionary **device_options) { - return AVERROR(ENOSYS); + int ret; + av_assert0(s && caps); + av_assert0(s->iformat || s->oformat); + if ((s->oformat && !s->oformat->create_device_capabilities) || + (s->iformat && !s->iformat->create_device_capabilities)) + return AVERROR(ENOSYS); + *caps = av_mallocz(sizeof(**caps)); + if (!(*caps)) + return AVERROR(ENOMEM); + (*caps)->device_context = s; + if (((ret = av_opt_set_dict(s->priv_data, device_options)) < 0)) + goto fail; + if (s->iformat) { + if ((ret = s->iformat->create_device_capabilities(s, *caps)) < 0) + goto fail; + } else { + if ((ret = s->oformat->create_device_capabilities(s, *caps)) < 0) + goto fail; + } + av_opt_set_defaults(*caps); + return 0; + fail: + av_freep(caps); + return ret; } void avdevice_capabilities_free(AVDeviceCapabilitiesQuery **caps, AVFormatContext *s) { - return; + if (!s || !caps || !(*caps)) + return; + av_assert0(s->iformat || s->oformat); + if (s->iformat) { + if (s->iformat->free_device_capabilities) + s->iformat->free_device_capabilities(s, *caps); + } else { + if (s->oformat->free_device_capabilities) + s->oformat->free_device_capabilities(s, *caps); + } + av_freep(caps); } -#endif int avdevice_list_devices(AVFormatContext *s, AVDeviceInfoList **device_list) { diff --git a/libavdevice/avdevice.h b/libavdevice/avdevice.h index 8370bbc7f2..727ba2a5f3 100644 --- a/libavdevice/avdevice.h +++ b/libavdevice/avdevice.h @@ -321,7 +321,6 @@ int avdevice_dev_to_app_control_message(struct AVFormatContext *s, enum AVDevToAppMessageType type, void *data, size_t data_size); -#if FF_API_DEVICE_CAPABILITIES /** * Following API allows user to probe device capabilities (supported codecs, * pixel formats, sample formats, resolutions, channel counts, etc). @@ -417,7 +416,6 @@ typedef struct AVDeviceCapabilitiesQuery { /** * AVOption table used by devices to implement device capabilities API. Should not be used by a user. */ -attribute_deprecated extern const AVOption av_device_capabilities[]; /** @@ -437,7 +435,6 @@ extern const AVOption av_device_capabilities[]; * * @return >= 0 on success, negative otherwise. */ -attribute_deprecated int avdevice_capabilities_create(AVDeviceCapabilitiesQuery **caps, AVFormatContext *s, AVDictionary **device_options); @@ -447,9 +444,7 @@ int avdevice_capabilities_create(AVDeviceCapabilitiesQuery **caps, AVFormatConte * @param caps Device capabilities data to be freed. * @param s Context of the device. */ -attribute_deprecated void avdevice_capabilities_free(AVDeviceCapabilitiesQuery **caps, AVFormatContext *s); -#endif /** * Structure describes basic parameters of the device. diff --git a/libavdevice/version.h b/libavdevice/version.h index 6021a0dd65..a51692621f 100644 --- a/libavdevice/version.h +++ b/libavdevice/version.h @@ -28,7 +28,7 @@ #include "libavutil/version.h" #define LIBAVDEVICE_VERSION_MAJOR 59 -#define LIBAVDEVICE_VERSION_MINOR 0 +#define LIBAVDEVICE_VERSION_MINOR 1 #define LIBAVDEVICE_VERSION_MICRO 100 #define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \ @@ -46,8 +46,5 @@ * dropped at a future version bump. The defines themselves are not part of * the public API and may change, break or disappear at any time. */ -#ifndef FF_API_DEVICE_CAPABILITIES -#define FF_API_DEVICE_CAPABILITIES (LIBAVDEVICE_VERSION_MAJOR < 60) -#endif #endif /* AVDEVICE_VERSION_H */ diff --git a/libavformat/avformat.h b/libavformat/avformat.h index a28ac372da..77c3261e47 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -578,6 +578,16 @@ typedef struct AVOutputFormat { * @see avdevice_list_devices() for more details. */ int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list); + /** + * Initialize device capabilities submodule. + * @see avdevice_capabilities_create() for more details. + */ + int (*create_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); + /** + * Free device capabilities submodule. + * @see avdevice_capabilities_free() for more details. + */ + int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); enum AVCodecID data_codec; /**< default data codec */ /** * Initialize format. May allocate data here, and set any AVFormatContext or @@ -743,6 +753,17 @@ typedef struct AVInputFormat { */ int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list); + /** + * Initialize device capabilities submodule. + * @see avdevice_capabilities_create() for more details. + */ + int (*create_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); + + /** + * Free device capabilities submodule. + * @see avdevice_capabilities_free() for more details. + */ + int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); } AVInputFormat; /** * @} From patchwork Thu Jun 3 22:45:50 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: 28074 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a6b:b214:0:0:0:0:0 with SMTP id b20csp537938iof; Thu, 3 Jun 2021 15:46:50 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwt5WLwd48dngQs6gYABBLPLIDgi2Rjn1P0HOHo+R+xDXpGNYQ1a7kc8SFp9JWraa7l0SA6 X-Received: by 2002:a17:906:4f10:: with SMTP id t16mr1318040eju.337.1622760409788; Thu, 03 Jun 2021 15:46:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1622760409; cv=none; d=google.com; s=arc-20160816; b=gqdL0Lqc7YTIm7OTp4ec3hZ3kQ7ewqsMLiPk4UGegJiHhM9OKuXTC3PgoL+a146Fw4 SuUhu9OGXmiuhvs34CYeRBtIjWUZKQYnKWJKiDT1QxAKiNK1ll/aMxSI3vOAnZmOToVM cpLf5hs7dTfY0QNI4pW9yZZYYbg+ITjhYTqX7DBrSSYVPtaQCeAl30dukImQJH+nfvEV G2oECL0E4FDsDL24Z4l8IaYVFikvcXJ7/zOCUbkz0/zV8k85YI+apZt9xfYnuUHQQofd yZv3LZtdSDfKai8azc97137cKeJFA60vQyMSy4BWI+knGX+wFg7Fb+72z21JiiO+Ls5L iZVw== 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=GeVRf67AjPEeA+a12mk8khuUChSdWK3yOCGoW7AzFx0=; b=ByxMaTOsFmlYCjCp6h2DZfPaq6qQseA8sw0/3D9ydYmgX/mlpGMv/JgQUvTYHKLWIn H3CQb0F5GDg1kcRFKQhHG4BHc7pvtLml1rCHzuk92tQEu2vB14WDLC+RzdMNietwMHlf FaxyKcr7Gx1XRssCvF+nlCiIv3ZvDNE/57Lxg4wrQTrI7qq5Ud7e3ZcY0TxBMOibVFB1 XRm18J8VtxR4dMXk5poN4+okuS5/kWTsbTOr00qU3uvyzqfHpvg6tqZ0VuPJ99TJbqAi QXlNFDuM7hyieGd2umvGpKHJFBYG0xrOz6ZCL5AV/meJw5/Thxajzo4Utr3XGd6TY3/l QwVQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=FIa4oHM8; 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 f12si3201124edw.443.2021.06.03.15.46.49; Thu, 03 Jun 2021 15:46:49 -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=FIa4oHM8; 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 B36C868A295; Fri, 4 Jun 2021 01:46:31 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lj1-f180.google.com (mail-lj1-f180.google.com [209.85.208.180]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 620C668A252 for ; Fri, 4 Jun 2021 01:46:24 +0300 (EEST) Received: by mail-lj1-f180.google.com with SMTP id p20so9103160ljj.8 for ; Thu, 03 Jun 2021 15:46:24 -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=1ae63w35O7aEQokppDL1xRCwApuaVqPd/cT3Xr6Q45k=; b=FIa4oHM8s/eop58+BVbg9dpglaItQgKzUdo02UDxLYe09PwlAjamhwbaqIAS/AVoQb SWYi7egd1NF5PRuYLQfaJwkBNzwjzdA6sb4BeybdFnsSfav807eQNGJG6qecmVNJz5cI 8OgaHb0KWkNe+HdAXwnbmQeDVZPB0MzJ+6Ph1xU2TVcTMRcBU8jRTTy/WWlr0o0J4S0Y JkZBl1SjCCI9T+TOktjAOaU6EIfUgzoCTQ0w+jsP99gvGezAZYKMOQ+FSX3q7oV1mxHe ClBwbreZqqv8yvMYF5OZeLgRM12KL9/HB44Aj0iNNbBr33NCcW+9S1u4bpsoN8dwVrEN vLxw== 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=1ae63w35O7aEQokppDL1xRCwApuaVqPd/cT3Xr6Q45k=; b=JasZVQSbq3gF9gEqLsHjeVTVOFXlPkq9G7SnyuOfz9zhdQ6VnnFOct5TalC/fcaykT pdulieC4P27eJcnjMZOZJ1au4tMdKuJRw68z45QMvi3scKpBUgHVt1G4ujNrYXIsBMRa Ak2YRfPipupohGFqF9/PH/ppkSKO0guvCglD5jX1Fl9OktQR/ygSlxoXbBLFebWWelDh rGeG8CpoNavmGFZ0RYZJ2b13HCw/Hv4rNSdrt7DfmYQRXpsjs3TsKvMy5ESfAAdwJB73 dl94baJ1g3vICSIRHoooDLewJO9QHoe40lP7Ww8WD6GfulyDs0MvHlZI8E4zYxOuK40A 8P4A== X-Gm-Message-State: AOAM533QvbgyYWfp96d2SpVIzbd5eId2NMUL6bAzw/iuFaNZBvJe74Hc MxUKMbXmS3bcDm9JCtjBph2v8d74tJQ= X-Received: by 2002:a05:651c:2049:: with SMTP id t9mr1112131ljo.180.1622760383542; Thu, 03 Jun 2021 15:46:23 -0700 (PDT) Received: from localhost.localdomain (84-217-56-54.customers.ownit.se. [84.217.56.54]) by smtp.gmail.com with ESMTPSA id t15sm82373lfp.176.2021.06.03.15.46.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jun 2021 15:46:23 -0700 (PDT) From: Diederick Niehorster To: ffmpeg-devel@ffmpeg.org Date: Fri, 4 Jun 2021 00:45:50 +0200 Message-Id: <20210603224552.1218-3-dcnieho@gmail.com> X-Mailer: git-send-email 2.28.0.windows.1 In-Reply-To: <20210603224552.1218-1-dcnieho@gmail.com> References: <20210603224552.1218-1-dcnieho@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 2/4] avdevice/avdevice: clean up avdevice_capabilities_create 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: p2851Kqlm2zh Draw implementation in line with that of avdevice_list_devices Signed-off-by: Diederick Niehorster --- libavdevice/avdevice.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libavdevice/avdevice.c b/libavdevice/avdevice.c index 371ec17d02..2e64d35cf5 100644 --- a/libavdevice/avdevice.c +++ b/libavdevice/avdevice.c @@ -98,12 +98,15 @@ int avdevice_capabilities_create(AVDeviceCapabilitiesQuery **caps, AVFormatConte AVDictionary **device_options) { int ret; - av_assert0(s && caps); + av_assert0(s); + av_assert0(caps); av_assert0(s->iformat || s->oformat); if ((s->oformat && !s->oformat->create_device_capabilities) || - (s->iformat && !s->iformat->create_device_capabilities)) + (s->iformat && !s->iformat->create_device_capabilities)) { + *caps = NULL; return AVERROR(ENOSYS); - *caps = av_mallocz(sizeof(**caps)); + } + *caps = av_mallocz(sizeof(AVDeviceCapabilitiesQuery)); if (!(*caps)) return AVERROR(ENOMEM); (*caps)->device_context = s; From patchwork Thu Jun 3 22:45:51 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: 28071 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a6b:b214:0:0:0:0:0 with SMTP id b20csp538055iof; Thu, 3 Jun 2021 15:46:59 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxPdGtozAG/TIUnNcUcIrzX//fjESSPNpAcBxavbjqshsJl612Q8LZXmAdrvGgD7X0Co9F9 X-Received: by 2002:a05:6402:b6f:: with SMTP id cb15mr1653586edb.25.1622760419447; Thu, 03 Jun 2021 15:46:59 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1622760419; cv=none; d=google.com; s=arc-20160816; b=AhkmOAaaTAgSezZJIk0E0u4kk1Bz5suHubjWokbKJCq7op9bQ18RrqPw00bq+oKImB USw3di5IyzxipwzjyeCVwS1tmbVmklz/uyg8usj/frhvQvWib5ZIyqv5SPnt/COzgcS9 iXT+tTYKUxQ59lTuz7uedHePSLR+J19GzfueoKF9I8B7m+3G1ybzsDPxPcW6arRVbKJH Ab8I9TanneI1CBrPwB8QPatGXNIou8bBGSYdmmzp6jK+BuZjKfMpqutXrupcH1qD7M2d kIKzKsr6K+xt/iHwlhw95Pc6qgZkvo8rFlCkx2t0VASdNizUCCSRcYplBLMkP91zK5BG nL2A== 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=W5WvVP4XBuD/RVma6oeSLltTwu2E52w69962jdYCeas=; b=ErCIBXxUYV91YG3Rc3TzbPQw5k/vCCgcdwpN0yHcfE9gIPWzktkHT6g3JXEFzw7/aq DDsn+XXuVVparSPMxTBGuxtDZyJnrUudnRK3Kz3gBmL27aNqAl+4DXpZE5CNjcTsd157 AWHSCY7LFZsh++TjV67WhPDB5ZKy4dP1YltAV4yK5dkVeVICS4QHo90kHNPAZMIux6yr fn6xe6ReX5QSnzckGEVjazOx+4+McGXbK/1wcks2mT4+fFN6JQ9cP5c88mynnSn9Hk8H rqlKygdO9J/968/ekpPmLq0JAb3+mnCiwUAuKTCSchoJfntbdN0E8969TSPLHdZ5b47x a+qg== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=qCQ2Fu0C; 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 ch8si3093550edb.535.2021.06.03.15.46.59; Thu, 03 Jun 2021 15:46:59 -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=qCQ2Fu0C; 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 A65FF68A2CE; Fri, 4 Jun 2021 01:46:32 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lf1-f46.google.com (mail-lf1-f46.google.com [209.85.167.46]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id BBF4568A2BC for ; Fri, 4 Jun 2021 01:46:25 +0300 (EEST) Received: by mail-lf1-f46.google.com with SMTP id v22so9840796lfa.3 for ; Thu, 03 Jun 2021 15:46:25 -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=qePLRAslwWh43bV5keS+HlPYlH+olkr8nivIcuT1nQc=; b=qCQ2Fu0C/aCrx/+wIfiXgUH93NXo6ZO8Re4DsNpt+lW+htqHWWCtj0IfXbrS7zYWyb qUCLo4vH6qiGsWDlNlPPRW45pY1CHXQaHaG2tshHyNaaZSI+jZM0kAndFdxPBLMF6u5+ OWyM5XyP4bbHhpL2YuaOPrIlgmiUI9OOwcQzcye1RP2pN3bxhOeGqMDkI+/RF7MWmrTa b6pN1ndRXiA68EqacWDmotUz4nA+BKSI3Ydz+hYLAQPnKoeugFoJk0V3xi9YACvvZms1 VZT5PhW2axHRCMW73uk+aIc7lAm0Ujj4+LEu3IrWABpOjD6N1JNzo4vWEQS/ipCMSOgB Zmgg== 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=qePLRAslwWh43bV5keS+HlPYlH+olkr8nivIcuT1nQc=; b=f/XAHXWIQGliT9CrBhe83EzieKftJIQ3LWbB31N2sX7XTf/4lRzcb4eA7YnYW0/a6k WtvvlYQgJivqAgJrJfxZmQjG+X4x7wk3O0A5eQ140lb840q+0szrRPIWFi43XV8ncix8 2gN6eWHBcY1cUkp/2rJxtb1wmkC5+ecPzqXOFytxDqzP0gzQCe08aekobglbpdFrRRvP 0bwBeGDILMN9gtQxyEkziwWOvt1+dGTlO1QDVI+xNklFBF5IKPb7PjYtSHxkM7LL8ZTe UsV6J8M1KEb8Tnmm3G9ZxeBBoiKHf+6ED3sSur0MA/TzWsYHneKgFn1zLMs58JoTuKPC v5tg== X-Gm-Message-State: AOAM532wQaQWp+933sODc68q0GyZ/MVz1sf9YxLxHn1o691NRm05tRUJ gqEVQyYXiMsPe3TkIg4gU4ujCQiTxZU= X-Received: by 2002:a05:6512:1c3:: with SMTP id f3mr754027lfp.79.1622760384465; Thu, 03 Jun 2021 15:46:24 -0700 (PDT) Received: from localhost.localdomain (84-217-56-54.customers.ownit.se. [84.217.56.54]) by smtp.gmail.com with ESMTPSA id t15sm82373lfp.176.2021.06.03.15.46.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jun 2021 15:46:24 -0700 (PDT) From: Diederick Niehorster To: ffmpeg-devel@ffmpeg.org Date: Fri, 4 Jun 2021 00:45:51 +0200 Message-Id: <20210603224552.1218-4-dcnieho@gmail.com> X-Mailer: git-send-email 2.28.0.windows.1 In-Reply-To: <20210603224552.1218-1-dcnieho@gmail.com> References: <20210603224552.1218-1-dcnieho@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 3/4] avdevice/dshow: implement capabilities API 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: QDFwO0D2P/tG This implements avdevice_capabilities_create and avdevice_capabilities_free for the dshow device. Signed-off-by: Diederick Niehorster --- libavdevice/dshow.c | 498 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 462 insertions(+), 36 deletions(-) diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c index 8d0a6fcc09..c65492119e 100644 --- a/libavdevice/dshow.c +++ b/libavdevice/dshow.c @@ -30,6 +30,48 @@ #include "objidl.h" #include "shlwapi.h" +enum DshowCapQueryType { + CAP_QUERY_NONE = 0, + CAP_QUERY_SAMPLE_FORMAT, + CAP_QUERY_SAMPLE_RATE, + CAP_QUERY_CHANNELS, + CAP_QUERY_CODEC, + CAP_QUERY_PIXEL_FORMAT, + CAP_QUERY_FRAME_SIZE, + CAP_QUERY_FPS +}; +typedef struct DshowCapQueryTypeEntry { + const char* name; + enum DshowCapQueryType query_type; +} DshowCapQueryTypeEntry; + +static const DshowCapQueryTypeEntry query_table[] = { + { "sample_format", CAP_QUERY_SAMPLE_FORMAT }, + { "sample_rate", CAP_QUERY_SAMPLE_RATE }, + { "channels", CAP_QUERY_CHANNELS }, + { "codec", CAP_QUERY_CODEC }, + { "pixel_format", CAP_QUERY_PIXEL_FORMAT }, + { "frame_size", CAP_QUERY_FRAME_SIZE }, + { "fps", CAP_QUERY_FPS }, +}; + +static enum DshowCapQueryType dshow_get_query_type(const char* option_name) +{ + for (int i = 0; i < FF_ARRAY_ELEMS(query_table); ++i) { + if (!strcmp(query_table[i].name, option_name)) + return query_table[i].query_type; + } + return CAP_QUERY_NONE; +} + +static const char* dshow_get_query_type_string(enum DshowCapQueryType query_type) +{ + for (int i = 0; i < FF_ARRAY_ELEMS(query_table); ++i) { + if (query_table[i].query_type == query_type) + return query_table[i].name; + } + return NULL; +} static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount) { @@ -54,6 +96,26 @@ static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount) return avpriv_find_pix_fmt(avpriv_get_raw_pix_fmt_tags(), biCompression); // all others } +static enum AVCodecID waveform_codec_id(enum AVSampleFormat sample_fmt) +{ + switch (sample_fmt) { + case AV_SAMPLE_FMT_U8: return AV_CODEC_ID_PCM_U8; + case AV_SAMPLE_FMT_S16: return AV_CODEC_ID_PCM_S16LE; + case AV_SAMPLE_FMT_S32: return AV_CODEC_ID_PCM_S32LE; + default: return AV_CODEC_ID_NONE; /* Should never happen. */ + } +} + +static enum AVSampleFormat sample_fmt_bits_per_sample(int bits) +{ + switch (bits) { + case 8: return AV_SAMPLE_FMT_U8; + case 16: return AV_SAMPLE_FMT_S16; + case 32: return AV_SAMPLE_FMT_S32; + default: return AV_SAMPLE_FMT_NONE; /* Should never happen. */ + } +} + static int dshow_read_close(AVFormatContext *s) { @@ -317,10 +379,13 @@ fail1: * try to set parameters specified through AVOptions and if successful * return 1 in *pformat_set. * If pformat_set is NULL, list all pin capabilities. + * When listing pin capabilities, if ranges is NULL, output to log, + * else store capabilities in ranges. */ static void dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype, - IPin *pin, int *pformat_set) + IPin *pin, int *pformat_set, + AVOptionRanges *ranges, enum DshowCapQueryType query_type) { struct dshow_ctx *ctx = avctx->priv_data; IAMStreamConfig *config = NULL; @@ -338,7 +403,11 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype, if (!caps) goto end; - for (i = 0; i < n && !format_set; i++) { + for (i = 0; i < n && (!format_set || ranges); i++) { + AVOptionRange *range = NULL; + AVOptionRange **range_list = NULL; + int nb_range = 0; + r = IAMStreamConfig_GetStreamCaps(config, i, &type, (void *) caps); if (r != S_OK) goto next; @@ -365,7 +434,7 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype, } else { goto next; } - if (!pformat_set) { + if (!pformat_set && !ranges) { enum AVPixelFormat pix_fmt = dshow_pixfmt(bih->biCompression, bih->biBitCount); if (pix_fmt == AV_PIX_FMT_NONE) { enum AVCodecID codec_id = av_codec_get_id(tags, bih->biCompression); @@ -410,6 +479,81 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype, bih->biWidth = ctx->requested_width; bih->biHeight = ctx->requested_height; } + + if (ranges) { + if (query_type == CAP_QUERY_FRAME_SIZE) { + for (int j = 0; j < 3; j++) { + range = av_mallocz(sizeof(AVOptionRange)); + if (!range) + goto next; + range->str = av_strdup(j == 0 ? "pixel_count" : (j == 1 ? "width" : (j == 2 ? "height" : ""))); + if (!range->str) + goto next; + switch (j) + { + case 0: + range->value_min = vcaps->MinOutputSize.cx * vcaps->MinOutputSize.cy; + range->value_max = vcaps->MaxOutputSize.cx * vcaps->MaxOutputSize.cy; + break; + case 1: + range->value_min = vcaps->MinOutputSize.cx; + range->value_max = vcaps->MaxOutputSize.cx; + break; + case 2: + range->value_min = vcaps->MinOutputSize.cy; + range->value_max = vcaps->MaxOutputSize.cy; + break; + } + range->is_range = range->value_min != range->value_max; + + if (av_dynarray_add_nofree(&range_list, + &nb_range, range) < 0) + goto next; + range = NULL; // copied into array, make sure not freed below + } + } + else { + range = av_mallocz(sizeof(AVOptionRange)); + if (!range) + goto next; + range->str = av_strdup(dshow_get_query_type_string(query_type)); + if (!range->str) + goto next; + + switch (query_type) + { + case CAP_QUERY_CODEC: + if (dshow_pixfmt(bih->biCompression, bih->biBitCount) == AV_PIX_FMT_NONE) { + const AVCodecTag* const tags[] = { avformat_get_riff_video_tags(), NULL }; + range->value_min = av_codec_get_id(tags, bih->biCompression); + } + else + range->value_min = AV_CODEC_ID_RAWVIDEO; + range->value_max = range->value_min; + break; + case CAP_QUERY_PIXEL_FORMAT: + range->value_min = range->value_max = dshow_pixfmt(bih->biCompression, bih->biBitCount); + range->value_min; + break; + case CAP_QUERY_FPS: + range->value_min = 1e7 / vcaps->MaxFrameInterval; + range->value_max = 1e7 / vcaps->MinFrameInterval; + break; + + default: + // an audio property is being queried, output 0 + range->value_min = range->value_max = 0; + break; + } + + range->is_range = range->value_min != range->value_max; + + if (av_dynarray_add_nofree(&range_list, + &nb_range, range) < 0) + goto next; + range = NULL; // copied into array, make sure not freed below + } + } } else { AUDIO_STREAM_CONFIG_CAPS *acaps = caps; WAVEFORMATEX *fx; @@ -421,7 +565,7 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype, } else { goto next; } - if (!pformat_set) { + if (!pformat_set && !ranges) { av_log(avctx, AV_LOG_INFO, " min ch=%lu bits=%lu rate=%6lu max ch=%lu bits=%lu rate=%6lu\n", acaps->MinimumChannels, acaps->MinimumBitsPerSample, acaps->MinimumSampleFrequency, acaps->MaximumChannels, acaps->MaximumBitsPerSample, acaps->MaximumSampleFrequency); @@ -445,11 +589,90 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype, goto next; fx->nChannels = ctx->channels; } + + if (ranges) { + if (query_type == CAP_QUERY_FRAME_SIZE) { + for (int j = 0; j < 3; j++) { + range = av_mallocz(sizeof(AVOptionRange)); + if (!range) + goto next; + range->str = av_strdup(j == 0 ? "pixel_count" : (j == 1 ? "width" : (j == 2 ? "height" : ""))); + if (!range->str) + goto next; + // an video property is being queried, output 0 + range->value_min = range->value_max = 0; + range->is_range = 0; + + if (av_dynarray_add_nofree(&range_list, + &nb_range, range) < 0) + goto next; + range = NULL; // copied into array, make sure not freed below + } + } + else { + range = av_mallocz(sizeof(AVOptionRange)); + if (!range) + goto next; + range->str = av_strdup(dshow_get_query_type_string(query_type)); + if (!range->str) + goto next; + + switch (query_type) + { + case CAP_QUERY_SAMPLE_FORMAT: + range->value_min = sample_fmt_bits_per_sample(acaps->MinimumBitsPerSample); + range->value_max = sample_fmt_bits_per_sample(acaps->MaximumBitsPerSample); + break; + case CAP_QUERY_SAMPLE_RATE: + range->value_min = acaps->MinimumSampleFrequency; + range->value_max = acaps->MaximumSampleFrequency; + break; + case CAP_QUERY_CHANNELS: + range->value_min = acaps->MinimumChannels; + range->value_max = acaps->MaximumChannels; + break; + + default: + // an video property is being queried, output 0 + range->value_min = range->value_max = 0; + break; + } + + range->is_range = range->value_min != range->value_max; + + if (av_dynarray_add_nofree(&range_list, + &nb_range, range) < 0) + goto next; + range = NULL; // copied into array, make sure not freed below + } + } } if (IAMStreamConfig_SetFormat(config, type) != S_OK) goto next; + else if (ranges) { + // format matched and could be set successfully. Add capabilities to ranges output + for (int j=0; j< nb_range; ++j) { + if (av_dynarray_add_nofree(&ranges->range, + &ranges->nb_ranges, range_list[j]) < 0) + goto next; + range_list[j] = NULL; // copied into array, make sure not freed below + } + } format_set = 1; next: + if (range) { + av_freep(&range->str); + av_freep(&range); + } + if (range_list) { + for (int j = 0; j < nb_range; ++j) { + if (range_list[j]) { + av_freep(&range_list[j]->str); + av_freep(&range_list[j]); + } + } + av_freep(&range_list); + } if (type->pbFormat) CoTaskMemFree(type->pbFormat); CoTaskMemFree(type); @@ -558,10 +781,13 @@ end: * devtype, retrieve the first output pin and return the pointer to the * object found in *ppin. * If ppin is NULL, cycle through all pins listing audio/video capabilities. + * If ppin is not NULL and ranges is also not null, enumerate all formats + * supported by the selected pin. */ static int dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype, - enum dshowSourceFilterType sourcetype, IBaseFilter *device_filter, IPin **ppin) + enum dshowSourceFilterType sourcetype, IBaseFilter *device_filter, + IPin **ppin, AVOptionRanges *ranges, enum DshowCapQueryType query_type) { struct dshow_ctx *ctx = avctx->priv_data; IEnumPins *pins = 0; @@ -630,7 +856,7 @@ dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype, if (!ppin) { av_log(avctx, AV_LOG_INFO, " Pin \"%s\" (alternative pin name \"%s\")\n", name_buf, pin_buf); - dshow_cycle_formats(avctx, devtype, pin, NULL); + dshow_cycle_formats(avctx, devtype, pin, NULL, NULL, CAP_QUERY_NONE); goto next; } @@ -642,13 +868,13 @@ dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype, } } - if (set_format) { - dshow_cycle_formats(avctx, devtype, pin, &format_set); + if (set_format || ranges) { + dshow_cycle_formats(avctx, devtype, pin, &format_set, ranges, query_type); if (!format_set) { goto next; } } - if (devtype == AudioDevice && ctx->audio_buffer_size) { + if (devtype == AudioDevice && ctx->audio_buffer_size && !ranges) { if (dshow_set_audio_buffer_size(avctx, pin) < 0) { av_log(avctx, AV_LOG_ERROR, "unable to set audio buffer size %d to pin, using pin anyway...", ctx->audio_buffer_size); } @@ -673,8 +899,22 @@ next: IEnumMediaTypes_Release(types); if (p) IKsPropertySet_Release(p); - if (device_pin != pin) + if (device_pin != pin) { IPin_Release(pin); + // clear all ranges info again, wrong pin + if (ranges) { + for (int i = 0; i < ranges->nb_ranges; i++) { + AVOptionRange* range = ranges->range[i]; + if (range) { + av_freep(&range->str); + av_freep(&ranges->range[i]); + } + } + av_freep(&ranges->range); + ranges->nb_ranges = 0; + } + device_pin = NULL; + } av_free(name_buf); av_free(pin_buf); if (pin_id) @@ -706,17 +946,19 @@ next: */ static int dshow_list_device_options(AVFormatContext *avctx, ICreateDevEnum *devenum, - enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype) + enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype, + AVOptionRanges *ranges, enum DshowCapQueryType query_type) { struct dshow_ctx *ctx = avctx->priv_data; IBaseFilter *device_filter = NULL; + IPin *device_pin = NULL; char *device_unique_name = NULL; int r; if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter, &device_unique_name)) < 0) return r; ctx->device_filter[devtype] = device_filter; - if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, NULL)) < 0) + if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, ranges ? &device_pin : NULL, ranges, query_type)) < 0) return r; av_freep(&device_unique_name); return 0; @@ -800,7 +1042,7 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum, goto error; } - if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, &device_pin)) < 0) { + if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, &device_pin, NULL, CAP_QUERY_NONE)) < 0) { ret = r; goto error; } @@ -912,26 +1154,6 @@ error: return ret; } -static enum AVCodecID waveform_codec_id(enum AVSampleFormat sample_fmt) -{ - switch (sample_fmt) { - case AV_SAMPLE_FMT_U8: return AV_CODEC_ID_PCM_U8; - case AV_SAMPLE_FMT_S16: return AV_CODEC_ID_PCM_S16LE; - case AV_SAMPLE_FMT_S32: return AV_CODEC_ID_PCM_S32LE; - default: return AV_CODEC_ID_NONE; /* Should never happen. */ - } -} - -static enum AVSampleFormat sample_fmt_bits_per_sample(int bits) -{ - switch (bits) { - case 8: return AV_SAMPLE_FMT_U8; - case 16: return AV_SAMPLE_FMT_S16; - case 32: return AV_SAMPLE_FMT_S32; - default: return AV_SAMPLE_FMT_NONE; /* Should never happen. */ - } -} - static int dshow_add_device(AVFormatContext *avctx, enum dshowDeviceType devtype) @@ -1138,14 +1360,14 @@ static int dshow_read_header(AVFormatContext *avctx) } if (ctx->list_options) { if (ctx->device_name[VideoDevice]) - if ((r = dshow_list_device_options(avctx, devenum, VideoDevice, VideoSourceDevice))) { + if ((r = dshow_list_device_options(avctx, devenum, VideoDevice, VideoSourceDevice, NULL, CAP_QUERY_NONE))) { ret = r; goto error; } if (ctx->device_name[AudioDevice]) { - if (dshow_list_device_options(avctx, devenum, AudioDevice, AudioSourceDevice)) { + if (dshow_list_device_options(avctx, devenum, AudioDevice, AudioSourceDevice, NULL, CAP_QUERY_NONE)) { /* show audio options from combined video+audio sources as fallback */ - if ((r = dshow_list_device_options(avctx, devenum, AudioDevice, VideoSourceDevice))) { + if ((r = dshow_list_device_options(avctx, devenum, AudioDevice, VideoSourceDevice, NULL, CAP_QUERY_NONE))) { ret = r; goto error; } @@ -1289,6 +1511,208 @@ static int dshow_read_packet(AVFormatContext *s, AVPacket *pkt) return ctx->eof ? AVERROR(EIO) : pkt->size; } +// TODO: how to expose extra info? If no field found, check if it in a set of extra keys (like color_range)? +static int dshow_query_ranges_func(AVOptionRanges** ranges_arg, void* obj, const char* key, int flags) +{ + AVDeviceCapabilitiesQuery *caps = obj; + const AVFormatContext *avctx = caps->device_context; + struct dshow_ctx *ctx = avctx->priv_data; + + int backup_sample_size; + int backup_sample_rate; + int backup_channels; + enum AVCodecID backup_video_codec_id; + enum AVPixelFormat backup_pixel_format; + int backup_requested_width; + int backup_requested_height; + char* backup_framerate = NULL; + + enum DshowCapQueryType query_type = CAP_QUERY_NONE; + + AVOptionRanges *ranges = av_mallocz(sizeof(AVOptionRanges)); + const AVOption *field = av_opt_find(obj, key, NULL, 0, flags); + int ret; + + ICreateDevEnum *devenum = NULL; + + *ranges_arg = NULL; + + if (!ranges) { + ret = AVERROR(ENOMEM); + goto fail1; + } + + if (!field) { + ret = AVERROR_OPTION_NOT_FOUND; + goto fail1; + } + + // turn option name into cap query + query_type = dshow_get_query_type(field->name); + + if (query_type == CAP_QUERY_NONE) { + av_log(avctx, AV_LOG_ERROR, "Querying the option %s is not supported for a dshow device\n",field->name); + ret = AVERROR(EINVAL); + goto fail1; + } + + if (ctx->device_name[0]) { + av_log(avctx, AV_LOG_ERROR, "You cannot query device capabilities on an opened device\n"); + ret = AVERROR(EIO); + goto fail1; + } + + if (!parse_device_name(avctx)) { + av_log(avctx, AV_LOG_ERROR, "You must set a device name (AVFormatContext url) to specify which device to query capabilities from\n"); + ret = AVERROR(EINVAL); + goto fail1; + } + + // take backup of dshow parameters/options + // audio + backup_sample_size = ctx->sample_size; + backup_sample_rate = ctx->sample_rate; + backup_channels = ctx->channels; + // video + backup_video_codec_id = ctx->video_codec_id; + backup_pixel_format = ctx->pixel_format; + backup_requested_width = ctx->requested_width; + backup_requested_height= ctx->requested_height; + backup_framerate = ctx->framerate; + + + // set format constraints set in AVDeviceCapabilitiesQuery + // audio (NB: channel_layout not used) + ctx->sample_size = av_get_bytes_per_sample(caps->sample_format) << 3; + ctx->sample_rate = (caps->sample_rate == -1) ? 0 : caps->sample_rate; + ctx->channels = (caps->channels == -1) ? 0 : caps->channels; + // video (NB: window_width and window_height not used) + ctx->video_codec_id = caps->codec; + ctx->pixel_format = caps->pixel_format; + ctx->requested_width = caps->frame_width; + ctx->requested_height = caps->frame_height; + // checking whether requested framerate is set is done by !ctx->framerate + if (caps->fps.num > 0 && caps->fps.den > 0) { + ctx->requested_framerate = caps->fps; + ctx->framerate = av_strdup("dummy"); // just make sure its non-zero + if (!ctx->framerate) { + ret = AVERROR(ENOMEM); + goto fail2; + } + } + else + ctx->framerate = NULL; // make sure its NULL (if it wasn't, we already have a backup of the pointer to restore later) + + // now iterate matching format of pin that would be selected when device + // is opened with options currently in effect. + // for each matching format, output its parameter range, also if that same + // range already returned for another format. That way, user can reconstruct + // possible valid combinations by av_opt_query_ranges() for each of the + // format options and matching returned values by sequence number. + CoInitialize(0); + + if (CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, + &IID_ICreateDevEnum, (void **) &devenum)) { + av_log(avctx, AV_LOG_ERROR, "Could not enumerate system devices.\n"); + goto fail2; + } + ctx->video_codec_id = avctx->video_codec_id ? avctx->video_codec_id + : AV_CODEC_ID_RAWVIDEO; + + ranges->nb_components = field->type == AV_OPT_TYPE_IMAGE_SIZE ? 3 : 1; + if (ctx->device_name[VideoDevice]) + if ((ret = dshow_list_device_options(avctx, devenum, VideoDevice, VideoSourceDevice, ranges, query_type)) < 0) + goto fail2; + if (ctx->device_name[AudioDevice]) { + if (dshow_list_device_options(avctx, devenum, AudioDevice, AudioSourceDevice, ranges, query_type) < 0) { + /* show audio options from combined video+audio sources as fallback */ + if ((ret = dshow_list_device_options(avctx, devenum, AudioDevice, VideoSourceDevice, ranges, query_type)) < 0) + goto fail2; + } + } + ret = ranges->nb_ranges ? ranges->nb_components : 0; + + // when dealing with a multi-component item (regardless of whether + // AV_OPT_MULTI_COMPONENT_RANGE is set or not), we need to reorganize the + // output range array from [r1_c1 r1_c2 r1_c3 r2_c1 r2_c2 r2_c3 ...] to + // [r1_c1 r2_c1 ... r1_c2 r2_c2 ... r1_c3 r2_c3 ...] to be consistent with + // documentation of AVOptionRanges in libavutil/opt.h + // this is only the case for a AV_OPT_TYPE_IMAGE_SIZE option. + if (ranges->nb_ranges && ranges->nb_components>1) { + AVOptionRanges* old_ranges; + ranges->nb_ranges /= ranges->nb_components; + old_ranges = ranges; + ranges = av_mallocz(sizeof(AVOptionRanges)); + if (!ranges) { + ranges = old_ranges; // for cleanup + ret = AVERROR(ENOMEM); + goto fail2; + } + ranges->nb_components = old_ranges->nb_components; + ranges->nb_ranges = old_ranges->nb_ranges; + ranges->range = av_malloc(ranges->nb_components * ranges->nb_ranges * sizeof(AVOptionRange*)); + + for (int n = 0; n < ranges->nb_components * ranges->nb_ranges; n++) { + int i = n / ranges->nb_components; + int j = n % ranges->nb_components; + ranges->range[ranges->nb_ranges * j + i] = old_ranges->range[n]; + old_ranges->range[n] = NULL; // don't keep double references + } + + av_opt_freep_ranges(&old_ranges); + } + + // success, set output + *ranges_arg = ranges; + +fail2: + // set dshow parameters/options back to original values + // audio + ctx->sample_size = backup_sample_size; + ctx->sample_rate = backup_sample_rate; + ctx->channels = backup_channels; + // video + ctx->video_codec_id = backup_video_codec_id; + ctx->pixel_format = backup_pixel_format; + ctx->requested_width = backup_requested_width; + ctx->requested_height = backup_requested_height; + if (ctx->framerate) + av_free(ctx->framerate); + ctx->framerate = backup_framerate; + + if (devenum) + ICreateDevEnum_Release(devenum); + + dshow_read_close(avctx); // clears filenames and removes device_filters or other state variables that may have been set + +fail1: + if (ret < 0) + av_opt_freep_ranges(&ranges); + + return ret; +} + +// fake class to point av_opt_query_ranges to our query_ranges function +static const AVClass dshow_dev_caps_class = { + .class_name = "", + .item_name = av_default_item_name, + .option = av_device_capabilities, + .version = LIBAVDEVICE_VERSION_INT, + .query_ranges = dshow_query_ranges_func, +}; + +static int dshow_create_device_capabilities(struct AVFormatContext* s, struct AVDeviceCapabilitiesQuery* caps) +{ + caps->av_class = &dshow_dev_caps_class; + return 0; +} + +static int dshow_free_device_capabilities(struct AVFormatContext* s, struct AVDeviceCapabilitiesQuery* caps) +{ + // nothing to clean up + return 0; +} + #define OFFSET(x) offsetof(struct dshow_ctx, x) #define DEC AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { @@ -1335,6 +1759,8 @@ const AVInputFormat ff_dshow_demuxer = { .read_header = dshow_read_header, .read_packet = dshow_read_packet, .read_close = dshow_read_close, + .create_device_capabilities = dshow_create_device_capabilities, + .free_device_capabilities = dshow_free_device_capabilities, .flags = AVFMT_NOFILE, .priv_class = &dshow_class, }; From patchwork Thu Jun 3 22:45:52 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: 28070 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a6b:b214:0:0:0:0:0 with SMTP id b20csp538176iof; Thu, 3 Jun 2021 15:47:09 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyJUcJtjBcmTvgMJgutRsBUEqXKziQNxQSVM6pFOB8fKxGof84d6I+Ym4HK+lr3TiQu5TxZ X-Received: by 2002:a17:907:1112:: with SMTP id qu18mr1300313ejb.511.1622760429440; Thu, 03 Jun 2021 15:47:09 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1622760429; cv=none; d=google.com; s=arc-20160816; b=CdGlGYxyfRRaITAn5su1XeIzSkoGBSii3UJ7t6a6d9zvlbfLxyErOETHWCb/l46QEy WeQWKGbcqzZz/R7gWgmXfVNqTngtWig/WsZHr2jksx+EN2OnMcrgWWh8rRFO6j4iFLgg vIZ5vFfNv3NQm3brOiw8p42xI/3svwoA31lNgncDk9UJ/7o3m9P3CmFYh9r4MVcELkO0 8SBVxcT6OVumxy9EuWAG9apOLVHaXgTlFIP3RQ10Gxh40WJT+9kxWoDWlOlwNMUB+1ez GwOPpsQhC/2hZRDPkp53qlZO/OGK9DXqfqN6xZ4TWz0M83Z1KwlOj6f6omCNXFLxSHA5 WIvQ== 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=xtm6vihorRTVqzNsAIcAKftlTJnsb9y7aMe1S58Xbp4=; b=NsuSZ7K5/KEBF9r2YQSCCbrXj9ngoT/VrJB7h+K2WPJNj2rWTeH+/f3Mk/H+/xpvBX WaEqnD8m3IDOaTLDXmWknr1Ktn9CpVKnHSBgS9CUvcZn6ZYuMTj2pfsPj7Fl9aHKXeMO CjAsfVvr0LL0W1qvCfa9ZZhZ3DHj9cVWdq5x3MSB3FywdFH1cYsSyZRtDvK1HkIljB8l CMNDRCy833lhYz7g/XoZJEBSjao8MBy1/vkKIhoL2TjTIjJQ1UIkbFamtbV/F3H/sQ8O k9xK0rRM+d5UQxq//NTZODfIel5Msf8NQcWjkXxI8/u5JbGJrrEjqsUkUynNic0yPBBh xdWA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=ZvV4wIkN; 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 u10si3183515ejf.585.2021.06.03.15.47.09; Thu, 03 Jun 2021 15:47:09 -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=ZvV4wIkN; 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 9B62F689829; Fri, 4 Jun 2021 01:46:33 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lj1-f169.google.com (mail-lj1-f169.google.com [209.85.208.169]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 5DBBA68A2C3 for ; Fri, 4 Jun 2021 01:46:26 +0300 (EEST) Received: by mail-lj1-f169.google.com with SMTP id p20so9103223ljj.8 for ; Thu, 03 Jun 2021 15:46:26 -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=pVuug6zOBrm12AB23nP8todnuFf6FXEqrhUsNaKTNXY=; b=ZvV4wIkNCeV51fw7vP2cpeJiCytEJEDSi1gRhIt1eRm8a4NqwaAq+eDl7tPe+ND3TT aHtGX3h7lqvYwn7qT3cu11H8yc6yqYOdo4TwJNTnMQTvRcpygvSJGbgSZLEQ8xwWretj IkxQKQJclPV8JEFPjaqS1Xl13B9F/GbWPFuRZc9GJ4HVvFAYmPMkLGHEzALyq4BGfVk4 P7Al7liFc6n09DPE7BtKh8uMbGXg5+qJFcGPeEadv/Ya2mFxXAP+NESnJa7neBmxPc+8 hbekUdoBlwKM3eng/1wkLTl4YF9173ft9A5nMIfqAkQlmpMEntS0vk/zVgTfzW3iOpF+ zPZQ== 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=pVuug6zOBrm12AB23nP8todnuFf6FXEqrhUsNaKTNXY=; b=XvlfEFBBmEnVTRCg5wDhVjn2IaW9dwoSlPo13FC1cTXamNz1QinYK8XBRxrdXGUf0h Pbb4MgC0WCTojvvlTVoN7ACXMEkISQ2kO8Dp1i4OaDEts3Qie0hj0JYzsakRuxnIwchf Xc9q8iviBfC/NECwEIIgy0iZyMzqtXh+lnHiuOM0ulDlXYy2giWkOm6f22lGxAwGIdfv QTn9C6PzyisMCW7Sse5btd/VB/31hc9b6B21MwnxeDqmfPAo1AlZzmTVmjK1LEaR9muA ZZzuVImxL9QZ7IcklPsFhw/n3h9oVI+emqtZCemEYRBaGsMwrjvJKuAdD6uPNztaO6Mo oSvg== X-Gm-Message-State: AOAM530jWatBUntr3aW7o6I8dEkFlJ4MQWUP2f6mO7sekHtvIs4C211O iAv4DUpGSfXpNiNQvOOM2P4pzUwefJQ= X-Received: by 2002:a05:651c:306:: with SMTP id a6mr1145847ljp.285.1622760385278; Thu, 03 Jun 2021 15:46:25 -0700 (PDT) Received: from localhost.localdomain (84-217-56-54.customers.ownit.se. [84.217.56.54]) by smtp.gmail.com with ESMTPSA id t15sm82373lfp.176.2021.06.03.15.46.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jun 2021 15:46:24 -0700 (PDT) From: Diederick Niehorster To: ffmpeg-devel@ffmpeg.org Date: Fri, 4 Jun 2021 00:45:52 +0200 Message-Id: <20210603224552.1218-5-dcnieho@gmail.com> X-Mailer: git-send-email 2.28.0.windows.1 In-Reply-To: <20210603224552.1218-1-dcnieho@gmail.com> References: <20210603224552.1218-1-dcnieho@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 4/4] 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: gDf0lWaHqAxx Signed-off-by: Diederick Niehorster --- configure | 2 + doc/examples/.gitignore | 1 + doc/examples/Makefile | 47 ++++---- doc/examples/Makefile.example | 1 + doc/examples/device_get_capabilities.c | 151 +++++++++++++++++++++++++ 5 files changed, 179 insertions(+), 23 deletions(-) create mode 100644 doc/examples/device_get_capabilities.c diff --git a/configure b/configure index 82367fd30d..5e9666d017 100755 --- a/configure +++ b/configure @@ -1705,6 +1705,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 @@ -3712,6 +3713,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..7988ed4226 100644 --- a/doc/examples/Makefile +++ b/doc/examples/Makefile @@ -1,26 +1,27 @@ -EXAMPLES-$(CONFIG_AVIO_LIST_DIR_EXAMPLE) += avio_list_dir -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_ENCODE_AUDIO_EXAMPLE) += encode_audio -EXAMPLES-$(CONFIG_ENCODE_VIDEO_EXAMPLE) += encode_video -EXAMPLES-$(CONFIG_EXTRACT_MVS_EXAMPLE) += extract_mvs -EXAMPLES-$(CONFIG_FILTER_AUDIO_EXAMPLE) += filter_audio -EXAMPLES-$(CONFIG_FILTERING_AUDIO_EXAMPLE) += filtering_audio -EXAMPLES-$(CONFIG_FILTERING_VIDEO_EXAMPLE) += filtering_video -EXAMPLES-$(CONFIG_HTTP_MULTICLIENT_EXAMPLE) += http_multiclient -EXAMPLES-$(CONFIG_HW_DECODE_EXAMPLE) += hw_decode -EXAMPLES-$(CONFIG_METADATA_EXAMPLE) += metadata -EXAMPLES-$(CONFIG_MUXING_EXAMPLE) += muxing -EXAMPLES-$(CONFIG_QSVDEC_EXAMPLE) += qsvdec -EXAMPLES-$(CONFIG_REMUXING_EXAMPLE) += remuxing -EXAMPLES-$(CONFIG_RESAMPLING_AUDIO_EXAMPLE) += resampling_audio -EXAMPLES-$(CONFIG_SCALING_VIDEO_EXAMPLE) += scaling_video -EXAMPLES-$(CONFIG_TRANSCODE_AAC_EXAMPLE) += transcode_aac -EXAMPLES-$(CONFIG_TRANSCODING_EXAMPLE) += transcoding -EXAMPLES-$(CONFIG_VAAPI_ENCODE_EXAMPLE) += vaapi_encode -EXAMPLES-$(CONFIG_VAAPI_TRANSCODE_EXAMPLE) += vaapi_transcode +EXAMPLES-$(CONFIG_AVIO_LIST_DIR_EXAMPLE) += avio_list_dir +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 +EXAMPLES-$(CONFIG_FILTER_AUDIO_EXAMPLE) += filter_audio +EXAMPLES-$(CONFIG_FILTERING_AUDIO_EXAMPLE) += filtering_audio +EXAMPLES-$(CONFIG_FILTERING_VIDEO_EXAMPLE) += filtering_video +EXAMPLES-$(CONFIG_HTTP_MULTICLIENT_EXAMPLE) += http_multiclient +EXAMPLES-$(CONFIG_HW_DECODE_EXAMPLE) += hw_decode +EXAMPLES-$(CONFIG_METADATA_EXAMPLE) += metadata +EXAMPLES-$(CONFIG_MUXING_EXAMPLE) += muxing +EXAMPLES-$(CONFIG_QSVDEC_EXAMPLE) += qsvdec +EXAMPLES-$(CONFIG_REMUXING_EXAMPLE) += remuxing +EXAMPLES-$(CONFIG_RESAMPLING_AUDIO_EXAMPLE) += resampling_audio +EXAMPLES-$(CONFIG_SCALING_VIDEO_EXAMPLE) += scaling_video +EXAMPLES-$(CONFIG_TRANSCODE_AAC_EXAMPLE) += transcode_aac +EXAMPLES-$(CONFIG_TRANSCODING_EXAMPLE) += transcoding +EXAMPLES-$(CONFIG_VAAPI_ENCODE_EXAMPLE) += vaapi_encode +EXAMPLES-$(CONFIG_VAAPI_TRANSCODE_EXAMPLE) += vaapi_transcode EXAMPLES := $(EXAMPLES-yes:%=doc/examples/%$(PROGSSUF)$(EXESUF)) EXAMPLES_G := $(EXAMPLES-yes:%=doc/examples/%$(PROGSSUF)_g$(EXESUF)) 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..f3b9f31e0d --- /dev/null +++ b/doc/examples/device_get_capabilities.c @@ -0,0 +1,151 @@ +/* + * 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 + + + +int main (int argc, char **argv) +{ + int ret = 0; + const char* dshow_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; + + if (argc != 5) { + fprintf(stderr, "usage: %s dshow_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 video=\"Integrated Webcam\" frame_size pixel_format yuyv422", + argv[0], argv[0]); + exit(1); + } + dshow_input_name = argv[1]; + query_cap = argv[2]; + set_cap_name = argv[3]; + set_cap_value = argv[4]; + + // make sure avdevices can be found + avdevice_register_all(); + // find our device (capabilities API is currently + // only implemented for dshow device, so hardcode that) + fmt = av_find_input_format("dshow"); + + // since there is no equivalent of avformat_alloc_output_context2 for an input context, + // so we get this dirty code that users shouldn't have to write.... + fmt_ctx = avformat_alloc_context(); + fmt_ctx->url = av_strdup(dshow_input_name); + fmt_ctx->iformat = fmt; + if (fmt_ctx->iformat->priv_data_size > 0) { + if (!(fmt_ctx->priv_data = av_mallocz(fmt_ctx->iformat->priv_data_size))) { + ret = AVERROR(ENOMEM); + goto end; + } + if (fmt_ctx->iformat->priv_class) { + *(const AVClass**)fmt_ctx->priv_data = fmt_ctx->iformat->priv_class; + av_opt_set_defaults(fmt_ctx->priv_data); + } + } + // end dirty code + + // query the capability without any filter set + ret = avdevice_capabilities_create(&caps, fmt_ctx, NULL); + if (ret < 0) + goto end; + + ret = av_opt_query_ranges(&ranges, caps, query_cap, AV_OPT_MULTI_COMPONENT_RANGE); + if (ret < 0) + goto end; + + for (int range_index = 0; range_index < ranges->nb_ranges; range_index++) { + 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) + printf(", "); + printf("%s: %.2f -- %.2f", range->str, range->value_min, range->value_max); + } + printf("\n"); + } + 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) + goto end; + + ret = av_opt_query_ranges(&ranges, caps, query_cap, AV_OPT_MULTI_COMPONENT_RANGE); + if (ret < 0) + goto end; + + for (int range_index = 0; range_index < ranges->nb_ranges; range_index++) { + 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) + printf(", "); + printf("%s: %.2f -- %.2f", range->str, range->value_min, range->value_max); + } + printf("\n"); + } + + +end: + av_opt_freep_ranges(&ranges); + avdevice_capabilities_free(&caps, fmt_ctx); + + avformat_close_input(&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; +}