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