Blob Blame Raw


#include <openquicktime.h>
#include <colormodels.h>

#include "tiio_movL.h"
#include "traster.h"
#include "trasterimage.h"
#include "tsound.h"
#include "tconvert.h"
#include "trop.h"
#include "tsystem.h"
//#define DUMP_KEYFRAMES

bool IsQuickTimeInstalled()
{
	return true;
}

enum {
	QTNoError = 0,
	QTUnableToOpenFile,
	QTUnableToSeekToKeyFrame,
	QTNoSuchFile,
	QTUnsupportedVideoFormat
};

class TQTException : public TImageException
{
public:
	TQTException(const TFilePath &fp, int ec)
		: TImageException(fp, getErrorMessage(ec)) {}
	TQTException(const TFilePath &fp, int ec, int v)
		: TImageException(fp, getErrorMessage(ec) + toString(v))
	{
	}

	~TQTException() {}
	static string getErrorMessage(int ec)
	{
		switch (ec) {
		case QTNoError:
			return "No error";
		case QTUnableToOpenFile:
			return "unable to open file";
		case QTUnableToSeekToKeyFrame:
			return "unable to seek to keyframe";
		case QTNoSuchFile:
			return "no such file";
		case QTUnsupportedVideoFormat:
			return "Unsupported video format";
		}
		return "unknown error";
	}
};

//-----------------------------------------------------------
//  TImageWriterMov
//-----------------------------------------------------------

class TImageWriterMov : public TImageWriter
{

public:
	TImageWriterMov(const TFilePath &, int frameIndex, TLevelWriterMov *);
	~TImageWriterMov() {}
	bool is64bitOutputSupported() { return false; }

private:
	//not implemented
	TImageWriterMov(const TImageWriterMov &);
	TImageWriterMov &operator=(const TImageWriterMov &src);

public:
	void save(const TImageP &);
	int m_frameIndex;

private:
	TLevelWriterMov *m_lwm;
};

//-----------------------------------------------------------
//  TImageReaderMov
//-----------------------------------------------------------
class TImageReaderMov : public TImageReader
{

public:
	TImageReaderMov(const TFilePath &, int frameIndex, TLevelReaderMov *);
	~TImageReaderMov() {}

private:
	//not implemented
	TImageReaderMov(const TImageReaderMov &);
	TImageReaderMov &operator=(const TImageReaderMov &src);

public:
	TImageP load();
	int m_frameIndex;

	TDimension getSize() const { return TDimension(m_lrm->m_lx, m_lrm->m_ly); }
	TRect getBBox() const { return TRect(0, 0, m_lrm->m_lx - 1, m_lrm->m_ly - 1); }

private:
	TLevelReaderMov *m_lrm;
};

//-----------------------------------------------------------
//-----------------------------------------------------------
//        TImageWriterMov
//-----------------------------------------------------------

TImageWriterMov::TImageWriterMov(const TFilePath &path, int frameIndex, TLevelWriterMov *lwm)
	: TImageWriter(path), m_lwm(lwm), m_frameIndex(frameIndex)
{
}

//-----------------------------------------------------------

void TImageWriterMov::save(const TImageP &img)
{
	assert(false);
}

//-----------------------------------------------------------
//        TLevelWriterMov
//-----------------------------------------------------------

/*
class TWriterInfoMov : public TWriterInfo {
public:
  TWriterInfoMov() : TWriterInfo() { assert(!"Not implemented"); }
  ~TWriterInfoMov() {}
private:
};
*/

//-----------------------------------------------------------

TLevelWriterMov::TLevelWriterMov(const TFilePath &path, TWriterInfo *info)
	: TLevelWriter(path, info)
//,m_initDone(false)
//,m_rate(25)
//,m_IOError(QTNoError)
//,quality(DM_IMAGE_QUALITY_NORMAL)
//,compression(DM_IMAGE_QT_ANIM)
//,m_writerInfo(new TWriterInfoMov())
{
	assert(false);
}

//-----------------------------------------------------------

void TLevelWriterMov::saveSoundTrack(TSoundTrack *)
{
	throw TImageException(m_path, "TLevelWriterMov::saveSoundTrack not Implemented");
}
//-----------------------------------------------------------

/*
TWriterInfo *TLevelWriterMov::getWriterInfo() const
{
return m_writerInfo;
}
*/

//-----------------------------------------------------------

TLevelWriterMov::~TLevelWriterMov()
{
	assert(0);
}

//-----------------------------------------------------------

TImageWriterP TLevelWriterMov::getFrameWriter(TFrameId fid)
{
	assert(false);
}

//-----------------------------------------------------------
//------------------------------------------------

