]> git.tdb.fi Git - xinema.git/blobdiff - source/xinestream.cpp
Treat zero frame duration as zero fps rather than infinity
[xinema.git] / source / xinestream.cpp
index 619ec5800872e7d1c843f4eddde41c50178c1193..416902a3d7b835907ddc39ef0384a2a3369f7c85 100644 (file)
@@ -1,4 +1,4 @@
-#include <msp/io/print.h>
+#include <msp/strings/format.h>
 #include "xineengine.h"
 #include "xinestream.h"
 
@@ -7,18 +7,31 @@ using namespace Msp;
 
 XineStream::XineStream(XineEngine &e, const string &mrl):
        engine(e),
-       state(STOPPED)
+       filename(mrl.substr(mrl.rfind('/')+1)),
+       state(STOPPED),
+       title(filename),
+       video_width(0),
+       video_height(0),
+       framerate(0.0f),
+       current_audio(0),
+       current_spu(OFF),
+       channels_changed(false)
 {
        stream = xine_stream_new(engine.get_engine(), engine.get_audio_driver(), engine.get_video_driver());
-       xine_open(stream, mrl.c_str());
-
        queue = xine_event_new_queue(stream);
+       xine_open(stream, mrl.c_str());
 
-       check_info();
+       update_channels();
+       update_info();
 
        engine.add_stream(*this);
 }
 
+const string &XineStream::get_title() const
+{
+       return title.empty() ? filename : title;
+}
+
 XineStream::~XineStream()
 {
        engine.remove_stream(*this);
@@ -68,10 +81,31 @@ void XineStream::set_state(State s)
        if(s==state)
                return;
 
+       MutexLock lock(mutex);
        state = s;
        signal_state_changed.emit(state);
 }
 
+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::tick()
 {
        while(xine_event_t *event = xine_event_get(queue))
@@ -80,24 +114,59 @@ void XineStream::tick()
                xine_event_free(event);
        }
 
-       check_info();
+       if(channels_changed)
+       {
+               channels_changed = false;
+               update_channels();
+       }
+
+       update_info();
 }
 
-void XineStream::check_info()
+bool XineStream::equals(const string &s1, const char *s2)
+{
+       if(!s2)
+               return s1.empty();
+       return !s1.compare(s2);
+}
+
+void XineStream::update_info()
 {
        const char *xt = xine_get_meta_info(stream, XINE_META_INFO_TITLE);
-       if(xt)
+       if(!equals(title, xt))
        {
-               if(title.compare(xt))
-               {
-                       title = xt;
-                       signal_title_changed.emit(title);
-               }
+               MutexLock lock(mutex);
+               title = (xt ? xt : string());
+               signal_title_changed.emit(get_title());
        }
-       else if(!title.empty())
+
+       unsigned w = xine_get_stream_info(stream, XINE_STREAM_INFO_VIDEO_WIDTH);
+       unsigned h = xine_get_stream_info(stream, XINE_STREAM_INFO_VIDEO_HEIGHT);
+       if(w!=video_width || h!=video_height)
        {
-               title.clear();
-               signal_title_changed.emit(title);
+               MutexLock lock(mutex);
+               video_width = w;
+               video_height = h;
+               signal_video_size_changed.emit(video_width, video_height);
+       }
+
+       unsigned frame_dur = xine_get_stream_info(stream, XINE_STREAM_INFO_FRAME_DURATION);
+       float fps = (frame_dur ? 90000.0f/frame_dur : 0.0f);
+       if(fps!=framerate)
+       {
+               MutexLock lock(mutex);
+               framerate = fps;
+               signal_framerate_changed.emit(framerate);
+       }
+
+       const char *xvc = xine_get_meta_info(stream, XINE_META_INFO_VIDEOCODEC);
+       const char *xac = xine_get_meta_info(stream, XINE_META_INFO_AUDIOCODEC);
+       if(!equals(video_codec, xvc) || !equals(audio_codec, xac))
+       {
+               MutexLock lock(mutex);
+               video_codec = (xvc ? xvc : string());
+               audio_codec = (xac ? xac : string());
+               signal_codecs_changed.emit(video_codec, audio_codec);
        }
 
        int dur_msec, pos_msec;
@@ -106,14 +175,66 @@ void XineStream::check_info()
        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)
+       {
+               if(xine_get_audio_lang(stream, i, langbuf))
+                       audio_channels[i].assign(langbuf);
+               else
+                       audio_channels[i].assign("unknown");
+       }
+
+       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)
+       {
+               if(xine_get_spu_lang(stream, i, langbuf))
+                       spu_channels[i].assign(langbuf);
+               else
+                       spu_channels[i].assign("unknown");
+       }
+
+       signal_channels_changed.emit();
 }
 
 void XineStream::handle_event(const xine_event_t &event)
@@ -122,12 +243,10 @@ void XineStream::handle_event(const xine_event_t &event)
        {
        case XINE_EVENT_UI_PLAYBACK_FINISHED:
                set_state(STOPPED);
+               signal_finished.emit();
                break;
-       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_CHANNELS_CHANGED:
+               channels_changed = true;
                break;
        }
 }