summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/demuxers/Makefile.am6
-rw-r--r--src/demuxers/demux_film.c683
2 files changed, 688 insertions, 1 deletions
diff --git a/src/demuxers/Makefile.am b/src/demuxers/Makefile.am
index b0d482fa8..220546951 100644
--- a/src/demuxers/Makefile.am
+++ b/src/demuxers/Makefile.am
@@ -26,7 +26,7 @@ lib_LTLIBRARIES = $(ogg_module) $(qt_modules) $(asf_module) xineplug_dmx_avi.la
xineplug_dmx_mpeg_block.la xineplug_dmx_mpeg.la \
xineplug_dmx_mpeg_elem.la xineplug_dmx_mpeg_audio.la \
xineplug_dmx_mpeg_pes.la xineplug_dmx_mpeg_ts.la \
- xineplug_dmx_cda.la
+ xineplug_dmx_cda.la xineplug_dmx_film.la
xineplug_dmx_ogg_la_SOURCES = demux_ogg.c
xineplug_dmx_ogg_la_LIBADD = $(OGG_LIBS) \
@@ -73,6 +73,10 @@ xineplug_dmx_cda_la_SOURCES = demux_cda.c
xineplug_dmx_cda_la_LIBADD = $(top_builddir)/src/xine-engine/libxine.la
xineplug_dmx_cda_la_LDFLAGS = -avoid-version -module
+xineplug_dmx_film_la_SOURCES = demux_film.c
+xineplug_dmx_film_la_LIBADD = $(top_builddir)/src/xine-engine/libxine.la
+xineplug_dmx_film_la_LDFLAGS = -avoid-version -module
+
include_HEADERS = demux.h
##
diff --git a/src/demuxers/demux_film.c b/src/demuxers/demux_film.c
new file mode 100644
index 000000000..9a8e5673a
--- /dev/null
+++ b/src/demuxers/demux_film.c
@@ -0,0 +1,683 @@
+/*
+ * 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
+ *
+ * FILM (CPK) File Demuxer by Mike Melanson (melanson@pcisys.net)
+ * For more information on the FILM file format, visit:
+ * http://www.pcisys.net/~melanson/codecs/
+ *
+ * $Id: demux_film.c,v 1.1 2002/05/27 07:32:36 tmmm Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "xine_internal.h"
+#include "xineutils.h"
+#include "compat.h"
+#include "demux.h"
+#include "bswap.h"
+
+#define BE_16(x) (be2me_16(*(unsigned short *)(x)))
+#define BE_32(x) (be2me_32(*(unsigned int *)(x)))
+
+#define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \
+ ( (long)(unsigned char)(ch3) | ( (long)(unsigned char)(ch2) << 8 ) | \
+ ( (long)(unsigned char)(ch1) << 16 ) | ( (long)(unsigned char)(ch0) << 24 ) )
+
+#define FILM_TAG FOURCC_TAG('F', 'I', 'L', 'M')
+#define FDSC_TAG FOURCC_TAG('F', 'D', 'S', 'C')
+#define STAB_TAG FOURCC_TAG('S', 'T', 'A', 'B')
+#define CVID_TAG FOURCC_TAG('c', 'v', 'i', 'd')
+
+#define VALID_ENDS "cpk,cak,film"
+
+/* TODO: lobby the xine team to revise the API so that it's no longer
+ necessary to ship around this inane Win32-specific structure */
+typedef struct {
+ long biSize;
+ long biWidth;
+ long biHeight;
+ short biPlanes;
+ short biBitCount;
+ long biCompression;
+ long biSizeImage;
+ long biXPelsPerMeter;
+ long biYPelsPerMeter;
+ long biClrUsed;
+ long biClrImportant;
+} BITMAPINFOHEADER;
+
+typedef struct {
+ off_t sample_offset;
+ unsigned int sample_size;
+ unsigned int syncinfo1;
+ unsigned int syncinfo2;
+ int64_t pts;
+} film_sample_t;
+
+typedef struct {
+
+ demux_plugin_t demux_plugin;
+
+ xine_t *xine;
+
+ config_values_t *config;
+
+ fifo_buffer_t *video_fifo;
+ fifo_buffer_t *audio_fifo;
+
+ input_plugin_t *input;
+
+ pthread_t thread;
+ int thread_running;
+ pthread_mutex_t mutex;
+
+ off_t start;
+ int status;
+
+ char version[4];
+
+ /* video information */
+ unsigned int video_codec;
+ unsigned int video_type;
+ BITMAPINFOHEADER bih;
+
+ /* audio information */
+ unsigned int audio_type;
+ unsigned int sample_rate;
+ unsigned int audio_bits;
+ unsigned int audio_channels;
+
+ /* playback info */
+ unsigned int frequency;
+ unsigned int sample_count;
+ film_sample_t *sample_table;
+
+} demux_film_t ;
+
+/* returns 1 if FILM file was opened successfully */
+static int open_film_file(demux_film_t *film)
+{
+ unsigned char *film_header;
+ unsigned int film_header_size;
+ unsigned char scratch[16];
+ unsigned int chunk_type;
+ unsigned int chunk_size;
+ unsigned int i, j;
+ unsigned int audio_byte_count = 0;
+
+ /* initialize structure fields */
+ film->bih.biWidth = 0;
+ film->bih.biHeight = 0;
+ film->video_codec = 0;
+ film->sample_rate = 0;
+ film->audio_bits = 0;
+ film->audio_channels = 0;
+
+ /* reset the file */
+ film->input->seek(film->input, 0, SEEK_SET);
+
+ /* get the signature, header length and file version */
+ if (film->input->read(film->input, scratch, 16) != 16) {
+ return 0;
+ }
+ if (BE_32(&scratch[0]) != FILM_TAG) {
+ xine_log(film->xine, XINE_LOG_FORMAT,
+ _("demux_film: This is not a FILM file (why was it sent to this demuxer?\n"));
+ return 0;
+ }
+
+ /* header size = header size - 16-byte FILM signature */
+ film_header_size = BE_32(&scratch[4]) - 16;
+ film_header = xine_xmalloc(film_header_size);
+ if (!film_header)
+ return 0;
+ strncpy(film->version, &scratch[8], 4);
+
+ /* load the rest of the FILM header */
+ if (film->input->read(film->input, film_header, film_header_size) !=
+ film_header_size) {
+ return 0;
+ }
+
+ /* traverse the FILM header */
+ i = 0;
+ while (i < film_header_size) {
+ chunk_type = BE_32(&film_header[i]);
+ chunk_size = BE_32(&film_header[i + 4]);
+
+ /* sanity check the chunk size */
+ if (i + chunk_size > film_header_size) {
+ xine_log(film->xine, XINE_LOG_FORMAT,
+ _("invalid FILM chunk size\n"));
+ return 0;
+ }
+
+ switch(chunk_type) {
+ case FDSC_TAG:
+ /* always fetch the video information */
+ film->bih.biWidth = BE_32(&film_header[i + 16]);
+ film->bih.biHeight = BE_32(&film_header[i + 12]);
+ film->video_codec = BE_32(&film_header[i + 8]);
+ if (film->video_codec == CVID_TAG)
+ film->video_type = BUF_VIDEO_CINEPAK;
+ else
+ film->video_type = 0;
+
+ /* fetch the audio information if the chunk size checks out */
+ if (chunk_size == 32) {
+ film->audio_channels = film_header[21];
+ film->audio_bits = film_header[22];
+ film->sample_rate = BE_16(&film_header[24]);
+ } else {
+ /* otherwise, make a few assumptions about the audio parms */
+ film->audio_channels = 1;
+ film->audio_bits = 8;
+ film->sample_rate = 22050;
+ }
+ if (film->sample_rate)
+ film->audio_type = BUF_AUDIO_LPCM_BE;
+ else
+ film->audio_type = 0;
+ break;
+
+ case STAB_TAG:
+ /* load the sample table */
+ film->frequency = BE_32(&film_header[i + 8]);
+ film->sample_count = BE_32(&film_header[i + 12]);
+ film->sample_table =
+ xine_xmalloc(film->sample_count * sizeof(film_sample_t));
+ for (j = 0; j < film->sample_count; j++) {
+ film->sample_table[j].sample_offset =
+ BE_32(&film_header[(i + 16) + j * 16 + 0])
+ + film_header_size + 16;
+ film->sample_table[j].sample_size =
+ BE_32(&film_header[(i + 16) + j * 16 + 4]);
+ film->sample_table[j].syncinfo1 =
+ BE_32(&film_header[(i + 16) + j * 16 + 8]);
+ film->sample_table[j].syncinfo2 =
+ BE_32(&film_header[(i + 16) + j * 16 + 12]);
+
+ /* figure out the pts */
+ if (film->sample_table[j].syncinfo1 == 0xFFFFFFFF) {
+ film->sample_table[j].pts = audio_byte_count;
+ film->sample_table[j].pts *= 90000;
+ film->sample_table[j].pts /=
+ (film->sample_rate * film->audio_channels * (film->audio_bits / 8));
+ audio_byte_count += film->sample_table[j].sample_size;
+ }
+ else
+ film->sample_table[j].pts =
+ (90000 * (film->sample_table[j].syncinfo1 & 0x7FFFFFFF)) /
+ film->frequency;
+ }
+
+ /*
+ * in some files, this chunk length does not account for the 16-byte
+ * chunk preamble; watch for it
+ */
+ if (chunk_size == film->sample_count * 16)
+ i += 16;
+ break;
+
+ default:
+ xine_log(film->xine, XINE_LOG_FORMAT,
+ _("unrecognized FILM chunk\n"));
+ return 0;
+ }
+
+ i += chunk_size;
+ }
+
+ return 1;
+}
+
+static void *demux_film_loop (void *this_gen) {
+
+ demux_film_t *this = (demux_film_t *) this_gen;
+ buf_element_t *buf = NULL;
+ int i = 0;
+ unsigned int cvid_chunk_size;
+ int fixed_cvid_header;
+ unsigned int remaining_sample_bytes;
+
+ /* do-while needed to seek after demux finished */
+ do {
+ /* main demuxer loop */
+ while (this->status == DEMUX_OK) {
+printf("loading sample #%d\n", i);
+
+ /* check if all the samples have been sent */
+ if (i >= this->sample_count) {
+ this->status = DEMUX_FINISHED;
+ break;
+ }
+
+ if ((this->sample_table[i].syncinfo1 != 0xFFFFFFFF) &&
+ (this->video_type == BUF_VIDEO_CINEPAK)) {
+ /* do a special song and dance when loading CVID data */
+ if (this->version)
+ cvid_chunk_size = this->sample_table[i].sample_size - 2;
+ else
+ cvid_chunk_size = this->sample_table[i].sample_size - 6;
+ /* reset flag */
+ fixed_cvid_header = 0;
+
+ remaining_sample_bytes = cvid_chunk_size;
+ this->input->seek(this->input, this->sample_table[i].sample_offset,
+ SEEK_SET);
+
+ while (remaining_sample_bytes) {
+printf ("loading CVID packet\n");
+ buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
+ buf->type = this->video_type;
+ buf->input_pos = this->sample_table[i].sample_offset;
+ buf->pts = this->sample_table[i].pts;
+ buf->decoder_flags = 0;
+
+ if (remaining_sample_bytes > buf->max_size)
+ buf->size = buf->max_size;
+ else
+ buf->size = remaining_sample_bytes;
+ remaining_sample_bytes -= buf->size;
+
+ if (!fixed_cvid_header) {
+ if (this->input->read(this->input, buf->content, 10) != 10) {
+ this->status = DEMUX_FINISHED;
+ break;
+ }
+
+ /* skip over the extra non-spec CVID bytes */
+ this->input->seek(this->input,
+ this->sample_table[i].sample_size - cvid_chunk_size, SEEK_CUR);
+
+ /* load the rest of the chunk */
+ if (this->input->read(this->input, buf->content + 10,
+ buf->size - 10) != buf->size - 10) {
+ this->status = DEMUX_FINISHED;
+ break;
+ }
+
+ /* adjust the length in the CVID data chunk */
+ buf->content[1] = (cvid_chunk_size >> 16) & 0xFF;
+ buf->content[2] = (cvid_chunk_size >> 8) & 0xFF;
+ buf->content[3] = (cvid_chunk_size >> 0) & 0xFF;
+
+ fixed_cvid_header = 1;
+ } else {
+ if (this->input->read(this->input, buf->content, buf->size) !=
+ buf->size) {
+ this->status = DEMUX_FINISHED;
+ break;
+ }
+ }
+
+ if ((this->sample_table[i].syncinfo1 & 0x80000000) == 0)
+ buf->decoder_flags |= BUF_FLAG_KEYFRAME;
+ if (!remaining_sample_bytes)
+ buf->decoder_flags |= BUF_FLAG_FRAME_END;
+ this->video_fifo->put(this->video_fifo, buf);
+ }
+ } else if (this->sample_table[i].syncinfo1 != 0xFFFFFFFF) {
+ /* FILM files always appear to use Cinepak video, but pretend that
+ sometimes they don't and add a provision to load another kind of
+ video chunk */
+ remaining_sample_bytes = this->sample_table[i].sample_size;
+ this->input->seek(this->input, this->sample_table[i].sample_offset,
+ SEEK_SET);
+
+ while (remaining_sample_bytes) {
+printf ("loading video packet\n");
+ buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
+ buf->type = this->video_type;
+ buf->input_pos = this->sample_table[i].sample_offset;
+ buf->pts = this->sample_table[i].pts;
+ buf->decoder_flags = 0;
+
+ if (remaining_sample_bytes > buf->max_size)
+ buf->size = buf->max_size;
+ else
+ buf->size = remaining_sample_bytes;
+ remaining_sample_bytes -= buf->size;
+
+ if (this->input->read(this->input, buf->content, buf->size) !=
+ buf->size) {
+ this->status = DEMUX_FINISHED;
+ break;
+ }
+
+ if ((this->sample_table[i].syncinfo1 & 0x80000000) == 0)
+ buf->decoder_flags |= BUF_FLAG_KEYFRAME;
+ if (!remaining_sample_bytes)
+ buf->decoder_flags |= BUF_FLAG_FRAME_END;
+ this->video_fifo->put(this->video_fifo, buf);
+ }
+ } else {
+ /* load an audio sample and packetize it */
+ remaining_sample_bytes = this->sample_table[i].sample_size;
+ this->input->seek(this->input, this->sample_table[i].sample_offset,
+ SEEK_SET);
+
+ while (remaining_sample_bytes) {
+printf ("loading audio packet\n");
+ buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
+ buf->type = this->audio_type;
+ buf->input_pos = this->sample_table[i].sample_offset;
+ buf->pts = this->sample_table[i].pts;
+ buf->decoder_flags = 0;
+
+ if (remaining_sample_bytes > buf->max_size)
+ buf->size = buf->max_size;
+ else
+ buf->size = remaining_sample_bytes;
+ remaining_sample_bytes -= buf->size;
+
+ if (this->input->read(this->input, buf->content, buf->size) !=
+ buf->size) {
+ this->status = DEMUX_FINISHED;
+ break;
+ }
+
+ if (!remaining_sample_bytes)
+ buf->decoder_flags |= BUF_FLAG_FRAME_END;
+ this->audio_fifo->put(this->audio_fifo, buf);
+ }
+ }
+
+ i++;
+
+ /* someone may want to interrupt us */
+ pthread_mutex_unlock( &this->mutex );
+ pthread_mutex_lock( &this->mutex );
+ }
+ } while (this->status == DEMUX_OK);
+
+ printf ("demux_film: demux loop finished (status: %d)\n",
+ this->status);
+
+ this->status = DEMUX_FINISHED;
+
+// if (this->send_end_buffers) {
+ if (1) {
+ buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
+ buf->type = BUF_CONTROL_END;
+ buf->decoder_flags = BUF_FLAG_END_STREAM; /* stream finished */
+ this->video_fifo->put (this->video_fifo, buf);
+
+ if(this->audio_fifo) {
+ buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
+ buf->type = BUF_CONTROL_END;
+ buf->decoder_flags = BUF_FLAG_END_STREAM; /* stream finished */
+ this->audio_fifo->put (this->audio_fifo, buf);
+ }
+ }
+ return NULL;
+}
+
+static int demux_film_open(demux_plugin_t *this_gen, input_plugin_t *input,
+ int stage) {
+
+ demux_film_t *this = (demux_film_t *) this_gen;
+ char sig[4];
+
+ 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, sig, 4) != 4) {
+ return DEMUX_CANNOT_HANDLE;
+ }
+ if (strncmp(sig, "FILM", 4) == 0)
+ return DEMUX_CAN_HANDLE;
+
+ 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_film", VALID_ENDS,
+ "valid mrls ending for film demuxer",
+ NULL, NULL, NULL)));
+ while((m = xine_strsep(&valid_ends, ",")) != NULL) {
+
+ while(*m == ' ' || *m == '\t') m++;
+
+ if(!strcasecmp((suffix + 1), m)) {
+ this->input = input;
+ return DEMUX_CAN_HANDLE;
+ }
+ }
+ return DEMUX_CANNOT_HANDLE;
+ }
+ break;
+
+ default:
+ return DEMUX_CANNOT_HANDLE;
+ break;
+
+ }
+
+ return DEMUX_CANNOT_HANDLE;
+}
+
+static int demux_film_start (demux_plugin_t *this_gen,
+ fifo_buffer_t *video_fifo,
+ fifo_buffer_t *audio_fifo,
+ off_t start_pos, int start_time) {
+
+ demux_film_t *this = (demux_film_t *) this_gen;
+ buf_element_t *buf;
+ int err;
+
+//printf ("start pos, time = %d, %d\n", start_pos, start_time);
+ pthread_mutex_lock(&this->mutex);
+
+ /* if thread is not running, initialize demuxer */
+ if (!this->thread_running) {
+ this->video_fifo = video_fifo;
+ this->audio_fifo = audio_fifo;
+
+ /* open the FILM file */
+ if (!open_film_file(this)) {
+ pthread_mutex_unlock(&this->mutex);
+ return DEMUX_FINISHED;
+ }
+
+ /* print vital stats */
+ xine_log (this->xine, XINE_LOG_FORMAT,
+ _("demux_film: FILM version %c%c%c%c\n"),
+ this->version[0],
+ this->version[1],
+ this->version[2],
+ this->version[3]);
+ if (this->video_type)
+ xine_log (this->xine, XINE_LOG_FORMAT,
+ _("demux_film: %c%c%c%c video @ %dx%d, %d Hz playback clock\n"),
+ (this->video_codec >> 24) & 0xFF,
+ (this->video_codec >> 16) & 0xFF,
+ (this->video_codec >> 8) & 0xFF,
+ (this->video_codec >> 0) & 0xFF,
+ this->bih.biWidth,
+ this->bih.biHeight,
+ this->frequency);
+ if (this->audio_type)
+ xine_log (this->xine, XINE_LOG_FORMAT,
+ _("demux_film: %d Hz, %d-bit %s%s PCM audio\n"),
+ this->sample_rate,
+ this->audio_bits,
+ (this->audio_bits == 16) ? "big-endian " : "",
+ (this->audio_channels == 1) ? "monaural" : "stereo");
+
+ /* send start buffers */
+ if (this->video_fifo && this->video_type) {
+ buf = this->video_fifo->buffer_pool_alloc(this->video_fifo);
+ buf->type = BUF_CONTROL_START;
+ this->video_fifo->put(this->video_fifo, buf);
+ }
+ if (this->audio_fifo && this->audio_type) {
+ buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo);
+ buf->type = BUF_CONTROL_START;
+ this->audio_fifo->put(this->audio_fifo, buf);
+ }
+
+ /* send new pts */
+ if (this->video_fifo && this->video_type) {
+ buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
+ buf->type = BUF_CONTROL_NEWPTS;
+ buf->disc_off = 0;
+ this->video_fifo->put (this->video_fifo, buf);
+ }
+ if (this->audio_fifo && this->audio_type) {
+ buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
+ buf->type = BUF_CONTROL_NEWPTS;
+ buf->disc_off = 0;
+ this->audio_fifo->put (this->audio_fifo, buf);
+ }
+
+ /* send init info to decoders */
+ if (this->video_fifo && this->video_type) {
+ buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
+ buf->content = buf->mem;
+ buf->decoder_flags = BUF_FLAG_HEADER;
+ buf->decoder_info[0] = 0;
+ buf->decoder_info[1] = 0; /* initial video_step */
+ memcpy(buf->content, &this->bih, sizeof(this->bih));
+ buf->size = sizeof(this->bih);
+ if (this->video_codec == CVID_TAG)
+ buf->type = BUF_VIDEO_CINEPAK;
+ else
+ buf->type = 0;
+ this->video_fifo->put (this->video_fifo, buf);
+ }
+
+ if (this->audio_fifo && this->audio_type) {
+ buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
+ buf->content = buf->mem;
+ buf->type = BUF_AUDIO_LPCM_BE;
+ buf->decoder_flags = BUF_FLAG_HEADER;
+ buf->decoder_info[0] = 0;
+ buf->decoder_info[1] = this->sample_rate;
+ buf->decoder_info[2] = this->audio_bits;
+ buf->decoder_info[3] = this->audio_channels;
+ this->audio_fifo->put (this->audio_fifo, buf);
+ }
+
+ this->status = DEMUX_OK;
+ this->thread_running = 1;
+
+ if ((err = pthread_create (&this->thread, NULL, demux_film_loop, this)) != 0) {
+ printf ("demux_film: can't create new thread (%s)\n", strerror(err));
+ abort();
+ }
+ }
+
+ pthread_mutex_unlock(&this->mutex);
+
+ return this->status;
+}
+
+static int demux_film_seek (demux_plugin_t *this_gen,
+ off_t start_pos, int start_time) {
+ demux_film_t *this = (demux_film_t *) this_gen;
+
+ return this->status;
+}
+
+static void demux_film_stop (demux_plugin_t *this_gen) {
+
+}
+
+static void demux_film_close (demux_plugin_t *this) {
+
+}
+
+static int demux_film_get_status (demux_plugin_t *this_gen) {
+ demux_film_t *this = (demux_film_t *) this_gen;
+
+ return this->status;
+}
+
+static char *demux_film_get_id(void) {
+ return "FILM (CPK)";
+}
+
+static int demux_film_get_stream_length (demux_plugin_t *this_gen) {
+
+printf ("demux_film_get_stream_length() called\n");
+
+ return 0;
+}
+
+static char *demux_film_get_mimetypes(void) {
+ return NULL;
+}
+
+
+demux_plugin_t *init_demuxer_plugin(int iface, xine_t *xine) {
+ demux_film_t *this;
+
+ if (iface != 8) {
+ printf ("demux_film: plugin doesn't support plugin API version %d.\n"
+ " this means there's a version mismatch between xine and this "
+ " demuxer plugin. Installing current demux plugins should help.\n",
+ iface);
+ return NULL;
+ }
+
+ this = (demux_film_t *) xine_xmalloc(sizeof(demux_film_t));
+ this->config = xine->config;
+ this->xine = xine;
+
+ this->demux_plugin.interface_version = DEMUXER_PLUGIN_IFACE_VERSION;
+ this->demux_plugin.open = demux_film_open;
+ this->demux_plugin.start = demux_film_start;
+ this->demux_plugin.seek = demux_film_seek;
+ this->demux_plugin.stop = demux_film_stop;
+ this->demux_plugin.close = demux_film_close;
+ this->demux_plugin.get_status = demux_film_get_status;
+ this->demux_plugin.get_identifier = demux_film_get_id;
+ this->demux_plugin.get_stream_length = demux_film_get_stream_length;
+ this->demux_plugin.get_mimetypes = demux_film_get_mimetypes;
+
+ return &this->demux_plugin;
+}