Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
e280ae
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
Toshihiro Shimizu 890ddd
#define _CRT_SECURE_NO_DEPRECATE 1
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define _WIN32_DCOM
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define _WIN32_WINNT 0x0500
Toshihiro Shimizu 890ddd
#include "tsystem.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <windows.h></windows.h>
Toshihiro Shimizu 890ddd
#include <objbase.h></objbase.h>
Toshihiro Shimizu 890ddd
#include "texception.h"
Toshihiro Shimizu 890ddd
#include "tiio_avi.h"
Toshihiro Shimizu 890ddd
#include "tsound.h"
Toshihiro Shimizu 890ddd
#include "tconvert.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "timageinfo.h"
Toshihiro Shimizu 890ddd
#include "trasterimage.h"
Toshihiro Shimizu 890ddd
e280ae
#include <type_traits></type_traits>
e280ae
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define DibPtr(lpbi) (LPBYTE)(DibColors(lpbi) + (UINT)(lpbi)->biClrUsed)
Toshihiro Shimizu 890ddd
#define DibColors(lpbi) ((LPRGBQUAD)((LPBYTE)(lpbi) + (int)(lpbi)->biSize))
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void WideChar2Char(LPCWSTR wideCharStr, char *str, int strBuffSize) {
Shinya Kitaoka 120a6e
  WideCharToMultiByte(CP_ACP, 0, wideCharStr, -1, str, strBuffSize, 0, 0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
std::string buildAVIExceptionString(int rc) {
Shinya Kitaoka 120a6e
  switch (rc) {
Shinya Kitaoka 120a6e
  case AVIERR_BADFORMAT:
Shinya Kitaoka 120a6e
    return "The file couldn't be read, indicating a corrupt file or an "
Shinya Kitaoka 120a6e
           "unrecognized format.";
Shinya Kitaoka 120a6e
  case AVIERR_MEMORY:
Shinya Kitaoka 120a6e
    return "The file could not be opened because of insufficient memory.";
Shinya Kitaoka 120a6e
  case AVIERR_FILEREAD:
Shinya Kitaoka 120a6e
    return "A disk error occurred while reading the file.";
Shinya Kitaoka 120a6e
  case AVIERR_FILEOPEN:
Shinya Kitaoka 120a6e
    return "A disk error occurred while opening the file.";
Shinya Kitaoka 120a6e
  case REGDB_E_CLASSNOTREG:
Shinya Kitaoka 120a6e
    return "According to the registry, the type of file specified in "
Shinya Kitaoka 120a6e
           "m_aviFileOpen does not have a handler to process it.";
Shinya Kitaoka 120a6e
  case AVIERR_UNSUPPORTED:
Shinya Kitaoka 120a6e
    return "Format unsupported";
Shinya Kitaoka 120a6e
  case AVIERR_INTERNAL:
Shinya Kitaoka 120a6e
    return "Internal error";
Shinya Kitaoka 120a6e
  case AVIERR_NODATA:
Shinya Kitaoka 120a6e
    return "No data";
Shinya Kitaoka 120a6e
  default:
Shinya Kitaoka 120a6e
    return "Unable to create avi.";
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
std::string SplitFourCC(DWORD fcc) {
Shinya Kitaoka 120a6e
  std::string s;
Shinya Kitaoka 120a6e
  s += (char((fcc & 0x000000ff) >> 0));
Shinya Kitaoka 120a6e
  s += (char((fcc & 0x0000ff00) >> 8));
Shinya Kitaoka 120a6e
  s += (char((fcc & 0x00ff0000) >> 16));
Shinya Kitaoka 120a6e
  s += (char((fcc & 0xff000000) >> 24));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return s;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRaster32P DIBToRaster(UCHAR *pDIBImage, int width, int height) {
Shinya Kitaoka 120a6e
  assert(pDIBImage);
Shinya Kitaoka 120a6e
  if (!pDIBImage) return TRaster32P();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // BITMAPINFOHEADER *bihdr = reinterpret_cast<bitmapinfoheader *="">(pDIBImage);</bitmapinfoheader>
Shinya Kitaoka 120a6e
  UCHAR *rawData = pDIBImage;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRaster32P rasOut32(width, height);
Shinya Kitaoka 120a6e
  // ULONG imgSize = bihdr->biSizeImage;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int ly = rasOut32->getLy();
Shinya Kitaoka 120a6e
  int n  = 0;
Shinya Kitaoka 120a6e
  rasOut32->lock();
Shinya Kitaoka 120a6e
  while (n < ly) {
Shinya Kitaoka 120a6e
    TPixel32 *pix    = rasOut32->pixels(n);
Shinya Kitaoka 120a6e
    TPixel32 *endPix = pix + rasOut32->getLx();
Shinya Kitaoka 120a6e
    while (pix < endPix) {
Shinya Kitaoka 120a6e
      pix->b = *rawData;
Shinya Kitaoka 120a6e
      rawData++;
Shinya Kitaoka 120a6e
      pix->g = *rawData;
Shinya Kitaoka 120a6e
      rawData++;
Shinya Kitaoka 120a6e
      pix->r = *rawData;
Shinya Kitaoka 120a6e
      rawData++;
Shinya Kitaoka 120a6e
      pix->m = 255;
Shinya Kitaoka 120a6e
      ++pix;
Shinya Kitaoka 120a6e
      // rawData += 3;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    ++n;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  rasOut32->unlock();
Shinya Kitaoka 120a6e
  return rasOut32;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int getPrevKeyFrame(PAVISTREAM videoStream, int index) {
Shinya Kitaoka 120a6e
  return AVIStreamFindSample(videoStream, index, FIND_PREV | FIND_KEY);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool isAKeyFrame(PAVISTREAM videoStream, int index) {
Shinya Kitaoka 120a6e
  return index == getPrevKeyFrame(videoStream, index);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
};  // end of namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===========================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//  TImageWriterAvi
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//===========================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class TImageWriterAvi final : public TImageWriter {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  int m_frameIndex;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TImageWriterAvi(const TFilePath &path, int frameIndex, TLevelWriterAvi *lwa)
Shinya Kitaoka 120a6e
      : TImageWriter(path), m_frameIndex(frameIndex), m_lwa(lwa) {
Shinya Kitaoka 120a6e
    m_lwa->addRef();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  ~TImageWriterAvi() { m_lwa->release(); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  bool is64bitOutputSupported() override { return false; }
Shinya Kitaoka 473e70
  void save(const TImageP &img) override { m_lwa->save(img, m_frameIndex); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  TLevelWriterAvi *m_lwa;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // not implemented
Shinya Kitaoka 120a6e
  TImageWriterAvi(const TImageWriterAvi &);
Shinya Kitaoka 120a6e
  TImageWriterAvi &operator=(const TImageWriterAvi &src);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===========================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//  TLevelWriterAvi;
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//===========================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TLevelWriterAvi::TLevelWriterAvi(const TFilePath &path, TPropertyGroup *winfo)
Shinya Kitaoka 120a6e
    : TLevelWriter(path, winfo)
Shinya Kitaoka 120a6e
    , m_aviFile(0)
Shinya Kitaoka 120a6e
    , m_videoStream(0)
Shinya Kitaoka 120a6e
    , m_audioStream(0)
Shinya Kitaoka 120a6e
    , m_bitmapinfo(0)
Shinya Kitaoka 120a6e
    , m_outputFmt(0)
Shinya Kitaoka 120a6e
    , m_hic(0)
Shinya Kitaoka 120a6e
    , m_initDone(false)
Shinya Kitaoka 120a6e
    , IOError(0)
Shinya Kitaoka 120a6e
    , m_st(0)
Shinya Kitaoka 120a6e
    , m_bpp(32)
Shinya Kitaoka 120a6e
    , m_maxDataSize(0)
Shinya Kitaoka 120a6e
    , m_buffer(0)
Shinya Kitaoka 120a6e
    , m_firstframe(-1) {
Shinya Kitaoka 120a6e
  CoInitializeEx(0, COINIT_MULTITHREADED);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_frameRate = 12.;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  AVIFileInit();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (TSystem::doesExistFileOrLevel(m_path)) TSystem::deleteFile(m_path);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int rc = AVIFileOpenW(&m_aviFile, m_path.getWideString().c_str(),
Shinya Kitaoka 120a6e
                        OF_CREATE | OF_WRITE, 0);
Shinya Kitaoka 120a6e
  if (rc != 0) throw TImageException(getFilePath(), "Unable to create file");
Shinya Kitaoka 120a6e
  m_delayedFrames.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TLevelWriterAvi::~TLevelWriterAvi() {
Shinya Kitaoka 120a6e
  // controllo che non ci siano ancora dei frame in coda nel codec (alcuni codec
Shinya Kitaoka 120a6e
  // sono asincroni!)
Shinya Kitaoka 120a6e
  while (!m_delayedFrames.empty()) {
Shinya Kitaoka 120a6e
    LONG lSampWritten, lBytesWritten;
Shinya Kitaoka 120a6e
    int frameIndex = m_delayedFrames.front();
Shinya Kitaoka 120a6e
    DWORD flagsOut = 0;
Shinya Kitaoka 120a6e
    DWORD flagsIn  = !frameIndex ? AVIIF_KEYFRAME : 0;
Shinya Kitaoka 120a6e
    BITMAPINFOHEADER outHeader;
Shinya Kitaoka 120a6e
    void *bufferOut = 0;
Shinya Kitaoka 120a6e
    int res =
Shinya Kitaoka 120a6e
        compressFrame(&outHeader, &bufferOut, frameIndex, flagsIn, flagsOut);
Shinya Kitaoka 120a6e
    if (res != ICERR_OK) {
Shinya Kitaoka 120a6e
      if (bufferOut) _aligned_free(bufferOut);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (AVIStreamWrite(m_videoStream, frameIndex, 1, bufferOut,
Shinya Kitaoka 120a6e
                       outHeader.biSizeImage, flagsOut, &lSampWritten,
Shinya Kitaoka 120a6e
                       &lBytesWritten)) {
Shinya Kitaoka 120a6e
      if (bufferOut) _aligned_free(bufferOut);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    m_delayedFrames.pop_front();
Shinya Kitaoka 120a6e
    if (bufferOut) _aligned_free(bufferOut);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_st) {
Shinya Kitaoka 120a6e
    doSaveSoundTrack();
Shinya Kitaoka 120a6e
    m_st = 0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_hic) {
Shinya Kitaoka 120a6e
    ICCompressEnd(m_hic);
Shinya Kitaoka 120a6e
    ICClose(m_hic);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_bitmapinfo) free(m_bitmapinfo);
Shinya Kitaoka 120a6e
  if (m_outputFmt) free(m_outputFmt);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_videoStream) AVIStreamClose(m_videoStream);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_audioStream) AVIStreamClose(m_audioStream);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_aviFile) AVIFileClose(m_aviFile);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  AVIFileExit();
Shinya Kitaoka 120a6e
  CoUninitialize();
Shinya Kitaoka 120a6e
  if (!m_delayedFrames.empty())
Shinya Kitaoka 120a6e
    throw TImageException(
Shinya Kitaoka 120a6e
        getFilePath(),
Shinya Kitaoka 120a6e
        "error compressing frame " + std::to_string(m_delayedFrames.front()));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TLevelWriterAvi::searchForCodec() {
Shinya Kitaoka 120a6e
  if (!m_properties) m_properties = new Tiio::AviWriterProperties();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TEnumProperty *p = (TEnumProperty *)m_properties->getProperty("Codec");
Shinya Kitaoka 120a6e
  assert(p);
Shinya Kitaoka 120a6e
  std::wstring codecName = p->getValue();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //--------  // cerco compressorName fra i codec
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  HIC hic = 0;
Shinya Kitaoka 120a6e
  ICINFO icinfo;
Shinya Kitaoka 120a6e
  memset(&icinfo, 0, sizeof(ICINFO));
Shinya Kitaoka 120a6e
  bool found = false;
Shinya Kitaoka 120a6e
  if (codecName != L"Uncompressed") {
Shinya Kitaoka 120a6e
    char descr[2048], name[2048];
Shinya Kitaoka 120a6e
    DWORD fccType = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    BITMAPINFO inFmt;
Shinya Kitaoka 120a6e
    memset(&inFmt, 0, sizeof(BITMAPINFO));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    inFmt.bmiHeader.biSize  = sizeof(BITMAPINFOHEADER);
Shinya Kitaoka 120a6e
    inFmt.bmiHeader.biWidth = inFmt.bmiHeader.biHeight = 100;
Shinya Kitaoka 120a6e
    inFmt.bmiHeader.biPlanes                           = 1;
Shinya Kitaoka 120a6e
    inFmt.bmiHeader.biCompression                      = BI_RGB;
Shinya Kitaoka 120a6e
    found                                              = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (int bpp = 32; (bpp >= 24) && !found; bpp -= 8) {
Shinya Kitaoka 120a6e
      inFmt.bmiHeader.biBitCount = bpp;
Shinya Kitaoka 120a6e
      for (int i = 0; ICInfo(fccType, i, &icinfo); i++) {
Shinya Kitaoka 120a6e
        hic = ICOpen(icinfo.fccType, icinfo.fccHandler, ICMODE_COMPRESS);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        ICGetInfo(hic, &icinfo,
Shinya Kitaoka 120a6e
                  sizeof(ICINFO));  // Find out the compressor name
Shinya Kitaoka 120a6e
        WideChar2Char(icinfo.szDescription, descr, sizeof(descr));
Shinya Kitaoka 120a6e
        WideChar2Char(icinfo.szName, name, sizeof(name));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        std::string compressorName;
Shinya Kitaoka 120a6e
        compressorName = std::string(name) + " '" + std::to_string(bpp) + "' " +
Shinya Kitaoka 120a6e
                         std::string(descr);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (hic) {
Shinya Kitaoka 120a6e
          if (ICCompressQuery(hic, &inFmt, NULL) != ICERR_OK) {
Shinya Kitaoka 120a6e
            ICClose(hic);
Shinya Kitaoka 120a6e
            continue;  // Skip this compressor if it can't handle the format.
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
          if (::to_wstring(compressorName) == codecName) {
Shinya Kitaoka 120a6e
            found = true;
Shinya Kitaoka 120a6e
            m_bpp = bpp;
Shinya Kitaoka 120a6e
            break;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
          ICClose(hic);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_hic = hic;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TLevelWriterAvi::createBitmap(int lx, int ly) {
Shinya Kitaoka 120a6e
  const RGBQUAD NOMASK = {0x00, 0x00, 0x00, 0x00};
Shinya Kitaoka 120a6e
  m_bitmapinfo =
Shinya Kitaoka 120a6e
      (BITMAPINFO *)calloc(1, sizeof(BITMAPINFOHEADER) + 255 * sizeof(RGBQUAD));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_bitmapinfo->bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
Shinya Kitaoka 120a6e
  m_bitmapinfo->bmiHeader.biWidth         = lx;
Shinya Kitaoka 120a6e
  m_bitmapinfo->bmiHeader.biHeight        = ly;
Shinya Kitaoka 120a6e
  m_bitmapinfo->bmiHeader.biPlanes        = 1;
Shinya Kitaoka 120a6e
  m_bitmapinfo->bmiHeader.biBitCount      = m_bpp;
Shinya Kitaoka 120a6e
  m_bitmapinfo->bmiHeader.biCompression   = BI_RGB;
Shinya Kitaoka 120a6e
  m_bitmapinfo->bmiHeader.biSizeImage     = lx * ly * m_bpp / 8;
Shinya Kitaoka 120a6e
  m_bitmapinfo->bmiHeader.biXPelsPerMeter = 0;
Shinya Kitaoka 120a6e
  m_bitmapinfo->bmiHeader.biYPelsPerMeter = 0;
Shinya Kitaoka 120a6e
  m_bitmapinfo->bmiHeader.biClrUsed       = 0;
Shinya Kitaoka 120a6e
  m_bitmapinfo->bmiHeader.biClrImportant  = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_bitmapinfo->bmiColors[0] = NOMASK;
Shinya Kitaoka 120a6e
  m_bitmapinfo->bmiColors[1] = NOMASK;
Shinya Kitaoka 120a6e
  m_bitmapinfo->bmiColors[2] = NOMASK;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_buffer = _aligned_malloc(m_bitmapinfo->bmiHeader.biSizeImage, 128);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TImageWriterP TLevelWriterAvi::getFrameWriter(TFrameId fid) {
Shinya Kitaoka 120a6e
  if (IOError != 0)
Shinya Kitaoka 120a6e
    throw TImageException(m_path, buildAVIExceptionString(IOError));
Shinya Kitaoka 120a6e
  if (fid.getLetter() != 0) return TImageWriterP(0);
Shinya Kitaoka 120a6e
  int index            = fid.getNumber() - 1;
Shinya Kitaoka 120a6e
  TImageWriterAvi *iwa = new TImageWriterAvi(m_path, index, this);
Shinya Kitaoka 120a6e
  return TImageWriterP(iwa);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TLevelWriterAvi::save(const TImageP &img, int frameIndex) {
Shinya Kitaoka 120a6e
  CoInitializeEx(0, COINIT_MULTITHREADED);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_firstframe < 0) m_firstframe = frameIndex;
shun-iwasawa a63c2d
  int index = frameIndex - m_firstframe;
Shinya Kitaoka 120a6e
  TRasterImageP image(img);
Shinya Kitaoka 120a6e
  int lx = image->getRaster()->getLx();
Shinya Kitaoka 120a6e
  int ly = image->getRaster()->getLy();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int pixelSize = image->getRaster()->getPixelSize();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (pixelSize != 4)
Shinya Kitaoka 120a6e
    throw TImageException(getFilePath(), "Unsupported pixel type");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QMutexLocker sl(&m_mutex);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!m_initDone) {
Shinya Kitaoka 120a6e
    searchForCodec();
Shinya Kitaoka 120a6e
    createBitmap(lx, ly);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    DWORD num = DWORD(tround(m_frameRate * 100.0));
Shinya Kitaoka 120a6e
    DWORD den = 100;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    AVISTREAMINFO psi;
Shinya Kitaoka 120a6e
    memset(&psi, 0, sizeof(AVISTREAMINFO));
Shinya Kitaoka 120a6e
    psi.fccType = streamtypeVIDEO;
Shinya Kitaoka 120a6e
    if (m_hic) {
Shinya Kitaoka 120a6e
      ICINFO icinfo;
Shinya Kitaoka 120a6e
      ICGetInfo(m_hic, &icinfo, sizeof(ICINFO));
Shinya Kitaoka 120a6e
      psi.fccHandler = icinfo.fccHandler;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    psi.dwScale        = den;
Shinya Kitaoka 120a6e
    psi.dwRate         = num;
Shinya Kitaoka 120a6e
    psi.dwQuality      = ICQUALITY_DEFAULT;
Shinya Kitaoka 120a6e
    psi.rcFrame.right  = lx;
Shinya Kitaoka 120a6e
    psi.rcFrame.bottom = ly;
Shinya Kitaoka 120a6e
    ::strcpy(psi.szName, m_path.getName().c_str());
Shinya Kitaoka 120a6e
    int rc;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (AVIFileCreateStream(m_aviFile, &(m_videoStream), &(psi)))
Shinya Kitaoka 120a6e
      throw TImageException(getFilePath(), "Unable to create video stream");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!m_hic) {
Shinya Kitaoka 120a6e
      if (AVIStreamSetFormat(m_videoStream, 0, &m_bitmapinfo->bmiHeader,
Shinya Kitaoka 120a6e
                             m_bitmapinfo->bmiHeader.biSize))
Shinya Kitaoka 120a6e
        throw TImageException(getFilePath(), "unable to set format");
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      m_outputFmt = (BITMAPINFO *)calloc(
Shinya Kitaoka 120a6e
          1, sizeof(BITMAPINFOHEADER) + 255 * sizeof(RGBQUAD));
Shinya Kitaoka 120a6e
      m_outputFmt->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      rc = ICCompressGetFormat(m_hic, m_bitmapinfo, m_outputFmt);
Shinya Kitaoka 120a6e
      if (rc != ICERR_OK)
Shinya Kitaoka 120a6e
        throw TImageException(getFilePath(),
Shinya Kitaoka 120a6e
                              "Error codec (ec = " + std::to_string(rc) + ")");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      ICCOMPRESSFRAMES icf;
Shinya Kitaoka 120a6e
      memset(&icf, 0, sizeof icf);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      icf.dwFlags     = (DWORD)&icf.lKeyRate;
Shinya Kitaoka 120a6e
      icf.lStartFrame = index;
Shinya Kitaoka 120a6e
      icf.lFrameCount = 0;
Shinya Kitaoka 120a6e
      icf.lQuality    = ICQUALITY_DEFAULT;
Shinya Kitaoka 120a6e
      icf.lDataRate   = 0;
Shinya Kitaoka 120a6e
      icf.lKeyRate    = (DWORD)(num / den);
Shinya Kitaoka 120a6e
      icf.dwRate      = num;
Shinya Kitaoka 120a6e
      icf.dwScale     = den;
Shinya Kitaoka 120a6e
      ICSendMessage(m_hic, ICM_COMPRESS_FRAMES_INFO, (WPARAM)&icf,
Shinya Kitaoka 120a6e
                    sizeof(ICCOMPRESSFRAMES));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      m_maxDataSize = ICCompressGetSize(m_hic, m_bitmapinfo, m_outputFmt);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      rc = ICCompressBegin(m_hic, m_bitmapinfo, m_outputFmt);
Shinya Kitaoka 120a6e
      if (rc != ICERR_OK)
Shinya Kitaoka 120a6e
        throw TImageException(getFilePath(), "Error starting codec (ec = " +
Shinya Kitaoka 120a6e
                                                 std::to_string(rc) + ")");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (AVIStreamSetFormat(m_videoStream, 0, &m_outputFmt->bmiHeader,
Shinya Kitaoka 120a6e
                             m_outputFmt->bmiHeader.biSize))
Shinya Kitaoka 120a6e
        throw TImageException(getFilePath(), "unable to set format");
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    m_initDone = true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // copio l'immagine nella bitmap che ho creato in createBitmap
Shinya Kitaoka 120a6e
  image->getRaster()->lock();
Shinya Kitaoka 120a6e
  void *buffin = image->getRaster()->getRawData();
Shinya Kitaoka 120a6e
  assert(buffin);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRasterGR8P raux;
Shinya Kitaoka 120a6e
  if (m_bpp == 24) {
Shinya Kitaoka 120a6e
    int newlx = lx * 3;
Shinya Kitaoka 120a6e
    raux      = TRasterGR8P(newlx, ly);
Shinya Kitaoka 120a6e
    raux->lock();
Shinya Kitaoka 120a6e
    UCHAR *buffout24 = (UCHAR *)raux->getRawData();  // new UCHAR[newlx*ly];
Shinya Kitaoka 120a6e
    TPixel *buffin32 = (TPixel *)buffin;
Shinya Kitaoka 120a6e
    buffin           = buffout24;
Shinya Kitaoka 120a6e
    for (int i = 0; i < ly; i++) {
Shinya Kitaoka 120a6e
      UCHAR *pix = buffout24 + newlx * i;
Shinya Kitaoka 120a6e
      for (int j = 0; j < lx; j++, buffin32++) {
Shinya Kitaoka 120a6e
        *pix++ = buffin32->b;
Shinya Kitaoka 120a6e
        *pix++ = buffin32->g;
Shinya Kitaoka 120a6e
        *pix++ = buffin32->r;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    raux->unlock();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  memcpy(m_buffer, buffin, lx * ly * m_bpp / 8);
Shinya Kitaoka 120a6e
  image->getRaster()->unlock();
Shinya Kitaoka 120a6e
  raux = TRasterGR8P();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  LONG lSampWritten, lBytesWritten;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  lSampWritten  = 0;
Shinya Kitaoka 120a6e
  lBytesWritten = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!m_hic) {
Shinya Kitaoka 120a6e
    if (AVIStreamWrite(m_videoStream, index, 1, m_buffer,
Shinya Kitaoka 120a6e
                       m_bitmapinfo->bmiHeader.biSizeImage, AVIIF_KEYFRAME,
Shinya Kitaoka 120a6e
                       &lSampWritten, &lBytesWritten)) {
Shinya Kitaoka 120a6e
      throw TImageException(getFilePath(), "error writing frame");
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    BITMAPINFOHEADER outHeader;
Shinya Kitaoka 120a6e
    void *bufferOut = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    DWORD flagsOut = 0;
Shinya Kitaoka 120a6e
    DWORD flagsIn  = !index ? ICCOMPRESS_KEYFRAME : 0;
Shinya Kitaoka 120a6e
    int res = compressFrame(&outHeader, &bufferOut, index, flagsIn, flagsOut);
Shinya Kitaoka 120a6e
    if (res != ICERR_OK) {
Shinya Kitaoka 120a6e
      if (bufferOut) _aligned_free(bufferOut);
Shinya Kitaoka 120a6e
      throw TImageException(getFilePath(),
Shinya Kitaoka 120a6e
                            "error compressing frame " + std::to_string(index));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (outHeader.biCompression == '05xd' ||
Shinya Kitaoka 120a6e
        outHeader.biCompression == '05XD' ||
Shinya Kitaoka 120a6e
        outHeader.biCompression == 'divx' || outHeader.biCompression == 'DIVX')
Shinya Kitaoka 120a6e
      if (outHeader.biSizeImage == 1 && *(char *)bufferOut == 0x7f) {
Shinya Kitaoka 120a6e
        m_delayedFrames.push_back(index);
Shinya Kitaoka 120a6e
        if (bufferOut) _aligned_free(bufferOut);
Shinya Kitaoka 120a6e
        return;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    if (!m_delayedFrames.empty()) {
Shinya Kitaoka 120a6e
      m_delayedFrames.push_back(index);
Shinya Kitaoka 120a6e
      index = m_delayedFrames.front();
Shinya Kitaoka 120a6e
      m_delayedFrames.pop_front();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (AVIStreamWrite(m_videoStream, index, 1, bufferOut,
Shinya Kitaoka 120a6e
                       outHeader.biSizeImage, !index ? flagsOut : 0,
Shinya Kitaoka 120a6e
                       &lSampWritten, &lBytesWritten)) {
Shinya Kitaoka 120a6e
      if (bufferOut) _aligned_free(bufferOut);
Shinya Kitaoka 120a6e
      throw TImageException(getFilePath(), "error writing frame");
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (bufferOut) _aligned_free(bufferOut);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TLevelWriterAvi::compressFrame(BITMAPINFOHEADER *outHeader,
Shinya Kitaoka 120a6e
                                   void **bufferOut, int frameIndex,
Shinya Kitaoka 120a6e
                                   DWORD flagsIn, DWORD &flagsOut) {
shun-iwasawa a63c2d
  *bufferOut    = _aligned_malloc(m_maxDataSize, 128);
shun-iwasawa a63c2d
  *outHeader    = m_outputFmt->bmiHeader;
shun-iwasawa a63c2d
  DWORD chunkId = 0;
Shinya Kitaoka 120a6e
  if (flagsIn) flagsOut = AVIIF_KEYFRAME;
shun-iwasawa a63c2d
  int res = ICCompress(m_hic, flagsIn, outHeader, *bufferOut,
Shinya Kitaoka 120a6e
                       &m_bitmapinfo->bmiHeader, m_buffer, &chunkId, &flagsOut,
Shinya Kitaoka 120a6e
                       frameIndex, frameIndex ? 0 : 0xFFFFFF, 0, NULL, NULL);
Shinya Kitaoka 120a6e
  return res;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TLevelWriterAvi::TLevelWriterAvi(const TFilePath &path) : TLevelWriter(path) {}
Toshihiro Shimizu 890ddd
TLevelWriterAvi::~TLevelWriterAvi() {}
Shinya Kitaoka 120a6e
TImageWriterP TLevelWriterAvi::getFrameWriter(TFrameId) {
Shinya Kitaoka 120a6e
  throw TImageException(getFilePath(), "not supported");
Shinya Kitaoka 120a6e
  return TImageWriterP(iwa);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
void TImageWriterAvi::save(const TImageP &) {
Shinya Kitaoka 120a6e
  throw TImageException(m_path, "AVI file format not supported");
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TLevelWriterAvi::saveSoundTrack(TSoundTrack *st) {
Shinya Kitaoka 120a6e
  if (!m_aviFile) throw TException("unable to save soundtrack");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!st) throw TException("null reference to soundtrack");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_st =
Shinya Kitaoka 120a6e
      st;  // prima devo aver salvato tutto il video, salvo l'audio alla fine!
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TLevelWriterAvi::doSaveSoundTrack() {
Shinya Kitaoka 120a6e
  WAVEFORMATEX waveinfo;
Shinya Kitaoka 120a6e
  int ret;
Shinya Kitaoka 120a6e
  LONG lSampWritten, lBytesWritten;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  AVISTREAMINFO audioStreamInfo;
Shinya Kitaoka 120a6e
  memset(&audioStreamInfo, 0, sizeof(AVISTREAMINFO));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  audioStreamInfo.fccType    = streamtypeAUDIO;
Shinya Kitaoka 120a6e
  audioStreamInfo.fccHandler = 0;
Shinya Kitaoka 120a6e
  audioStreamInfo.dwFlags    = 0;
Shinya Kitaoka 120a6e
  audioStreamInfo.dwCaps     = 0;
Shinya Kitaoka 120a6e
  audioStreamInfo.wPriority  = 0;
Shinya Kitaoka 120a6e
  audioStreamInfo.wLanguage  = 0;
Shinya Kitaoka 120a6e
  audioStreamInfo.dwScale    = 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  audioStreamInfo.dwRate = m_st->getSampleRate();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  audioStreamInfo.dwStart               = 0;
Shinya Kitaoka 120a6e
  audioStreamInfo.dwLength              = 0;
Shinya Kitaoka 120a6e
  audioStreamInfo.dwInitialFrames       = 0;
Shinya Kitaoka 120a6e
  audioStreamInfo.dwSuggestedBufferSize = 0;
Shinya Kitaoka 120a6e
  audioStreamInfo.dwQuality             = (ULONG)-1;
Shinya Kitaoka 120a6e
  audioStreamInfo.dwSampleSize          = 0;
Shinya Kitaoka 120a6e
  audioStreamInfo.rcFrame.left          = 0;
Shinya Kitaoka 120a6e
  audioStreamInfo.rcFrame.top           = 0;
Shinya Kitaoka 120a6e
  audioStreamInfo.rcFrame.right         = 0;
Shinya Kitaoka 120a6e
  audioStreamInfo.rcFrame.bottom        = 0;
Shinya Kitaoka 120a6e
  audioStreamInfo.dwEditCount           = 0;
Shinya Kitaoka 120a6e
  audioStreamInfo.dwFormatChangeCount   = 0;
Shinya Kitaoka 120a6e
  audioStreamInfo.szName[0]             = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 38fd86
  waveinfo.wFormatTag      = WAVE_FORMAT_PCM;  // WAVE_FORMAT_DRM
Shinya Kitaoka 38fd86
  waveinfo.nChannels       = m_st->getChannelCount();
Shinya Kitaoka 38fd86
  waveinfo.nSamplesPerSec  = m_st->getSampleRate();
Shinya Kitaoka 38fd86
  waveinfo.wBitsPerSample  = m_st->getBitPerSample();
Shinya Kitaoka 38fd86
  waveinfo.nBlockAlign     = waveinfo.nChannels * waveinfo.wBitsPerSample >> 3;
Shinya Kitaoka 120a6e
  waveinfo.nAvgBytesPerSec = waveinfo.nSamplesPerSec * waveinfo.nBlockAlign;
Shinya Kitaoka 120a6e
  waveinfo.cbSize          = sizeof(WAVEFORMATEX);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const UCHAR *buffer = m_st->getRawData();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (AVIFileCreateStream(m_aviFile, &m_audioStream, &audioStreamInfo))
Shinya Kitaoka 120a6e
    throw TException("error creating soundtrack stream");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (AVIStreamSetFormat(m_audioStream, 0, &waveinfo, sizeof(WAVEFORMATEX)))
Shinya Kitaoka 120a6e
    throw TException("error setting soundtrack format");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  LONG count   = m_st->getSampleCount();
Shinya Kitaoka 120a6e
  LONG bufSize = m_st->getSampleCount() * m_st->getSampleSize();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (ret = AVIStreamWrite(m_audioStream, 0, count, (char *)buffer, bufSize,
Shinya Kitaoka 120a6e
                           AVIIF_KEYFRAME, &lSampWritten, &lBytesWritten))
Shinya Kitaoka 120a6e
    throw TException("error writing soundtrack samples");
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===========================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//  TImageReaderAvi
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//===========================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class TImageReaderAvi final : public TImageReader {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  int m_frameIndex;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TImageReaderAvi(const TFilePath &path, int index, TLevelReaderAvi *lra)
Shinya Kitaoka 120a6e
      : TImageReader(path), m_lra(lra), m_frameIndex(index) {
Shinya Kitaoka 120a6e
    m_lra->addRef();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  ~TImageReaderAvi() { m_lra->release(); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  TImageP load() override { return m_lra->load(m_frameIndex); }
Shinya Kitaoka 120a6e
  TDimension getSize() const { return m_lra->getSize(); }
Shinya Kitaoka 120a6e
  TRect getBBox() const { return TRect(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  TLevelReaderAvi *m_lra;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // not implemented
Shinya Kitaoka 120a6e
  TImageReaderAvi(const TImageReaderAvi &);
Shinya Kitaoka 120a6e
  TImageReaderAvi &operator=(const TImageReaderAvi &src);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===========================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//  TLevelReaderAvi
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//===========================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Toshihiro Shimizu 890ddd
TLevelReaderAvi::TLevelReaderAvi(const TFilePath &path)
Shinya Kitaoka 120a6e
    : TLevelReader(path)
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Shinya Kitaoka 120a6e
    , m_srcBitmapInfo(0)
Shinya Kitaoka 120a6e
    , m_dstBitmapInfo(0)
Shinya Kitaoka 120a6e
    , m_hic(0)
Shinya Kitaoka 120a6e
    , IOError(0)
Shinya Kitaoka 120a6e
    , m_prevFrame(-1)
Shinya Kitaoka 120a6e
    , m_decompressedBuffer(0)
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 120a6e
  CoInitializeEx(0, COINIT_MULTITHREADED);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  AVIFileInit();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int rc = AVIStreamOpenFromFileW(&m_videoStream, path.getWideString().c_str(),
Shinya Kitaoka 120a6e
                                  streamtypeVIDEO, 0, OF_READ, 0);
Shinya Kitaoka 120a6e
  if (rc != 0) {
Shinya Kitaoka 120a6e
    IOError = rc;
Shinya Kitaoka 120a6e
    throw TImageException(m_path, buildAVIExceptionString(IOError));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  LONG size       = sizeof(BITMAPINFO);
Shinya Kitaoka 120a6e
  m_srcBitmapInfo = (BITMAPINFO *)calloc(1, size);
Shinya Kitaoka 120a6e
  m_dstBitmapInfo = (BITMAPINFO *)calloc(1, size);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  rc = AVIStreamReadFormat(m_videoStream, 0, m_srcBitmapInfo, &size);
Shinya Kitaoka 120a6e
  if (rc) throw TImageException(getFilePath(), "error reading info.");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  *m_dstBitmapInfo                         = *m_srcBitmapInfo;
Shinya Kitaoka 120a6e
  m_dstBitmapInfo->bmiHeader.biCompression = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  AVISTREAMINFO si;
Shinya Kitaoka 120a6e
  rc = AVIStreamInfo(m_videoStream, &si, sizeof(AVISTREAMINFO));
Shinya Kitaoka 120a6e
  if (rc) throw TImageException(getFilePath(), "error reading info.");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_info              = new TImageInfo();
Shinya Kitaoka 120a6e
  m_info->m_frameRate = si.dwRate / double(si.dwScale);
Shinya Kitaoka 120a6e
  m_info->m_lx        = si.rcFrame.right - si.rcFrame.left;
Shinya Kitaoka 120a6e
  m_info->m_ly        = si.rcFrame.bottom - si.rcFrame.top;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int bpp = m_srcBitmapInfo->bmiHeader.biBitCount;
Shinya Kitaoka 120a6e
  switch (bpp) {
Shinya Kitaoka 120a6e
  case 32: {
Shinya Kitaoka 120a6e
    m_info->m_bitsPerSample  = 8;
Shinya Kitaoka 120a6e
    m_info->m_samplePerPixel = 4;
Shinya Kitaoka 120a6e
    m_dstBitmapInfo->bmiHeader.biSizeImage =
Shinya Kitaoka 120a6e
        m_dstBitmapInfo->bmiHeader.biWidth *
Shinya Kitaoka 120a6e
        m_dstBitmapInfo->bmiHeader.biHeight * 4;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  case 24: {
Shinya Kitaoka 120a6e
    m_info->m_bitsPerSample  = 8;
Shinya Kitaoka 120a6e
    m_info->m_samplePerPixel = 3;
Shinya Kitaoka 120a6e
    m_dstBitmapInfo->bmiHeader.biSizeImage =
Shinya Kitaoka 120a6e
        m_dstBitmapInfo->bmiHeader.biWidth *
Shinya Kitaoka 120a6e
        m_dstBitmapInfo->bmiHeader.biHeight * 3;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  case 16: {
Shinya Kitaoka 120a6e
    m_info->m_bitsPerSample  = 8;
Shinya Kitaoka 120a6e
    m_info->m_samplePerPixel = 2;
Shinya Kitaoka 120a6e
    // chiedo al decoder di decomprimerla in un'immagine a 24 bit (sperando che
Shinya Kitaoka 120a6e
    // lo permetta)
Shinya Kitaoka 120a6e
    m_dstBitmapInfo->bmiHeader.biBitCount = 24;
Shinya Kitaoka 120a6e
    m_dstBitmapInfo->bmiHeader.biSizeImage =
Shinya Kitaoka 120a6e
        m_dstBitmapInfo->bmiHeader.biWidth *
Shinya Kitaoka 120a6e
        m_dstBitmapInfo->bmiHeader.biHeight * 3;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  default: {
Shinya Kitaoka 120a6e
    throw TImageException(getFilePath(),
Shinya Kitaoka 120a6e
                          "unable to find a decompressor for this format");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  Tiio::AviWriterProperties *prop = new Tiio::AviWriterProperties();
Shinya Kitaoka 120a6e
  m_info->m_properties            = prop;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_srcBitmapInfo->bmiHeader.biCompression != 0) {
Shinya Kitaoka 120a6e
    // ci sono dei codec (es. Xvid) che non decomprimono bene dentro immagini a
Shinya Kitaoka 120a6e
    // 32 bit.
Shinya Kitaoka 120a6e
    m_dstBitmapInfo->bmiHeader.biBitCount = 24;
Shinya Kitaoka 120a6e
    m_dstBitmapInfo->bmiHeader.biSizeImage =
Shinya Kitaoka 120a6e
        m_dstBitmapInfo->bmiHeader.biWidth *
Shinya Kitaoka 120a6e
        m_dstBitmapInfo->bmiHeader.biHeight * 3;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    ICINFO icinfo;
Shinya Kitaoka 120a6e
    memset(&icinfo, 0, sizeof(ICINFO));
Shinya Kitaoka 120a6e
    ICInfo(ICTYPE_VIDEO, si.fccHandler, &icinfo);
Shinya Kitaoka 120a6e
    m_hic = ICOpen(icinfo.fccType, icinfo.fccHandler, ICMODE_DECOMPRESS);
Shinya Kitaoka 120a6e
    if (!m_hic) {
Shinya Kitaoka 120a6e
      m_hic = findCandidateDecompressor();
Shinya Kitaoka 120a6e
      if (!m_hic)
Shinya Kitaoka 120a6e
        throw TImageException(getFilePath(),
Shinya Kitaoka 120a6e
                              "unable to find a decompressor for this format");
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    DWORD result = ICDecompressQuery(m_hic, m_srcBitmapInfo, m_dstBitmapInfo);
Shinya Kitaoka 120a6e
    if (result != ICERR_OK)
Shinya Kitaoka 120a6e
      throw TImageException(getFilePath(),
Shinya Kitaoka 120a6e
                            "unable to find a decompressor for this format");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    result = ICDecompressBegin(m_hic, m_srcBitmapInfo, m_dstBitmapInfo);
Shinya Kitaoka 120a6e
    if (result != ICERR_OK)
Shinya Kitaoka 120a6e
      throw TImageException(getFilePath(),
Shinya Kitaoka 120a6e
                            "unable to initializate the decompressor");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    char descr[2048], name[2048];
Shinya Kitaoka 120a6e
    ICGetInfo(m_hic, &icinfo, sizeof(ICINFO));  // Find out the compressor name
Shinya Kitaoka 120a6e
    WideChar2Char(icinfo.szDescription, descr, sizeof(descr));
Shinya Kitaoka 120a6e
    WideChar2Char(icinfo.szName, name, sizeof(name));
Shinya Kitaoka 120a6e
    std::string compressorName;
Shinya Kitaoka 120a6e
    compressorName = std::string(name) + " '" +
Shinya Kitaoka 120a6e
                     std::to_string(m_dstBitmapInfo->bmiHeader.biBitCount) +
Shinya Kitaoka 120a6e
                     "' " + std::string(descr);
Shinya Kitaoka 120a6e
    TEnumProperty *p =
Shinya Kitaoka 120a6e
        (TEnumProperty *)m_info->m_properties->getProperty("Codec");
Shinya Kitaoka 120a6e
    p->setValue(::to_wstring(compressorName));
Shinya Kitaoka 120a6e
    m_decompressedBuffer =
Shinya Kitaoka 120a6e
        _aligned_malloc(m_dstBitmapInfo->bmiHeader.biSizeImage, 128);
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    m_hic = 0;
Shinya Kitaoka 120a6e
    TEnumProperty *p =
Shinya Kitaoka 120a6e
        (TEnumProperty *)m_info->m_properties->getProperty("Codec");
Shinya Kitaoka 120a6e
    p->setValue(L"Uncompressed");
Shinya Kitaoka 120a6e
    m_decompressedBuffer = _aligned_malloc(si.dwSuggestedBufferSize, 128);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TLevelReaderAvi::~TLevelReaderAvi() {
Shinya Kitaoka 120a6e
  if (m_hic) {
Shinya Kitaoka 120a6e
    ICDecompressEnd(m_hic);
Shinya Kitaoka 120a6e
    ICClose(m_hic);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_srcBitmapInfo) free(m_srcBitmapInfo);
Shinya Kitaoka 120a6e
  if (m_dstBitmapInfo) free(m_dstBitmapInfo);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_videoStream) AVIStreamClose(m_videoStream);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  AVIFileExit();
Shinya Kitaoka 120a6e
  _aligned_free(m_decompressedBuffer);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
HIC TLevelReaderAvi::findCandidateDecompressor() {
Shinya Kitaoka 120a6e
  ICINFO info        = {0};
Shinya Kitaoka 120a6e
  BITMAPINFO srcInfo = *m_srcBitmapInfo;
Shinya Kitaoka 120a6e
  BITMAPINFO dstInfo = *m_dstBitmapInfo;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (DWORD id = 0; ICInfo(ICTYPE_VIDEO, id, &info); ++id) {
Shinya Kitaoka 120a6e
    info.dwSize = sizeof(
Shinya Kitaoka 120a6e
        ICINFO);  // I don't think this is necessary, but just in case....
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    HIC hic = ICOpen(info.fccType, info.fccHandler, ICMODE_DECOMPRESS);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!hic) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    DWORD result = ICDecompressQuery(hic, &srcInfo, &dstInfo);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (result == ICERR_OK) {
Shinya Kitaoka 120a6e
      // Check for a codec that doesn't actually support what it says it does.
Shinya Kitaoka 120a6e
      // We ask the codec whether it can do a specific conversion that it can't
Shinya Kitaoka 120a6e
      // possibly support.  If it does it, then we call BS and ignore the codec.
Shinya Kitaoka 120a6e
      // The Grand Tech Camera Codec and Panasonic DV codecs are known to do
Shinya Kitaoka 120a6e
      // this.
Shinya Kitaoka 120a6e
      //
Shinya Kitaoka 120a6e
      // (general idea from Raymond Chen's blog)
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      BITMAPINFOHEADER testSrc = {// note: can't be static const since
Shinya Kitaoka 120a6e
                                  // IsBadWritePtr() will get called on it
Shinya Kitaoka 120a6e
                                  sizeof(BITMAPINFOHEADER),
Shinya Kitaoka 120a6e
                                  320,
Shinya Kitaoka 120a6e
                                  240,
Shinya Kitaoka 120a6e
                                  1,
Shinya Kitaoka 120a6e
                                  24,
Shinya Kitaoka 120a6e
                                  0x2E532E42,
Shinya Kitaoka 120a6e
                                  320 * 240 * 3,
Shinya Kitaoka 120a6e
                                  0,
Shinya Kitaoka 120a6e
                                  0,
Shinya Kitaoka 120a6e
                                  0,
Shinya Kitaoka 120a6e
                                  0};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      DWORD res = ICDecompressQuery(hic, &testSrc, NULL);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (ICERR_OK == res) {  // Don't need to wrap this, as it's OK if testSrc
Shinya Kitaoka 120a6e
                              // gets modified.
Shinya Kitaoka 120a6e
        ICINFO info = {sizeof(ICINFO)};
Shinya Kitaoka 120a6e
        ICGetInfo(hic, &info, sizeof info);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // Okay, let's give the codec a chance to redeem itself. Reformat the
Shinya Kitaoka 120a6e
        // input format into
Shinya Kitaoka 120a6e
        // a plain 24-bit RGB image, and ask it what the compressed format is.
Shinya Kitaoka 120a6e
        // If it produces
Shinya Kitaoka 120a6e
        // a FOURCC that matches, allow it to handle the format. This should
Shinya Kitaoka 120a6e
        // allow at least
Shinya Kitaoka 120a6e
        // the codec's primary format to work. Otherwise, drop it on the ground.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (m_srcBitmapInfo) {
Shinya Kitaoka 120a6e
          BITMAPINFOHEADER unpackedSrc = {sizeof(BITMAPINFOHEADER),
Shinya Kitaoka 120a6e
                                          m_srcBitmapInfo->bmiHeader.biWidth,
Shinya Kitaoka 120a6e
                                          m_srcBitmapInfo->bmiHeader.biHeight,
Shinya Kitaoka 120a6e
                                          1,
Shinya Kitaoka 120a6e
                                          24,
Shinya Kitaoka 120a6e
                                          BI_RGB,
Shinya Kitaoka 120a6e
                                          0,
Shinya Kitaoka 120a6e
                                          0,
Shinya Kitaoka 120a6e
                                          0,
Shinya Kitaoka 120a6e
                                          0,
Shinya Kitaoka 120a6e
                                          0};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          unpackedSrc.biSizeImage =
Shinya Kitaoka 120a6e
              ((unpackedSrc.biWidth * 3 + 3) & ~3) * abs(unpackedSrc.biHeight);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          LONG size = ICCompressGetFormatSize(hic, &unpackedSrc);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          if (size >= sizeof(BITMAPINFOHEADER)) {
Shinya Kitaoka 120a6e
            BITMAPINFOHEADER tmp;
Shinya Kitaoka 120a6e
            if (ICERR_OK == ICCompressGetFormat(hic, &unpackedSrc, &tmp) &&
Shinya Kitaoka 120a6e
                tmp.biCompression == m_srcBitmapInfo->bmiHeader.biCompression)
Shinya Kitaoka 120a6e
              return hic;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      } else
Shinya Kitaoka 120a6e
        return hic;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    ICClose(hic);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return NULL;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TLevelP TLevelReaderAvi::loadInfo() {
Shinya Kitaoka 120a6e
  if (IOError) throw TImageException(m_path, buildAVIExceptionString(IOError));
Shinya Kitaoka 120a6e
  int nFrames = AVIStreamLength(m_videoStream);
Shinya Kitaoka 120a6e
  if (nFrames == -1) return TLevelP();
Shinya Kitaoka 120a6e
  TLevelP level;
Shinya Kitaoka 120a6e
  for (int i = 1; i <= nFrames; i++) level->setFrame(i, TImageP());
Shinya Kitaoka 120a6e
  return level;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TImageReaderP TLevelReaderAvi::getFrameReader(TFrameId fid) {
Shinya Kitaoka 120a6e
  if (IOError != 0)
Shinya Kitaoka 120a6e
    throw TImageException(m_path, buildAVIExceptionString(IOError));
Shinya Kitaoka 120a6e
  if (fid.getLetter() != 0) return TImageReaderP(0);
Shinya Kitaoka 120a6e
  int index = fid.getNumber() - 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TImageReaderAvi *ira = new TImageReaderAvi(m_path, index, this);
Shinya Kitaoka 120a6e
  return TImageReaderP(ira);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TDimension TLevelReaderAvi::getSize() {
Shinya Kitaoka 120a6e
  QMutexLocker sl(&m_mutex);
Shinya Kitaoka 120a6e
  AVISTREAMINFO psi;
Shinya Kitaoka 120a6e
  AVIStreamInfo(m_videoStream, &psi, sizeof(AVISTREAMINFO));
Shinya Kitaoka 120a6e
  return TDimension(psi.rcFrame.right - psi.rcFrame.left,
Shinya Kitaoka 120a6e
                    psi.rcFrame.bottom - psi.rcFrame.top);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TImageP TLevelReaderAvi::load(int frameIndex) {
Shinya Kitaoka 120a6e
  AVISTREAMINFO si;
Shinya Kitaoka 120a6e
  int rc = AVIStreamInfo(m_videoStream, &si, sizeof(AVISTREAMINFO));
Shinya Kitaoka 120a6e
  if (rc) throw TImageException(getFilePath(), "error reading info.");
Shinya Kitaoka 120a6e
  void *bufferOut = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!m_hic) {
Shinya Kitaoka 120a6e
    rc = readFrameFromStream(m_decompressedBuffer, si.dwSuggestedBufferSize,
Shinya Kitaoka 120a6e
                             frameIndex);
Shinya Kitaoka 120a6e
    if (rc) {
Shinya Kitaoka 120a6e
      throw TImageException(m_path, "unable read frame " +
Shinya Kitaoka 120a6e
                                        std::to_string(frameIndex) +
Shinya Kitaoka 120a6e
                                        "from video stream.");
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    int prevKeyFrame = m_prevFrame == frameIndex - 1
Shinya Kitaoka 120a6e
                           ? frameIndex
Shinya Kitaoka 120a6e
                           : getPrevKeyFrame(m_videoStream, frameIndex);
Shinya Kitaoka 120a6e
    while (prevKeyFrame <= frameIndex) {
Shinya Kitaoka 120a6e
      bufferOut       = _aligned_malloc(si.dwSuggestedBufferSize, 128);
Shinya Kitaoka 120a6e
      DWORD bytesRead = si.dwSuggestedBufferSize;
Shinya Kitaoka 120a6e
      rc              = readFrameFromStream(bufferOut, bytesRead, prevKeyFrame);
Shinya Kitaoka 120a6e
      if (rc) {
Shinya Kitaoka 120a6e
        _aligned_free(bufferOut);
Shinya Kitaoka 120a6e
        throw TImageException(m_path, "unable read frame " +
Shinya Kitaoka 120a6e
                                          std::to_string(frameIndex) +
Shinya Kitaoka 120a6e
                                          "from video stream.");
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      DWORD res = decompressFrame(bufferOut, bytesRead, m_decompressedBuffer,
Shinya Kitaoka 120a6e
                                  prevKeyFrame, frameIndex);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      _aligned_free(bufferOut);
Shinya Kitaoka 120a6e
      if (res != ICERR_OK) {
Shinya Kitaoka 120a6e
        throw TImageException(
Shinya Kitaoka 120a6e
            m_path, "error decompressing frame " + std::to_string(frameIndex));
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      prevKeyFrame++;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int width  = m_srcBitmapInfo->bmiHeader.biWidth;
Shinya Kitaoka 120a6e
  int height = m_srcBitmapInfo->bmiHeader.biHeight;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int bpp     = m_dstBitmapInfo->bmiHeader.biBitCount;
Shinya Kitaoka 120a6e
  m_prevFrame = frameIndex;
Shinya Kitaoka 120a6e
  switch (bpp) {
Shinya Kitaoka 120a6e
  case 32: {
Shinya Kitaoka 120a6e
    TRasterPT<tpixelrgbm32> ret;</tpixelrgbm32>
Shinya Kitaoka 120a6e
    ret.create(width, height);
Shinya Kitaoka 120a6e
    ret->lock();
Shinya Kitaoka 120a6e
    memcpy(ret->getRawData(), m_decompressedBuffer, width * height * 4);
Shinya Kitaoka 120a6e
    ret->unlock();
Shinya Kitaoka 120a6e
    return TRasterImageP(ret);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  case 24: {
Shinya Kitaoka 120a6e
    TRasterImageP i(DIBToRaster((UCHAR *)m_decompressedBuffer, width, height));
Shinya Kitaoka 120a6e
    return i;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  default: {
Shinya Kitaoka 120a6e
    throw TImageException(m_path,
Shinya Kitaoka 120a6e
                          std::to_string(bpp) + " to 32 bit not supported\n");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return TRasterImageP();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TLevelReaderAvi::readFrameFromStream(void *bufferOut, DWORD &bufferSize,
Shinya Kitaoka 120a6e
                                         int frameIndex) const {
Shinya Kitaoka 120a6e
  assert(bufferOut && bufferSize > 0);
Shinya Kitaoka 120a6e
  LONG bytesReaded   = 0;
Shinya Kitaoka 120a6e
  LONG samplesReaded = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int rc = AVIStreamRead(m_videoStream, frameIndex, 1, bufferOut, bufferSize,
Shinya Kitaoka 120a6e
                         &bytesReaded, &samplesReaded);
Shinya Kitaoka 120a6e
  if (!rc) {
Shinya Kitaoka 120a6e
    assert(samplesReaded == 1);  // deve aver letto un frame!!!
Shinya Kitaoka 120a6e
    assert(bytesReaded <=
Shinya Kitaoka 120a6e
           (LONG)bufferSize);  // deve aver letto un numero di byte
Shinya Kitaoka 120a6e
    // minore o uguale di quello che ci aspettiamo
Shinya Kitaoka 120a6e
    bufferSize = bytesReaded;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return rc;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DWORD TLevelReaderAvi::decompressFrame(void *srcBuffer, int srcSize,
Shinya Kitaoka 120a6e
                                       void *dstBuffer, int currentFrame,
Shinya Kitaoka 120a6e
                                       int desiredFrame) {
Shinya Kitaoka 120a6e
  BITMAPINFOHEADER srcHeader = m_srcBitmapInfo->bmiHeader;
Shinya Kitaoka 120a6e
  BITMAPINFOHEADER dstHeader = m_dstBitmapInfo->bmiHeader;
Shinya Kitaoka 120a6e
  srcHeader.biSizeImage      = srcSize;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  DWORD dwFlags = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!isAKeyFrame(m_videoStream, currentFrame))
Shinya Kitaoka 120a6e
    dwFlags |= ICDECOMPRESS_NOTKEYFRAME;
Shinya Kitaoka 120a6e
  if (currentFrame < desiredFrame) dwFlags |= ICDECOMPRESS_PREROLL;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  DWORD res = ICDecompress(m_hic, dwFlags, &srcHeader, srcBuffer, &dstHeader,
Shinya Kitaoka 120a6e
                           dstBuffer);
Shinya Kitaoka 120a6e
  return res;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
TLevelReaderAvi::TLevelReaderAvi(const TFilePath &path)::TLevelReader(path) {}
Toshihiro Shimizu 890ddd
TLevelReaderAvi::~TLevelReaderAvi() {}
Toshihiro Shimizu 890ddd
TLevelP TLevelReaderAvi::loadInfo() { return TLevelP(); }
Shinya Kitaoka 120a6e
TImageReaderP TLevelReaderAvi::getFrameReader(TFrameId fid) {
Shinya Kitaoka 120a6e
  throw TImageException(m_path, "AVI not supported");
Shinya Kitaoka 120a6e
  return TImageReaderP(0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
TDimension TLevelReaderAvi::getSize() { return TDimension(); }
Shinya Kitaoka 120a6e
TImageP TLevelReaderAvi::load(int frameIndex) {
Shinya Kitaoka 120a6e
  throw TImageException(m_path, "AVI not supported");
Shinya Kitaoka 120a6e
  return TImageP(0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===========================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//  Tiio::AviWriterProperties
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//===========================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Shinya Kitaoka ba547e
Shinya Kitaoka ba547e
namespace {
Shinya Kitaoka 120a6e
BOOL safe_ICInfo(DWORD fccType, DWORD fccHandler, ICINFO *lpicinfo) {
Shinya Kitaoka ba547e
#ifdef _MSC_VER
Shinya Kitaoka 120a6e
  __try {
Shinya Kitaoka 120a6e
    return ICInfo(fccType, fccHandler, lpicinfo);
Shinya Kitaoka 120a6e
  } __except (EXCEPTION_EXECUTE_HANDLER) {
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return FALSE;
Shinya Kitaoka ba547e
#else
Shinya Kitaoka 120a6e
  return ICInfo(fccType, fccHandler, lpicinfo);
Shinya Kitaoka ba547e
#endif
Shinya Kitaoka 120a6e
}
Shinya Kitaoka ba547e
Shinya Kitaoka 120a6e
LRESULT safe_ICClose(HIC hic) {
Shinya Kitaoka ba547e
#ifdef _MSC_VER
Shinya Kitaoka 120a6e
  __try {
Shinya Kitaoka 120a6e
    if (hic) {
Shinya Kitaoka 120a6e
      return ICClose(hic);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } __except (EXCEPTION_EXECUTE_HANDLER) {
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka ba547e
#else
Shinya Kitaoka 120a6e
  if (hic) {
Shinya Kitaoka 120a6e
    return ICClose(hic);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka ba547e
#endif
Shinya Kitaoka 120a6e
  return ICERR_OK;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka ba547e
e280ae
#ifdef _MSC_VER
shun_iwasawa 0cae24
typedef std::unique_ptr<std::remove_pointer_t<hic>, decltype(&safe_ICClose)></std::remove_pointer_t<hic>
shun_iwasawa 0cae24
    hic_t;
e280ae
#else
shun_iwasawa 0cae24
typedef std::unique_ptr<std::remove_pointer<hic>::type, decltype(&safe_ICClose)></std::remove_pointer<hic>
shun_iwasawa 0cae24
    hic_t;
e280ae
#endif
Shinya Kitaoka ba547e
Shinya Kitaoka 120a6e
hic_t safe_ICOpen(DWORD fccType, DWORD fccHandler, UINT wMode) {
Shinya Kitaoka ba547e
#ifdef _MSC_VER
Shinya Kitaoka 120a6e
  HIC const hic = [fccType, fccHandler, wMode]() -> HIC {
Shinya Kitaoka 120a6e
    __try {
Shinya Kitaoka 120a6e
      return ICOpen(fccType, fccHandler, wMode);
Shinya Kitaoka 120a6e
    } __except (EXCEPTION_EXECUTE_HANDLER) {
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return nullptr;
Shinya Kitaoka 120a6e
  }();
Shinya Kitaoka ba547e
#else
Shinya Kitaoka 120a6e
  HIC hic = nullptr;
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    hic = ICOpen(fccType, fccHandler, wMode);
Shinya Kitaoka 120a6e
  } catch (...) {
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka ba547e
#endif
Shinya Kitaoka 120a6e
  return hic_t(hic, safe_ICClose);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka ba547e
Shinya Kitaoka 120a6e
LRESULT safe_ICGetInfo(hic_t const &hic, ICINFO *picinfo, DWORD cb) {
Shinya Kitaoka ba547e
#ifdef _MSC_VER
Shinya Kitaoka 120a6e
  __try {
Shinya Kitaoka 120a6e
    return ICGetInfo(hic.get(), picinfo, cb);
Shinya Kitaoka 120a6e
  } __except (EXCEPTION_EXECUTE_HANDLER) {
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return 0;  // return copied size in bytes (0 means an error)
Shinya Kitaoka ba547e
#else
Shinya Kitaoka 120a6e
  return ICGetInfo(hic.get(), picinfo, cb);
Shinya Kitaoka ba547e
#endif
Shinya Kitaoka 120a6e
}
Shinya Kitaoka ba547e
Shinya Kitaoka 120a6e
LRESULT safe_ICCompressQuery(hic_t const &hic, BITMAPINFO *lpbiInput,
Shinya Kitaoka 120a6e
                             BITMAPINFO *lpbiOutput) {
Shinya Kitaoka ba547e
#ifdef _MSC_VER
Shinya Kitaoka 120a6e
  __try {
Shinya Kitaoka 120a6e
    return ICCompressQuery(hic.get(), lpbiInput, lpbiOutput);
Shinya Kitaoka 120a6e
  } __except (EXCEPTION_EXECUTE_HANDLER) {
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return ICERR_INTERNAL;
Shinya Kitaoka ba547e
#else
Shinya Kitaoka 120a6e
  return ICCompressQuery(hic.get(), lpbiInput, lpbiOutput);
Shinya Kitaoka ba547e
#endif
Shinya Kitaoka 120a6e
}
shun-iwasawa a63c2d
}  // namespace
Shinya Kitaoka ba547e
Shinya Kitaoka 120a6e
Tiio::AviWriterProperties::AviWriterProperties() : m_codec("Codec") {
Shinya Kitaoka 120a6e
  if (m_defaultCodec.getRange().empty()) {
Shinya Kitaoka 120a6e
    char descr[2048], name[2048];
Shinya Kitaoka 120a6e
    DWORD fccType = 0;
Shinya Kitaoka 120a6e
    ICINFO icinfo;
Shinya Kitaoka 120a6e
    BITMAPINFO inFmt;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_defaultCodec.addValue(L"Uncompressed");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    memset(&inFmt, 0, sizeof(BITMAPINFO));
Shinya Kitaoka 120a6e
    inFmt.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
Shinya Kitaoka 120a6e
    inFmt.bmiHeader.biWidth       = 100;
Shinya Kitaoka 120a6e
    inFmt.bmiHeader.biHeight      = 100;
Shinya Kitaoka 120a6e
    inFmt.bmiHeader.biPlanes      = 1;
Shinya Kitaoka 120a6e
    inFmt.bmiHeader.biCompression = BI_RGB;
Shinya Kitaoka 120a6e
    for (int bpp = 32; bpp >= 24; bpp -= 8) {
Shinya Kitaoka 120a6e
      inFmt.bmiHeader.biBitCount = bpp;
Shinya Kitaoka 120a6e
      for (int i = 0;; i++) {
Shinya Kitaoka 120a6e
        memset(&icinfo, 0, sizeof icinfo);
Shinya Kitaoka 120a6e
        if (!safe_ICInfo(fccType, i, &icinfo)) {
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        auto const hic =
Shinya Kitaoka 120a6e
            safe_ICOpen(icinfo.fccType, icinfo.fccHandler, ICMODE_QUERY);
Shinya Kitaoka 120a6e
        if (!hic) {
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // Find out the compressor name
Shinya Kitaoka 120a6e
        if (safe_ICGetInfo(hic, &icinfo, sizeof(ICINFO)) == 0) {
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        WideChar2Char(icinfo.szDescription, descr, sizeof(descr));
Shinya Kitaoka 120a6e
        WideChar2Char(icinfo.szName, name, sizeof(name));
Shinya Kitaoka 120a6e
        if ((strstr(name, "IYUV") != 0) ||
Shinya Kitaoka 120a6e
            ((strstr(name, "IR32") != 0) && (bpp == 24))) {
Shinya Kitaoka 120a6e
          continue;
Shinya Kitaoka 120a6e
        }
shun-iwasawa a63c2d
        // Give up to load codecs once the blackmagic codec is found -
shun-iwasawa a63c2d
        // as it seems to cause crash for unknown reasons (issue #138)
shun-iwasawa a63c2d
        if (strstr(descr, "Blackmagic") != 0) break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        std::string compressorName;
Shinya Kitaoka 120a6e
        compressorName = std::string(name) + " '" + std::to_string(bpp) + "' " +
Shinya Kitaoka 120a6e
                         std::string(descr);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // per il momento togliamo i codec indeo
Shinya Kitaoka 120a6e
        if (std::string(compressorName).find("Indeo") != -1) {
Shinya Kitaoka 120a6e
          continue;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (safe_ICCompressQuery(hic, &inFmt, nullptr) != ICERR_OK) {
Shinya Kitaoka 120a6e
          continue;  // Skip this compressor if it can't handle the format.
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        m_defaultCodec.addValue(::to_wstring(compressorName));
Shinya Kitaoka 120a6e
        if (compressorName.find("inepak") != -1) {
Shinya Kitaoka 120a6e
          m_defaultCodec.setValue(::to_wstring(compressorName));
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_codec = m_defaultCodec;
Shinya Kitaoka 120a6e
  bind(m_codec);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
shun-iwasawa e87e08
void Tiio::AviWriterProperties::updateTranslation() {
shun-iwasawa e87e08
  m_codec.setQStringName(tr("Codec"));
shun-iwasawa e87e08
  m_codec.setItemUIName(L"Uncompressed", tr("Uncompressed"));
shun-iwasawa e87e08
}
shun-iwasawa e87e08
Shinya Kitaoka 120a6e
TEnumProperty Tiio::AviWriterProperties::m_defaultCodec =
Shinya Kitaoka 120a6e
    TEnumProperty("Codec");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif