From Stephan Huber and Riccardo Corsi, port of QuickTime plugin to Windows
This commit is contained in:
@@ -6,21 +6,17 @@
|
||||
* Copyright (c) 2004 __MyCompanyName__. All rights reserved.
|
||||
*
|
||||
*/
|
||||
#include <OpenGL/gl.h>
|
||||
#include <OpenGL/glext.h>
|
||||
#include <osg/GL>
|
||||
|
||||
#include <osg/Endian>
|
||||
#include <osgDB/FileNameUtils>
|
||||
|
||||
#include "MovieData.h"
|
||||
#include "QTUtils.h"
|
||||
|
||||
|
||||
|
||||
using namespace osgQuicktime;
|
||||
|
||||
namespace osg {
|
||||
|
||||
MovieData::MovieData() : _movie(NULL), _gw(NULL), _fError(false)
|
||||
MovieData::MovieData() : _pointer(NULL), _movie(NULL), _gw(NULL), _fError(false)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -28,6 +24,7 @@ MovieData::MovieData() : _movie(NULL), _gw(NULL), _fError(false)
|
||||
|
||||
MovieData::~MovieData()
|
||||
{
|
||||
if (_pointer) free(_pointer);
|
||||
if (_gw) DisposeGWorld(_gw);
|
||||
if (_movie) DisposeMovie(_movie);
|
||||
}
|
||||
@@ -35,10 +32,13 @@ MovieData::~MovieData()
|
||||
|
||||
|
||||
|
||||
void MovieData::load(osg::Image* image, std::string filename, float startTime)
|
||||
void MovieData::load(osg::Image* image, std::string afilename, float startTime)
|
||||
{
|
||||
Rect bounds;
|
||||
|
||||
std::string filename = afilename;
|
||||
if (!osgDB::isFileNameNativeStyle(filename))
|
||||
filename = osgDB::convertFileNameToNativeStyle(filename);
|
||||
|
||||
osg::notify(osg::INFO) << "MovieData :: opening movie '" << filename << "'" << std::endl;
|
||||
|
||||
OSStatus err = MakeMovieFromPath(filename.c_str(),&_movie);
|
||||
@@ -75,6 +75,9 @@ void MovieData::load(osg::Image* image, std::string filename, float startTime)
|
||||
|
||||
UpdateMovie(_movie);
|
||||
SetMovieRate(_movie,0);
|
||||
SetMovieActive(_movie, true);
|
||||
UpdateMovie(_movie);
|
||||
MoviesTask(_movie,0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,30 +91,30 @@ 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);
|
||||
_pointer = (char*)malloc(4 * _textureWidth * _textureHeight + 32);
|
||||
|
||||
if (pointer == NULL) {
|
||||
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);
|
||||
buffer = (void*)(((unsigned long)(_pointer + 31) >> 5) << 5);
|
||||
|
||||
GLenum internalFormat = (getCpuByteOrder()==osg::BigEndian)?
|
||||
GL_UNSIGNED_INT_8_8_8_8_REV :
|
||||
GL_UNSIGNED_INT_8_8_8_8;
|
||||
|
||||
image->setImage(_textureWidth,_textureHeight,0,
|
||||
image->setImage(_textureWidth,_textureHeight,1,
|
||||
(GLint) GL_RGBA8,
|
||||
(GLenum)GL_BGRA_EXT,
|
||||
internalFormat,
|
||||
(unsigned char*) buffer,osg::Image::USE_MALLOC_FREE,4);
|
||||
internalformat,
|
||||
(unsigned char*) buffer,osg::Image::NO_DELETE,4);
|
||||
|
||||
}
|
||||
|
||||
@@ -162,6 +165,36 @@ void MovieData::_initGWorldStuff(osg::Image * image) {
|
||||
|
||||
}
|
||||
|
||||
void MovieData::setMovieTime(float atime) {
|
||||
float time = (atime > getMovieDuration()) ? getMovieDuration() : atime;
|
||||
|
||||
TimeValue t = (TimeValue) (time * _timescale);
|
||||
SetMovieTimeValue(_movie,t);
|
||||
_checkMovieError("setMovieTime failed");
|
||||
UpdateMovie(_movie);
|
||||
MoviesTask(_movie,0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void MovieData::setMovieRate(float rate) {
|
||||
// osg::notify(osg::ALWAYS) << "new movierate: " << rate << " current: " << getMovieRate() << std::endl;
|
||||
_movieRate = rate;
|
||||
if (rate != 0) {
|
||||
PrerollMovie(_movie, GetMovieTime(_movie,NULL), X2Fix(rate));
|
||||
_checkMovieError("PrerollMovie failed");
|
||||
}
|
||||
|
||||
SetMovieRate(_movie, X2Fix(rate));
|
||||
_checkMovieError("setMovieRate failed");
|
||||
MoviesTask(_movie, 0);
|
||||
_checkMovieError("MoviesTask failed");
|
||||
|
||||
UpdateMovie(_movie);
|
||||
_checkMovieError("UpdateMovie failed");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -13,35 +13,90 @@
|
||||
#include <osg/Notify>
|
||||
#include <osg/Image>
|
||||
#include <string>
|
||||
#include <QuickTime/QuickTime.h>
|
||||
|
||||
namespace osg {
|
||||
|
||||
#include "QTUtils.h"
|
||||
|
||||
|
||||
/**
|
||||
* the class MovieData encapsulates all quicktime-related stuff, so it doesn't polute the namespaces
|
||||
* it handles all calls to quicktime etc... It is mainly used by the QuicktimeImageStream, it is
|
||||
* rarely needed in other contexts
|
||||
*/
|
||||
class MovieData {
|
||||
|
||||
public:
|
||||
/** default constructor */
|
||||
MovieData();
|
||||
|
||||
/** default destructor */
|
||||
~MovieData();
|
||||
|
||||
/**
|
||||
* loads a movie, start it playing at startTime, use Image for the storage
|
||||
* @param image the image, to use as storage
|
||||
* @param fileName the movie to open
|
||||
* @param startTime the starttime to begin with
|
||||
*/
|
||||
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; }
|
||||
/** @return the duration for this movie in seconds */
|
||||
inline float getMovieDuration() { return GetMovieDuration(_movie)/(float)_timescale;}
|
||||
|
||||
/** @return the current position for this movie in seconds */
|
||||
inline float getMovieTime() {return GetMovieTime(_movie,NULL)/(float)_timescale; }
|
||||
|
||||
/** stes the movietime */
|
||||
void setMovieTime(float atime);
|
||||
|
||||
/** @return the Movie-handle, to use it with other quicktime-calls */
|
||||
inline Movie &getMovie() { return _movie; }
|
||||
|
||||
/** @return the current movieRate */
|
||||
inline float getMovieRate() { return Fix2X(GetMovieRate(_movie)); }
|
||||
/** @return returns the cached movierate, may differ to the real movierate */
|
||||
inline float getCachedMovieRate() { return _movieRate; }
|
||||
|
||||
/** sets the MovieRate for this movie */
|
||||
void setMovieRate(float rate);
|
||||
|
||||
/** sets the volume for the soundtrack of this movie */
|
||||
void setVolume(float volume) { SetMovieVolume(_movie,(short)(volume*255));}
|
||||
float getVolume() { return GetMovieVolume(_movie) / 255.0f; }
|
||||
|
||||
void setAudioBalance(float f) {
|
||||
Float32 balance = f;
|
||||
SetMovieAudioBalance(_movie, balance, 0);
|
||||
}
|
||||
|
||||
float getAudioBalance() {
|
||||
Float32 balance;
|
||||
float f;
|
||||
GetMovieAudioBalance(_movie, &balance, 0);
|
||||
f = balance;
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
char* _pointer;
|
||||
Movie _movie;
|
||||
GWorldPtr _gw;
|
||||
|
||||
unsigned int _movieWidth, _movieHeight, _textureWidth, _textureHeight;
|
||||
float _timescale;
|
||||
bool _fError;
|
||||
float _movieRate;
|
||||
|
||||
/** inits the image for storage */
|
||||
void _initImage(osg::Image* image);
|
||||
|
||||
/** inits the gWorld, where the movie gets drawn into */
|
||||
void _initGWorldStuff(osg::Image * image);
|
||||
|
||||
/** inits the texture */
|
||||
void _initTexture();
|
||||
|
||||
/** checks for an movie-error */
|
||||
inline void _checkMovieError(std::string msg) {
|
||||
if (GetMoviesError()) {
|
||||
_fError = true;
|
||||
@@ -52,6 +107,6 @@ namespace osg {
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,33 +6,75 @@
|
||||
* Copyright (c) 2002 digital mind. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Referenced>
|
||||
#include <osg/Notify>
|
||||
#include <QuickTime/QuickTime.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
#include "QTUtils.h"
|
||||
#include "osgDB/Registry"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace osgQuicktime {
|
||||
|
||||
|
||||
class QuicktimeInitializer : public osg::Referenced {
|
||||
public:
|
||||
QuicktimeInitializer() :osg::Referenced() {
|
||||
static bool s_fQuicktimeInited = 0;
|
||||
if (!s_fQuicktimeInited) {
|
||||
#ifndef __APPLE__
|
||||
InitializeQTML(0);
|
||||
#endif
|
||||
OSErr 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;
|
||||
registerQTReader();
|
||||
s_fQuicktimeInited = true;
|
||||
}
|
||||
}
|
||||
|
||||
~QuicktimeInitializer() {
|
||||
#ifndef __APPLE__
|
||||
ExitMovies();
|
||||
#endif
|
||||
//osg::notify(osg::DEBUG_INFO) << "Quicktime deinitialized successfully" << endl;
|
||||
}
|
||||
|
||||
protected:
|
||||
void registerQTReader() {
|
||||
osgDB::Registry* r = osgDB::Registry::instance();
|
||||
r->addFileExtensionAlias("jpg", "qt");
|
||||
r->addFileExtensionAlias("jpe", "qt");
|
||||
r->addFileExtensionAlias("jpeg", "qt");
|
||||
r->addFileExtensionAlias("tif", "qt");
|
||||
r->addFileExtensionAlias("tiff", "qt");
|
||||
r->addFileExtensionAlias("gif", "qt");
|
||||
r->addFileExtensionAlias("png", "qt");
|
||||
r->addFileExtensionAlias("psd", "qt");
|
||||
r->addFileExtensionAlias("tga", "qt");
|
||||
r->addFileExtensionAlias("mov", "qt");
|
||||
r->addFileExtensionAlias("avi", "qt");
|
||||
r->addFileExtensionAlias("mpg", "qt");
|
||||
r->addFileExtensionAlias("mpv", "qt");
|
||||
r->addFileExtensionAlias("dv", "qt");
|
||||
r->addFileExtensionAlias("mp4", "qt");
|
||||
r->addFileExtensionAlias("m4v", "qt");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void initQuicktime(bool erase) {
|
||||
|
||||
static osg::ref_ptr<QuicktimeInitializer> s_qt_init = new QuicktimeInitializer();
|
||||
if (erase)
|
||||
s_qt_init = NULL;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
void exitQuicktime() {
|
||||
initQuicktime(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +85,7 @@ namespace osgQuicktime {
|
||||
// wandelt einen Posix-Pfad in ein FSSpec um.
|
||||
// ---------------------------------------------------------------------------
|
||||
OSStatus MakeFSSpecFromPath(const char* path, FSSpec* spec) {
|
||||
#ifdef __APPLE__
|
||||
OSStatus err;
|
||||
FSRef fsref;
|
||||
Boolean isdir;
|
||||
@@ -58,17 +101,23 @@ namespace osgQuicktime {
|
||||
// Ditto
|
||||
err = FSGetCatalogInfo(&fsref, kFSCatInfoNone, NULL, NULL, spec, NULL);
|
||||
return err;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// MakeMovieFromPath
|
||||
// erzeugt movie-objekt aus Pfad
|
||||
// ---------------------------------------------------------------------------
|
||||
OSStatus MakeMovieFromPath(const char* path, Movie* movie) {
|
||||
OSStatus err;
|
||||
FSSpec spec;
|
||||
short resref;
|
||||
#ifdef __APPLE__
|
||||
MakeFSSpecFromPath(path, &spec);
|
||||
#else
|
||||
err = NativePathNameToFSSpec((char*)path, &spec, 0 /* flags */);
|
||||
#endif
|
||||
err = OpenMovieFile(&spec, &resref, fsRdPerm);
|
||||
if (err!=0) return err;
|
||||
err = NewMovieFromFile(movie, resref, NULL, NULL, 0, NULL);
|
||||
@@ -78,4 +127,3 @@ namespace osgQuicktime {
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -7,14 +7,56 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <QuickTime/QuickTime.h>
|
||||
#ifndef QTUTILS_HEADER_
|
||||
#define QTUTILS_HEADER_
|
||||
|
||||
namespace osgQuicktime {
|
||||
#ifdef __APPLE__
|
||||
#include <Quicktime/Quicktime.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
#else
|
||||
#include <QTML.h>
|
||||
#include <Movies.h>
|
||||
#include <Quickdraw.h>
|
||||
#include <QDOffscreen.h>
|
||||
#include <QuicktimeComponents.h>
|
||||
#include <FixMath.h>
|
||||
#include <CGBitmapContext.h>
|
||||
#include <CGImage.h>
|
||||
#include <CGColorSpace.h>
|
||||
#include <ImageCompression.h>
|
||||
|
||||
void initQuicktime();
|
||||
extern "C" {
|
||||
/** legacy function for Windows */
|
||||
inline void GetPortBounds(GWorldPtr gw, Rect* rect) {
|
||||
(*rect) = (gw->portRect);
|
||||
}
|
||||
/** legacy function for Windows */
|
||||
inline PixMapHandle GetPortPixMap (CGrafPtr port) {
|
||||
return port->portPixMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
OSStatus MakeFSSpecFromPath(const char* path, FSSpec* spec);
|
||||
OSStatus MakeMovieFromPath(const char* path, Movie* movie);
|
||||
#define SetRect MacSetRect
|
||||
#define OffsetRect MacOffsetRect
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* inits Quicktime, if erase = true, the Quicktime-stuff gets cleaned, call it before your app exits
|
||||
* @param erase true, if you want to cleanup quicktime-related stuff
|
||||
*/
|
||||
void initQuicktime(bool erase = false);
|
||||
|
||||
/** cleans up all quicktime-related stuff */
|
||||
void exitQuicktime();
|
||||
|
||||
/** constructs an FSSpec out of an path */
|
||||
OSStatus MakeFSSpecFromPath(const char* path, FSSpec* spec);
|
||||
|
||||
/** opens a movie from a path */
|
||||
OSStatus MakeMovieFromPath(const char* path, Movie* movie);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -50,18 +50,23 @@ PORTIONS OF THIS CODE ARE COPYRIGHT APPLE COMPUTER -
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
#include <QuickTime/ImageCompression.h> // for image loading and decompression
|
||||
#include <QuickTime/QuickTimeComponents.h> // for file type support
|
||||
#else
|
||||
#include <ImageCompression.h> // for image loading and decompression
|
||||
#include <QuickTimeComponents.h> // for file type support
|
||||
#endif
|
||||
|
||||
#include <OpenGL/gl.h> // for OpenGL API
|
||||
#include <OpenGL/glu.h> // for OpenGL API
|
||||
#include <OpenGL/glext.h> // for OpenGL extension support
|
||||
|
||||
#include <osg/GL> // for OpenGL API
|
||||
#include "QTUtils.h"
|
||||
#include "QTtexture.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// ==================================
|
||||
|
||||
enum // how to scale image to power of two on read if scaling
|
||||
@@ -346,15 +351,10 @@ FSSpec *darwinPathToFSSpec (char *fname ) {
|
||||
|
||||
FSSpec *fs;
|
||||
OSStatus result;
|
||||
#if defined( __APPLE__ )
|
||||
FSRef ref;
|
||||
|
||||
/* convert the POSIX path to an FSRef */
|
||||
#if defined( __APPLE__ ) && ( __GNUC__ > 3 )
|
||||
result = FSPathMakeRef( (UInt8*)fname, &ref, false); // fname is not a directory
|
||||
#else
|
||||
result = FSPathMakeRef(fname, &ref, false); // fname is not a directory
|
||||
#endif
|
||||
|
||||
result = FSPathMakeRef( (UInt8*)fname, &ref, false); // fname is not a directory
|
||||
if (result!=0) return NULL;
|
||||
|
||||
/* and then convert the FSRef to an FSSpec */
|
||||
@@ -365,6 +365,16 @@ FSSpec *darwinPathToFSSpec (char *fname ) {
|
||||
// failed:
|
||||
free(fs);
|
||||
return NULL;
|
||||
#else
|
||||
// windows implementation to get a fsspec
|
||||
fs = (FSSpec *) malloc(sizeof(FSSpec));
|
||||
result = NativePathNameToFSSpec(fname, fs, 0 /* flags */);
|
||||
|
||||
if (0 == result)
|
||||
return fs;
|
||||
free(fs);
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
unsigned char* LoadBufferFromDarwinPath ( const char *fname, long *origWidth,
|
||||
long *origHeight, long *origDepth,
|
||||
long *buffWidth, long *buffHeight, long *buffDepth);
|
||||
|
||||
long *origHeight, long *origDepth,
|
||||
long *buffWidth, long *buffHeight, long *buffDepth);
|
||||
|
||||
char* QTfailureMessage(void);
|
||||
FSSpec *darwinPathToFSSpec (char *fname );
|
||||
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
// -*-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
|
||||
*/
|
||||
* 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 <osg/Notify>
|
||||
@@ -34,201 +34,254 @@
|
||||
#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;
|
||||
|
||||
static OpenThreads::Mutex* s_qtMutex = new OpenThreads::Mutex;
|
||||
|
||||
int QuicktimeImageStream::_qtInstanceCount = 0;
|
||||
|
||||
// Constructor: setup and start thread
|
||||
QuicktimeImageStream::QuicktimeImageStream(std::string fileName) : ImageStream()
|
||||
{
|
||||
// ricky
|
||||
if(_qtInstanceCount == 0)
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*s_qtMutex);
|
||||
osg::notify(osg::NOTICE) << "quicktime Init" << std::endl;
|
||||
initQuicktime();
|
||||
}
|
||||
++ _qtInstanceCount;
|
||||
// end ricky
|
||||
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*s_qtMutex);
|
||||
osgQuicktime::initQuicktime();
|
||||
}
|
||||
|
||||
_len = 0;
|
||||
|
||||
_data = new MovieData();
|
||||
|
||||
for (int i = 0; i < NUM_CMD_INDEX; i++)
|
||||
_cmd[i] = THREAD_IDLE;
|
||||
_wrIndex = _rdIndex = 0;
|
||||
_len = 0;
|
||||
_data = new MovieData();
|
||||
|
||||
load(fileName);
|
||||
for (int i = 0; i < NUM_CMD_INDEX; i++)
|
||||
_cmd[i] = THREAD_IDLE;
|
||||
_wrIndex = _rdIndex = 0;
|
||||
|
||||
if (!fileName.empty())
|
||||
setFileName(fileName);
|
||||
load(fileName);
|
||||
|
||||
if (!fileName.empty())
|
||||
setFileName(fileName);
|
||||
|
||||
// ricky
|
||||
_status = ImageStream::PAUSED;
|
||||
}
|
||||
|
||||
|
||||
// Deconstructor: stop and terminate thread
|
||||
QuicktimeImageStream::~QuicktimeImageStream()
|
||||
{
|
||||
if( isRunning() )
|
||||
{
|
||||
quit(true);
|
||||
}
|
||||
|
||||
if( isRunning() )
|
||||
{
|
||||
quit(true);
|
||||
}
|
||||
// ricky
|
||||
-- _qtInstanceCount;
|
||||
if(_qtInstanceCount == 0)
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*s_qtMutex);
|
||||
osg::notify(osg::NOTICE) << "quicktime Exit" << std::endl;
|
||||
exitQuicktime();
|
||||
}
|
||||
// end ricky
|
||||
|
||||
// clean up quicktime movies.
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*s_qtMutex);
|
||||
delete _data;
|
||||
}
|
||||
// clean up quicktime movies.
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*s_qtMutex);
|
||||
delete _data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Set command
|
||||
void QuicktimeImageStream::setCmd(ThreadCommand cmd)
|
||||
void QuicktimeImageStream::setCmd(ThreadCommand cmd, float rate)
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||
|
||||
_cmd[_wrIndex] = cmd;
|
||||
_wrIndex = (_wrIndex + 1) % NUM_CMD_INDEX;
|
||||
_cmd[_wrIndex] = cmd;
|
||||
_rates[_wrIndex] = rate;
|
||||
_wrIndex = (_wrIndex + 1) % NUM_CMD_INDEX;
|
||||
}
|
||||
|
||||
|
||||
// Get command
|
||||
QuicktimeImageStream::ThreadCommand QuicktimeImageStream::getCmd()
|
||||
{
|
||||
ThreadCommand cmd = THREAD_IDLE;
|
||||
ThreadCommand cmd = THREAD_IDLE;
|
||||
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||
|
||||
if (_rdIndex != _wrIndex) {
|
||||
cmd = _cmd[_rdIndex];
|
||||
_rdIndex = (_rdIndex + 1) % NUM_CMD_INDEX;
|
||||
}
|
||||
if (_rdIndex != _wrIndex) {
|
||||
cmd = _cmd[_rdIndex];
|
||||
_currentRate = _rates[_rdIndex];
|
||||
_rdIndex = (_rdIndex + 1) % NUM_CMD_INDEX;
|
||||
}
|
||||
|
||||
return cmd;
|
||||
return cmd;
|
||||
}
|
||||
|
||||
|
||||
void QuicktimeImageStream::load(std::string fileName)
|
||||
{
|
||||
osg::notify(osg::DEBUG_INFO) << "QT-ImageStream: loading quicktime movie from " << fileName << std::endl;
|
||||
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*s_qtMutex);
|
||||
osg::notify(osg::DEBUG_INFO) << "QT-ImageStream: loading quicktime movie from " << fileName << std::endl;
|
||||
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*s_qtMutex);
|
||||
|
||||
_data->load(this, fileName);
|
||||
|
||||
_len = _data->getMovieDuration();
|
||||
_current = 0;
|
||||
|
||||
|
||||
_data->load(this, fileName);
|
||||
|
||||
_len = _data->getMovieDuration();
|
||||
|
||||
|
||||
}
|
||||
|
||||
void QuicktimeImageStream::quit(bool wiatForThreadToExit)
|
||||
{
|
||||
osg::notify(osg::DEBUG_INFO)<<"Sending quit"<<this<<std::endl;
|
||||
setCmd(THREAD_QUIT);
|
||||
osg::notify(osg::DEBUG_INFO)<<"Sending quit"<<this<<std::endl;
|
||||
setCmd(THREAD_QUIT);
|
||||
|
||||
if (wiatForThreadToExit)
|
||||
{
|
||||
while(isRunning())
|
||||
{
|
||||
osg::notify(osg::DEBUG_INFO)<<"Waiting for QuicktimeImageStream to quit"<<this<<std::endl;
|
||||
OpenThreads::Thread::YieldCurrentThread();
|
||||
}
|
||||
osg::notify(osg::DEBUG_INFO)<<"QuicktimeImageStream has quit"<<this<<std::endl;
|
||||
}
|
||||
if (wiatForThreadToExit)
|
||||
{
|
||||
while(isRunning())
|
||||
{
|
||||
osg::notify(osg::DEBUG_INFO)<<"Waiting for QuicktimeImageStream to quit"<<this<<std::endl;
|
||||
OpenThreads::Thread::YieldCurrentThread();
|
||||
}
|
||||
osg::notify(osg::DEBUG_INFO)<<"QuicktimeImageStream has quit"<<this<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
bool playing = false;
|
||||
bool done = false;
|
||||
|
||||
float currentTime=0.0f;
|
||||
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*s_qtMutex);
|
||||
/*
|
||||
OSErr err;
|
||||
err = EnterMoviesOnThread(0);
|
||||
ERR_MSG(err,"EnterMoviesOnThread");
|
||||
err = AttachMovieToCurrentThread(_data->getMovie());
|
||||
*/
|
||||
while (!done) {
|
||||
|
||||
if (cmd != THREAD_IDLE) {
|
||||
switch (cmd) {
|
||||
|
||||
ThreadCommand cmd = getCmd();
|
||||
osg::notify(osg::DEBUG_INFO) << "movietime: " << _data->getMovieTime() << " rate: " << _data->getMovieRate() << " state " << cmd << " playing: " << playing << " done " << done << " " << _wrIndex << "/" << _rdIndex << std::endl;
|
||||
// Handle commands
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*s_qtMutex);
|
||||
|
||||
if (cmd != THREAD_IDLE) {
|
||||
osg::notify(osg::DEBUG_INFO) << "new cmd: " << cmd << std::endl;
|
||||
switch (cmd) {
|
||||
case THREAD_START: // Start or continue stream
|
||||
StartMovie(_data->getMovie());
|
||||
playing = true;
|
||||
break;
|
||||
_data->setMovieRate(1.0f);
|
||||
|
||||
playing = true;
|
||||
break;
|
||||
|
||||
case THREAD_STOP:
|
||||
SetMovieRate(_data->getMovie(),0);
|
||||
osg::notify(INFO) << "QT-ImageStream: stop at "<< std::endl;
|
||||
playing = false;
|
||||
break;
|
||||
_data->setMovieRate(0);
|
||||
osg::notify(osg::INFO) << "QT-ImageStream: stop at "<< std::endl;
|
||||
playing = false;
|
||||
break;
|
||||
|
||||
case THREAD_REWIND:
|
||||
SetMovieRate(_data->getMovie(),0);
|
||||
GoToBeginningOfMovie(_data->getMovie());
|
||||
break;
|
||||
SetMovieRate(_data->getMovie(),0);
|
||||
GoToBeginningOfMovie(_data->getMovie());
|
||||
break;
|
||||
|
||||
case THREAD_FORWARD:
|
||||
SetMovieRate(_data->getMovie(),0);
|
||||
GoToEndOfMovie(_data->getMovie());
|
||||
break;
|
||||
|
||||
case THREAD_SEEK:
|
||||
_data->setMovieTime(_currentRate);
|
||||
playing = true;
|
||||
break;
|
||||
|
||||
case THREAD_SETRATE:
|
||||
_data->setMovieRate(_currentRate);
|
||||
playing = (_currentRate != 0.0f);
|
||||
break;
|
||||
|
||||
case THREAD_CLOSE:
|
||||
SetMovieRate(_data->getMovie(),0);
|
||||
break;
|
||||
_data->setMovieRate(0);
|
||||
break;
|
||||
|
||||
case THREAD_QUIT: // TODO
|
||||
SetMovieRate(_data->getMovie(),0);
|
||||
osg::notify(INFO) << "QT-ImageStream: quit" << std::endl;
|
||||
//playing = false;
|
||||
done = true;
|
||||
break;
|
||||
_data->setMovieRate(0);
|
||||
osg::notify(osg::INFO) << "QT-ImageStream: quit" << std::endl;
|
||||
//playing = false;
|
||||
done = true;
|
||||
break;
|
||||
default:
|
||||
osg::notify(osg::WARN) << "QT-ImageStream: Unknown command " << cmd << std::endl;
|
||||
break;
|
||||
}
|
||||
osg::notify(osg::WARN) << "QT-ImageStream: Unknown command " << cmd << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MoviesTask(_data->getMovie(),0);
|
||||
MoviesTask(_data->getMovie(),0);
|
||||
_current = _data->getMovieTime();
|
||||
}
|
||||
|
||||
currentTime = _data->getMovieTime();
|
||||
}
|
||||
|
||||
|
||||
if (_lastUpdate!= currentTime)
|
||||
{
|
||||
if (_lastUpdate!= _current)
|
||||
{
|
||||
// force the texture to update the image
|
||||
dirty();
|
||||
// update internal time and take care of looping
|
||||
_lastUpdate = _current;
|
||||
|
||||
dirty();
|
||||
_lastUpdate = currentTime;
|
||||
|
||||
if (currentTime>=_data->getMovieDuration())
|
||||
{
|
||||
if (getLoopingMode()==LOOPING)
|
||||
{
|
||||
rewind();
|
||||
play();
|
||||
}
|
||||
else
|
||||
{
|
||||
pause();
|
||||
}
|
||||
if (getLoopingMode() == LOOPING)
|
||||
{
|
||||
// loopen wir rueckwaerts?
|
||||
if ((_current <= 0.0f) && (_data->getCachedMovieRate() < 0.0f)) {
|
||||
forward();
|
||||
setMovieRate(_data->getCachedMovieRate());
|
||||
}
|
||||
// loppen wir vorw<72>rts?
|
||||
else if ((_current >= _len) && (_data->getCachedMovieRate() > 0.0f))
|
||||
{
|
||||
rewind();
|
||||
setMovieRate(_data->getCachedMovieRate());
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // NO LOOPING
|
||||
//ricky
|
||||
if(_current >= _len)
|
||||
{
|
||||
pause();
|
||||
rewind();
|
||||
}
|
||||
// orig
|
||||
//pause();
|
||||
|
||||
}
|
||||
|
||||
if (playing)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
else if (!done)
|
||||
{
|
||||
OpenThreads::Thread::microSleep(IDLE_TIMEOUT);
|
||||
}
|
||||
}
|
||||
// err = ExitMoviesOnThread();
|
||||
//ERR_MSG(err,"ExitMoviesOnThread");
|
||||
}
|
||||
}
|
||||
|
||||
if (playing)
|
||||
{
|
||||
OpenThreads::Thread::microSleep(16000);
|
||||
}
|
||||
else if (!done)
|
||||
{
|
||||
OpenThreads::Thread::microSleep(IDLE_TIMEOUT);
|
||||
}
|
||||
}
|
||||
/*
|
||||
err = DetachMovieFromCurrentThread(_data->getMovie());
|
||||
err = ExitMoviesOnThread();
|
||||
ERR_MSG(err,"ExitMoviesOnThread");
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -32,78 +32,118 @@
|
||||
|
||||
#define NUM_CMD_INDEX 20
|
||||
|
||||
namespace osg {
|
||||
|
||||
class MovieData;
|
||||
|
||||
/**
|
||||
* Quicktime Image Stream class.
|
||||
*/
|
||||
class 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<const QuicktimeImageStream*>(obj) != NULL;
|
||||
}
|
||||
virtual const char* className() const { return "QuicktimeImageStream"; }
|
||||
|
||||
/// Start or continue stream.
|
||||
virtual void play()
|
||||
{
|
||||
if (!isRunning()) start();
|
||||
|
||||
setCmd(THREAD_START);
|
||||
}
|
||||
|
||||
/// Pause stream at current position.
|
||||
virtual void pause() { setCmd(THREAD_STOP); }
|
||||
|
||||
/// Rewind stream to beginning.
|
||||
virtual void rewind() { setCmd(THREAD_REWIND); }
|
||||
|
||||
virtual void quit(bool wiatForThreadToExit);
|
||||
|
||||
/// 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;
|
||||
|
||||
/// Set command.
|
||||
void setCmd(ThreadCommand cmd);
|
||||
|
||||
/// Get command.
|
||||
ThreadCommand getCmd();
|
||||
|
||||
|
||||
};
|
||||
class MovieData;
|
||||
|
||||
/**
|
||||
* Quicktime Image Stream class. streams a quicktime movie into an image
|
||||
*/
|
||||
class QuicktimeImageStream : public osg::ImageStream, public OpenThreads::Thread
|
||||
{
|
||||
public:
|
||||
/** Constructor
|
||||
* @param fileName movie to open */
|
||||
QuicktimeImageStream(std::string fileName = "");
|
||||
virtual Object* clone() const { return new QuicktimeImageStream; }
|
||||
virtual bool isSameKindAs(const Object* obj) const {
|
||||
return dynamic_cast<const QuicktimeImageStream*>(obj) != NULL;
|
||||
}
|
||||
|
||||
virtual const char* className() const { return "QuicktimeImageStream"; }
|
||||
|
||||
/// Start or continue stream.
|
||||
virtual void play()
|
||||
{
|
||||
if (!isRunning()) start();
|
||||
|
||||
setCmd(THREAD_START);
|
||||
|
||||
// ricky
|
||||
_status = ImageStream::PLAYING;
|
||||
}
|
||||
|
||||
/// sets the movierate of this movie
|
||||
void setMovieRate(float rate) {
|
||||
if (!isRunning()) start();
|
||||
setCmd(THREAD_SETRATE,rate);
|
||||
}
|
||||
|
||||
/// Pause stream at current position.
|
||||
virtual void pause()
|
||||
{
|
||||
setCmd(THREAD_STOP);
|
||||
// ricky
|
||||
_status = ImageStream::PAUSED;
|
||||
}
|
||||
|
||||
/// Rewind stream to beginning.
|
||||
virtual void rewind() { setCmd(THREAD_REWIND); }
|
||||
|
||||
/// forward stream to the end
|
||||
virtual void forward() { setCmd(THREAD_FORWARD); }
|
||||
|
||||
/// stop playing
|
||||
virtual void quit(bool wiatForThreadToExit);
|
||||
|
||||
/// Get total length in seconds.
|
||||
inline float getLength() const { return _len; }
|
||||
|
||||
/// jumps to a specific position
|
||||
void jumpTo(float pos) {
|
||||
setCmd(THREAD_SEEK, pos);
|
||||
}
|
||||
|
||||
/// returns the current playing position
|
||||
inline float getCurrentTime() const { return _current; }
|
||||
|
||||
/// @return the current moviedata-object
|
||||
MovieData* getMovieData() { return _data; }
|
||||
|
||||
/// loads a movie from fileName
|
||||
void load(std::string fileName);
|
||||
|
||||
/// starts the thread
|
||||
virtual void run();
|
||||
|
||||
protected:
|
||||
/// destructor
|
||||
virtual ~QuicktimeImageStream();
|
||||
|
||||
private:
|
||||
float _lastUpdate;
|
||||
float _len;
|
||||
float _current;
|
||||
float _currentRate;
|
||||
|
||||
MovieData* _data;
|
||||
|
||||
enum ThreadCommand {
|
||||
THREAD_IDLE = 0,
|
||||
THREAD_START,
|
||||
THREAD_STOP,
|
||||
THREAD_REWIND,
|
||||
THREAD_FORWARD,
|
||||
THREAD_SEEK,
|
||||
THREAD_SETRATE,
|
||||
THREAD_CLOSE,
|
||||
THREAD_QUIT
|
||||
};
|
||||
ThreadCommand _cmd[NUM_CMD_INDEX];
|
||||
float _rates[NUM_CMD_INDEX];
|
||||
int _wrIndex, _rdIndex;
|
||||
|
||||
OpenThreads::Mutex _mutex;
|
||||
|
||||
/// Set command.
|
||||
void setCmd(ThreadCommand cmd, float rate = 0.0f);
|
||||
|
||||
/// Get command.
|
||||
ThreadCommand getCmd();
|
||||
|
||||
// ricky
|
||||
static int _qtInstanceCount;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
#ifndef SEEK_SET
|
||||
# define SEEK_SET 0
|
||||
#endif
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <QuickTime/QuickTime.h>
|
||||
#include "QTUtils.h"
|
||||
#include "QTtexture.h"
|
||||
#include "QuicktimeImageStream.h"
|
||||
|
||||
@@ -28,375 +27,394 @@ using namespace osg;
|
||||
|
||||
class ReaderWriterQT : public osgDB::ReaderWriter
|
||||
{
|
||||
public:
|
||||
virtual const char* className() const { return "Default Quicktime Image Reader/Writer"; }
|
||||
|
||||
virtual bool acceptsMovieExtension(const std::string& extension) const
|
||||
{
|
||||
return osgDB::equalCaseInsensitive(extension,"mov") ||
|
||||
osgDB::equalCaseInsensitive(extension,"mpg") ||
|
||||
osgDB::equalCaseInsensitive(extension,"mpv") ||
|
||||
osgDB::equalCaseInsensitive(extension,"mp4") ||
|
||||
osgDB::equalCaseInsensitive(extension,"m4v") ||
|
||||
osgDB::equalCaseInsensitive(extension,"dv");
|
||||
}
|
||||
|
||||
virtual bool acceptsExtension(const std::string& extension) const
|
||||
{
|
||||
// this should be the only image importer required on the Mac
|
||||
// dont know what else it supports, but these will do
|
||||
return osgDB::equalCaseInsensitive(extension,"rgb") ||
|
||||
osgDB::equalCaseInsensitive(extension,"rgba") ||
|
||||
osgDB::equalCaseInsensitive(extension,"jpg") ||
|
||||
osgDB::equalCaseInsensitive(extension,"jpeg") ||
|
||||
osgDB::equalCaseInsensitive(extension,"tif") ||
|
||||
osgDB::equalCaseInsensitive(extension,"tiff") ||
|
||||
osgDB::equalCaseInsensitive(extension,"gif") ||
|
||||
osgDB::equalCaseInsensitive(extension,"png") ||
|
||||
osgDB::equalCaseInsensitive(extension,"pict") ||
|
||||
osgDB::equalCaseInsensitive(extension,"pct") ||
|
||||
osgDB::equalCaseInsensitive(extension,"tga") ||
|
||||
osgDB::equalCaseInsensitive(extension,"psd") ||
|
||||
acceptsMovieExtension(extension);
|
||||
}
|
||||
public:
|
||||
virtual const char* className() const { return "Default Quicktime Image Reader/Writer"; }
|
||||
|
||||
virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options*) const
|
||||
{
|
||||
std::string ext = osgDB::getLowerCaseFileExtension(file);
|
||||
if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
|
||||
virtual bool acceptsMovieExtension(const std::string& extension) const
|
||||
{
|
||||
return osgDB::equalCaseInsensitive(extension,"mov") ||
|
||||
osgDB::equalCaseInsensitive(extension,"mpg") ||
|
||||
osgDB::equalCaseInsensitive(extension,"mpv") ||
|
||||
osgDB::equalCaseInsensitive(extension,"mp4") ||
|
||||
osgDB::equalCaseInsensitive(extension,"m4v") ||
|
||||
osgDB::equalCaseInsensitive(extension,"dv") ||
|
||||
osgDB::equalCaseInsensitive(extension,"avi") ||
|
||||
osgDB::equalCaseInsensitive(extension,"swf");
|
||||
}
|
||||
|
||||
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))
|
||||
virtual bool acceptsExtension(const std::string& extension) const
|
||||
{
|
||||
// this should be the only image importer required on the Mac
|
||||
// dont know what else it supports, but these will do
|
||||
return
|
||||
/*osgDB::equalCaseInsensitive(extension,"rgb") ||
|
||||
osgDB::equalCaseInsensitive(extension,"rgba") ||
|
||||
osgDB::equalCaseInsensitive(extension,"jpg") ||
|
||||
osgDB::equalCaseInsensitive(extension,"jpeg") ||
|
||||
osgDB::equalCaseInsensitive(extension,"tif") ||
|
||||
osgDB::equalCaseInsensitive(extension,"tiff") ||
|
||||
osgDB::equalCaseInsensitive(extension,"gif") ||
|
||||
osgDB::equalCaseInsensitive(extension,"png") ||
|
||||
osgDB::equalCaseInsensitive(extension,"pict") ||
|
||||
osgDB::equalCaseInsensitive(extension,"pct") ||
|
||||
osgDB::equalCaseInsensitive(extension,"tga") ||
|
||||
osgDB::equalCaseInsensitive(extension,"psd") ||
|
||||
*/
|
||||
acceptsMovieExtension(extension);
|
||||
}
|
||||
|
||||
virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options*) const
|
||||
{
|
||||
|
||||
// ricky
|
||||
// If using only the QuicktimeImageStream class for the movies, you can comment
|
||||
// out this line, as the init function is called inside the QTImageStream
|
||||
// ctor.
|
||||
// It is left here for compatibility with the original plugin, to handle
|
||||
// regular 2D images as well.
|
||||
initQuicktime();
|
||||
|
||||
std::string ext = osgDB::getLowerCaseFileExtension(file);
|
||||
if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
|
||||
|
||||
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.
|
||||
QuicktimeImageStream* moov = new QuicktimeImageStream(fileName);
|
||||
// moov->play();
|
||||
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
|
||||
// an image was monochrome. So it will waste texture memory unless it gets a monochrome hint.
|
||||
|
||||
unsigned char *pixels = LoadBufferFromDarwinPath ( fileName.c_str(), &origWidth,&origHeight,&origDepth,
|
||||
&buffWidth,&buffHeight,
|
||||
&buffDepth);
|
||||
|
||||
// IMPORTANT -
|
||||
// origDepth in BYTES, buffDepth in BITS
|
||||
if (pixels == 0)
|
||||
{
|
||||
osg::notify(osg::WARN) << "LoadBufferFromDarwinPath failed " << fileName.c_str() << QTfailureMessage() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int pixelFormat;
|
||||
|
||||
switch(origDepth)
|
||||
{
|
||||
case 1 :
|
||||
pixelFormat = GL_RGB;
|
||||
break;
|
||||
case 2 :
|
||||
pixelFormat = GL_LUMINANCE_ALPHA;
|
||||
break;
|
||||
case 3 :
|
||||
pixelFormat = GL_RGB;
|
||||
break;
|
||||
case 4 :
|
||||
pixelFormat = GL_RGBA;
|
||||
break;
|
||||
default :
|
||||
osg::notify(osg::WARN) << "Unknown file type in " << fileName.c_str() << " with " << origDepth << std::endl;
|
||||
pixelFormat = (GLenum)-1;
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
unsigned char *srcp=pixels, *dstp=pixels;
|
||||
|
||||
int i, j;
|
||||
|
||||
// swizzle entire image in-place
|
||||
unsigned char r, g, b, a;
|
||||
for (i=0; i<buffHeight; i++ ) {
|
||||
|
||||
switch (origDepth)
|
||||
{
|
||||
// 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->play();
|
||||
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
|
||||
// an image was monochrome. So it will waste texture memory unless it gets a monochrome hint.
|
||||
|
||||
unsigned char *pixels = LoadBufferFromDarwinPath ( fileName.c_str(), &origWidth,&origHeight,&origDepth,
|
||||
&buffWidth,&buffHeight,
|
||||
&buffDepth);
|
||||
|
||||
// IMPORTANT -
|
||||
// origDepth in BYTES, buffDepth in BITS
|
||||
|
||||
if (pixels == 0) {
|
||||
osg::notify(osg::WARN) << "LoadBufferFromDarwinPath failed " << fileName.c_str() << QTfailureMessage() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int pixelFormat;
|
||||
|
||||
switch(origDepth) {
|
||||
case 1 :
|
||||
pixelFormat = GL_RGB;
|
||||
break;
|
||||
case 2 :
|
||||
pixelFormat = GL_LUMINANCE_ALPHA;
|
||||
break;
|
||||
case 3 :
|
||||
pixelFormat = GL_RGB;
|
||||
break;
|
||||
case 4 :
|
||||
pixelFormat = GL_RGBA;
|
||||
break;
|
||||
default :
|
||||
osg::notify(osg::WARN) << "Unknown file type in " << fileName.c_str() << " with " << origDepth << std::endl;
|
||||
pixelFormat = (GLenum)-1;
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
unsigned char *srcp=pixels, *dstp=pixels;
|
||||
|
||||
int i, j;
|
||||
|
||||
// swizzle entire image in-place
|
||||
unsigned char r, g, b, a;
|
||||
for (i=0; i<buffHeight; i++ ) {
|
||||
|
||||
switch (origDepth) {
|
||||
/*
|
||||
since 8-bit tgas will get expanded into colour, have to use RGB code for 8-bit images
|
||||
|
||||
case 1 :
|
||||
for (j=0; j<buffWidth; j++ ) {
|
||||
dstp[0]=srcp[2];
|
||||
srcp+=4;
|
||||
dstp++;
|
||||
}
|
||||
break;
|
||||
*/
|
||||
case 2 :
|
||||
for (j=0; j<buffWidth; j++ ) {
|
||||
dstp[1]=srcp[0];
|
||||
dstp[0]=srcp[2];
|
||||
srcp+=4;
|
||||
dstp+=2;
|
||||
}
|
||||
break;
|
||||
case 1 :
|
||||
case 3 :
|
||||
for (j=0; j<buffWidth; j++ ) {
|
||||
dstp[0]=srcp[1];
|
||||
dstp[1]=srcp[2];
|
||||
dstp[2]=srcp[3];
|
||||
srcp+=4;
|
||||
dstp+=3;
|
||||
}
|
||||
break;
|
||||
case 4 :
|
||||
for (j=0; j<buffWidth; j++ ) {
|
||||
r=srcp[1];
|
||||
g=srcp[2];
|
||||
b=srcp[3];
|
||||
a=srcp[0];
|
||||
|
||||
dstp[0]=r;
|
||||
dstp[1]=g;
|
||||
dstp[2]=b;
|
||||
dstp[3]=a;
|
||||
|
||||
srcp+=4;
|
||||
dstp+=4;
|
||||
}
|
||||
break;
|
||||
default :
|
||||
// osg::notify(osg::WARN) << "ERROR IN RETURNED PIXEL DEPTH, CANNOT COPE" << std::endl;
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
since 8-bit tgas will get expanded into colour, have to use RGB code for 8-bit images
|
||||
|
||||
Image* image = new Image();
|
||||
image->setFileName(fileName.c_str());
|
||||
image->setImage(buffWidth,buffHeight,1,
|
||||
buffDepth >> 3,
|
||||
pixelFormat,
|
||||
GL_UNSIGNED_BYTE,
|
||||
pixels,
|
||||
osg::Image::USE_NEW_DELETE );
|
||||
|
||||
notify(INFO) << "image read ok "<<buffWidth<<" "<<buffHeight<<std::endl;
|
||||
return image;
|
||||
}
|
||||
|
||||
virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options*) const
|
||||
{
|
||||
std::string ext = osgDB::getFileExtension(fileName);
|
||||
if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
|
||||
|
||||
//Buidl map of extension <-> osFileTypes
|
||||
std::map<std::string, OSType> extmap;
|
||||
|
||||
extmap.insert(std::pair<std::string, OSType>("jpg", kQTFileTypeJPEG));
|
||||
extmap.insert(std::pair<std::string, OSType>("jpeg", kQTFileTypeJPEG));
|
||||
extmap.insert(std::pair<std::string, OSType>("bmp", kQTFileTypeBMP));
|
||||
extmap.insert(std::pair<std::string, OSType>("tif", kQTFileTypeTIFF));
|
||||
extmap.insert(std::pair<std::string, OSType>("tiff", kQTFileTypeTIFF));
|
||||
extmap.insert(std::pair<std::string, OSType>("png", kQTFileTypePNG));
|
||||
extmap.insert(std::pair<std::string, OSType>("gif", kQTFileTypeGIF));
|
||||
extmap.insert(std::pair<std::string, OSType>("psd", kQTFileTypePhotoShop));
|
||||
// extmap.insert(std::pair<std::string, OSType>("tga", kQTFileTypeTargaImage));
|
||||
extmap.insert(std::pair<std::string, OSType>("sgi", kQTFileTypeSGIImage));
|
||||
extmap.insert(std::pair<std::string, OSType>("rgb", kQTFileTypeSGIImage));
|
||||
extmap.insert(std::pair<std::string, OSType>("rgba", kQTFileTypeSGIImage));
|
||||
|
||||
std::map<std::string, OSType>::iterator cur = extmap.find(ext);
|
||||
|
||||
// can not handle this type of file, perhaps a movie?
|
||||
if (cur == extmap.end())
|
||||
return WriteResult::FILE_NOT_HANDLED;
|
||||
|
||||
OSType desiredType = cur->second;
|
||||
GraphicsExportComponent geComp = NULL;
|
||||
case 1 :
|
||||
for (j=0; j<buffWidth; j++ ) {
|
||||
dstp[0]=srcp[2];
|
||||
srcp+=4;
|
||||
dstp++;
|
||||
}
|
||||
break;
|
||||
*/
|
||||
case 2 :
|
||||
for (j=0; j<buffWidth; j++ ) {
|
||||
dstp[1]=srcp[0];
|
||||
dstp[0]=srcp[2];
|
||||
srcp+=4;
|
||||
dstp+=2;
|
||||
}
|
||||
break;
|
||||
|
||||
OSErr err = OpenADefaultComponent(GraphicsExporterComponentType, desiredType, &geComp);
|
||||
|
||||
case 1 :
|
||||
case 3 :
|
||||
for (j=0; j<buffWidth; j++ ) {
|
||||
dstp[0]=srcp[1];
|
||||
dstp[1]=srcp[2];
|
||||
dstp[2]=srcp[3];
|
||||
srcp+=4;
|
||||
dstp+=3;
|
||||
}
|
||||
break;
|
||||
case 4 :
|
||||
for (j=0; j<buffWidth; j++ ) {
|
||||
r=srcp[1];
|
||||
g=srcp[2];
|
||||
b=srcp[3];
|
||||
a=srcp[0];
|
||||
|
||||
dstp[0]=r;
|
||||
dstp[1]=g;
|
||||
dstp[2]=b;
|
||||
dstp[3]=a;
|
||||
|
||||
srcp+=4;
|
||||
dstp+=4;
|
||||
}
|
||||
break;
|
||||
default :
|
||||
// osg::notify(osg::WARN) << "ERROR IN RETURNED PIXEL DEPTH, CANNOT COPE" << std::endl;
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Image* image = new Image();
|
||||
image->setFileName(fileName.c_str());
|
||||
image->setImage(buffWidth,buffHeight,1,
|
||||
buffDepth >> 3,
|
||||
pixelFormat,
|
||||
GL_UNSIGNED_BYTE,
|
||||
pixels,
|
||||
osg::Image::USE_NEW_DELETE );
|
||||
|
||||
notify(DEBUG_INFO) << "image read ok "<<buffWidth<<" "<<buffHeight<<std::endl;
|
||||
return image;
|
||||
}
|
||||
|
||||
virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options*) const
|
||||
{
|
||||
std::string ext = osgDB::getFileExtension(fileName);
|
||||
if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
|
||||
|
||||
initQuicktime();
|
||||
|
||||
//Buidl map of extension <-> osFileTypes
|
||||
std::map<std::string, OSType> extmap;
|
||||
|
||||
extmap.insert(std::pair<std::string, OSType>("jpg", kQTFileTypeJPEG));
|
||||
extmap.insert(std::pair<std::string, OSType>("jpeg", kQTFileTypeJPEG));
|
||||
extmap.insert(std::pair<std::string, OSType>("bmp", kQTFileTypeBMP));
|
||||
extmap.insert(std::pair<std::string, OSType>("tif", kQTFileTypeTIFF));
|
||||
extmap.insert(std::pair<std::string, OSType>("tiff", kQTFileTypeTIFF));
|
||||
extmap.insert(std::pair<std::string, OSType>("png", kQTFileTypePNG));
|
||||
extmap.insert(std::pair<std::string, OSType>("gif", kQTFileTypeGIF));
|
||||
extmap.insert(std::pair<std::string, OSType>("psd", kQTFileTypePhotoShop));
|
||||
// extmap.insert(std::pair<std::string, OSType>("tga", kQTFileTypeTargaImage));
|
||||
extmap.insert(std::pair<std::string, OSType>("sgi", kQTFileTypeSGIImage));
|
||||
extmap.insert(std::pair<std::string, OSType>("rgb", kQTFileTypeSGIImage));
|
||||
extmap.insert(std::pair<std::string, OSType>("rgba", kQTFileTypeSGIImage));
|
||||
|
||||
std::map<std::string, OSType>::iterator cur = extmap.find(ext);
|
||||
|
||||
// can not handle this type of file, perhaps a movie?
|
||||
if (cur == extmap.end())
|
||||
return WriteResult::FILE_NOT_HANDLED;
|
||||
|
||||
OSType desiredType = cur->second;
|
||||
GraphicsExportComponent geComp = NULL;
|
||||
|
||||
OSErr err = OpenADefaultComponent(GraphicsExporterComponentType, desiredType, &geComp);
|
||||
|
||||
if (err != noErr) {
|
||||
osg::notify(osg::WARN) << "ReaderWriterQT: could not open Graphics epxorter for type " << ext << ", Err: " << err << std::endl;
|
||||
return WriteResult::FILE_NOT_HANDLED;
|
||||
}
|
||||
|
||||
GWorldPtr gw = NULL;
|
||||
|
||||
// we are converting the images back to 32bit, it seems, that quicktime can't handle others
|
||||
|
||||
unsigned long desiredPixelFormat = k32ARGBPixelFormat;
|
||||
|
||||
|
||||
|
||||
// we need to swizzle the colours again :)
|
||||
unsigned int numBytes = img.computeNumComponents(img.getPixelFormat());
|
||||
|
||||
unsigned int buffWidth = img.s();
|
||||
unsigned int buffHeight = img.t();
|
||||
char * pixels = (char*) malloc(buffHeight * buffWidth * 4);
|
||||
|
||||
|
||||
|
||||
const unsigned char *srcp = img.data();
|
||||
char *dstp=pixels;
|
||||
unsigned int i, j;
|
||||
for (i=0; i<buffHeight; i++ ) {
|
||||
|
||||
switch (numBytes) {
|
||||
case 1 :
|
||||
dstp[0] = 0;
|
||||
dstp[1] = srcp[0];
|
||||
dstp[2] = srcp[0];
|
||||
dstp[3] = srcp[0];
|
||||
srcp+=1;
|
||||
dstp+=4;
|
||||
|
||||
break;
|
||||
case 3 :
|
||||
for (j=0; j<buffWidth; j++ ) {
|
||||
dstp[0]=0;
|
||||
dstp[1]=srcp[0];
|
||||
dstp[2]=srcp[1];
|
||||
dstp[3]=srcp[2];
|
||||
|
||||
srcp+=3;
|
||||
dstp+=4;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4 :
|
||||
for (j=0; j<buffWidth; j++ ) {
|
||||
// shift from RGBA to ARGB
|
||||
dstp[0]=srcp[3];
|
||||
dstp[1]=srcp[0];
|
||||
dstp[2]=srcp[1];
|
||||
dstp[3]=srcp[2];
|
||||
|
||||
srcp+=4;
|
||||
dstp+=4;
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
// osg::notify(osg::WARN) << "ERROR IN RETURNED PIXEL DEPTH, CANNOT COPE" << std::endl;
|
||||
return WriteResult::ERROR_IN_WRITING_FILE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Flip the image
|
||||
unsigned imageSize = buffWidth*buffHeight*4;
|
||||
char *tBuffer = (char*)malloc((size_t)imageSize);
|
||||
unsigned int rowBytes = buffWidth * 4;
|
||||
for (i = 0, j = imageSize - rowBytes; i < imageSize; i += rowBytes, j -= rowBytes)
|
||||
memcpy( &tBuffer[j], &pixels[i], (size_t)rowBytes );
|
||||
|
||||
memcpy(pixels, tBuffer, (size_t)imageSize);
|
||||
free(tBuffer);
|
||||
|
||||
FSSpec* fileSpec = NULL;
|
||||
|
||||
try {
|
||||
Rect bounds;
|
||||
SetRect(&bounds, 0,0, img.s(), img.t());
|
||||
|
||||
err = QTNewGWorldFromPtr(&gw, desiredPixelFormat, &bounds, 0,0,0, pixels, buffWidth*4);
|
||||
if (err != noErr) {
|
||||
osg::notify(osg::WARN) << "ReaderWriterQT: could not create gworld for type " << ext << ", Err: " << err << std::endl;
|
||||
throw err;
|
||||
}
|
||||
|
||||
// create a dummy file at location
|
||||
FILE *fp = fopen(fileName.c_str(), "wb");
|
||||
if (!fp) {
|
||||
osg::notify(osg::WARN) << "ReaderWriterQT: could not create file!" << std::endl;
|
||||
throw err;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
// get an FSSpec to the file, so quicktime can handle the file.
|
||||
fileSpec = darwinPathToFSSpec( const_cast<char*>(fileName.c_str()) );
|
||||
if (fileSpec == NULL) {
|
||||
osg::notify(osg::WARN) << "ReaderWriterQT: could not get FSSpec" << std::endl;
|
||||
throw err;
|
||||
}
|
||||
|
||||
err = GraphicsExportSetInputGWorld(geComp, gw);
|
||||
if (err != noErr) {
|
||||
osg::notify(osg::WARN) << "ReaderWriterQT: could not set input gworld for type " << ext << ", Err: " << err << std::endl;
|
||||
throw err;
|
||||
}
|
||||
|
||||
err = GraphicsExportSetOutputFile(geComp, fileSpec);
|
||||
if (err != noErr) {
|
||||
osg::notify(osg::WARN) << "ReaderWriterQT: could not set output file for type " << ext << ", Err: " << err << std::endl;
|
||||
throw err;
|
||||
}
|
||||
|
||||
// Set the compression quality (needed for JPEG, not necessarily for other formats)
|
||||
if (desiredType == kQTFileTypeJPEG) {
|
||||
err = GraphicsExportSetCompressionQuality(geComp, codecLosslessQuality);
|
||||
if (err != noErr) {
|
||||
osg::notify(osg::WARN) << "ReaderWriterQT: could not open Graphics epxorter for type " << ext << ", Err: " << err << std::endl;
|
||||
return WriteResult::FILE_NOT_HANDLED;
|
||||
osg::notify(osg::WARN) << "ReaderWriterQT: could not set compression for type " << ext << ", Err: " << err << std::endl;
|
||||
throw err;
|
||||
}
|
||||
|
||||
CGContextRef cg_context = NULL;
|
||||
|
||||
// we are converting the images back to 32bit, it seems, that quicktime can't handle others
|
||||
// unsigned long desiredPixelFormat = k32ARGBPixelFormat;
|
||||
|
||||
|
||||
|
||||
// we need to swizzle the colours again :)
|
||||
unsigned int numBytes = img.computeNumComponents(img.getPixelFormat());
|
||||
}
|
||||
|
||||
unsigned int buffWidth = img.s();
|
||||
unsigned int buffHeight = img.t();
|
||||
char * pixels = (char*) malloc(buffHeight * buffWidth * 4);
|
||||
|
||||
|
||||
|
||||
const unsigned char *srcp = img.data();
|
||||
char *dstp=pixels;
|
||||
unsigned int i, j;
|
||||
for (i=0; i<buffHeight; i++ ) {
|
||||
|
||||
switch (numBytes) {
|
||||
case 1 :
|
||||
dstp[0] = 0xFFFFFFFF;
|
||||
dstp[1] = srcp[0];
|
||||
dstp[2] = srcp[0];
|
||||
dstp[3] = srcp[0];
|
||||
srcp+=1;
|
||||
dstp+=4;
|
||||
|
||||
break;
|
||||
case 3 :
|
||||
for (j=0; j<buffWidth; j++ ) {
|
||||
dstp[0]=0xFFFFFFFF;
|
||||
dstp[1]=srcp[0];
|
||||
dstp[2]=srcp[1];
|
||||
dstp[3]=srcp[2];
|
||||
if(32 == numBytes)
|
||||
{
|
||||
err = GraphicsExportSetDepth( geComp,
|
||||
k32ARGBPixelFormat ); // depth
|
||||
}
|
||||
// else k24RGBPixelFormat???
|
||||
|
||||
srcp+=3;
|
||||
dstp+=4;
|
||||
}
|
||||
break;
|
||||
case 4 :
|
||||
for (j=0; j<buffWidth; j++ ) {
|
||||
// shift from RGBA to ARGB
|
||||
dstp[0]=srcp[3];
|
||||
dstp[1]=srcp[0];
|
||||
dstp[2]=srcp[1];
|
||||
dstp[3]=srcp[2];
|
||||
|
||||
srcp+=4;
|
||||
dstp+=4;
|
||||
}
|
||||
break;
|
||||
default :
|
||||
// osg::notify(osg::WARN) << "ERROR IN RETURNED PIXEL DEPTH, CANNOT COPE" << std::endl;
|
||||
return WriteResult::ERROR_IN_WRITING_FILE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Flip the image
|
||||
unsigned imageSize = buffWidth*buffHeight*4;
|
||||
char *tBuffer = (char*)malloc((size_t)imageSize);
|
||||
unsigned int rowBytes = buffWidth * 4;
|
||||
for (i = 0, j = imageSize - rowBytes; i < imageSize; i += rowBytes, j -= rowBytes)
|
||||
memcpy( &tBuffer[j], &pixels[i], (size_t)rowBytes );
|
||||
// do the export
|
||||
err = GraphicsExportDoExport(geComp, NULL);
|
||||
if (err != noErr) {
|
||||
osg::notify(osg::WARN) << "ReaderWriterQT: could not save file for type " << ext << ", Err: " << err << std::endl;
|
||||
throw err;
|
||||
}
|
||||
|
||||
memcpy(pixels, tBuffer, (size_t)imageSize);
|
||||
free(tBuffer);
|
||||
|
||||
FSSpec* fileSpec = NULL;
|
||||
if (geComp != NULL)
|
||||
CloseComponent(geComp);
|
||||
|
||||
try {
|
||||
// I'm not sure what the bitsPerComponet should be. For RGB and RGBA in 24 and 32 bit pixel formats, it's 8.
|
||||
// Since the code above put everything in ARGB, I guess I can hardcode everything.
|
||||
cg_context = CGBitmapContextCreate(pixels, img.s(), img.t(), 8, buffWidth*4,
|
||||
CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB),
|
||||
kCGImageAlphaPremultipliedFirst // The code above put everything in ARGB
|
||||
);
|
||||
if (cg_context == NULL) {
|
||||
osg::notify(osg::WARN) << "ReaderWriterQT: could not create gworld for type " << ext << ", Err: " << err << std::endl;
|
||||
// This seems really messed up, but throwing Sin16's seems really messed up in general.
|
||||
throw 0;
|
||||
}
|
||||
DisposeGWorld (gw);
|
||||
if (fileSpec != NULL ) free(fileSpec);
|
||||
if (pixels) free(pixels);
|
||||
|
||||
return WriteResult::FILE_SAVED;
|
||||
}
|
||||
|
||||
|
||||
catch (...) {
|
||||
|
||||
if (geComp != NULL) CloseComponent(geComp);
|
||||
if (gw != NULL) DisposeGWorld (gw);
|
||||
if (fileSpec != NULL ) free(fileSpec);
|
||||
if (pixels) free(pixels);
|
||||
|
||||
return WriteResult::ERROR_IN_WRITING_FILE;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// create a dummy file at location
|
||||
FILE *fp = fopen(fileName.c_str(), "wb");
|
||||
if (!fp) {
|
||||
osg::notify(osg::WARN) << "ReaderWriterQT: could not create file!" << std::endl;
|
||||
throw err;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
// get an FSSpec to the file, so quicktime can handle the file.
|
||||
fileSpec = darwinPathToFSSpec( const_cast<char*>(fileName.c_str()) );
|
||||
if (fileSpec == NULL) {
|
||||
osg::notify(osg::WARN) << "ReaderWriterQT: could not get FSSpec" << std::endl;
|
||||
throw err;
|
||||
}
|
||||
|
||||
err = GraphicsExportSetInputCGBitmapContext(geComp, cg_context);
|
||||
if (err != noErr) {
|
||||
osg::notify(osg::WARN) << "ReaderWriterQT: could not set input gworld for type " << ext << ", Err: " << err << std::endl;
|
||||
throw err;
|
||||
}
|
||||
|
||||
err = GraphicsExportSetOutputFile(geComp, fileSpec);
|
||||
if (err != noErr) {
|
||||
osg::notify(osg::WARN) << "ReaderWriterQT: could not set output file for type " << ext << ", Err: " << err << std::endl;
|
||||
throw err;
|
||||
}
|
||||
|
||||
// Set the compression quality (needed for JPEG, not necessarily for other formats)
|
||||
if (desiredType == kQTFileTypeJPEG) {
|
||||
err = GraphicsExportSetCompressionQuality(geComp, codecLosslessQuality);
|
||||
if (err != noErr) {
|
||||
osg::notify(osg::WARN) << "ReaderWriterQT: could not set compression for type " << ext << ", Err: " << err << std::endl;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
if(32 == numBytes)
|
||||
{
|
||||
err = GraphicsExportSetDepth( geComp,
|
||||
k32ARGBPixelFormat ); // depth
|
||||
}
|
||||
// else k24RGBPixelFormat???
|
||||
|
||||
// do the export
|
||||
err = GraphicsExportDoExport(geComp, NULL);
|
||||
if (err != noErr) {
|
||||
osg::notify(osg::WARN) << "ReaderWriterQT: could not save file for type " << ext << ", Err: " << err << std::endl;
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (geComp != NULL)
|
||||
CloseComponent(geComp);
|
||||
|
||||
CGContextRelease(cg_context);
|
||||
if (fileSpec != NULL ) free(fileSpec);
|
||||
if (pixels) free(pixels);
|
||||
|
||||
return WriteResult::FILE_SAVED;
|
||||
}
|
||||
|
||||
|
||||
catch (...) {
|
||||
|
||||
if (geComp != NULL) CloseComponent(geComp);
|
||||
if (cg_context != NULL) CGContextRelease(cg_context);
|
||||
if (fileSpec != NULL ) free(fileSpec);
|
||||
if (pixels) free(pixels);
|
||||
|
||||
return WriteResult::ERROR_IN_WRITING_FILE;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user