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