1 // (C) Robert Osfield, Feb 2004.
2 // GPL'd.
3 
4 #include <osg/ImageStream>
5 #include <osg/Notify>
6 #include <osg/Geode>
7 #include <osg/GL>
8 #include <osg/Timer>
9 
10 #include <osgDB/Registry>
11 #include <osgDB/FileNameUtils>
12 #include <osgDB/FileUtils>
13 
14 #include <xine.h>
15 #include <xine/xineutils.h>
16 #include <xine/video_out.h>
17 
18 #include "video_out_rgb.h"
19 
20 namespace osgXine
21 {
22 
23 class XineImageStream : public osg::ImageStream
24 {
25     public:
26         XineImageStream():
27             _xine(0),
28             _vo(0),
29             _ao(0),
30             _visual(0),
31             _stream(0),
32             _event_queue(0),
33             _ready(false),
34             _volume(-1.0)
35         {
36             setOrigin(osg::Image::TOP_LEFT);
37         }
38 
39         /** Copy constructor using CopyOp to manage deep vs shallow copy. */
40         XineImageStream(const XineImageStream& image,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
41             ImageStream(image,copyop) {}
42 
43         META_Object(osgXine,XineImageStream);
normalize__anon3687b70d010844 
45         void setVolume(float volume)
46         {
47             _volume = osg::minimum(osg::maximum(volume,0.0f),1.0f);
48             if (_stream)
49             {
50                 xine_set_param(_stream, XINE_PARAM_AUDIO_VOLUME, static_cast<int>(_volume*100.0f));
51                 OSG_NOTICE<<"Setting volume "<<_volume<<std::endl;
52             }
53         }
54 
55         float getVolume() const
56         {
57             return _volume;
58         }
59 
60         bool open(xine_t* xine, const std::string& filename)
61         {
62             if (filename==getFileName()) return true;
63 
64             _xine = xine;
65 
66             // create visual
67             rgbout_visual_info_t* visual = new rgbout_visual_info_t;
68             visual->levels = PXLEVEL_ALL;
69             visual->format = PX_RGB32;
70             visual->user_data = this;
71             visual->callback = my_render_frame;
72 
73             // set up video driver
74             _vo = xine_open_video_driver(_xine, "rgb", XINE_VISUAL_TYPE_RGBOUT, (void*)visual);
75 
76             // set up audio driver
77             char* audio_driver = getenv("OSG_XINE_AUDIO_DRIVER");
78             _ao = audio_driver ? xine_open_audio_driver(_xine, audio_driver, NULL) : xine_open_audio_driver(_xine, "auto", NULL);
79 
80             if (!_vo)
81             {
82                 OSG_NOTICE<<"XineImageStream::open() : Failed to create video driver"<<std::endl;
83                 return false;
84             }
85 
86 
87             // set up stream
88             _stream = xine_stream_new(_xine, _ao, _vo);
89 
90             if (_stream)
91             {
92                 if (_volume < 0.0)
93                 {
94                     _volume = static_cast<float>(xine_get_param(_stream, XINE_PARAM_AUDIO_VOLUME))/100.0f;
95                 }
96                 else
97                 {
98                     setVolume(_volume);
99                 }
100             }
101 
102             _event_queue = xine_event_new_queue(_stream);
103             xine_event_create_listener_thread(_event_queue, event_listener, this);
104 
105             int result = xine_open(_stream, filename.c_str());
106 
107             if (result==0)
108             {
109                 OSG_INFO<<"XineImageStream::open() : Could not ready movie file."<<std::endl;
110                 close();
111                 return false;
112             }
113 
114 
115             _ready = false;
116 
117             int width = xine_get_stream_info(_stream,XINE_STREAM_INFO_VIDEO_WIDTH);
118             int height = xine_get_stream_info(_stream,XINE_STREAM_INFO_VIDEO_HEIGHT);
119             allocateImage(width,height,1,GL_RGB,GL_UNSIGNED_BYTE,1);
120 
121             OSG_INFO<<"XineImageStream::open() size "<<width<<" "<<height<<std::endl;
122 
123             // play();
124 
125             return true;
126 
127         }
128 
129         virtual void play()
130         {
131             if (_status!=PLAYING && _stream)
132             {
133                 if (_status==PAUSED)
134                 {
135                     xine_set_param (_stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
136                     _status=PLAYING;
137                 }
138                 else
139                 {
140                     OSG_INFO<<"XineImageStream::play()"<<std::endl;
141                     if (xine_play(_stream, 0, 0))
142                     {
143                         while (!_ready)
144                         {
145                             OSG_INFO<<"   waiting..."<<std::endl;
146                             OpenThreads::Thread::microSleep(10000);
147                         }
148 
149                         _status=PLAYING;
150 
151                     }
152                     else
153                     {
154                         OSG_NOTICE<<"Error!!!"<<std::endl;
155                     }
156                 }
157             }
158         }
159 
160         virtual void pause()
161         {
162             if (_status==PAUSED || _status==INVALID) return;
163 
164             _status=PAUSED;
165 
166             if (_stream)
167             {
168                 xine_set_param (_stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
169             }
170         }
171 
172         virtual void rewind()
173         {
174             if (_status==INVALID) return;
175 
176             _status=REWINDING;
177             if (_stream)
178             {
179                 OSG_INFO<<"Warning::XineImageStream::rewind() - rewind disabled at present."<<std::endl;
180                 //xine_trick_mode(_stream,XINE_TRICK_MODE_FAST_REWIND,0);
181             }
182         }
183 
184         virtual void quit(bool /*waitForThreadToExit*/ = true)
185         {
186             close();
187         }
188 
189         static void my_render_frame(uint32_t width, uint32_t height, void* data, void* userData)
190         {
191             XineImageStream* imageStream = (XineImageStream*) userData;
192 
193             GLenum pixelFormat = GL_BGRA;
194 
195             imageStream->setImage(width,height,1,
196                               GL_RGB,
197                               pixelFormat,GL_UNSIGNED_BYTE,
198                               (unsigned char *)data,
199                               osg::Image::NO_DELETE,
200                               1);
201 
202             imageStream->_ready = true;
203         }
204 
205 
206         xine_t*                 _xine;
207 
208         xine_video_port_t*      _vo;
209         xine_audio_port_t*      _ao;
210 
211         rgbout_visual_info_t*   _visual;
212         xine_stream_t*          _stream;
213         xine_event_queue_t*     _event_queue;
214         bool                    _ready;
215         float                   _volume;
216 
217     protected:
218 
219 
220         virtual ~XineImageStream()
221         {
222             OSG_INFO<<"Killing XineImageStream"<<std::endl;
223             close();
224             OSG_INFO<<"Closed XineImageStream"<<std::endl;
225         }
226 
227         void close()
228         {
229 
230             OSG_INFO<<"XineImageStream::close()"<<std::endl;
231 
232             if (_stream)
233             {
234                   OSG_INFO<<"  Closing stream"<<std::endl;
235 
236                   xine_close(_stream);
237 
238                   OSG_INFO<<"  Disposing stream"<<std::endl;
239 
240                   xine_dispose(_stream);
241                   _stream = 0;
242             }
243 
244 
245             if (_event_queue)
246             {
247                 _event_queue = 0;
248             }
249 
250             if (_ao)
251             {
252                OSG_INFO<<"  Closing audio driver"<<std::endl;
253 
254                 xine_close_audio_driver(_xine, _ao);
255 
256                 _ao = 0;
257             }
258 
259             if (_vo)
260             {
261                OSG_INFO<<"  Closing video driver"<<std::endl;
262 
263                 xine_close_video_driver(_xine, _vo);
264 
265                 _vo = 0;
266             }
267 
268            OSG_INFO<<"closed XineImageStream "<<std::endl;
269 
270         }
271 
272 
273         static void event_listener(void *user_data, const xine_event_t *event)
274         {
275             XineImageStream* xis = reinterpret_cast<XineImageStream*>(user_data);
276             switch(event->type)
277             {
278             case XINE_EVENT_UI_PLAYBACK_FINISHED:
279                 if (xis->getLoopingMode()==LOOPING)
280                 {
281                     //rewind();
282                     xine_play(xis->_stream, 0, 0);
283                 }
284                 break;
285             }
286         }
287 
288 };
289 
290 }
291 
292 class ReaderWriterXine : public osgDB::ReaderWriter
293 {
294     public:
295 
296         ReaderWriterXine()
297         {
298             supportsExtension("avi","");
299             supportsExtension("db","");
300             supportsExtension("ogv","");
301             supportsExtension("flv","");
302             supportsExtension("mov","");
303             supportsExtension("m4v","");
304             supportsExtension("mpg","Mpeg movie format");
305             supportsExtension("mpv","Mpeg movie format");
306             supportsExtension("wmv","");
307             supportsExtension("xine","Xine plugin Pseduo plugin");
308 
309             _xine = xine_new();
310 
311             const char* user_home = xine_get_homedir();
312             if(user_home)
313             {
314                 std::string configFile(std::string(user_home)+"/.xine/config");
315                 xine_config_load(_xine, configFile.c_str());
316             }
317 
318             xine_init(_xine);
319 
320             register_rgbout_plugin(_xine);
321         }
322 
323         virtual ~ReaderWriterXine()
324         {
325             OSG_INFO<<"~ReaderWriterXine()"<<std::endl;
326 
327             if (_xine) xine_exit(_xine);
328             _xine = NULL;
329         }
330 
331         virtual const char* className() const { return "Xine ImageStream Reader"; }
332 
333         virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const
334         {
335             std::string ext = osgDB::getLowerCaseFileExtension(file);
336             if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
337 
338             std::string fileName;
339             if (ext=="xine")
340             {
341                 fileName = osgDB::findDataFile( osgDB::getNameLessExtension(file), options);
342                 OSG_INFO<<"Xine stipped filename = "<<fileName<<std::endl;
343             }
344             else
345             {
346                 fileName = osgDB::findDataFile( file, options );
347                 if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
348             }
349 
350             OSG_INFO<<"ReaderWriterXine::readImage "<< file<< std::endl;
351 
352             osg::ref_ptr<osgXine::XineImageStream> imageStream = new osgXine::XineImageStream();
353 
354             if (!imageStream->open(_xine, fileName)) return ReadResult::FILE_NOT_HANDLED;
355 
356             return imageStream.release();
357         }
358 
359     protected:
360         xine_t*             _xine;
361 
362 
363 };
364 
365 // now register with Registry to instantiate the above
366 // reader/writer.
367 REGISTER_OSGPLUGIN(xine, ReaderWriterXine)
368