Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifndef x64
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "texception.h"
Toshihiro Shimizu 890ddd
#include "tsound.h"
Toshihiro Shimizu 890ddd
#include "tconvert.h"
Toshihiro Shimizu 890ddd
#include "tpropertytype.h"
Toshihiro Shimizu 890ddd
#include "timageinfo.h"
Toshihiro Shimizu 890ddd
#include "tlevel_io.h"
Toshihiro Shimizu 890ddd
#include "../avi/tiio_avi.h"
Toshihiro Shimizu 890ddd
#include "trasterimage.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tiio_mov.h"
Toshihiro Shimizu 890ddd
#include "movsettings.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace  stuff
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Shinya Kitaoka 3bfa54
const std::string firstFrameKey = "frst";			// First frame atom id
Toshihiro Shimizu 890ddd
const int firstFrameKeySize = 4 * sizeof(char); //
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class QuickTimeCleanUp;
Toshihiro Shimizu 890ddd
class QuickTimeStuff
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	static QuickTimeStuff *instance()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if (!m_singleton)
Toshihiro Shimizu 890ddd
			m_singleton = new QuickTimeStuff();
Toshihiro Shimizu 890ddd
		return m_singleton;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	OSErr getStatus() { return m_status; }
Toshihiro Shimizu 890ddd
	~QuickTimeStuff()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Toshihiro Shimizu 890ddd
	QuickTimeStuff() : m_status(noErr)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_status = InitializeQTML(0);
Toshihiro Shimizu 890ddd
		EnterMovies();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	static QuickTimeStuff *m_singleton;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	OSErr m_status;
Toshihiro Shimizu 890ddd
	friend class QuickTimeCleanUp; //questa DEVE essere friend, cosi' posso controllare direttamente
Toshihiro Shimizu 890ddd
								   //lo stato del singleton.
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class QuickTimeCleanUp
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	QuickTimeCleanUp() {}
Toshihiro Shimizu 890ddd
	~QuickTimeCleanUp()
