diff --git a/src/osgDB/Registry.cpp b/src/osgDB/Registry.cpp index 41cb3e312..75aca6f37 100644 --- a/src/osgDB/Registry.cpp +++ b/src/osgDB/Registry.cpp @@ -159,14 +159,18 @@ Registry::Registry() addFileExtensionAlias("tiff", "qt"); addFileExtensionAlias("gif", "qt"); addFileExtensionAlias("png", "qt"); + addFileExtensionAlias("mov", "qt"); + addFileExtensionAlias("mpg", "qt"); + addFileExtensionAlias("mpv", "qt"); + addFileExtensionAlias("dv", "qt"); #else addFileExtensionAlias("jpg", "jpeg"); addFileExtensionAlias("jpe", "jpeg"); addFileExtensionAlias("tif", "tiff"); -#endif - addFileExtensionAlias("mpg", "mpeg"); addFileExtensionAlias("mpv", "mpeg"); +#endif + // remove geo to lwo alias as the new Carbon Graphics GEO format // also uses the .geo. It is still possible to load light wave .geo diff --git a/src/osgPlugins/quicktime/GNUmakefile b/src/osgPlugins/quicktime/GNUmakefile index 1a1b09eb9..1517af85d 100644 --- a/src/osgPlugins/quicktime/GNUmakefile +++ b/src/osgPlugins/quicktime/GNUmakefile @@ -2,7 +2,10 @@ TOPDIR = ../../.. include $(TOPDIR)/Make/makedefs CXXFILES = ReaderWriterQT.cpp\ - QTtexture.cpp + QTtexture.cpp\ + MovieData.cpp\ + QTUtils.cpp\ + QuicktimeImageStream.cpp\ LIBS += $(QUICKTIME) $(OSG_LIBS) $(OTHER_LIBS) diff --git a/src/osgPlugins/quicktime/MovieData.cpp b/src/osgPlugins/quicktime/MovieData.cpp new file mode 100644 index 000000000..acb6fd832 --- /dev/null +++ b/src/osgPlugins/quicktime/MovieData.cpp @@ -0,0 +1,160 @@ +/* + * MovieData.cpp + * lala + * + * Created by Stephan Huber on Wed Mar 10 2004. + * Copyright (c) 2004 __MyCompanyName__. All rights reserved. + * + */ +#include +#include + +#include "MovieData.h" +#include "QTUtils.h" + +using namespace osgQuicktime; + +namespace osg { + + MovieData::MovieData() : _movie(NULL), _gw(NULL), _fError(false) { + + } + + + MovieData::~MovieData() { + + if (_gw) DisposeGWorld(_gw); + if (_movie) DisposeMovie(_movie); + } + + + + + void MovieData::load(osg::Image* image, std::string filename, float startTime) { + + Rect bounds; + + osg::notify(osg::INFO) << "MovieData :: opening movie '" << filename << "'" << std::endl; + + OSStatus err = MakeMovieFromPath(filename.c_str(),&_movie); + if (err !=0) { + _fError = true; + osg::notify(osg::FATAL) << " MovieData :: MakeMovieFromPath failed with err " << err << std::endl; + return; + } + + GetMovieBox(_movie, &bounds); + _checkMovieError("Can't get movie box\n"); + + OffsetRect(&bounds, -bounds.left, -bounds.top); + SetMovieBox(_movie, &bounds); + _checkMovieError("Can't set movie box\n"); + + _movieWidth = bounds.right; + _movieHeight = bounds.bottom; + + _timescale = (float)GetMovieTimeScale(_movie); + + _initImage(image); + if (!_fError) _initGWorldStuff(image); + + + if (!_fError) { + + if ( startTime == 0.0f) + GoToBeginningOfMovie(_movie); + else { + TimeValue t = (TimeValue) (startTime*_timescale); + SetMovieTimeValue(_movie,t); + } + + UpdateMovie(_movie); + SetMovieRate(_movie,0); + } + + +} + + +// --------------------------------------------------------------------------- +// _intImage +// create image for storing +// --------------------------------------------------------------------------- + +void MovieData::_initImage(osg::Image* image) { + + void* buffer; + char* pointer; + + + _textureWidth = ((_movieWidth + 7) >> 3) << 3; + _textureHeight = _movieHeight; + + // some magic alignment... + pointer = (char*)malloc(4 * _textureWidth * _textureHeight + 32); + + if (pointer == NULL) { + osg::notify(osg::FATAL) << "MovieData: " << "Can't allocate texture buffer" << std::endl; + _fError= true; + } + + buffer = (void*)(((unsigned long)(pointer + 31) >> 5) << 5); + + image->setImage(_textureWidth,_textureHeight,0, + (GLint) GL_RGBA8, + (GLenum)GL_BGRA_EXT, + (GLenum)GL_UNSIGNED_INT_8_8_8_8_REV, + (unsigned char*) buffer,osg::Image::USE_MALLOC_FREE,4); + +} + +// --------------------------------------------------------------------------- +// _initGWorldStuff +// init gworld-stuff, so quicktime can play the movie into the gWorld. +// --------------------------------------------------------------------------- + +void MovieData::_initGWorldStuff(osg::Image * image) { + + Rect textureBounds; + OSStatus err; + GDHandle origDevice; + CGrafPtr origPort; + PixMapHandle pixmap = NULL; + + textureBounds.left = 0; + textureBounds.top = 0; + textureBounds.right = image->s(); + textureBounds.bottom = image->t(); + err = QTNewGWorldFromPtr(&_gw, k32ARGBPixelFormat, &textureBounds, NULL, NULL, 0, image->data(), 4 * image->s()); + + if (err !=0 ) + osg::notify(osg::FATAL) << "MovieData : Could not create gWorld" << std::endl; + + GetGWorld (&origPort, &origDevice); + SetGWorld(_gw, NULL); // set current graphics port to offscreen + SetMovieGWorld(_movie, (CGrafPtr)_gw, NULL); + + _checkMovieError("SetMovieGWorld failed"); + + pixmap = GetGWorldPixMap (_gw); + if (pixmap) + { + if (!LockPixels (pixmap)) // lock offscreen pixel map + { + osg::notify(osg::FATAL) << "Could not lock PixMap" << std::endl; + ExitToShell (); + } + } + else + { + osg::notify(osg::FATAL) << "Could not GetGWorldPixMap" << std::endl; + ExitToShell (); + } + + SetGWorld(origPort, origDevice); + +} + + + +} // namespace \ No newline at end of file diff --git a/src/osgPlugins/quicktime/MovieData.h b/src/osgPlugins/quicktime/MovieData.h new file mode 100644 index 000000000..511a5215e --- /dev/null +++ b/src/osgPlugins/quicktime/MovieData.h @@ -0,0 +1,57 @@ +/* + * MovieData.h + * encapsulates movie-related stuff + * + * Created by Stephan Huber on Wed Mar 10 2004. + * Copyright (c) 2004 digital mind. All rights reserved. + * + */ + +#ifndef _MOVIEDATA_HEADER_ +#define _MOVIEDATA_HEADER_ + +#include +#include +#include +#include + +namespace osg { + + class MovieData { + + public: + MovieData(); + ~MovieData(); + + void load(osg::Image* image, std::string fileName, float startTime = 0.0f); + + float getMovieDuration() { return GetMovieDuration(_movie)/(float)_timescale;} + float getMovieTime() {return GetMovieTime(_movie,NULL)/(float)_timescale; } + + Movie &getMovie() { return _movie; } + + protected: + Movie _movie; + GWorldPtr _gw; + + unsigned int _movieWidth, _movieHeight, _textureWidth, _textureHeight; + float _timescale; + bool _fError; + + void _initImage(osg::Image* image); + void _initGWorldStuff(osg::Image * image); + void _initTexture(); + + inline void _checkMovieError(std::string msg) { + if (GetMoviesError()) { + _fError = true; + osg::notify(osg::ALWAYS) << "MovieData: GetMoviesError fails at " << msg << std::endl; + } + } + + }; + + +} // namespace + +#endif \ No newline at end of file diff --git a/src/osgPlugins/quicktime/QTUtils.cpp b/src/osgPlugins/quicktime/QTUtils.cpp new file mode 100644 index 000000000..01bf2e928 --- /dev/null +++ b/src/osgPlugins/quicktime/QTUtils.cpp @@ -0,0 +1,81 @@ +/* + * QTUtils.cpp + * NativeContext + * + * Created by Stephan Huber on Fri Sep 06 2002. + * Copyright (c) 2002 digital mind. All rights reserved. + * + */ + +#include +#include +#include +#include "QTUtils.h" + +using namespace std; + +namespace osgQuicktime { + + + void initQuicktime() { + + static bool s_fQuicktimeInited = 0; + + OSErr err; + if (!s_fQuicktimeInited) { + err = EnterMovies(); + if (err!=0) + osg::notify(osg::FATAL) << "Error while initializing quicktime: " << err << endl; + else + osg::notify(osg::DEBUG_INFO) << "Quicktime initialized successfully" << endl; + s_fQuicktimeInited = true; + } + else + osg::notify(osg::DEBUG_INFO) << "Quicktime already initialized ..." << endl; + + } + + + + + // --------------------------------------------------------------------------- + // MakeFSSPecFromPath + // wandelt einen Posix-Pfad in ein FSSpec um. + // --------------------------------------------------------------------------- + OSStatus MakeFSSpecFromPath(const char* path, FSSpec* spec) { + OSStatus err; + FSRef fsref; + Boolean isdir; + /* + FSPathMakeRef is only available in Carbon. It takes a POSIX path and + tries to convert it into a MacOS FSRef object. + We don't want folders, only files, so we'll fail here if we got a + directory. + */ + err = FSPathMakeRef((const UInt8*)path, &fsref, &isdir); + if (err!=0) return err; + if (isdir) return 1; + // Ditto + err = FSGetCatalogInfo(&fsref, kFSCatInfoNone, NULL, NULL, spec, NULL); + return err; + } + + // --------------------------------------------------------------------------- + // MakeMovieFromPath + // erzeugt movie-objekt aus Pfad + // --------------------------------------------------------------------------- + OSStatus MakeMovieFromPath(const char* path, Movie* movie) { + OSStatus err; + FSSpec spec; + short resref; + MakeFSSpecFromPath(path, &spec); + err = OpenMovieFile(&spec, &resref, fsRdPerm); + if (err!=0) return err; + err = NewMovieFromFile(movie, resref, NULL, NULL, 0, NULL); + if (err==0) err=GetMoviesError(); + return err; + } + + + +} // namespace \ No newline at end of file diff --git a/src/osgPlugins/quicktime/QTUtils.h b/src/osgPlugins/quicktime/QTUtils.h new file mode 100644 index 000000000..c01c7051e --- /dev/null +++ b/src/osgPlugins/quicktime/QTUtils.h @@ -0,0 +1,20 @@ +/* + * QTUtils.h + * NativeContext + * + * Created by Stephan Huber on Fri Sep 06 2002. + * Copyright (c) 2002 digital mind. All rights reserved. + * + */ + +#include +#include + +namespace osgQuicktime { + + void initQuicktime(); + + OSStatus MakeFSSpecFromPath(const char* path, FSSpec* spec); + OSStatus MakeMovieFromPath(const char* path, Movie* movie); + +} \ No newline at end of file diff --git a/src/osgPlugins/quicktime/QuicktimeImageStream.cpp b/src/osgPlugins/quicktime/QuicktimeImageStream.cpp new file mode 100644 index 000000000..f87c77dac --- /dev/null +++ b/src/osgPlugins/quicktime/QuicktimeImageStream.cpp @@ -0,0 +1,194 @@ +// -*-c++-*- + +/* + * Copyright (C) 2004 Stephan Huber http://digitalmind.de + * + * + * The Open Scene Graph (OSG) is a cross platform C++/OpenGL library for + * real-time rendering of large 3D photo-realistic models. + * The OSG homepage is http://www.openscenegraph.org/ + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "QuicktimeImageStream.h" +#include +#include + +#include "QTUtils.h" +#include "MovieData.h" + + +using namespace osg; + +#define IDLE_TIMEOUT 150000L +#define ERR_MSG(no,msg) osg::notify(osg::WARN) << "QT-ImageStream: " << msg << " failed with error " << no << std::endl; + + + +// Constructor: setup and start thread +QuicktimeImageStream::QuicktimeImageStream(std::string fileName) : ImageStream() +{ + + osgQuicktime::initQuicktime(); + + _len = 0; + + _data = new MovieData(); + + for (int i = 0; i < NUM_CMD_INDEX; i++) + _cmd[i] = THREAD_IDLE; + _wrIndex = _rdIndex = 0; + + load(fileName); + + if (!fileName.empty()) + setFileName(fileName); + + startThread(); + start(); +} + + +// Deconstructor: stop and terminate thread +QuicktimeImageStream::~QuicktimeImageStream() +{ + stop(); + + setCmd(THREAD_QUIT); + + if( isRunning() ) + { + + // cancel the thread.. + cancel(); + //join(); + + // then wait for the the thread to stop running. + while(isRunning()) + { + osg::notify(osg::DEBUG_INFO)<<"Waiting for QuicktimeImageStream to cancel"<load(this, fileName); + + _len = _data->getMovieDuration(); + + +} + + +void QuicktimeImageStream::run() +{ + bool playing = false; + bool done = false; + OSErr err; + + // err = EnterMoviesOnThread(0); + // ERR_MSG(err,"EnterMoviesOnThread"); + + while (!done) { + // osg::notify(osg::ALWAYS) << "movietime: " << _data->getMovieTime() << " state " << getCmd() << std::endl; + // Handle commands + ThreadCommand cmd = getCmd(); + if (cmd != THREAD_IDLE) { + switch (cmd) { + case THREAD_START: // Start or continue stream + StartMovie(_data->getMovie()); + playing = true; + break; + + case THREAD_STOP: + SetMovieRate(_data->getMovie(),0); + osg::notify(NOTICE) << "QT-ImageStream: stop at "<< std::endl; + playing = false; + break; + + case THREAD_REWIND: + SetMovieRate(_data->getMovie(),0); + GoToBeginningOfMovie(_data->getMovie()); + break; + + case THREAD_CLOSE: + SetMovieRate(_data->getMovie(),0); + break; + + case THREAD_QUIT: // TODO + SetMovieRate(_data->getMovie(),0); + osg::notify(NOTICE) << "QT-ImageStream: quit" << std::endl; + done = true; + break; + default: + osg::notify(osg::WARN) << "QT-ImageStream: Unknown command " << cmd << std::endl; + break; + } + } + + MoviesTask(_data->getMovie(),0); + float currentTime = _data->getMovieTime(); + if (_lastUpdate!= currentTime) { + dirty(); + _lastUpdate = currentTime; + } + + if (playing) { + // TODO + + + } + else { + ::usleep(IDLE_TIMEOUT); + } + } + // err = ExitMoviesOnThread(); + //ERR_MSG(err,"ExitMoviesOnThread"); +} diff --git a/src/osgPlugins/quicktime/QuicktimeImageStream.h b/src/osgPlugins/quicktime/QuicktimeImageStream.h new file mode 100644 index 000000000..c74c51038 --- /dev/null +++ b/src/osgPlugins/quicktime/QuicktimeImageStream.h @@ -0,0 +1,108 @@ +// -*-c++-*- + +/* + * Copyright (C) 2004 Stephan Huber http://digitalmind.de + * + * The Open Scene Graph (OSG) is a cross platform C++/OpenGL library for + * real-time rendering of large 3D photo-realistic models. + * The OSG homepage is http://www.openscenegraph.org/ + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _QUICKTIMEIMAGESTREAM_H_ +#define _QUICKTIMEIMAGESTREAM_H_ + +#include + +#include +#include + +#define NUM_CMD_INDEX 4 + +namespace osg { + + class MovieData; + + /** + * Quicktime Image Stream class. + */ + class SG_EXPORT QuicktimeImageStream : public osg::ImageStream, public OpenThreads::Thread + { + public: + QuicktimeImageStream(std::string fileName = ""); + + virtual Object* clone() const { return new QuicktimeImageStream; } + virtual bool isSameKindAs(const Object* obj) const { + return dynamic_cast(obj) != NULL; + } + virtual const char* className() const { return "QuicktimeImageStream"; } + + /// Start or continue stream. + virtual void start() { setCmd(THREAD_START); } + + /// Stop stream at current position. + virtual void stop() { setCmd(THREAD_STOP); } + + /// Rewind stream to beginning. + virtual void rewind() { setCmd(THREAD_REWIND); } + + + + /// Get total length in seconds. + inline float getLength() const { return _len; } + + void load(std::string fileName); + + virtual void run(); + + protected: + virtual ~QuicktimeImageStream(); + + private: + float _lastUpdate; + float _len; + + MovieData* _data; + + enum ThreadCommand { + THREAD_IDLE = 0, + THREAD_START, + THREAD_STOP, + THREAD_REWIND, + THREAD_CLOSE, + THREAD_QUIT + }; + ThreadCommand _cmd[NUM_CMD_INDEX]; + int _wrIndex, _rdIndex; + + OpenThreads::Mutex _mutex; + + // Lock/unlock object. + inline void lock() { _mutex.lock(); } + inline void unlock() { _mutex.unlock(); } + + /// Set command. + void setCmd(ThreadCommand cmd); + + /// Get command. + ThreadCommand getCmd(); + + + }; + +} // namespace + +#endif diff --git a/src/osgPlugins/quicktime/ReaderWriterQT.cpp b/src/osgPlugins/quicktime/ReaderWriterQT.cpp index f663b2d04..8a307b5f3 100644 --- a/src/osgPlugins/quicktime/ReaderWriterQT.cpp +++ b/src/osgPlugins/quicktime/ReaderWriterQT.cpp @@ -18,6 +18,7 @@ #endif #include "QTtexture.h" +#include "QuicktimeImageStream.h" using namespace osg; @@ -26,6 +27,14 @@ class ReaderWriterQT : public osgDB::ReaderWriter public: virtual const char* className() { return "Default Quicktime Image Reader/Writer"; } + virtual bool acceptsMovieExtension(const std::string& extension) + { + return osgDB::equalCaseInsensitive(extension,"mov") || + osgDB::equalCaseInsensitive(extension,"mpg") || + osgDB::equalCaseInsensitive(extension,"mpv") || + osgDB::equalCaseInsensitive(extension,"dv"); + } + virtual bool acceptsExtension(const std::string& extension) { // this should be the only image importer required on the Mac @@ -40,7 +49,8 @@ class ReaderWriterQT : public osgDB::ReaderWriter osgDB::equalCaseInsensitive(extension,"png") || osgDB::equalCaseInsensitive(extension,"pict") || osgDB::equalCaseInsensitive(extension,"pct") || - osgDB::equalCaseInsensitive(extension,"tga"); + osgDB::equalCaseInsensitive(extension,"tga") || + acceptsMovieExtension(extension); } virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options*) @@ -51,6 +61,19 @@ class ReaderWriterQT : public osgDB::ReaderWriter std::string fileName = osgDB::findDataFile( file ); if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; + // if the file is a movie file then load as an ImageStream. + if (acceptsMovieExtension(ext)) + { + // note from Robert Osfield when integrating, we should probably have so + // error handling mechanism here. Possibly move the load from + // the constructor to a seperate load method, and have a valid + // state on the ImageStream... will integrated as is right now + // to get things off the ground. + osg::QuicktimeImageStream* moov = new osg::QuicktimeImageStream(fileName); + moov->start(); + return moov; + } + long origWidth, origHeight,buffWidth,buffHeight,buffDepth,origDepth; // NOTE - implememntation means that this will always return 32 bits, so it is hard to work out if