From: Martin Jacobs Subject: Add http to non-http redirection in http input plugin Amazon web site sends audio probes with redirection from http to rtps provided in a redirected http file. Xine input plugin for http mrls is able to deal with a http redirect but xine is then unable to switch to reading a rtps stream. Example: http://www.amazon.de/gp/music/clipserve/B000001GB0001001/1/ref=mu_sam_ra001_001 after http redirection xine gets a file containing this information: rtsp://77.67.2.201:554/real.amazon-de.eu2/phononet/B/0/0/0/0/0/1/G/B/0/01.01.rm?cloakport=80,554,7070 --stop-- pnm://77.67.2.201:7070/real.amazon-de.eu2/phononet/B/0/0/0/0/0/1/G/B/0/01.01.rm?cloakport=80,554,7070 --- xine-lib-1.1.15-orig/src/input/input_http.c 2008-06-25 15:04:09.000000000 +0200 +++ xine-lib-1.1.15-orig/src/input/input_http.c 2008-09-13 14:25:52.000000000 +0200 @@ -63,6 +63,7 @@ #define TAG_ICY_METAINT "icy-metaint:" #define TAG_CONTENT_TYPE "Content-Type:" #define TAG_LASTFM_SERVER "Server: last.fm " +#define TAG_LOCATION "Location:" typedef struct { input_plugin_t input_plugin; @@ -661,6 +662,7 @@ int use_proxy; int proxyport; int mpegurl_redirect = 0; + int realaudio_redirect = 0; char mime_type[256]; mime_type[0] = 0; @@ -869,20 +871,36 @@ this->contentlength = (off_t)contentlength; } } - - if (!strncasecmp(this->buf, "Location: ", 10)) { + + if (!strncasecmp(this->buf, TAG_LOCATION " ", 10)) { char *href = (this->buf + 10); - lprintf ("trying to open target of redirection: >%s<\n", href); + xine_log (this->stream->xine, XINE_LOG_MSG, + _("input_http: redirection target = %s\n"), + href); + /* switch to new url */ href = _x_canonicalise_url (this->mrl, href); free(this->mrl); this->mrl = href; + return http_plugin_open(this_gen); } + /* Amazon web site sends audio probes with redirection in a file */ { - static const char mpegurl_ct_str[] = "Content-Type: audio/x-mpegurl"; + static const char realaudio_ct_str[] = TAG_CONTENT_TYPE " audio/x-pn-realaudio"; + static const size_t realaudio_ct_size = sizeof(realaudio_ct_str)-1; + + if (!strncasecmp(this->buf, realaudio_ct_str, realaudio_ct_size)) { + lprintf("Opening an %s file, late redirect.", realaudio_ct_str); + + realaudio_redirect = 1; + } + } + + { + static const char mpegurl_ct_str[] = TAG_CONTENT_TYPE " audio/x-mpegurl"; static const size_t mpegurl_ct_size = sizeof(mpegurl_ct_str)-1; if (!strncasecmp(this->buf, mpegurl_ct_str, mpegurl_ct_size)) { lprintf("Opening an audio/x-mpegurl file, late redirect."); @@ -982,6 +1000,43 @@ } } + /* amazon delivers a file containing new urls, first line contains rtsp url. (mja) + Example: + rtsp://77.67.2.201:554/real.amazon-de.eu2/phononet/B/0/0/0/0/0/1/G/B/0/01.01.rm?cloakport=80,554,7070 + --stop-- + pnm://77.67.2.201:7070/real.amazon-de.eu2/phononet/B/0/0/0/0/0/1/G/B/0/01.01.rm?cloakport=80,554,7070 + */ + if ( realaudio_redirect ) { + char buf[4096] = { 0, }; + char *newline = NULL; + + /* read data from redirection location (mja) */ + http_plugin_read_int(this, buf, sizeof(buf)-1); + newline = strstr(buf, "\r\n"); + + /* If the newline can't be found, either the 4K buffer is too small, or + * more likely something is fuzzy. + */ + if ( newline ) { + char *href; + + *newline = '\0'; + + href = _x_canonicalise_url (this->mrl, buf); + xine_log (this->stream->xine, XINE_LOG_MSG, + _("input_http: late redirection to %s\n"), href); + lprintf("realaudio pointing to %s\n", buf); + + /* exchange mrl (mja) */ + free(this->mrl); + this->mrl = href; + + /* stop for now and trigger new mrl evaluation (mja) */ + return -13; + } + } + + /* * fill preview buffer */ --- xine-lib-1.1.15-orig/src/xine-engine/xine.c 2008-06-25 15:04:09.000000000 +0200 +++ xine-lib-1.1.15-orig/src/xine-engine/xine.c 2008-09-13 14:27:55.000000000 +0200 @@ -876,6 +876,28 @@ stream->err = XINE_ERROR_INPUT_FAILED; _x_flush_events_queues (stream); return 0; + case -13: /* Open successfull, but got new mrl! (mja) */ + input_source = strdup(stream->input_plugin->get_mrl(stream->input_plugin)); + /* close current input plugin and select a new one (mja) */ + stream->input_plugin->dispose(stream->input_plugin); + stream->input_plugin = NULL; + /* try to find a new input plugin (mja) */ + stream->input_plugin = _x_find_input_plugin (stream, input_source); + free(input_source); + + if ( stream->input_plugin ) { + int res; + + xine_log (stream->xine, XINE_LOG_MSG, _("xine: found input plugin : %s\n"), + stream->input_plugin->input_class->get_description(stream->input_plugin->input_class)); + if (stream->input_plugin->input_class->eject_media) + stream->eject_class = stream->input_plugin->input_class; + _x_meta_info_set_utf8(stream, XINE_META_INFO_INPUT_PLUGIN, + (stream->input_plugin->input_class->get_identifier (stream->input_plugin->input_class))); + + res = (stream->input_plugin->open) (stream->input_plugin); + } + break; default: xine_log (stream->xine, XINE_LOG_MSG, _("xine: input plugin cannot open MRL [%s]\n"),mrl); stream->input_plugin->dispose(stream->input_plugin);