diff options
author | Mike Melanson <mike@multimedia.cx> | 2002-11-02 23:45:47 +0000 |
---|---|---|
committer | Mike Melanson <mike@multimedia.cx> | 2002-11-02 23:45:47 +0000 |
commit | ce1b018f825fe9753beb8027e277b1f6c5208682 (patch) | |
tree | a89264bf5f3b87f0e4c6e4463565c6c2c39352ef | |
parent | 2110ccbb0cbd7b63bb8d2067d3a56f7d63e366fc (diff) | |
download | xine-lib-ce1b018f825fe9753beb8027e277b1f6c5208682.tar.gz xine-lib-ce1b018f825fe9753beb8027e277b1f6c5208682.tar.bz2 |
added Robin Kay's EA WVE demuxer
CVS patchset: 3160
CVS date: 2002/11/02 23:45:47
-rw-r--r-- | ChangeLog | 2 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | src/demuxers/Makefile.am | 7 | ||||
-rw-r--r-- | src/demuxers/demux_eawve.c | 487 |
4 files changed, 496 insertions, 1 deletions
@@ -11,6 +11,7 @@ xine-lib (next version) [someone fill in stability and urgency] * Sun/NeXT SND/AU file demuxer * YUV4MPEG2 file demuxer * RealMedia & RealAudio file demuxers + * Electronic Arts WVE file demuxer * Id CIN video decoder * QT RLE video decoder * QT SMC video decoder @@ -18,6 +19,7 @@ xine-lib (next version) [someone fill in stability and urgency] * Wing Commander III video decoder * Logarithmic PCM (mu-law & A-law) audio decoder * GSM 6.10 audio decoder + * Electronic Arts ADPCM audio decoder * time-based seeking in ogg-streams * improved support for ogg-streams containing video (so-called ogm streams) * spu encoding for full overlay support with dxr3 diff --git a/configure.ac b/configure.ac index c3852b2be..487ba2372 100644 --- a/configure.ac +++ b/configure.ac @@ -1191,6 +1191,7 @@ echo " - wc3 mve - voc" echo " - vqa - aiff" echo " - cda - snd/au" echo " - yuv4mpeg2 - real/realaudio" +echo " - ea wve" if test x"$enable_asf" = "xyes"; then echo " - asf" fi diff --git a/src/demuxers/Makefile.am b/src/demuxers/Makefile.am index 1a7992840..2a6f4512f 100644 --- a/src/demuxers/Makefile.am +++ b/src/demuxers/Makefile.am @@ -55,7 +55,8 @@ lib_LTLIBRARIES = $(ogg_module) $(asf_module) xineplug_dmx_avi.la\ xineplug_dmx_snd.la \ xineplug_dmx_yuv4mpeg2.la \ xineplug_dmx_real.la \ - xineplug_dmx_realaudio.la + xineplug_dmx_realaudio.la \ + xineplug_dmx_eawve.la xineplug_dmx_ogg_la_SOURCES = demux_ogg.c xineplug_dmx_ogg_la_LIBADD = $(OGG_LIBS) $(VORBIS_LIBS)\ @@ -158,6 +159,10 @@ xineplug_dmx_realaudio_la_SOURCES = demux_realaudio.c xineplug_dmx_realaudio_la_LIBADD = $(top_builddir)/src/xine-engine/libxine.la xineplug_dmx_realaudio_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@ +xineplug_dmx_eawve_la_SOURCES = demux_eawve.c +xineplug_dmx_eawve_la_LIBADD = $(top_builddir)/src/xine-engine/libxine.la +xineplug_dmx_eawve_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@ + include_HEADERS = demux.h qtpalette.h ## diff --git a/src/demuxers/demux_eawve.c b/src/demuxers/demux_eawve.c new file mode 100644 index 000000000..d17cc541c --- /dev/null +++ b/src/demuxers/demux_eawve.c @@ -0,0 +1,487 @@ +/* + * Copyright (C) 2000-2002 the xine project + * + * This file is part of xine, a unix video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: demux_eawve.c,v 1.1 2002/11/02 23:45:48 tmmm Exp $ + * + * demux_wve.c, Demuxer plugin for Electronic Arts' WVE file format + * + * written and currently maintained by Robin Kay <komadori@myrealbox.com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> + +#include "xine_internal.h" +#include "xineutils.h" +#include "bswap.h" +#include "demux.h" + +#define FOURCC_TAG(ch0, ch1, ch2, ch3) \ + (((uint32_t)(ch3)) | \ + ((uint32_t)(ch2) << 8) | \ + ((uint32_t)(ch1) << 16) | \ + ((uint32_t)(ch0) << 24)) + +typedef struct { + demux_plugin_t demux_plugin; + xine_stream_t *stream; + config_values_t *config; + fifo_buffer_t *video_fifo; + fifo_buffer_t *audio_fifo; + input_plugin_t *input; + + int thread_running; + + int status; + int send_end_buffers; + + int num_channels; + int compression_type; + int num_samples; + + int sample_counter; + char last_mrl[1024]; +} demux_wve_t; + +typedef struct { + + demux_class_t demux_class; + + /* class-wide, global variables here */ + + xine_t *xine; + config_values_t *config; +} demux_wve_class_t; + +typedef struct { + uint32_t id; + uint32_t size; +} chunk_header_t; + +/* + * Read an arbitary number of byte into a word + */ + +static uint32_t read_arbitary(input_plugin_t *input) +{ + uint8_t size, byte; + int i; + uint32_t word; + + if (input->read(input, (void*)&size, 1) != 1) { + return 0; + } + + word = 0; + for (i=0;i<size;i++) { + if (input->read(input, (void*)&byte, 1) != 1) { + return 0; + } + word <<= 8; + word |= byte; + } + + return word; +} + +/* + * Skip a number of bytes + */ + +static int skip_bytes(input_plugin_t *input, int bytes) +{ + if ((input->get_capabilities(input) & INPUT_CAP_SEEKABLE) != 0) { + return input->seek(input, bytes, SEEK_CUR); + } + else { + int i, dummy; + + for (i=0;i<bytes;i++) { + if (input->read(input, (void*)&dummy, 1) != 1) { + return -1; + } + } + return input->get_current_pos(input); + } +} + +/* + * Process WVE file header + * Returns 1 if the WVE file is valid and successfully opened, 0 otherwise + */ + +static int process_header(demux_wve_t *this) +{ + int inHeader; + uint32_t blockid, size; + + if (this->input->get_current_pos(this->input) != 0) { + if ((this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) == 0) { + return 0; + } + this->input->seek(this->input, 0, SEEK_SET); + } + + if (this->input->read(this->input, (void*)&blockid, 4) != 4) { + return 0; + } + if (be2me_32(blockid) != FOURCC_TAG('S', 'C', 'H', 'l')) { + return 0; + } + + if (this->input->read(this->input, (void*)&size, 4) != 4) { + return 0; + } + size = le2me_32(size); + printf("demux_wve: header block is %d bytes long\n", size); + + if (this->input->read(this->input, (void*)&blockid, 4) != 4) { + return 0; + } + if (be2me_32(blockid) != FOURCC_TAG('P', 'T', '\0', '\0')) { + printf("demux_wve: PT header missing\n"); + return 0; + } + + inHeader = 1; + while (inHeader) { + int inSubheader; + uint8_t byte; + if (this->input->read(this->input, (void*)&byte, 1) != 1) { + return 0; + } + + switch (byte) { + case 0xFD: + printf("demux_wve: entered audio subheader\n"); + inSubheader = 1; + while (inSubheader) { + uint8_t subbyte; + if (this->input->read(this->input, (void*)&subbyte, 1) != 1) { + return 0; + } + + switch (subbyte) { + case 0x82: + this->num_channels = read_arbitary(this->input); + printf("demux_wve: num_channels (element 0x82) set to 0x%08x\n", this->num_channels); + break; + case 0x83: + this->compression_type = read_arbitary(this->input); + printf("demux_wve: compression_type (element 0x83) set to 0x%08x\n", this->compression_type); + break; + case 0x85: + this->num_samples = read_arbitary(this->input); + printf("demux_wve: num_samples (element 0x85) set to 0x%08x\n", this->num_samples); + break; + default: + printf("demux_wve: element 0x%02x set to 0x%08x\n", subbyte, read_arbitary(this->input)); + break; + case 0x8A: + printf("demux_wve: element 0x%02x set to 0x%08x\n", subbyte, read_arbitary(this->input)); + printf("demux_wve: exited audio subheader\n"); + inSubheader = 0; + break; + } + } + break; + default: + printf("demux_wve: header element 0x%02x set to 0x%08x\n", byte, read_arbitary(this->input)); + break; + case 0xFF: + printf("demux_wve: end of header block reached\n"); + inHeader = 0; + break; + } + } + + if (skip_bytes(this->input, size - this->input->get_current_pos(this->input)) < 0) { + return 0; + } + + return 1; +} + +/* + * !IMPORTANT! !IMPORTANT! !IMPORTANT! !IMPORTANT! !IMPORTANT! + * All the following functions are defined by the xine demuxer API + * !IMPORTANT! !IMPORTANT! !IMPORTANT! !IMPORTANT! !IMPORTANT! + */ + +static int demux_wve_send_chunk(demux_wve_t *this) +{ + chunk_header_t header; + + if (this->input->read(this->input, (void*)&header, sizeof(chunk_header_t)) != sizeof(chunk_header_t)) { + printf("demux_wve: read error\n"); + this->status = DEMUX_FINISHED; + return this->status; + } + header.id = be2me_32(header.id); + header.size = le2me_32(header.size) - 8; + + switch (header.id) { + case FOURCC_TAG('S', 'C', 'D', 'l'): { + int first_segment = 1; + + while (header.size > 0) { + buf_element_t *buf; + + buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo); + buf->type = BUF_AUDIO_EA_ADPCM; + buf->input_pos = this->input->get_current_pos(this->input); + buf->input_time = this->sample_counter / 22050; + buf->pts = this->sample_counter; + buf->pts *= 90000; + buf->pts /= 22050; + + if (header.size > buf->max_size) { + buf->size = buf->max_size; + } + else { + buf->size = header.size; + } + header.size -= buf->size; + + if (this->input->read(this->input, buf->content, buf->size) != buf->size) { + printf("demux_wve: read error\n"); + this->status = DEMUX_FINISHED; + buf->free_buffer(buf); + break; + } + + if (first_segment) { + buf->decoder_flags |= BUF_FLAG_FRAME_START; + this->sample_counter += LE_32(buf->content); + first_segment = 0; + } + + if (header.size == 0) { + buf->decoder_flags |= BUF_FLAG_FRAME_END; + } + + this->audio_fifo->put(this->audio_fifo, buf); + } + } + break; + + case FOURCC_TAG('S', 'C', 'E', 'l'): { + printf("SCEl reached\n"); + this->status = DEMUX_FINISHED; + } + break; + + default: { + if (skip_bytes(this->input, header.size) < 0) { + printf("demux_wve: read error\n"); + this->status = DEMUX_FINISHED; + } + } + break; + } + + return this->status; +} + +static void demux_wve_send_headers(demux_plugin_t *this_gen) { + + demux_wve_t *this = (demux_wve_t *) this_gen; + + this->video_fifo = this->stream->video_fifo; + this->audio_fifo = this->stream->audio_fifo; + + this->status = DEMUX_OK; + + /* load stream information */ + this->stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO] = 0; + this->stream->stream_info[XINE_STREAM_INFO_HAS_AUDIO] = 1; + this->stream->stream_info[XINE_STREAM_INFO_AUDIO_CHANNELS] = 2; + this->stream->stream_info[XINE_STREAM_INFO_AUDIO_SAMPLERATE] = 22050; + this->stream->stream_info[XINE_STREAM_INFO_AUDIO_BITS] = 16; + + /* send start buffers */ + xine_demux_control_start(this->stream); + + /* send init info to decoders */ + if (this->audio_fifo) { + buf_element_t *buf; + + buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo); + buf->type = BUF_AUDIO_EA_ADPCM; + buf->decoder_flags = BUF_FLAG_HEADER; + buf->decoder_info[0] = 0; + buf->decoder_info[1] = 22050; + buf->decoder_info[2] = 16; + buf->decoder_info[3] = 2; + this->audio_fifo->put(this->audio_fifo, buf); + } + + xine_demux_control_headers_done (this->stream); +} + +static int demux_wve_seek(demux_wve_t *this, off_t start_pos, int start_time) +{ + + if (!this->thread_running) { + xine_demux_control_newpts(this->stream, 0, 0); + + this->status = DEMUX_OK; + this->sample_counter = 0; + + this->thread_running = 1; + } + + return this->status; +} + +static void demux_wve_dispose(demux_wve_t *this) +{ + free(this); +} + +static int demux_wve_get_status(demux_wve_t *this) +{ + return this->status; +} + +static int demux_wve_get_stream_length(demux_wve_t *this) +{ + return this->num_samples / 22050; +} + +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_wve_t *this; + + if (! (input->get_capabilities(input) & INPUT_CAP_SEEKABLE)) { + printf(_("demux_wve.c: input not seekable, can not handle!\n")); + return NULL; + } + + this = xine_xmalloc (sizeof (demux_wve_t)); + this->stream = stream; + this->input = input; + + this->demux_plugin.send_headers = (void*)demux_wve_send_headers; + this->demux_plugin.send_chunk = (void*)demux_wve_send_chunk; + this->demux_plugin.seek = (void*)demux_wve_seek; + this->demux_plugin.dispose = (void*)demux_wve_dispose; + this->demux_plugin.get_status = (void*)demux_wve_get_status; + this->demux_plugin.get_stream_length = (void*)demux_wve_get_stream_length; + this->demux_plugin.demux_class = class_gen; + + this->status = DEMUX_FINISHED; + + switch (stream->content_detection_method) { + + case METHOD_BY_CONTENT: + case METHOD_EXPLICIT: + + if (!process_header(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, ".wve", 4)) { + free (this); + return NULL; + } + + if (!process_header(this)) { + free (this); + return NULL; + } + + } + + break; + + default: + free (this); + return NULL; + } + + strncpy (this->last_mrl, input->get_mrl (input), 1024); + + return &this->demux_plugin; +} + +static char *get_description (demux_class_t *this_gen) { + return "Electronics Arts WVE format demux plugin"; +} + +static char *get_identifier (demux_class_t *this_gen) { + return "EA WVE"; +} + +static char *get_extensions (demux_class_t *this_gen) { + return "wve"; +} + +static char *get_mimetypes (demux_class_t *this_gen) { + return NULL; +} + +static void class_dispose (demux_class_t *this) { + free (this); +} + +static void *init_plugin (xine_t *xine, void *data) { + + demux_wve_class_t *this; + + this = xine_xmalloc (sizeof (demux_wve_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; +} + +plugin_info_t xine_plugin_info[] = { + { PLUGIN_DEMUX, 15, "wve", XINE_VERSION_CODE, NULL, (void*)init_plugin}, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; |