diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/demuxers/demux_real.c | 499 |
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 } }; |