Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifndef x64
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "texception.h"
Toshihiro Shimizu 890ddd
#include "tsound.h"
Toshihiro Shimizu 890ddd
#include "tconvert.h"
Toshihiro Shimizu 890ddd
#include "tpropertytype.h"
Toshihiro Shimizu 890ddd
#include "timageinfo.h"
Toshihiro Shimizu 890ddd
#include "tlevel_io.h"
Toshihiro Shimizu 890ddd
#include "../avi/tiio_avi.h"
Toshihiro Shimizu 890ddd
#include "trasterimage.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tiio_mov.h"
Toshihiro Shimizu 890ddd
#include "movsettings.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace  stuff
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
const std::string firstFrameKey = "frst";            // First frame atom id
Shinya Kitaoka 120a6e
const int firstFrameKeySize     = 4 * sizeof(char);  //
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class QuickTimeCleanUp;
Shinya Kitaoka 120a6e
class QuickTimeStuff {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  static QuickTimeStuff *instance() {
Shinya Kitaoka 120a6e
    if (!m_singleton) m_singleton = new QuickTimeStuff();
Shinya Kitaoka 120a6e
    return m_singleton;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  OSErr getStatus() { return m_status; }
Shinya Kitaoka 120a6e
  ~QuickTimeStuff() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  QuickTimeStuff() : m_status(noErr) {
Shinya Kitaoka 120a6e
    m_status = InitializeQTML(0);
Shinya Kitaoka 120a6e
    EnterMovies();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  static QuickTimeStuff *m_singleton;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  OSErr m_status;
Shinya Kitaoka 120a6e
  friend class QuickTimeCleanUp;  // questa DEVE essere friend, cosi' posso
Shinya Kitaoka 120a6e
                                  // controllare direttamente
Shinya Kitaoka 120a6e
  // lo stato del singleton.
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class QuickTimeCleanUp {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  QuickTimeCleanUp() {}
Shinya Kitaoka 120a6e
  ~QuickTimeCleanUp() { /*
Shinya Kitaoka 120a6e
                                      Nel caso si arrivasse qui senza il
Shinya Kitaoka 120a6e
                           singleton instanziato, e si facesse direttamente
Shinya Kitaoka 120a6e
                                      'delete QuickTimeStuff::instance();'
Shinya Kitaoka 120a6e
                           Quicktime non farebbe in tempo a terminare le
Shinya Kitaoka 120a6e
                                      sue routine di inizializzazione (che sono
Shinya Kitaoka 120a6e
                           ANCHE su altri thread) e la chiamata a
Shinya Kitaoka 120a6e
                                      TerminateQTML() causerebbe un crash
Shinya Kitaoka 120a6e
                                      */
Shinya Kitaoka 120a6e
    if (QuickTimeStuff::m_singleton) delete QuickTimeStuff::m_singleton;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
QuickTimeCleanUp cleanUp;
Toshihiro Shimizu 890ddd
QuickTimeStuff *QuickTimeStuff::m_singleton = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
enum QTLibError {
Shinya Kitaoka 120a6e
  QTNoError = 0x0000,
Shinya Kitaoka 120a6e
  QTNotInstalled,
Shinya Kitaoka 120a6e
  QTUnknownError,
Shinya Kitaoka 120a6e
  QTUnableToOpenFile,
Shinya Kitaoka 120a6e
  QTCantCreateFile,
Shinya Kitaoka 120a6e
  QTUnableToGetCompressorNames,
Shinya Kitaoka 120a6e
  QTUnableToCreateResource,
Shinya Kitaoka 120a6e
  QTUnableToUpdateMovie,
Shinya Kitaoka 120a6e
  QTBadTimeValue,
Shinya Kitaoka 120a6e
  QTUnableToDoMovieTask,
Shinya Kitaoka 120a6e
  QTUnableToSetTimeValue,
Shinya Kitaoka 120a6e
  QTUnableToSetMovieGWorld,
Shinya Kitaoka 120a6e
  QTUnableToSetMovieBox,
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
string buildQTErrorString(int ec) {
Shinya Kitaoka 120a6e
  switch (ec) {
Shinya Kitaoka 120a6e
  case QTNotInstalled:
Shinya Kitaoka 120a6e
    return "Can't create; ensure that quicktime is correctly installed on your "
Shinya Kitaoka 120a6e
           "machine";
Shinya Kitaoka 120a6e
  case QTUnknownError:
Shinya Kitaoka 120a6e
    return "Unknown error";
Shinya Kitaoka 120a6e
  case QTUnableToOpenFile:
Shinya Kitaoka 120a6e
    return "can't open file";
Shinya Kitaoka 120a6e
  case QTCantCreateFile:
Shinya Kitaoka 120a6e
    return "can't create movie";
Shinya Kitaoka 120a6e
  case QTUnableToGetCompressorNames:
Shinya Kitaoka 120a6e
    return "unable to get compressor name";
Shinya Kitaoka 120a6e
  case QTUnableToCreateResource:
Shinya Kitaoka 120a6e
    return "can't create resource";
Shinya Kitaoka 120a6e
  case QTUnableToUpdateMovie:
Shinya Kitaoka 120a6e
    return "unable to update movie";
Shinya Kitaoka 120a6e
  case QTBadTimeValue:
Shinya Kitaoka 120a6e
    return "bad frame number";
Shinya Kitaoka 120a6e
  case QTUnableToDoMovieTask:
Shinya Kitaoka 120a6e
    return "unable to do movie task";
Shinya Kitaoka 120a6e
  case QTUnableToSetTimeValue:
Shinya Kitaoka 120a6e
    return "unable to set time value";
Shinya Kitaoka 120a6e
  case QTUnableToSetMovieGWorld:
Shinya Kitaoka 120a6e
    return "unable to set movie graphic world";
Shinya Kitaoka 120a6e
  case QTUnableToSetMovieBox:
Shinya Kitaoka 120a6e
    return "unable to set movie box";
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  default: { return "unknown error ('" + std::to_string(ec) + "')"; }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline LPSTR AtlW2AHelper(LPSTR lpa, LPCWSTR lpw, int nChars, UINT acp) {
Shinya Kitaoka 120a6e
  assert(lpw != NULL);
Shinya Kitaoka 120a6e
  assert(lpa != NULL);
Shinya Kitaoka 120a6e
  // verify that no illegal character present
Shinya Kitaoka 120a6e
  // since lpa was allocated based on the size of lpw
Shinya Kitaoka 120a6e
  // don't worry about the number of chars
Shinya Kitaoka 120a6e
  lpa[0] = '\0';
Shinya Kitaoka 120a6e
  WideCharToMultiByte(acp, 0, lpw, -1, lpa, nChars, NULL, NULL);
Shinya Kitaoka 120a6e
  return lpa;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline char *filePath2unichar(const TFilePath &path) {
Shinya Kitaoka 120a6e
  int _convert    = 0;
Shinya Kitaoka 120a6e
  std::wstring ws = path.getWideString();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  LPCWSTR lpw = ws.c_str();
Shinya Kitaoka 120a6e
  char *name  = NULL;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (lpw) {
Shinya Kitaoka 120a6e
    _convert   = (lstrlenW(lpw) + 1) * 2;
Shinya Kitaoka 120a6e
    LPSTR pStr = new char[_convert];
Shinya Kitaoka 120a6e
    name       = AtlW2AHelper(pStr, lpw, _convert, 0);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  char *outName = new char[1024];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (QTMLGetCanonicalPathName(name, outName, 1024) == noErr) {
Shinya Kitaoka 120a6e
    delete[] name;
Shinya Kitaoka 120a6e
    return outName;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  delete[] outName;
Shinya Kitaoka 120a6e
  return name;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFilePath getLegalName(const TFilePath &name) {
Shinya Kitaoka 120a6e
  if (QuickTimeStuff::instance()->getStatus() != noErr) return name;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFilePath legalName;
Shinya Kitaoka 120a6e
  char outDir[1024];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFilePath dirName(name.getParentDir());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  char dirNameFp[1024] = "";
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  OSErr err = QTMLGetCanonicalPathName(dirNameFp, outDir, 1024);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (err == noErr)
Shinya Kitaoka 120a6e
    legalName = TFilePath(outDir) + name.withoutParentDir();
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    legalName = name;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return legalName;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
string long2fourchar(TINT32 fcc) {
Shinya Kitaoka 120a6e
  string s;
Shinya Kitaoka 120a6e
  s += (char((fcc & 0xff000000) >> 24));
Shinya Kitaoka 120a6e
  s += (char((fcc & 0x00ff0000) >> 16));
Shinya Kitaoka 120a6e
  s += (char((fcc & 0x0000ff00) >> 8));
Shinya Kitaoka 120a6e
  s += (char((fcc & 0x000000ff) >> 0));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return s;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TimeScale frameRateToTimeScale(double frameRate) {
Shinya Kitaoka 120a6e
  return tround(frameRate * 100.0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// const std::string CodecNamesId   = "PU_CodecName";
Shinya Kitaoka 120a6e
// const std::string CodecQualityId = "PU_CodecQuality";
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool IsQuickTimeInstalled() {
Shinya Kitaoka 120a6e
  return QuickTimeStuff::instance()->getStatus() == noErr;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//  TImageWriterMov
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class TImageWriterMov final : public TImageWriter {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  TImageWriterMov(const TFilePath &, int frameIndex, TLevelWriterMov *);
Shinya Kitaoka 120a6e
  ~TImageWriterMov() { m_lwm->release(); }
Shinya Kitaoka 473e70
  bool is64bitOutputSupported() override { 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 473e70
  void save(const TImageP &) override;
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
//-----------------------------------------------------------
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) {
Shinya Kitaoka 120a6e
  m_lwm->addRef();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
void copy(TRasterP rin, PixelXRGB *bufout, int lx, int ly) {
Shinya Kitaoka 120a6e
  TRaster32P rin32 = rin;
Shinya Kitaoka 120a6e
  assert(rin32);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  PixelXRGB *rowout = &(bufout[(ly - 1) * lx]);
Shinya Kitaoka 120a6e
  rin32->lock();
Shinya Kitaoka 120a6e
  for (int y = 0; y < rin32->getLy(); y++) {
Shinya Kitaoka 120a6e
    PixelXRGB *pixout      = rowout;
Shinya Kitaoka 120a6e
    TPixelRGBM32 *pixin    = rin32->pixels(y);
Shinya Kitaoka 120a6e
    TPixelRGBM32 *pixinEnd = pixin + rin32->getLx();
Shinya Kitaoka 120a6e
    while (pixin < pixinEnd) {
Shinya Kitaoka 120a6e
      pixout->x = pixin->m;
Shinya Kitaoka 120a6e
      pixout->r = pixin->r;
Shinya Kitaoka 120a6e
      pixout->g = pixin->g;
Shinya Kitaoka 120a6e
      pixout->b = pixin->b;
Shinya Kitaoka 120a6e
      pixout++;
Shinya Kitaoka 120a6e
      pixin++;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    rowout -= lx;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  rin32->unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
/*
Shinya Kitaoka 3bfa54
TWriterInfo *TWriterInfoMov::create(const std::string &)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
return new TWriterInfoMov();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TWriterInfoMov::TWriterInfoMov(const TWriterInfoMov&src)
Toshihiro Shimizu 890ddd
               :TWriterInfo(src)
Toshihiro Shimizu 890ddd
               ,m_codecTable(src.m_codecTable)
Toshihiro Shimizu 890ddd
               ,m_qualityTable(src.m_qualityTable)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TWriterInfo *TWriterInfoMov::clone() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
return new TWriterInfoMov(*this);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
/*
Shinya Kitaoka d1f6c4
class MovWriterProperties final : public TPropertyGroup {
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
  TEnumProperty m_codec;
Toshihiro Shimizu 890ddd
  TEnumProperty m_quality;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Tiio::TifWriterProperties::TifWriterProperties()
Toshihiro Shimizu 890ddd
                    : m_byteOrdering("Byte Order")
Toshihiro Shimizu 890ddd
                    , m_compressionType("Compression Type")
Toshihiro Shimizu 890ddd
                    , m_matte("Alpha Channel", true)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
    m_byteOrdering.addValue(L"IBM PC");
Toshihiro Shimizu 890ddd
    m_byteOrdering.addValue(L"Mac");
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Toshihiro Shimizu 890ddd
  m_byteOrdering.setValue(L"IBM PC");
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
  m_byteOrdering.setValue(L"Mac");
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  m_compressionType.addValue(L"NONE");
Toshihiro Shimizu 890ddd
  m_compressionType.addValue(L"LZW");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  bind(m_byteOrdering);
Toshihiro Shimizu 890ddd
  bind(m_matte);
Toshihiro Shimizu 890ddd
  bind(m_compressionType);
Toshihiro Shimizu 890ddd
  m_compressionType.setValue(L"LZW");
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
CodecType Tiio::MovWriterProperties::getCurrentCodec()const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
std::map<wstring, codectype="">::const_iterator it;</wstring,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
it = m_codecMap.find(m_codec.getValue());
Toshihiro Shimizu 890ddd
assert(it!=m_codecMap.end());
Toshihiro Shimizu 890ddd
return it->second;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
wstring Tiio::MovWriterProperties::getCurrentNameFromCodec(CodecType
Shinya Kitaoka 120a6e
&cCodec)const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
std::map<wstring, codectype="">::const_iterator it;</wstring,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
for(it=m_codecMap.begin();it!=m_codecMap.end();++it)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
  CodecType tmp=it->second;
Toshihiro Shimizu 890ddd
  if(it->second==cCodec) break;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
assert(it!=m_codecMap.end());
Toshihiro Shimizu 890ddd
return it->first;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
wstring Tiio::MovWriterProperties::getCurrentQualityFromCodeQ(CodecQ
Shinya Kitaoka 120a6e
&cCodecQ)const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
std::map<wstring, codecq="">::const_iterator it;</wstring,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
for(it=m_qualityMap.begin();it!=m_qualityMap.end();++it)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
  CodecQ tmp=it->second;
Toshihiro Shimizu 890ddd
  if(it->second==cCodecQ) break;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
assert(it!=m_qualityMap.end());
Toshihiro Shimizu 890ddd
return it->first;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
CodecQ Tiio::MovWriterProperties::getCurrentQuality() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
std::map<wstring, codecq="">::const_iterator it;</wstring,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
it = m_qualityMap.find(m_quality.getValue());
Toshihiro Shimizu 890ddd
assert(it!=m_qualityMap.end());
Toshihiro Shimizu 890ddd
return it->second;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
TPropertyGroup* Tiio::MovWriterProperties::clone() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
  MovWriterProperties*g = new MovWriterProperties();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        g->m_codec.setValue(m_codec.getValue());
Shinya Kitaoka 120a6e
        g->m_quality.setValue(m_quality.getValue());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
return (TPropertyGroup*)g;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Tiio::MovWriterProperties::MovWriterProperties()
Toshihiro Shimizu 890ddd
//: m_codec("Codec")
Toshihiro Shimizu 890ddd
//, m_quality("Quality")
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 120a6e
  if (InitializeQTML(0) != noErr) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ComponentInstance ci =
Shinya Kitaoka 120a6e
      OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
Shinya Kitaoka 120a6e
  QTAtomContainer settings;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (SCGetSettingsAsAtomContainer(ci, &settings) != noErr) assert(false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  fromAtomsToProperties(settings, *this);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TImageWriterMov::save(const TImageP &img) {
Shinya Kitaoka 120a6e
  m_lwm->save(img, m_frameIndex);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TLevelWriterMov::save(const TImageP &img, int frameIndex) {
Shinya Kitaoka 120a6e
  m_firstFrame = std::min(frameIndex, m_firstFrame);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRasterImageP image(img);
Shinya Kitaoka 120a6e
  if (!image) throw TImageException(getFilePath(), "Unsupported image type");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int lx = image->getRaster()->getLx();
Shinya Kitaoka 120a6e
  int ly = image->getRaster()->getLy();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int pixSize = image->getRaster()->getPixelSize();
Shinya Kitaoka 120a6e
  if (pixSize != 4)
Shinya Kitaoka 120a6e
    throw TImageException(getFilePath(), "Unsupported pixel type");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QMutexLocker sl(&m_mutex);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!m_videoTrack) {
Shinya Kitaoka 120a6e
    if (!m_properties) m_properties = new Tiio::MovWriterProperties();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    Tiio::MovWriterProperties *prop =
Shinya Kitaoka 120a6e
        (Tiio::MovWriterProperties *)(m_properties);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    QTAtomContainer atoms;
Shinya Kitaoka 120a6e
    QTNewAtomContainer(&atoms);
Shinya Kitaoka 120a6e
    fromPropertiesToAtoms(*prop, atoms);
Shinya Kitaoka 120a6e
    m_ci = OpenDefaultComponent(StandardCompressionType,
Shinya Kitaoka 120a6e
                                StandardCompressionSubType);
Shinya Kitaoka 120a6e
    if (SCSetSettingsFromAtomContainer(m_ci, atoms) != noErr) {
Shinya Kitaoka 120a6e
      CloseComponent(m_ci);
Shinya Kitaoka 120a6e
      assert(!"cannot use that quickTime codec, use default");
Shinya Kitaoka 120a6e
      m_ci = OpenDefaultComponent(StandardCompressionType,
Shinya Kitaoka 120a6e
                                  StandardCompressionSubType);
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    QTDisposeAtomContainer(atoms);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    Rect frame;
Shinya Kitaoka 120a6e
    QDErr err;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (QuickTimeStuff::instance()->getStatus() != noErr) {
Shinya Kitaoka 120a6e
      m_IOError = QTNotInstalled;
Shinya Kitaoka 120a6e
      throw TImageException(m_path, buildQTErrorString(m_IOError));
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // First, set the movie's time scale to match a suitable multiple of
Shinya Kitaoka 120a6e
    // m_frameRate.
Shinya Kitaoka 120a6e
    // The timeScale will be used for both the movie and media.
Shinya Kitaoka 120a6e
    TimeScale timeScale = ::frameRateToTimeScale(m_frameRate);
Shinya Kitaoka 120a6e
    SetMovieTimeScale(m_movie, timeScale);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_videoTrack = NewMovieTrack(m_movie, FixRatio((short)lx, 1),
Shinya Kitaoka 120a6e
                                 FixRatio((short)ly, 1), kNoVolume);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if ((err = GetMoviesError() != noErr))
Shinya Kitaoka 120a6e
      throw TImageException(getFilePath(), "can't create video track");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_videoMedia = NewTrackMedia(m_videoTrack, VideoMediaType, timeScale, 0, 0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if ((err = GetMoviesError() != noErr))
Shinya Kitaoka 120a6e
      throw TImageException(getFilePath(), "can't create video media");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    frame.left   = 0;
Shinya Kitaoka 120a6e
    frame.top    = 0;
Shinya Kitaoka 120a6e
    frame.right  = lx;
Shinya Kitaoka 120a6e
    frame.bottom = ly;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if ((err = NewGWorld(&(m_gworld), pixSize * 8, &frame, 0, 0, 0)) != noErr)
Shinya Kitaoka 120a6e
      throw TImageException(getFilePath(), "can't create movie buffer");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    LockPixels(m_gworld->portPixMap);
Shinya Kitaoka 120a6e
    /*
Shinya Kitaoka 120a6e
if ((err = ImageCodecGetMaxCompressionSize(Ci, m_gworld->portPixMap, &frame, 0,
Shinya Kitaoka 120a6e
                                   quality, codecType, anyCodec,
Shinya Kitaoka 120a6e
                                   &max_compressed_size))!=noErr)
Shinya Kitaoka 120a6e
                                   throw TImageException(getFilePath(), "can't
Shinya Kitaoka 120a6e
get max compression size");
Shinya Kitaoka 120a6e
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if ((err = MemError()) != noErr)
Shinya Kitaoka 120a6e
      throw TImageException(getFilePath(), "can't allocate img handle");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_pixmap = GetGWorldPixMap(m_gworld);
Shinya Kitaoka 120a6e
    if (!LockPixels(m_pixmap))
Shinya Kitaoka 120a6e
      throw TImageException(getFilePath(), "can't lock pixels");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_buf  = (PixelXRGB *)(*(m_pixmap))->baseAddr;
Shinya Kitaoka 120a6e
    buf_lx = lx;
Shinya Kitaoka 120a6e
    buf_ly = ly;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  OSErr err = noErr;
Shinya Kitaoka 120a6e
  if ((err = BeginMediaEdits(m_videoMedia)) != noErr)
Shinya Kitaoka 120a6e
    throw TImageException(getFilePath(), "can't begin edit video media");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  Rect frame;
Shinya Kitaoka 120a6e
  ImageDescriptionHandle img_descr = 0;
Shinya Kitaoka 120a6e
  Handle compressedData            = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  frame.left   = 0;
Shinya Kitaoka 120a6e
  frame.top    = 0;
Shinya Kitaoka 120a6e
  frame.right  = lx;
Shinya Kitaoka 120a6e
  frame.bottom = ly;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRasterP ras = image->getRaster();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  copy(ras, m_buf, buf_lx, buf_ly);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if ((err = SCCompressImage(m_ci, m_gworld->portPixMap, &frame, &img_descr,
Shinya Kitaoka 120a6e
                             &compressedData)) != noErr)
Shinya Kitaoka 120a6e
    throw TImageException(getFilePath(), "can't compress image");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
if ((err = CompressImage(m_gworld->portPixMap,
Shinya Kitaoka 120a6e
&frame,
Shinya Kitaoka 120a6e
quality, codecType,
Shinya Kitaoka 120a6e
img_descr, compressed_data_ptr))!=noErr)
Shinya Kitaoka 120a6e
throw TImageException(getFilePath(), "can't compress image");
Shinya Kitaoka 120a6e
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TimeValue sampleTime;
Shinya Kitaoka 120a6e
  if ((err = AddMediaSample(m_videoMedia, compressedData, 0,
Shinya Kitaoka 120a6e
                            (*img_descr)->dataSize,
Shinya Kitaoka 120a6e
                            100,  // 100 matches the length of 1 frame
Shinya Kitaoka 120a6e
                            (SampleDescriptionHandle)
Shinya Kitaoka 120a6e
                                img_descr,  // in the movie/media's timeScale
Shinya Kitaoka 120a6e
                            1,
Shinya Kitaoka 120a6e
                            0, &sampleTime)) != noErr)
Shinya Kitaoka 120a6e
    throw TImageException(getFilePath(), "can't add image to movie media");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if ((err = EndMediaEdits(m_videoMedia)) != noErr)
Shinya Kitaoka 120a6e
    throw TImageException(getFilePath(), "can't end edit media");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  DisposeHandle(compressedData);
Shinya Kitaoka 120a6e
  DisposeHandle((Handle)img_descr);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_savedFrames.push_back(std::pair<int, timevalue="">(frameIndex, sampleTime));</int,>
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
//        TLevelWriterMov
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TLevelWriterMov::TLevelWriterMov(const TFilePath &path, TPropertyGroup *winfo)
Shinya Kitaoka 120a6e
    : TLevelWriter(path, winfo)
Shinya Kitaoka 120a6e
    , m_IOError(QTNoError)
Shinya Kitaoka 120a6e
    , m_pixmap(0)
Shinya Kitaoka 120a6e
    , m_gworld(0)
Shinya Kitaoka 120a6e
    , m_videoMedia(0)
Shinya Kitaoka 120a6e
    , m_soundMedia(0)
Shinya Kitaoka 120a6e
    , m_videoTrack(0)
Shinya Kitaoka 120a6e
    , m_soundTrack(0)
Shinya Kitaoka 120a6e
    , m_movie(0)
Shinya Kitaoka 120a6e
    , m_firstFrame((std::numeric_limits<int>::max)()) {</int>
Shinya Kitaoka 120a6e
  m_frameRate = 12.;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  char *pStr = filePath2unichar(m_path);
Shinya Kitaoka 120a6e
  QDErr err;
Shinya Kitaoka 120a6e
  FSSpec fspec;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if ((err = NativePathNameToFSSpec(pStr, &fspec, kFullNativePath)) != noErr) {
Shinya Kitaoka 120a6e
    delete[] pStr;
Shinya Kitaoka 120a6e
    pStr      = 0;
Shinya Kitaoka 120a6e
    m_IOError = QTUnableToOpenFile;
Shinya Kitaoka 120a6e
    throw TImageException(m_path, buildQTErrorString(m_IOError));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  delete[] pStr;
Shinya Kitaoka 120a6e
  pStr = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (err = CreateMovieFile(
Shinya Kitaoka 120a6e
                &fspec, 'TVOD', smCurrentScript,
Shinya Kitaoka 120a6e
                createMovieFileDeleteCurFile | createMovieFileDontCreateResFile,
Shinya Kitaoka 120a6e
                &(m_refNum), &(m_movie)) != noErr) {
Shinya Kitaoka 120a6e
    m_IOError = QTCantCreateFile;
Shinya Kitaoka 120a6e
    throw TImageException(m_path, buildQTErrorString(m_IOError));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Shinya Kitaoka 120a6e
#define FailIf(cond, handler)                                                  \
Shinya Kitaoka 120a6e
  if (cond) {                                                                  \
Shinya Kitaoka 120a6e
    DebugStr((ConstStr255Param) #cond " goto " #handler);                      \
Shinya Kitaoka 120a6e
    goto handler;                                                              \
Shinya Kitaoka 120a6e
  } else                                                                       \
Shinya Kitaoka 120a6e
    0
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
#define FailIf(cond, handler)                                                  \
Shinya Kitaoka 120a6e
  if (cond) {                                                                  \
Shinya Kitaoka 120a6e
    goto handler;                                                              \
Shinya Kitaoka 120a6e
  } else                                                                       \
Shinya Kitaoka 120a6e
    0
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Shinya Kitaoka 120a6e
#define FailWithAction(cond, action, handler)                                  \
Shinya Kitaoka 120a6e
  if (cond) {                                                                  \
Shinya Kitaoka 120a6e
    DebugStr((ConstStr255Param) #cond " goto " #handler);                      \
Shinya Kitaoka 120a6e
    { action; }                                                                \
Shinya Kitaoka 120a6e
    goto handler;                                                              \
Shinya Kitaoka 120a6e
  } else                                                                       \
Shinya Kitaoka 120a6e
    0
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
#define FailWithAction(cond, action, handler)                                  \
Shinya Kitaoka 120a6e
  if (cond) {                                                                  \
Shinya Kitaoka 120a6e
    { action; }                                                                \
Shinya Kitaoka 120a6e
    goto handler;                                                              \
Shinya Kitaoka 120a6e
  } else                                                                       \
Shinya Kitaoka 120a6e
    0
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TLevelWriterMov::saveSoundTrack(TSoundTrack *st) {
Shinya Kitaoka 120a6e
  OSErr myErr = noErr;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!st) throw TException("null reference to soundtrack");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (st->getBitPerSample() != 16)
Shinya Kitaoka 120a6e
    throw TImageException(m_path, "Only 16 bits per sample is supported");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_soundTrack == 0) {
Shinya Kitaoka 120a6e
    m_soundTrack = NewMovieTrack(m_movie, 0, 0, kFullVolume);
Shinya Kitaoka 120a6e
    myErr        = GetMoviesError();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    FailIf(myErr != noErr, CompressErr);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_soundMedia =
Shinya Kitaoka 120a6e
        NewTrackMedia(m_soundTrack, SoundMediaType, st->getSampleRate(), NULL,
Shinya Kitaoka 120a6e
                      0);  // track->rate >> 16
Shinya Kitaoka 120a6e
    myErr = GetMoviesError();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    FailIf(myErr != noErr, Exit);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  SoundDescriptionV1Handle mySampleDesc;
Shinya Kitaoka 120a6e
  Handle myDestHandle;
Shinya Kitaoka 120a6e
  SoundComponentData sourceInfo;
Shinya Kitaoka 120a6e
  SoundComponentData destInfo;
Shinya Kitaoka 120a6e
  SoundConverter converter;
Shinya Kitaoka 120a6e
  CompressionInfo compressionInfo;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  myDestHandle = NewHandle(0);
Shinya Kitaoka 120a6e
  FailWithAction(myDestHandle == NULL, myErr = MemError(), NoDest);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  *myDestHandle = (char *)st->getRawData();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // start a media editing session
Shinya Kitaoka 120a6e
  myErr = BeginMediaEdits(m_soundMedia);
Shinya Kitaoka 120a6e
  FailIf(myErr != noErr, Exit);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  sourceInfo.flags       = 0x0;
Shinya Kitaoka 120a6e
  sourceInfo.format      = kSoundNotCompressed;
Shinya Kitaoka 120a6e
  sourceInfo.numChannels = st->getChannelCount();
Shinya Kitaoka 120a6e
  sourceInfo.sampleSize  = st->getBitPerSample();
Shinya Kitaoka 120a6e
  sourceInfo.sampleRate  = st->getSampleRate();
Shinya Kitaoka 120a6e
  sourceInfo.sampleCount = st->getSampleCount();
Shinya Kitaoka 120a6e
  sourceInfo.buffer      = (unsigned char *)st->getRawData();
Shinya Kitaoka 120a6e
  sourceInfo.reserved    = 0x0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  destInfo.flags = kNoSampleRateConversion | kNoSampleSizeConversion |
Shinya Kitaoka 120a6e
                   kNoSampleFormatConversion | kNoChannelConversion |
Shinya Kitaoka 120a6e
                   kNoDecompression | kNoVolumeConversion |
Shinya Kitaoka 120a6e
                   kNoRealtimeProcessing;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  destInfo.format      = k16BitNativeEndianFormat;
Shinya Kitaoka 120a6e
  destInfo.numChannels = st->getChannelCount();
Shinya Kitaoka 120a6e
  destInfo.sampleSize  = st->getBitPerSample();
Shinya Kitaoka 120a6e
  destInfo.sampleRate  = st->getSampleRate();
Shinya Kitaoka 120a6e
  destInfo.sampleCount = st->getSampleCount();
Shinya Kitaoka 120a6e
  destInfo.buffer      = (unsigned char *)st->getRawData();
Shinya Kitaoka 120a6e
  destInfo.reserved    = 0x0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  SoundConverterOpen(&sourceInfo, &destInfo, &converter);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  myErr =
Shinya Kitaoka 120a6e
      SoundConverterGetInfo(converter, siCompressionFactor, &compressionInfo);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  myErr =
Shinya Kitaoka 120a6e
      SoundConverterGetInfo(converter, siCompressionFactor, &compressionInfo);
Shinya Kitaoka 120a6e
  myErr = GetCompressionInfo(fixedCompression, sourceInfo.format,
Shinya Kitaoka 120a6e
                             sourceInfo.numChannels, sourceInfo.sampleSize,
Shinya Kitaoka 120a6e
                             &compressionInfo);
Shinya Kitaoka 120a6e
  FailIf(myErr != noErr, ConverterErr);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  compressionInfo.bytesPerFrame =
Shinya Kitaoka 120a6e
      compressionInfo.bytesPerPacket * destInfo.numChannels;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //////////
Shinya Kitaoka 120a6e
  //
Shinya Kitaoka 120a6e
  // create a sound sample description
Shinya Kitaoka 120a6e
  //
Shinya Kitaoka 120a6e
  //////////
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // use the SoundDescription format 1 because it adds fields for data size
Shinya Kitaoka 120a6e
  // information
Shinya Kitaoka 120a6e
  // and is required by AddSoundDescriptionExtension if an extension is required
Shinya Kitaoka 120a6e
  // for the compression format
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  mySampleDesc =
Shinya Kitaoka 120a6e
      (SoundDescriptionV1Handle)NewHandleClear(sizeof(SoundDescriptionV1));
Shinya Kitaoka 120a6e
  FailWithAction(myErr != noErr, myErr = MemError(), Exit);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  (**mySampleDesc).desc.descSize      = sizeof(SoundDescriptionV1);
Shinya Kitaoka 120a6e
  (**mySampleDesc).desc.dataFormat    = destInfo.format;
Shinya Kitaoka 120a6e
  (**mySampleDesc).desc.resvd1        = 0;
Shinya Kitaoka 120a6e
  (**mySampleDesc).desc.resvd2        = 0;
Shinya Kitaoka 120a6e
  (**mySampleDesc).desc.dataRefIndex  = 1;
Shinya Kitaoka 120a6e
  (**mySampleDesc).desc.version       = 1;
Shinya Kitaoka 120a6e
  (**mySampleDesc).desc.revlevel      = 0;
Shinya Kitaoka 120a6e
  (**mySampleDesc).desc.vendor        = 0;
Shinya Kitaoka 120a6e
  (**mySampleDesc).desc.numChannels   = destInfo.numChannels;
Shinya Kitaoka 120a6e
  (**mySampleDesc).desc.sampleSize    = destInfo.sampleSize;
Shinya Kitaoka 120a6e
  (**mySampleDesc).desc.compressionID = 0;
Shinya Kitaoka 120a6e
  (**mySampleDesc).desc.packetSize    = 0;
Shinya Kitaoka 120a6e
  (**mySampleDesc).desc.sampleRate    = st->getSampleRate() << 16;
Shinya Kitaoka 120a6e
  (**mySampleDesc).samplesPerPacket   = compressionInfo.samplesPerPacket;
Shinya Kitaoka 120a6e
  (**mySampleDesc).bytesPerPacket     = compressionInfo.bytesPerPacket;
Shinya Kitaoka 120a6e
  (**mySampleDesc).bytesPerFrame      = compressionInfo.bytesPerFrame;
Shinya Kitaoka 120a6e
  (**mySampleDesc).bytesPerSample     = compressionInfo.bytesPerSample;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //////////
Shinya Kitaoka 120a6e
  //
Shinya Kitaoka 120a6e
  // add samples to the media
Shinya Kitaoka 120a6e
  //
Shinya Kitaoka 120a6e
  //////////
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  myErr = AddMediaSample(
Shinya Kitaoka 120a6e
      m_soundMedia, myDestHandle, 0,
Shinya Kitaoka 120a6e
      destInfo.sampleCount * compressionInfo.bytesPerFrame, 1,
Shinya Kitaoka 120a6e
      (SampleDescriptionHandle)mySampleDesc,
Shinya Kitaoka 120a6e
      destInfo.sampleCount * compressionInfo.samplesPerPacket, 0, NULL);
Shinya Kitaoka 120a6e
  FailIf(myErr != noErr, MediaErr);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  myErr = EndMediaEdits(m_soundMedia);
Shinya Kitaoka 120a6e
  FailIf(myErr != noErr, MediaErr);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// NOTE: Sound media is inserted into the movie track only at destruction
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
ConverterErr:  // Multiple bailout labels just to
Shinya Kitaoka 120a6e
NoDest:        // separate debugging strings, it seems.
Shinya Kitaoka 120a6e
CompressErr:   //
Shinya Kitaoka 120a6e
Exit:          // Should be done better...
Shinya Kitaoka 120a6e
MediaErr:      //
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (mySampleDesc != NULL) DisposeHandle((Handle)mySampleDesc);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (converter) SoundConverterClose(converter);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (myErr != noErr) throw TImageException(m_path, "error saving audio track");
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TLevelWriterMov::~TLevelWriterMov() {
Shinya Kitaoka 120a6e
  if (m_pixmap) UnlockPixels(m_pixmap);
Shinya Kitaoka 120a6e
  if (m_gworld && m_gworld->portPixMap) UnlockPixels(m_gworld->portPixMap);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_gworld) DisposeGWorld(m_gworld);
Shinya Kitaoka 120a6e
  if (m_ci) CloseComponent(m_ci);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QDErr err;
Shinya Kitaoka 120a6e
  OSStatus mderr;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_videoTrack) {
Shinya Kitaoka 120a6e
    // Insert the saved Frames into the track.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // NOTE: Holes in the frames sequence will be intended as still frames,
Shinya Kitaoka 120a6e
    // rather than left blank.
Shinya Kitaoka 120a6e
    //       I'm quite unsure whether this behavior is actually useful - or used
Shinya Kitaoka 120a6e
    //       at all.
Shinya Kitaoka 120a6e
    //       In particular, the last frame is an exception, and does NOT drag to
Shinya Kitaoka 120a6e
    //       the end of the
Shinya Kitaoka 120a6e
    //       movie (see below). I think it's not used - frames are consecutive
Shinya Kitaoka 120a6e
    //       AFAIK.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TimeValue movieTimeScale = GetMovieTimeScale(m_movie);
Shinya Kitaoka 120a6e
    int savedFramesSize      = (int)m_savedFrames.size() - 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int i;
Shinya Kitaoka 120a6e
    for (i = 0; i < savedFramesSize; ++i) {
Shinya Kitaoka 120a6e
      TimeValue mediaPosition = m_savedFrames[i].second;
Shinya Kitaoka 120a6e
      TimeValue trackPosition =
Shinya Kitaoka 120a6e
          ((m_savedFrames[i].first - m_firstFrame) * movieTimeScale) /
Shinya Kitaoka 120a6e
          m_frameRate;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TimeValue duration = m_savedFrames[i + 1].first - m_savedFrames[i].first;
Shinya Kitaoka 120a6e
      Fixed ratio        = tround(fixed1 / (double)duration);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if ((err = InsertMediaIntoTrack(m_videoTrack, trackPosition,
Shinya Kitaoka 120a6e
                                      mediaPosition, 100, ratio)) != noErr)
Shinya Kitaoka 120a6e
        throw TImageException(getFilePath(), "can't insert media into track");
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (savedFramesSize >= 0) {
Shinya Kitaoka 120a6e
      TimeValue mediaPosition = m_savedFrames[i].second;
Shinya Kitaoka 120a6e
      TimeValue trackPosition =
Shinya Kitaoka 120a6e
          ((m_savedFrames[i].first - m_firstFrame) * movieTimeScale) /
Shinya Kitaoka 120a6e
          m_frameRate;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // The last frame has duration 1 (frame):
Shinya Kitaoka 120a6e
      //   duration = 1  =>  ratio = fixed1
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if ((err = InsertMediaIntoTrack(m_videoTrack, trackPosition,
Shinya Kitaoka 120a6e
                                      mediaPosition, 100, fixed1)) != noErr)
Shinya Kitaoka 120a6e
        throw TImageException(getFilePath(), "can't insert media into track");
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    QTMetaDataRef metaDataRef;
Shinya Kitaoka 120a6e
    if ((mderr = QTCopyMovieMetaData(m_movie, &metaDataRef)) != noErr)
Shinya Kitaoka 120a6e
      throw TImageException(getFilePath(),
Shinya Kitaoka 120a6e
                            "can't access metadata informations");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if ((mderr = QTMetaDataAddItem(
Shinya Kitaoka 120a6e
             metaDataRef, kQTMetaDataStorageFormatUserData,
Shinya Kitaoka 120a6e
             kQTMetaDataKeyFormatUserData, (const UInt8 *)firstFrameKey.c_str(),
Shinya Kitaoka 120a6e
             firstFrameKeySize, (const UInt8 *)(&m_firstFrame), sizeof(int),
Shinya Kitaoka 120a6e
             kQTMetaDataTypeUnsignedIntegerBE, 0)) != noErr)
Shinya Kitaoka 120a6e
      throw TImageException(getFilePath(),
Shinya Kitaoka 120a6e
                            "can't insert metadata informations");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    QTMetaDataRelease(metaDataRef);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_soundTrack) {
Shinya Kitaoka 120a6e
    if (0 != (err = InsertMediaIntoTrack(
Shinya Kitaoka 120a6e
                  m_soundTrack, 0, 0, GetMediaDuration(m_soundMedia), fixed1)))
Shinya Kitaoka 120a6e
      throw TImageException(getFilePath(), "can't insert sound into track");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  short resId = movieInDataForkResID;
Shinya Kitaoka 120a6e
  if (m_movie) {
Shinya Kitaoka 120a6e
    if ((err = AddMovieResource(m_movie, m_refNum, &resId, 0)) !=
Shinya Kitaoka 120a6e
        noErr)  // Why no thrown exception here?
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
    }  // throw TImageException(getFilePath(), "Can't add resource"); //
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_videoMedia)                   // And anyway, how exceptions
Shinya Kitaoka 120a6e
    DisposeTrackMedia(m_videoMedia);  // deal with absence of corresponding
Shinya Kitaoka 120a6e
  if (m_videoTrack)                   // disposals?
Shinya Kitaoka 120a6e
    DisposeMovieTrack(m_videoTrack);  // I guess se should use RAII here... -.-'
Shinya Kitaoka 120a6e
  if (m_soundMedia) DisposeTrackMedia(m_soundMedia);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_refNum) CloseMovieFile(m_refNum);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  DisposeMovie(m_movie);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TImageWriterP TLevelWriterMov::getFrameWriter(TFrameId fid) {
Shinya Kitaoka 120a6e
  if (m_IOError) throw TImageException(m_path, buildQTErrorString(m_IOError));
Shinya Kitaoka 120a6e
  if (fid.getLetter() != 0) return TImageWriterP(0);
Shinya Kitaoka 120a6e
  int index = fid.getNumber() - 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TImageWriterMov *iwm = new TImageWriterMov(m_path, index, this);
Shinya Kitaoka 120a6e
  return TImageWriterP(iwm);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
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_track(0)
Shinya Kitaoka 120a6e
    , m_movie(0)
Shinya Kitaoka 120a6e
    , m_depth(0)
Shinya Kitaoka 120a6e
    , m_readAsToonzOutput(false)
Shinya Kitaoka 120a6e
    , m_yMirror(true)
Shinya Kitaoka 120a6e
    , m_loadTimecode(false) {
Shinya Kitaoka 120a6e
  FSSpec fspec;
Shinya Kitaoka 120a6e
  QDErr err;
Shinya Kitaoka 120a6e
  Boolean dataRefWasChanged;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (QuickTimeStuff::instance()->getStatus() != noErr) {
Shinya Kitaoka 120a6e
    m_IOError = QTNotInstalled;
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  char *pStr = filePath2unichar(m_path);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if ((err = NativePathNameToFSSpec(pStr, &fspec, kFullNativePath)) != noErr) {
Shinya Kitaoka 120a6e
    delete[] pStr;
Shinya Kitaoka 120a6e
    pStr = 0;
Shinya Kitaoka 120a6e
    throw TImageException(path, "can't open file");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  delete[] pStr;
Shinya Kitaoka 120a6e
  pStr = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if ((err = OpenMovieFile(&fspec, &m_refNum, fsRdPerm))) {
Shinya Kitaoka 120a6e
    m_IOError = QTUnableToOpenFile;
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  short resId = 0;
Shinya Kitaoka 120a6e
  Str255 name;
Shinya Kitaoka 120a6e
  err = NewMovieFromFile(&m_movie, m_refNum, &resId, name, fsRdPerm,
Shinya Kitaoka 120a6e
                         &dataRefWasChanged);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int numTracks = GetMovieTrackCount(m_movie);
Shinya Kitaoka 120a6e
  if (numTracks < 1) {
Shinya Kitaoka 120a6e
    m_IOError = QTUnableToOpenFile;
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(numTracks == 1 || numTracks == 2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_track =
Shinya Kitaoka 120a6e
      GetMovieIndTrackType(m_movie, 1, VideoMediaType, movieTrackMediaType);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ImageDescriptionHandle imageH;
Shinya Kitaoka 120a6e
  imageH = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TINT32 index   = 1;
Shinya Kitaoka 120a6e
  Media theMedia = GetTrackMedia(m_track);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  GetMediaSampleDescription(theMedia, index, (SampleDescriptionHandle)imageH);
Shinya Kitaoka 120a6e
  ImageDescriptionPtr imagePtr = *imageH;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if ((imagePtr->cType >> 16) == 0x4458 /*'DX'*/ &&
Shinya Kitaoka 120a6e
      path.getType() == "avi")  // DIVX - compressed, QT is unable to read it.
Shinya Kitaoka 120a6e
  {                             // Done externally with the... AVI reader o_o.
Shinya Kitaoka 120a6e
    m_IOError = QTUnableToDoMovieTask;
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Retrieve the timecode media handler
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    Track tcTrack = GetMovieIndTrackType(m_movie, 1, TimeCodeMediaType,
Shinya Kitaoka 120a6e
                                         movieTrackMediaType);
Shinya Kitaoka 120a6e
    Media tcMedia     = GetTrackMedia(tcTrack);
Shinya Kitaoka 120a6e
    m_timecodeHandler = GetMediaHandler(tcMedia);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_lx    = imagePtr->width;
Shinya Kitaoka 120a6e
  m_ly    = imagePtr->height;
Shinya Kitaoka 120a6e
  m_depth = imagePtr->depth;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_info = new TImageInfo();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_info->m_lx        = m_lx;
Shinya Kitaoka 120a6e
  m_info->m_ly        = m_ly;
Shinya Kitaoka 120a6e
  m_info->m_frameRate = GetMediaTimeScale(theMedia) /
Shinya Kitaoka 120a6e
                        100.0;  // REMOVE THIS! Not all movs have this
Shinya Kitaoka 120a6e
                                // kind of format - only those from Toonz...
Shinya Kitaoka 120a6e
  Tiio::MovWriterProperties *prop = new Tiio::MovWriterProperties();
Shinya Kitaoka 120a6e
  m_info->m_properties            = prop;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  DisposeHandle((Handle)imageH);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TLevelReaderMov::~TLevelReaderMov() {
Shinya Kitaoka 120a6e
  StopMovie(m_movie);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_refNum) CloseMovieFile(m_refNum);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_movie) DisposeMovie(m_movie);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TLevelReaderMov::loadedTimecode(UCHAR &hh, UCHAR &mm, UCHAR &ss,
Shinya Kitaoka 120a6e
                                     UCHAR &ff) {
Shinya Kitaoka 120a6e
  hh = m_hh, mm = m_mm, ss = m_ss, ff = m_ff;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TLevelReaderMov::setYMirror(bool enabled) { m_yMirror = enabled; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TLevelReaderMov::setLoadTimecode(bool enabled) {
Shinya Kitaoka 120a6e
  m_loadTimecode = enabled;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TLevelReaderMov::enableRandomAccessRead(bool enable) {
Shinya Kitaoka 120a6e
  m_readAsToonzOutput = enable;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
//  TImageReaderMov
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class TImageReaderMov final : public TImageReader {
Shinya Kitaoka 120a6e
  TLevelReaderMov *m_lrm;
Shinya Kitaoka 120a6e
  TImageInfo *m_info;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  int m_frameIndex;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  TImageReaderMov(const TFilePath &, int frameIndex, TLevelReaderMov *,
Shinya Kitaoka 120a6e
                  TImageInfo *);
Shinya Kitaoka 120a6e
  ~TImageReaderMov() { m_lrm->release(); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  TImageP load() override;
Shinya Kitaoka 120a6e
  void load(const TRasterP &rasP, const TPoint &pos = TPoint(0, 0),
Shinya Kitaoka 120a6e
            int shrinkX = 1, int shrinkY = 1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TDimension getSize() const { return m_lrm->getSize(); }
Shinya Kitaoka 120a6e
  TRect getBBox() const { return m_lrm->getBBox(); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  const TImageInfo *getImageInfo() const override { return m_info; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  // Not copyable
Shinya Kitaoka 120a6e
  TImageReaderMov(const TImageReaderMov &);
Shinya Kitaoka 120a6e
  TImageReaderMov &operator=(const TImageReaderMov &);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TImageReaderMov::TImageReaderMov(const TFilePath &path, int frameIndex,
Shinya Kitaoka 120a6e
                                 TLevelReaderMov *lrm, TImageInfo *info)
Shinya Kitaoka 120a6e
    : TImageReader(path), m_lrm(lrm), m_frameIndex(frameIndex), m_info(info) {
Shinya Kitaoka 120a6e
  m_lrm->addRef();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TLevelP TLevelReaderMov::loadInfo() {
Shinya Kitaoka 120a6e
  if (m_readAsToonzOutput)  // Mov files written with Toonz support special
Shinya Kitaoka 120a6e
    return loadToonzOutputFormatInfo();  // metadata atoms - separate procedure
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Level is NOT a recognized mov from Toonz. Just read each movie's
Shinya Kitaoka 120a6e
  // interesting image as a consecutive
Shinya Kitaoka 120a6e
  // level frame.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TLevelP level;
Shinya Kitaoka 120a6e
  if (m_IOError != QTNoError)
Shinya Kitaoka 120a6e
    throw TImageException(m_path, buildQTErrorString(m_IOError));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  OSType mediaType = VisualMediaCharacteristic;
Shinya Kitaoka 120a6e
  TimeValue nextTime, currentTime;
Shinya Kitaoka 120a6e
  currentTime = 0;
Shinya Kitaoka 120a6e
  nextTime    = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int f = 0;  // 0 is the first frame index
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // io vorrei fare '|', ma sul manuale c'e' scritto '+'
Shinya Kitaoka 120a6e
  GetMovieNextInterestingTime(m_movie, nextTimeMediaSample + nextTimeEdgeOK, 1,
Shinya Kitaoka 120a6e
                              &mediaType, currentTime, 0, &nextTime, 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (nextTime != -1) {
Shinya Kitaoka 120a6e
    TFrameId frame(f + 1);
Shinya Kitaoka 120a6e
    level->setFrame(frame, TImageP());
Shinya Kitaoka 120a6e
    currentTimes[f] = nextTime;
Shinya Kitaoka 120a6e
    ++f;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  currentTime = nextTime;
Shinya Kitaoka 120a6e
  while (nextTime != -1) {
Shinya Kitaoka 120a6e
    GetMovieNextInterestingTime(m_movie, nextTimeMediaSample, 1, &mediaType,
Shinya Kitaoka 120a6e
                                currentTime, 0, &nextTime, 0);
Shinya Kitaoka 120a6e
    if (nextTime != -1) {
Shinya Kitaoka 120a6e
      TFrameId frame(f + 1);
Shinya Kitaoka 120a6e
      level->setFrame(frame, TImageP());
Shinya Kitaoka 120a6e
      currentTimes[f] = nextTime;
Shinya Kitaoka 120a6e
      ++f;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    currentTime = nextTime;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return level;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TLevelP TLevelReaderMov::loadToonzOutputFormatInfo() {
Shinya Kitaoka 120a6e
  TLevelP level;
Shinya Kitaoka 120a6e
  if (m_IOError != QTNoError)
Shinya Kitaoka 120a6e
    throw TImageException(m_path, buildQTErrorString(m_IOError));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  OSStatus mderr;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Retrieve the first frame of movie. This info has been put in a metadata
Shinya Kitaoka 120a6e
  // atom.
Shinya Kitaoka 120a6e
  QTMetaDataRef metaDataRef;
Shinya Kitaoka 120a6e
  if ((mderr = QTCopyMovieMetaData(m_movie, &metaDataRef)) != noErr)
Shinya Kitaoka 120a6e
    throw TImageException(m_path, "can't access metadata informations");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QTMetaDataItem firstFrameItem;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Find the metadata atom
Shinya Kitaoka 120a6e
  mderr = QTMetaDataGetNextItem(
Shinya Kitaoka 120a6e
      metaDataRef, kQTMetaDataStorageFormatUserData,
Shinya Kitaoka 120a6e
      kQTMetaDataItemUninitialized, kQTMetaDataKeyFormatUserData,
Shinya Kitaoka 120a6e
      (const UInt8 *)firstFrameKey.c_str(), firstFrameKeySize, &firstFrameItem);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Try to read the value. If the atom was not found, just assume firstFrame =
Shinya Kitaoka 120a6e
  // 0.
Shinya Kitaoka 120a6e
  int firstFrame = 0;
Shinya Kitaoka 120a6e
  if (mderr == noErr) {
Shinya Kitaoka 120a6e
    // The atom was found. Then, retrieve the value
Shinya Kitaoka 120a6e
    if ((mderr = QTMetaDataGetItemValue(metaDataRef, firstFrameItem,
Shinya Kitaoka 120a6e
                                        (UInt8 *)(&firstFrame), sizeof(int),
Shinya Kitaoka 120a6e
                                        0) != noErr))
Shinya Kitaoka 120a6e
      throw TImageException(m_path, "can't read metadata informations");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  mderr = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QTMetaDataRelease(metaDataRef);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  OSType mediaType   = VisualMediaCharacteristic;
Shinya Kitaoka 120a6e
  TimeValue nextTime = 0, currentTime = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TimeValue movieDuration = GetMovieDuration(m_movie);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<timevalue> interestingTimeValues;</timevalue>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // io vorrei fare '|', ma sul manuale c'e' scritto '+'
Shinya Kitaoka 120a6e
  GetMovieNextInterestingTime(m_movie, nextTimeMediaSample + nextTimeEdgeOK, 1,
Shinya Kitaoka 120a6e
                              &mediaType, currentTime, 0, &nextTime, 0);
Shinya Kitaoka 120a6e
  if (nextTime != -1) {
Shinya Kitaoka 120a6e
    interestingTimeValues.push_back(nextTime);
Shinya Kitaoka 120a6e
    currentTime = nextTime;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  while (nextTime != -1) {
Shinya Kitaoka 120a6e
    GetMovieNextInterestingTime(m_movie, nextTimeMediaSample, 1, &mediaType,
Shinya Kitaoka 120a6e
                                currentTime, 0, &nextTime, 0);
Shinya Kitaoka 120a6e
    if (nextTime != -1) {
Shinya Kitaoka 120a6e
      interestingTimeValues.push_back(nextTime);
Shinya Kitaoka 120a6e
      currentTime = nextTime;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (currentTime != -1) {
Shinya Kitaoka 120a6e
    double frameRate         = m_info->m_frameRate;
Shinya Kitaoka 120a6e
    TimeScale movieTimeScale = GetMovieTimeScale(m_movie);
Shinya Kitaoka 120a6e
    int firstFrameTimeValue  = movieTimeScale * firstFrame;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    std::vector<timevalue>::iterator it;</timevalue>
Shinya Kitaoka 120a6e
    for (it = interestingTimeValues.begin(); it != interestingTimeValues.end();
Shinya Kitaoka 120a6e
         ++it) {
Shinya Kitaoka 120a6e
      int frame =
Shinya Kitaoka 120a6e
          firstFrame +
Shinya Kitaoka 120a6e
          tround((*it * frameRate) /
Shinya Kitaoka 120a6e
                 (double)movieTimeScale);  // (Daniele) There was a ceil here,
Shinya Kitaoka 120a6e
      TFrameId frameId(frame + 1);  // before. But I honestly don't remember
Shinya Kitaoka 120a6e
      level->setFrame(frameId,
Shinya Kitaoka 120a6e
                      TImageP());  // WHY I placed it there. Round seems more
Shinya Kitaoka 120a6e
      currentTimes[frame] = *it;   // appropriate...
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
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
  TRasterPT<tpixelrgbm32> ret(m_lrm->getSize());</tpixelrgbm32>
Shinya Kitaoka 120a6e
  m_lrm->load(ret, m_frameIndex, TPointI(), 1, 1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return TRasterImageP(ret);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TImageReaderMov::load(const TRasterP &rasP, const TPoint &pos, int shrinkX,
Shinya Kitaoka 120a6e
                           int shrinkY) {
Shinya Kitaoka 120a6e
  if ((shrinkX != 1) || (shrinkY != 1) || (pos != TPoint(0, 0)))
Shinya Kitaoka 120a6e
    TImageReader::load(rasP, pos, shrinkX, shrinkY);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    m_lrm->load(rasP, m_frameIndex, pos, shrinkX, shrinkY);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline void setMatteAndYMirror(const TRaster32P &ras) {
Shinya Kitaoka 120a6e
  ras->lock();
Shinya Kitaoka 120a6e
  TPixel32 *upRow = ras->pixels();
Shinya Kitaoka 120a6e
  TPixel32 *dwRow = ras->pixels(ras->getLy() - 1);
Shinya Kitaoka 38fd86
  int hLy  = (int)(ras->getLy() / 2. + 0.5);  // piccola pessimizzazione...
Shinya Kitaoka 38fd86
  int wrap = ras->getWrap();
Shinya Kitaoka 38fd86
  int lx   = ras->getLx();
Shinya Kitaoka 120a6e
  TPixel32 *upPix = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPixel32 *lastPix = ras->pixels(hLy);
Shinya Kitaoka 120a6e
  while (upPix < lastPix) {
Shinya Kitaoka 120a6e
    upPix            = upRow;
Shinya Kitaoka 120a6e
    TPixel32 *dwPix  = dwRow;
Shinya Kitaoka 120a6e
    TPixel32 *endPix = upPix + lx;
Shinya Kitaoka 120a6e
    while (upPix < endPix) {
Shinya Kitaoka 120a6e
      TPixel32 tmpPix(upPix->r, upPix->g, upPix->b, 0xff);
Shinya Kitaoka 120a6e
      *upPix   = *dwPix;
Shinya Kitaoka 120a6e
      upPix->m = 0xff;
Shinya Kitaoka 120a6e
      *dwPix   = tmpPix;
Shinya Kitaoka 120a6e
      ++upPix;
Shinya Kitaoka 120a6e
      ++dwPix;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    upRow += wrap;
Shinya Kitaoka 120a6e
    dwRow -= wrap;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  ras->unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TLevelReaderMov::load(const TRasterP &rasP, int frameIndex,
Shinya Kitaoka 120a6e
                           const TPoint &pos, int shrinkX, int shrinkY) {
Shinya Kitaoka 120a6e
  GWorldPtr offscreenGWorld = 0;
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    QMutexLocker sl(&m_mutex);
Shinya Kitaoka 120a6e
    if (m_IOError != QTNoError)
Shinya Kitaoka 120a6e
      throw TImageException(m_path, buildQTErrorString(m_IOError));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TRaster32P ras = rasP;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    Rect rect;
Shinya Kitaoka 120a6e
    rect.right  = pos.x + ras->getLx();
Shinya Kitaoka 120a6e
    rect.left   = pos.x;
Shinya Kitaoka 120a6e
    rect.bottom = pos.y + ras->getLy();
Shinya Kitaoka 120a6e
    rect.top    = pos.y;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    OSErr err;
Shinya Kitaoka 120a6e
    ras->lock();
Shinya Kitaoka 120a6e
    err = QTNewGWorldFromPtr(&offscreenGWorld, k32BGRAPixelFormat, &rect, 0, 0,
Shinya Kitaoka 120a6e
                             0, ras->getRawData(), ras->getWrap() * 4);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (err != noErr) {
Shinya Kitaoka 120a6e
      m_IOError = QTUnableToCreateResource;
Shinya Kitaoka 120a6e
      goto error;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    SetMovieBox(m_movie, &rect);
Shinya Kitaoka 120a6e
    err = GetMoviesError();
Shinya Kitaoka 120a6e
    if (err != noErr) {
Shinya Kitaoka 120a6e
      m_IOError = QTUnableToSetMovieBox;
Shinya Kitaoka 120a6e
      goto error;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    SetMovieGWorld(m_movie, offscreenGWorld, GetGWorldDevice(offscreenGWorld));
Shinya Kitaoka 120a6e
    err = GetMoviesError();
Shinya Kitaoka 120a6e
    if (err != noErr) {
Shinya Kitaoka 120a6e
      m_IOError = QTUnableToSetMovieGWorld;
Shinya Kitaoka 120a6e
      goto error;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (currentTimes.empty()) loadInfo();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    std::map<int, timevalue="">::iterator it = currentTimes.find(frameIndex);</int,>
Shinya Kitaoka 120a6e
    if (it == currentTimes.end()) goto error;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TimeValue currentTime = it->second;
Shinya Kitaoka 120a6e
    SetMovieTimeValue(m_movie, currentTime);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    err = GetMoviesError();
Shinya Kitaoka 120a6e
    if (err != noErr) {
Shinya Kitaoka 120a6e
      m_IOError = QTUnableToSetTimeValue;
Shinya Kitaoka 120a6e
      goto error;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    err = UpdateMovie(m_movie);
Shinya Kitaoka 120a6e
    if (err != noErr) {
Shinya Kitaoka 120a6e
      m_IOError = QTUnableToUpdateMovie;
Shinya Kitaoka 120a6e
      goto error;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    MoviesTask(m_movie, 0);
Shinya Kitaoka 120a6e
    err = GetMoviesError();
Shinya Kitaoka 120a6e
    if (err != noErr) {
Shinya Kitaoka 120a6e
      m_IOError = QTUnableToDoMovieTask;
Shinya Kitaoka 120a6e
      goto error;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    DisposeGWorld(offscreenGWorld);
Shinya Kitaoka 120a6e
    ras->unlock();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_yMirror) {
Shinya Kitaoka 120a6e
    if (m_depth != 32)
Shinya Kitaoka 120a6e
      setMatteAndYMirror(rasP);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      rasP->yMirror();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_loadTimecode) {
Shinya Kitaoka 120a6e
    // Also build current Timecode
Shinya Kitaoka 120a6e
    TimeCodeRecord tc;
Shinya Kitaoka 120a6e
    HandlerError err = TCGetCurrentTimeCode(m_timecodeHandler, 0, 0, &tc, 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_hh = tc.t.hours;
Shinya Kitaoka 120a6e
    m_mm = tc.t.minutes;
Shinya Kitaoka 120a6e
    m_ss = tc.t.seconds;
Shinya Kitaoka 120a6e
    m_ff = tc.t.frames;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return;
Toshihiro Shimizu 890ddd
error:
Shinya Kitaoka 120a6e
  rasP->unlock();
Shinya Kitaoka 120a6e
  if (offscreenGWorld) DisposeGWorld(offscreenGWorld);
Shinya Kitaoka 120a6e
  throw TImageException(m_path, buildQTErrorString(m_IOError));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TLevelReaderMov::timecode(int frameIndex, UCHAR &hh, UCHAR &mm, UCHAR &ss,
Shinya Kitaoka 120a6e
                               UCHAR &ff) {
Shinya Kitaoka 120a6e
  hh = mm = ss = ff = 0xff;
Shinya Kitaoka 120a6e
  if (!m_timecodeHandler) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  QMutexLocker sl(&m_mutex);
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    if (m_IOError != QTNoError) goto error;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (currentTimes.empty()) loadInfo();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    std::map<int, timevalue="">::iterator it = currentTimes.find(frameIndex);</int,>
Shinya Kitaoka 120a6e
    if (it == currentTimes.end()) goto error;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    TimeValue currentTime = it->second;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    TimeCodeRecord tc;
Shinya Kitaoka 120a6e
    HandlerError err =
Shinya Kitaoka 120a6e
        TCGetTimeCodeAtTime(m_timecodeHandler, currentTime, 0, 0, &tc, 0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    hh = tc.t.hours;
Shinya Kitaoka 120a6e
    mm = tc.t.minutes;
Shinya Kitaoka 120a6e
    ss = tc.t.seconds;
Shinya Kitaoka 120a6e
    ff = tc.t.frames;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
error:
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  throw TImageException(m_path, buildQTErrorString(m_IOError));
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 TImageException(m_path, buildQTErrorString(m_IOError));
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, m_info);
Shinya Kitaoka 120a6e
  return TImageReaderP(irm);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TLevelReader *TLevelReaderMov::create(const TFilePath &f) {
Shinya Kitaoka 120a6e
  TLevelReaderMov *reader = new TLevelReaderMov(f);
Shinya Kitaoka 120a6e
  if (reader->m_IOError != QTNoError && f.getType() == "avi") {
Shinya Kitaoka 120a6e
    delete reader;
Shinya Kitaoka 120a6e
    return new TLevelReaderAvi(f);
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    return reader;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// You can use the SCSetInfo function with the scSettingsStateType selector to
Shinya Kitaoka 120a6e
// retrieve a handle
Shinya Kitaoka 120a6e
//  containing the current compression settings; this might be useful if you
Shinya Kitaoka 120a6e
//  were allowing the user
Shinya Kitaoka 120a6e
//  to compress a series of images and wanted to preserve the user's settings
Shinya Kitaoka 120a6e
//  from one image to the
Shinya Kitaoka 120a6e
//  next (instead of reverting to the defaults for every image). Note, however,
Shinya Kitaoka 120a6e
//  that the data in
Shinya Kitaoka 120a6e
//  that handle is byte-ordered according to the platform the code is running
Shinya Kitaoka 120a6e
//  on. As a result, you
Shinya Kitaoka 120a6e
//  should not store that data in a file and expect that file to be valid on
Shinya Kitaoka 120a6e
//  other platforms. To
Shinya Kitaoka 120a6e
//  get a handle of data in a platform-independent format, use the function
Shinya Kitaoka 120a6e
//  SCGetSettingsAsAtomContainer
Shinya Kitaoka 120a6e
//  (introduced in QuickTime 3); to restore the settings in that handle, use the
Shinya Kitaoka 120a6e
//  related function
Toshihiro Shimizu 890ddd
//  SCSetSettingsAsAtomContainer.
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif