AVOptions: add new API for enumerating children.
authorAnton Khirnov <anton@khirnov.net>
Mon, 3 Oct 2011 17:49:12 +0000 (19:49 +0200)
committerAnton Khirnov <anton@khirnov.net>
Wed, 12 Oct 2011 14:51:16 +0000 (16:51 +0200)
This will allow the caller to enumerate child contexts in a generic way
and since the API is recursive, it also allows for deeper nesting (e.g.
AVFormatContext->AVIOContext->URLContext)

This will also allow the new setting/reading API to transparently apply
to children contexts.

libavcodec/options.c
libavformat/options.c
libavutil/log.h
libavutil/opt.c
libavutil/opt.h

index 1c5240634bc0e47a8aa808f36c0d838ed3069bcb..3483db7cc6e638c2a85e7eb63d7544c398e94ca2 100644 (file)
@@ -39,22 +39,27 @@ static const char* context_to_name(void* ptr) {
         return "NULL";
 }
 
-static const AVOption *opt_find(void *obj, const char *name, const char *unit, int opt_flags, int search_flags)
+static void *codec_child_next(void *obj, void *prev)
 {
     AVCodecContext *s = obj;
-    AVCodec        *c = NULL;
+    if (!prev && s->codec && s->codec->priv_class && s->priv_data)
+        return s->priv_data;
+    return NULL;
+}
 
-    if (!(search_flags & AV_OPT_SEARCH_FAKE_OBJ) && s->priv_data) {
-        if (s->codec->priv_class)
-            return av_opt_find(s->priv_data, name, unit, opt_flags, search_flags);
-        return NULL;
-    }
+static const AVClass *codec_child_class_next(const AVClass *prev)
+{
+    AVCodec *c = NULL;
 
-    while ((c = av_codec_next(c))) {
-        const AVOption *o;
-        if (c->priv_class && (o = av_opt_find(&c->priv_class, name, unit, opt_flags, search_flags)))
-            return o;
-    }
+    /* find the codec that corresponds to prev */
+    while (prev && (c = av_codec_next(c)))
+        if (c->priv_class == prev)
+            break;
+
+    /* find next codec with priv options */
+    while (c = av_codec_next(c))
+        if (c->priv_class)
+            return c->priv_class;
     return NULL;
 }
 
@@ -522,7 +527,8 @@ static const AVClass av_codec_context_class = {
     .option                  = options,
     .version                 = LIBAVUTIL_VERSION_INT,
     .log_level_offset_offset = OFFSET(log_level_offset),
-    .opt_find                = opt_find,
+    .child_next              = codec_child_next,
+    .child_class_next        = codec_child_class_next,
 };
 
 void avcodec_get_context_defaults2(AVCodecContext *s, enum AVMediaType codec_type){
index 43a6dec32307fca90b677cca1ad93123c0ac98b0..475166f3ce051e234725eda1cb379c531315ce49 100644 (file)
@@ -33,30 +33,36 @@ static const char* format_to_name(void* ptr)
     else return "NULL";
 }
 
