summaryrefslogtreecommitdiff
path: root/src/demuxers/demux_roq.c
diff options
context:
space:
mode:
authorMike Melanson <mike@multimedia.cx>2002-10-23 02:55:01 +0000
committerMike Melanson <mike@multimedia.cx>2002-10-23 02:55:01 +0000
commit3fd3d7d33515f867316010fe4fbe63bd57d1f7d3 (patch)
treeb0e1958bd806edb68d889a42201a3ebe397d87f4 /src/demuxers/demux_roq.c
parent6a57fa96f65018f48bed7d086d34af54e85a1960 (diff)
downloadxine-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.c492
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 }
};