[FFmpeg-devel] [PATCH 2/4] lavd: add device capabilities API

Lukasz Marek lukasz.m.luki at gmail.com
Mon Feb 3 01:02:49 CET 2014


Signed-off-by: Lukasz Marek <lukasz.m.luki at gmail.com>
---
 libavdevice/avdevice.c | 191 +++++++++++++++++++++++++++++++++++++++
 libavdevice/avdevice.h | 238 +++++++++++++++++++++++++++++++++++++++++++++++++
 libavdevice/version.h  |   2 +-
 libavformat/avformat.h |  12 +++
 libavformat/version.h  |   2 +-
 5 files changed, 443 insertions(+), 2 deletions(-)

diff --git a/libavdevice/avdevice.c b/libavdevice/avdevice.c
index 51617fb..fa524a2 100644
--- a/libavdevice/avdevice.c
+++ b/libavdevice/avdevice.c
@@ -17,9 +17,48 @@
  */
 
 #include "libavutil/avassert.h"
+#include "libavcodec/avcodec.h"
 #include "avdevice.h"
 #include "config.h"
 
+#define AVDEVICE_AV_PARAM     AV_OPT_FLAG_AUDIO_PARAM    | AV_OPT_FLAG_VIDEO_PARAM
+#define AVDEVICE_DECENC_PARAM AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+#define AVDEVICE_ALL_PARAM    AVDEVICE_AV_PARAM          | AVDEVICE_DECENC_PARAM
+
+const AVOption av_device_capabilities[] = {
+    { "__device_name",    "device name", offsetof(AVDeviceCapabilities, device_name), AV_OPT_TYPE_STRING,
+        {.str = NULL}, 0, 0, AVDEVICE_ALL_PARAM },
+    { "__device_context",  "device context", offsetof(AVDeviceCapabilities, device_context), AV_OPT_TYPE_POINTER,
+        {.str = NULL}, 0, 0, AVDEVICE_ALL_PARAM },
+    { "__codec",          "codec", offsetof(AVDeviceCapabilities, codec), AV_OPT_TYPE_INT,
+        {.i64 = -1}, -1, INT_MAX, AVDEVICE_ALL_PARAM },
+    { "__format",         "format", offsetof(AVDeviceCapabilities, format), AV_OPT_TYPE_INT,
+        {.i64 = -1}, -1, INT_MAX, AVDEVICE_ALL_PARAM },
+
+    { "__sample_rate",    "sample rate", offsetof(AVDeviceCapabilities, sample_rate), AV_OPT_TYPE_INT,
+        {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_AUDIO_PARAM | AVDEVICE_DECENC_PARAM },
+    { "__channels",       "channels", offsetof(AVDeviceCapabilities, channels), AV_OPT_TYPE_INT,
+        {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_AUDIO_PARAM | AVDEVICE_DECENC_PARAM },
+    { "__channel_layout", "channel layout", offsetof(AVDeviceCapabilities, channel_layout), AV_OPT_TYPE_INT,
+        {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_AUDIO_PARAM | AVDEVICE_DECENC_PARAM },
+
+    { "__window_width",  "window width", offsetof(AVDeviceCapabilities, window_width), AV_OPT_TYPE_INT,
+        {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_VIDEO_PARAM | AVDEVICE_DECENC_PARAM },
+    { "__window_height", "window height", offsetof(AVDeviceCapabilities, window_height), AV_OPT_TYPE_INT,
+        {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_VIDEO_PARAM | AVDEVICE_DECENC_PARAM },
+    { "__frame_width",   "frame width", offsetof(AVDeviceCapabilities, frame_width), AV_OPT_TYPE_INT,
+        {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_VIDEO_PARAM | AVDEVICE_DECENC_PARAM },
+    { "__frame_height",  "frame height", offsetof(AVDeviceCapabilities, frame_height), AV_OPT_TYPE_INT,
+        {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_VIDEO_PARAM | AVDEVICE_DECENC_PARAM },
+    { "__fps",            "fps", offsetof(AVDeviceCapabilities, fps), AV_OPT_TYPE_RATIONAL,
+        {.dbl = -1}, -1, INT_MAX, AV_OPT_FLAG_VIDEO_PARAM | AVDEVICE_DECENC_PARAM },
+    { NULL }
+};
+
+#undef AVDEVICE_AV_PARAM
+#undef AVDEVICE_DECENC_PARAM
+#undef AVDEVICE_ALL_PARAM
+
 unsigned avdevice_version(void)
 {
     av_assert0(LIBAVDEVICE_VERSION_MICRO >= 100);
@@ -52,3 +91,155 @@ int avdevice_dev_to_app_control_message(struct AVFormatContext *s, enum AVDevToA
         return AVERROR(ENOSYS);
     return s->control_message_cb(s, type, data, data_size);
 }
+
+static const char * get_opt_name_from_cap_enum(enum AVDeviceCapability capability)
+{
+    switch (capability) {
+    case AV_DEV_CAP_DEVICE_NAME:
+        return "__device_name";
+    case AV_DEV_CAP_CODEC_ID:
+        return "__codec";
+    case AV_DEV_CAP_FORMAT:
+        return "__format";
+    case AV_DEV_CAP_SAMPLE_RATE:
+        return "__sample_rate";
+    case AV_DEV_CAP_CHANNELS:
+        return "__channels";
+    case AV_DEV_CAP_CHANNEL_LAYOUT:
+        return "__channel_layout";
+    case AV_DEV_CAP_WINDOW_WIDTH:
+        return "__window_width";
+    case AV_DEV_CAP_WINDOW_HEIGHT:
+        return "__window_height";
+    case AV_DEV_CAP_FRAME_WIDTH:
+        return "__frame_width";
+    case AV_DEV_CAP_FRAME_HEIGHT:
+        return "__frame_height";
+    case AV_DEV_CAP_FPS:
+        return "__fps";
+    default:
+        break;
+    }
+    return NULL;
+}
+int avdevice_init_device_capabilities(AVFormatContext *s, AVDictionary **device_options)
+{
+    int ret;
+    if ((ret = av_opt_set_pointer(s->priv_data, "__device_context", s,
+                                  AV_OPT_SEARCH_CHILDREN)) < 0)
+        return (ret == AVERROR_OPTION_NOT_FOUND) ? AVERROR(ENOSYS) : ret;
+    if ((ret = av_opt_set_dict(s->priv_data, device_options)) < 0)
+        return ret;
+    return 0;
+}
+
+int avdevice_finish_device_capabilities(AVFormatContext *s,
+                                        AVDeviceCapabilities **spec,
+                                        enum AVDeviceApplyStrategy strategy)
+{
+    if (!s->oformat || !s->oformat->apply_configuration)
+        return AVERROR(ENOSYS);
+    return s->oformat->apply_configuration(s, (void **)spec, strategy);
+}
+
+void avdevice_free_device_capabilities(AVDeviceCapabilities **spec)
+{
+    if (!spec || !(*spec))
+        return;
+    av_free((*spec)->device_name);
+    av_freep(spec);
+}
+
+int avdevice_get_device_capability(AVFormatContext *s, enum AVDeviceCapability capability,
+                                   AVOptionRanges **allowed_values)
+{
+    const char *opt_name;
+    if (!s || !allowed_values ||
+        !(opt_name = get_opt_name_from_cap_enum(capability)))
+        return AVERROR(EINVAL);
+    return av_opt_query_ranges(allowed_values, s->priv_data, opt_name, AV_OPT_SEARCH_CHILDREN);
+}
+
+int avdevice_set_device_capability_int(AVFormatContext *s,
+                                       enum AVDeviceCapability capability, int64_t value)
+{
+    const char *opt_name;
+    if (!s || !(opt_name = get_opt_name_from_cap_enum(capability)))
+        return AVERROR(EINVAL);
+    switch (capability) {
+    case AV_DEV_CAP_CODEC_ID:
+    case AV_DEV_CAP_FORMAT:
+    case AV_DEV_CAP_SAMPLE_RATE:
+    case AV_DEV_CAP_CHANNELS:
+    case AV_DEV_CAP_CHANNEL_LAYOUT:
+    case AV_DEV_CAP_WINDOW_WIDTH:
+    case AV_DEV_CAP_WINDOW_HEIGHT:
+    case AV_DEV_CAP_FRAME_WIDTH:
+    case AV_DEV_CAP_FRAME_HEIGHT:
+        return av_opt_set_int(s->priv_data, opt_name, value, AV_OPT_SEARCH_CHILDREN);
+    default:
+        break;
+    }
+    av_log(s, AV_LOG_ERROR, "Capability %s is not of integer type.\n", opt_name);
+    return AVERROR(EINVAL);
+}
+
+int avdevice_set_device_capability_string(AVFormatContext *s,
+                                          enum AVDeviceCapability capability,
+                                          const char *value)
+{
+    const char *opt_name;
+    if (!s || !(opt_name = get_opt_name_from_cap_enum(capability)))
+        return AVERROR(EINVAL);
+    switch (capability) {
+    case AV_DEV_CAP_DEVICE_NAME:
+        return av_opt_set(s->priv_data, opt_name, value, AV_OPT_SEARCH_CHILDREN);
+    default:
+        break;
+    }
+    av_log(s, AV_LOG_ERROR, "Capability %s is not of string type.\n", opt_name);
+    return AVERROR(EINVAL);
+}
+
+int avdevice_set_device_capability_q(AVFormatContext *s,
+                                     enum AVDeviceCapability capability,
+                                     AVRational value)
+{
+    const char *opt_name;
+    if (!s || !(opt_name = get_opt_name_from_cap_enum(capability)))
+        return AVERROR(EINVAL);
+    switch (capability) {
+    case AV_DEV_CAP_FPS:
+        return av_opt_set_q(s->priv_data, opt_name, value, AV_OPT_SEARCH_CHILDREN);
+    default:
+        break;
+    }
+    av_log(s, AV_LOG_ERROR, "Capability %s is not of AVRational type.\n", opt_name);
+    return AVERROR(EINVAL);
+}
+
+int avdevice_list_devices(AVFormatContext *s, AVDeviceInfoList **device_list)
+{
+    if (!s->oformat || !s->oformat->get_device_list)
+        return AVERROR(ENOSYS);
+    return s->oformat->get_device_list(s, (void **)device_list);
+}
+
+void avdevice_free_list_devices(AVDeviceInfoList **device_list)
+{
+    AVDeviceInfoList *list;
+    AVDeviceInfo *dev;
+    int i;
+
+    if (!device_list || !(*device_list))
+        return;
+    list = *device_list;
+
+    for (i = 0; i < list->nb_devices; i++) {
+        dev = &list->devices[i];
+        av_free(dev->device_name);
+        av_free(dev->device_description);
+        av_free(dev);
+    }
+    av_freep(device_list);
+}
diff --git a/libavdevice/avdevice.h b/libavdevice/avdevice.h
index a6408ea..bfcca35 100644
--- a/libavdevice/avdevice.h
+++ b/libavdevice/avdevice.h
@@ -43,6 +43,9 @@
  * @}
  */
 
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "libavutil/dict.h"
 #include "libavformat/avformat.h"
 
 /**
@@ -186,4 +189,239 @@ int avdevice_dev_to_app_control_message(struct AVFormatContext *s,
                                         enum AVDevToAppMessageType type,
                                         void *data, size_t data_size);
 
+/**
+ * Structure describes device capabilites.
+ *
+ * It is used by devices in conjuntion with av_device_capabilities AVOption table
+ * to to implement capabilities probing API.
+ */
+typedef struct AVDeviceCapabilities {
+    const AVClass *class;
+    char *device_name;
+    AVFormatContext *device_context;
+    enum AVCodecID codec;
+    int format;                          /**< AVSampleFormat or AVPixelFormat */
+    int sample_rate;
+    int channels;
+    int64_t channel_layout;
+    int window_width;
+    int window_height;
+    int frame_width;
+    int frame_height;
+    AVRational fps;
+} AVDeviceCapabilities;
+
+extern const AVOption av_device_capabilities[];
+
+/**
+ * Enumerates device capabilities that can be probed.
+ */
+enum AVDeviceCapability {
+    /**
+     * Device name.
+     *
+     * set:  set the device to read capability of.
+     * get:  value previously set, use avdevice_list_devices()
+     *       to get full list of the devices.
+     * type: string.
+     */
+    AV_DEV_CAP_DEVICE_NAME,
+
+    /**
+     * Supported codecs.
+     *
+     * set:  limit following queries to configurations supporting the codec.
+     * get:  list all supported codecs.
+     * type: int (enum AVCodecID).
+     */
+    AV_DEV_CAP_CODEC_ID,
+
+    /**
+     * Supported sample/pixel formats.
+     *
+     * set:  limit following queries to configurations supporting the format.
+     * get:  list all supported formats.
+     * type: int (enum AVSampleFormat / enum AVPixelFormat).
+     */
+    AV_DEV_CAP_FORMAT,
+
+    /**
+     * Supported sample/pixel formats.
+     *
+     * set:  limit following queries to configurations supporting the format.
+     * get:  list all supported formats.
+     * type: int (enum AVSampleFormat / enum AVPixelFormat).
+     */
+    AV_DEV_CAP_SAMPLE_RATE,
+
+    /**
+     * Supported channels count.
+     *
+     * set:  limit following queries to configurations supporting the cannels count.
+     * get:  list all supported channels count.
+     * type: int.
+     */
+    AV_DEV_CAP_CHANNELS,
+
+    /**
+     * Supported cannel layouts.
+     *
+     * set:  limit following queries to configurations supporting the cannel layouts.
+     * get:  list all supported cannel layouts.
+     * type: int.
+     */
+    AV_DEV_CAP_CHANNEL_LAYOUT,
+
+    /**
+     * Supported window width/height.
+     *
+     * set:  limit following queries to configurations supporting the window width/height.
+     * get:  list range of supported window width/height.
+     * type: int.
+     */
+    AV_DEV_CAP_WINDOW_WIDTH,
+    AV_DEV_CAP_WINDOW_HEIGHT,
+
+    /**
+     * Supported frame width/height.
+     *
+     * set:  limit following queries to configurations supporting the frame width/height.
+     * get:  list range of supported frame width/height.
+     * type: int.
+     */
+    AV_DEV_CAP_FRAME_WIDTH,
+    AV_DEV_CAP_FRAME_HEIGHT,
+
+    /**
+     * Supported frames per second.
+     *
+     * set:  limit following queries to configurations supporting the fps.
+     * get:  list range of supported fps.
+     * type: int.
+     */
+    AV_DEV_CAP_FPS
+};
+
+enum AVDeviceApplyStrategy {
+    AVDeviceApplyStrategyAbandon,           /**< don't apply settings to device */
+    AVDeviceApplyStrategyAbandonNotValid,   /**< don't apply settings to device when invalid */
+    AVDeviceApplyFixToTheNearestValidValue, /**< adjust values to the nearest valid value */
+    AVDeviceApplyFixToTheBestValidValue     /**< adjust values to the best valid value */
+};
+
+/**
+ * Function prepares the device to be probed.
+ *
+ * This function must be called before using av_device_get_device_capability()
+ * or av_device_set_device_capability_*().
+ * avdevice_finish_device_capabilities() must be called afterwards.
+ *
+ * @param s              device context.
+ * @param device_options device-specific options.
+ * @return >= 0 on success, negative otherwise.
+ */
+int avdevice_init_device_capabilities(AVFormatContext *s,
+                                      AVDictionary **device_options);
+
+/**
+ * Apply set parameters to device context and release data allocated
+ * by avdevice_init_device_capabilities().
+ *
+ * All set capabilities are validated and tested. When configuration is not
+ * working then adjustment takes place according to provided strategy.
+ * After potential adjustments, set capabilities are applied and device configuration.
+ * Mapping between capablities and device settings are device-specific.
+ * In particular output device may not apply all parameters to the context,
+ * but use stream properties when avformat_write_header() is called.
+ *
+ * @note: This may be useful to validate if input stream may be passed directly
+ *        to output device, but usually capabilites should be tested one by one
+ *        and correct values should be provided.
+ *
+ * @param s         device context
+ * @param[out] spec returns device configuration. May be NULL. If not NULL
+ *                  then must be freed with avdevice_free_device_capabilities().
+ * @param strategy  fixing values strategy. Ignored when spec is not provided.
+ * @return >= 0 on success, negative otherwise.
+ *         AVERROR(EINVAL) when strategy is not implemented.
+ */
+int avdevice_finish_device_capabilities(AVFormatContext *s,
+                                        AVDeviceCapabilities **spec,
+                                        enum AVDeviceApplyStrategy strategy);
+
+/**
+ * Free AVDeviceCapabilities struct and its allocated data.
+ *
+ * @param spec structure to be freed
+ */
+void avdevice_free_device_capabilities(AVDeviceCapabilities **spec);
+
+/**
+ * Return range(s) of valid values for device capability.
+ *
+ * This function allow to get ranges of values for device capability.
+ * Returned ranges takes into account real device capablities and
+ * values previously set by avdevice_set_device_capability_* functions.
+ * For example list of supported formats may dependes on the codec set previously,
+ * fps may depends on resolution or codec set previously.
+ *
+ * @param s           device context
+ * @param capability  capability to be tested.
+ * @param[out] ranges list of allowed ranges for selected capability.
+ * @return >= 0 on success, negative otherwise.
+ */
+int avdevice_get_device_capability(AVFormatContext *s,
+                                   enum AVDeviceCapability capability,
+                                   AVOptionRanges **ranges);
+
+/**
+ * Set device capability.
+ *
+ * @param s     device context
+ * @param value new value for capability
+ * @return >= 0 on success, negative otherwise.
+ */
+int avdevice_set_device_capability_int(AVFormatContext *s,
+                                       enum AVDeviceCapability capability,
+                                       int64_t value);
+int avdevice_set_device_capability_string(AVFormatContext *s,
+                                          enum AVDeviceCapability capability,
+                                          const char *value);
+int avdevice_set_device_capability_q(AVFormatContext *s,
+                                     enum AVDeviceCapability capability,
+                                     AVRational value);
+
+/**
+ * Structure describes basic parameters of the device.
+ */
+typedef struct AVDeviceInfo {
+    char *device_name;                   /**< device name, format depends on device */
+    char *device_description;            /**< human friendly name */
+} AVDeviceInfo;
+
+/**
+ * List of available devices.
+ */
+typedef struct AVDeviceInfoList {
+    AVDeviceInfo *devices;               /**< list of autodetected devices */
+    int nb_devices;                      /**< number of autodetected devices */
+    int default_device;                  /**< index of default device */
+} AVDeviceInfoList;
+
+/**
+ * List available devices.
+ *
+ * @param ofmt         device format.
+ * @param[out] devices list of autodetected devices.
+ * @return count of autodetected devices, negative on error.
+ */
+int avdevice_list_devices(struct AVFormatContext *s, AVDeviceInfoList **device_list);
+
+/**
+ * Convinient function to free result of avdevice_list_devices().
+ *
+ * @param devices device list to be freed.
+ */
+void avdevice_free_list_devices(AVDeviceInfoList **device_list);
+
 #endif /* AVDEVICE_AVDEVICE_H */
diff --git a/libavdevice/version.h b/libavdevice/version.h
index a621775..0dedc73 100644
--- a/libavdevice/version.h
+++ b/libavdevice/version.h
@@ -28,7 +28,7 @@
 #include "libavutil/version.h"
 
 #define LIBAVDEVICE_VERSION_MAJOR  55
-#define LIBAVDEVICE_VERSION_MINOR   7
+#define LIBAVDEVICE_VERSION_MINOR   8
 #define LIBAVDEVICE_VERSION_MICRO 100
 
 #define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 50b7108..58bed4e 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -458,6 +458,18 @@ typedef struct AVOutputFormat {
      */
     int (*control_message)(struct AVFormatContext *s, int type,
                            void *data, size_t data_size);
+    /**
+     * Returns device list with it properties.
+     * @see avdevice_list_devices() for more details.
+     */
+    int (*get_device_list)(struct AVFormatContext *s, void **device_list);
+    /**
+     * Allows to apply device configuration via avdevice_set_device_capability_*
+     * API with posibility to adjust not matching configuration.
+     * @see avdevice_finish_device_capabilities() for more details.
+     */
+    int (*apply_configuration)(struct AVFormatContext *s, void **configuration,
+                               int strategy);
 } AVOutputFormat;
 /**
  * @}
diff --git a/libavformat/version.h b/libavformat/version.h
index 38945a5..0fcbe60 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -30,7 +30,7 @@
 #include "libavutil/version.h"
 
 #define LIBAVFORMAT_VERSION_MAJOR 55
-#define LIBAVFORMAT_VERSION_MINOR 29
+#define LIBAVFORMAT_VERSION_MINOR 30
 #define LIBAVFORMAT_VERSION_MICRO 100
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
-- 
1.8.3.2



More information about the ffmpeg-devel mailing list