//------------------------------------------------
// TImageReaderMov
//------------------------------------------------

TImageReaderMov::TImageReaderMov(const TFilePath &path, int frameIndex, TLevelReaderMov *lrm)
	: TImageReader(path), m_lrm(lrm), m_frameIndex(frameIndex)
{
}

//------------------------------------------------

using namespace std;

TLevelReaderMov::TLevelReaderMov(const TFilePath &path)
	: TLevelReader(path), m_IOError(QTNoError), m_lastFrameDecoded(-1), m_fileMov(0), m_lx(0), m_ly(0)
{
	if (!TFileStatus(path).doesExist()) {
		m_IOError = QTNoSuchFile;
		return;
	}
	m_fileMov = oqt_open((char *)path.getString().c_str());
	if (!m_fileMov) {
		m_IOError = QTUnableToOpenFile;
		return;
	}

	oqt_read_headers(m_fileMov);

	/*
  if(!oqt_get_video_track_count(m_fileMov))
    {
      m_status = !DM_SUCCESS;
      m_IOError = QTCheckLibError;
      return;
    }
  */

	m_lx = oqt_get_video_width(m_fileMov, 0);
	m_ly = oqt_get_video_height(m_fileMov, 0);
	/*
  char *vc = oqt_get_video_compressor(m_fileMov, 0);
  cout << "video compressor = " << vc[0] << vc[1] << vc[2] << vc[3] << endl;  
  */
}

//------------------------------------------------

TLevelReaderMov::~TLevelReaderMov()
{
	if (m_fileMov)
		oqt_close(m_fileMov);
}

//------------------------------------------------

TLevelP TLevelReaderMov::loadInfo()
{
	TLevelP level;
	if (m_IOError != QTNoError) {
		throw TQTException(m_path, m_IOError);
	}
	if (oqt_supported_video(m_fileMov, 0) == 0) {
		m_IOError = QTUnsupportedVideoFormat;
		throw TQTException(m_path, m_IOError);
	}

	int frameCount = oqt_get_video_length(m_fileMov, 0);

	for (int i = 1; i <= frameCount; i++)
		level->setFrame(TFrameId(i), TImageP());

#ifdef DUMP_KEYFRAMES
	for (int k = 1; k < frameCount; k++) {
		cout << "frame = " << k << "; keyframe before = " << oqt_get_video_keyframe_before(m_fileMov, 0, k)
			 << "; keyframe after = " << oqt_get_video_keyframe_after(m_fileMov, 0, k) << endl;
	}
#endif

	return level;
}

//------------------------------------------------

TImageP TImageReaderMov::load()
{
	if (m_lrm->m_IOError != QTNoError)
		throw TQTException(m_path, m_lrm->m_IOError);

	TThread::ScopedLock sl(m_lrm->m_mutex);
	int rc;
	TRaster32P ret(m_lrm->m_lx, m_lrm->m_ly);
	unsigned char **data = (unsigned char **)malloc(m_lrm->m_ly * sizeof(unsigned char *));
	for (int i = 0; i < m_lrm->m_ly; ++i) {
		unsigned char *ptr = (unsigned char *)ret->pixels(i);
		data[i] = ptr;
	}
	int cmodel = BC_RGBA8888;
	int frame;
	if (m_lrm->m_lastFrameDecoded != (m_frameIndex - 1)) {
		oqt_int64_t kfb = oqt_get_video_keyframe_before(m_lrm->m_fileMov, 0, m_frameIndex);
		assert(kfb <= m_frameIndex);
		rc = oqt_set_video_position(m_lrm->m_fileMov, 0, kfb);
		if (rc) {
			throw TQTException(m_lrm->m_path, QTUnableToSeekToKeyFrame, kfb);
		}
		frame = kfb - 1;
	} else
		frame = m_lrm->m_lastFrameDecoded;

	do {
		rc = oqt_decode_video(m_lrm->m_fileMov,
							  0,
							  cmodel,
							  data);
		frame++;
	} while (frame != m_frameIndex);

	m_lrm->m_lastFrameDecoded = m_frameIndex;
	ret->yMirror();
	free(data);
	return TRasterImageP(ret);
}

//------------------------------------------------

TImageReaderP TLevelReaderMov::getFrameReader(TFrameId fid)
{
	if (m_IOError != QTNoError) {
		throw TQTException(m_path, m_IOError);
	}

	if (fid.getLetter() != 0)
		return TImageReaderP(0);
	int index = fid.getNumber() - 1;

	TImageReaderMov *irm = new TImageReaderMov(m_path, index, this);
	return TImageReaderP(irm);
}