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

Revision 8972, 15.2 kB (checked in by robert, 6 years ago)

From Tatsuhiro Nishioka, submissions posted by Stephan Huber, "attached you'll find a modified ReaderWriterQT.cpp-file where I removed the support for rgb(a)-files.
Quicktime supports only files with 3/4-channels rgba-files and not 1/2-channels rgb-files.

This submission is from Tatsuhiro Nishioka, here's his original quote:

When FlightGear? crashes, the error message
"GraphicsImportGetNaturalBounds? failed" shows up. By adding printf
debug, I found the error was -8969: codecBadDataErr when loading a
gray-scaled (2 channels) rgba files even though the file can be loaded
with Gimp and osgViewer properly.

So I made an investigation on this problem and found an interesting
thing. This error occurs only when non-rgb files are loaded before rgb
files. The reason is that rgba files can be handled by both
osgdb_rgb.so and osgdb_qt.so, but the error happens only when
osgdb_qt.so try to load a gray-scaled rgba file.

When a program is about to load an rgba file, osgdb_rgb.so is loaded
and it handles the rgba file properly. In contrast, when a gray-scaled
rgb file is being loaded after a non-rgb file (say png) is already
loaded by osgdb_qt.so, osgdb_qt.so tries to load the file instead of
osgdb_rgb, which causes the error above.

Anyway, the bad thing is that QuickTime? cannot handle gray-scaled rgb
files properly. The solution for this is not to let osgdb_qt handle
rgb files since osgdb_rgb can handle these properly.

"

  • 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
