|
|
|
@@ -49,6 +49,8 @@ typedef struct { |
|
|
|
char *content_type; |
|
|
|
char *user_agent; |
|
|
|
int64_t off, filesize; |
|
|
|
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[MAX_URL_SIZE]; |
|
|
|
HTTPAuthState auth_state; |
|
|
|
HTTPAuthState proxy_auth_state; |
|
|
|
@@ -65,6 +67,9 @@ typedef struct { |
|
|
|
int rw_timeout; |
|
|
|
char *mime_type; |
|
|
|
char *cookies; ///< holds newline (\n) delimited Set-Cookie header field values (without the "Set-Cookie: " field name) |
|
|
|
int icy; |
|
|
|
char *icy_metadata_headers; |
|
|
|
char *icy_metadata_packet; |
|
|
|
} HTTPContext; |
|
|
|
|
|
|
|
#define OFFSET(x) offsetof(HTTPContext, x) |
|
|
|
@@ -82,6 +87,9 @@ static const AVOption options[] = { |
|
|
|
{"timeout", "set timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E }, |
|
|
|
{"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, 0 }, |
|
|
|
{"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_packet", "return current ICY metadata packet", OFFSET(icy_metadata_packet), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 }, |
|
|
|
{NULL} |
|
|
|
}; |
|
|
|
#define HTTP_CLASS(flavor)\ |
|
|
|
@@ -218,6 +226,7 @@ int ff_http_do_new_request(URLContext *h, const char *uri) |
|
|
|
HTTPContext *s = h->priv_data; |
|
|
|
|
|
|
|
s->off = 0; |
|
|
|
s->icy_data_read = 0; |
|
|
|
av_strlcpy(s->location, uri, sizeof(s->location)); |
|
|
|
|
|
|
|
return http_open_cnx(h); |
|
|
|
@@ -375,6 +384,16 @@ static int process_line(URLContext *h, char *line, int line_count, |
|
|
|
snprintf(s->cookies, str_size, "%s\n%s", tmp, p); |
|
|
|
av_free(tmp); |
|
|
|
} |
|
|
|
} else if (!av_strcasecmp (tag, "Icy-MetaInt")) { |
|
|
|
s->icy_metaint = strtoll(p, NULL, 10); |
|
|
|
} else if (!av_strncasecmp(tag, "Icy-", 4)) { |
|
|
|
// Concat all Icy- header lines |
|
|
|
char *buf = av_asprintf("%s%s: %s\n", |
|
|
|
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; |
|
|
|
} |
|
|
|
} |
|
|
|
return 1; |
|
|
|
@@ -580,6 +599,10 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, |
|
|
|
av_free(cookies); |
|
|
|
} |
|
|
|
} |
|
|
|
if (!has_header(s->headers, "\r\nIcy-MetaData: ") && s->icy) { |
|
|
|
len += av_strlcatf(headers + len, sizeof(headers) - len, |
|
|
|
"Icy-MetaData: %d\r\n", 1); |
|
|
|
} |
|
|
|
|
|
|
|
/* now add in custom headers */ |
|
|
|
if (s->headers) |
|
|
|
@@ -613,6 +636,7 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, |
|
|
|
s->buf_end = s->buffer; |
|
|
|
s->line_count = 0; |
|
|
|
s->off = 0; |
|
|
|
s->icy_data_read = 0; |
|
|
|
s->filesize = -1; |
|
|
|
s->willclose = 0; |
|
|
|
s->end_chunked_post = 0; |
|
|
|
@@ -652,6 +676,7 @@ static int http_buf_read(URLContext *h, uint8_t *buf, int size) |
|
|
|
} |
|
|
|
if (len > 0) { |
|
|
|
s->off += len; |
|
|
|
s->icy_data_read += len; |
|
|
|
if (s->chunksize > 0) |
|
|
|
s->chunksize -= len; |
|
|
|
} |
|
|
|
@@ -693,6 +718,32 @@ static int http_read(URLContext *h, uint8_t *buf, int size) |
|
|
|
} |
|
|
|
size = FFMIN(size, s->chunksize); |
|
|
|
} |
|
|
|
if (s->icy_metaint > 0) { |
|
|
|
int remaining = s->icy_metaint - s->icy_data_read; /* until next metadata packet */ |
|
|
|
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. |
|
|
|
int ch = http_getc(s); |
|
|
|
if (ch < 0) |
|
|
|
return ch; |
|
|
|
if (ch > 0) { |
|
|
|
char data[255 * 16 + 1]; |
|
|
|
int n; |
|
|
|
int ret; |
|
|
|
ch *= 16; |
|
|
|
for (n = 0; n < ch; n++) |
|
|
|
data[n] = http_getc(s); |
|
|
|
data[ch + 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); |
|
|
|
} |
|
|
|
return http_buf_read(h, buf, size); |
|
|
|
} |
|
|
|
|
|
|
|
|