]> git.tdb.fi Git - xinema.git/blobdiff - source/xinestream.cpp
Move the xine_open call after event queue creation
[xinema.git] / source / xinestream.cpp
index fd2c6224fb9e6aea49551af343f829b4881d37fe..1d7433e5e5807eacfe5ae799f3d12fb84c02ec32 100644 (file)
@@ -1,33 +1,99 @@
-#include <msp/io/print.h>
+#include <msp/strings/format.h>
 #include "xineengine.h"
 #include "xinestream.h"
 
 using namespace std;
 using namespace Msp;
 
-XineStream::XineStream(XineEngine &engine, const string &mrl)
+XineStream::XineStream(XineEngine &e, const string &mrl):
+       engine(e),
+       state(STOPPED),
+       current_audio(0),
+       current_spu(OFF),
+       channels_changed(false)
 {
        stream = xine_stream_new(engine.get_engine(), engine.get_audio_driver(), engine.get_video_driver());
+       queue = xine_event_new_queue(stream);
        xine_open(stream, mrl.c_str());
 
-       queue = xine_event_new_queue(stream);
+       update_channels();
+       update_info();
+
+       engine.add_stream(*this);
 }
 
 XineStream::~XineStream()
 {
+       engine.remove_stream(*this);
+
        xine_close(stream);
        xine_event_dispose_queue(queue);
        xine_dispose(stream);
 }
 
+void XineStream::select_audio_channel(int i)
+{
+       if(i>=0 && static_cast<unsigned>(i)>=audio_channels.size())
+               throw out_of_range("XineStream::set_audio_channel");
+
+       if(i<0)
+               i = OFF;
+       xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, (i==OFF ? -2 : i));
+}
+
+void XineStream::select_spu_channel(int i)
+{
+       if(i>=0 && static_cast<unsigned>(i)>=spu_channels.size())
+               throw out_of_range("XineStream::set_spu_channel");
+
+       if(i<0)
+               i = OFF;
+       xine_set_param(stream, XINE_PARAM_SPU_CHANNEL, (i==OFF ? -2 : i));
+}
+
 void XineStream::play()
 {
-       xine_play(stream, 0, 0);
+       if(state==STOPPED)
+               xine_play(stream, 0, 0);
+       else if(state==PAUSED)
+               xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
+
+       set_state(PLAYING);
+}
+
+void XineStream::seek(const Time::TimeDelta &time)
+{
+       xine_play(stream, 0, time/Time::msec);
+       if(state!=PLAYING)
+       {
+               xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
+               set_state(PAUSED);
+       }
+}
+
+void XineStream::pause()
+{
+       if(state==PLAYING)
+       {
+               xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
+               set_state(PAUSED);
+       }
 }
 
 void XineStream::stop()
 {
        xine_stop(stream);
+       set_state(STOPPED);
+}
+
+void XineStream::set_state(State s)
+{
+       if(s==state)
+               return;
+
+       MutexLock lock(mutex);
+       state = s;
+       signal_state_changed.emit(state);
 }
 
 void XineStream::tick()
@@ -37,17 +103,125 @@ void XineStream::tick()
                handle_event(*event);
                xine_event_free(event);
        }
+
+       if(channels_changed)
+       {
+               channels_changed = false;
+               update_channels();
+       }
+
+       update_info();
+}
+
+void XineStream::update_info()
+{
+       const char *xt = xine_get_meta_info(stream, XINE_META_INFO_TITLE);
+       if((xt && title.compare(xt)) || (!xt && !title.empty()))
+       {
+               MutexLock lock(mutex);
+               title = (xt ? xt : string());
+               signal_title_changed.emit(title);
+       }
+
+       int dur_msec, pos_msec;
+       xine_get_pos_length(stream, 0, &pos_msec, &dur_msec);
+       Time::TimeDelta dur = dur_msec*Time::msec;
+       Time::TimeDelta pos = pos_msec*Time::msec;
+       if(dur!=duration)
+       {
+               MutexLock lock(mutex);
+               duration = dur;
+               signal_duration_changed.emit(duration);
+       }
+       if(pos!=position)
+       {
+               MutexLock lock(mutex);
+               position = pos;
+               signal_position_changed.emit(position);
+       }
+
+       int audio = xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL);
+       if(audio==-1 && !audio_channels.empty())
+               audio = 0;
+       else if(audio<0)
+               audio = OFF;
+       if(audio!=current_audio)
+       {
+               MutexLock lock(mutex);
+               current_audio = audio;
+               signal_current_audio_channel_changed.emit(current_audio);
+       }
+
+       int spu = xine_get_param(stream, XINE_PARAM_SPU_CHANNEL);
+       if(spu<0)
+               spu = OFF;
+       if(spu!=current_spu)
+       {
+               MutexLock lock(mutex);
+               current_spu = spu;
+               signal_current_spu_channel_changed.emit(current_spu);
+       }
+}
+
+void XineStream::update_channels()
+{
+       MutexLock lock(mutex);
+       char langbuf[XINE_LANG_MAX];
+
+       unsigned n_audio = xine_get_stream_info(stream, XINE_STREAM_INFO_MAX_AUDIO_CHANNEL);
+       audio_channels.resize(n_audio);
+       for(unsigned i=0; i<n_audio; ++i)
+       {
+               xine_get_audio_lang(stream, i, langbuf);
+               audio_channels[i].assign(langbuf);
+       }
+
+       unsigned n_spu = xine_get_stream_info(stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL);
+       spu_channels.resize(n_spu);
+       for(unsigned i=0; i<n_spu; ++i)
+       {
+               xine_get_spu_lang(stream, i, langbuf);
+               spu_channels[i].assign(langbuf);
+       }
+
+       signal_channels_changed.emit();
 }
 
 void XineStream::handle_event(const xine_event_t &event)
 {
        switch(event.type)
        {
-       case XINE_EVENT_PROGRESS:
-               {
-                       xine_progress_data_t *data = reinterpret_cast<xine_progress_data_t *>(event.data);
-                       IO::print("%s [%d%%]\n", data->description, data->percent);
-               }
+       case XINE_EVENT_UI_PLAYBACK_FINISHED:
+               set_state(STOPPED);
+               signal_finished.emit();
                break;
+       case XINE_EVENT_UI_CHANNELS_CHANGED:
+               channels_changed = true;
+               break;
+       }
+}
+
+
+void operator<<(LexicalConverter &conv, XineStream::State state)
+{
+       switch(state)
+       {
+       case XineStream::STOPPED: conv.result("STOPPED"); return;
+       case XineStream::PAUSED: conv.result("PAUSED"); return;
+       case XineStream::PLAYING: conv.result("PLAYING"); return;
+       default: conv.result(format("State(%d)", static_cast<int>(state))); return;
        }
 }
+
+void operator>>(const LexicalConverter &conv, XineStream::State &state)
+{
+       const string &str = conv.get();
+       if(str=="STOPPED")
+               state = XineStream::STOPPED;
+       else if(str=="PAUSED")
+               state = XineStream::PAUSED;
+       else if(str=="PLAYING")
+               state = XineStream::PLAYING;
+       else
+               throw lexical_error(format("Conversion of '%s' to XineStream::State", str));
+}