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