Commit ca2369cd authored by Michael Niedermayer's avatar Michael Niedermayer

Merge commit '8075c3d8'

* commit '8075c3d8':
  http: Add support reading ICY metadata

Conflicts:
	doc/protocols.texi
	libavformat/http.c

See: a92fbe16
See: 636273d3Merged-by: 's avatarMichael Niedermayer <michaelni@gmx.at>
parents 21d4c571 8075c3d8
...@@ -213,7 +213,7 @@ m3u8 files. ...@@ -213,7 +213,7 @@ m3u8 files.
HTTP (Hyper Text Transfer Protocol). HTTP (Hyper Text Transfer Protocol).
This protocol accepts the following options. This protocol accepts the following options:
@table @option @table @option
@item seekable @item seekable
...@@ -257,12 +257,14 @@ the @option{icy_metadata_headers} and @option{icy_metadata_packet} options. ...@@ -257,12 +257,14 @@ the @option{icy_metadata_headers} and @option{icy_metadata_packet} options.
The default is 0. The default is 0.
@item icy_metadata_headers @item icy_metadata_headers
If the server supports ICY metadata, this contains the ICY specific HTTP reply If the server supports ICY metadata, this contains the ICY-specific HTTP reply
headers, separated with newline characters. headers, separated by newline characters.
@item icy_metadata_packet @item icy_metadata_packet
If the server supports ICY metadata, and @option{icy} was set to 1, this If the server supports ICY metadata, and @option{icy} was set to 1, this
contains the last non-empty metadata packet sent by the server. contains the last non-empty metadata packet sent by the server. It should be
polled in regular intervals by applications interested in mid-stream metadata
updates.
@item cookies @item cookies
Set the cookies to be sent in future requests. The format of each cookie is the Set the cookies to be sent in future requests. The format of each cookie is the
......
...@@ -54,8 +54,6 @@ typedef struct { ...@@ -54,8 +54,6 @@ typedef struct {
char *content_type; char *content_type;
char *user_agent; char *user_agent;
int64_t off, filesize, req_end_offset; int64_t off, filesize, req_end_offset;
int icy_data_read; ///< how much data was read since last ICY metadata packet
int icy_metaint; ///< after how many bytes of read data a new metadata packet will be found
char *location; char *location;
HTTPAuthState auth_state; HTTPAuthState auth_state;
HTTPAuthState proxy_auth_state; HTTPAuthState proxy_auth_state;
...@@ -78,6 +76,10 @@ typedef struct { ...@@ -78,6 +76,10 @@ typedef struct {
char *mime_type; char *mime_type;
char *cookies; ///< holds newline (\n) delimited Set-Cookie header field values (without the "Set-Cookie: " field name) char *cookies; ///< holds newline (\n) delimited Set-Cookie header field values (without the "Set-Cookie: " field name)
int icy; int icy;
/* how much data was read since the last ICY metadata packet */
int icy_data_read;
/* after how many bytes of read data a new metadata packet will be found */
int icy_metaint;
char *icy_metadata_headers; char *icy_metadata_headers;
char *icy_metadata_packet; char *icy_metadata_packet;
#if CONFIG_ZLIB #if CONFIG_ZLIB
...@@ -104,8 +106,8 @@ static const AVOption options[] = { ...@@ -104,8 +106,8 @@ static const AVOption options[] = {
{"mime_type", "set MIME type", OFFSET(mime_type), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 }, {"mime_type", "set MIME type", OFFSET(mime_type), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 },
{"cookies", "set cookies to be sent in applicable future requests, use newline delimited Set-Cookie HTTP field value syntax", OFFSET(cookies), AV_OPT_TYPE_STRING, {0}, 0, 0, D }, {"cookies", "set cookies to be sent in applicable future requests, use newline delimited Set-Cookie HTTP field value syntax", OFFSET(cookies), AV_OPT_TYPE_STRING, {0}, 0, 0, D },
{"icy", "request ICY metadata", OFFSET(icy), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D }, {"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, 0 }, {"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, 0 }, {"icy_metadata_packet", "return current ICY metadata packet", OFFSET(icy_metadata_packet), AV_OPT_TYPE_STRING, {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" }, {"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" }, {"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" }, {"basic", "HTTP basic authentication", 0, AV_OPT_TYPE_CONST, {.i64 = HTTP_AUTH_BASIC}, 0, 0, D|E, "auth_type" },
...@@ -403,6 +405,23 @@ static int parse_content_encoding(URLContext *h, char *p) ...@@ -403,6 +405,23 @@ static int parse_content_encoding(URLContext *h, char *p)
return 0; return 0;
} }
// Concat all Icy- header lines
static int parse_icy(HTTPContext *s, const char *tag, const char *p)
{
int len = 4 + strlen(p) + strlen(tag);
int ret;
if (s->icy_metadata_headers)
len += strlen(s->icy_metadata_headers);
if ((ret = av_reallocp(&s->icy_metadata_headers, len)) < 0)
return ret;
av_strlcatf(s->icy_metadata_headers, len, "%s: %s\n", tag, p);
return 0;
}
static int process_line(URLContext *h, char *line, int line_count, static int process_line(URLContext *h, char *line, int line_count,
int *new_location) int *new_location)
{ {
...@@ -489,13 +508,8 @@ static int process_line(URLContext *h, char *line, int line_count, ...@@ -489,13 +508,8 @@ static int process_line(URLContext *h, char *line, int line_count,
} else if (!av_strcasecmp (tag, "Icy-MetaInt")) { } else if (!av_strcasecmp (tag, "Icy-MetaInt")) {
s->icy_metaint = strtoll(p, NULL, 10); s->icy_metaint = strtoll(p, NULL, 10);
} else if (!av_strncasecmp(tag, "Icy-", 4)) { } else if (!av_strncasecmp(tag, "Icy-", 4)) {
// Concat all Icy- header lines if ((ret = parse_icy(s, tag, p)) < 0)
char *buf = av_asprintf("%s%s: %s\n", return ret;
s->icy_metadata_headers ? s->icy_metadata_headers : "", tag, p);
if (!buf)
return AVERROR(ENOMEM);
av_freep(&s->icy_metadata_headers);
s->icy_metadata_headers = buf;
} else if (!av_strcasecmp(tag, "Content-Encoding")) { } else if (!av_strcasecmp(tag, "Content-Encoding")) {
if ((ret = parse_content_encoding(h, p)) < 0) if ((ret = parse_content_encoding(h, p)) < 0)
return ret; return ret;
...@@ -905,37 +919,52 @@ static int http_read_stream_all(URLContext *h, uint8_t *buf, int size) ...@@ -905,37 +919,52 @@ static int http_read_stream_all(URLContext *h, uint8_t *buf, int size)
return pos; return pos;
} }
static int store_icy(URLContext *h, int size)
{
HTTPContext *s = h->priv_data;
/* until next metadata packet */
int remaining = s->icy_metaint - s->icy_data_read;
if (remaining < 0)
return AVERROR_INVALIDDATA;
if (!remaining) {
// The metadata packet is variable sized. It has a 1 byte header
// which sets the length of the packet (divided by 16). If it's 0,
// the metadata doesn't change. After the packet, icy_metaint bytes
// of normal data follow.
uint8_t ch;
int len = http_read_stream_all(h, &ch, 1);
if (len < 0)
return len;
if (ch > 0) {
char data[255 * 16 + 1];
int ret;
len = ch * 16;
ret = http_read_stream_all(h, data, len);
if (ret < 0)
return ret;
data[len + 1] = 0;
if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0)
return ret;
}
s->icy_data_read = 0;
remaining = s->icy_metaint;
}
return FFMIN(size, remaining);
}
static int http_read(URLContext *h, uint8_t *buf, int size) static int http_read(URLContext *h, uint8_t *buf, int size)
{ {
HTTPContext *s = h->priv_data; HTTPContext *s = h->priv_data;
if (s->icy_metaint > 0) { if (s->icy_metaint > 0) {
int remaining = s->icy_metaint - s->icy_data_read; /* until next metadata packet */ size = store_icy(h, size);
if (!remaining) { if (size < 0)
// The metadata packet is variable sized. It has a 1 byte header return size;
// which sets the length of the packet (divided by 16). If it's 0,
// the metadata doesn't change. After the packet, icy_metaint bytes
// of normal data follow.
uint8_t ch;
int len = http_read_stream_all(h, &ch, 1);
if (len < 1)
return len;
if (ch > 0) {
char data[255 * 16 + 1];
int ret;
len = ch * 16;
ret = http_read_stream_all(h, data, len);
if (ret < len)
return ret;
data[len + 1] = 0;
if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0)
return ret;
}
s->icy_data_read = 0;
remaining = s->icy_metaint;
}
size = FFMIN(size, remaining);
} }
size = http_read_stream(h, buf, size); size = http_read_stream(h, buf, size);
if (size > 0) if (size > 0)
s->icy_data_read += size; s->icy_data_read += size;
......
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