From patchwork Thu Jun 3 22:32:57 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: 28067 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a6b:b214:0:0:0:0:0 with SMTP id b20csp535116iof; Thu, 3 Jun 2021 15:41:15 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxUl6G2Awwjwnr5EhaYExjC7HgZzAa5CstLzs+/qxOOInsHqO0BIovMhY3AdIfGTHvVJpHD X-Received: by 2002:a05:6402:158e:: with SMTP id c14mr1614171edv.128.1622760074978; Thu, 03 Jun 2021 15:41:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1622760074; cv=none; d=google.com; s=arc-20160816; b=Wrr6ZEkTOXW2tIBvCokJnUhr3m62xqu78woeujStKEDIFogs20pocYYthJixJJp3yt PZCYkBM3BE/7ceISAsC+dBD0whUlgBWFRYa+7TLTWFPUZKEySaDalPfiwqv/WSZ5wxof qoVwpBsKKkRI2Lou/MCJT+vWigZYrsMMfIfCWIDbA/TJ9g2axboGEBKryh7lMCKY3bdA +XQp8cdm3KTPXN9QXjle0FDQSb+Qjsg90SkNs3KPUB7vNCEOD5o495hY328BVR3i0yqP UtebjIFoFo6OIz9ZeI7a2Fj35WNwMOieYiP/DjfhTng6bxyXkUnEo0oQZWkGue8+3TG4 oTfw== 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=twBnKPRp2db7VtLvFsL7uUn7clwCWlXOWW+Tq97tgW5tNEluKFnOU0WkNhsSM7Hi0T gDi/j24vrNGG2Nrk08SHYqGMeLCTSVFI045rit+VuxyzvluZ+Y8UY5eToM8LFOq4xwsM CNZ5faWWPAdzDuUsl/rkzB3mKH9Tf+UEyclRa64elQnnwno4qW9HopDDZEppAovLIlot o0mj9PXY2TrmtEHGiVzx0ZSnzzmRi/Y7VF0vSJremqwroUn3xf8B6KYW+2vyZdr/IX2a AyXKQs7v3iAf2kRo/KK5ua5oN0mMl6jMjID+QocQrxU/ZYWj3Hij4Qb5aBWlVP3kiCdi QiDA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=ewVSyhAw; 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 bo20si3315533edb.524.2021.06.03.15.41.14; Thu, 03 Jun 2021 15:41:14 -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=ewVSyhAw; 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 BD53A68A134; Fri, 4 Jun 2021 01:41:10 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lf1-f45.google.com (mail-lf1-f45.google.com [209.85.167.45]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id F3D8B6882FB for ; Fri, 4 Jun 2021 01:41:03 +0300 (EEST) Received: by mail-lf1-f45.google.com with SMTP id n12so4177369lft.10 for ; Thu, 03 Jun 2021 15:41:03 -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=ewVSyhAwc5dusnQc9spV5ZFN9Q93k/QUXoMeGnCg0AqIiyTh8BklIz2cHa5D6vIuAp hFnXBjGOhMEAQjHoX+VrACzPDzcbEry3rqZEgyhEsjtkJcMICbTkY/ReWm/f2HTLq2Qh AVRl4WXJ+sYqaoqAa04ta/4reP2j2ewOFvxM6SH4m9kW57Z4OajLVvG8mUZs0e5ve6zW YlA2hJaenxQsx9xXvzv1dH9KDeO17BDblc+udEJi3vz7QP7FuqV0/svczsqp4yKzYfWx jlcKN++L4UR2kzEjdcXns3KNxpU9wJogy8wG18dRkXz6nrZ+GE2Ss/O0ZL+OwQaTWyK3 4gMg== 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=uGAmeUT5+qKWl1huIOIiQCNBNI2RMCjArcnR4wDSfOMno9LaUubxzCrDC2L+D/7J3E W85/SFDCY7jrB4j4bf+FB2TamTITte1+ap5H28WXz2G2fjf/v1wdvBNowoZhO6q6ZCjq zyeFlrZG4v1k893ICAsitdC+C1aTYc8MxuQeN51gpLLCYFIZ8RyOvwcYEMBSg1Ios2yx T/Hbp4ha0bu8pSoGAiYqzJhaxD+EsgxkcncmGgnH8xrN1QgytoeaqaxHzOdsyJYsIMxP p13Mq8VySHYIpzynfhc6ZXyP33jQNqqBGP7L7tBNxBPuA5yjwWZgqR3jPsGq6Q6ZcEIL TvNg== X-Gm-Message-State: AOAM533ngT+k08HQWVOBj52Ku7fK+g7OomxoSwD6r+xx/bvGx/oysHDm dVK+95jCLtgDjARuIVTk7TRC3hLssQc= X-Received: by 2002:a05:6512:b95:: with SMTP id b21mr698599lfv.491.1622759741667; Thu, 03 Jun 2021 15:35:41 -0700 (PDT) Received: from localhost.localdomain (84-217-56-54.customers.ownit.se. [84.217.56.54]) by smtp.gmail.com with ESMTPSA id b6sm236026lfa.296.2021.06.03.15.35.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jun 2021 15:35:41 -0700 (PDT) From: Diederick Niehorster To: ffmpeg-devel@ffmpeg.org Date: Fri, 4 Jun 2021 00:32:57 +0200 Message-Id: <20210603223302.1047-2-dcnieho@gmail.com> X-Mailer: git-send-email 2.28.0.windows.1 In-Reply-To: <20210603223302.1047-1-dcnieho@gmail.com> References: <20210603223302.1047-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: jHteKpfEWPbR 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:32:59 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: 28066 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a6b:b214:0:0:0:0:0 with SMTP id b20csp535710iof; Thu, 3 Jun 2021 15:42:30 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwHkbiEZIoX93iVG2+Fud0hvyNDlKPBWdItcz84zReD2rpZonntqf5R2n2mVtqJLYuZ2h3f X-Received: by 2002:a17:906:e4b:: with SMTP id q11mr1336397eji.404.1622760150495; Thu, 03 Jun 2021 15:42:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1622760150; cv=none; d=google.com; s=arc-20160816; b=yekZTLon1geesLr6T6kcB9k0I92KOVM4EC5swMNmZ7zHPMKgEuYkF5zN2CfQqis5wQ ek9X5E2LHedj7wAFGe60edKuPgOthxyLHWgVgLm9O4RB2r82zjopwS0A7IjX1NKhrJi/ WKcSOgXznI+r3iSg+Wn0fJYUZ3AmlA7Vz/lYibuDHazyDiQIXTU5SPFr0MnlKkG0JgPm osCCiaoccD5gzO+h+h/I7UKHGuc9GT7efZgEQAtDPvuasCBX0VLlKBlyPGk0D2i2v2hk Cb2HgWTpmZ3GcBqaU0eZXr63mD6CDsb5Z9XHg0WO+YWO+qVx4O4+J7zH8yszHoXK7kLm exaA== 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=B35t/VYwXFCLriAIM+1iB6GdsUhAytApNpsw+PdhNv+FhuP6EIGJ2GBb5ogO0MOjrC I7FLIUImF+D6DvxQEFX7i2MoUE9eUulWlQPiqwNYobsKAioaIKPhv3EYGcLDA4kO1gHO MqPfm5KmGInxynIorLbrDaDBWnPC1IVQIbuXX/Av+d4ucnjX3mHcmEMJ+BruFksGUxJJ UXYJtK9p+4d6wrn1W2vZJkQgwKz+YyBns5I/PD04R7t5Tt0Sa/KQerA4gBM8mGFboGJR 8Meqmn/krqAUh8aAuS589LTPQB5iCqC30qMft3oQHlOYa1NzdAjjteDkum+UHAznwwX4 /Mpg== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=LF83m7NO; 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 22si665640ejc.357.2021.06.03.15.42.30; Thu, 03 Jun 2021 15:42:30 -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=LF83m7NO; 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 0B57E68A148; Fri, 4 Jun 2021 01:42:28 +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 3A3E068A148 for ; Fri, 4 Jun 2021 01:42:21 +0300 (EEST) Received: by mail-lj1-f180.google.com with SMTP id a4so9134206ljd.5 for ; Thu, 03 Jun 2021 15:42:21 -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=LF83m7NOXY2jHxO33TFDH/++l6Lu1Ux5ClqzMqxwPTIorU/w6d21tm8G/OIGpaAsZL 11SDgp0kZ3h7K0MNFCgzxMD6F4mV4aAqFwLGPGJ1zgIWv4oGkaeJx7L8BP2cxgeZQzEF W84YKNx7yUFveitqmwCXf3np57sK/aX1b2u1KbyH4z839HAJTaPxcBSAyXgtN34ojeXk KwsPXIcX0S4Bf6oPM6N61esb8brfP8h7k5pWUX7nVujX2fDS/TKnwt0c/s4QQi0y4M9o vSuDfBL2k0Yi87DR/A0Ay1/HQxpNmyYO/xU3zuZH1Gjfp6LkRtwtsspctE3kNSfkEUdW o5Ew== 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=PS9lPazxFqxed3o+BdED17ya8jgTHYsUkvMZqISdPUUNmuvvqi9RtgXVZae5yc/7Lx bl0o23t67qqa0wAaDaK7qeVyfCq4ojLefHKgikZ101qFh9O3yuyl+443MXK406foMNnF cS7/PSf0L1mIfYiUdiEBA0fNAbP8PwZ2BY4OIwSlLPZKFYpiPYJEh6xKSQebJLaAqXPA 0xlAzLYbI6+KKUYXK5YuO7fCFp22V4MY6RKRiu6Eaehz0xmewRY6H6A0qBccUMWoudsC pMvjuQsM9b56RHZONqlENn+D+dLkkWK5ewyiJgW20R7gIuQEDSG9UoFor6vqAR2Lm4RJ +SGg== X-Gm-Message-State: AOAM533UpH932xpzoc2IQDyQ4JPaSTij51hfVbZDlvn8bioNuKQxF45U KuiEjd/CJ25DZwMeQ7EfJZrIqSnXto0= X-Received: by 2002:a2e:b895:: with SMTP id r21mr1111251ljp.369.1622759743440; Thu, 03 Jun 2021 15:35:43 -0700 (PDT) Received: from localhost.localdomain (84-217-56-54.customers.ownit.se. [84.217.56.54]) by smtp.gmail.com with ESMTPSA id b6sm236026lfa.296.2021.06.03.15.35.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jun 2021 15:35:43 -0700 (PDT) From: Diederick Niehorster To: ffmpeg-devel@ffmpeg.org Date: Fri, 4 Jun 2021 00:32:59 +0200 Message-Id: <20210603223302.1047-4-dcnieho@gmail.com> X-Mailer: git-send-email 2.28.0.windows.1 In-Reply-To: <20210603223302.1047-1-dcnieho@gmail.com> References: <20210603223302.1047-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: OWLmyB67knE5 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:33:01 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: 28076 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a6b:b214:0:0:0:0:0 with SMTP id b20csp544415iof; Thu, 3 Jun 2021 15:59:10 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxNzRNB37sjc4lQOXHvDU5FB6rPy/N1oH5tcIP+xsghBe7SzQHcoeZNT1xut8yBb4quifTE X-Received: by 2002:a17:906:757:: with SMTP id z23mr1333026ejb.537.1622761150579; Thu, 03 Jun 2021 15:59:10 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1622761150; cv=none; d=google.com; s=arc-20160816; b=gHFENzLWOSr1lcEjGndB/pPPfaMxXVSR4TDfo0NG9Z433EVg7PFt1XpGFXTa6SE3gu 5Z08rgo2p11WkVCC9y19+wvMTWkRSCglxSlXHM2ivJOQdjv5J6kDjqmMbVbB7HHxBe50 ekSVqCFtGy9YdDOFDogutxzAlI/cmb8OE9503KTnaM4PJtFRCHycceTT0nt/TDSJFbs0 My7ZNJMlU5D5wwPS1PgTqA55FiStL9xg8fi0FPfWjSpfGiBLdWEoYABQ5nGQo7+J9knu hJKbBmjSz/QkPwZGL8lPG2uY2rdb3uk+Qf78t+UJkX71g6VNFJFBZK9DQIK5b4gqT1d+ m2Bg== 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=evd64AWb/2BFv9iDIeP39jdww23G/Ut6+/v31JjKpZQ7RcN9sFbLJB1L+FKaf2B9Qc qZCNZB2YQgDnNgu19V8IQEfJlkluE9eHiQps49IifuTdAAphTrQRB5BaPjHcmUQ9CFku 0e8D64IqMqkGDRNE6WktE7UiwemhBzwDQ2kTf+p7+WoLJA5ycpfn2n3t3YFxXc74XzpY WF7aDjuViAPcsibFuxAYO615Ql9JZpZ0k4bmYFqt3QY+N+Om+Ffm4adJG0t1LPTyE5T0 l+YzzIAAhTebPcP/fPVV/9tYmOCirm9uKU/tkko8xY/agBXJMvYZLVJ9vVN+S+zIZqj3 R2qw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=VmUOfBD2; 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 l22si3123926edw.387.2021.06.03.15.59.10; Thu, 03 Jun 2021 15:59:10 -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=VmUOfBD2; 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 B28C068A2BC; Fri, 4 Jun 2021 01:59:07 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wr1-f51.google.com (mail-wr1-f51.google.com [209.85.221.51]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id BA58D689FB5 for ; Fri, 4 Jun 2021 01:59:00 +0300 (EEST) Received: by mail-wr1-f51.google.com with SMTP id f2so7367547wri.11 for ; Thu, 03 Jun 2021 15:59:00 -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=VmUOfBD2Hpl4EinPkDf9qvjkhkinRwvp4BYsT0WbTcgHd4wc0s4hUNDBG0QeyQIgJl dOg664A1rSF7zaY6n4BbZp4ES8Pn9ivbi0EAKtn+x0Y+rF+Cv3oow16m+t+DQx8etzgH XnWdhNDxZZUIO2AdbPr8Qt+iLcZj1ORQS/xxt740ZsdbPugT8j7ADQFJd40SLdV93RdV gef22SO3vgnXQLAqB/N+PnJiSmCNxJnwoZkMlkeUDt3CZ/UMR07cDfTZ2PUcoCHLniSW B8WX0RvDrno4ViF+2DbOlc8ZfcIYf0gbfCATATbrxLNYTysVt5TYNbpt1ADTrLtuJJ+/ bdlw== 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=eRImlN29tmJm4c9GBmS28bCwIXf8wsALWF/C83qmLJA5y6ptY1Q2Rr/cAmO3QlID/h E+jukJXpaEHcVq7yRb8+YrUY0QUuQ8hHz6NSlDvmrVFjVd+m0bRTTy+iw6xTgqxZZY40 kEcG/4TM4VQm34FSykVZLxAMm5fHqo7R4HUVXcUYVNRH0KlD8qrNesOBm0llwOJ/UVmK l8Cq/NwPwTtn1Q+wzr9p2MwvTRuSmAgUJsjwf2nsemWc2x1L2wQ+7HLYjLUq4Mulqs40 mQ6t0TMi5y2X1q3+dOZzL2NFTkXjRktcYRpNeLsK12j8Mi8Z+fx1V7DLqms8OSUcxvN/ xgQA== X-Gm-Message-State: AOAM5308IxsLKLUXxfvOQ1ZihSiVPjrfFysyoNE2ABur7lpEXwz6BRNd mNoen9Oq3dJ5WJoY1oS5T0nAgQGl7Sg= X-Received: by 2002:a2e:9802:: with SMTP id a2mr1124932ljj.232.1622759745084; Thu, 03 Jun 2021 15:35:45 -0700 (PDT) Received: from localhost.localdomain (84-217-56-54.customers.ownit.se. [84.217.56.54]) by smtp.gmail.com with ESMTPSA id b6sm236026lfa.296.2021.06.03.15.35.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jun 2021 15:35:44 -0700 (PDT) From: Diederick Niehorster To: ffmpeg-devel@ffmpeg.org Date: Fri, 4 Jun 2021 00:33:01 +0200 Message-Id: <20210603223302.1047-6-dcnieho@gmail.com> X-Mailer: git-send-email 2.28.0.windows.1 In-Reply-To: <20210603223302.1047-1-dcnieho@gmail.com> References: <20210603223302.1047-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: O8N1qPeau6Nd 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:33:02 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: 28065 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a6b:b214:0:0:0:0:0 with SMTP id b20csp535336iof; Thu, 3 Jun 2021 15:41:41 -0700 (PDT) X-Google-Smtp-Source: ABdhPJynHl0Gccfm39KRUrGj/B8ODoWeWQg13m15GEHAU0rnYTMVJJm/tGqqgxnKzyRg52S0g0Tn X-Received: by 2002:a05:6402:1648:: with SMTP id s8mr1623553edx.256.1622760101081; Thu, 03 Jun 2021 15:41:41 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1622760101; cv=none; d=google.com; s=arc-20160816; b=zm9egayRLcLkbrWufbnkBcCJVBxDKlJeF3iBjc/4hyLkmvYLOdFBhK/PTbxpJH56ZT IPflMGlTnKxaFCoFxX/VHPzdlckhz0J5AR7DjiPYbGcReQ7nJtj3ok7i8udIoGbBa4UT zsfLW3mxtYARThPAmQawo1yqPr/50eCCJShuUg7mMJRMXZql1+ndSQQ6ViUtXMmdN1j0 2ccJmdYuy9wnA8aZmxwy1/Vx/mVszSr2zmYClmsb6dgf0wKvVKtwYRiRMbAAFTOWlgUy z0RT96sugdGRdjg/95w45rLfPfa1J+i6wmJ2dRBXxCv+7uDGO4BNyY0T9RVU14R1MHmj m8zg== 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=u8tXtIh5qJzwYhKD3KkeeyXXLmyIxZIsN+l9+UqRdRikNqnOibN+PzsDFZN47BBkAE Li+IFm4l+S3IcFO3NM6Z31Cb9mxrubYVf9PdNXyVFZYuzr9vjJ5QwKAO4UVUemB3ptyT cpDW/YfO9TnuXuKw4JlvbL2vjYDy9GLHIkZWP306WEz2IbcsjBxGMOPFrpUxwjoBubVk XnDj/6JDPQy86Oq5aaZ5Ror0NoM3NCU8UGG9RvoKLz51L5+fscxirRUNAKsfXt4gln6I fYMS4uuDpgGgUaYrglPGCQuWn72z0XpRBr4sFZek9DZiYpZIp5BR1DaZbWSLaKQQKNPw Ei6A== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=RuTZV5qT; 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 z71si3656433ede.151.2021.06.03.15.41.40; Thu, 03 Jun 2021 15:41: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=RuTZV5qT; 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 EAC0468A196; Fri, 4 Jun 2021 01:41:37 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lf1-f47.google.com (mail-lf1-f47.google.com [209.85.167.47]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id E0D5768A15D for ; Fri, 4 Jun 2021 01:41:31 +0300 (EEST) Received: by mail-lf1-f47.google.com with SMTP id f30so11212627lfj.1 for ; Thu, 03 Jun 2021 15:41:31 -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=RuTZV5qTMXU3gzuZqIZSbdmbb635UPCF7tuT0CN3hyOAQDEzWABMg5FswQ6MHmCMzH FV2fZYeXiUMCRHAEav5EH7lJCOanD6JTapwUdz0l4VL3BgVVGWTd1kNtqrZo1jjGTeqt aDQGXk5eZTfmPJZgl8VY8fDP6xDKRD9E3FW902KxabjCzZY/ghIE9b2JRU3YX+NS9Vc/ dRJmw5XLHT70dj1540yyAsPONjo/Tdyr3IzcD1fAEAjlH+EI6G+YC5v6bx8Xos92t9lf Y+pun9+QM3uZCjv8WMIjZZqwvgkrpAU/KLXjoCzT8GJJTP5AWqVaXkriXXrJiHuofHjE KuSg== 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=CSARyqH+CTaHt1NNHnEKf0f/tP5DlZtyOff9sVf3vTa8L6Hnha24tCKtTDIfaxOnhb svVRsJkB9Gan8HHqduZhFC+deyq9N8rT8cq9F+EXNbotkI4ArfETRhsK433y2fTKRlpC ZRPVm0wOumGGBC9hiMAb5M+9DNp1xg93yd8VnfD75PyIa3aH0oy7MbJp1/Ijm/aHvmWN sdxWkvpDQsxLsfT8fguVcyBpFKjJHey5//OihvAU2bSsaln1jS+aMtasL3dGQmwWBWWa YjVpQNx3oZYauJarMumEJs+v80MgxI8nCd5wt7Rxa100sTRRakEEaSAl5VXmhFZDSKHf gZ1g== X-Gm-Message-State: AOAM5314n7kBF8g4s4dH1ku00kFq+0Tj0QQAtzgvFKS4jtA0GeSwngwW c6ltViOBg/3MY0wremnU/XC0LVeuWng= X-Received: by 2002:a05:6512:2390:: with SMTP id c16mr730084lfv.183.1622759745876; Thu, 03 Jun 2021 15:35:45 -0700 (PDT) Received: from localhost.localdomain (84-217-56-54.customers.ownit.se. [84.217.56.54]) by smtp.gmail.com with ESMTPSA id b6sm236026lfa.296.2021.06.03.15.35.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jun 2021 15:35:45 -0700 (PDT) From: Diederick Niehorster To: ffmpeg-devel@ffmpeg.org Date: Fri, 4 Jun 2021 00:33:02 +0200 Message-Id: <20210603223302.1047-7-dcnieho@gmail.com> X-Mailer: git-send-email 2.28.0.windows.1 In-Reply-To: <20210603223302.1047-1-dcnieho@gmail.com> References: <20210603223302.1047-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: 6AR0gg1mFvxA 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; +}