[FFmpeg-devel] [PATCH] http: add support for reading streamcast metadata

Stefano Sabatini stefasab at gmail.com
Mon Jul 1 10:11:47 CEST 2013


On date Saturday 2013-06-29 16:59:50 +0200, wm4 encoded:
> Actually, one change I made removed 0-termination for a string, so
> here's an updated patch.

> From 06026873ffee9d231075025fe968c6f46d49c3ae Mon Sep 17 00:00:00 2001
> From: wm4 <nfxjfg at googlemail.com>
> Date: Wed, 26 Jun 2013 00:53:26 +0200
> Subject: [PATCH] http: add support for reading streamcast metadata
> 
> Allow applications to request reading streamcast metadata. This uses
> AVOptions as API, and requires the application to explicitly request
> and read metadata. Metadata can be updated mid-stream; if an
> application is interested in that, it has to poll for the data by
> reading the "icy_metadata_packet" option in regular intervals.
> 
> There doesn't seem to be a nice way to transfer the metadata in a nicer
> way. Converting the metadata to ID3v2 tags might be a nice idea, but
> the libavformat mp3 demuxer doesn't seem to read these tags mid-stream,
> and even then we couldn't guarantee that tags are not inserted in the
> middle of mp3 packet data.
> 
> This commit provides the minimum to enable applications to retrieve
> this information at all.
> ---
>  doc/protocols.texi | 14 ++++++++++++++
>  libavformat/http.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 65 insertions(+)
> 
> diff --git a/doc/protocols.texi b/doc/protocols.texi
> index 97ff62d..e8427aa 100644
> --- a/doc/protocols.texi
> +++ b/doc/protocols.texi
> @@ -228,6 +228,20 @@ not specified.
>  @item mime_type
>  Set MIME type.
>  
> + at item icy
> +If set to 1 request ICY (SHOUTcast) metadata from the server. If the server
> +supports this, the metadata has to be retrieved by the application by reading
> +the @option{icy_metadata_headers} and @option{icy_metadata_packet} options.
> +The default is 0.
> +
> + at item icy_metadata_headers
> +If the server supports ICY metadata, this contains the ICY specific HTTP reply
> +headers, separated with newline characters.
> +
> + at item icy_metadata_packet
> +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.
> +
>  @item cookies
>  Set the cookies to be sent in future requests. The format of each cookie is the
>  same as the value of a Set-Cookie HTTP response field. Multiple cookies can be
> diff --git a/libavformat/http.c b/libavformat/http.c
> index 91f8d1f..be82352 100644
> --- a/libavformat/http.c
> +++ b/libavformat/http.c
> @@ -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);

Nit++: you could just write "Icy-MetaData: 1\r\n"

[...]

Patch LGTM, thanks.
-- 
FFmpeg = Furious & Forgiving Mournful Peaceful Extroverse Gadget


More information about the ffmpeg-devel mailing list