Exporting icecast metadata as an option with name "metadata" so that it can be
pulled more easily. Also adding a dict type to AVOption to allow for easier
export of metadata (as suggested here:
https://lists.libav.org/pipermail/libav-devel/2014-May/060016.html).
---
libavformat/http.c | 32 ++++++++++++++++++++++++++++++
libavutil/dict.c | 2 +-
libavutil/dict.h | 2 +-
libavutil/opt.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++----
libavutil/opt.h | 26 ++++++++++++++-----------
5 files changed, 102 insertions(+), 17 deletions(-)
diff --git a/libavformat/http.c b/libavformat/http.c
index 948930a..10c2d0e 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -78,6 +78,7 @@ typedef struct {
int icy_metaint;
char *icy_metadata_headers;
char *icy_metadata_packet;
+ AVDictionary *metadata;
#if CONFIG_ZLIB
int compressed;
z_stream inflate_stream;
@@ -103,6 +104,7 @@ static const AVOption options[] = {
{"icy", "request ICY metadata", OFFSET(icy), AV_OPT_TYPE_INT, {.i64 = 0}, 0,
1, D },
{"icy_metadata_headers", "return ICY metadata headers",
OFFSET(icy_metadata_headers), AV_OPT_TYPE_STRING, {0}, 0, 0, AV_OPT_FLAG_EXPORT
},
{"icy_metadata_packet", "return current ICY metadata packet",
OFFSET(icy_metadata_packet), AV_OPT_TYPE_STRING, {0}, 0, 0, AV_OPT_FLAG_EXPORT
},
+{"metadata", "metadata read from the bitstream", OFFSET(metadata),
AV_OPT_TYPE_DICT, {0}, 0, 0, AV_OPT_FLAG_EXPORT },
{"auth_type", "HTTP authentication type", OFFSET(auth_state.auth_type),
AV_OPT_TYPE_INT, {.i64 = HTTP_AUTH_NONE}, HTTP_AUTH_NONE, HTTP_AUTH_BASIC, D|E,
"auth_type" },
{"none", "No auth method set, autodetect", 0, AV_OPT_TYPE_CONST, {.i64 =
HTTP_AUTH_NONE}, 0, 0, D|E, "auth_type" },
{"basic", "HTTP basic authentication", 0, AV_OPT_TYPE_CONST, {.i64 =
HTTP_AUTH_BASIC}, 0, 0, D|E, "auth_type" },
@@ -784,6 +786,32 @@ static int http_read_stream_all(URLContext *h, uint8_t
*buf, int size)
return pos;
}
+static void update_metadata(HTTPContext *s, char *data)
+{
+ char *key;
+ char *val;
+ char *end;
+ char *next = data;
+
+ while (1) {
+ key = next;
+ val = strstr(key, "='");
+ if (!val)
+ break;
+ end = strstr(val, "';");
+ if (!end)
+ break;
+
+ *val = '\0';
+ *end = '\0';
+ val += 2;
+
+ av_dict_set(&s->metadata, key, val, 0);
+
+ next = end + 2;
+ }
+}
+
static int store_icy(URLContext *h, int size)
{
HTTPContext *s = h->priv_data;
@@ -810,9 +838,13 @@ static int store_icy(URLContext *h, int size)
if (ret < 0)
return ret;
data[len + 1] = 0;
+
if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0)
return ret;
+
+ update_metadata(s, data);
}
+
s->icy_data_read = 0;
remaining = s->icy_metaint;
}
diff --git a/libavutil/dict.c b/libavutil/dict.c
index 7e49bbe..101bed7 100644
--- a/libavutil/dict.c
+++ b/libavutil/dict.c
@@ -186,7 +186,7 @@ void av_dict_free(AVDictionary **pm)
av_freep(pm);
}
-void av_dict_copy(AVDictionary **dst, AVDictionary *src, int flags)
+void av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
{
AVDictionaryEntry *t = NULL;
diff --git a/libavutil/dict.h b/libavutil/dict.h
index d7415c3..f835fca 100644
--- a/libavutil/dict.h
+++ b/libavutil/dict.h
@@ -141,7 +141,7 @@ int av_dict_parse_string(AVDictionary **pm, const char *str,
* @param flags flags to use when setting entries in *dst
* @note metadata is read using the AV_DICT_IGNORE_SUFFIX flag
*/
-void av_dict_copy(AVDictionary **dst, AVDictionary *src, int flags);
+void av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags);
/**
* Free all the memory allocated for an AVDictionary struct
diff --git a/libavutil/opt.c b/libavutil/opt.c
index 9f9f1f2..b6c9275 100644
--- a/libavutil/opt.c
+++ b/libavutil/opt.c
@@ -307,6 +307,24 @@ int av_opt_set_bin(void *obj, const char *name, const
uint8_t *val, int len, int
return 0;
}
+int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val,
int search_flags)
+{
+ void *target_obj;
+ AVDictionary **dst;
+ const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags,
&target_obj);
+
+ if (!o || !target_obj)
+ return AVERROR_OPTION_NOT_FOUND;
+ if (o->flags & AV_OPT_FLAG_READONLY)
+ return AVERROR(EINVAL);
+
+ dst = (AVDictionary**)(((uint8_t*)target_obj) + o->offset);
+ av_dict_free(dst);
+ av_dict_copy(dst, val, 0);
+
+ return 0;
+}
+
int av_opt_get(void *obj, const char *name, int search_flags, uint8_t
**out_val)
{
void *dst, *target_obj;
@@ -410,6 +428,23 @@ int av_opt_get_q(void *obj, const char *name, int
search_flags, AVRational *out_
return 0;
}
+int av_opt_get_dict_val(void *obj, const char *name, int search_flags,
AVDictionary **out_val)
+{
+ void *target_obj;
+ AVDictionary *src;
+ const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags,
&target_obj);
+
+ if (!o || !target_obj)
+ return AVERROR_OPTION_NOT_FOUND;
+ if (o->type != AV_OPT_TYPE_DICT)
+ return AVERROR(EINVAL);
+
+ src = *(AVDictionary**)(((uint8_t*)target_obj) + o->offset);
+ av_dict_copy(out_val, src, 0);
+
+ return 0;
+}
+
int av_opt_flag_is_set(void *obj, const char *field_name, const char
*flag_name)
{
const AVOption *field = av_opt_find(obj, field_name, NULL, 0, 0);
@@ -539,7 +574,8 @@ void av_opt_set_defaults(void *s)
av_opt_set(s, opt->name, opt->default_val.str, 0);
break;
case AV_OPT_TYPE_BINARY:
- /* Cannot set default for binary */
+ case AV_OPT_TYPE_DICT:
+ /* Cannot set defaults for these types */
break;
default:
av_log(s, AV_LOG_DEBUG, "AVOption type %d of option %s not
implemented yet\n", opt->type, opt->name);
@@ -621,9 +657,22 @@ int av_set_options_string(void *ctx, const char *opts,
void av_opt_free(void *obj)
{
const AVOption *o = NULL;
- while ((o = av_opt_next(obj, o)))
- if (o->type == AV_OPT_TYPE_STRING || o->type == AV_OPT_TYPE_BINARY)
- av_freep((uint8_t *)obj + o->offset);
+ while ((o = av_opt_next(obj, o))) {
+ switch (o->type) {
+ case AV_OPT_TYPE_STRING:
+ case AV_OPT_TYPE_BINARY:
+ av_freep((uint8_t *)obj + o->offset);
+ break;
+
+ case AV_OPT_TYPE_DICT: {
+ av_dict_free((AVDictionary**)(((uint8_t*)obj) + o->offset));
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
}
int av_opt_set_dict(void *obj, AVDictionary **options)
diff --git a/libavutil/opt.h b/libavutil/opt.h
index b90feaa..3a712fe 100644
--- a/libavutil/opt.h
+++ b/libavutil/opt.h
@@ -223,7 +223,8 @@ enum AVOptionType{
AV_OPT_TYPE_FLOAT,
AV_OPT_TYPE_STRING,
AV_OPT_TYPE_RATIONAL,
- AV_OPT_TYPE_BINARY, ///< offset must point to a pointer immediately
followed by an int for the length
+ AV_OPT_TYPE_BINARY,
+ AV_OPT_TYPE_DICT, ///< offset must point to a pointer immediately
followed by an int for the length
AV_OPT_TYPE_CONST = 128,
};
@@ -253,6 +254,7 @@ typedef struct AVOption {
int64_t i64;
double dbl;
const char *str;
+ AVDictionary *dict;
/* TODO those are unused now */
AVRational q;
} default_val;
@@ -325,7 +327,7 @@ int av_set_options_string(void *ctx, const char *opts,
const char *key_val_sep, const char *pairs_sep);
/**
- * Free all string and binary options in obj.
+ * Free all allocated objects in obj.
*/
void av_opt_free(void *obj);
@@ -491,11 +493,12 @@ const AVClass *av_opt_child_class_next(const AVClass
*parent, const AVClass *pre
* AVERROR(ERANGE) if the value is out of range
* AVERROR(EINVAL) if the value is not valid
*/
-int av_opt_set (void *obj, const char *name, const char *val, int
search_flags);
-int av_opt_set_int (void *obj, const char *name, int64_t val, int
search_flags);
-int av_opt_set_double(void *obj, const char *name, double val, int
search_flags);
-int av_opt_set_q (void *obj, const char *name, AVRational val, int
search_flags);
-int av_opt_set_bin (void *obj, const char *name, const uint8_t *val, int
size, int search_flags);
+int av_opt_set (void *obj, const char *name, const char *val, int
search_flags);
+int av_opt_set_int (void *obj, const char *name, int64_t val, int
search_flags);
+int av_opt_set_double (void *obj, const char *name, double val, int
search_flags);
+int av_opt_set_q (void *obj, const char *name, AVRational val, int
search_flags);
+int av_opt_set_bin (void *obj, const char *name, const uint8_t *val, int
size, int search_flags);
+int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val,
int search_flags);
/**
* @}
*/
@@ -515,10 +518,11 @@ int av_opt_set_bin (void *obj, const char *name, const
uint8_t *val, int size,
/**
* @note the returned string will av_malloc()ed and must be av_free()ed by the
caller
*/
-int av_opt_get (void *obj, const char *name, int search_flags, uint8_t
**out_val);
-int av_opt_get_int (void *obj, const char *name, int search_flags, int64_t
*out_val);
-int av_opt_get_double(void *obj, const char *name, int search_flags, double
*out_val);
-int av_opt_get_q (void *obj, const char *name, int search_flags,
AVRational *out_val);
+int av_opt_get (void *obj, const char *name, int search_flags, uint8_t
**out_val);
+int av_opt_get_int (void *obj, const char *name, int search_flags, int64_t
*out_val);
+int av_opt_get_double (void *obj, const char *name, int search_flags, double
*out_val);
+int av_opt_get_q (void *obj, const char *name, int search_flags,
AVRational *out_val);
+int av_opt_get_dict_val(void *obj, const char *name, int search_flags,
AVDictionary **out_val);
/**
* @}
* @}
--
2.0.0.rc2
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel