diff options
author | Mike Melanson <mike@multimedia.cx> | 2002-10-23 02:55:01 +0000 |
---|---|---|
committer | Mike Melanson <mike@multimedia.cx> | 2002-10-23 02:55:01 +0000 |
commit | 3fd3d7d33515f867316010fe4fbe63bd57d1f7d3 (patch) | |
tree | b0e1958bd806edb68d889a42201a3ebe397d87f4 /src/demuxers/demux_roq.c | |
parent | 6a57fa96f65018f48bed7d086d34af54e85a1960 (diff) | |
download | xine-lib-3fd3d7d33515f867316010fe4fbe63bd57d1f7d3.tar.gz xine-lib-3fd3d7d33515f867316010fe4fbe63bd57d1f7d3.tar.bz2 |
bring the RoQ subsystem in line with the latest API revision
CVS patchset: 2949
CVS date: 2002/10/23 02:55:01
Diffstat (limited to 'src/demuxers/demux_roq.c')
-rw-r--r-- | src/demuxers/demux_roq.c | 492 |
1 files changed, 268 insertions, 224 deletions
diff --git a/src/demuxers/demux_roq.c b/src/demuxers/demux_roq.c index ca32985df..0103d3aab 100644 --- a/src/demuxers/demux_roq.c +++ b/src/demuxers/demux_roq.c @@ -21,7 +21,7 @@ * For more information regarding the RoQ file format, visit: * http://www.csse.monash.edu.au/~timf/ * - * $Id: demux_roq.c,v 1.20 2002/10/12 17:11:59 jkeil Exp $ + * $Id: demux_roq.c,v 1.21 2002/10/23 02:55:01 tmmm Exp $ */ #ifdef HAVE_CONFIG_H @@ -52,13 +52,11 @@ #define RoQ_SOUND_MONO 0x1020 #define RoQ_SOUND_STEREO 0x1021 -#define VALID_ENDS "roq" - typedef struct { demux_plugin_t demux_plugin; - xine_t *xine; + xine_stream_t *stream; config_values_t *config; @@ -81,8 +79,105 @@ typedef struct { unsigned int width; unsigned int height; unsigned int audio_channels; + + char last_mrl[1024]; } demux_roq_t ; +typedef struct { + + demux_class_t demux_class; + + /* class-wide, global variables here */ + + xine_t *xine; + config_values_t *config; +} demux_roq_class_t; + +/* returns 1 if the RoQ file was opened successfully, 0 otherwise */ +static int open_roq_file(demux_roq_t *this) { + + char preamble[RoQ_CHUNK_PREAMBLE_SIZE]; + int i; + unsigned int chunk_type; + unsigned int chunk_size; + + this->status = DEMUX_OK; + + this->input->seek(this->input, 0, SEEK_SET); + if (this->input->read(this->input, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != + RoQ_CHUNK_PREAMBLE_SIZE) + return 0; + + this->width = this->height = 0; + this->audio_channels = 0; /* assume no audio at first */ + + /* + * RoQ files enjoy a constant framerate; pts calculation: + * + * xine pts frame # + * -------- = ------- => xine pts = 90000 * frame # / fps + * 90000 fps + * + * therefore, the frame pts increment is 90000 / fps + */ + this->fps = LE_16(&preamble[6]); + this->frame_pts_inc = 90000 / this->fps; + + /* iterate through the first 2 seconds worth of chunks searching for + * the RoQ_INFO chunk and an audio chunk */ + i = this->fps * 2; + while (i-- > 0) { + /* if this read fails, then maybe it's just a really small RoQ file + * (even less than 2 seconds) */ + if (this->input->read(this->input, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != + RoQ_CHUNK_PREAMBLE_SIZE) + break; + chunk_type = LE_16(&preamble[0]); + chunk_size = LE_32(&preamble[2]); + + if (chunk_type == RoQ_INFO) { + /* fetch the width and height; reuse the preamble bytes */ + if (this->input->read(this->input, preamble, 8) != 8) + break; + + this->width = LE_16(&preamble[0]); + this->height = LE_16(&preamble[2]); + + /* if an audio chunk was already found, search is done */ + if (this->audio_channels) + break; + + /* prep the size for a seek */ + chunk_size -= 8; + } else { + /* if it was an audio chunk and the info chunk has already been + * found (as indicated by width and height) then break */ + if (chunk_type == RoQ_SOUND_MONO) { + this->audio_channels = 1; + if (this->width && this->height) + break; + } else if (chunk_type == RoQ_SOUND_STEREO) { + this->audio_channels = 2; + if (this->width && this->height) + break; + } + } + + /* skip the rest of the chunk */ + this->input->seek(this->input, chunk_size, SEEK_CUR); + } + + /* after all is said and done, if there is a width and a height, + * regard it as being a valid file and reset to the first chunk */ + if (this->width && this->height) { + this->input->seek(this->input, 8, SEEK_SET); + } else { + return 0; + } + + return 1; +} + static void *demux_roq_loop (void *this_gen) { demux_roq_t *this = (demux_roq_t *) this_gen; @@ -236,7 +331,7 @@ static void *demux_roq_loop (void *this_gen) { 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; @@ -245,180 +340,65 @@ static void *demux_roq_loop (void *this_gen) { return NULL; } -static int load_roq_and_send_headers(demux_roq_t *this) { +static void demux_roq_send_headers(demux_plugin_t *this_gen) { - char preamble[RoQ_CHUNK_PREAMBLE_SIZE]; - int i; - unsigned int chunk_type; - unsigned int chunk_size; + demux_roq_t *this = (demux_roq_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->input->seek(this->input, 0, SEEK_SET); - if (this->input->read(this->input, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != - RoQ_CHUNK_PREAMBLE_SIZE) { - this->status = DEMUX_FINISHED; - pthread_mutex_unlock(&this->mutex); - return DEMUX_CANNOT_HANDLE; - } - - this->width = this->height = 0; - this->audio_channels = 0; /* assume no audio at first */ - - /* - * RoQ files enjoy a constant framerate; pts calculation: - * - * xine pts frame # - * -------- = ------- => xine pts = 90000 * frame # / fps - * 90000 fps - * - * therefore, the frame pts increment is 90000 / fps - */ - this->fps = LE_16(&preamble[6]); - this->frame_pts_inc = 90000 / this->fps; - - /* iterate through the first 2 seconds worth of chunks searching for - * the RoQ_INFO chunk and an audio chunk */ - i = this->fps * 2; - while (i-- > 0) { - /* if this read fails, then maybe it's just a really small RoQ file - * (even less than 2 seconds) */ - if (this->input->read(this->input, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != - RoQ_CHUNK_PREAMBLE_SIZE) - break; - chunk_type = LE_16(&preamble[0]); - chunk_size = LE_32(&preamble[2]); - - if (chunk_type == RoQ_INFO) { - /* fetch the width and height; reuse the preamble bytes */ - if (this->input->read(this->input, preamble, 8) != 8) - break; - - this->width = LE_16(&preamble[0]); - this->height = LE_16(&preamble[2]); - - /* if an audio chunk was already found, search is done */ - if (this->audio_channels) - break; - - /* prep the size for a seek */ - chunk_size -= 8; - } else { - /* if it was an audio chunk and the info chunk has already been - * found (as indicated by width and height) then break */ - if (chunk_type == RoQ_SOUND_MONO) { - this->audio_channels = 1; - if (this->width && this->height) - break; - } else if (chunk_type == RoQ_SOUND_STEREO) { - this->audio_channels = 2; - if (this->width && this->height) - break; - } - } - - /* skip the rest of the chunk */ - this->input->seek(this->input, chunk_size, SEEK_CUR); - } - - /* after all is said and done, if there is a width and a height, - * regard it as being a valid file and reset to the first chunk */ - if (this->width && this->height) { - this->input->seek(this->input, 8, SEEK_SET); - } else { - this->status = DEMUX_FINISHED; - pthread_mutex_unlock(&this->mutex); - return DEMUX_CANNOT_HANDLE; - } - /* load stream information */ - this->xine->stream_info[XINE_STREAM_INFO_VIDEO_WIDTH] = this->width; - this->xine->stream_info[XINE_STREAM_INFO_VIDEO_HEIGHT] = this->height; - this->xine->stream_info[XINE_STREAM_INFO_AUDIO_CHANNELS] = + this->stream->stream_info[XINE_STREAM_INFO_VIDEO_WIDTH] = this->width; + this->stream->stream_info[XINE_STREAM_INFO_VIDEO_HEIGHT] = this->height; + this->stream->stream_info[XINE_STREAM_INFO_AUDIO_CHANNELS] = this->audio_channels; - this->xine->stream_info[XINE_STREAM_INFO_AUDIO_SAMPLERATE] = + this->stream->stream_info[XINE_STREAM_INFO_AUDIO_SAMPLERATE] = RoQ_AUDIO_SAMPLE_RATE; - this->xine->stream_info[XINE_STREAM_INFO_AUDIO_BITS] = 16; - - xine_demux_control_headers_done (this->xine); - - pthread_mutex_unlock (&this->mutex); - - return DEMUX_CAN_HANDLE; -} - -static int demux_roq_open(demux_plugin_t *this_gen, input_plugin_t *input, - int stage) { - demux_roq_t *this = (demux_roq_t *) this_gen; - char preamble[RoQ_CHUNK_PREAMBLE_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, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != - RoQ_CHUNK_PREAMBLE_SIZE) - return DEMUX_CANNOT_HANDLE; - - /* check for the RoQ magic numbers */ - if ((LE_16(&preamble[0]) == RoQ_MAGIC_NUMBER) && - (LE_32(&preamble[2]) == 0xFFFFFFFF)) - return load_roq_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_roq", VALID_ENDS, - _("valid mrls ending for roq demuxer"), - NULL, 20, NULL, NULL))); - while((m = xine_strsep(&valid_ends, ",")) != NULL) { - - while(*m == ' ' || *m == '\t') m++; - - if(!strcasecmp((suffix + 1), m)) - return load_roq_and_send_headers(this); - } - return DEMUX_CANNOT_HANDLE; + this->stream->stream_info[XINE_STREAM_INFO_AUDIO_BITS] = 16; + + /* send start buffers */ + xine_demux_control_start(this->stream); + + /* send init info to decoders */ + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + buf->decoder_flags = BUF_FLAG_HEADER; + buf->decoder_info[0] = 0; + buf->decoder_info[1] = this->frame_pts_inc; /* initial video_step */ + /* really be a rebel: No structure at all, just put the video width + * and height straight into the buffer, BE_16 format */ + buf->content[0] = (this->width >> 8) & 0xFF; + buf->content[1] = (this->width >> 0) & 0xFF; + buf->content[2] = (this->height >> 8) & 0xFF; + buf->content[3] = (this->height >> 0) & 0xFF; + buf->size = 4; + buf->type = BUF_VIDEO_ROQ; + this->video_fifo->put (this->video_fifo, buf); + + if (this->audio_fifo && this->audio_channels) { + buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + buf->type = BUF_AUDIO_ROQ; + buf->decoder_flags = BUF_FLAG_HEADER; + buf->decoder_info[0] = 0; + buf->decoder_info[1] = RoQ_AUDIO_SAMPLE_RATE; + buf->decoder_info[2] = 16; + buf->decoder_info[3] = this->audio_channels; + this->audio_fifo->put (this->audio_fifo, buf); } - break; - default: - return DEMUX_CANNOT_HANDLE; - break; - - } + xine_demux_control_headers_done (this->stream); - return DEMUX_CANNOT_HANDLE; + pthread_mutex_unlock (&this->mutex); } static int demux_roq_start (demux_plugin_t *this_gen, off_t start_pos, int start_time) { demux_roq_t *this = (demux_roq_t *) this_gen; - buf_element_t *buf; int err; pthread_mutex_lock(&this->mutex); @@ -426,46 +406,8 @@ static int demux_roq_start (demux_plugin_t *this_gen, /* if thread is not running, initialize demuxer */ if (!this->thread_running) { - /* print vital stats */ - xine_log (this->xine, XINE_LOG_MSG, - _("demux_roq: RoQ file, video is %dx%d, %d frames/sec\n"), - this->width, this->height, this->fps); - if (this->audio_channels) - xine_log (this->xine, XINE_LOG_MSG, - _("demux_roq: 16-bit, 22050 Hz %s RoQ DPCM audio\n"), - (this->audio_channels == 1) ? "monaural" : "stereo"); - - /* 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 */ - buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); - buf->decoder_flags = BUF_FLAG_HEADER; - buf->decoder_info[0] = 0; - buf->decoder_info[1] = this->frame_pts_inc; /* initial video_step */ - /* really be a rebel: No structure at all, just put the video width - * and height straight into the buffer, BE_16 format */ - buf->content[0] = (this->width >> 8) & 0xFF; - buf->content[1] = (this->width >> 0) & 0xFF; - buf->content[2] = (this->height >> 8) & 0xFF; - buf->content[3] = (this->height >> 0) & 0xFF; - buf->size = 4; - buf->type = BUF_VIDEO_ROQ; - this->video_fifo->put (this->video_fifo, buf); - - if (this->audio_fifo && this->audio_channels) { - buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); - buf->type = BUF_AUDIO_ROQ; - buf->decoder_flags = BUF_FLAG_HEADER; - buf->decoder_info[0] = 0; - buf->decoder_info[1] = RoQ_AUDIO_SAMPLE_RATE; - buf->decoder_info[2] = 16; - buf->decoder_info[3] = this->audio_channels; - this->audio_fifo->put (this->audio_fifo, buf); - } + xine_demux_control_newpts(this->stream, 0, 0); this->status = DEMUX_OK; this->send_end_buffers = 1; @@ -510,9 +452,9 @@ static void demux_roq_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_roq_dispose (demux_plugin_t *this) { @@ -522,11 +464,7 @@ static void demux_roq_dispose (demux_plugin_t *this) { static int demux_roq_get_status (demux_plugin_t *this_gen) { demux_roq_t *this = (demux_roq_t *) this_gen; - return this->status; -} - -static char *demux_roq_get_id(void) { - return "RoQ"; + return (this->thread_running?DEMUX_OK:DEMUX_FINISHED); } static int demux_roq_get_stream_length (demux_plugin_t *this_gen) { @@ -534,45 +472,151 @@ static int demux_roq_get_stream_length (demux_plugin_t *this_gen) { return 0; } -static char *demux_roq_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) { - demux_roq_t *this; + input_plugin_t *input = (input_plugin_t *) input_gen; + demux_roq_t *this; + char preamble[RoQ_CHUNK_PREAMBLE_SIZE]; - this = (demux_roq_t *) xine_xmalloc(sizeof(demux_roq_t)); - this->config = xine->config; - this->xine = xine; + if (! (input->get_capabilities(input) & INPUT_CAP_SEEKABLE)) { + printf(_("demux_roq.c: input not seekable, can not handle!\n")); + return NULL; + } - (void *) this->config->register_string(this->config, - "mrl.ends_roq", VALID_ENDS, - _("valid mrls ending for roq demuxer"), - NULL, 20, NULL, NULL); + this = xine_xmalloc (sizeof (demux_roq_t)); + this->stream = stream; + this->input = input; - this->demux_plugin.open = demux_roq_open; + this->demux_plugin.send_headers = demux_roq_send_headers; this->demux_plugin.start = demux_roq_start; this->demux_plugin.seek = demux_roq_seek; this->demux_plugin.stop = demux_roq_stop; this->demux_plugin.dispose = demux_roq_dispose; this->demux_plugin.get_status = demux_roq_get_status; - this->demux_plugin.get_identifier = demux_roq_get_id; this->demux_plugin.get_stream_length = demux_roq_get_stream_length; - this->demux_plugin.get_mimetypes = demux_roq_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: + + input->seek(input, 0, SEEK_SET); + if (input->read(input, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != + RoQ_CHUNK_PREAMBLE_SIZE) { + free (this); + return NULL; + } + + /* check for the RoQ magic numbers */ + if ((LE_16(&preamble[0]) == RoQ_MAGIC_NUMBER) && + (LE_32(&preamble[2]) == 0xFFFFFFFF)) { + free (this); + return NULL; + } + + if (!open_roq_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, ".roq", 4)) { + free (this); + return NULL; + } + + if (!open_roq_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_roq: RoQ file, video is %dx%d, %d frames/sec\n"), + this->width, this->height, this->fps); + if (this->audio_channels) + xine_log (this->stream->xine, XINE_LOG_MSG, + _("demux_roq: 16-bit, 22050 Hz %s RoQ DPCM audio\n"), + (this->audio_channels == 1) ? "monaural" : "stereo"); return &this->demux_plugin; } +static char *get_description (demux_class_t *this_gen) { + return "Id RoQ file demux plugin"; +} + +static char *get_identifier (demux_class_t *this_gen) { + return "RoQ"; +} + +static char *get_extensions (demux_class_t *this_gen) { + return "roq"; +} + +static char *get_mimetypes (demux_class_t *this_gen) { + return NULL; +} + +static void class_dispose (demux_class_t *this_gen) { + + demux_roq_class_t *this = (demux_roq_class_t *) this_gen; + + free (this); +} + +static void *init_plugin (xine_t *xine, void *data) { + + demux_roq_class_t *this; + + this = xine_xmalloc (sizeof (demux_roq_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, "roq", XINE_VERSION_CODE, NULL, init_demuxer_plugin }, + { PLUGIN_DEMUX, 14, "roq", XINE_VERSION_CODE, NULL, init_plugin }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; |