X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fxinestream.cpp;h=416902a3d7b835907ddc39ef0384a2a3369f7c85;hb=HEAD;hp=5614dd00838324e29a3483e70e16459792a02770;hpb=3bd92c1fa7a85b47356cd6f2bad23893955a0785;p=xinema.git diff --git a/source/xinestream.cpp b/source/xinestream.cpp index 5614dd0..416902a 100644 --- a/source/xinestream.cpp +++ b/source/xinestream.cpp @@ -1,4 +1,4 @@ -#include +#include #include "xineengine.h" #include "xinestream.h" @@ -6,18 +6,32 @@ using namespace std; using namespace Msp; XineStream::XineStream(XineEngine &e, const string &mrl): - engine(e) + engine(e), + 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); @@ -29,12 +43,67 @@ XineStream::~XineStream() 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::select_audio_channel(int i) +{ + if(i>=0 && static_cast(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(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() @@ -45,24 +114,59 @@ void XineStream::tick() xine_event_free(event); } - check_info(); + if(channels_changed) + { + channels_changed = false; + update_channels(); + } + + update_info(); +} + +bool XineStream::equals(const string &s1, const char *s2) +{ + if(!s2) + return s1.empty(); + return !s1.compare(s2); } -void XineStream::check_info() +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) + { + 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) { - title.clear(); - signal_title_changed.emit(title); + 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; @@ -71,25 +175,103 @@ 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(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(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)); +}