]> git.tdb.fi Git - xinema.git/blob - source/xinestream.cpp
4fc2e88fa1f569bcf2ef811117d2a02eb8bbef11
[xinema.git] / source / xinestream.cpp
1 #include <msp/strings/format.h>
2 #include "xineengine.h"
3 #include "xinestream.h"
4
5 using namespace std;
6 using namespace Msp;
7
8 XineStream::XineStream(XineEngine &e, const string &mrl):
9         engine(e),
10         filename(mrl.substr(mrl.rfind('/')+1)),
11         state(STOPPED),
12         title(filename),
13         current_audio(0),
14         current_spu(OFF),
15         channels_changed(false)
16 {
17         stream = xine_stream_new(engine.get_engine(), engine.get_audio_driver(), engine.get_video_driver());
18         queue = xine_event_new_queue(stream);
19         xine_open(stream, mrl.c_str());
20
21         update_channels();
22         update_info();
23
24         engine.add_stream(*this);
25 }
26
27 const string &XineStream::get_title() const
28 {
29         return title.empty() ? filename : title;
30 }
31
32 XineStream::~XineStream()
33 {
34         engine.remove_stream(*this);
35
36         xine_close(stream);
37         xine_event_dispose_queue(queue);
38         xine_dispose(stream);
39 }
40
41 void XineStream::play()
42 {
43         if(state==STOPPED)
44                 xine_play(stream, 0, 0);
45         else if(state==PAUSED)
46                 xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
47
48         set_state(PLAYING);
49 }
50
51 void XineStream::seek(const Time::TimeDelta &time)
52 {
53         xine_play(stream, 0, time/Time::msec);
54         if(state!=PLAYING)
55         {
56                 xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
57                 set_state(PAUSED);
58         }
59 }
60
61 void XineStream::pause()
62 {
63         if(state==PLAYING)
64         {
65                 xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
66                 set_state(PAUSED);
67         }
68 }
69
70 void XineStream::stop()
71 {
72         xine_stop(stream);
73         set_state(STOPPED);
74 }
75
76 void XineStream::set_state(State s)
77 {
78         if(s==state)
79                 return;
80
81         MutexLock lock(mutex);
82         state = s;
83         signal_state_changed.emit(state);
84 }
85
86 void XineStream::select_audio_channel(int i)
87 {
88         if(i>=0 && static_cast<unsigned>(i)>=audio_channels.size())
89                 throw out_of_range("XineStream::set_audio_channel");
90
91         if(i<0)
92                 i = OFF;
93         xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, (i==OFF ? -2 : i));
94 }
95
96 void XineStream::select_spu_channel(int i)
97 {
98         if(i>=0 && static_cast<unsigned>(i)>=spu_channels.size())
99                 throw out_of_range("XineStream::set_spu_channel");
100
101         if(i<0)
102                 i = OFF;
103         xine_set_param(stream, XINE_PARAM_SPU_CHANNEL, (i==OFF ? -2 : i));
104 }
105
106 void XineStream::tick()
107 {
108         while(xine_event_t *event = xine_event_get(queue))
109         {
110                 handle_event(*event);
111                 xine_event_free(event);
112         }
113
114         if(channels_changed)
115         {
116                 channels_changed = false;
117                 update_channels();
118         }
119
120         update_info();
121 }
122
123 void XineStream::update_info()
124 {
125         const char *xt = xine_get_meta_info(stream, XINE_META_INFO_TITLE);
126         if((xt && title.compare(xt)) || (!xt && !title.empty()))
127         {
128                 MutexLock lock(mutex);
129                 title = (xt ? xt : string());
130                 signal_title_changed.emit(get_title());
131         }
132
133         int dur_msec, pos_msec;
134         xine_get_pos_length(stream, 0, &pos_msec, &dur_msec);
135         Time::TimeDelta dur = dur_msec*Time::msec;
136         Time::TimeDelta pos = pos_msec*Time::msec;
137         if(dur!=duration)
138         {
139                 MutexLock lock(mutex);
140                 duration = dur;
141                 signal_duration_changed.emit(duration);
142         }
143         if(pos!=position)
144         {
145                 MutexLock lock(mutex);
146                 position = pos;
147                 signal_position_changed.emit(position);
148         }
149
150         int audio = xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL);
151         if(audio==-1 && !audio_channels.empty())
152                 audio = 0;
153         else if(audio<0)
154                 audio = OFF;
155         if(audio!=current_audio)
156         {
157                 MutexLock lock(mutex);
158                 current_audio = audio;
159                 signal_current_audio_channel_changed.emit(current_audio);
160         }
161
162         int spu = xine_get_param(stream, XINE_PARAM_SPU_CHANNEL);
163         if(spu<0)
164                 spu = OFF;
165         if(spu!=current_spu)
166         {
167                 MutexLock lock(mutex);
168                 current_spu = spu;
169                 signal_current_spu_channel_changed.emit(current_spu);
170         }
171 }
172
173 void XineStream::update_channels()
174 {
175         MutexLock lock(mutex);
176         char langbuf[XINE_LANG_MAX];
177
178         unsigned n_audio = xine_get_stream_info(stream, XINE_STREAM_INFO_MAX_AUDIO_CHANNEL);
179         audio_channels.resize(n_audio);
180         for(unsigned i=0; i<n_audio; ++i)
181         {
182                 if(xine_get_audio_lang(stream, i, langbuf))
183                         audio_channels[i].assign(langbuf);
184                 else
185                         audio_channels[i].assign("unknown");
186         }
187
188         unsigned n_spu = xine_get_stream_info(stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL);
189         spu_channels.resize(n_spu);
190         for(unsigned i=0; i<n_spu; ++i)
191         {
192                 if(xine_get_spu_lang(stream, i, langbuf))
193                         spu_channels[i].assign(langbuf);
194                 else
195                         spu_channels[i].assign("unknown");
196         }
197
198         signal_channels_changed.emit();
199 }
200
201 void XineStream::handle_event(const xine_event_t &event)
202 {
203         switch(event.type)
204         {
205         case XINE_EVENT_UI_PLAYBACK_FINISHED:
206                 set_state(STOPPED);
207                 signal_finished.emit();
208                 break;
209         case XINE_EVENT_UI_CHANNELS_CHANGED:
210                 channels_changed = true;
211                 break;
212         }
213 }
214
215
216 void operator<<(LexicalConverter &conv, XineStream::State state)
217 {
218         switch(state)
219         {
220         case XineStream::STOPPED: conv.result("STOPPED"); return;
221         case XineStream::PAUSED: conv.result("PAUSED"); return;
222         case XineStream::PLAYING: conv.result("PLAYING"); return;
223         default: conv.result(format("State(%d)", static_cast<int>(state))); return;
224         }
225 }
226
227 void operator>>(const LexicalConverter &conv, XineStream::State &state)
228 {
229         const string &str = conv.get();
230         if(str=="STOPPED")
231                 state = XineStream::STOPPED;
232         else if(str=="PAUSED")
233                 state = XineStream::PAUSED;
234         else if(str=="PLAYING")
235                 state = XineStream::PLAYING;
236         else
237                 throw lexical_error(format("Conversion of '%s' to XineStream::State", str));
238 }