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