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
Shinya Kitaoka 120a6e
bool IsQuickTimeInstalled() { return true; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
enum {
Shinya Kitaoka 120a6e
  QTNoError = 0,
Shinya Kitaoka 120a6e
  QTUnableToOpenFile,
Shinya Kitaoka 120a6e
  QTUnableToSeekToKeyFrame,
Shinya Kitaoka 120a6e
  QTNoSuchFile,
Shinya Kitaoka 120a6e
  QTUnsupportedVideoFormat
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class TQTException : public TImageException {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  TQTException(const TFilePath &fp, int ec)
Shinya Kitaoka 120a6e
      : TImageException(fp, getErrorMessage(ec)) {}
Shinya Kitaoka 120a6e
  TQTException(const TFilePath &fp, int ec, int v)
Shinya Kitaoka 120a6e
      : TImageException(fp, getErrorMessage(ec) + toString(v)) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ~TQTException() {}
Shinya Kitaoka 120a6e
  static string getErrorMessage(int ec) {
Shinya Kitaoka 120a6e
    switch (ec) {
Shinya Kitaoka 120a6e
    case QTNoError:
Shinya Kitaoka 120a6e
      return "No error";
Shinya Kitaoka 120a6e
    case QTUnableToOpenFile:
Shinya Kitaoka 120a6e
      return "unable to open file";
Shinya Kitaoka 120a6e
    case QTUnableToSeekToKeyFrame:
Shinya Kitaoka 120a6e
      return "unable to seek to keyframe";
Shinya Kitaoka 120a6e
    case QTNoSuchFile:
Shinya Kitaoka 120a6e
      return "no such file";
Shinya Kitaoka 120a6e
    case QTUnsupportedVideoFormat:
Shinya Kitaoka 120a6e
      return "Unsupported video format";
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return "unknown error";
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
//  TImageWriterMov
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class TImageWriterMov : public TImageWriter {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  TImageWriterMov(const TFilePath &, int frameIndex, TLevelWriterMov *);
Shinya Kitaoka 120a6e
  ~TImageWriterMov() {}
Shinya Kitaoka 120a6e
  bool is64bitOutputSupported() { return false; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  // not implemented
Shinya Kitaoka 120a6e
  TImageWriterMov(const TImageWriterMov &);
Shinya Kitaoka 120a6e
  TImageWriterMov &operator=(const TImageWriterMov &src);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  void save(const TImageP &);
Shinya Kitaoka 120a6e
  int m_frameIndex;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  TLevelWriterMov *m_lwm;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
//  TImageReaderMov
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Shinya Kitaoka 120a6e
class TImageReaderMov : public TImageReader {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  TImageReaderMov(const TFilePath &, int frameIndex, TLevelReaderMov *);
Shinya Kitaoka 120a6e
  ~TImageReaderMov() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  // not implemented
Shinya Kitaoka 120a6e
  TImageReaderMov(const TImageReaderMov &);
Shinya Kitaoka 120a6e
  TImageReaderMov &operator=(const TImageReaderMov &src);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  TImageP load();
Shinya Kitaoka 120a6e
  int m_frameIndex;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TDimension getSize() const { return TDimension(m_lrm->m_lx, m_lrm->m_ly); }
Shinya Kitaoka 120a6e
  TRect getBBox() const {
Shinya Kitaoka 120a6e
    return TRect(0, 0, m_lrm->m_lx - 1, m_lrm->m_ly - 1);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  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
Shinya Kitaoka 120a6e
TImageWriterMov::TImageWriterMov(const TFilePath &path, int frameIndex,
Shinya Kitaoka 120a6e
                                 TLevelWriterMov *lwm)
Shinya Kitaoka 120a6e
    : TImageWriter(path), m_lwm(lwm), m_frameIndex(frameIndex) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TImageWriterMov::save(const TImageP &img) { assert(false); }
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)
Shinya Kitaoka 120a6e
    : 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
{
Shinya Kitaoka 120a6e
  assert(false);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TLevelWriterMov::saveSoundTrack(TSoundTrack *) {
Shinya Kitaoka 120a6e
  throw TImageException(m_path,
Shinya Kitaoka 120a6e
                        "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
Shinya Kitaoka 120a6e
TLevelWriterMov::~TLevelWriterMov() { assert(0); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TImageWriterP TLevelWriterMov::getFrameWriter(TFrameId fid) { assert(false); }
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
Shinya Kitaoka 120a6e
TImageReaderMov::TImageReaderMov(const TFilePath &path, int frameIndex,
Shinya Kitaoka 120a6e
                                 TLevelReaderMov *lrm)
Shinya Kitaoka 120a6e
    : TImageReader(path), m_lrm(lrm), m_frameIndex(frameIndex) {}
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)
Shinya Kitaoka 120a6e
    : TLevelReader(path)
Shinya Kitaoka 120a6e
    , m_IOError(QTNoError)
Shinya Kitaoka 120a6e
    , m_lastFrameDecoded(-1)
Shinya Kitaoka 120a6e
    , m_fileMov(0)
Shinya Kitaoka 120a6e
    , m_lx(0)
Shinya Kitaoka 120a6e
    , m_ly(0) {
Shinya Kitaoka 120a6e
  if (!TFileStatus(path).doesExist()) {
Shinya Kitaoka 120a6e
    m_IOError = QTNoSuchFile;
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_fileMov = oqt_open((char *)path.getString().c_str());
Shinya Kitaoka 120a6e
  if (!m_fileMov) {
Shinya Kitaoka 120a6e
    m_IOError = QTUnableToOpenFile;
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  oqt_read_headers(m_fileMov);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
if(!oqt_get_video_track_count(m_fileMov))
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 120a6e
m_status = !DM_SUCCESS;
Shinya Kitaoka 120a6e
m_IOError = QTCheckLibError;
Shinya Kitaoka 120a6e
return;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_lx = oqt_get_video_width(m_fileMov, 0);
Shinya Kitaoka 120a6e
  m_ly = oqt_get_video_height(m_fileMov, 0);
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
char *vc = oqt_get_video_compressor(m_fileMov, 0);
Shinya Kitaoka 120a6e
cout << "video compressor = " << vc[0] << vc[1] << vc[2] << vc[3] << endl;
Shinya Kitaoka 120a6e
*/
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TLevelReaderMov::~TLevelReaderMov() {
Shinya Kitaoka 120a6e
  if (m_fileMov) oqt_close(m_fileMov);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TLevelP TLevelReaderMov::loadInfo() {
Shinya Kitaoka 120a6e
  TLevelP level;
Shinya Kitaoka 120a6e
  if (m_IOError != QTNoError) {
Shinya Kitaoka 120a6e
    throw TQTException(m_path, m_IOError);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (oqt_supported_video(m_fileMov, 0) == 0) {
Shinya Kitaoka 120a6e
    m_IOError = QTUnsupportedVideoFormat;
Shinya Kitaoka 120a6e
    throw TQTException(m_path, m_IOError);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int frameCount = oqt_get_video_length(m_fileMov, 0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (int i = 1; i <= frameCount; i++) level->setFrame(TFrameId(i), TImageP());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef DUMP_KEYFRAMES
Shinya Kitaoka 120a6e
  for (int k = 1; k < frameCount; k++) {
Shinya Kitaoka 120a6e
    cout << "frame = " << k << "; keyframe before = "
Shinya Kitaoka 120a6e
         << oqt_get_video_keyframe_before(m_fileMov, 0, k)
Shinya Kitaoka 120a6e
         << "; keyframe after = "
Shinya Kitaoka 120a6e
         << oqt_get_video_keyframe_after(m_fileMov, 0, k) << endl;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return level;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TImageP TImageReaderMov::load() {
Shinya Kitaoka 120a6e
  if (m_lrm->m_IOError != QTNoError)
Shinya Kitaoka 120a6e
    throw TQTException(m_path, m_lrm->m_IOError);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TThread::ScopedLock sl(m_lrm->m_mutex);
Shinya Kitaoka 120a6e
  int rc;
Shinya Kitaoka 120a6e
  TRaster32P ret(m_lrm->m_lx, m_lrm->m_ly);
Shinya Kitaoka 120a6e
  unsigned char **data =
Shinya Kitaoka 120a6e
      (unsigned char **)malloc(m_lrm->m_ly * sizeof(unsigned char *));
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_lrm->m_ly; ++i) {
Shinya Kitaoka 120a6e
    unsigned char *ptr = (unsigned char *)ret->pixels(i);
Shinya Kitaoka 120a6e
    data[i]            = ptr;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  int cmodel = BC_RGBA8888;
Shinya Kitaoka 120a6e
  int frame;
Shinya Kitaoka 120a6e
  if (m_lrm->m_lastFrameDecoded != (m_frameIndex - 1)) {
Shinya Kitaoka 120a6e
    oqt_int64_t kfb =
Shinya Kitaoka 120a6e
        oqt_get_video_keyframe_before(m_lrm->m_fileMov, 0, m_frameIndex);
Shinya Kitaoka 120a6e
    assert(kfb <= m_frameIndex);
Shinya Kitaoka 120a6e
    rc = oqt_set_video_position(m_lrm->m_fileMov, 0, kfb);
Shinya Kitaoka 120a6e
    if (rc) {
Shinya Kitaoka 120a6e
      throw TQTException(m_lrm->m_path, QTUnableToSeekToKeyFrame, kfb);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    frame = kfb - 1;
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    frame = m_lrm->m_lastFrameDecoded;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  do {
Shinya Kitaoka 120a6e
    rc = oqt_decode_video(m_lrm->m_fileMov, 0, cmodel, data);
Shinya Kitaoka 120a6e
    frame++;
Shinya Kitaoka 120a6e
  } while (frame != m_frameIndex);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_lrm->m_lastFrameDecoded = m_frameIndex;
Shinya Kitaoka 120a6e
  ret->yMirror();
Shinya Kitaoka 120a6e
  free(data);
Shinya Kitaoka 120a6e
  return TRasterImageP(ret);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TImageReaderP TLevelReaderMov::getFrameReader(TFrameId fid) {
Shinya Kitaoka 120a6e
  if (m_IOError != QTNoError) {
Shinya Kitaoka 120a6e
    throw TQTException(m_path, m_IOError);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (fid.getLetter() != 0) return TImageReaderP(0);
Shinya Kitaoka 120a6e
  int index = fid.getNumber() - 1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TImageReaderMov *irm = new TImageReaderMov(m_path, index, this);
Shinya Kitaoka 120a6e
  return TImageReaderP(irm);
Toshihiro Shimizu 890ddd
}