[FFmpeg-devel] [PATCH 1/4] lavf: add probe device API

wm4 nfxjfg at googlemail.com
Mon Nov 25 17:30:53 CET 2013


On Tue, 12 Nov 2013 00:11:59 +0100
Lukasz Marek <lukasz.m.luki at gmail.com> wrote:

> Adds new API dedicated for output devices.
> 
> This API allows to
> - Test device with provided configuration
>   Audio devices params:
>     - device name
>     - codec
>     - sample format
>     - channel count
>     - channels layout
>     - sample rate
>   Video devices params:
>     - device name
>     - codec
>     - pixel format
>     - width (minimal width as input and real width as output)
>     - height (minimal height as input and real height as output)
> 
> - Get all supported configurations matching provided filter.
>   Filter may contain any subset of Audio/Video device params.
> 
> Behaviour of probe function can also be modified by flags.
> 
> Signed-off-by: Lukasz Marek <lukasz.m.luki at gmail.com>
> ---
>  libavformat/avformat.h |   97 +++++++++++++++++++++++++++++++++++++++++++++++-
>  libavformat/utils.c    |   72 +++++++++++++++++++++++++++++++++++
>  2 files changed, 167 insertions(+), 2 deletions(-)
> 
> diff --git a/libavformat/avformat.h b/libavformat/avformat.h
> index 6bd54ce..68b9269 100644
> --- a/libavformat/avformat.h
> +++ b/libavformat/avformat.h
> @@ -323,6 +323,28 @@ typedef struct AVFrac {
>      int64_t val, num, den;
>  } AVFrac;
>  
> +/**
> + *
> + */
> +typedef struct AVDeviceConfig {
> +    struct AVDeviceConfig *next;
> +    char* device_name;                  ///< device name, format depends on device
> +    char* device_description;           ///< human friendly name
> +    enum AVCodecID codec;               ///< codec
> +    int format;                         ///< format (AVPixelFormat / AVSampleFormat)
> +    union {
> +        struct {  // audio parameters
> +            int sample_rate;            ///< [in]: expected sample rate,   [out]: device's default sample rate
> +            int channels;               ///< [in]: expected channel count, [out]: device's default channel count
> +            int64_t channel_layout;     ///< [in]: expected layout,        [out]: device's default layout
> +        };
> +        struct {  // video parameters
> +            int width;                  ///< [in]: required width,  [out]: maximum width
> +            int height;                 ///< [in]: required height, [out]: maximum height
> +        };
> +    } stream_info;
> +} AVDeviceConfig;
> +
>  /*************************************************/
>  /* input/output formats */
>  
> @@ -379,6 +401,14 @@ typedef struct AVProbeData {
>  
>  #define AVFMT_SEEK_TO_PTS   0x4000000 /**< Seeking is based on PTS */
>  
> +#define AV_PROBEDEV_DEFAULT_DEV                 0x0001  /**< Probe default device only */
> +#define AV_PROBEDEV_RAW_DATA                    0x0002  /**< Return only raw codecs: AV_CODEC_ID_PCM_*,
> +                                                                                     AV_CODEC_ID_RAWVIDEO */
> +#define AV_PROBEDEV_ALLOW_STREAM_PARAM_CHANGES  0x0004  /**< Allow modification of wanted stream
> +                                                             parameteres when provided value is not supported.
> +                                                             Video devices will update width and height for
> +                                                             screen resolution. */
> +
>  /**
>   * @addtogroup lavf_encoding
>   * @{
> @@ -453,6 +483,11 @@ typedef struct AVOutputFormat {
>  
>      void (*get_output_timestamp)(struct AVFormatContext *s, int stream,
>                                   int64_t *dts, int64_t *wall);
> +
> +    /**
> +     * Probe device. See avformat_probe_device() for more details.
> +     */
> +    AVDeviceConfig* (*probe_device)(AVDeviceConfig *wanted, int flags, AVDictionary *opts);
>  } AVOutputFormat;
>  /**
>   * @}
> @@ -1954,7 +1989,6 @@ enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name,
>  int av_get_output_timestamp(struct AVFormatContext *s, int stream,
>                              int64_t *dts, int64_t *wall);
>  
> -
>  /**
>   * @}
>   */
> @@ -2164,6 +2198,66 @@ int av_match_ext(const char *filename, const char *extensions);
>  int avformat_query_codec(AVOutputFormat *ofmt, enum AVCodecID codec_id, int std_compliance);
>  
>  /**
> + * Probe device and return all valid configurations that are working on hardware.
> + *
> + * Some audio device system may use any sample rate and channel count.
> + * Audio devices will not return all possible stream parameters (sample rate, channel count/layout),
> + * but will return all device names and all codec/format pairs.
> + * Stream parameters will be copied from wanted configuration or default device values will
> + * be used when no wanted value specified.
> + * Stream defaults will also be copied from default device values when provided
> + * configuration is invalid and AV_PROBEDEV_ALLOW_STREAM_PARAM_CHANGES flag is set.
> + *
> + * Video devices will return all devices that fulfill wanted configuration.
> + * They will set width/height with screen resolution when AV_PROBEDEV_ALLOW_STREAM_PARAM_CHANGES flag is set.
> + *
> + * When AV_PROBEDEV_DEFAULT_DEV flag is provided then only default device is returned.
> + * This flag has precedence over devices requested by wanted configuration or options.
> + * When default device cannot be determined, then random one device is returned.
> + *
> + * When AV_PROBEDEV_RAW_DATA flag is provided then only raw codec will be returned.
> + * It is supposed to be useful when filters are used.
> + *
> + * @param ofmt output device context.
> + * @param[out] valid all valid configurations or NULL when no valid configuration detected.
> + *             Returned value must be freed with avformat_free_device_config().
> + * @param wanted expected configuration. May be NULL or not fully filled.
> + * @param flags combination of AV_PROBE_DEVICE_*.
> + * @param opts device options. Meaning of options is device dependent.
> + *        If any option is also available in wanted configuration then wanted
> + *        configuration has precedence.
> + * @return 0 on success, negative otherwise.
> + * @note AVERROR_PATCHWELCOME is returned when device doesn't implement this function.
> + *       In this case, negative result doesn't mean tested configuration is invalid.
> + */
> +int avformat_probe_device(AVOutputFormat *ofmt, AVDeviceConfig **valid,
> +                          AVDeviceConfig *wanted, int flags, AVDictionary *opts);
> +
> +/**
> + * Free device configuration and its internal data.
> + *
> + * @param config data to be freed.
> + */
> +void avformat_free_device_config(AVDeviceConfig **config);
> +
> +/**
> + * Initialize configuration with default values.
> + *
> + * @param config configuration to initialize.
> + *
> + * @note Function doesn't free internal data.
> + */
> +void avformat_device_config_defaults(AVDeviceConfig *config);
> +
> +/**
> + * Copy device configuration.
> + *
> + * @param config configuration to be copied.
> + * @return deep copy of device configuration.
> + */
> +AVDeviceConfig* avformat_copy_device_config(AVDeviceConfig* config);
> +
> +/**
>   * @defgroup riff_fourcc RIFF FourCCs
>   * @{
>   * Get the tables mapping RIFF FourCCs to libavcodec AVCodecIDs. The tables are
> @@ -2235,7 +2329,6 @@ int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st,
>  
>  int avformat_queue_attached_pictures(AVFormatContext *s);
>  
> -
>  /**
>   * @}
>   */
> diff --git a/libavformat/utils.c b/libavformat/utils.c
> index f02312f..d71e9ad 100644
> --- a/libavformat/utils.c
> +++ b/libavformat/utils.c
> @@ -4008,6 +4008,78 @@ int avformat_query_codec(AVOutputFormat *ofmt, enum AVCodecID codec_id, int std_
>      return AVERROR_PATCHWELCOME;
>  }
>  
> +int avformat_probe_device(AVOutputFormat *ofmt, AVDeviceConfig **valid,
> +                          AVDeviceConfig *wanted, int flags, AVDictionary *opts)
> +{
> +    if (!valid)
> +        return -1;
> +    *valid = NULL;
> +    if (!ofmt)
> +        return -1;
> +    if (!ofmt->probe_device)
> +        return AVERROR_PATCHWELCOME;
> +
> +    if (wanted && wanted->codec != AV_CODEC_ID_NONE && wanted->format != -1) {
> +        int i;
> +        AVCodec *codec = avcodec_find_encoder(wanted->codec);
> +        if (!codec)
> +            return -1;
> +        if (codec->sample_fmts)
> +            for (i = 0;; i++) {
> +                if (wanted->format == codec->sample_fmts[i])
> +                    break;
> +                if (codec->sample_fmts[i] == -1)
> +                    return -1;
> +            }
> +        if (codec->pix_fmts)
> +            for (i = 0;; i++) {
> +                if (wanted->format == codec->pix_fmts[i])
> +                    break;
> +                if (codec->pix_fmts[i] == -1)
> +                    return -1;
> +            }
> +    }
> +
> +    *valid = ofmt->probe_device(wanted, flags, opts);
> +    return 0;
> +}
> +
> +void avformat_free_device_config(AVDeviceConfig **config)
> +{
> +    AVDeviceConfig *current, *next;
> +    if (!config)
> +        return;
> +
> +    next = *config;
> +    while (next) {
> +        current = next;
> +        next = current->next;
> +        av_free(current->device_name);
> +        av_free(current->device_description);
> +        av_free(current);
> +    }
> +    *config = NULL;
> +}
> +
> +void avformat_device_config_defaults(AVDeviceConfig *config)
> +{
> +    if (!config)
> +        return;
> +    memset(config, 0, sizeof(AVDeviceConfig));
> +    config->format = -1; /* AV_PIX_FMT_NONE or AV_SAMPLE_FMT_NONE */
> +}
> +
> +AVDeviceConfig* avformat_copy_device_config(AVDeviceConfig* config)
> +{
> +    AVDeviceConfig *copy = av_memdup(config, sizeof(AVDeviceConfig));
> +    if (copy) {
> +        copy->next = NULL;
> +        copy->device_name = av_strdup(config->device_name);
> +        copy->device_description = av_strdup(config->device_description);
> +    }
> +    return copy;
> +}
> +
>  int avformat_network_init(void)
>  {
>  #if CONFIG_NETWORK

Has anyone thought of the idea that the (de)muxer API is maybe not the
best way to handle I/O devices? I think even messing it into
libavfilter might make more sense. Or making a new API.


More information about the ffmpeg-devel mailing list