summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Melanson <mike@multimedia.cx>2002-11-02 23:45:47 +0000
committerMike Melanson <mike@multimedia.cx>2002-11-02 23:45:47 +0000
commitce1b018f825fe9753beb8027e277b1f6c5208682 (patch)
treea89264bf5f3b87f0e4c6e4463565c6c2c39352ef
parent2110ccbb0cbd7b63bb8d2067d3a56f7d63e366fc (diff)
downloadxine-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--ChangeLog2
-rw-r--r--configure.ac1
-rw-r--r--src/demuxers/Makefile.am7
-rw-r--r--src/demuxers/demux_eawve.c487
4 files changed, 496 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 9aec2e2aa..7d2e96a55 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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 }
+};