[MPlayer-dev-eng] [PATCH] shoutcast/ultravox support
Reimar Döffinger
Reimar.Doeffinger at stud.uni-karlsruhe.de
Sun Jul 17 15:41:35 CEST 2005
Hi,
it could probably be improved, but I think it works well enough to be
applied soon (I am open to suggestions though).
The samples on winamp.com almost work with this patch, I see two
remaining issues:
1) sound does not work (at least that problem we seem to have in common
with xine *g*)
2) framerate is not detected correctly
Greetings,
Reimar Döffinger
-------------- next part --------------
Index: libmpdemux/network.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/network.c,v
retrieving revision 1.114
diff -u -r1.114 network.c
--- libmpdemux/network.c 10 Jul 2005 14:09:45 -0000 1.114
+++ libmpdemux/network.c 17 Jul 2005 13:40:47 -0000
@@ -400,6 +400,8 @@
else
http_set_field( http_hdr, "User-Agent: MPlayer/"VERSION);
+ http_set_field(http_hdr, "Icy-MetaData: 1");
+
if(pos>0) {
// Extend http_send_request with possibility to do partial content retrieval
#ifdef __MINGW32__
Index: libmpdemux/http.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/http.c,v
retrieving revision 1.23
diff -u -r1.23 http.c
--- libmpdemux/http.c 16 Jun 2005 07:42:01 -0000 1.23
+++ libmpdemux/http.c 17 Jul 2005 13:40:50 -0000
@@ -34,6 +34,144 @@
extern int http_seek(stream_t *stream, off_t pos);
+typedef struct {
+ unsigned metaint;
+ unsigned metapos;
+ int is_ultravox;
+} scast_data_t;
+
+/**
+ * \brief first read any data from sc->buffer then from fd
+ * \param fd file descriptor to read data from
+ * \param buffer buffer to read into
+ * \param len how many bytes to read
+ * \param sc streaming control containing buffer to read from first
+ * \return len unless there is a read error or eof
+ */
+static unsigned my_read(int fd, char *buffer, int len, streaming_ctrl_t *sc) {
+ unsigned pos = 0;
+ unsigned cp_len = sc->buffer_size - sc->buffer_pos;
+ if (cp_len > len)
+ cp_len = len;
+ memcpy(buffer, &sc->buffer[sc->buffer_pos], cp_len);
+ sc->buffer_pos += cp_len;
+ pos += cp_len;
+ while (pos < len) {
+ int ret = read(fd, &buffer[pos], len - pos);
+ if (ret <= 0)
+ break;
+ pos += ret;
+ }
+ return pos;
+}
+
+static unsigned uvox_meta_read(int fd, streaming_ctrl_t *sc) {
+ unsigned metaint;
+ unsigned char info[6];
+ do {
+ my_read(fd, info, 1, sc);
+ if (info[0] == 0x00)
+ my_read(fd, info, 6, sc);
+ else
+ my_read(fd, &info[1], 5, sc);
+ if (info[0] != 0x5a || info[1] != 0x00) {
+ mp_msg(MSGT_DEMUXER, MSGL_ERR, "Invalid or unknown uvox metadata\n");
+ return 0;
+ }
+ metaint = info[4] << 8 | info[5];
+ if (info[3] == 0x02) {
+ char *metabuf = malloc(metaint);
+ my_read(fd, metabuf, metaint, sc);
+ free(metabuf);
+ }
+ } while (info[3] == 0x02);
+ return metaint;
+}
+
+/**
+ * \brief read one scast meta data entry and print it
+ */
+static void scast_meta_read(int fd, streaming_ctrl_t *sc) {
+ unsigned char tmp = 0;
+ unsigned metalen;
+ my_read(fd, &tmp, 1, sc);
+ metalen = tmp * 16;
+ if (metalen > 0) {
+ char *info = (char *)malloc(metalen + 1);
+ unsigned nlen = my_read(fd, info, metalen, sc);
+ info[nlen] = 0;
+ mp_msg(MSGT_DEMUXER, MSGL_INFO, "\nICY Info: %s\n", info);
+ free(info);
+ }
+}
+
+static int scast_streaming_read(int fd, char *buffer, int size,
+ streaming_ctrl_t *sc) {
+ scast_data_t *sd = (scast_data_t *)sc->data;
+ unsigned block, ret;
+ unsigned done = 0;
+
+ // first read remaining data up to next metadata
+ block = sd->metaint - sd->metapos;
+ if (block > size)
+ block = size;
+ ret = my_read(fd, buffer, block, sc);
+ sd->metapos += ret;
+ done += ret;
+ if (ret != block) // read problems or eof
+ size = done;
+
+ while (done < size) { // now comes the metadata
+ if (sd->is_ultravox)
+ sd->metaint = uvox_meta_read(fd, sc);
+ else
+ scast_meta_read(fd, sc); // read and display metadata
+ sd->metapos = 0;
+ block = size - done;
+ if (block > sd->metaint)
+ block = sd->metaint;
+ ret = my_read(fd, &buffer[done], block, sc);
+ sd->metapos += ret;
+ done += ret;
+ if (ret != block) // read problems or eof
+ size = done;
+ }
+ return done;
+}
+
+static int scast_streaming_start(stream_t *stream) {
+ int metaint;
+ int fromhdr;
+ scast_data_t *scast_data;
+ HTTP_header_t *http_hdr = stream->streaming_ctrl->data;
+ int is_ultravox = http_hdr && strcasecmp(http_hdr->protocol, "ICY") != 0;
+ if (!stream || stream->fd < 0 || !http_hdr)
+ return -1;
+ if (is_ultravox)
+ metaint = 0;
+ else {
+ metaint = atoi(http_get_field(http_hdr, "Icy-MetaInt"));
+ if (metaint <= 0)
+ return -1;
+ }
+ stream->streaming_ctrl->buffer = malloc(http_hdr->body_size);
+ stream->streaming_ctrl->buffer_size = http_hdr->body_size;
+ stream->streaming_ctrl->buffer_pos = 0;
+ memcpy(stream->streaming_ctrl->buffer, http_hdr->body, http_hdr->body_size);
+ scast_data = malloc(sizeof(scast_data_t));
+ scast_data->metaint = metaint;
+ scast_data->metapos = 0;
+ scast_data->is_ultravox = is_ultravox;
+ http_free(http_hdr);
+ stream->streaming_ctrl->data = scast_data;
+ stream->streaming_ctrl->streaming_read = scast_streaming_read;
+ stream->streaming_ctrl->streaming_seek = NULL;
+ stream->streaming_ctrl->prebuffer_size = 64 * 1024; // 64 KBytes
+ stream->streaming_ctrl->buffering = 1;
+ stream->streaming_ctrl->status = streaming_playing_e;
+ return 0;
+}
+
static int nop_streaming_start( stream_t *stream ) {
HTTP_header_t *http_hdr = NULL;
char *next_url=NULL;
@@ -677,14 +815,20 @@
}
static int fixup_open(stream_t *stream,int seekable) {
+ HTTP_header_t *http_hdr = stream->streaming_ctrl->data;
+ int is_icy = http_hdr && strcasecmp(http_hdr->protocol, "ICY") == 0;
+ char *content_type = http_get_field( http_hdr, "Content-Type" );
+ int is_ultravox = http_hdr && content_type &&
+ strcasecmp(content_type, "misc/ultravox") == 0;
stream->type = STREAMTYPE_STREAM;
- if(seekable)
+ if(!is_icy && !is_ultravox && seekable)
{
stream->flags |= STREAM_SEEK;
stream->seek = http_seek;
}
stream->streaming_ctrl->bandwidth = network_bandwidth;
+ if ((!is_icy && !is_ultravox) || scast_streaming_start(stream))
if(nop_streaming_start( stream )) {
mp_msg(MSGT_NETWORK,MSGL_ERR,"nop_streaming_start failed\n");
streaming_ctrl_free(stream->streaming_ctrl);
@@ -751,7 +895,7 @@
"Bertrand, Albeau, Reimar Doeffinger, Arpi?",
"plain http",
open_s1,
- {"http", "http_proxy", NULL},
+ {"http", "http_proxy", "unsv", NULL},
NULL,
0 // Urls are an option string
};
More information about the MPlayer-dev-eng
mailing list