-static const AVOption *opt_find(void *obj, const char *name, const char *unit, int opt_flags, int search_flags)
+static void *format_child_next(void *obj, void *prev)
+{
+    AVFormatContext *s = obj;
+    if (!prev && s->priv_data &&
+        ((s->iformat && s->iformat->priv_class) ||
+          s->oformat && s->oformat->priv_class))
+        return s->priv_data;
+    return NULL;
+}
+
+static const AVClass *format_child_class_next(const AVClass *prev)
 {
-    AVFormatContext   *s = obj;
     AVInputFormat  *ifmt = NULL;
     AVOutputFormat *ofmt = NULL;
-    if (!(search_flags & AV_OPT_SEARCH_FAKE_OBJ) && s->priv_data) {
-        if ((s->iformat && !s->iformat->priv_class) ||
-            (s->oformat && !s->oformat->priv_class))
-            return NULL;
-        return av_opt_find(s->priv_data, name, unit, opt_flags, search_flags);
-    }
-
-    while ((ifmt = av_iformat_next(ifmt))) {
-        const AVOption *o;
-
-        if (ifmt->priv_class && (o = av_opt_find(&ifmt->priv_class, name, unit, opt_flags, search_flags)))
-            return o;
-    }
-    while ((ofmt = av_oformat_next(ofmt))) {
-        const AVOption *o;
-
-        if (ofmt->priv_class && (o = av_opt_find(&ofmt->priv_class, name, unit, opt_flags, search_flags)))
-            return o;
-    }
+
+    while (prev && (ifmt = av_iformat_next(ifmt)))
+        if (ifmt->priv_class == prev)
+            break;
+    if ((prev && ifmt) || (!prev))
+        while (ifmt = av_iformat_next(ifmt))
+            if (ifmt->priv_class)
+                return ifmt->priv_class;
+
+    while (prev && (ofmt = av_oformat_next(ofmt)))
+        if (ofmt->priv_class == prev)
+            break;
+    while (ofmt = av_oformat_next(ofmt))
+        if (ofmt->priv_class)
+            return ofmt->priv_class;
+
     return NULL;
 }
 
@@ -103,7 +109,8 @@ static const AVClass av_format_context_class = {
     .item_name      = format_to_name,
     .option         = options,
     .version        = LIBAVUTIL_VERSION_INT,
-    .opt_find       = opt_find,
+    .child_next     = format_child_next,
+    .child_class_next = format_child_class_next,
 };
 
 static void avformat_get_context_defaults(AVFormatContext *s)
index c1d9a6c39316b69030e5b2872c3346564353c149..18d0ddf0a837ed22e3ebdc3133612329a5570f7e 100644 (file)
@@ -73,11 +73,19 @@ typedef struct {
     int parent_log_context_offset;
 
     /**
-     * A function for extended searching, e.g. in possible
-     * children objects.
+     * Return next AVOptions-enabled child or NULL
      */
-    const struct AVOption* (*opt_find)(void *obj, const char *name, const char *unit,
-                                       int opt_flags, int search_flags);
+    void* (*child_next)(void *obj, void *prev);
+
+    /**
+     * Return an AVClass corresponding to next potential
+     * AVOptions-enabled child.
+     *
+     * The difference between child_next and this is that
+     * child_next iterates over _already existing_ objects, while
+     * child_class_next iterates over _all possible_ children.
+     */
+    const struct AVClass* (*child_class_next)(const struct AVClass *prev);
 } AVClass;
 
 /* av_log API */
index 78fdf63a32ac7c2b6664d7ec418e599e35d3a6e4..b732703c6d67dcbac9fed006ffbef5080a094360 100644 (file)
@@ -583,22 +583,60 @@ int av_opt_set_dict(void *obj, AVDictionary **options)
 const AVOption *av_opt_find(void *obj, const char *name, const char *unit,
                             int opt_flags, int search_flags)
 {
-    AVClass *c = *(AVClass**)obj;
+    return av_opt_find2(obj, name, unit, opt_flags, search_flags, NULL);
+}
+
+const AVOption *av_opt_find2(void *obj, const char *name, const char *unit,
+                             int opt_flags, int search_flags, void **target_obj)
+{
+    const AVClass  *c = *(AVClass**)obj;
     const AVOption *o = NULL;
 
-    if (c->opt_find && search_flags & AV_OPT_SEARCH_CHILDREN &&
-        (o = c->opt_find(obj, name, unit, opt_flags, search_flags)))
-        return o;
+    if (search_flags & AV_OPT_SEARCH_CHILDREN) {
+        if (search_flags & AV_OPT_SEARCH_FAKE_OBJ) {
+            const AVClass *child = NULL;
+            while (child = av_opt_child_class_next(c, child))
+                if (o = av_opt_find2(&child, name, unit, opt_flags, search_flags, NULL))
+                    return o;
+        } else {
+            void *child = NULL;
+            while (child = av_opt_child_next(obj, child))
+                if (o = av_opt_find2(child, name, unit, opt_flags, search_flags, target_obj))
+                    return o;
+        }
+    }
 
     while (o = av_next_option(obj, o)) {
         if (!strcmp(o->name, name) && (o->flags & opt_flags) == opt_flags &&
             ((!unit && o->type != FF_OPT_TYPE_CONST) ||
-             (unit  && o->unit && !strcmp(o->unit, unit))))
+             (unit  && o->unit && !strcmp(o->unit, unit)))) {
+            if (target_obj) {
+                if (!(search_flags & AV_OPT_SEARCH_FAKE_OBJ))
+                    *target_obj = obj;
+                else
+                    *target_obj = NULL;
+            }
             return o;
+        }
     }
     return NULL;
 }
 
