| |
| |
| #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" |
| |
| |
| 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"; |
| } |
| }; |
| |
| |
| |
| |
| |
| class TImageWriterMov : public TImageWriter { |
| public: |
| TImageWriterMov(const TFilePath &, int frameIndex, TLevelWriterMov *); |
| ~TImageWriterMov() {} |
| bool is64bitOutputSupported() { return false; } |
| |
| private: |
| |
| TImageWriterMov(const TImageWriterMov &); |
| TImageWriterMov &operator=(const TImageWriterMov &src); |
| |
| public: |
| void save(const TImageP &); |
| int m_frameIndex; |
| |
| private: |
| TLevelWriterMov *m_lwm; |
| }; |
| |
| |
| |
| |
| class TImageReaderMov : public TImageReader { |
| public: |
| TImageReaderMov(const TFilePath &, int frameIndex, TLevelReaderMov *); |
| ~TImageReaderMov() {} |
| |
| private: |
| |
| 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(const TFilePath &path, int frameIndex, |
| TLevelWriterMov *lwm) |
| : TImageWriter(path), m_lwm(lwm), m_frameIndex(frameIndex) {} |
| |
| |
| |
| void TImageWriterMov::save(const TImageP &img) { assert(false); } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| TLevelWriterMov::TLevelWriterMov(const TFilePath &path, TWriterInfo *info) |
| : TLevelWriter(path, info) |
| |
| |
| |
| |
| |
| |
| { |
| assert(false); |
| } |
| |
| |
| |
| void TLevelWriterMov::saveSoundTrack(TSoundTrack *) { |
| throw TImageException(m_path, |
| "TLevelWriterMov::saveSoundTrack not Implemented"); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| TLevelWriterMov::~TLevelWriterMov() { assert(0); } |
| |
| |
| |
| TImageWriterP TLevelWriterMov::getFrameWriter(TFrameId fid) { assert(false); } |
| |
| |
| |
| |
| |
| |
| |
| |
| 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); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| m_lx = oqt_get_video_width(m_fileMov, 0); |
| m_ly = oqt_get_video_height(m_fileMov, 0); |
| |
| |
| |
| |
| } |
| |
| |
| |
| 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); |
| } |
| |