From 58f833f31e88bebac909db5fc433cd4e19f1837d Mon Sep 17 00:00:00 2001 From: Miguel Freitas Date: Wed, 29 Jan 2003 02:33:35 +0000 Subject: - preliminary support for reference streams parsing at xine-lib (they are sent to gui using a new event) - function to return demux from mime type string (used by xine-plugin) - very simple parser for ram files at demux_real CVS patchset: 4030 CVS date: 2003/01/29 02:33:35 --- include/xine.h.in | 28 +++++++- src/demuxers/demux_asf.c | 8 ++- src/demuxers/demux_real.c | 158 ++++++++++++++++++++++++++++++++++++----- src/xine-engine/load_plugins.c | 49 ++++++++++++- 4 files changed, 219 insertions(+), 24 deletions(-) diff --git a/include/xine.h.in b/include/xine.h.in index 6fa89c39a..f195c70cc 100644 --- a/include/xine.h.in +++ b/include/xine.h.in @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xine.h.in,v 1.57 2003/01/18 15:29:19 miguelfreitas Exp $ + * $Id: xine.h.in,v 1.58 2003/01/29 02:33:35 miguelfreitas Exp $ * * public xine-lib (libxine) interface and documentation * @@ -819,6 +819,11 @@ char *xine_get_file_extensions (xine_t *self); * the pointer returned can be free()ed when no longer used */ char *xine_get_mime_types (xine_t *self); +/* get the demuxer identifier that handles a given mime type + * + * the pointer returned can be free()ed when no longer used + * returns NULL if no demuxer is available to handle this. */ +char *xine_get_demux_for_mime_type (xine_t *self, const char *mime_type); /* get a description string for an input plugin */ const char *xine_get_input_plugin_description (xine_t *self, @@ -1141,6 +1146,7 @@ void xine_config_reset (xine_t *self); #define XINE_EVENT_AUDIO_LEVEL 6 /* report current audio level (l/r) */ #define XINE_EVENT_QUIT 7 /* last event sent when stream is disposed */ #define XINE_EVENT_PROGRESS 8 /* index creation/network connections */ +#define XINE_EVENT_MRL_REFERENCE 9 /* demuxer->frontend: MRL reference(s) for the real stream */ /* input events coming from frontend */ #define XINE_EVENT_INPUT_MOUSE_BUTTON 101 @@ -1231,6 +1237,26 @@ typedef struct { int percent; } xine_progress_data_t; +/* + * mrl reference data is sent by demuxers when a reference stream is found. + * this stream just contains pointers (urls) to the real data, which are + * passed to frontend using this event type. (examples: .asx, .mov and .ram) + * + * ideally, frontends should add these mrls to a "hierarchical playlist". + * that is, instead of the original file, the ones provided here should be + * played instead. on pratice, just using a simple playlist should work. + * + * mrl references should be played in the same order they are received, just + * after the current stream finishes. + * alternative playlists may be provided and should be used in case of + * failure of the primary playlist. + */ +typedef struct { + int alternative; /* alternative playlist number, usually 0 */ + char mrl[1]; /* might (will) be longer */ +} xine_mrl_reference_data_t; + + /* opaque xine_event_queue_t */ typedef struct xine_event_queue_s xine_event_queue_t; diff --git a/src/demuxers/demux_asf.c b/src/demuxers/demux_asf.c index d941df984..c20452847 100644 --- a/src/demuxers/demux_asf.c +++ b/src/demuxers/demux_asf.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: demux_asf.c,v 1.101 2003/01/26 17:38:41 tmattern Exp $ + * $Id: demux_asf.c,v 1.102 2003/01/29 02:33:35 miguelfreitas Exp $ * * demultiplexer for asf streams * @@ -1565,13 +1565,15 @@ static char *get_identifier (demux_class_t *this_gen) { } static char *get_extensions (demux_class_t *this_gen) { - return "asf wmv wma"; + return "asf asx wmv wma"; } static char *get_mimetypes (demux_class_t *this_gen) { return "video/x-ms-asf: asf: ASF video;" "video/x-ms-wmv: wmv: WMV video;" - "application/vnd.ms-asf: asf: ASF video;"; + "application/vnd.ms-asf: asf: ASF video;" + "application/x-mplayer2: asf,asx,asp: mplayer2;" + "video/x-ms-asf-plugin: asf,asx,asp: mms animation;"; } static void class_dispose (demux_class_t *this_gen) { diff --git a/src/demuxers/demux_real.c b/src/demuxers/demux_real.c index f40849e6a..f0d082071 100644 --- a/src/demuxers/demux_real.c +++ b/src/demuxers/demux_real.c @@ -28,7 +28,7 @@ * * Based on FFmpeg's libav/rm.c. * - * $Id: demux_real.c,v 1.37 2003/01/23 16:12:13 miguelfreitas Exp $ + * $Id: demux_real.c,v 1.38 2003/01/29 02:33:36 miguelfreitas Exp $ */ #ifdef HAVE_CONFIG_H @@ -40,6 +40,7 @@ #include #include #include +#include #include "xine_internal.h" #include "xineutils.h" @@ -121,6 +122,7 @@ typedef struct { int fragment_size; /* video sub-demux */ + int reference_mode; } demux_real_t ; typedef struct { @@ -593,6 +595,77 @@ static void real_parse_headers (demux_real_t *this) { } } + +/* very naive approach for parsing ram files. it will extract known + * mrls directly so it should work for simple smil files too. + * no attempt is made to support smil features: + * http://service.real.com/help/library/guides/production/htmfiles/smil.htm + */ +static int demux_real_parse_references( demux_real_t *this) { + + char *buf = NULL; + int buf_size = 0; + int buf_used = 0; + int len, i, j; + int alternative = 0; + xine_mrl_reference_data_t *data; + xine_event_t uevent; + + + /* read file to memory. + * warning: dumb code, but hopefuly ok since reference file is small */ + do { + buf_size += 1024; + buf = realloc(buf, buf_size+1); + + len = this->input->read(this->input, &buf[buf_used], buf_size-buf_used); + + if( len > 0 ) + buf_used += len; + + /* 50k of reference file? no way. something must be wrong */ + if( buf_used > 50*1024 ) + break; + } while( len > 0 ); + + if(buf_used) + buf[buf_used] = '\0'; + + for(i=0;istream; + uevent.data_length = strlen(&buf[i])+sizeof(xine_mrl_reference_data_t); + data = malloc(uevent.data_length); + uevent.data = data; + strcpy(data->mrl, &buf[i]); + data->alternative = alternative; + xine_event_send(this->stream, &uevent); + + i = j; + } + } + + free(buf); + + this->status = DEMUX_FINISHED; + return this->status; +} + /* redefine abs as macro to handle 64-bit diffs. i guess llabs may not be available everywhere */ #define abs(x) ( ((x)<0) ? -(x) : (x) ) @@ -654,6 +727,9 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { int64_t pts; off_t offset; + if(this->reference_mode) + return demux_real_parse_references(this); + /* load a header from wherever the stream happens to be pointing */ if ( (size=this->input->read(this->input, header, DATA_PACKET_HEADER_SIZE)) != DATA_PACKET_HEADER_SIZE) { @@ -876,7 +952,7 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { n = this->input->read (this->input, buf->content, size); - if (nfree_buffer(buf); @@ -967,8 +1043,12 @@ static void demux_real_send_headers(demux_plugin_t *this_gen) { this->video_stream_num = -1; this->audio_stream_num = -1; - real_parse_headers (this); - + if( !this->reference_mode ) { + real_parse_headers (this); + } else { + if ((this->input->get_capabilities (this->input) & INPUT_CAP_SEEKABLE) != 0) + this->input->seek (this->input, 0, SEEK_SET); + } } static int demux_real_seek (demux_plugin_t *this_gen, @@ -1023,6 +1103,26 @@ static int demux_real_get_optional_data(demux_plugin_t *this_gen, return DEMUX_OPTIONAL_UNSUPPORTED; } +/* help function to discover stream type. returns: + * 0 if not known. + * 1 if normal stream. + * 2 if reference stream. + */ +static int real_check_stream_type(uint8_t *buf, int len) +{ + if ((buf[0] == 0x2e) + && (buf[1] == 'R') + && (buf[2] == 'M') + && (buf[3] == 'F')) + return 1; + + buf[len] = '\0'; + if( strstr(buf,"pnm://") || strstr(buf,"rtsp://") || strstr(buf,"") ) + return 2; + + return 0; +} + static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *stream, input_plugin_t *input_gen) { @@ -1033,46 +1133,40 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str case METHOD_BY_CONTENT: { - uint8_t buf[4096]; + uint8_t buf[4096], len; if ((input->get_capabilities(input) & INPUT_CAP_SEEKABLE) != 0) { input->seek(input, 0, SEEK_SET); - if (input->read(input, buf, 4)) { + if ((len = input->read(input, buf, 1024))) { #ifdef LOG printf ("demux_real: input seekable, read 4 bytes: %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]); #endif - if ((buf[0] != 0x2e) - || (buf[1] != 'R') - || (buf[2] != 'M') - || (buf[3] != 'F')) + if (!real_check_stream_type(buf,len)) return NULL; } else return NULL; - } else if (input->get_optional_data (input, buf, INPUT_OPTIONAL_DATA_PREVIEW)) { + } else if ((len = input->get_optional_data (input, buf, INPUT_OPTIONAL_DATA_PREVIEW))) { #ifdef LOG printf ("demux_real: input provides preview, read 4 bytes: %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]); #endif - if ((buf[0] != 0x2e) - || (buf[1] != 'R') - || (buf[2] != 'M') - || (buf[3] != 'F')) + if (!real_check_stream_type(buf,len)) return NULL; } else return NULL; } - +#ifdef LOG printf ("demux_real: by content accepted.\n"); - +#endif break; case METHOD_BY_EXTENSION: { @@ -1118,6 +1212,32 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str this->stream = stream; this->input = input; + + /* discover stream type */ + { + uint8_t buf[4096], len; + + this->reference_mode = 0; + if ((len = input->get_capabilities(input) & INPUT_CAP_SEEKABLE) != 0) { + + input->seek(input, 0, SEEK_SET); + + if ((len = input->read(input, buf, 1024))) { + if (real_check_stream_type(buf,len) == 2) + this->reference_mode = 1; + } + + } else if ((len = input->get_optional_data (input, buf, INPUT_OPTIONAL_DATA_PREVIEW))) { + + if (real_check_stream_type(buf,len) == 2) + this->reference_mode = 1; + } + + if(this->reference_mode) + printf("demux_real: reference stream detected\n"); + } + + this->demux_plugin.send_headers = demux_real_send_headers; this->demux_plugin.send_chunk = demux_real_send_chunk; this->demux_plugin.seek = demux_real_seek; @@ -1132,7 +1252,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str strncpy (this->last_mrl, input->get_mrl (input), 1024); - return &this->demux_plugin; } @@ -1149,7 +1268,8 @@ static char *get_extensions (demux_class_t *this_gen) { } static char *get_mimetypes (demux_class_t *this_gen) { - return "audio/x-pn-realaudio: ra, rm, ram: Real Media File;"; + return "audio/x-pn-realaudio: ra, rm, ram: Real Media file;" + "audio/x-pn-realaudio-plugin: rpm: Real Media plugin file;"; } static void class_dispose (demux_class_t *this_gen) { diff --git a/src/xine-engine/load_plugins.c b/src/xine-engine/load_plugins.c index cdffd4570..d89548894 100644 --- a/src/xine-engine/load_plugins.c +++ b/src/xine-engine/load_plugins.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: load_plugins.c,v 1.138 2003/01/18 20:35:24 f1rmb Exp $ + * $Id: load_plugins.c,v 1.139 2003/01/29 02:33:36 miguelfreitas Exp $ * * * Load input/demux/audio_out/video_out/codec plugins @@ -37,6 +37,7 @@ #include #include #include +#include #include #include "xine_internal.h" @@ -2011,6 +2012,52 @@ char *xine_get_mime_types (xine_t *self) { } +/* get the demuxer identifier that handles a given mime type + * + * the pointer returned can be free()ed when no longer used + * returns NULL if no demuxer is available to handle this. */ +char *xine_get_demux_for_mime_type (xine_t *self, const char *mime_type) { + + plugin_catalog_t *catalog = self->plugin_catalog; + plugin_node_t *node; + char *id = NULL; + char *mime_arg, *mime_demux; + char *s; + + /* create a copy and convert to lower case */ + mime_arg = strdup(mime_type); + for(s=mime_arg; *s; s++) + *s = tolower(*s); + + pthread_mutex_lock (&catalog->lock); + + node = xine_list_first_content (catalog->demux); + while (node && !id) { + demux_class_t *cls = (demux_class_t *)node->plugin_class; + + s = cls->get_mimetypes (cls); + if (s) { + mime_demux = strdup(s); + + for(s=mime_demux; *s; s++) + *s = tolower(*s); + + if( strstr(mime_demux, mime_arg) ) + id = strdup(node->info->id); + + free(mime_demux); + } + node = xine_list_next_content (catalog->demux); + } + + pthread_mutex_unlock (&catalog->lock); + + free(mime_arg); + + return id; +} + + static void dispose_plugin_list (xine_list_t *list) { plugin_node_t *node; -- cgit v1.2.3