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

Lukasz Marek lukasz.m.luki at gmail.com
Tue Nov 12 00:11:59 CET 2013


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
-- 
1.7.10.4



More information about the ffmpeg-devel mailing list