Toshihiro Shimizu 890ddd
	{ /*
Toshihiro Shimizu 890ddd
                        Nel caso si arrivasse qui senza il singleton instanziato, e si facesse direttamente
Toshihiro Shimizu 890ddd
                        'delete QuickTimeStuff::instance();' Quicktime non farebbe in tempo a terminare le
Toshihiro Shimizu 890ddd
                        sue routine di inizializzazione (che sono ANCHE su altri thread) e la chiamata a
Toshihiro Shimizu 890ddd
                        TerminateQTML() causerebbe un crash
Toshihiro Shimizu 890ddd
                        */
Toshihiro Shimizu 890ddd
		if (QuickTimeStuff::m_singleton)
Toshihiro Shimizu 890ddd
			delete QuickTimeStuff::m_singleton;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
QuickTimeCleanUp cleanUp;
Toshihiro Shimizu 890ddd
QuickTimeStuff *QuickTimeStuff::m_singleton = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
enum QTLibError {
Toshihiro Shimizu 890ddd
	QTNoError = 0x0000,
Toshihiro Shimizu 890ddd
	QTNotInstalled,
Toshihiro Shimizu 890ddd
	QTUnknownError,
Toshihiro Shimizu 890ddd
	QTUnableToOpenFile,
Toshihiro Shimizu 890ddd
	QTCantCreateFile,
Toshihiro Shimizu 890ddd
	QTUnableToGetCompressorNames,
Toshihiro Shimizu 890ddd
	QTUnableToCreateResource,
Toshihiro Shimizu 890ddd
	QTUnableToUpdateMovie,
Toshihiro Shimizu 890ddd
	QTBadTimeValue,
Toshihiro Shimizu 890ddd
	QTUnableToDoMovieTask,
Toshihiro Shimizu 890ddd
	QTUnableToSetTimeValue,
Toshihiro Shimizu 890ddd
	QTUnableToSetMovieGWorld,
Toshihiro Shimizu 890ddd
	QTUnableToSetMovieBox,
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
string buildQTErrorString(int ec)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	switch (ec) {
Toshihiro Shimizu 890ddd
	case QTNotInstalled:
Toshihiro Shimizu 890ddd
		return "Can't create; ensure that quicktime is correctly installed on your machine";
Toshihiro Shimizu 890ddd
	case QTUnknownError:
Toshihiro Shimizu 890ddd
		return "Unknown error";
Toshihiro Shimizu 890ddd
	case QTUnableToOpenFile:
Toshihiro Shimizu 890ddd
		return "can't open file";
Toshihiro Shimizu 890ddd
	case QTCantCreateFile:
Toshihiro Shimizu 890ddd
		return "can't create movie";
Toshihiro Shimizu 890ddd
	case QTUnableToGetCompressorNames:
Toshihiro Shimizu 890ddd
		return "unable to get compressor name";
Toshihiro Shimizu 890ddd
	case QTUnableToCreateResource:
Toshihiro Shimizu 890ddd
		return "can't create resource";
Toshihiro Shimizu 890ddd
	case QTUnableToUpdateMovie:
Toshihiro Shimizu 890ddd
		return "unable to update movie";
Toshihiro Shimizu 890ddd
	case QTBadTimeValue:
Toshihiro Shimizu 890ddd
		return "bad frame number";
Toshihiro Shimizu 890ddd
	case QTUnableToDoMovieTask:
Toshihiro Shimizu 890ddd
		return "unable to do movie task";
Toshihiro Shimizu 890ddd
	case QTUnableToSetTimeValue:
Toshihiro Shimizu 890ddd
		return "unable to set time value";
Toshihiro Shimizu 890ddd
	case QTUnableToSetMovieGWorld:
Toshihiro Shimizu 890ddd
		return "unable to set movie graphic world";
Toshihiro Shimizu 890ddd
	case QTUnableToSetMovieBox:
Toshihiro Shimizu 890ddd
		return "unable to set movie box";
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	default: {
Toshihiro Shimizu 890ddd
		return "unknown error ('" + toString(ec) + "')";
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline LPSTR AtlW2AHelper(LPSTR lpa, LPCWSTR lpw, int nChars, UINT acp)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(lpw != NULL);
Toshihiro Shimizu 890ddd
	assert(lpa != NULL);
Toshihiro Shimizu 890ddd
	// verify that no illegal character present
Toshihiro Shimizu 890ddd
	// since lpa was allocated based on the size of lpw
Toshihiro Shimizu 890ddd
	// don't worry about the number of chars
Toshihiro Shimizu 890ddd
	lpa[0] = '\0';
Toshihiro Shimizu 890ddd
	WideCharToMultiByte(acp, 0, lpw, -1, lpa, nChars, NULL, NULL);
Toshihiro Shimizu 890ddd
	return lpa;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline char *filePath2unichar(const TFilePath &path)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int _convert = 0;
Toshihiro Shimizu 890ddd
	std::wstring ws = path.getWideString();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	LPCWSTR lpw = ws.c_str();
Toshihiro Shimizu 890ddd
	char *name = NULL;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (lpw) {
Toshihiro Shimizu 890ddd
		_convert = (lstrlenW(lpw) + 1) * 2;
Toshihiro Shimizu 890ddd
		LPSTR pStr = new char[_convert];
Toshihiro Shimizu 890ddd
		name = AtlW2AHelper(pStr, lpw, _convert, 0);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	char *outName = new char[1024];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (QTMLGetCanonicalPathName(name, outName, 1024) == noErr) {
Toshihiro Shimizu 890ddd
		delete[] name;
Toshihiro Shimizu 890ddd
		return outName;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	delete[] outName;
Toshihiro Shimizu 890ddd
	return name;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TFilePath getLegalName(const TFilePath &name)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (QuickTimeStuff::instance()->getStatus() != noErr)
Toshihiro Shimizu 890ddd
		return name;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TFilePath legalName;
Toshihiro Shimizu 890ddd
	char outDir[1024];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TFilePath dirName(name.getParentDir());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	char dirNameFp[1024] = "";
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	OSErr err = QTMLGetCanonicalPathName(dirNameFp, outDir, 1024);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (err == noErr)
Toshihiro Shimizu 890ddd
		legalName = TFilePath(outDir) + name.withoutParentDir();
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		legalName = name;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return legalName;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
string long2fourchar(TINT32 fcc)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	string s;
Toshihiro Shimizu 890ddd
	s += (char((fcc & 0xff000000) >> 24));
Toshihiro Shimizu 890ddd
	s += (char((fcc & 0x00ff0000) >> 16));
Toshihiro Shimizu 890ddd
	s += (char((fcc & 0x0000ff00) >> 8));
Toshihiro Shimizu 890ddd
	s += (char((fcc & 0x000000ff) >> 0));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return s;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TimeScale frameRateToTimeScale(double frameRate)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return tround(frameRate * 100.0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 3bfa54
//const std::string CodecNamesId   = "PU_CodecName";
Shinya Kitaoka 3bfa54
//const std::string CodecQualityId = "PU_CodecQuality";
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} //namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool IsQuickTimeInstalled()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return QuickTimeStuff::instance()->getStatus() == noErr;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//  TImageWriterMov
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class TImageWriterMov : public TImageWriter
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	TImageWriterMov(const TFilePath &, int frameIndex, TLevelWriterMov *);
Toshihiro Shimizu 890ddd
	~TImageWriterMov() { m_lwm->release(); }
Toshihiro Shimizu 890ddd
	bool is64bitOutputSupported() { return false; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Toshihiro Shimizu 890ddd
	//not implemented
Toshihiro Shimizu 890ddd
	TImageWriterMov(const TImageWriterMov &);
Toshihiro Shimizu 890ddd
	TImageWriterMov &operator=(const TImageWriterMov &src);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	void save(const TImageP &);
Toshihiro Shimizu 890ddd
	int m_frameIndex;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Toshihiro Shimizu 890ddd
	TLevelWriterMov *m_lwm;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
//        TImageWriterMov
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TImageWriterMov::TImageWriterMov(const TFilePath &path, int frameIndex, TLevelWriterMov *lwm)
Toshihiro Shimizu 890ddd
	: TImageWriter(path), m_lwm(lwm), m_frameIndex(frameIndex)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_lwm->addRef();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
void copy(TRasterP rin, PixelXRGB *bufout, int lx, int ly)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TRaster32P rin32 = rin;
Toshihiro Shimizu 890ddd
	assert(rin32);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	PixelXRGB *rowout = &(bufout[(ly - 1) * lx]);
Toshihiro Shimizu 890ddd
	rin32->lock();
Toshihiro Shimizu 890ddd
	for (int y = 0; y < rin32->getLy(); y++) {
Toshihiro Shimizu 890ddd
		PixelXRGB *pixout = rowout;
Toshihiro Shimizu 890ddd
		TPixelRGBM32 *pixin = rin32->pixels(y);
Toshihiro Shimizu 890ddd
		TPixelRGBM32 *pixinEnd = pixin + rin32->getLx();
Toshihiro Shimizu 890ddd
		while (pixin < pixinEnd) {
Toshihiro Shimizu 890ddd
			pixout->x = pixin->m;
Toshihiro Shimizu 890ddd
			pixout->r = pixin->r;
Toshihiro Shimizu 890ddd
			pixout->g = pixin->g;
Toshihiro Shimizu 890ddd
			pixout->b = pixin->b;
Toshihiro Shimizu 890ddd
			pixout++;
Toshihiro Shimizu 890ddd
			pixin++;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		rowout -= lx;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	rin32->unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
/*
Shinya Kitaoka 3bfa54
TWriterInfo *TWriterInfoMov::create(const std::string &)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
return new TWriterInfoMov();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TWriterInfoMov::TWriterInfoMov(const TWriterInfoMov&src)
Toshihiro Shimizu 890ddd
               :TWriterInfo(src)
Toshihiro Shimizu 890ddd
               ,m_codecTable(src.m_codecTable)
Toshihiro Shimizu 890ddd
               ,m_qualityTable(src.m_qualityTable)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TWriterInfo *TWriterInfoMov::clone() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
return new TWriterInfoMov(*this);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
class MovWriterProperties : public TPropertyGroup {
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
  TEnumProperty m_codec;
Toshihiro Shimizu 890ddd
  TEnumProperty m_quality;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Tiio::TifWriterProperties::TifWriterProperties()
Toshihiro Shimizu 890ddd
                    : m_byteOrdering("Byte Order")
Toshihiro Shimizu 890ddd
                    , m_compressionType("Compression Type")
Toshihiro Shimizu 890ddd
                    , m_matte("Alpha Channel", true)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
    m_byteOrdering.addValue(L"IBM PC");
Toshihiro Shimizu 890ddd
    m_byteOrdering.addValue(L"Mac");
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Toshihiro Shimizu 890ddd
  m_byteOrdering.setValue(L"IBM PC");
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
  m_byteOrdering.setValue(L"Mac");
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  m_compressionType.addValue(L"NONE");
Toshihiro Shimizu 890ddd
  m_compressionType.addValue(L"LZW");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  bind(m_byteOrdering);
Toshihiro Shimizu 890ddd
  bind(m_matte);
Toshihiro Shimizu 890ddd
  bind(m_compressionType);
Toshihiro Shimizu 890ddd
  m_compressionType.setValue(L"LZW");
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
CodecType Tiio::MovWriterProperties::getCurrentCodec()const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
std::map<wstring, codectype="">::const_iterator it;</wstring,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
it = m_codecMap.find(m_codec.getValue());
Toshihiro Shimizu 890ddd
assert(it!=m_codecMap.end());
Toshihiro Shimizu 890ddd
return it->second;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
wstring Tiio::MovWriterProperties::getCurrentNameFromCodec(CodecType &cCodec)const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
std::map<wstring, codectype="">::const_iterator it;</wstring,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
for(it=m_codecMap.begin();it!=m_codecMap.end();++it)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
  CodecType tmp=it->second;
Toshihiro Shimizu 890ddd
  if(it->second==cCodec) break;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
assert(it!=m_codecMap.end());
Toshihiro Shimizu 890ddd
return it->first;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
wstring Tiio::MovWriterProperties::getCurrentQualityFromCodeQ(CodecQ &cCodecQ)const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
std::map<wstring, codecq="">::const_iterator it;</wstring,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
for(it=m_qualityMap.begin();it!=m_qualityMap.end();++it)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
  CodecQ tmp=it->second;
Toshihiro Shimizu 890ddd
  if(it->second==cCodecQ) break;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
assert(it!=m_qualityMap.end());
Toshihiro Shimizu 890ddd
return it->first;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
CodecQ Tiio::MovWriterProperties::getCurrentQuality() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
std::map<wstring, codecq="">::const_iterator it;</wstring,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
it = m_qualityMap.find(m_quality.getValue());
Toshihiro Shimizu 890ddd
assert(it!=m_qualityMap.end());
Toshihiro Shimizu 890ddd
return it->second;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
TPropertyGroup* Tiio::MovWriterProperties::clone() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
  MovWriterProperties*g = new MovWriterProperties();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	g->m_codec.setValue(m_codec.getValue());
Toshihiro Shimizu 890ddd
	g->m_quality.setValue(m_quality.getValue());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
return (TPropertyGroup*)g;  
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Tiio::MovWriterProperties::MovWriterProperties()
Toshihiro Shimizu 890ddd
//: m_codec("Codec")
Toshihiro Shimizu 890ddd
//, m_quality("Quality")
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (InitializeQTML(0) != noErr)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ComponentInstance ci = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
Toshihiro Shimizu 890ddd
	QTAtomContainer settings;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (SCGetSettingsAsAtomContainer(ci, &settings) != noErr)
Toshihiro Shimizu 890ddd
		assert(false);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	fromAtomsToProperties(settings, *this);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TImageWriterMov::save(const TImageP &img)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_lwm->save(img, m_frameIndex);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TLevelWriterMov::save(const TImageP &img, int frameIndex)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_firstFrame = tmin(frameIndex, m_firstFrame);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRasterImageP image(img);
Toshihiro Shimizu 890ddd
	if (!image)
Toshihiro Shimizu 890ddd
		throw TImageException(getFilePath(), "Unsupported image type");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int lx = image->getRaster()->getLx();
Toshihiro Shimizu 890ddd
	int ly = image->getRaster()->getLy();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int pixSize = image->getRaster()->getPixelSize();
Toshihiro Shimizu 890ddd
	if (pixSize != 4)
Toshihiro Shimizu 890ddd
		throw TImageException(getFilePath(), "Unsupported pixel type");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QMutexLocker sl(&m_mutex);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!m_videoTrack) {
Toshihiro Shimizu 890ddd
		if (!m_properties)
Toshihiro Shimizu 890ddd
			m_properties = new Tiio::MovWriterProperties();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		Tiio::MovWriterProperties *prop = (Tiio::MovWriterProperties *)(m_properties);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		QTAtomContainer atoms;
Toshihiro Shimizu 890ddd
		QTNewAtomContainer(&atoms);
Toshihiro Shimizu 890ddd
		fromPropertiesToAtoms(*prop, atoms);
Toshihiro Shimizu 890ddd
		m_ci = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
Toshihiro Shimizu 890ddd
		if (SCSetSettingsFromAtomContainer(m_ci, atoms) != noErr) {
Toshihiro Shimizu 890ddd
			CloseComponent(m_ci);
Toshihiro Shimizu 890ddd
			assert(!"cannot use that quickTime codec, use default");
Toshihiro Shimizu 890ddd
			m_ci = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		QTDisposeAtomContainer(atoms);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		Rect frame;
Toshihiro Shimizu 890ddd
		QDErr err;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (QuickTimeStuff::instance()->getStatus() != noErr) {
Toshihiro Shimizu 890ddd
			m_IOError = QTNotInstalled;
Toshihiro Shimizu 890ddd
			throw TImageException(m_path, buildQTErrorString(m_IOError));
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// First, set the movie's time scale to match a suitable multiple of m_frameRate.
Toshihiro Shimizu 890ddd
		// The timeScale will be used for both the movie and media.
Toshihiro Shimizu 890ddd
		TimeScale timeScale = ::frameRateToTimeScale(m_frameRate);
Toshihiro Shimizu 890ddd
		SetMovieTimeScale(m_movie, timeScale);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_videoTrack = NewMovieTrack(m_movie, FixRatio((short)lx, 1), FixRatio((short)ly, 1), kNoVolume);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if ((err = GetMoviesError() != noErr))
Toshihiro Shimizu 890ddd
			throw TImageException(getFilePath(), "can't create video track");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_videoMedia = NewTrackMedia(m_videoTrack, VideoMediaType, timeScale, 0, 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if ((err = GetMoviesError() != noErr))
Toshihiro Shimizu 890ddd
			throw TImageException(getFilePath(), "can't create video media");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		frame.left = 0;
Toshihiro Shimizu 890ddd
		frame.top = 0;
Toshihiro Shimizu 890ddd
		frame.right = lx;
Toshihiro Shimizu 890ddd
		frame.bottom = ly;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if ((err = NewGWorld(&(m_gworld), pixSize * 8, &frame, 0, 0, 0)) != noErr)
Toshihiro Shimizu 890ddd
			throw TImageException(getFilePath(), "can't create movie buffer");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		LockPixels(m_gworld->portPixMap);
Toshihiro Shimizu 890ddd
		/*
Toshihiro Shimizu 890ddd
    if ((err = ImageCodecGetMaxCompressionSize(Ci, m_gworld->portPixMap, &frame, 0, 
Toshihiro Shimizu 890ddd
                                               quality, codecType, anyCodec, 
Toshihiro Shimizu 890ddd
                                               &max_compressed_size))!=noErr)
Toshihiro Shimizu 890ddd
                                               throw TImageException(getFilePath(), "can't get max compression size");
Toshihiro Shimizu 890ddd
    */
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if ((err = MemError()) != noErr)
Toshihiro Shimizu 890ddd
			throw TImageException(getFilePath(), "can't allocate img handle");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_pixmap = GetGWorldPixMap(m_gworld);
Toshihiro Shimizu 890ddd
		if (!LockPixels(m_pixmap))
Toshihiro Shimizu 890ddd
			throw TImageException(getFilePath(), "can't lock pixels");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_buf = (PixelXRGB *)(*(m_pixmap))->baseAddr;
Toshihiro Shimizu 890ddd
		buf_lx = lx;
Toshihiro Shimizu 890ddd
		buf_ly = ly;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	OSErr err = noErr;
Toshihiro Shimizu 890ddd
	if ((err = BeginMediaEdits(m_videoMedia)) != noErr)
Toshihiro Shimizu 890ddd
		throw TImageException(getFilePath(), "can't begin edit video media");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Rect frame;
Toshihiro Shimizu 890ddd
	ImageDescriptionHandle img_descr = 0;
Toshihiro Shimizu 890ddd
	Handle compressedData = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	frame.left = 0;
Toshihiro Shimizu 890ddd
	frame.top = 0;
Toshihiro Shimizu 890ddd
	frame.right = lx;
Toshihiro Shimizu 890ddd
	frame.bottom = ly;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRasterP ras = image->getRaster();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	copy(ras, m_buf, buf_lx, buf_ly);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if ((err = SCCompressImage(m_ci,
Toshihiro Shimizu 890ddd
							   m_gworld->portPixMap,
Toshihiro Shimizu 890ddd
							   &frame,
Toshihiro Shimizu 890ddd
							   &img_descr,
Toshihiro Shimizu 890ddd
							   &compressedData)) != noErr)
Toshihiro Shimizu 890ddd
		throw TImageException(getFilePath(), "can't compress image");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	/*
Toshihiro Shimizu 890ddd
  if ((err = CompressImage(m_gworld->portPixMap, 
Toshihiro Shimizu 890ddd
  &frame, 
Toshihiro Shimizu 890ddd
  quality, codecType,
Toshihiro Shimizu 890ddd
  img_descr, compressed_data_ptr))!=noErr)
Toshihiro Shimizu 890ddd
  throw TImageException(getFilePath(), "can't compress image");
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TimeValue sampleTime;
Toshihiro Shimizu 890ddd
	if ((err = AddMediaSample(m_videoMedia, compressedData, 0,
Toshihiro Shimizu 890ddd
							  (*img_descr)->dataSize, 100,		  // 100 matches the length of 1 frame
Toshihiro Shimizu 890ddd
							  (SampleDescriptionHandle)img_descr, // in the movie/media's timeScale
Toshihiro Shimizu 890ddd
							  1, 0, &sampleTime)) != noErr)
Toshihiro Shimizu 890ddd
		throw TImageException(getFilePath(), "can't add image to movie media");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if ((err = EndMediaEdits(m_videoMedia)) != noErr)
Toshihiro Shimizu 890ddd
		throw TImageException(getFilePath(), "can't end edit media");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	DisposeHandle(compressedData);
Toshihiro Shimizu 890ddd
	DisposeHandle((Handle)img_descr);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_savedFrames.push_back(std::pair<int, timevalue="">(frameIndex, sampleTime));</int,>
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
//        TLevelWriterMov
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TLevelWriterMov::TLevelWriterMov(const TFilePath &path, TPropertyGroup *winfo)
Toshihiro Shimizu 890ddd
	: TLevelWriter(path, winfo), m_IOError(QTNoError), m_pixmap(0), m_gworld(0), m_videoMedia(0), m_soundMedia(0), m_videoTrack(0), m_soundTrack(0), m_movie(0), m_firstFrame((std::numeric_limits<int>::max)())</int>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_frameRate = 12.;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	char *pStr = filePath2unichar(m_path);
Toshihiro Shimizu 890ddd
	QDErr err;
Toshihiro Shimizu 890ddd
	FSSpec fspec;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if ((err = NativePathNameToFSSpec(pStr, &fspec, kFullNativePath)) != noErr) {
Toshihiro Shimizu 890ddd
		delete[] pStr;
Toshihiro Shimizu 890ddd
		pStr = 0;
Toshihiro Shimizu 890ddd
		m_IOError = QTUnableToOpenFile;
Toshihiro Shimizu 890ddd
		throw TImageException(m_path, buildQTErrorString(m_IOError));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	delete[] pStr;
Toshihiro Shimizu 890ddd
	pStr = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (err = CreateMovieFile(&fspec, 'TVOD', smCurrentScript,
Toshihiro Shimizu 890ddd
							  createMovieFileDeleteCurFile | createMovieFileDontCreateResFile,
Toshihiro Shimizu 890ddd
							  &(m_refNum), &(m_movie)) != noErr) {
Toshihiro Shimizu 890ddd
		m_IOError = QTCantCreateFile;
Toshihiro Shimizu 890ddd
		throw TImageException(m_path, buildQTErrorString(m_IOError));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Toshihiro Shimizu 890ddd
#define FailIf(cond, handler)                                 \
Toshihiro Shimizu 890ddd
	if (cond) {                                               \
Toshihiro Shimizu 890ddd
		DebugStr((ConstStr255Param) #cond " goto " #handler); \
Toshihiro Shimizu 890ddd
		goto handler;                                         \
Toshihiro Shimizu 890ddd
	} else                                                    \
Toshihiro Shimizu 890ddd
	0
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
#define FailIf(cond, handler) \
Toshihiro Shimizu 890ddd
	if (cond) {               \
Toshihiro Shimizu 890ddd
		goto handler;         \
Toshihiro Shimizu 890ddd
	} else                    \
Toshihiro Shimizu 890ddd
	0
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Toshihiro Shimizu 890ddd
#define FailWithAction(cond, action, handler)                 \
Toshihiro Shimizu 890ddd
	if (cond) {                                               \
Toshihiro Shimizu 890ddd
		DebugStr((ConstStr255Param) #cond " goto " #handler); \
Toshihiro Shimizu 890ddd
		{                                                     \
Toshihiro Shimizu 890ddd
			action;                                           \
Toshihiro Shimizu 890ddd
		}                                                     \
Toshihiro Shimizu 890ddd
		goto handler;                                         \
Toshihiro Shimizu 890ddd
	} else                                                    \
Toshihiro Shimizu 890ddd
	0
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
#define FailWithAction(cond, action, handler) \
Toshihiro Shimizu 890ddd
	if (cond) {                               \
Toshihiro Shimizu 890ddd
		{                                     \
Toshihiro Shimizu 890ddd
			action;                           \
Toshihiro Shimizu 890ddd
		}                                     \
Toshihiro Shimizu 890ddd
		goto handler;                         \
Toshihiro Shimizu 890ddd
	} else                                    \
Toshihiro Shimizu 890ddd
	0
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TLevelWriterMov::saveSoundTrack(TSoundTrack *st)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	OSErr myErr = noErr;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!st)
Toshihiro Shimizu 890ddd
		throw TException("null reference to soundtrack");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (st->getBitPerSample() != 16)
Toshihiro Shimizu 890ddd
		throw TImageException(m_path, "Only 16 bits per sample is supported");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_soundTrack == 0) {
Toshihiro Shimizu 890ddd
		m_soundTrack = NewMovieTrack(m_movie, 0, 0, kFullVolume);
Toshihiro Shimizu 890ddd
		myErr = GetMoviesError();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		FailIf(myErr != noErr, CompressErr);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_soundMedia = NewTrackMedia(m_soundTrack, SoundMediaType, st->getSampleRate(), NULL, 0); //track->rate >> 16
Toshihiro Shimizu 890ddd
		myErr = GetMoviesError();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		FailIf(myErr != noErr, Exit);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	SoundDescriptionV1Handle mySampleDesc;
Toshihiro Shimizu 890ddd
	Handle myDestHandle;
Toshihiro Shimizu 890ddd
	SoundComponentData sourceInfo;
Toshihiro Shimizu 890ddd
	SoundComponentData destInfo;
Toshihiro Shimizu 890ddd
	SoundConverter converter;
Toshihiro Shimizu 890ddd
	CompressionInfo compressionInfo;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	myDestHandle = NewHandle(0);
Toshihiro Shimizu 890ddd
	FailWithAction(myDestHandle == NULL, myErr = MemError(), NoDest);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	*myDestHandle = (char *)st->getRawData();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// start a media editing session
Toshihiro Shimizu 890ddd
	myErr = BeginMediaEdits(m_soundMedia);
Toshihiro Shimizu 890ddd
	FailIf(myErr != noErr, Exit);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	sourceInfo.flags = 0x0;
Toshihiro Shimizu 890ddd
	sourceInfo.format = kSoundNotCompressed;
Toshihiro Shimizu 890ddd
	sourceInfo.numChannels = st->getChannelCount();
Toshihiro Shimizu 890ddd
	sourceInfo.sampleSize = st->getBitPerSample();
Toshihiro Shimizu 890ddd
	sourceInfo.sampleRate = st->getSampleRate();
Toshihiro Shimizu 890ddd
	sourceInfo.sampleCount = st->getSampleCount();
Toshihiro Shimizu 890ddd
	sourceInfo.buffer = (unsigned char *)st->getRawData();
Toshihiro Shimizu 890ddd
	sourceInfo.reserved = 0x0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	destInfo.flags = kNoSampleRateConversion | kNoSampleSizeConversion |
Toshihiro Shimizu 890ddd
					 kNoSampleFormatConversion | kNoChannelConversion |
Toshihiro Shimizu 890ddd
					 kNoDecompression | kNoVolumeConversion |
Toshihiro Shimizu 890ddd
					 kNoRealtimeProcessing;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	destInfo.format = k16BitNativeEndianFormat;
Toshihiro Shimizu 890ddd
	destInfo.numChannels = st->getChannelCount();
Toshihiro Shimizu 890ddd
	destInfo.sampleSize = st->getBitPerSample();
Toshihiro Shimizu 890ddd
	destInfo.sampleRate = st->getSampleRate();
Toshihiro Shimizu 890ddd
	destInfo.sampleCount = st->getSampleCount();
Toshihiro Shimizu 890ddd
	destInfo.buffer = (unsigned char *)st->getRawData();
Toshihiro Shimizu 890ddd
	destInfo.reserved = 0x0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	SoundConverterOpen(&sourceInfo, &destInfo, &converter);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	myErr = SoundConverterGetInfo(converter, siCompressionFactor, &compressionInfo);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	myErr = SoundConverterGetInfo(converter, siCompressionFactor, &compressionInfo);
Toshihiro Shimizu 890ddd
	myErr = GetCompressionInfo(fixedCompression, sourceInfo.format, sourceInfo.numChannels, sourceInfo.sampleSize, &compressionInfo);
Toshihiro Shimizu 890ddd
	FailIf(myErr != noErr, ConverterErr);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	compressionInfo.bytesPerFrame = compressionInfo.bytesPerPacket * destInfo.numChannels;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//////////
Toshihiro Shimizu 890ddd
	//
Toshihiro Shimizu 890ddd
	// create a sound sample description
Toshihiro Shimizu 890ddd
	//
Toshihiro Shimizu 890ddd
	//////////
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// use the SoundDescription format 1 because it adds fields for data size information
Toshihiro Shimizu 890ddd
	// and is required by AddSoundDescriptionExtension if an extension is required for the compression format
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	mySampleDesc = (SoundDescriptionV1Handle)NewHandleClear(sizeof(SoundDescriptionV1));
Toshihiro Shimizu 890ddd
	FailWithAction(myErr != noErr, myErr = MemError(), Exit);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	(**mySampleDesc).desc.descSize = sizeof(SoundDescriptionV1);
Toshihiro Shimizu 890ddd
	(**mySampleDesc).desc.dataFormat = destInfo.format;
Toshihiro Shimizu 890ddd
	(**mySampleDesc).desc.resvd1 = 0;
Toshihiro Shimizu 890ddd
	(**mySampleDesc).desc.resvd2 = 0;
Toshihiro Shimizu 890ddd
	(**mySampleDesc).desc.dataRefIndex = 1;
Toshihiro Shimizu 890ddd
	(**mySampleDesc).desc.version = 1;
Toshihiro Shimizu 890ddd
	(**mySampleDesc).desc.revlevel = 0;
Toshihiro Shimizu 890ddd
	(**mySampleDesc).desc.vendor = 0;
Toshihiro Shimizu 890ddd
	(**mySampleDesc).desc.numChannels = destInfo.numChannels;
Toshihiro Shimizu 890ddd
	(**mySampleDesc).desc.sampleSize = destInfo.sampleSize;
Toshihiro Shimizu 890ddd
	(**mySampleDesc).desc.compressionID = 0;
Toshihiro Shimizu 890ddd
	(**mySampleDesc).desc.packetSize = 0;
Toshihiro Shimizu 890ddd
	(**mySampleDesc).desc.sampleRate = st->getSampleRate() << 16;
Toshihiro Shimizu 890ddd
	(**mySampleDesc).samplesPerPacket = compressionInfo.samplesPerPacket;
Toshihiro Shimizu 890ddd
	(**mySampleDesc).bytesPerPacket = compressionInfo.bytesPerPacket;
Toshihiro Shimizu 890ddd
	(**mySampleDesc).bytesPerFrame = compressionInfo.bytesPerFrame;
Toshihiro Shimizu 890ddd
	(**mySampleDesc).bytesPerSample = compressionInfo.bytesPerSample;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//////////
Toshihiro Shimizu 890ddd
	//
Toshihiro Shimizu 890ddd
	// add samples to the media
Toshihiro Shimizu 890ddd
	//
Toshihiro Shimizu 890ddd
	//////////
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	myErr = AddMediaSample(m_soundMedia, myDestHandle,
Toshihiro Shimizu 890ddd
						   0,
Toshihiro Shimizu 890ddd
						   destInfo.sampleCount * compressionInfo.bytesPerFrame,
Toshihiro Shimizu 890ddd
						   1,
Toshihiro Shimizu 890ddd
						   (SampleDescriptionHandle)mySampleDesc,
Toshihiro Shimizu 890ddd
						   destInfo.sampleCount * compressionInfo.samplesPerPacket,
Toshihiro Shimizu 890ddd
						   0,
Toshihiro Shimizu 890ddd
						   NULL);
Toshihiro Shimizu 890ddd
	FailIf(myErr != noErr, MediaErr);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	myErr = EndMediaEdits(m_soundMedia);
Toshihiro Shimizu 890ddd
	FailIf(myErr != noErr, MediaErr);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// NOTE: Sound media is inserted into the movie track only at destruction
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
ConverterErr: // Multiple bailout labels just to
Toshihiro Shimizu 890ddd
NoDest:		  // separate debugging strings, it seems.
Toshihiro Shimizu 890ddd
CompressErr:  //
Toshihiro Shimizu 890ddd
Exit:		  // Should be done better...
Toshihiro Shimizu 890ddd
MediaErr:	 //
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (mySampleDesc != NULL)
Toshihiro Shimizu 890ddd
		DisposeHandle((Handle)mySampleDesc);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (converter)
Toshihiro Shimizu 890ddd
		SoundConverterClose(converter);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (myErr != noErr)
Toshihiro Shimizu 890ddd
		throw TImageException(m_path, "error saving audio track");
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TLevelWriterMov::~TLevelWriterMov()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_pixmap)
Toshihiro Shimizu 890ddd
		UnlockPixels(m_pixmap);
Toshihiro Shimizu 890ddd
	if (m_gworld && m_gworld->portPixMap)
Toshihiro Shimizu 890ddd
		UnlockPixels(m_gworld->portPixMap);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_gworld)
Toshihiro Shimizu 890ddd
		DisposeGWorld(m_gworld);
Toshihiro Shimizu 890ddd
	if (m_ci)
Toshihiro Shimizu 890ddd
		CloseComponent(m_ci);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QDErr err;
Toshihiro Shimizu 890ddd
	OSStatus mderr;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_videoTrack) {
Toshihiro Shimizu 890ddd
		// Insert the saved Frames into the track.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// NOTE: Holes in the frames sequence will be intended as still frames, rather than left blank.
Toshihiro Shimizu 890ddd
		//       I'm quite unsure whether this behavior is actually useful - or used at all.
Toshihiro Shimizu 890ddd
		//       In particular, the last frame is an exception, and does NOT drag to the end of the
Toshihiro Shimizu 890ddd
		//       movie (see below). I think it's not used - frames are consecutive AFAIK.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TimeValue movieTimeScale = GetMovieTimeScale(m_movie);
Toshihiro Shimizu 890ddd
		int savedFramesSize = (int)m_savedFrames.size() - 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int i;
Toshihiro Shimizu 890ddd
		for (i = 0; i < savedFramesSize; ++i) {
Toshihiro Shimizu 890ddd
			TimeValue mediaPosition = m_savedFrames[i].second;
Toshihiro Shimizu 890ddd
			TimeValue trackPosition = ((m_savedFrames[i].first - m_firstFrame) * movieTimeScale) / m_frameRate;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			TimeValue duration = m_savedFrames[i + 1].first - m_savedFrames[i].first;
Toshihiro Shimizu 890ddd
			Fixed ratio = tround(fixed1 / (double)duration);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if ((err =
Toshihiro Shimizu 890ddd
					 InsertMediaIntoTrack(m_videoTrack, trackPosition, mediaPosition, 100, ratio)) != noErr)
Toshihiro Shimizu 890ddd
				throw TImageException(getFilePath(), "can't insert media into track");
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (savedFramesSize >= 0) {
Toshihiro Shimizu 890ddd
			TimeValue mediaPosition = m_savedFrames[i].second;
Toshihiro Shimizu 890ddd
			TimeValue trackPosition = ((m_savedFrames[i].first - m_firstFrame) * movieTimeScale) / m_frameRate;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// The last frame has duration 1 (frame):
Toshihiro Shimizu 890ddd
			//   duration = 1  =>  ratio = fixed1
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if ((err =
Toshihiro Shimizu 890ddd
					 InsertMediaIntoTrack(m_videoTrack, trackPosition, mediaPosition, 100, fixed1)) != noErr)
Toshihiro Shimizu 890ddd
				throw TImageException(getFilePath(), "can't insert media into track");
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		QTMetaDataRef metaDataRef;
Toshihiro Shimizu 890ddd
		if ((mderr = QTCopyMovieMetaData(m_movie, &metaDataRef)) != noErr)
Toshihiro Shimizu 890ddd
			throw TImageException(getFilePath(), "can't access metadata informations");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if ((mderr =
Toshihiro Shimizu 890ddd
				 QTMetaDataAddItem(
Toshihiro Shimizu 890ddd
					 metaDataRef,
Toshihiro Shimizu 890ddd
					 kQTMetaDataStorageFormatUserData,
Toshihiro Shimizu 890ddd
					 kQTMetaDataKeyFormatUserData,
Toshihiro Shimizu 890ddd
					 (const UInt8 *)firstFrameKey.c_str(),
Toshihiro Shimizu 890ddd
					 firstFrameKeySize,
Toshihiro Shimizu 890ddd
					 (const UInt8 *)(&m_firstFrame),
Toshihiro Shimizu 890ddd
					 sizeof(int),
Toshihiro Shimizu 890ddd
					 kQTMetaDataTypeUnsignedIntegerBE,
Toshihiro Shimizu 890ddd
					 0)) != noErr)
Toshihiro Shimizu 890ddd
			throw TImageException(getFilePath(), "can't insert metadata informations");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		QTMetaDataRelease(metaDataRef);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_soundTrack) {
Toshihiro Shimizu 890ddd
		if (0 != (err = InsertMediaIntoTrack(m_soundTrack, 0, 0, GetMediaDuration(m_soundMedia), fixed1)))
Toshihiro Shimizu 890ddd
			throw TImageException(getFilePath(), "can't insert sound into track");
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	short resId = movieInDataForkResID;
Toshihiro Shimizu 890ddd
	if (m_movie) {
Toshihiro Shimizu 890ddd
		if ((err = AddMovieResource(m_movie, m_refNum, &resId, 0)) != noErr) // Why no thrown exception here?
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
		} // throw TImageException(getFilePath(), "Can't add resource");             //
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_videoMedia)					 // And anyway, how exceptions
Toshihiro Shimizu 890ddd
		DisposeTrackMedia(m_videoMedia); // deal with absence of corresponding
Toshihiro Shimizu 890ddd
	if (m_videoTrack)					 // disposals?
Toshihiro Shimizu 890ddd
		DisposeMovieTrack(m_videoTrack); // I guess se should use RAII here...  -.-'
Toshihiro Shimizu 890ddd
	if (m_soundMedia)
Toshihiro Shimizu 890ddd
		DisposeTrackMedia(m_soundMedia);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_refNum)
Toshihiro Shimizu 890ddd
		CloseMovieFile(m_refNum);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	DisposeMovie(m_movie);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TImageWriterP TLevelWriterMov::getFrameWriter(TFrameId fid)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_IOError)
Toshihiro Shimizu 890ddd
		throw TImageException(m_path, buildQTErrorString(m_IOError));
Toshihiro Shimizu 890ddd
	if (fid.getLetter() != 0)
Toshihiro Shimizu 890ddd
		return TImageWriterP(0);
Toshihiro Shimizu 890ddd
	int index = fid.getNumber() - 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TImageWriterMov *iwm = new TImageWriterMov(m_path, index, this);
Toshihiro Shimizu 890ddd
	return TImageWriterP(iwm);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TLevelReaderMov::TLevelReaderMov(const TFilePath &path)
Toshihiro Shimizu 890ddd
	: TLevelReader(path), m_IOError(QTNoError), m_track(0), m_movie(0), m_depth(0), m_readAsToonzOutput(false), m_yMirror(true), m_loadTimecode(false)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	FSSpec fspec;
Toshihiro Shimizu 890ddd
	QDErr err;
Toshihiro Shimizu 890ddd
	Boolean dataRefWasChanged;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (QuickTimeStuff::instance()->getStatus() != noErr) {
Toshihiro Shimizu 890ddd
		m_IOError = QTNotInstalled;
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	char *pStr = filePath2unichar(m_path);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if ((err = NativePathNameToFSSpec(pStr, &fspec, kFullNativePath)) != noErr) {
Toshihiro Shimizu 890ddd
		delete[] pStr;
Toshihiro Shimizu 890ddd
		pStr = 0;
Toshihiro Shimizu 890ddd
		throw TImageException(path, "can't open file");
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	delete[] pStr;
Toshihiro Shimizu 890ddd
	pStr = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if ((err = OpenMovieFile(&fspec, &m_refNum, fsRdPerm))) {
Toshihiro Shimizu 890ddd
		m_IOError = QTUnableToOpenFile;
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	short resId = 0;
Toshihiro Shimizu 890ddd
	Str255 name;
Toshihiro Shimizu 890ddd
	err = NewMovieFromFile(&m_movie, m_refNum, &resId,
Toshihiro Shimizu 890ddd
						   name, fsRdPerm, &dataRefWasChanged);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int numTracks = GetMovieTrackCount(m_movie);
Toshihiro Shimizu 890ddd
	if (numTracks < 1) {
Toshihiro Shimizu 890ddd
		m_IOError = QTUnableToOpenFile;
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(numTracks == 1 || numTracks == 2);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_track = GetMovieIndTrackType(m_movie, 1, VideoMediaType, movieTrackMediaType);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ImageDescriptionHandle imageH;
Toshihiro Shimizu 890ddd
	imageH = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TINT32 index = 1;
Toshihiro Shimizu 890ddd
	Media theMedia = GetTrackMedia(m_track);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	GetMediaSampleDescription(theMedia, index, (SampleDescriptionHandle)imageH);
Toshihiro Shimizu 890ddd
	ImageDescriptionPtr imagePtr = *imageH;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if ((imagePtr->cType >> 16) == 0x4458 /*'DX'*/ && path.getType() == "avi") // DIVX - compressed, QT is unable to read it.
Toshihiro Shimizu 890ddd
	{																		   // Done externally with the... AVI reader o_o.
Toshihiro Shimizu 890ddd
		m_IOError = QTUnableToDoMovieTask;
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Retrieve the timecode media handler
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		Track tcTrack = GetMovieIndTrackType(m_movie, 1, TimeCodeMediaType, movieTrackMediaType);
Toshihiro Shimizu 890ddd
		Media tcMedia = GetTrackMedia(tcTrack);
Toshihiro Shimizu 890ddd
		m_timecodeHandler = GetMediaHandler(tcMedia);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_lx = imagePtr->width;
Toshihiro Shimizu 890ddd
	m_ly = imagePtr->height;
Toshihiro Shimizu 890ddd
	m_depth = imagePtr->depth;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_info = new TImageInfo();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_info->m_lx = m_lx;
Toshihiro Shimizu 890ddd
	m_info->m_ly = m_ly;
Toshihiro Shimizu 890ddd
	m_info->m_frameRate = GetMediaTimeScale(theMedia) / 100.0; // REMOVE THIS! Not all movs have this
Toshihiro Shimizu 890ddd
															   // kind of format - only those from Toonz...
Toshihiro Shimizu 890ddd
	Tiio::MovWriterProperties *prop = new Tiio::MovWriterProperties();
Toshihiro Shimizu 890ddd
	m_info->m_properties = prop;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	DisposeHandle((Handle)imageH);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TLevelReaderMov::~TLevelReaderMov()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	StopMovie(m_movie);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_refNum)
Toshihiro Shimizu 890ddd
		CloseMovieFile(m_refNum);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_movie)
Toshihiro Shimizu 890ddd
		DisposeMovie(m_movie);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TLevelReaderMov::loadedTimecode(UCHAR &hh, UCHAR &mm, UCHAR &ss, UCHAR &ff)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	hh = m_hh, mm = m_mm, ss = m_ss, ff = m_ff;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TLevelReaderMov::setYMirror(bool enabled)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_yMirror = enabled;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TLevelReaderMov::setLoadTimecode(bool enabled)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_loadTimecode = enabled;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TLevelReaderMov::enableRandomAccessRead(bool enable)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_readAsToonzOutput = enable;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
//  TImageReaderMov
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class TImageReaderMov : public TImageReader
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TLevelReaderMov *m_lrm;
Toshihiro Shimizu 890ddd
	TImageInfo *m_info;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	int m_frameIndex;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	TImageReaderMov(const TFilePath &, int frameIndex, TLevelReaderMov *, TImageInfo *);
Toshihiro Shimizu 890ddd
	~TImageReaderMov() { m_lrm->release(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TImageP load();
Toshihiro Shimizu 890ddd
	void load(const TRasterP &rasP, const TPoint &pos = TPoint(0, 0), int shrinkX = 1, int shrinkY = 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TDimension getSize() const { return m_lrm->getSize(); }
Toshihiro Shimizu 890ddd
	TRect getBBox() const { return m_lrm->getBBox(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TImageInfo *getImageInfo() const { return m_info; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Toshihiro Shimizu 890ddd
	// Not copyable
Toshihiro Shimizu 890ddd
	TImageReaderMov(const TImageReaderMov &);
Toshihiro Shimizu 890ddd
	TImageReaderMov &operator=(const TImageReaderMov &);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TImageReaderMov::TImageReaderMov(const TFilePath &path, int frameIndex, TLevelReaderMov *lrm, TImageInfo *info)
Toshihiro Shimizu 890ddd
	: TImageReader(path), m_lrm(lrm), m_frameIndex(frameIndex), m_info(info)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_lrm->addRef();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TLevelP TLevelReaderMov::loadInfo()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_readAsToonzOutput)				// Mov files written with Toonz support special
Toshihiro Shimizu 890ddd
		return loadToonzOutputFormatInfo(); // metadata atoms - separate procedure
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Level is NOT a recognized mov from Toonz. Just read each movie's interesting image as a consecutive
Toshihiro Shimizu 890ddd
	// level frame.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TLevelP level;
Toshihiro Shimizu 890ddd
	if (m_IOError != QTNoError)
Toshihiro Shimizu 890ddd
		throw TImageException(m_path, buildQTErrorString(m_IOError));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	OSType mediaType = VisualMediaCharacteristic;
Toshihiro Shimizu 890ddd
	TimeValue nextTime, currentTime;
Toshihiro Shimizu 890ddd
	currentTime = 0;
Toshihiro Shimizu 890ddd
	nextTime = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int f = 0; // 0 is the first frame index
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// io vorrei fare '|', ma sul manuale c'e' scritto '+'
Toshihiro Shimizu 890ddd
	GetMovieNextInterestingTime(m_movie, nextTimeMediaSample + nextTimeEdgeOK, 1, &mediaType, currentTime, 0, &nextTime, 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (nextTime != -1) {
Toshihiro Shimizu 890ddd
		TFrameId frame(f + 1);
Toshihiro Shimizu 890ddd
		level->setFrame(frame, TImageP());
Toshihiro Shimizu 890ddd
		currentTimes[f] = nextTime;
Toshihiro Shimizu 890ddd
		++f;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	currentTime = nextTime;
Toshihiro Shimizu 890ddd
	while (nextTime != -1) {
Toshihiro Shimizu 890ddd
		GetMovieNextInterestingTime(m_movie, nextTimeMediaSample, 1, &mediaType, currentTime, 0, &nextTime, 0);
Toshihiro Shimizu 890ddd
		if (nextTime != -1) {
Toshihiro Shimizu 890ddd
			TFrameId frame(f + 1);
Toshihiro Shimizu 890ddd
			level->setFrame(frame, TImageP());
Toshihiro Shimizu 890ddd
			currentTimes[f] = nextTime;
Toshihiro Shimizu 890ddd
			++f;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		currentTime = nextTime;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	return level;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TLevelP TLevelReaderMov::loadToonzOutputFormatInfo()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TLevelP level;
Toshihiro Shimizu 890ddd
	if (m_IOError != QTNoError)
Toshihiro Shimizu 890ddd
		throw TImageException(m_path, buildQTErrorString(m_IOError));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	OSStatus mderr;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Retrieve the first frame of movie. This info has been put in a metadata atom.
Toshihiro Shimizu 890ddd
	QTMetaDataRef metaDataRef;
Toshihiro Shimizu 890ddd
	if ((mderr = QTCopyMovieMetaData(m_movie, &metaDataRef)) != noErr)
Toshihiro Shimizu 890ddd
		throw TImageException(m_path, "can't access metadata informations");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QTMetaDataItem firstFrameItem;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Find the metadata atom
Toshihiro Shimizu 890ddd
	mderr = QTMetaDataGetNextItem(
Toshihiro Shimizu 890ddd
		metaDataRef,
Toshihiro Shimizu 890ddd
		kQTMetaDataStorageFormatUserData,
Toshihiro Shimizu 890ddd
		kQTMetaDataItemUninitialized,
Toshihiro Shimizu 890ddd
		kQTMetaDataKeyFormatUserData,
Toshihiro Shimizu 890ddd
		(const UInt8 *)firstFrameKey.c_str(),
Toshihiro Shimizu 890ddd
		firstFrameKeySize,
Toshihiro Shimizu 890ddd
		&firstFrameItem);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Try to read the value. If the atom was not found, just assume firstFrame = 0.
Toshihiro Shimizu 890ddd
	int firstFrame = 0;
Toshihiro Shimizu 890ddd
	if (mderr == noErr) {
Toshihiro Shimizu 890ddd
		// The atom was found. Then, retrieve the value
Toshihiro Shimizu 890ddd
		if ((mderr =
Toshihiro Shimizu 890ddd
				 QTMetaDataGetItemValue(
Toshihiro Shimizu 890ddd
					 metaDataRef,
Toshihiro Shimizu 890ddd
					 firstFrameItem,
Toshihiro Shimizu 890ddd
					 (UInt8 *)(&firstFrame),
Toshihiro Shimizu 890ddd
					 sizeof(int),
Toshihiro Shimizu 890ddd
					 0) != noErr))
Toshihiro Shimizu 890ddd
			throw TImageException(m_path, "can't read metadata informations");
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	mderr = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QTMetaDataRelease(metaDataRef);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	OSType mediaType = VisualMediaCharacteristic;
Toshihiro Shimizu 890ddd
	TimeValue nextTime = 0, currentTime = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TimeValue movieDuration = GetMovieDuration(m_movie);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<timevalue> interestingTimeValues;</timevalue>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// io vorrei fare '|', ma sul manuale c'e' scritto '+'
Toshihiro Shimizu 890ddd
	GetMovieNextInterestingTime(m_movie, nextTimeMediaSample + nextTimeEdgeOK, 1, &mediaType, currentTime, 0, &nextTime, 0);
Toshihiro Shimizu 890ddd
	if (nextTime != -1) {
Toshihiro Shimizu 890ddd
		interestingTimeValues.push_back(nextTime);
Toshihiro Shimizu 890ddd
		currentTime = nextTime;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	while (nextTime != -1) {
Toshihiro Shimizu 890ddd
		GetMovieNextInterestingTime(m_movie, nextTimeMediaSample, 1, &mediaType, currentTime, 0, &nextTime, 0);
Toshihiro Shimizu 890ddd
		if (nextTime != -1) {
Toshihiro Shimizu 890ddd
			interestingTimeValues.push_back(nextTime);
Toshihiro Shimizu 890ddd
			currentTime = nextTime;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (currentTime != -1) {
Toshihiro Shimizu 890ddd
		double frameRate = m_info->m_frameRate;
Toshihiro Shimizu 890ddd
		TimeScale movieTimeScale = GetMovieTimeScale(m_movie);
Toshihiro Shimizu 890ddd
		int firstFrameTimeValue = movieTimeScale * firstFrame;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		std::vector<timevalue>::iterator it;</timevalue>
Toshihiro Shimizu 890ddd
		for (it = interestingTimeValues.begin(); it != interestingTimeValues.end(); ++it) {
Toshihiro Shimizu 890ddd
			int frame = firstFrame + tround((*it * frameRate) / (double)movieTimeScale); // (Daniele) There was a ceil here,
Toshihiro Shimizu 890ddd
			TFrameId frameId(frame + 1);												 // before. But I honestly don't remember
Toshihiro Shimizu 890ddd
			level->setFrame(frameId, TImageP());										 // WHY I placed it there. Round seems more
Toshihiro Shimizu 890ddd
			currentTimes[frame] = *it;													 // appropriate...
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return level;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TImageP TImageReaderMov::load()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TRasterPT<tpixelrgbm32> ret(m_lrm->getSize());</tpixelrgbm32>
Toshihiro Shimizu 890ddd
	m_lrm->load(ret, m_frameIndex, TPointI(), 1, 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return TRasterImageP(ret);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TImageReaderMov::load(const TRasterP &rasP, const TPoint &pos, int shrinkX, int shrinkY)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if ((shrinkX != 1) || (shrinkY != 1) || (pos != TPoint(0, 0)))
Toshihiro Shimizu 890ddd
		TImageReader::load(rasP, pos, shrinkX, shrinkY);
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		m_lrm->load(rasP, m_frameIndex, pos, shrinkX, shrinkY);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void setMatteAndYMirror(const TRaster32P &ras)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	ras->lock();
Toshihiro Shimizu 890ddd
	TPixel32 *upRow = ras->pixels();
Toshihiro Shimizu 890ddd
	TPixel32 *dwRow = ras->pixels(ras->getLy() - 1);
Toshihiro Shimizu 890ddd
	int hLy = (int)(ras->getLy() / 2. + 0.5); //piccola pessimizzazione...
Toshihiro Shimizu 890ddd
	int wrap = ras->getWrap();
Toshihiro Shimizu 890ddd
	int lx = ras->getLx();
Toshihiro Shimizu 890ddd
	TPixel32 *upPix = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPixel32 *lastPix = ras->pixels(hLy);
Toshihiro Shimizu 890ddd
	while (upPix < lastPix) {
Toshihiro Shimizu 890ddd
		upPix = upRow;
Toshihiro Shimizu 890ddd
		TPixel32 *dwPix = dwRow;
Toshihiro Shimizu 890ddd
		TPixel32 *endPix = upPix + lx;
Toshihiro Shimizu 890ddd
		while (upPix < endPix) {
Toshihiro Shimizu 890ddd
			TPixel32 tmpPix(upPix->r, upPix->g, upPix->b, 0xff);
Toshihiro Shimizu 890ddd
			*upPix = *dwPix;
Toshihiro Shimizu 890ddd
			upPix->m = 0xff;
Toshihiro Shimizu 890ddd
			*dwPix = tmpPix;
Toshihiro Shimizu 890ddd
			++upPix;
Toshihiro Shimizu 890ddd
			++dwPix;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		upRow += wrap;
Toshihiro Shimizu 890ddd
		dwRow -= wrap;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	ras->unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TLevelReaderMov::load(const TRasterP &rasP, int frameIndex, const TPoint &pos, int shrinkX, int shrinkY)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	GWorldPtr offscreenGWorld = 0;
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		QMutexLocker sl(&m_mutex);
Toshihiro Shimizu 890ddd
		if (m_IOError != QTNoError)
Toshihiro Shimizu 890ddd
			throw TImageException(m_path, buildQTErrorString(m_IOError));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TRaster32P ras = rasP;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		Rect rect;
Toshihiro Shimizu 890ddd
		rect.right = pos.x + ras->getLx();
Toshihiro Shimizu 890ddd
		rect.left = pos.x;
Toshihiro Shimizu 890ddd
		rect.bottom = pos.y + ras->getLy();
Toshihiro Shimizu 890ddd
		rect.top = pos.y;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		OSErr err;
Toshihiro Shimizu 890ddd
		ras->lock();
Toshihiro Shimizu 890ddd
		err = QTNewGWorldFromPtr(
Toshihiro Shimizu 890ddd
			&offscreenGWorld, k32BGRAPixelFormat,
Toshihiro Shimizu 890ddd
			&rect, 0, 0, 0, ras->getRawData(), ras->getWrap() * 4);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (err != noErr) {
Toshihiro Shimizu 890ddd
			m_IOError = QTUnableToCreateResource;
Toshihiro Shimizu 890ddd
			goto error;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		SetMovieBox(m_movie, &rect);
Toshihiro Shimizu 890ddd
		err = GetMoviesError();
Toshihiro Shimizu 890ddd
		if (err != noErr) {
Toshihiro Shimizu 890ddd
			m_IOError = QTUnableToSetMovieBox;
Toshihiro Shimizu 890ddd
			goto error;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		SetMovieGWorld(m_movie, offscreenGWorld, GetGWorldDevice(offscreenGWorld));
Toshihiro Shimizu 890ddd
		err = GetMoviesError();
Toshihiro Shimizu 890ddd
		if (err != noErr) {
Toshihiro Shimizu 890ddd
			m_IOError = QTUnableToSetMovieGWorld;
Toshihiro Shimizu 890ddd
			goto error;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (currentTimes.empty())
Toshihiro Shimizu 890ddd
			loadInfo();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		std::map<int, timevalue="">::iterator it = currentTimes.find(frameIndex);</int,>
Toshihiro Shimizu 890ddd
		if (it == currentTimes.end())
Toshihiro Shimizu 890ddd
			goto error;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TimeValue currentTime = it->second;
Toshihiro Shimizu 890ddd
		SetMovieTimeValue(m_movie, currentTime);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		err = GetMoviesError();
Toshihiro Shimizu 890ddd
		if (err != noErr) {
Toshihiro Shimizu 890ddd
			m_IOError = QTUnableToSetTimeValue;
Toshihiro Shimizu 890ddd
			goto error;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		err = UpdateMovie(m_movie);
Toshihiro Shimizu 890ddd
		if (err != noErr) {
Toshihiro Shimizu 890ddd
			m_IOError = QTUnableToUpdateMovie;
Toshihiro Shimizu 890ddd
			goto error;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		MoviesTask(m_movie, 0);
Toshihiro Shimizu 890ddd
		err = GetMoviesError();
Toshihiro Shimizu 890ddd
		if (err != noErr) {
Toshihiro Shimizu 890ddd
			m_IOError = QTUnableToDoMovieTask;
Toshihiro Shimizu 890ddd
			goto error;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		DisposeGWorld(offscreenGWorld);
Toshihiro Shimizu 890ddd
		ras->unlock();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_yMirror) {
Toshihiro Shimizu 890ddd
		if (m_depth != 32)
Toshihiro Shimizu 890ddd
			setMatteAndYMirror(rasP);
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			rasP->yMirror();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_loadTimecode) {
Toshihiro Shimizu 890ddd
		//Also build current Timecode
Toshihiro Shimizu 890ddd
		TimeCodeRecord tc;
Toshihiro Shimizu 890ddd
		HandlerError err = TCGetCurrentTimeCode(m_timecodeHandler, 0, 0, &tc, 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_hh = tc.t.hours;
Toshihiro Shimizu 890ddd
		m_mm = tc.t.minutes;
Toshihiro Shimizu 890ddd
		m_ss = tc.t.seconds;
Toshihiro Shimizu 890ddd
		m_ff = tc.t.frames;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return;
Toshihiro Shimizu 890ddd
error:
Toshihiro Shimizu 890ddd
	rasP->unlock();
Toshihiro Shimizu 890ddd
	if (offscreenGWorld)
Toshihiro Shimizu 890ddd
		DisposeGWorld(offscreenGWorld);
Toshihiro Shimizu 890ddd
	throw TImageException(m_path, buildQTErrorString(m_IOError));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TLevelReaderMov::timecode(int frameIndex, UCHAR &hh, UCHAR &mm, UCHAR &ss, UCHAR &ff)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	hh = mm = ss = ff = 0xff;
Toshihiro Shimizu 890ddd
	if (!m_timecodeHandler)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QMutexLocker sl(&m_mutex);
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if (m_IOError != QTNoError)
Toshihiro Shimizu 890ddd
			goto error;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (currentTimes.empty())
Toshihiro Shimizu 890ddd
			loadInfo();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		std::map<int, timevalue="">::iterator it = currentTimes.find(frameIndex);</int,>
Toshihiro Shimizu 890ddd
		if (it == currentTimes.end())
Toshihiro Shimizu 890ddd
			goto error;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TimeValue currentTime = it->second;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TimeCodeRecord tc;
Toshihiro Shimizu 890ddd
		HandlerError err = TCGetTimeCodeAtTime(m_timecodeHandler, currentTime,
Toshihiro Shimizu 890ddd
											   0, 0, &tc, 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		hh = tc.t.hours;
Toshihiro Shimizu 890ddd
		mm = tc.t.minutes;
Toshihiro Shimizu 890ddd
		ss = tc.t.seconds;
Toshihiro Shimizu 890ddd
		ff = tc.t.frames;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
error:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	throw TImageException(m_path, buildQTErrorString(m_IOError));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TImageReaderP TLevelReaderMov::getFrameReader(TFrameId fid)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_IOError != QTNoError)
Toshihiro Shimizu 890ddd
		throw TImageException(m_path, buildQTErrorString(m_IOError));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (fid.getLetter() != 0)
Toshihiro Shimizu 890ddd
		return TImageReaderP(0);
Toshihiro Shimizu 890ddd
	int index = fid.getNumber() - 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TImageReaderMov *irm = new TImageReaderMov(m_path, index, this, m_info);
Toshihiro Shimizu 890ddd
	return TImageReaderP(irm);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TLevelReader *TLevelReaderMov::create(const TFilePath &f)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TLevelReaderMov *reader = new TLevelReaderMov(f);
Toshihiro Shimizu 890ddd
	if (reader->m_IOError != QTNoError && f.getType() == "avi") {
Toshihiro Shimizu 890ddd
		delete reader;
Toshihiro Shimizu 890ddd
		return new TLevelReaderAvi(f);
Toshihiro Shimizu 890ddd
	} else
Toshihiro Shimizu 890ddd
		return reader;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// You can use the SCSetInfo function with the scSettingsStateType selector to retrieve a handle
Toshihiro Shimizu 890ddd
//  containing the current compression settings; this might be useful if you were allowing the user
Toshihiro Shimizu 890ddd
//  to compress a series of images and wanted to preserve the user's settings from one image to the
Toshihiro Shimizu 890ddd
//  next (instead of reverting to the defaults for every image). Note, however, that the data in
Toshihiro Shimizu 890ddd
//  that handle is byte-ordered according to the platform the code is running on. As a result, you
Toshihiro Shimizu 890ddd
//  should not store that data in a file and expect that file to be valid on other platforms. To
Toshihiro Shimizu 890ddd
//  get a handle of data in a platform-independent format, use the function SCGetSettingsAsAtomContainer
Toshihiro Shimizu 890ddd
//  (introduced in QuickTime 3); to restore the settings in that handle, use the related function
Toshihiro Shimizu 890ddd
//  SCSetSettingsAsAtomContainer.
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif