#include #include #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); }