Commit 641c7afe authored by Anton Khirnov's avatar Anton Khirnov

AVOptions: add new API for enumerating children.

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.
parent 1bca8f4b
...@@ -39,22 +39,27 @@ static const char* context_to_name(void* ptr) { ...@@ -39,22 +39,27 @@ static const char* context_to_name(void* ptr) {
return "NULL"; 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; AVCodecContext *s = obj;
if (!prev && s->codec && s->codec->priv_class && s->priv_data)
return s->priv_data;
return NULL;
}
static const AVClass *codec_child_class_next(const AVClass *prev)
{
AVCodec *c = NULL; AVCodec *c = NULL;
if (!(search_flags & AV_OPT_SEARCH_FAKE_OBJ) && s->priv_data) { /* find the codec that corresponds to prev */
if (s->codec->priv_class) while (prev && (c = av_codec_next(c)))
return av_opt_find(s->priv_data, name, unit, opt_flags, search_flags); if (c->priv_class == prev)
return NULL; break;
}
while ((c = av_codec_next(c))) { /* find next codec with priv options */
const AVOption *o; while (c = av_codec_next(c))
if (c->priv_class && (o = av_opt_find(&c->priv_class, name, unit, opt_flags, search_flags))) if (c->priv_class)
return o; return c->priv_class;
}
return NULL; return NULL;
} }
...@@ -522,7 +527,8 @@ static const AVClass av_codec_context_class = { ...@@ -522,7 +527,8 @@ static const AVClass av_codec_context_class = {
.option = options, .option = options,
.version = LIBAVUTIL_VERSION_INT, .version = LIBAVUTIL_VERSION_INT,
.log_level_offset_offset = OFFSET(log_level_offset), .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){ void avcodec_get_context_defaults2(AVCodecContext *s, enum AVMediaType codec_type){
......
...@@ -33,30 +33,36 @@ static const char* format_to_name(void* ptr) ...@@ -33,30 +33,36 @@ static const char* format_to_name(void* ptr)
else return "NULL"; 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; 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)
{
AVInputFormat *ifmt = NULL; AVInputFormat *ifmt = NULL;
AVOutputFormat *ofmt = 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))) { while (prev && (ifmt = av_iformat_next(ifmt)))
const AVOption *o; if (ifmt->priv_class == prev)
break;
if ((prev && ifmt) || (!prev))
while (ifmt = av_iformat_next(ifmt))
if (ifmt->priv_class)
return ifmt->priv_class;
if (ifmt->priv_class && (o = av_opt_find(&ifmt->priv_class, name, unit, opt_flags, search_flags))) while (prev && (ofmt = av_oformat_next(ofmt)))
return o; if (ofmt->priv_class == prev)
} break;
while ((ofmt = av_oformat_next(ofmt))) { while (ofmt = av_oformat_next(ofmt))
const AVOption *o; if (ofmt->priv_class)
return ofmt->priv_class;
if (ofmt->priv_class && (o = av_opt_find(&ofmt->priv_class, name, unit, opt_flags, search_flags)))
return o;
}
return NULL; return NULL;
} }
...@@ -103,7 +109,8 @@ static const AVClass av_format_context_class = { ...@@ -103,7 +109,8 @@ static const AVClass av_format_context_class = {
.item_name = format_to_name, .item_name = format_to_name,
.option = options, .option = options,
.version = LIBAVUTIL_VERSION_INT, .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) static void avformat_get_context_defaults(AVFormatContext *s)
......
...@@ -73,11 +73,19 @@ typedef struct { ...@@ -73,11 +73,19 @@ typedef struct {
int parent_log_context_offset; int parent_log_context_offset;
/** /**
* A function for extended searching, e.g. in possible * Return next AVOptions-enabled child or NULL
* children objects.
*/ */
const struct AVOption* (*opt_find)(void *obj, const char *name, const char *unit, void* (*child_next)(void *obj, void *prev);
int opt_flags, int search_flags);
/**
* 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; } AVClass;
/* av_log API */ /* av_log API */
......
...@@ -583,19 +583,57 @@ int av_opt_set_dict(void *obj, AVDictionary **options) ...@@ -583,19 +583,57 @@ int av_opt_set_dict(void *obj, AVDictionary **options)
const AVOption *av_opt_find(void *obj, const char *name, const char *unit, const AVOption *av_opt_find(void *obj, const char *name, const char *unit,
int opt_flags, int search_flags) 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; const AVOption *o = NULL;
if (c->opt_find && search_flags & AV_OPT_SEARCH_CHILDREN && if (search_flags & AV_OPT_SEARCH_CHILDREN) {
(o = c->opt_find(obj, name, unit, opt_flags, search_flags))) 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; return o;
}
}
while (o = av_next_option(obj, o)) { while (o = av_next_option(obj, o)) {
if (!strcmp(o->name, name) && (o->flags & opt_flags) == opt_flags && if (!strcmp(o->name, name) && (o->flags & opt_flags) == opt_flags &&
((!unit && o->type != FF_OPT_TYPE_CONST) || ((!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 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; return NULL;
} }
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "rational.h" #include "rational.h"
#include "avutil.h" #include "avutil.h"
#include "dict.h" #include "dict.h"
#include "log.h"
enum AVOptionType{ enum AVOptionType{
FF_OPT_TYPE_FLAGS, FF_OPT_TYPE_FLAGS,
...@@ -255,4 +256,44 @@ int av_opt_set_dict(void *obj, struct AVDictionary **options); ...@@ -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, const AVOption *av_opt_find(void *obj, const char *name, const char *unit,
int opt_flags, int search_flags); 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 */ #endif /* AVUTIL_OPT_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment