root/OpenSceneGraph/trunk/src/osgPlugins/quicktime/ReaderWriterQT.cpp @ 12697

Revision 12697, 18.0 kB (checked in by robert, 3 years ago)

From Alberto Luacas, typo fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include "osg/Image"
2#include "osg/Notify"
3
4#include <osg/Geode>
5
6#include <osg/observer_ptr>
7
8#include "osg/GL"
9
10#include "osgDB/FileNameUtils"
11#include "osgDB/Registry"
12#include "osgDB/FileUtils"
13
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <sstream>
18
19
20#ifndef __APPLE__
21#include "Components.h"
22#include "QuickTimeComponents.h"
23#else
24#include <QuickTime/QuickTime.h>
25#endif
26
27#ifndef SEEK_SET
28define SEEK_SET 0
29#endif
30#include "QTUtils.h"
31#include "QTLiveUtils.h"
32#include "QTImportExport.h"
33#include "QuicktimeImageStream.h"
34#include "QuicktimeLiveImageStream.h"
35
36
37using namespace osg;
38
39
40class ReaderWriterQT : public osgDB::ReaderWriter
41{
42public:
43
44
45    // This class is used as a helper to de-initialize
46    // properly quicktime, when the last media loaded
47    // with the quicktime plugin is released.
48    // All loaded media must be added to the observer
49    // (see ReaderWriterQT::readImage() function)
50    class QuicktimeInitializer : public osg::Observer
51    {
52    public:
53
54       QuicktimeInitializer ():
55          _instanceCount(0),
56             _setup(false)
57          {}
58
59          virtual ~QuicktimeInitializer()
60          {
61             // When we get here, the exit() function
62             // should have been called, when last media was released.
63             // In case no media has been added after initialization,
64             // let's perform an extra check
65             if (_setup && _instanceCount == 0)
66             {
67                exit();
68             }
69          };
70
71          void addMedia(Image* ptr)
72          {
73             ptr->addObserver(this);
74             ++ _instanceCount;
75          }
76
77          virtual void objectDeleted(void*)
78          {
79             -- _instanceCount;
80             if(_instanceCount== 0)
81                exit();
82          }
83
84          void init()
85          {
86             if (!_setup)
87             {
88                #ifndef __APPLE__
89                InitializeQTML(0);
90                #endif
91
92                OSErr err = EnterMovies();
93                if (err!=0)
94                {
95                   OSG_FATAL << "Error while initializing quicktime: " << err << std::endl;
96                }
97                else
98                {
99                   OSG_DEBUG << "Quicktime initialized successfully"  << std::endl;
100                }
101
102                _setup = true;
103             }
104          }
105
106          void exit()
107          {
108             #ifndef __APPLE__
109             ExitMovies();
110             #endif
111
112             _setup = false;
113          }
114
115    private:
116       unsigned int _instanceCount;
117       bool _setup;
118
119    };
120
121
122
123
124
125    ReaderWriterQT()
126    {
127
128       registerQtReader();
129
130
131        supportsExtension("mov","Movie format");
132        supportsExtension("mpg","Movie format");
133        supportsExtension("mpv","Movie format");
134        supportsExtension("mp4","Movie format");
135        supportsExtension("m4v","Movie format");
136        supportsExtension("dv","Movie format");
137        supportsExtension("avi","Movie format");
138        supportsExtension("sdp","RTSP Movie format");
139        supportsExtension("flv","Movie format");
140        supportsExtension("swf","Movie format");
141        supportsExtension("3gp","Mobile movie format");
142
143        supportsExtension("live","Live video streaming");
144       
145        supportsProtocol("http", "streaming media per http");
146        supportsProtocol("rtsp", "streaming media per rtsp");
147
148        #ifdef QT_HANDLE_IMAGES_ALSO
149        supportsExtension("jpg","jpg image format");
150        supportsExtension("jpeg","jpeg image format");
151        supportsExtension("tif","tif image format");
152        supportsExtension("tiff","tiff image format");
153        supportsExtension("gif","gif image format");
154        supportsExtension("png","png image format");
155        supportsExtension("pict","pict image format");
156        supportsExtension("pct","pct image format");
157        supportsExtension("tga","tga image format");
158        supportsExtension("psd","psd image format");
159        #endif
160    }
161
162    ~ReaderWriterQT()
163    {
164    }
165
166
167   virtual const char* className() const { return "Default Quicktime Image Reader/Writer"; }
168
169   virtual bool acceptsMovieExtension(const std::string& extension) const
170   {
171      return osgDB::equalCaseInsensitive(extension,"mov") ||
172         osgDB::equalCaseInsensitive(extension,"mpg") ||
173         osgDB::equalCaseInsensitive(extension,"mpv") ||
174         osgDB::equalCaseInsensitive(extension,"mp4") ||
175         osgDB::equalCaseInsensitive(extension,"m4v") ||
176         osgDB::equalCaseInsensitive(extension,"dv")  ||
177         osgDB::equalCaseInsensitive(extension,"avi") ||
178         osgDB::equalCaseInsensitive(extension,"sdp") ||
179         osgDB::equalCaseInsensitive(extension,"flv") ||
180         osgDB::equalCaseInsensitive(extension,"swf") ||
181         osgDB::equalCaseInsensitive(extension,"3gp");
182   }
183
184   virtual bool acceptsLiveExtension(const std::string& extension) const
185   {
186       return osgDB::equalCaseInsensitive(extension,"live");     
187   }
188
189   virtual bool acceptsExtension(const std::string& extension) const
190   {
191      // this should be the only image importer required on the Mac
192      // dont know what else it supports, but these will do
193      return
194
195         #ifdef QT_HANDLE_IMAGES_ALSO
196         osgDB::equalCaseInsensitive(extension,"jpg") ||
197         osgDB::equalCaseInsensitive(extension,"jpeg") ||
198         osgDB::equalCaseInsensitive(extension,"tif") ||               
199         osgDB::equalCaseInsensitive(extension,"tiff") ||
200         osgDB::equalCaseInsensitive(extension,"gif") ||
201         osgDB::equalCaseInsensitive(extension,"png") ||
202         osgDB::equalCaseInsensitive(extension,"pict") ||
203         osgDB::equalCaseInsensitive(extension,"pct") ||
204         osgDB::equalCaseInsensitive(extension,"tga") ||
205         osgDB::equalCaseInsensitive(extension,"psd") ||
206         #endif
207
208         acceptsMovieExtension(extension) ||
209         acceptsLiveExtension(extension);
210   }
211
212   virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const
213   {
214      std::string ext = osgDB::getLowerCaseFileExtension(file);
215      if (osgDB::equalCaseInsensitive(ext,"qt"))
216      {
217         return readImage(osgDB::getNameLessExtension(file),options);
218      }
219     
220      if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
221
222      // if the file is a ".live" video encoded string then load as an ImageStream
223      if (acceptsLiveExtension(ext))
224      {
225          long num_video_components;
226          {
227              // Begin QuickTime
228              QTScopedQTMLInitialiser  qt_init;
229              QTScopedMovieInitialiser qt_movie_init;
230              //
231              ComponentDescription video_component_description;
232              video_component_description.componentType         = 'vdig';  /* A unique 4-byte code indentifying the command set */
233              video_component_description.componentSubType      = 0L;      /* Particular flavor of this instance */
234              video_component_description.componentManufacturer = 0L;      /* Vendor indentification */
235              video_component_description.componentFlags        = 0L;      /* 8 each for Component,Type,SubType,Manuf/revision */
236              video_component_description.componentFlagsMask    = 0L;      /* Mask for specifying which flags to consider in search, zero during registration */
237              num_video_components = CountComponents (&video_component_description);
238          }
239          if (osgDB::getNameLessExtension(file) == "devices")
240          {
241              OSG_ALWAYS << " available Video DigitizerComponents : " << num_video_components << std::endl;
242              if (num_video_components)
243              {
244                  // Probe Video Dig
245                  probe_video_digitizer_components();
246                  // Probe SG
247                  std::vector<OSG_SGDeviceList> devices_list = probe_sequence_grabber_components();
248                  if (devices_list.size())
249                  {
250                      // Video
251                      OSG_SGDeviceList& video_device_list = devices_list[0];
252                      // Print
253                      OSG_ALWAYS << std::endl;
254                      OSG_ALWAYS << "Video Component/Input IDs follow: " << std::endl;
255                      OSG_ALWAYS << std::endl;
256                      for (unsigned int device_input = 0; device_input < video_device_list.size(); ++device_input)
257                      {
258                          OSG_SGDevicePair device_pair = video_device_list[device_input];
259                          OSG_ALWAYS << device_pair.first.c_str() << "    " << device_pair.second.c_str() << std::endl;
260                      }
261                  }
262                  if (devices_list.size() > 1)
263                  {
264                      // Audio
265                      OSG_SGDeviceList& audio_device_list = devices_list[1];
266                      // Print
267                      OSG_ALWAYS << std::endl;
268                      OSG_ALWAYS << "Audio Component/Input IDs follow: " << std::endl;
269                      OSG_ALWAYS << std::endl;
270                      for (unsigned int device_input = 0; device_input < audio_device_list.size(); ++device_input)
271                      {
272                          OSG_SGDevicePair device_pair = audio_device_list[device_input];
273                          OSG_ALWAYS << device_pair.first.c_str() << "    " << device_pair.second.c_str() << std::endl;
274                      }
275                  }
276              }
277              return ReadResult::FILE_NOT_HANDLED;
278          }
279          else
280          {
281              OSG_DEBUG << " available Video DigitizerComponents : " << num_video_components << std::endl;
282              if (num_video_components)
283              {
284                  // Note from Riccardo Corsi
285                  // Quicktime initialization is done here, when a media is found
286                  // and before any image or movie is loaded.
287                  // After the first call the function does nothing.
288                  // The cleaning up is left to the QuicktimeInitializer (see below)
289                  _qtExitObserver.init();
290
291                  //
292                  QuicktimeLiveImageStream* p_qt_image_stream = new QuicktimeLiveImageStream(osgDB::getNameLessExtension(file));
293                  // add the media to the observer for proper clean up on exit
294                  _qtExitObserver.addMedia(p_qt_image_stream);
295                  return p_qt_image_stream;
296              }
297              else
298              {
299                  OSG_DEBUG << "No available Video DigitizerComponents : " <<  std::endl;
300                  return ReadResult::FILE_NOT_HANDLED;
301              }
302          }
303      }
304
305      // Not an encoded "live" psuedo file - so check a real file exists
306      // only find the file if it isn't a URL
307      std::string fileName = file;
308     
309     
310      // Note from Riccardo Corsi
311      // Quicktime initialization is done here, when a media is found
312      // and before any image or movie is loaded.
313      // After the first call the function does nothing.
314      // The cleaning up is left to the QuicktimeInitializer (see below)
315      _qtExitObserver.init();
316
317
318      // if the file is a movie file then load as an ImageStream.
319      if (acceptsMovieExtension(ext))
320      {
321         // quicktime supports playing movies from URLs
322         if (!osgDB::containsServerAddress(fileName)) {
323             fileName = osgDB::findDataFile( file,  options);
324            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
325         }
326         
327         // note from Robert Osfield when integrating, we should probably have so
328         // error handling mechanism here.  Possibly move the load from
329         // the constructor to a separate load method, and have a valid
330         // state on the ImageStream... will integrated as is right now
331         // to get things off the ground.
332         QuicktimeImageStream* moov = new QuicktimeImageStream(fileName);
333         // moov->play();
334
335         // add the media to the observer for proper clean up on exit
336         _qtExitObserver.addMedia(moov);
337
338         return moov;
339      }
340       
341       
342        // no live-video, no movie-file, so try to load as an image
343       
344        fileName = osgDB::findDataFile( file,  options);
345        if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
346           
347        QuicktimeImportExport importer;
348
349        osgDB::ifstream is;
350        is.open (fileName.c_str(), std::ios::binary | std::ios::in );
351        is.seekg (0, std::ios::end);
352        long length = is.tellg();
353        is.seekg (0, std::ios::beg);
354
355        osg::ref_ptr<osg::Image> image = importer.readFromStream(is, fileName, length);
356        is.close();
357        if (!importer.success() || (image == NULL)) {
358            OSG_WARN << "Error reading file " << file << " : " << importer.getLastErrorString() << std::endl;
359            return ReadResult::ERROR_IN_READING_FILE;
360        }
361
362      _qtExitObserver.addMedia(image.get());
363
364      return image.release();
365   }
366   
367    virtual ReadResult readImage (std::istream& is, const osgDB::ReaderWriter::Options* options=NULL) const 
368    {
369        std::string filename = "";
370        long sizeHint(0);
371        // check options for a file-type-hint
372        if (options) {
373            std::istringstream iss(options->getOptionString());
374            std::string opt;
375            while (iss >> opt)
376            {
377                int index = opt.find( "=" );
378                if( opt.substr( 0, index ) == "filename" ||
379                    opt.substr( 0, index ) == "FILENAME" )
380                {
381                    filename = opt.substr( index+1 );
382                } else if( opt.substr( 0, index ) == "size" ||
383                    opt.substr( 0, index ) == "SIZE" )
384                {
385                    std::string sizestr = opt.substr( index+1 );
386                    sizeHint = atol(sizestr.c_str());
387                }
388            }
389        }
390
391        _qtExitObserver.init();
392       
393        QuicktimeImportExport importer;
394        osg::ref_ptr<osg::Image> image = importer.readFromStream(is, filename, sizeHint);
395       
396        if (!importer.success() || (image == NULL)) {
397            OSG_WARN << "Error reading from stream "  << importer.getLastErrorString() << std::endl;
398            return ReadResult::ERROR_IN_READING_FILE;
399        }
400        _qtExitObserver.addMedia(image.get());
401        return image.release();
402       
403    }
404
405    virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options*) const
406    {
407        std::string ext = osgDB::getFileExtension(fileName);
408        if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
409
410        _qtExitObserver.init();
411
412        //Buidl map  of extension <-> osFileTypes
413        std::map<std::string, OSType> extmap;
414
415        extmap.insert(std::pair<std::string, OSType>("jpg",  kQTFileTypeJPEG));
416        extmap.insert(std::pair<std::string, OSType>("jpeg", kQTFileTypeJPEG));
417        extmap.insert(std::pair<std::string, OSType>("bmp",  kQTFileTypeBMP));
418        extmap.insert(std::pair<std::string, OSType>("tif",  kQTFileTypeTIFF));
419        extmap.insert(std::pair<std::string, OSType>("tiff", kQTFileTypeTIFF));
420        extmap.insert(std::pair<std::string, OSType>("png",  kQTFileTypePNG));
421        extmap.insert(std::pair<std::string, OSType>("gif",  kQTFileTypeGIF));
422        extmap.insert(std::pair<std::string, OSType>("psd",  kQTFileTypePhotoShop));
423        extmap.insert(std::pair<std::string, OSType>("sgi",  kQTFileTypeSGIImage));
424       
425        std::map<std::string, OSType>::iterator cur = extmap.find(ext);
426
427        // can not handle this type of file, perhaps a movie?
428        if (cur == extmap.end())
429         return WriteResult::FILE_NOT_HANDLED;
430
431        osgDB::ofstream os(fileName.c_str(), std::ios::binary | std::ios::trunc | std::ios::out);
432        if(os.good())
433        {
434            QuicktimeImportExport exporter;
435            exporter.writeToStream(os, const_cast<osg::Image*>(&img), fileName);
436           
437            if (exporter.success())
438                return WriteResult::FILE_SAVED;
439        }
440
441        return WriteResult::ERROR_IN_WRITING_FILE;
442    }
443   
444    virtual WriteResult writeImage (const osg::Image& img, std::ostream& os, const Options* options=NULL) const
445    {
446        std::string filename = "file.jpg"; // use jpeg if not otherwise specified
447       
448        if (options) {
449            std::istringstream iss(options->getOptionString());
450            std::string opt;
451            while (iss >> opt)
452            {
453                int index = opt.find( "=" );
454                if( opt.substr( 0, index ) == "filename" ||
455                    opt.substr( 0, index ) == "FILENAME" )
456                {
457                    filename = opt.substr( index+1 );
458                }
459            }
460        }
461       
462        _qtExitObserver.init();
463
464        QuicktimeImportExport exporter;
465        exporter.writeToStream(os, const_cast<osg::Image*>(&img), filename);
466           
467        if (exporter.success())
468            return WriteResult::FILE_SAVED;
469       
470        return WriteResult::ERROR_IN_WRITING_FILE;         
471    }
472
473protected:
474
475   //internal utils
476   void registerQtReader() const
477   {
478      osgDB::Registry* r = osgDB::Registry::instance();
479      r->addFileExtensionAlias("mov""qt");
480
481      #ifdef QT_HANDLE_IMAGES_ALSO
482      r->addFileExtensionAlias("jpg""qt");
483      r->addFileExtensionAlias("jpe""qt");
484      r->addFileExtensionAlias("jpeg", "qt");
485      r->addFileExtensionAlias("tif""qt");
486      r->addFileExtensionAlias("tiff", "qt");
487      r->addFileExtensionAlias("gif""qt");
488      r->addFileExtensionAlias("png""qt");
489      r->addFileExtensionAlias("psd""qt");
490      r->addFileExtensionAlias("tga""qt");
491      r->addFileExtensionAlias("mov""qt");
492      r->addFileExtensionAlias("avi""qt");
493      r->addFileExtensionAlias("mpg""qt");
494      r->addFileExtensionAlias("mpv""qt");
495      r->addFileExtensionAlias("dv",   "qt");
496      r->addFileExtensionAlias("mp4""qt");
497      r->addFileExtensionAlias("m4v""qt");         
498      #endif
499   }
500
501    mutable QuicktimeInitializer _qtExitObserver;
502};
503
504// now register with Registry to instantiate the above
505// reader/writer.
506REGISTER_OSGPLUGIN(quicktime, ReaderWriterQT)
Note: See TracBrowser for help on using the browser.