#if (defined(x64) || defined(__LP64__))
//Toonz includes
#include "tfilepath.h"
#include "trasterimage.h"
#include "tstream.h"
#include "timageinfo.h"
#include "trop.h"
#include "tsound.h"
//tipc includes
#include "tipc.h"
#include "t32bitsrv_wrap.h"
//Qt includes
#include <QSharedMemory>
#include <QMutexLocker>
#include <QDataStream>
#include "tiio_mov_proxy.h"
/*
For a list of supported commands through the 32-bit background server,
see the related "t32libserver" project.
*/
//******************************************************************************
// Generic stuff implementation
//******************************************************************************
bool IsQuickTimeInstalled()
{
#if !defined(__OSX__)
//NOTE: This is *NOT* the same function as Tiio::isQuickTimeInstalled !!
//There actually are 2 distinct functions with essentially the same name, one
//in tnzcore lib, the other in image. The core version is currently NEVER USED
//throughout Toonz, even if it's EXPORT-defined.
QLocalSocket socket;
if (!tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), 3000, t32bitsrv::srvCmdline()))
return false;
tipc::Stream stream(&socket);
tipc::Message msg;
stream << (msg << QString("$isQTInstalled"));
if (tipc::readMessage(stream, msg) != "yes")
return false;
return true;
#else
return false;
#endif
};
//---------------------------------------------------------------------
Tiio::MovWriterProperties::MovWriterProperties()
{
QLocalSocket socket;
tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1, t32bitsrv::srvCmdline());
tipc::Stream stream(&socket);
tipc::Message msg;
//Retrieve a temporary file to pass the data
QString fp;
{
stream << (msg << QString("$tmpfile_request") << QString("MovWriterProps"));
if (tipc::readMessage(stream, msg) != "ok")
goto err;
msg >> fp;
assert(!fp.isEmpty());
}
//Make the server write the data to the file
{
stream << (msg << tipc::clr << QString("$defaultMovProps") << fp);
if (tipc::readMessage(stream, msg) != "ok")
goto err;
//Load the data
TFilePath tfp(fp.toStdWString());
TIStream is(tfp);
loadData(is);
}
//Release the temporary file
{
stream << (msg << tipc::clr << QString("$tmpfile_release") << QString("MovWriterProps"));
if (tipc::readMessage(stream, msg) != "ok")
goto err;
}
return;
err:
throw TException("Server error");
}
//******************************************************************************
// TImageWriterMov Proxy implementation
//******************************************************************************
class TImageWriterMovProxy : public TImageWriter
{
TLevelWriterMov *m_lw;
public:
int m_frameIndex;
public:
TImageWriterMovProxy(const TFilePath &fp, int frameIndex, TLevelWriterMov *lw);
~TImageWriterMovProxy();
bool is64bitOutputSupported() { return false; }
void save(const TImageP &);
private:
//not implemented
TImageWriterMovProxy(const TImageWriterMovProxy &);
TImageWriterMovProxy &operator=(const TImageWriterMovProxy &src);
};
//------------------------------------------------------------------
TImageWriterMovProxy::TImageWriterMovProxy(const TFilePath &fp, int frameIndex, TLevelWriterMov *lw)
: TImageWriter(fp), m_lw(lw), m_frameIndex(frameIndex)
{
m_lw->addRef();
}
//------------------------------------------------------------------
TImageWriterMovProxy::~TImageWriterMovProxy()
{
m_lw->release();
}
//------------------------------------------------------------------
void TImageWriterMovProxy::save(const TImageP &img)
{
m_lw->save(img, m_frameIndex);
}
//******************************************************************************
// TLevelWriterMov Proxy implementation
//******************************************************************************
TLevelWriterMov::TLevelWriterMov(const TFilePath &path, TPropertyGroup *winfo)
: TLevelWriter(path, winfo)
{
static TAtomicVar count;
unsigned int currCount = ++count;
m_id = currCount;
QLocalSocket socket;
tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1, t32bitsrv::srvCmdline());
tipc::Stream stream(&socket);
tipc::Message msg;
QString res, propsFp;
if (winfo) {
//Request a temporary file to store the infos to
stream << (msg << QString("$tmpfile_request") << QString("initLWMov") + QString::number(currCount));
if (tipc::readMessage(stream, msg) != "ok")
goto err;
msg >> propsFp >> tipc::clr;
assert(!propsFp.isEmpty());
TFilePath propsTfp(propsFp.toStdWString());
{
TOStream os(propsTfp);
winfo->saveData(os);
}
}
//Pass fp to the server
stream << (msg << QString("$initLWMov") << m_id << QString::fromStdWString(path.getWideString()) << propsFp);
if (tipc::readMessage(stream, msg) != "ok")
goto err;
if (winfo) {
stream << (msg << tipc::clr << QString("$tmpfile_release")
<< QString("initLWMov") + QString::number(currCount));
if (tipc::readMessage(stream, msg) != "ok")
goto err;
}
return;
err:
throw TException("Unable to write file");
}
//------------------------------------------------------------------
TLevelWriterMov::~TLevelWriterMov()
{
QLocalSocket socket;
tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1, t32bitsrv::srvCmdline());
tipc::Stream stream(&socket);
tipc::Message msg;
QString res;
stream << (msg << QString("$closeLWMov") << m_id);
if (tipc::readMessage(stream, msg) != "ok")
throw TException("Unable to write file");
}
//------------------------------------------------------------------
void TLevelWriterMov::setFrameRate(double fps)
{
TLevelWriter::setFrameRate(fps);
QLocalSocket socket;
tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1, t32bitsrv::srvCmdline());
tipc::Stream stream(&socket);
tipc::Message msg;
QString res;
stream << (msg << QString("$LWMovSetFrameRate") << m_id << fps);
if (tipc::readMessage(stream, msg) != "ok")
throw TException("Unexpected error");
}
//------------------------------------------------------------------
TImageWriterP TLevelWriterMov::getFrameWriter(TFrameId fid)
{
if (fid.getLetter() != 0)
return TImageWriterP(0);
int index = fid.getNumber() - 1;
return new TImageWriterMovProxy(m_path, index, this);
}
//------------------------------------------------------------------
void TLevelWriterMov::save(const TImageP &img, int frameIndex)
{
TRasterImageP ri(img);
if (!img)
throw TImageException(getFilePath(), "Unsupported image type");
TRasterP ras(ri->getRaster());
int lx = ras->getLx(), ly = ras->getLy(), pixSize = ras->getPixelSize();
if (pixSize != 4)
throw TImageException(getFilePath(), "Unsupported pixel type");
int size = lx * ly * pixSize;
//Send messages
QLocalSocket socket;
tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1, t32bitsrv::srvCmdline());
tipc::Stream stream(&socket);
tipc::Message msg;
//Send the write message.
stream << (msg << QString("$LWMovImageWrite") << m_id << frameIndex << lx << ly);
//Send the data through a shared memory segment
{
t32bitsrv::RasterExchanger<TPixel32> exch(ras);
tipc::writeShMemBuffer(stream, msg << tipc::clr, size, &exch);
}
if (tipc::readMessage(stream, msg) != "ok")
throw TImageException(getFilePath(), "Couln't save image");
}
//------------------------------------------------------------------
void TLevelWriterMov::saveSoundTrack(TSoundTrack *st)
{
if (st == 0)
return;
//Prepare connection
QLocalSocket socket;
tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1, t32bitsrv::srvCmdline());
unsigned int size = st->getSampleSize() * st->getSampleCount();
//Send the saveSoundTract command to the server
tipc::Stream stream(&socket);
tipc::Message msg;
stream << (msg << QString("$LWMovSaveSoundTrack") << m_id << st->getSampleRate() << st->getBitPerSample()
<< st->getChannelCount() << st->getSampleCount() << st->getFormat().m_signedSample);
t32bitsrv::BufferExchanger exch((UCHAR *)st->getRawData());
tipc::writeShMemBuffer(stream, msg << tipc::clr, size, &exch);
QString res(tipc::readMessage(stream, msg));
assert(res == "ok");
}
//******************************************************************************
// TImageReaderMov Proxy implementation
//******************************************************************************
class TImageReaderMovProxy : public TImageReader
{
TLevelReaderMov *m_lr;
TImageInfo *m_info;
public:
int m_frameIndex;
public:
TImageReaderMovProxy(const TFilePath &fp, int frameIndex, TLevelReaderMov *lr, TImageInfo *info);
~TImageReaderMovProxy() { m_lr->release(); }
TImageP load();
void load(const TRasterP &rasP, const TPoint &pos = TPoint(0, 0), int shrinkX = 1, int shrinkY = 1);
TDimension getSize() const { return m_lr->getSize(); }
TRect getBBox() const { return m_lr->getBBox(); }
const TImageInfo *getImageInfo() const { return m_info; }
private:
//not implemented
TImageReaderMovProxy(const TImageReaderMovProxy &);
TImageReaderMovProxy &operator=(const TImageReaderMovProxy &src);
};
//------------------------------------------------------------------
TImageReaderMovProxy::TImageReaderMovProxy(const TFilePath &fp, int frameIndex,
TLevelReaderMov *lr, TImageInfo *info)
: TImageReader(fp), m_lr(lr), m_frameIndex(frameIndex), m_info(info)
{
m_lr->addRef();
}
//------------------------------------------------------------------
TImageP TImageReaderMovProxy::load()
{
TRaster32P ras(m_lr->getSize());
m_lr->load(ras, m_frameIndex, TPointI(), 1, 1);
return TRasterImageP(ras);
}
//------------------------------------------------------------------
void TImageReaderMovProxy::load(const TRasterP &rasP, const TPoint &pos, int shrinkX, int shrinkY)
{
//NOTE: The original implementation is different. But is also does not make sense...
//I've substituted it with the lrm plain call.
m_lr->load(rasP, m_frameIndex, pos, shrinkX, shrinkY);
}
//******************************************************************************
// TLevelReaderMov Proxy implementation
//******************************************************************************
TLevelReaderMov::TLevelReaderMov(const TFilePath &path)
: TLevelReader(path)
{
static TAtomicVar count;
unsigned int currCount = ++count;
m_id = currCount;
QLocalSocket socket;
tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1, t32bitsrv::srvCmdline());
tipc::Stream stream(&socket);
tipc::Message msg;
stream << (msg << QString("$initLRMov") << m_id << QString::fromStdWString(path.getWideString()));
if (tipc::readMessage(stream, msg) != "ok")
throw TImageException(path, "Couldn't open file");
double frameRate;
msg >> m_lx >> m_ly >> frameRate >> tipc::clr;
m_info = new TImageInfo;
m_info->m_lx = m_lx;
m_info->m_ly = m_ly;
m_info->m_frameRate = frameRate;
}
//------------------------------------------------------------------
TLevelReaderMov::~TLevelReaderMov()
{
QLocalSocket socket;
tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1, t32bitsrv::srvCmdline());
tipc::Stream stream(&socket);
tipc::Message msg;
stream << (msg << QString("$closeLRMov") << m_id);
QString res(tipc::readMessage(stream, msg));
assert(res == "ok");
}
//------------------------------------------------------------------
TImageReaderP TLevelReaderMov::getFrameReader(TFrameId fid)
{
if (fid.getLetter() != 0)
return TImageReaderP(0);
int index = fid.getNumber() - 1;
return new TImageReaderMovProxy(m_path, index, this, m_info);
}
//------------------------------------------------------------------
TLevelP TLevelReaderMov::loadInfo()
{
QLocalSocket socket;
tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1, t32bitsrv::srvCmdline());
tipc::Stream stream(&socket);
tipc::Message msg;
TLevelP level;
{
QString shMemId(tipc::uniqueId());
//Send the appropriate command
stream << (msg << QString("$LRMovLoadInfo") << m_id << shMemId);
if (tipc::readMessage(stream, msg) != "ok")
goto err;
int frameCount;
msg >> frameCount >> tipc::clr;
//Read the data in the shared memory segment
QSharedMemory shmem(shMemId);
shmem.attach();
shmem.lock();
int *f, *fBegin = (int *)shmem.data(), *fEnd = fBegin + frameCount;
assert(fBegin);
for (f = fBegin; f < fEnd; ++f)
level->setFrame(*f, TImageP());
shmem.unlock();
shmem.detach();
//Release the shared memory segment
stream << (msg << QString("$shmem_release") << shMemId);
if (tipc::readMessage(stream, msg) != "ok")
goto err;
}
return level;
err:
throw TException("Couldn't read movie data");
return TLevelP();
}
//------------------------------------------------------------------
void TLevelReaderMov::enableRandomAccessRead(bool enable)
{
QLocalSocket socket;
tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1, t32bitsrv::srvCmdline());
tipc::Stream stream(&socket);
tipc::Message msg;
stream << (msg << QString("$LRMovEnableRandomAccessRead") << m_id << QString(enable ? "true" : "false"));
QString res(tipc::readMessage(stream, msg));
assert(res == "ok");
}
//------------------------------------------------------------------
void TLevelReaderMov::load(const TRasterP &ras, int frameIndex, const TPoint &pos,
int shrinkX, int shrinkY)
{
QLocalSocket socket;
tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1, t32bitsrv::srvCmdline());
tipc::Stream stream(&socket);
tipc::Message msg;
unsigned int size = ras->getLx() * ras->getLy() * ras->getPixelSize();
//Send the appropriate command to the 32-bit server
stream << (msg << QString("$LRMovImageRead") << m_id << ras->getLx() << ras->getLy() << ras->getPixelSize()
<< frameIndex << pos.x << pos.y << shrinkX << shrinkY);
t32bitsrv::RasterExchanger<TPixel32> exch(ras);
if (!tipc::readShMemBuffer(stream, msg << tipc::clr, &exch))
throw TException("Couldn't load image");
}
#endif //x64