[FFmpeg-devel] [PATCH 4/4] examples: adding device_get_capabilities example

Andreas Rheinhardt andreas.rheinhardt at outlook.com
Sat Jun 5 09:51:26 EEST 2021


Diederick Niehorster:
> Signed-off-by: Diederick Niehorster <dcnieho at gmail.com>
> ---
>  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
>  

Moving everything to the right should be done in a separate commit (if
at all).

>  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 <libavdevice/avdevice.h>
> +#include <libavutil/avstring.h>
> +#include <libavformat/avformat.h>
> +#include <libavutil/log.h>
> +
> +
> +
> +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)

This information is internal and does not belong into an example; the
best way is probably to set the device type via a new argument.

> +    fmt = av_find_input_format("dshow");

Missing check for fmt (e.g. dshow is unavailable if not on Windows).

> +
> +    // 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);

Missing checks.

> +    fmt_ctx->iformat = fmt;
> +    if (fmt_ctx->iformat->priv_data_size > 0) {

priv_data_size is not part of the public API; so the code is indeed
dirty and so this example is unacceptable as-is. This might be a
scenario where AVFMT_FLAG_PRIV_OPT might have been useful, see
2ff40b98ecbd9befadddc8fe665a391f99bfca32.

> +        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);

avformat_close_input() may only be used if you have used
avformat_open_input(); otherwise one has to use avformat_free_context().

> +
> +    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;
> +}
> 



More information about the ffmpeg-devel mailing list