+void *av_opt_child_next(void *obj, void *prev)
+{
+    const AVClass *c = *(AVClass**)obj;
+    if (c->child_next)
+        return c->child_next(obj, prev);
+    return NULL;
+}
+
+const AVClass *av_opt_child_class_next(const AVClass *parent, const AVClass *prev)
+{
+    if (parent->child_class_next)
+        return parent->child_class_next(prev);
+    return NULL;
+}
+
 #ifdef TEST
 
 #undef printf
index 50c0a33bc70b32c0234d9a050b5c6e6bb22b1ddf..6f0a03be3cba1aa7abc281441dfff7f54c38a499 100644 (file)
@@ -30,6 +30,7 @@
 #include "rational.h"
 #include "avutil.h"
 #include "dict.h"
+#include "log.h"
 
 enum AVOptionType{
     FF_OPT_TYPE_FLAGS,
@@ -255,4 +256,44 @@ int av_opt_set_dict(void *obj, struct AVDictionary **options);
 const AVOption *av_opt_find(void *obj, const char *name, const char *unit,
                             int opt_flags, int search_flags);
 
+/**
+ * Look for an option in an object. Consider only options which
+ * have all the specified flags set.
+ *
+ * @param[in] obj A pointer to a struct whose first element is a
+ *                pointer to an AVClass.
+ *                Alternatively a double pointer to an AVClass, if
+ *                AV_OPT_SEARCH_FAKE_OBJ search flag is set.
+ * @param[in] name The name of the option to look for.
+ * @param[in] unit When searching for named constants, name of the unit
+ *                 it belongs to.
+ * @param opt_flags Find only options with all the specified flags set (AV_OPT_FLAG).
+ * @param search_flags A combination of AV_OPT_SEARCH_*.
+ * @param[out] target_obj if non-NULL, an object to which the option belongs will be
+ * written here. It may be different from obj if AV_OPT_SEARCH_CHILDREN is present
+ * in search_flags. This parameter is ignored if search_flags contain
+ * AV_OPT_SEARCH_FAKE_OBJ.
+ *
+ * @return A pointer to the option found, or NULL if no option
+ *         was found.
+ */
+const AVOption *av_opt_find2(void *obj, const char *name, const char *unit,
+                             int opt_flags, int search_flags, void **target_obj);
+
+/**
+ * Iterate over AVOptions-enabled children of obj.
+ *
+ * @param prev result of a previous call to this function or NULL
+ * @return next AVOptions-enabled child or NULL
+ */
+void *av_opt_child_next(void *obj, void *prev);
+
+/**
+ * Iterate over potential AVOptions-enabled children of parent.
+ *
+ * @param prev result of a previous call to this function or NULL
+ * @return AVClass corresponding to next potential child or NULL
+ */
+const AVClass *av_opt_child_class_next(const AVClass *parent, const AVClass *prev);
+
 #endif /* AVUTIL_OPT_H */