summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/demuxers/demux_real.c499
1 files changed, 267 insertions, 232 deletions
diff --git a/src/demuxers/demux_real.c b/src/demuxers/demux_real.c
index 62605de3b..fdaeacbfa 100644
--- a/src/demuxers/demux_real.c
+++ b/src/demuxers/demux_real.c
@@ -21,7 +21,7 @@
* For more information regarding the Real file format, visit:
* http://www.pcisys.net/~melanson/codecs/
*
- * $Id: demux_real.c,v 1.4 2002/10/12 17:11:59 jkeil Exp $
+ * $Id: demux_real.c,v 1.5 2002/10/27 03:18:11 tmmm Exp $
*/
#ifdef HAVE_CONFIG_H
@@ -62,8 +62,6 @@
#define PN_KEYFRAME_FLAG 0x0002
-#define VALID_ENDS "rm,ra"
-
typedef struct {
int stream;
int64_t offset;
@@ -76,7 +74,7 @@ typedef struct {
demux_plugin_t demux_plugin;
- xine_t *xine;
+ xine_stream_t *stream;
config_values_t *config;
@@ -111,8 +109,151 @@ typedef struct {
unsigned int current_data_chunk_packet_count;
unsigned int next_data_chunk_offset;
+ char last_mrl[1024];
} demux_real_t ;
+typedef struct {
+
+ demux_class_t demux_class;
+
+ /* class-wide, global variables here */
+
+ xine_t *xine;
+ config_values_t *config;
+} demux_real_class_t;
+
+/* returns 1 if the real file was opened successfully, 0 otherwise */
+static int open_real_file(demux_real_t *this) {
+
+ char preamble[PREAMBLE_SIZE];
+ unsigned int chunk_type = 0;
+ unsigned int chunk_size;
+ unsigned char *chunk_buffer;
+ int field_size;
+ int stream_ptr;
+ unsigned char data_chunk_header[DATA_CHUNK_HEADER_SIZE];
+ unsigned char signature[REAL_SIGNATURE_SIZE];
+
+ this->data_start = 0;
+ this->data_size = 0;
+ this->packets = NULL;
+ this->current_packet = 0;
+
+ this->input->seek(this->input, 0, SEEK_SET);
+ if (this->input->read(this->input, signature, REAL_SIGNATURE_SIZE) !=
+ REAL_SIGNATURE_SIZE)
+ return 0;
+
+ if (BE_32(signature) != RMF_TAG)
+ return 0;
+
+ /* skip to the start of the first chunk (the first chunk is 0x12 bytes
+ * long) and start traversing */
+ this->input->seek(this->input, 0x12, SEEK_SET);
+
+ /* iterate through chunks and gather information until the first DATA
+ * chunk is located */
+ while (chunk_type != DATA_TAG) {
+
+ if (this->input->read(this->input, preamble, PREAMBLE_SIZE) !=
+ PREAMBLE_SIZE)
+ return 0;
+ chunk_type = BE_32(&preamble[0]);
+ chunk_size = BE_32(&preamble[4]);
+
+ switch (chunk_type) {
+
+ case PROP_TAG:
+ case MDPR_TAG:
+ case CONT_TAG:
+
+ chunk_size -= PREAMBLE_SIZE;
+ chunk_buffer = xine_xmalloc(chunk_size);
+ if (this->input->read(this->input, chunk_buffer, chunk_size) !=
+ chunk_size) {
+ free(chunk_buffer);
+ return 0;
+ }
+
+ if (chunk_type == PROP_TAG) {
+
+ this->packet_count = BE_32(&chunk_buffer[18]);
+ this->duration = BE_32(&chunk_buffer[22]);
+ this->data_start = BE_32(&chunk_buffer[34]);
+
+ } else if (chunk_type == MDPR_TAG) {
+
+
+ } else if (chunk_type == CONT_TAG) {
+
+ stream_ptr = 2;
+
+ /* load the title string */
+ field_size = BE_16(&chunk_buffer[stream_ptr]);
+ stream_ptr += 2;
+ this->stream->meta_info[XINE_META_INFO_TITLE] =
+ xine_xmalloc(field_size + 1);
+ strncpy(this->stream->meta_info[XINE_META_INFO_TITLE],
+ &chunk_buffer[stream_ptr], field_size);
+ this->stream->meta_info[XINE_META_INFO_TITLE][field_size] = '\0';
+ stream_ptr += field_size;
+
+ /* load the author string */
+ field_size = BE_16(&chunk_buffer[stream_ptr]);
+ stream_ptr += 2;
+ this->stream->meta_info[XINE_META_INFO_ARTIST] =
+ xine_xmalloc(field_size + 1);
+ strncpy(this->stream->meta_info[XINE_META_INFO_ARTIST],
+ &chunk_buffer[stream_ptr], field_size);
+ this->stream->meta_info[XINE_META_INFO_ARTIST][field_size] = '\0';
+ stream_ptr += field_size;
+
+ /* load the copyright string as the year */
+ field_size = BE_16(&chunk_buffer[stream_ptr]);
+ stream_ptr += 2;
+ this->stream->meta_info[XINE_META_INFO_YEAR] =
+ xine_xmalloc(field_size + 1);
+ strncpy(this->stream->meta_info[XINE_META_INFO_YEAR],
+ &chunk_buffer[stream_ptr], field_size);
+ this->stream->meta_info[XINE_META_INFO_YEAR][field_size] = '\0';
+ stream_ptr += field_size;
+
+ /* load the comment string */
+ field_size = BE_16(&chunk_buffer[stream_ptr]);
+ stream_ptr += 2;
+ this->stream->meta_info[XINE_META_INFO_COMMENT] =
+ xine_xmalloc(field_size + 1);
+ strncpy(this->stream->meta_info[XINE_META_INFO_COMMENT],
+ &chunk_buffer[stream_ptr], field_size);
+ this->stream->meta_info[XINE_META_INFO_COMMENT][field_size] = '\0';
+ stream_ptr += field_size;
+ }
+
+ free(chunk_buffer);
+ break;
+
+ case DATA_TAG:
+ if (this->input->read(this->input, data_chunk_header,
+ DATA_CHUNK_HEADER_SIZE) != DATA_CHUNK_HEADER_SIZE)
+ return 0;
+ this->current_data_chunk_packet_count = BE_32(&data_chunk_header[2]);
+ this->next_data_chunk_offset = BE_32(&data_chunk_header[6]);
+ break;
+
+ default:
+ /* this should not occur, but in case it does, skip the chunk */
+ this->input->seek(this->input, chunk_size - PREAMBLE_SIZE, SEEK_CUR);
+ break;
+
+ }
+ }
+
+ /* allocate space for the packet list */
+ this->packets = xine_xmalloc(this->packet_count * sizeof(real_packet));
+
+ return 1;
+}
+
static void *demux_real_loop (void *this_gen) {
demux_real_t *this = (demux_real_t *) this_gen;
@@ -220,7 +361,7 @@ if (!this->current_data_chunk_packet_count) {
this->status = DEMUX_FINISHED;
if (this->send_end_buffers) {
- xine_demux_control_end(this->xine, BUF_FLAG_END_STREAM);
+ xine_demux_control_end(this->stream, BUF_FLAG_END_STREAM);
}
this->thread_running = 0;
@@ -230,205 +371,28 @@ if (!this->current_data_chunk_packet_count) {
return NULL;
}
-static int load_real_and_send_headers(demux_real_t *this) {
+static void demux_real_send_headers(demux_plugin_t *this_gen) {
- char preamble[PREAMBLE_SIZE];
- unsigned int chunk_type = 0;
- unsigned int chunk_size;
- unsigned char *chunk_buffer;
- int field_size;
- int stream_ptr;
- unsigned char data_chunk_header[DATA_CHUNK_HEADER_SIZE];
+ demux_real_t *this = (demux_real_t *) this_gen;
+ buf_element_t *buf;
pthread_mutex_lock( &this->mutex );
- this->video_fifo = this->xine->video_fifo;
- this->audio_fifo = this->xine->audio_fifo;
+ this->video_fifo = this->stream->video_fifo;
+ this->audio_fifo = this->stream->audio_fifo;
this->status = DEMUX_OK;
- this->data_start = 0;
- this->data_size = 0;
- this->packets = NULL;
- this->current_packet = 0;
-
- /* skip to the start of the first chunk (the first chunk is 0x12 bytes
- * long) and start traversing */
- this->input->seek(this->input, 0x12, SEEK_SET);
-
- /* iterate through chunks and gather information until the first DATA
- * chunk is located */
- while (chunk_type != DATA_TAG) {
- if (this->input->read(this->input, preamble, PREAMBLE_SIZE) !=
- PREAMBLE_SIZE) {
- this->status = DEMUX_FINISHED;
- pthread_mutex_unlock(&this->mutex);
- return DEMUX_CANNOT_HANDLE;
- }
- chunk_type = BE_32(&preamble[0]);
- chunk_size = BE_32(&preamble[4]);
+ /* send start buffers */
+/* xine_demux_control_start(this->stream);
+*/
- switch (chunk_type) {
+ /* send init info to decoders */
- case PROP_TAG:
- case MDPR_TAG:
- case CONT_TAG:
- chunk_size -= PREAMBLE_SIZE;
- chunk_buffer = xine_xmalloc(chunk_size);
- if (this->input->read(this->input, chunk_buffer, chunk_size) !=
- chunk_size) {
- free(chunk_buffer);
- this->status = DEMUX_FINISHED;
- pthread_mutex_unlock(&this->mutex);
- return DEMUX_CANNOT_HANDLE;
- }
-
- if (chunk_type == PROP_TAG) {
-
- this->packet_count = BE_32(&chunk_buffer[18]);
- this->duration = BE_32(&chunk_buffer[22]);
- this->data_start = BE_32(&chunk_buffer[34]);
-
- } else if (chunk_type == MDPR_TAG) {
-
-
- } else if (chunk_type == CONT_TAG) {
-
- stream_ptr = 2;
-
- /* load the title string */
- field_size = BE_16(&chunk_buffer[stream_ptr]);
- stream_ptr += 2;
- this->xine->meta_info[XINE_META_INFO_TITLE] =
- xine_xmalloc(field_size + 1);
- strncpy(this->xine->meta_info[XINE_META_INFO_TITLE],
- &chunk_buffer[stream_ptr], field_size);
- this->xine->meta_info[XINE_META_INFO_TITLE][field_size] = '\0';
- stream_ptr += field_size;
-
- /* load the author string */
- field_size = BE_16(&chunk_buffer[stream_ptr]);
- stream_ptr += 2;
- this->xine->meta_info[XINE_META_INFO_ARTIST] =
- xine_xmalloc(field_size + 1);
- strncpy(this->xine->meta_info[XINE_META_INFO_ARTIST],
- &chunk_buffer[stream_ptr], field_size);
- this->xine->meta_info[XINE_META_INFO_ARTIST][field_size] = '\0';
- stream_ptr += field_size;
-
- /* load the copyright string as the year */
- field_size = BE_16(&chunk_buffer[stream_ptr]);
- stream_ptr += 2;
- this->xine->meta_info[XINE_META_INFO_YEAR] =
- xine_xmalloc(field_size + 1);
- strncpy(this->xine->meta_info[XINE_META_INFO_YEAR],
- &chunk_buffer[stream_ptr], field_size);
- this->xine->meta_info[XINE_META_INFO_YEAR][field_size] = '\0';
- stream_ptr += field_size;
-
- /* load the comment string */
- field_size = BE_16(&chunk_buffer[stream_ptr]);
- stream_ptr += 2;
- this->xine->meta_info[XINE_META_INFO_COMMENT] =
- xine_xmalloc(field_size + 1);
- strncpy(this->xine->meta_info[XINE_META_INFO_COMMENT],
- &chunk_buffer[stream_ptr], field_size);
- this->xine->meta_info[XINE_META_INFO_COMMENT][field_size] = '\0';
- stream_ptr += field_size;
- }
-
- free(chunk_buffer);
- break;
-
- case DATA_TAG:
- if (this->input->read(this->input, data_chunk_header,
- DATA_CHUNK_HEADER_SIZE) != DATA_CHUNK_HEADER_SIZE) {
- this->status = DEMUX_FINISHED;
- pthread_mutex_unlock(&this->mutex);
- return DEMUX_CANNOT_HANDLE;
- }
- this->current_data_chunk_packet_count = BE_32(&data_chunk_header[2]);
- this->next_data_chunk_offset = BE_32(&data_chunk_header[6]);
- break;
-
- default:
- /* this should not occur, but in case it does, skip the chunk */
- this->input->seek(this->input, chunk_size - PREAMBLE_SIZE, SEEK_CUR);
- break;
-
- }
-
- }
-
- /* allocate space for the packet list */
- this->packets = xine_xmalloc(this->packet_count * sizeof(real_packet));
-
- xine_demux_control_headers_done (this->xine);
+ xine_demux_control_headers_done (this->stream);
pthread_mutex_unlock( &this->mutex );
-
- return DEMUX_CAN_HANDLE;
-}
-
-static int demux_real_open(demux_plugin_t *this_gen, input_plugin_t *input,
- int stage) {
- demux_real_t *this = (demux_real_t *) this_gen;
- unsigned char signature[REAL_SIGNATURE_SIZE];
-
- this->input = input;
-
- switch(stage) {
- case STAGE_BY_CONTENT: {
- if ((input->get_capabilities(input) & INPUT_CAP_SEEKABLE) == 0)
- return DEMUX_CANNOT_HANDLE;
-
- input->seek(input, 0, SEEK_SET);
- if (input->read(input, signature, REAL_SIGNATURE_SIZE) !=
- REAL_SIGNATURE_SIZE)
- return DEMUX_CANNOT_HANDLE;
-
- if (BE_32(signature) == RMF_TAG)
- return load_real_and_send_headers(this);
-
- return DEMUX_CANNOT_HANDLE;
- }
- break;
-
- case STAGE_BY_EXTENSION: {
- char *suffix;
- char *MRL;
- char *m, *valid_ends;
-
- MRL = input->get_mrl (input);
-
- suffix = strrchr(MRL, '.');
-
- if(!suffix)
- return DEMUX_CANNOT_HANDLE;
-
- xine_strdupa(valid_ends, (this->config->register_string(this->config,
- "mrl.ends_real", VALID_ENDS,
- _("valid mrls ending for real demuxer"),
- NULL, 20, NULL, NULL)));
- while((m = xine_strsep(&valid_ends, ",")) != NULL) {
-
- while(*m == ' ' || *m == '\t') m++;
-
- if(!strcasecmp((suffix + 1), m))
- return load_real_and_send_headers(this);
- }
- return DEMUX_CANNOT_HANDLE;
- }
- break;
-
- default:
- return DEMUX_CANNOT_HANDLE;
- break;
-
- }
-
- return DEMUX_CANNOT_HANDLE;
}
static int demux_real_seek (demux_plugin_t *this_gen,
@@ -438,7 +402,6 @@ static int demux_real_start (demux_plugin_t *this_gen,
off_t start_pos, int start_time) {
demux_real_t *this = (demux_real_t *) this_gen;
- buf_element_t *buf;
int err;
pthread_mutex_lock(&this->mutex);
@@ -448,22 +411,9 @@ static int demux_real_start (demux_plugin_t *this_gen,
/* if thread is not running, initialize demuxer */
if (!this->thread_running) {
- /* send vital stats */
- xine_log (this->xine, XINE_LOG_MSG,
- _("demux_real: Real media file, running time: %d min, %d sec\n"),
- this->duration / 1000 / 60,
- this->duration / 1000 % 60);
-
-
-
- /* send start buffers */
-// xine_demux_control_start(this->xine);
-
/* send new pts */
-// xine_demux_control_newpts(this->xine, 0, 0);
-
- /* send init info to decoders */
-
+/* xine_demux_control_newpts(this->stream, 0, 0);
+*/
this->status = DEMUX_OK;
this->send_end_buffers = 1;
@@ -504,15 +454,17 @@ static void demux_real_stop (demux_plugin_t *this_gen) {
pthread_mutex_unlock( &this->mutex );
pthread_join (this->thread, &p);
- xine_demux_flush_engine(this->xine);
+ xine_demux_flush_engine(this->stream);
- xine_demux_control_end(this->xine, BUF_FLAG_END_USER);
+ xine_demux_control_end(this->stream, BUF_FLAG_END_USER);
}
static void demux_real_dispose (demux_plugin_t *this_gen) {
demux_real_t *this = (demux_real_t *) this_gen;
+ demux_real_stop(this_gen);
+
free(this->packets);
free(this);
}
@@ -523,10 +475,6 @@ static int demux_real_get_status (demux_plugin_t *this_gen) {
return this->status;
}
-static char *demux_real_get_id(void) {
- return "RealMedia";
-}
-
static int demux_real_get_stream_length (demux_plugin_t *this_gen) {
demux_real_t *this = (demux_real_t *) this_gen;
@@ -535,46 +483,133 @@ static int demux_real_get_stream_length (demux_plugin_t *this_gen) {
return this->duration / 1000;
}
-static char *demux_real_get_mimetypes(void) {
- return NULL;
-}
-
+static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *stream,
+ input_plugin_t *input_gen) {
-static void *init_demuxer_plugin(xine_t *xine, void *data) {
+ input_plugin_t *input = (input_plugin_t *) input_gen;
+ demux_real_t *this;
- demux_real_t *this;
+ if (! (input->get_capabilities(input) & INPUT_CAP_SEEKABLE)) {
+ printf(_("demux_real.c: input not seekable, can not handle!\n"));
+ return NULL;
+ }
this = xine_xmalloc (sizeof (demux_real_t));
- this->config = xine->config;
- this->xine = xine;
+ this->stream = stream;
+ this->input = input;
- (void*) this->config->register_string(this->config,
- "mrl.ends_real", VALID_ENDS,
- _("valid mrls ending for real demuxer"),
- NULL, 20, NULL, NULL);
-
- this->demux_plugin.open = demux_real_open;
+ this->demux_plugin.send_headers = demux_real_send_headers;
this->demux_plugin.start = demux_real_start;
this->demux_plugin.seek = demux_real_seek;
this->demux_plugin.stop = demux_real_stop;
this->demux_plugin.dispose = demux_real_dispose;
this->demux_plugin.get_status = demux_real_get_status;
- this->demux_plugin.get_identifier = demux_real_get_id;
this->demux_plugin.get_stream_length = demux_real_get_stream_length;
- this->demux_plugin.get_mimetypes = demux_real_get_mimetypes;
+ this->demux_plugin.demux_class = class_gen;
this->status = DEMUX_FINISHED;
- pthread_mutex_init(&this->mutex, NULL);
+ pthread_mutex_init (&this->mutex, NULL);
+
+ switch (stream->content_detection_method) {
+
+ case METHOD_BY_CONTENT:
+
+ if (!open_real_file(this)) {
+ free (this);
+ return NULL;
+ }
+
+ break;
+
+ case METHOD_BY_EXTENSION: {
+ char *ending, *mrl;
+
+ mrl = input->get_mrl (input);
+
+ ending = strrchr(mrl, '.');
+
+ if (!ending) {
+ free (this);
+ return NULL;
+ }
+
+ if (strncasecmp (ending, ".rm", 3)) {
+ free (this);
+ return NULL;
+ }
+
+ if (!open_real_file(this)) {
+ free (this);
+ return NULL;
+ }
+
+ }
+
+ break;
+
+ default:
+ free (this);
+ return NULL;
+ }
+
+ strncpy (this->last_mrl, input->get_mrl (input), 1024);
+
+ /* print vital stats */
+ xine_log (this->stream->xine, XINE_LOG_MSG,
+ _("demux_real: Real media file, running time: %d min, %d sec\n"),
+ this->duration / 1000 / 60,
+ this->duration / 1000 % 60);
return &this->demux_plugin;
}
+static char *get_description (demux_class_t *this_gen) {
+ return "RealMedia file demux plugin";
+}
+
+static char *get_identifier (demux_class_t *this_gen) {
+ return "Real";
+}
+
+static char *get_extensions (demux_class_t *this_gen) {
+ return "rm";
+}
+
+static char *get_mimetypes (demux_class_t *this_gen) {
+ return NULL;
+}
+
+static void class_dispose (demux_class_t *this_gen) {
+
+ demux_real_class_t *this = (demux_real_class_t *) this_gen;
+
+ free (this);
+}
+
+static void *init_plugin (xine_t *xine, void *data) {
+
+ demux_real_class_t *this;
+
+ this = xine_xmalloc (sizeof (demux_real_class_t));
+ this->config = xine->config;
+ this->xine = xine;
+
+ this->demux_class.open_plugin = open_plugin;
+ this->demux_class.get_description = get_description;
+ this->demux_class.get_identifier = get_identifier;
+ this->demux_class.get_mimetypes = get_mimetypes;
+ this->demux_class.get_extensions = get_extensions;
+ this->demux_class.dispose = class_dispose;
+
+ return this;
+}
+
/*
* exported plugin catalog entry
*/
plugin_info_t xine_plugin_info[] = {
/* type, API, "name", version, special_info, init_function */
- { PLUGIN_DEMUX, 11, "real", XINE_VERSION_CODE, NULL, init_demuxer_plugin },
+ { PLUGIN_DEMUX, 14, "real", XINE_VERSION_CODE, NULL, init_plugin },
{ PLUGIN_NONE, 0, "", 0, NULL, NULL }
};