summaryrefslogtreecommitdiff
path: root/src/xine-engine/xine.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xine-engine/xine.c')
-rw-r--r--src/xine-engine/xine.c607
1 files changed, 607 insertions, 0 deletions
diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c
new file mode 100644
index 000000000..9093e50ec
--- /dev/null
+++ b/src/xine-engine/xine.c
@@ -0,0 +1,607 @@
+/*
+ * Copyright (C) 2000-2001 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: xine.c,v 1.1 2001/04/18 22:36:05 f1rmb Exp $
+ *
+ * top-level xine functions
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <pthread.h>
+#if defined (__linux__)
+#include <endian.h>
+#elif defined (__FreeBSD__)
+#include <machine/endian.h>
+#endif
+
+#include "xine.h"
+#include "xine_internal.h"
+#include "audio_out.h"
+#include "video_out.h"
+#include "demuxers/demux.h"
+#include "buffer.h"
+#include "libac3/ac3.h"
+#include "libmpg123/mpg123.h"
+#include "libmpg123/mpglib.h"
+#include "libmpeg2/mpeg2.h"
+#ifdef ARCH_X86
+#include "libw32dll/w32codec.h"
+#endif
+#include "libspudec/spudec.h"
+#include "input/input_plugin.h"
+#include "metronom.h"
+#include "configfile.h"
+#include "monitor.h"
+#include "video_decoder.h"
+#include "audio_decoder.h"
+
+/* debugging purposes only */
+uint32_t xine_debug;
+
+/*
+#define TEST_FILE
+*/
+#ifdef TEST_FILE
+int gTestFile=-1;
+#endif
+
+/*
+ * xine global variables
+ */
+
+void xine_notify_stream_finished (xine_t *this) {
+ printf ("xine_notify_stream_finished\n");
+
+ xine_stop (this);
+
+ this->status_callback (this->status);
+}
+
+/*
+ *
+ */
+void *xine_spu_loop (xine_t *this, void *dummy) {
+
+ buf_element_t *pBuf;
+ int bRunning = 1;
+
+ while (bRunning) {
+
+ pBuf = this->fifo_funcs->fifo_buffer_get (this->spu_fifo);
+
+ switch (pBuf->nType) {
+ case BUF_QUIT:
+ bRunning = 0;
+ break;
+ case BUF_RESET:
+ spudec_reset ();
+ break;
+ case BUF_SPU:
+ spudec_decode(pBuf->pContent, pBuf->nSize, pBuf->nPTS);
+ break;
+ }
+ this->fifo_funcs->buffer_pool_free (pBuf);
+ }
+
+ return NULL;
+}
+
+/*
+ *
+ */
+void xine_stop (xine_t *this) {
+
+ pthread_mutex_lock (&this->xine_lock);
+
+ if (!this->cur_input_plugin)
+ return;
+
+ this->mnStatus = XINE_STOP;
+
+ if(this->cur_demuxer_plugin) {
+ this->cur_demuxer_plugin->demux_stop ();
+ this->cur_demuxer_plugin = NULL;
+ }
+
+ // FIXME
+ this->fifo_funcs->fifo_buffer_clear(this->mBufVideo);
+ this->fifo_funcs->fifo_buffer_clear(this->mBufAudio);
+ this->fifo_funcs->fifo_buffer_clear(this->spu_fifo);
+
+ if (gAudioOut)
+ gAudioOut->close ();
+
+ metronom_reset();
+ metronom_stop_clock ();
+
+ vo_reset();
+
+ this->cur_input_plugin->close();
+ this->cur_input_plugin = NULL;
+
+ pthread_mutex_unlock (&this->xine_lock);
+}
+
+/*
+ * *****
+ * Demuxers probing stuff
+ */
+static int try_demux_with_stages(xine_t *this, const char *MRL,
+ int stage1, int stage2) {
+ int s = 0, i;
+ int stages[3] = {
+ stage1, stage2, -1
+ };
+
+ if(stages[0] == -1) {
+ fprintf(stderr, "%s(%d) wrong first stage = %d !!\n",
+ __FUNCTION__, __LINE__, stage1);
+ return 0;
+ }
+
+ while(stages[s] != -1) {
+ for(i = 0; i < this->num_demuxer_plugins; i++) {
+ if(this->demuxer_plugins[i].open(this->cur_input_plugin,
+ MRL, stages[s]) == DEMUX_CAN_HANDLE) {
+
+ this->cur_demuxer_plugin = &this->demux_plugins[i];
+
+ xprintf(VERBOSE|DEMUX,"demuxer '%s' handle in stage '%s'.\n",
+ this->demux_plugins[i].get_identifier(),
+ (stages[s] == STAGE_BY_CONTENT) ? "STAGE_BY_CONTENT"
+ : ((stages[s] == STAGE_BY_EXTENSION) ? "STAGE_BY_EXTENSION"
+ : "UNKNOWN"));
+ return 1;
+ }
+#ifdef DEBUG
+ else
+ xprintf(VERBOSE|DEMUX, "demuxer '%s' cannot handle in stage '%s'.\n",
+ this->demuxer_plugins[i].get_identifier(),
+ (stages[s] == STAGE_BY_CONTENT) ? "STAGE_BY_CONTENT"
+ : ((stages[s] == STAGE_BY_EXTENSION) ? "STAGE_BY_EXTENSION"
+ : "UNKNOWN"));
+#endif
+ }
+ s++;
+ }
+
+ return 0;
+}
+/*
+ * Try to find a demuxer which handle the MRL stream
+ */
+static int find_demuxer(xine_t *this, const char *MRL) {
+
+ this->cur_demuxer_plugin = NULL;
+
+ switch(this->demux_strategy) {
+
+ case DEMUX_DEFAULT_STRATEGY:
+ if(try_demux_with_stages(this, MRL, STAGE_BY_CONTENT, STAGE_BY_EXTENSION))
+ return 1;
+ break;
+
+ case DEMUX_REVERT_STRATEGY:
+ if(try_demux_with_stages(this, MRL, STAGE_BY_EXTENSION, STAGE_BY_CONTENT))
+ return 1;
+ break;
+
+ case DEMUX_CONTENT_STRATEGY:
+ if(try_demux_with_stages(this, MRL, STAGE_BY_CONTENT, -1))
+ return 1;
+ break;
+
+ case DEMUX_EXTENSION_STRATEGY:
+ if(try_demux_with_stages(this, MRL, STAGE_BY_EXTENSION, -1))
+ return 1;
+ break;
+
+ }
+
+ return 0;
+}
+
+/*
+ *
+ */
+static void xine_play_internal (xine_t *this, char *MRL,
+ int spos, off_t pos) {
+
+ double share ;
+ off_t len;
+ int i;
+
+ xprintf (VERBOSE|LOOP, "xine open %s, start pos = %d\n",MRL, spos);
+
+ if (this->status == XINE_PAUSE) {
+ xine_pause();
+ return;
+ }
+
+ if (this->status != XINE_STOP) {
+ xine_stop ();
+ }
+
+ /*
+ * find input plugin
+ */
+
+ this->cur_input_plugin = NULL;
+
+ for (i = 0; i < this->num_input_plugins; i++) {
+ if (this->input_plugins[i].open(MRL)) {
+ this->cur_input_plugin = &this->input_plugins[i];
+ break;
+ }
+ }
+
+ if (!this->cur_input_plugin) {
+ perror ("open input source");
+ this->cur_demuxer_plugin = NULL;
+ return;
+ }
+
+ /*
+ * find demuxer plugin
+ */
+
+ if(!find_demuxer(this, MRL)) {
+ printf ("error: couldn't find demuxer for >%s<\n", MRL);
+ return;
+ }
+
+ vo_set_logo_mode (0);
+
+ /*
+ * Init SPU decoder with colour lookup table.
+ */
+
+ if(this->cur_input_plugin->get_clut)
+ spudec_init(this->cur_input_plugin->get_clut());
+ else
+ spudec_init(NULL);
+
+ /*
+ * metronom
+ */
+
+ metronom_reset();
+
+ /*
+ * start demuxer
+ */
+
+ if (spos) {
+ len = this->cur_input_plugin->get_length ();
+ share = (double) spos / 65535;
+ pos = (off_t) (share * len) ;
+ }
+
+ this->cur_demuxer_plugin->demux_select_audio_channel (this->audio_channel);
+ this->cur_demuxer_plugin->demux_select_spu_channel (this->spu_channel);
+ this->cur_demuxer_plugin->demux_start (this->cur_input_plugin,
+ this->mBufVideo, //FIXME
+ this->mBufAudio,
+ this->spu_fifo, pos);
+
+ this->status = XINE_PLAY;
+ this->cur_input_pos = pos;
+
+ /*
+ * remember MRL
+ */
+
+ strncpy (this->cur_mrl, MRL, 1024);
+
+ /*
+ * start clock
+ */
+
+ metronom_start_clock (0);
+}
+
+/*
+ *
+ */
+void xine_play (xine_t *this, char *MRL, int spos) {
+
+ pthread_mutex_lock (&this->xine_lock);
+
+ if (this->status != XINE_PLAY)
+ xine_play_internal (this, MRL, spos, (off_t) 0);
+
+ pthread_mutex_unlock (&this->xine_lock);
+}
+
+/*
+ *
+ */
+static int xine_eject (xine_t *this, char *MRL) {
+ int i;
+
+ pthread_mutex_lock (&this->xine_lock);
+
+ if(this->cur_input_plugin == NULL) {
+
+ for (i = 0; i < this->num_input_plugins; i++) {
+ if (this->input_pluginss[i].open(MRL)) {
+ this->cur_input_plugin = &this->input_plugins[i];
+ this->cur_input_plugin->close();
+ break;
+ }
+ }
+ }
+
+ if (this->status == XINE_STOP
+ && this->cur_input_plugin && this->cur_input_plugin->eject_media) {
+
+ pthread_mutex_unlock (&this->xine_lock);
+
+ return this->cur_input_plugin->eject_media ();
+ }
+
+ pthread_mutex_unlock (&this->xine_lock);
+ return 0;
+}
+
+/*
+ *
+ */
+void xine_exit (xine_t *this) {
+
+ void *p;
+ buf_element_t *pBuf;
+
+ /*
+ * stop decoder threads
+ */
+
+ if (this->cur_input_plugin)
+ this->cur_input_plugin->demux_stop ();
+
+ this->fifo_funcs->fifo_buffer_clear(this->spu_fifo);
+
+ audio_decoder_shutdown ();
+ video_decoder_shutdown ();
+
+ this->status = XINE_QUIT;
+
+ config_file_save ();
+}
+
+/*
+ *
+ */
+static void xine_pause (xine_t *this) {
+
+ pthread_mutex_lock (&this->xine_lock);
+
+ if (this->status == XINE_PAUSE) {
+
+ xprintf (VERBOSE, "xine play %s from %Ld\n",
+ this->cur_mrl, this->cur_input_pos);
+
+ this->status = XINE_STOP;
+
+ xine_play_internal (this, this->cur_mrl, 0, this->cur_input_pos);
+ /* this->mnPausePos = 0; */
+
+ } else if (this->status == XINE_PLAY) {
+
+ if (!this->cur_input_plugin) {
+ pthread_mutex_unlock (&this->xine_lock);
+ return;
+ }
+
+ this->status = XINE_PAUSE;
+
+ this->cur_demuxer_plugin->demux_stop ();
+ this->cur_demuxer_plugin = NULL;
+
+ //FIXME
+ this->fifo_funcs->fifo_buffer_clear(this->mBufVideo);
+ this->fifo_funcs->fifo_buffer_clear(this->mBufAudio);
+ this->fifo_funcs->fifo_buffer_clear(this->spu_fifo);
+
+ if (gAudioOut)
+ gAudioOut->close ();
+
+ metronom_reset();
+ metronom_stop_clock ();
+
+ vo_reset ();
+
+ this->cur_input_plugin->close();
+ }
+
+ pthread_mutex_unlock (&this->xine_lock);
+}
+
+/*
+ *
+ */
+xine_t *xine_init (vo_instance_t *vo, ao_instance_t *ao,
+ gui_status_callback_func_t gui_status_callback,
+ int demux_strategy, uint32_t debug_lvl) {
+
+ xine_t *this = xmalloc (sizeof (xine_t));
+ int err;
+
+ this->status_callback = gui_status_callback;
+ this->demux_strategy = demux_strategy;
+ xine_debug = debug_lvl;
+
+#ifdef TEST_FILE
+ gTestFile = open ("/tmp/test.mp3", O_WRONLY | O_CREAT, 0644);
+#endif
+
+ /*
+ * init lock
+ */
+
+ pthread_mutex_init (&this->xine_lock, NULL);
+
+ /*
+ * Init buffers
+ */
+
+ this->fifo_funcs = buffer_pool_init (2000, 4096);
+ this->spu_fifo = this->fifo_funcs->fifo_buffer_new ();
+
+ /*
+ * init demuxer
+ */
+
+ xine_load_demux_plugins();
+
+ this->audio_channel = 0;
+ this->spu_channel = -1;
+ this->cur_input_pos = 0;
+
+ printf ("xine_init: demuxer initialized\n");
+
+ /*
+ * init and start decoder threads
+ */
+
+ this->mBufVideo = video_decoder_init (vo);
+
+ this->mBufAudio = audio_decoder_init (ao);
+
+ /*
+ * init SPU decoder, start SPU thread
+ */
+
+ spudec_init(NULL);
+
+ if((err = pthread_create (&this->spu_thread, NULL,
+ xine_spu_loop, NULL)) != 0) {
+ fprintf(stderr, "pthread_create failed: return code %d.\n", err);
+ exit(1);
+ }
+ else
+ printf ("xine_init: SPU thread created\n");
+
+ /*
+ * load input plugins
+ */
+
+ xine_load_input_plugins ();
+
+ printf ("xine_init: plugins loaded\n");
+
+ return this;
+}
+
+/*
+ *
+ */
+int xine_get_audio_channel (xine_t *this) {
+
+ return this->audio_channel;
+}
+
+/*
+ *
+ */
+void xine_select_audio_channel (xine_t *this, int nChannel) {
+
+ pthread_mutex_lock (&this->xine_lock);
+
+ this->audio_channel = nChannel;
+
+ if (this->cur_demuxer_plugin) {
+ this->cur_demuxer_plugin->demux_select_audio_channel (this->audio_channel);
+ }
+
+ pthread_mutex_unlock (&this->xine_lock);
+}
+
+/*
+ *
+ */
+int xine_get_spu_channel (xine_t *this) {
+
+ return this->spu_channel;
+}
+
+/*
+ *
+ */
+void xine_select_spu_channel (xine_t *this, int nChannel) {
+
+ pthread_mutex_lock (&this->xine_lock);
+
+ this->spu_channel = (nChannel >= -1 ? nChannel : -1);
+
+ if (this->cur_demuxer_plugin)
+ this->cur_demuxer_plugin->demux_select_spu_channel (this->spu_channel);
+
+ pthread_mutex_unlock (&this->xine_lock);
+}
+
+/*
+ *
+ */
+input_plugin_t* xine_get_input_plugin_list (xine_t *this, int *nInputPlugins) {
+
+ *nInputPlugins = this->num_input_plugins;
+ return this->input_plugins;
+}
+
+/*
+ *
+ */
+int xine_get_current_position (xine_t *this) {
+
+ off_t len;
+ double share;
+
+ pthread_mutex_lock (&this->xine_lock);
+
+ if (!this->cur_input_plugin) {
+ xprintf (VERBOSE|INPUT, "xine_get_current_position: no input source\n");
+ pthread_mutex_unlock (&this->xine_lock);
+ return 0;
+ }
+
+ /* pos = this->mCurInput->seek (0, SEEK_CUR); */
+ len = this->cur_input_plugin->get_length ();
+
+ share = (double) this->cur_input_pos / (double) len * 65535;
+
+ pthread_mutex_unlock (&this->xine_lock);
+
+ return (int) share;
+}
+
+/*
+ *
+ */
+int xine_get_status(xine_t *this) {
+
+ return this->status;
+}