[5981]39// This class is used as a helper to de-initialize
40// properly quicktime, when the last media loaded
41// with the quicktime plugin is released.
42// All loaded media must be added to the observer
43// (see ReaderWriterQT::readImage() function)
44class QuicktimeExitObserver : public osg::Observer
45{
46public:
[4002]47
[7586]48   QuicktimeExitObserver () : _instanceCount(0)
49   {
50   }
51   virtual ~QuicktimeExitObserver()
52   {
53   };
[4002]54
[5981]55   void addMedia(Image* ptr)
56   {
57      ptr->addObserver(this);
58      ++ _instanceCount;
59   }
60   
61   virtual void objectDeleted(void*)
62   {
63      -- _instanceCount;
64      if(_instanceCount== 0)
65         exitQuicktime();
66   }
67
68private:
69   unsigned int _instanceCount;
70};
71
72
73
[292]74class ReaderWriterQT : public osgDB::ReaderWriter
75{
[5799]76public:
[7586]77    ReaderWriterQT::ReaderWriterQT()
78    {
[8578]79        supportsExtension("mov","Movie format");
80        supportsExtension("mpg","Movie format");
81        supportsExtension("mpv","Movie format");
82        supportsExtension("mp4","Movie format");
83        supportsExtension("m4v","Movie format");
84        supportsExtension("dv","Movie format");
85        supportsExtension("avi","Movie format");
86        supportsExtension("flv","Movie format");
87        supportsExtension("swf","Movie format");
[8933]88        supportsExtension("3gp","Mobile movie format");
[8578]89
90        supportsExtension("live","Live video streaming");
91
92        #ifdef QT_HANDLE_IMAGES_ALSO
93        supportsExtension("jpg","jpg image format");
94        supportsExtension("jpeg","jpeg image format");
95        supportsExtension("tif","tif image format");
96        supportsExtension("tiff","tiff image format");
97        supportsExtension("gif","gif image format");
98        supportsExtension("png","png image format");
99        supportsExtension("pict","pict image format");
100        supportsExtension("pct","pct image format");
101        supportsExtension("tga","tga image format");
102        supportsExtension("psd","psd image format");
103        #endif
[7586]104    }
[8578]105
[7586]106    ReaderWriterQT::~ReaderWriterQT()
107    {
108    }
109
110
[5799]111   virtual const char* className() const { return "Default Quicktime Image Reader/Writer"; }
[292]112
[5799]113   virtual bool acceptsMovieExtension(const std::string& extension) const
114   {
115      return osgDB::equalCaseInsensitive(extension,"mov") ||
116         osgDB::equalCaseInsensitive(extension,"mpg") ||
117         osgDB::equalCaseInsensitive(extension,"mpv") ||
118         osgDB::equalCaseInsensitive(extension,"mp4") ||
119         osgDB::equalCaseInsensitive(extension,"m4v") ||
120         osgDB::equalCaseInsensitive(extension,"dv")  ||
121         osgDB::equalCaseInsensitive(extension,"avi") ||
[7571]122         osgDB::equalCaseInsensitive(extension,"flv") ||
[8933]123         osgDB::equalCaseInsensitive(extension,"swf") ||
124         osgDB::equalCaseInsensitive(extension,"3gp");
[5799]125   }
[2501]126
[7586]127   virtual bool acceptsLiveExtension(const std::string& extension) const
128   {
129       return osgDB::equalCaseInsensitive(extension,"live");     
130   }
131
[5799]132   virtual bool acceptsExtension(const std::string& extension) const
133   {
134      // this should be the only image importer required on the Mac
135      // dont know what else it supports, but these will do
[5981]136      return
137
138         #ifdef QT_HANDLE_IMAGES_ALSO
[5799]139         osgDB::equalCaseInsensitive(extension,"jpg") ||
140         osgDB::equalCaseInsensitive(extension,"jpeg") ||
141         osgDB::equalCaseInsensitive(extension,"tif") ||               
142         osgDB::equalCaseInsensitive(extension,"tiff") ||
143         osgDB::equalCaseInsensitive(extension,"gif") ||
144         osgDB::equalCaseInsensitive(extension,"png") ||
145         osgDB::equalCaseInsensitive(extension,"pict") ||
146         osgDB::equalCaseInsensitive(extension,"pct") ||
147         osgDB::equalCaseInsensitive(extension,"tga") ||
[5981]148         osgDB::equalCaseInsensitive(extension,"psd") ||
149         #endif
150
[7586]151         acceptsMovieExtension(extension) ||
152         acceptsLiveExtension(extension);
[5799]153   }
154
[5981]155   virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const
156   {
[5799]157      std::string ext = osgDB::getLowerCaseFileExtension(file);
[7363]158      if (osgDB::equalCaseInsensitive(ext,"qt"))
159      {
160         return readImage(osgDB::getNameLessExtension(file),options);
161      }
162     
[5799]163      if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
164
[7586]165      // if the file is a ".live" video encoded string then load as an ImageStream
166      if (acceptsLiveExtension(ext))
167      {
168          long num_video_components;
169          {
170              // Begin QuickTime
171              QTScopedQTMLInitialiser  qt_init;
172              QTScopedMovieInitialiser qt_movie_init;
173              //
174              ComponentDescription video_component_description;
175              video_component_description.componentType         = 'vdig';  /* A unique 4-byte code indentifying the command set */
176              video_component_description.componentSubType      = 0L;      /* Particular flavor of this instance */
177              video_component_description.componentManufacturer = 0L;      /* Vendor indentification */
178              video_component_description.componentFlags        = 0L;      /* 8 each for Component,Type,SubType,Manuf/revision */
179              video_component_description.componentFlagsMask    = 0L;      /* Mask for specifying which flags to consider in search, zero during registration */
180              num_video_components = CountComponents (&video_component_description);
181          }
182          if (osgDB::getNameLessExtension(file) == "devices")
183          {
184              osg::notify(osg::ALWAYS) << " available Video DigitizerComponents : " << num_video_components << std::endl;
185              if (num_video_components)
186              {
187                  // Probe Video Dig
188                  probe_video_digitizer_components();
189                  // Probe SG
190                  std::vector<OSG_SGDeviceList> devices_list = probe_sequence_grabber_components();
191                  if (devices_list.size())
192                  {
193                      // Video
194                      OSG_SGDeviceList& video_device_list = devices_list[0];
195                      // Print
196                      osg::notify(osg::ALWAYS) << std::endl;
197                      osg::notify(osg::ALWAYS) << "Video Component/Input IDs follow: " << std::endl;
198                      osg::notify(osg::ALWAYS) << std::endl;
[8132]199                      for (unsigned int device_input = 0; device_input < video_device_list.size(); ++device_input)
[7586]200                      {
201                          OSG_SGDevicePair device_pair = video_device_list[device_input];
202                          osg::notify(osg::ALWAYS) << device_pair.first.c_str() << "    " << device_pair.second.c_str() << std::endl;
203                      }
204                  }
205                  if (devices_list.size() > 1)
206                  {
207                      // Audio
208                      OSG_SGDeviceList& audio_device_list = devices_list[1];
209                      // Print
210                      osg::notify(osg::ALWAYS) << std::endl;
211                      osg::notify(osg::ALWAYS) << "Audio Component/Input IDs follow: " << std::endl;
212                      osg::notify(osg::ALWAYS) << std::endl;
[8132]213                      for (unsigned int device_input = 0; device_input < audio_device_list.size(); ++device_input)
[7586]214                      {
215                          OSG_SGDevicePair device_pair = audio_device_list[device_input];
216                          osg::notify(osg::ALWAYS) << device_pair.first.c_str() << "    " << device_pair.second.c_str() << std::endl;
217                      }
218                  }
219              }
220              return ReadResult::FILE_NOT_HANDLED;
221          }
222          else
223          {
224              osg::notify(osg::DEBUG_INFO) << " available Video DigitizerComponents : " << num_video_components << std::endl;
225              if (num_video_components)
226              {
227                  // Note from Riccardo Corsi
228                  // Quicktime initialization is done here, when a media is found
229                  // and before any image or movie is loaded.
230                  // After the first call the function does nothing.
231                  // The cleaning up is left to the QuicktimeExitObserver (see below)
232                  initQuicktime();
233                  //
234                  QuicktimeLiveImageStream* p_qt_image_stream = new QuicktimeLiveImageStream(osgDB::getNameLessExtension(file));
235                  // add the media to the observer for proper clean up on exit
236                  _qtExitObserver.addMedia(p_qt_image_stream);
237                  return p_qt_image_stream;
238              }
239              else
240              {
241                  osg::notify(osg::DEBUG_INFO) << "No available Video DigitizerComponents : " <<  std::endl;
242                  return ReadResult::FILE_NOT_HANDLED;
243              }
244          }
245      }
246
247      // Not an encoded "live" psuedo file - so check a real file exists
[5981]248      std::string fileName = osgDB::findDataFile( file,  options);
[5799]249      if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
250
[5981]251      // Note from Riccardo Corsi
252      // Quicktime initialization is done here, when a media is found
253      // and before any image or movie is loaded.
254      // After the first call the function does nothing.
255      // The cleaning up is left to the QuicktimeExitObserver (see below)
256      initQuicktime();
257
[7586]258
[5799]259      // if the file is a movie file then load as an ImageStream.
260      if (acceptsMovieExtension(ext))
261      {
262         // note from Robert Osfield when integrating, we should probably have so
263         // error handling mechanism here.  Possibly move the load from
264         // the constructor to a seperate load method, and have a valid
265         // state on the ImageStream... will integrated as is right now
266         // to get things off the ground.
267         QuicktimeImageStream* moov = new QuicktimeImageStream(fileName);
268         // moov->play();
[5981]269
270         // add the media to the observer for proper clean up on exit
271         _qtExitObserver.addMedia(moov);
272
[5799]273         return moov;
274      }
[5981]275 
[8132]276        QuicktimeImportExport importer;
[5799]277
[8132]278        std::ifstream is;
279        is.open (fileName.c_str(), std::ios::binary | std::ios::in );
280        is.seekg (0, std::ios::end);
281        long length = is.tellg();
282        is.seekg (0, std::ios::beg);
[5799]283
[8132]284        osg::ref_ptr<osg::Image> image = importer.readFromStream(is, fileName, length);
285        is.close();
286        if (!importer.success() || (image == NULL)) {
287            osg::notify(osg::WARN) << "Error reading file " << file << " : " << importer.getLastErrorString() << std::endl;
288            return ReadResult::ERROR_IN_READING_FILE;
289        }
[5799]290
[8132]291      _qtExitObserver.addMedia(image.get());
[5799]292
[8132]293      return image.release();
294   }
295   
296    virtual ReadResult readImage (std::istream& is, const osgDB::ReaderWriter::Options* options=NULL) const 
297    {
298        std::string filename = "";
299        long sizeHint(0);
300        // check options for a file-type-hint
301        if (options) {
302            std::istringstream iss(options->getOptionString());
303            std::string opt;
304            while (iss >> opt)
[2815]305            {
[8132]306                int index = opt.find( "=" );
307                if( opt.substr( 0, index ) == "filename" ||
308                    opt.substr( 0, index ) == "FILENAME" )
309                {
310                    filename = opt.substr( index+1 );
311                } else if( opt.substr( 0, index ) == "size" ||
312                    opt.substr( 0, index ) == "SIZE" )
313                {
314                    std::string sizestr = opt.substr( index+1 );
315                    sizeHint = atol(sizestr.c_str());
316                }
[2501]317            }
[8132]318        }
319       
320        QuicktimeImportExport importer;
321        osg::ref_ptr<osg::Image> image = importer.readFromStream(is, filename, sizeHint);
322       
323        if (!importer.success() || (image == NULL)) {
324            osg::notify(osg::WARN) << "Error reading from stream "  << importer.getLastErrorString() << std::endl;
325            return ReadResult::ERROR_IN_READING_FILE;
326        }
327        _qtExitObserver.addMedia(image.get());
328        return image.release();
329       
330    }
[1632]331
[8132]332    virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options*) const
333    {
334        std::string ext = osgDB::getFileExtension(fileName);
335        if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
[292]336
[8132]337        initQuicktime();
[5799]338
[8132]339        //Buidl map  of extension <-> osFileTypes
340        std::map<std::string, OSType> extmap;
[5799]341
[8132]342        extmap.insert(std::pair<std::string, OSType>("jpg",  kQTFileTypeJPEG));
343        extmap.insert(std::pair<std::string, OSType>("jpeg", kQTFileTypeJPEG));
344        extmap.insert(std::pair<std::string, OSType>("bmp",  kQTFileTypeBMP));
345        extmap.insert(std::pair<std::string, OSType>("tif",  kQTFileTypeTIFF));
346        extmap.insert(std::pair<std::string, OSType>("tiff", kQTFileTypeTIFF));
347        extmap.insert(std::pair<std::string, OSType>("png",  kQTFileTypePNG));
348        extmap.insert(std::pair<std::string, OSType>("gif",  kQTFileTypeGIF));
349        extmap.insert(std::pair<std::string, OSType>("psd",  kQTFileTypePhotoShop));
350        extmap.insert(std::pair<std::string, OSType>("sgi",  kQTFileTypeSGIImage));
[8972]351       
[8132]352        std::map<std::string, OSType>::iterator cur = extmap.find(ext);
[5981]353
[8132]354        // can not handle this type of file, perhaps a movie?
355        if (cur == extmap.end())
[5799]356         return WriteResult::FILE_NOT_HANDLED;
357
[8132]358        std::ofstream os(fileName.c_str(), std::ios::binary | std::ios::trunc | std::ios::out);
359        if(os.good())
360        {
361            QuicktimeImportExport exporter;
362            exporter.writeToStream(os, const_cast<osg::Image*>(&img), fileName);
363           
364            if (exporter.success())
365                return WriteResult::FILE_SAVED;
366        }
[5799]367
[8132]368        return WriteResult::ERROR_IN_WRITING_FILE;
369    }
370   
371    virtual WriteResult writeImage (const osg::Image& img, std::ostream& os, const Options* options=NULL) const
372    {
373        std::string filename = "file.jpg"; // use jpeg if not otherwise specified
374       
375        if (options) {
376            std::istringstream iss(options->getOptionString());
377            std::string opt;
378            while (iss >> opt)
379            {
380                int index = opt.find( "=" );
381                if( opt.substr( 0, index ) == "filename" ||
382                    opt.substr( 0, index ) == "FILENAME" )
383                {
384                    filename = opt.substr( index+1 );
385                }
[4002]386            }
[8132]387        }
388       
389        QuicktimeImportExport exporter;
390        exporter.writeToStream(os, const_cast<osg::Image*>(&img), filename);
391           
392        if (exporter.success())
393            return WriteResult::FILE_SAVED;
394       
395        return WriteResult::ERROR_IN_WRITING_FILE;         
396    }
[4002]397
398
[8132]399    mutable QuicktimeExitObserver _qtExitObserver;
[292]400};
401
402// now register with Registry to instantiate the above
403// reader/writer.
[7076]404REGISTER_OSGPLUGIN(quicktime, ReaderWriterQT)
Note: See TracBrowser for help on using the browser.