diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/demuxers/demux_vqa.c | 419 |
1 files changed, 227 insertions, 192 deletions
diff --git a/src/demuxers/demux_vqa.c b/src/demuxers/demux_vqa.c index 6087839e1..533ac7616 100644 --- a/src/demuxers/demux_vqa.c +++ b/src/demuxers/demux_vqa.c @@ -27,7 +27,7 @@ * block needs information from the previous audio block in order to be * decoded, thus making random seeking difficult. * - * $Id: demux_vqa.c,v 1.13 2002/10/12 17:11:59 jkeil Exp $ + * $Id: demux_vqa.c,v 1.14 2002/10/27 02:20:35 tmmm Exp $ */ #ifdef HAVE_CONFIG_H @@ -55,7 +55,7 @@ ( (long)(unsigned char)(ch0) << 24 ) ) #define FORM_TAG FOURCC_TAG('F', 'O', 'R', 'M') -#define WVQA_TAG FOURCC_TAG('W', 'Q', 'V', 'A') +#define WVQA_TAG FOURCC_TAG('W', 'V', 'Q', 'A') #define VQHD_TAG FOURCC_TAG('V', 'Q', 'H', 'D') #define FINF_TAG FOURCC_TAG('F', 'I', 'N', 'F') #define SND0_TAG FOURCC_TAG('S', 'N', 'D', '0') @@ -67,13 +67,11 @@ #define VQA_PTS_INC (90000 / VQA_FRAMERATE) #define VQA_PREAMBLE_SIZE 8 -#define VALID_ENDS "vqa" - typedef struct { demux_plugin_t demux_plugin; - xine_t *xine; + xine_stream_t *stream; config_values_t *config; @@ -98,8 +96,70 @@ typedef struct { unsigned int audio_sample_rate; unsigned int audio_bits; unsigned int audio_channels; + + char last_mrl[1024]; } demux_vqa_t ; +typedef struct { + + demux_class_t demux_class; + + /* class-wide, global variables here */ + + xine_t *xine; + config_values_t *config; +} demux_vqa_class_t; + +/* returns 1 if the VQA file was opened successfully, 0 otherwise */ +static int open_vqa_file(demux_vqa_t *this) { + + unsigned char header[VQA_HEADER_SIZE]; + off_t last_offset; + unsigned char preamble[VQA_PREAMBLE_SIZE]; + unsigned int chunk_size; + + this->input->seek(this->input, 0, SEEK_SET); + if (this->input->read(this->input, header, 12) != 12) + return 0; + + /* check for the VQA signatures */ + if ((BE_32(&header[0]) != FORM_TAG) || + (BE_32(&header[8]) != WVQA_TAG)) + return 0; + + /* get the file size (a.k.a., last offset) as reported by the file */ + this->input->seek(this->input, 4, SEEK_SET); + if (this->input->read(this->input, header, 4) != 4) + return 0; + last_offset = BE_32(&header[0]); + + /* get the actual filesize */ + this->filesize = this->input->get_length(this->input); + + /* skip to the VQA header */ + this->input->seek(this->input, 20, SEEK_SET); + if (this->input->read(this->input, header, VQA_HEADER_SIZE) + != VQA_HEADER_SIZE) + return 0; + + /* fetch the interesting information */ + this->video_width = LE_16(&header[6]); + this->video_height = LE_16(&header[8]); + this->vector_width = header[10]; + this->vector_height = header[11]; + this->audio_sample_rate = LE_16(&header[24]); + this->audio_channels = header[26]; + + /* skip the FINF chunk */ + if (this->input->read(this->input, preamble, VQA_PREAMBLE_SIZE) != + VQA_PREAMBLE_SIZE) + return 0; + chunk_size = BE_32(&preamble[4]); + this->input->seek(this->input, chunk_size, SEEK_CUR); + + return 1; +} + static void *demux_vqa_loop (void *this_gen) { demux_vqa_t *this = (demux_vqa_t *) this_gen; @@ -229,7 +289,7 @@ static void *demux_vqa_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; @@ -238,142 +298,76 @@ static void *demux_vqa_loop (void *this_gen) { return NULL; } -static int load_vqa_and_send_headers(demux_vqa_t *this) { +static void demux_vqa_send_headers(demux_plugin_t *this_gen) { - unsigned char header[VQA_HEADER_SIZE]; - off_t last_offset; - unsigned char preamble[VQA_PREAMBLE_SIZE]; - unsigned int chunk_size; + demux_vqa_t *this = (demux_vqa_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; - /* get the file size (a.k.a., last offset) as reported by the file */ - this->input->seek(this->input, 4, SEEK_SET); - if (this->input->read(this->input, header, 4) != 4) { - this->status = DEMUX_FINISHED; - pthread_mutex_unlock(&this->mutex); - return DEMUX_CANNOT_HANDLE; - } - last_offset = BE_32(&header[0]); - - /* get the actual filesize */ - this->filesize = this->input->get_length(this->input); - - /* skip to the VQA header */ - this->input->seek(this->input, 20, SEEK_SET); - if (this->input->read(this->input, header, VQA_HEADER_SIZE) - != VQA_HEADER_SIZE) { - this->status = DEMUX_FINISHED; - pthread_mutex_unlock(&this->mutex); - return DEMUX_CANNOT_HANDLE; - } - - /* fetch the interesting information */ - this->video_width = LE_16(&header[6]); - this->video_height = LE_16(&header[8]); - this->vector_width = header[10]; - this->vector_height = header[11]; - this->audio_sample_rate = LE_16(&header[24]); - this->audio_channels = header[26]; - - /* skip the FINF chunk */ - if (this->input->read(this->input, preamble, VQA_PREAMBLE_SIZE) != - VQA_PREAMBLE_SIZE) { - this->status = DEMUX_FINISHED; - pthread_mutex_unlock(&this->mutex); - return DEMUX_CANNOT_HANDLE; - } - chunk_size = BE_32(&preamble[4]); - this->input->seek(this->input, chunk_size, SEEK_CUR); - /* load stream information */ - this->xine->stream_info[XINE_STREAM_INFO_VIDEO_WIDTH] = this->video_width; - this->xine->stream_info[XINE_STREAM_INFO_VIDEO_HEIGHT] = this->video_height; - this->xine->stream_info[XINE_STREAM_INFO_AUDIO_CHANNELS] = + this->stream->stream_info[XINE_STREAM_INFO_VIDEO_WIDTH] = this->video_width; + this->stream->stream_info[XINE_STREAM_INFO_VIDEO_HEIGHT] = this->video_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] = this->audio_sample_rate; - this->xine->stream_info[XINE_STREAM_INFO_AUDIO_BITS] = + this->stream->stream_info[XINE_STREAM_INFO_AUDIO_BITS] = this->audio_bits; - xine_demux_control_headers_done (this->xine); - - pthread_mutex_unlock (&this->mutex); - - return DEMUX_CAN_HANDLE; -} - -static int demux_vqa_open(demux_plugin_t *this_gen, input_plugin_t *input, - int stage) { - demux_vqa_t *this = (demux_vqa_t *) this_gen; - char header[12]; - - 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, header, 12) != 12) - return DEMUX_CANNOT_HANDLE; - - /* check for the VQA signatures */ - if ((BE_32(&header[0]) == FORM_TAG) && - (BE_32(&header[8]) == WVQA_TAG)) - return load_vqa_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_vqa", VALID_ENDS, - _("valid mrls ending for vqa demuxer"), - NULL, 10, NULL, NULL))); - while((m = xine_strsep(&valid_ends, ",")) != NULL) { - - while(*m == ' ' || *m == '\t') m++; - - if(!strcasecmp((suffix + 1), m)) - return load_vqa_and_send_headers(this); - } - return DEMUX_CANNOT_HANDLE; + /* 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] = VQA_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->video_width >> 8) & 0xFF; + buf->content[1] = (this->video_width >> 0) & 0xFF; + buf->content[2] = (this->video_height >> 8) & 0xFF; + buf->content[3] = (this->video_height >> 0) & 0xFF; + buf->size = 4; + buf->type = BUF_VIDEO_VQA; + this->video_fifo->put (this->video_fifo, buf); + + /* send the vector size to the video decoder */ + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + buf->decoder_flags = BUF_FLAG_SPECIAL; + buf->decoder_info[1] = BUF_SPECIAL_VQA_VECTOR_SIZE; + buf->decoder_info[2] = this->vector_width; + buf->decoder_info[3] = this->vector_height; + buf->size = 0; + buf->type = BUF_VIDEO_VQA; + 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_VQA_IMA; + buf->decoder_flags = BUF_FLAG_HEADER; + buf->decoder_info[0] = 0; + buf->decoder_info[1] = this->audio_sample_rate; + buf->decoder_info[2] = 16; /* bits/samples */ + buf->decoder_info[3] = 1; /* 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_vqa_start (demux_plugin_t *this_gen, off_t start_pos, int start_time) { demux_vqa_t *this = (demux_vqa_t *) this_gen; - buf_element_t *buf; int err; pthread_mutex_lock(&this->mutex); @@ -381,53 +375,6 @@ static int demux_vqa_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_vqa: %dx%d VQA video; %d-channel %d Hz IMA ADPCM audio\n"), - this->video_width, - this->video_height, - this->audio_channels, - this->audio_sample_rate); - - /* send start buffers */ - xine_demux_control_start(this->xine); - - /* 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] = VQA_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->video_width >> 8) & 0xFF; - buf->content[1] = (this->video_width >> 0) & 0xFF; - buf->content[2] = (this->video_height >> 8) & 0xFF; - buf->content[3] = (this->video_height >> 0) & 0xFF; - buf->size = 4; - buf->type = BUF_VIDEO_VQA; - this->video_fifo->put (this->video_fifo, buf); - - /* send the vector size to the video decoder */ - buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); - buf->decoder_flags = BUF_FLAG_SPECIAL; - buf->decoder_info[1] = BUF_SPECIAL_VQA_VECTOR_SIZE; - buf->decoder_info[2] = this->vector_width; - buf->decoder_info[3] = this->vector_height; - buf->size = 0; - buf->type = BUF_VIDEO_VQA; - 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_VQA_IMA; - buf->decoder_flags = BUF_FLAG_HEADER; - buf->decoder_info[0] = 0; - buf->decoder_info[1] = this->audio_sample_rate; - buf->decoder_info[2] = 16; /* bits/samples */ - buf->decoder_info[3] = 1; /* channels */ - this->audio_fifo->put (this->audio_fifo, buf); - } - this->status = DEMUX_OK; this->send_end_buffers = 1; this->thread_running = 1; @@ -472,15 +419,17 @@ static void demux_vqa_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_vqa_dispose (demux_plugin_t *this_gen) { demux_vqa_t *this = (demux_vqa_t *) this_gen; + demux_vqa_stop(this_gen); + free(this); } @@ -490,54 +439,140 @@ static int demux_vqa_get_status (demux_plugin_t *this_gen) { return this->status; } -static char *demux_vqa_get_id(void) { - return "VQA"; -} - static int demux_vqa_get_stream_length (demux_plugin_t *this_gen) { return 0; } -static char *demux_vqa_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) { + input_plugin_t *input = (input_plugin_t *) input_gen; + demux_vqa_t *this; -static void *init_demuxer_plugin(xine_t *xine, void *data) { - demux_vqa_t *this; + if (! (input->get_capabilities(input) & INPUT_CAP_SEEKABLE)) { + printf(_("demux_vqa.c: input not seekable, can not handle!\n")); + return NULL; + } - this = (demux_vqa_t *) xine_xmalloc(sizeof(demux_vqa_t)); - this->config = xine->config; - this->xine = xine; + this = xine_xmalloc (sizeof (demux_vqa_t)); + this->stream = stream; + this->input = input; - (void *) this->config->register_string(this->config, - "mrl.ends_vqa", VALID_ENDS, - _("valid mrls ending for vqa demuxer"), - NULL, 10, NULL, NULL); - - this->demux_plugin.open = demux_vqa_open; + this->demux_plugin.send_headers = demux_vqa_send_headers; this->demux_plugin.start = demux_vqa_start; this->demux_plugin.seek = demux_vqa_seek; this->demux_plugin.stop = demux_vqa_stop; this->demux_plugin.dispose = demux_vqa_dispose; this->demux_plugin.get_status = demux_vqa_get_status; - this->demux_plugin.get_identifier = demux_vqa_get_id; this->demux_plugin.get_stream_length = demux_vqa_get_stream_length; - this->demux_plugin.get_mimetypes = demux_vqa_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_vqa_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, ".vqa", 4)) { + free (this); + return NULL; + } + + if (!open_vqa_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_vqa: %dx%d VQA video; %d-channel %d Hz IMA ADPCM audio\n"), + this->video_width, + this->video_height, + this->audio_channels, + this->audio_sample_rate); return &this->demux_plugin; } +static char *get_description (demux_class_t *this_gen) { + return "Westwood Studios VQA file demux plugin"; +} + +static char *get_identifier (demux_class_t *this_gen) { + return "VQA"; +} + +static char *get_extensions (demux_class_t *this_gen) { + return "vqa"; +} + +static char *get_mimetypes (demux_class_t *this_gen) { + return NULL; +} + +static void class_dispose (demux_class_t *this_gen) { + + demux_vqa_class_t *this = (demux_vqa_class_t *) this_gen; + + free (this); +} + +static void *init_plugin (xine_t *xine, void *data) { + + demux_vqa_class_t *this; + + this = xine_xmalloc (sizeof (demux_vqa_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, "vqa", XINE_VERSION_CODE, NULL, init_demuxer_plugin }, + { PLUGIN_DEMUX, 14, "vqa", XINE_VERSION_CODE, NULL, init_plugin }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; |