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

Revision 9932, 18.2 kB (checked in by robert, 6 years ago)

From Stephan Huber, clean up of Quicktime plugin

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