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

Revision 9769, 17.5 kB (checked in by robert, 5 years ago)

From Riccardo Corsi, "in attach you'll find a patch to cleanup a little bit the (de)initialization code of QuickTime? environment from the quickTime pluging.
It basically removes the static init() and exit() functions,and move them inside the observer class (the one that cleans everything up when the last media is unloaded).

It also add an extra check to clean up on exit if the QuickTime? env is initialized, but no media is succesfully loaded / written (it might happens with streaming resources).

I tested it under WinXP with zero, one and multiple videos.

Stephan reads in copy: could you kindly check if everything runs smooth under OSX as well? Also, have you got a chance to test it with streaming media?
"

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