/* * 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.4 2001/04/22 00:31:44 guenter Exp $ * * top-level xine functions * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #if defined (__linux__) #include #elif defined (__FreeBSD__) #include #endif #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 "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_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_functions_t *ao, gui_status_callback_func_t gui_status_callback, config_values_t *config, 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 */ buffer_pool_init (2000, 4096); /* * init demuxer */ load_demux_plugins(this, config, DEMUXER_PLUGIN_IFACE_VERSION); this->audio_channel = 0; this->spu_channel = -1; this->cur_input_pos = 0; printf ("xine_init: demuxer initialized\n"); /* * init and start decoder threads */ video_decoder_init (this); this->mBufAudio = audio_decoder_init (ao); /* * init SPU decoder */ this->spu_fifo = fifo_buffer_new (); spudec_init(NULL); /* * load input plugins */ load_input_plugins (this, config, INPUT_PLUGIN_IFACE_VERSION); 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; }