Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <openquicktime.h></openquicktime.h>
Toshihiro Shimizu 890ddd
#include <colormodels.h></colormodels.h>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tiio_movL.h"
Toshihiro Shimizu 890ddd
#include "traster.h"
Toshihiro Shimizu 890ddd
#include "trasterimage.h"
Toshihiro Shimizu 890ddd
#include "tsound.h"
Toshihiro Shimizu 890ddd
#include "tconvert.h"
Toshihiro Shimizu 890ddd
#include "trop.h"
Toshihiro Shimizu 890ddd
#include "tsystem.h"
Toshihiro Shimizu 890ddd
//#define DUMP_KEYFRAMES
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool IsQuickTimeInstalled()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
enum {
Toshihiro Shimizu 890ddd
	QTNoError = 0,
Toshihiro Shimizu 890ddd
	QTUnableToOpenFile,
Toshihiro Shimizu 890ddd
	QTUnableToSeekToKeyFrame,
Toshihiro Shimizu 890ddd
	QTNoSuchFile,
Toshihiro Shimizu 890ddd
	QTUnsupportedVideoFormat
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class TQTException : public TImageException
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	TQTException(const TFilePath &fp, int ec)
Toshihiro Shimizu 890ddd
		: TImageException(fp, getErrorMessage(ec)) {}
Toshihiro Shimizu 890ddd
	TQTException(const TFilePath &fp, int ec, int v)
Toshihiro Shimizu 890ddd
		: TImageException(fp, getErrorMessage(ec) + toString(v))
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	~TQTException() {}
Toshihiro Shimizu 890ddd
	static string getErrorMessage(int ec)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		switch (ec) {
Toshihiro Shimizu 890ddd
		case QTNoError:
Toshihiro Shimizu 890ddd
			return "No error";
Toshihiro Shimizu 890ddd
		case QTUnableToOpenFile:
Toshihiro Shimizu 890ddd
			return "unable to open file";
Toshihiro Shimizu 890ddd
		case QTUnableToSeekToKeyFrame:
Toshihiro Shimizu 890ddd
			return "unable to seek to keyframe";
Toshihiro Shimizu 890ddd
		case QTNoSuchFile:
Toshihiro Shimizu 890ddd
			return "no such file";
Toshihiro Shimizu 890ddd
		case QTUnsupportedVideoFormat:
Toshihiro Shimizu 890ddd
			return "Unsupported video format";
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		return "unknown error";
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
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() {}
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
//  TImageReaderMov
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
class TImageReaderMov : public TImageReader
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	TImageReaderMov(const TFilePath &, int frameIndex, TLevelReaderMov *);
Toshihiro Shimizu 890ddd
	~TImageReaderMov() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Toshihiro Shimizu 890ddd
	//not implemented
Toshihiro Shimizu 890ddd
	TImageReaderMov(const TImageReaderMov &);
Toshihiro Shimizu 890ddd
	TImageReaderMov &operator=(const TImageReaderMov &src);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	TImageP load();
Toshihiro Shimizu 890ddd
	int m_frameIndex;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TDimension getSize() const { return TDimension(m_lrm->m_lx, m_lrm->m_ly); }
Toshihiro Shimizu 890ddd
	TRect getBBox() const { return TRect(0, 0, m_lrm->m_lx - 1, m_lrm->m_ly - 1); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Toshihiro Shimizu 890ddd
	TLevelReaderMov *m_lrm;
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
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TImageWriterMov::save(const TImageP &img)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(false);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
//        TLevelWriterMov
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
class TWriterInfoMov : public TWriterInfo {
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
  TWriterInfoMov() : TWriterInfo() { assert(!"Not implemented"); }
Toshihiro Shimizu 890ddd
  ~TWriterInfoMov() {}
Toshihiro Shimizu 890ddd
private:
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TLevelWriterMov::TLevelWriterMov(const TFilePath &path, TWriterInfo *info)
Toshihiro Shimizu 890ddd
	: TLevelWriter(path, info)
Toshihiro Shimizu 890ddd
//,m_initDone(false)
Toshihiro Shimizu 890ddd
//,m_rate(25)
Toshihiro Shimizu 890ddd
//,m_IOError(QTNoError)
Toshihiro Shimizu 890ddd
//,quality(DM_IMAGE_QUALITY_NORMAL)
Toshihiro Shimizu 890ddd
//,compression(DM_IMAGE_QT_ANIM)
Toshihiro Shimizu 890ddd
//,m_writerInfo(new TWriterInfoMov())
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(false);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TLevelWriterMov::saveSoundTrack(TSoundTrack *)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	throw TImageException(m_path, "TLevelWriterMov::saveSoundTrack not Implemented");
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
TWriterInfo *TLevelWriterMov::getWriterInfo() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
return m_writerInfo;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TLevelWriterMov::~TLevelWriterMov()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(0);
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
	assert(false);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
// TImageReaderMov
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TImageReaderMov::TImageReaderMov(const TFilePath &path, int frameIndex, TLevelReaderMov *lrm)
Toshihiro Shimizu 890ddd
	: TImageReader(path), m_lrm(lrm), m_frameIndex(frameIndex)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace std;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TLevelReaderMov::TLevelReaderMov(const TFilePath &path)
Toshihiro Shimizu 890ddd
	: TLevelReader(path), m_IOError(QTNoError), m_lastFrameDecoded(-1), m_fileMov(0), m_lx(0), m_ly(0)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!TFileStatus(path).doesExist()) {
Toshihiro Shimizu 890ddd
		m_IOError = QTNoSuchFile;
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	m_fileMov = oqt_open((char *)path.getString().c_str());
Toshihiro Shimizu 890ddd
	if (!m_fileMov) {
Toshihiro Shimizu 890ddd
		m_IOError = QTUnableToOpenFile;
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	oqt_read_headers(m_fileMov);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	/*
Toshihiro Shimizu 890ddd
  if(!oqt_get_video_track_count(m_fileMov))
Toshihiro Shimizu 890ddd
    {
Toshihiro Shimizu 890ddd
      m_status = !DM_SUCCESS;
Toshihiro Shimizu 890ddd
      m_IOError = QTCheckLibError;
Toshihiro Shimizu 890ddd
      return;
Toshihiro Shimizu 890ddd
    }
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_lx = oqt_get_video_width(m_fileMov, 0);
Toshihiro Shimizu 890ddd
	m_ly = oqt_get_video_height(m_fileMov, 0);
Toshihiro Shimizu 890ddd
	/*
Toshihiro Shimizu 890ddd
  char *vc = oqt_get_video_compressor(m_fileMov, 0);
Toshihiro Shimizu 890ddd
  cout << "video compressor = " << vc[0] << vc[1] << vc[2] << vc[3] << endl;  
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TLevelReaderMov::~TLevelReaderMov()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_fileMov)
Toshihiro Shimizu 890ddd
		oqt_close(m_fileMov);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TLevelP TLevelReaderMov::loadInfo()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TLevelP level;
Toshihiro Shimizu 890ddd
	if (m_IOError != QTNoError) {
Toshihiro Shimizu 890ddd
		throw TQTException(m_path, m_IOError);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (oqt_supported_video(m_fileMov, 0) == 0) {
Toshihiro Shimizu 890ddd
		m_IOError = QTUnsupportedVideoFormat;
Toshihiro Shimizu 890ddd
		throw TQTException(m_path, m_IOError);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int frameCount = oqt_get_video_length(m_fileMov, 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int i = 1; i <= frameCount; i++)
Toshihiro Shimizu 890ddd
		level->setFrame(TFrameId(i), TImageP());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef DUMP_KEYFRAMES
Toshihiro Shimizu 890ddd
	for (int k = 1; k < frameCount; k++) {
Toshihiro Shimizu 890ddd
		cout << "frame = " << k << "; keyframe before = " << oqt_get_video_keyframe_before(m_fileMov, 0, k)
Toshihiro Shimizu 890ddd
			 << "; keyframe after = " << oqt_get_video_keyframe_after(m_fileMov, 0, k) << endl;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
#endif
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
	if (m_lrm->m_IOError != QTNoError)
Toshihiro Shimizu 890ddd
		throw TQTException(m_path, m_lrm->m_IOError);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TThread::ScopedLock sl(m_lrm->m_mutex);
Toshihiro Shimizu 890ddd
	int rc;
Toshihiro Shimizu 890ddd
	TRaster32P ret(m_lrm->m_lx, m_lrm->m_ly);
Toshihiro Shimizu 890ddd
	unsigned char **data = (unsigned char **)malloc(m_lrm->m_ly * sizeof(unsigned char *));
Toshihiro Shimizu 890ddd
	for (int i = 0; i < m_lrm->m_ly; ++i) {
Toshihiro Shimizu 890ddd
		unsigned char *ptr = (unsigned char *)ret->pixels(i);
Toshihiro Shimizu 890ddd
		data[i] = ptr;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	int cmodel = BC_RGBA8888;
Toshihiro Shimizu 890ddd
	int frame;
Toshihiro Shimizu 890ddd
	if (m_lrm->m_lastFrameDecoded != (m_frameIndex - 1)) {
Toshihiro Shimizu 890ddd
		oqt_int64_t kfb = oqt_get_video_keyframe_before(m_lrm->m_fileMov, 0, m_frameIndex);
Toshihiro Shimizu 890ddd
		assert(kfb <= m_frameIndex);
Toshihiro Shimizu 890ddd
		rc = oqt_set_video_position(m_lrm->m_fileMov, 0, kfb);
Toshihiro Shimizu 890ddd
		if (rc) {
Toshihiro Shimizu 890ddd
			throw TQTException(m_lrm->m_path, QTUnableToSeekToKeyFrame, kfb);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		frame = kfb - 1;
Toshihiro Shimizu 890ddd
	} else
Toshihiro Shimizu 890ddd
		frame = m_lrm->m_lastFrameDecoded;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	do {
Toshihiro Shimizu 890ddd
		rc = oqt_decode_video(m_lrm->m_fileMov,
Toshihiro Shimizu 890ddd
							  0,
Toshihiro Shimizu 890ddd
							  cmodel,
Toshihiro Shimizu 890ddd
							  data);
Toshihiro Shimizu 890ddd
		frame++;
Toshihiro Shimizu 890ddd
	} while (frame != m_frameIndex);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_lrm->m_lastFrameDecoded = m_frameIndex;
Toshihiro Shimizu 890ddd
	ret->yMirror();
Toshihiro Shimizu 890ddd
	free(data);
Toshihiro Shimizu 890ddd
	return TRasterImageP(ret);
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 TQTException(m_path, m_IOError);
Toshihiro Shimizu 890ddd
	}
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);
Toshihiro Shimizu 890ddd
	return TImageReaderP(irm);
Toshihiro Shimizu 890ddd
}