1 
2 
3 #if defined(x64) || defined(__LP64__) || defined(LINUX) || defined(FREEBSD) || (defined(_WIN32) && defined(__GNUC__))
4 
5 // Toonz includes
6 #include "tfilepath.h"
7 #include "trasterimage.h"
8 #include "tstream.h"
9 #include "timageinfo.h"
10 #include "trop.h"
11 #include "tsound.h"
12 #include "tmsgcore.h"
13 
14 // tipc includes
15 #include "tipc.h"
16 #include "t32bitsrv_wrap.h"
17 
18 // Qt includes
19 #include <QSharedMemory>
20 #include <QMutexLocker>
21 #include <QDataStream>
22 
23 #include "tiio_mov_proxy.h"
24 
25 /*
26   For a list of supported commands through the 32-bit background server,
27   see the related "t32libserver" project.
28 */
29 
30 //******************************************************************************
31 //    Generic stuff implementation
32 //******************************************************************************
33 
IsQuickTimeInstalled()34 bool IsQuickTimeInstalled() {
35 #if !defined(__OSX__)
36   // NOTE: This is *NOT* the same function as Tiio::isQuickTimeInstalled !!
37   // There actually are 2 distinct functions with essentially the same name, one
38   // in tnzcore lib, the other in image. The core version is currently NEVER
39   // USED
40   // throughout Toonz, even if it's EXPORT-defined.
41   QLocalSocket socket;
42   if (!tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), 3000,
43                                   t32bitsrv::srvCmdline()))
44     return false;
45 
46   tipc::Stream stream(&socket);
47   tipc::Message msg;
48 
49   stream << (msg << QString("$isQTInstalled"));
50 
51   if (tipc::readMessage(stream, msg) != "yes") return false;
52   return true;
53 #else
54   return false;
55 #endif
56 };
57 
58 //---------------------------------------------------------------------
59 
MovWriterProperties()60 Tiio::MovWriterProperties::MovWriterProperties() {
61   QLocalSocket socket;
62   tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1,
63                              t32bitsrv::srvCmdline());
64 
65   tipc::Stream stream(&socket);
66   tipc::Message msg;
67 
68   // Retrieve a temporary file to pass the data
69   QString fp;
70   {
71     stream << (msg << QString("$tmpfile_request") << QString("MovWriterProps"));
72 
73     if (tipc::readMessage(stream, msg) != "ok") goto err;
74 
75     msg >> fp;
76     assert(!fp.isEmpty());
77   }
78 
79   // Make the server write the data to the file
80   {
81     stream << (msg << tipc::clr << QString("$defaultMovProps") << fp);
82     if (tipc::readMessage(stream, msg) != "ok") goto err;
83 
84     // Load the data
85     TFilePath tfp(fp.toStdWString());
86     TIStream is(tfp);
87     loadData(is);
88   }
89 
90   // Release the temporary file
91   {
92     stream << (msg << tipc::clr << QString("$tmpfile_release")
93                    << QString("MovWriterProps"));
94     if (tipc::readMessage(stream, msg) != "ok") goto err;
95   }
96 
97   return;
98 
99 err:
100 
101   throw TException("Server error");
102 }
103 
104 //******************************************************************************
105 //    TImageWriterMov Proxy implementation
106 //******************************************************************************
107 
108 class TImageWriterMovProxy final : public TImageWriter {
109   TLevelWriterMov *m_lw;
110 
111 public:
112   int m_frameIndex;
113 
114 public:
115   TImageWriterMovProxy(const TFilePath &fp, int frameIndex,
116                        TLevelWriterMov *lw);
117   ~TImageWriterMovProxy();
118 
is64bitOutputSupported()119   bool is64bitOutputSupported() { return false; }
120   void save(const TImageP &);
121 
122 private:
123   // not implemented
124   TImageWriterMovProxy(const TImageWriterMovProxy &);
125   TImageWriterMovProxy &operator=(const TImageWriterMovProxy &src);
126 };
127 
128 //------------------------------------------------------------------
129 
TImageWriterMovProxy(const TFilePath & fp,int frameIndex,TLevelWriterMov * lw)130 TImageWriterMovProxy::TImageWriterMovProxy(const TFilePath &fp, int frameIndex,
131                                            TLevelWriterMov *lw)
132     : TImageWriter(fp), m_lw(lw), m_frameIndex(frameIndex) {
133   m_lw->addRef();
134 }
135 
136 //------------------------------------------------------------------
137 
~TImageWriterMovProxy()138 TImageWriterMovProxy::~TImageWriterMovProxy() { m_lw->release(); }
139 
140 //------------------------------------------------------------------
141 
save(const TImageP & img)142 void TImageWriterMovProxy::save(const TImageP &img) {
143   m_lw->save(img, m_frameIndex);
144 }
145 
146 //******************************************************************************
147 //    TLevelWriterMov Proxy implementation
148 //******************************************************************************
149 
TLevelWriterMov(const TFilePath & path,TPropertyGroup * winfo)150 TLevelWriterMov::TLevelWriterMov(const TFilePath &path, TPropertyGroup *winfo)
151     : TLevelWriter(path, winfo) {
152   static TAtomicVar count;
153   unsigned int currCount = ++count;
154   m_id                   = currCount;
155 
156   QLocalSocket socket;
157   tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1,
158                              t32bitsrv::srvCmdline());
159 
160   tipc::Stream stream(&socket);
161   tipc::Message msg;
162 
163   QString res, propsFp;
164   if (winfo) {
165     // Request a temporary file to store the infos to
166     stream << (msg << QString("$tmpfile_request")
167                    << QString("initLWMov") + QString::number(currCount));
168     if (tipc::readMessage(stream, msg) != "ok") goto err;
169 
170     msg >> propsFp >> tipc::clr;
171     assert(!propsFp.isEmpty());
172 
173     TFilePath propsTfp(propsFp.toStdWString());
174     {
175       TOStream os(propsTfp);
176       winfo->saveData(os);
177     }
178   }
179 
180   // Pass fp to the server
181   stream << (msg << QString("$initLWMov") << m_id
182                  << QString::fromStdWString(path.getWideString()) << propsFp);
183   if (tipc::readMessage(stream, msg) != "ok") goto err;
184 
185   if (winfo) {
186     stream << (msg << tipc::clr << QString("$tmpfile_release")
187                    << QString("initLWMov") + QString::number(currCount));
188     if (tipc::readMessage(stream, msg) != "ok") goto err;
189   }
190 
191   return;
192 
193 err:
194 
195   throw TException("Unable to write file");
196 }
197 
198 //------------------------------------------------------------------
199 
~TLevelWriterMov()200 TLevelWriterMov::~TLevelWriterMov() {
201   QLocalSocket socket;
202   tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1,
203                              t32bitsrv::srvCmdline());
204 
205   tipc::Stream stream(&socket);
206   tipc::Message msg;
207   QString res;
208 
209   stream << (msg << QString("$closeLWMov") << m_id);
210   if (tipc::readMessage(stream, msg) != "ok")
211     DVGui::warning("Unable to write file");
212 }
213 
214 //------------------------------------------------------------------
215 
setFrameRate(double fps)216 void TLevelWriterMov::setFrameRate(double fps) {
217   TLevelWriter::setFrameRate(fps);
218 
219   QLocalSocket socket;
220   tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1,
221                              t32bitsrv::srvCmdline());
222 
223   tipc::Stream stream(&socket);
224   tipc::Message msg;
225   QString res;
226 
227   stream << (msg << QString("$LWMovSetFrameRate") << m_id << fps);
228   if (tipc::readMessage(stream, msg) != "ok")
229     throw TException("Unexpected error");
230 }
231 
232 //------------------------------------------------------------------
233 
getFrameWriter(TFrameId fid)234 TImageWriterP TLevelWriterMov::getFrameWriter(TFrameId fid) {
235   if (fid.getLetter() != 0) return TImageWriterP(0);
236 
237   int index = fid.getNumber() - 1;
238   return new TImageWriterMovProxy(m_path, index, this);
239 }
240 
241 //------------------------------------------------------------------
242 
save(const TImageP & img,int frameIndex)243 void TLevelWriterMov::save(const TImageP &img, int frameIndex) {
244   TRasterImageP ri(img);
245   if (!img) throw TImageException(getFilePath(), "Unsupported image type");
246 
247   TRasterP ras(ri->getRaster());
248 
249   int lx = ras->getLx(), ly = ras->getLy(), pixSize = ras->getPixelSize();
250   if (pixSize != 4)
251     throw TImageException(getFilePath(), "Unsupported pixel type");
252 
253   int size = lx * ly * pixSize;
254 
255   // Send messages
256   QLocalSocket socket;
257   tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1,
258                              t32bitsrv::srvCmdline());
259 
260   tipc::Stream stream(&socket);
261   tipc::Message msg;
262 
263   // Send the write message.
264   stream << (msg << QString("$LWMovImageWrite") << m_id << frameIndex << lx
265                  << ly);
266 
267   // Send the data through a shared memory segment
268   {
269     t32bitsrv::RasterExchanger<TPixel32> exch(ras);
270     tipc::writeShMemBuffer(stream, msg << tipc::clr, size, &exch);
271   }
272 
273   if (tipc::readMessage(stream, msg) != "ok")
274     throw TImageException(getFilePath(), "Couln't save image");
275 }
276 
277 //------------------------------------------------------------------
278 
saveSoundTrack(TSoundTrack * st)279 void TLevelWriterMov::saveSoundTrack(TSoundTrack *st) {
280   if (st == 0) return;
281 
282   // Prepare connection
283   QLocalSocket socket;
284   tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1,
285                              t32bitsrv::srvCmdline());
286 
287   unsigned int size = st->getSampleSize() * st->getSampleCount();
288 
289   // Send the saveSoundTract command to the server
290   tipc::Stream stream(&socket);
291   tipc::Message msg;
292 
293   stream << (msg << QString("$LWMovSaveSoundTrack") << m_id
294                  << st->getSampleRate() << st->getBitPerSample()
295                  << st->getChannelCount() << st->getSampleCount()
296                  << st->getFormat().m_signedSample);
297 
298   t32bitsrv::BufferExchanger exch((UCHAR *)st->getRawData());
299   tipc::writeShMemBuffer(stream, msg << tipc::clr, size, &exch);
300 
301   QString res(tipc::readMessage(stream, msg));
302   assert(res == "ok");
303 }
304 
305 //******************************************************************************
306 //    TImageReaderMov Proxy implementation
307 //******************************************************************************
308 
309 class TImageReaderMovProxy final : public TImageReader {
310   TLevelReaderMov *m_lr;
311   TImageInfo *m_info;
312 
313 public:
314   int m_frameIndex;
315 
316 public:
317   TImageReaderMovProxy(const TFilePath &fp, int frameIndex, TLevelReaderMov *lr,
318                        TImageInfo *info);
~TImageReaderMovProxy()319   ~TImageReaderMovProxy() { m_lr->release(); }
320 
321   TImageP load();
322   void load(const TRasterP &rasP, const TPoint &pos = TPoint(0, 0),
323             int shrinkX = 1, int shrinkY = 1);
324 
getSize() const325   TDimension getSize() const { return m_lr->getSize(); }
getBBox() const326   TRect getBBox() const { return m_lr->getBBox(); }
327 
getImageInfo() const328   const TImageInfo *getImageInfo() const { return m_info; }
329 
330 private:
331   // not implemented
332   TImageReaderMovProxy(const TImageReaderMovProxy &);
333   TImageReaderMovProxy &operator=(const TImageReaderMovProxy &src);
334 };
335 
336 //------------------------------------------------------------------
337 
TImageReaderMovProxy(const TFilePath & fp,int frameIndex,TLevelReaderMov * lr,TImageInfo * info)338 TImageReaderMovProxy::TImageReaderMovProxy(const TFilePath &fp, int frameIndex,
339                                            TLevelReaderMov *lr,
340                                            TImageInfo *info)
341     : TImageReader(fp), m_lr(lr), m_frameIndex(frameIndex), m_info(info) {
342   m_lr->addRef();
343 }
344 
345 //------------------------------------------------------------------
346 
load()347 TImageP TImageReaderMovProxy::load() {
348   TRaster32P ras(m_lr->getSize());
349   m_lr->load(ras, m_frameIndex, TPointI(), 1, 1);
350   return TRasterImageP(ras);
351 }
352 
353 //------------------------------------------------------------------
354 
load(const TRasterP & rasP,const TPoint & pos,int shrinkX,int shrinkY)355 void TImageReaderMovProxy::load(const TRasterP &rasP, const TPoint &pos,
356                                 int shrinkX, int shrinkY) {
357   // NOTE: The original implementation is different. But is also does not make
358   // sense...
359   // I've substituted it with the lrm plain call.
360   m_lr->load(rasP, m_frameIndex, pos, shrinkX, shrinkY);
361 }
362 
363 //******************************************************************************
364 //    TLevelReaderMov Proxy implementation
365 //******************************************************************************
366 
TLevelReaderMov(const TFilePath & path)367 TLevelReaderMov::TLevelReaderMov(const TFilePath &path) : TLevelReader(path) {
368   static TAtomicVar count;
369   unsigned int currCount = ++count;
370   m_id                   = currCount;
371 
372   QLocalSocket socket;
373   tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1,
374                              t32bitsrv::srvCmdline());
375 
376   tipc::Stream stream(&socket);
377   tipc::Message msg;
378 
379   stream << (msg << QString("$initLRMov") << m_id
380                  << QString::fromStdWString(path.getWideString()));
381   if (tipc::readMessage(stream, msg) != "ok")
382     throw TImageException(path, "Couldn't open file");
383 
384   double frameRate;
385   msg >> m_lx >> m_ly >> frameRate >> tipc::clr;
386 
387   m_info              = new TImageInfo;
388   m_info->m_lx        = m_lx;
389   m_info->m_ly        = m_ly;
390   m_info->m_frameRate = frameRate;
391 }
392 
393 //------------------------------------------------------------------
394 
~TLevelReaderMov()395 TLevelReaderMov::~TLevelReaderMov() {
396   QLocalSocket socket;
397   tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1,
398                              t32bitsrv::srvCmdline());
399 
400   tipc::Stream stream(&socket);
401   tipc::Message msg;
402 
403   stream << (msg << QString("$closeLRMov") << m_id);
404   QString res(tipc::readMessage(stream, msg));
405   assert(res == "ok");
406 }
407 
408 //------------------------------------------------------------------
409 
getFrameReader(TFrameId fid)410 TImageReaderP TLevelReaderMov::getFrameReader(TFrameId fid) {
411   if (fid.getLetter() != 0) return TImageReaderP(0);
412 
413   int index = fid.getNumber() - 1;
414   return new TImageReaderMovProxy(m_path, index, this, m_info);
415 }
416 
417 //------------------------------------------------------------------
418 
loadInfo()419 TLevelP TLevelReaderMov::loadInfo() {
420   QLocalSocket socket;
421   tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1,
422                              t32bitsrv::srvCmdline());
423 
424   tipc::Stream stream(&socket);
425   tipc::Message msg;
426 
427   TLevelP level;
428   {
429     QString shMemId(tipc::uniqueId());
430 
431     // Send the appropriate command
432     stream << (msg << QString("$LRMovLoadInfo") << m_id << shMemId);
433     if (tipc::readMessage(stream, msg) != "ok") goto err;
434 
435     int frameCount;
436 
437     msg >> frameCount >> tipc::clr;
438 
439     // Read the data in the shared memory segment
440     QSharedMemory shmem(shMemId);
441     shmem.attach();
442     shmem.lock();
443 
444     int *f, *fBegin = (int *)shmem.data(), *fEnd = fBegin + frameCount;
445     assert(fBegin);
446 
447     for (f = fBegin; f < fEnd; ++f) level->setFrame(*f, TImageP());
448 
449     shmem.unlock();
450     shmem.detach();
451 
452     // Release the shared memory segment
453     stream << (msg << QString("$shmem_release") << shMemId);
454     if (tipc::readMessage(stream, msg) != "ok") goto err;
455   }
456 
457   return level;
458 
459 err:
460 
461   throw TException("Couldn't read movie data");
462   return TLevelP();
463 }
464 
465 //------------------------------------------------------------------
466 
enableRandomAccessRead(bool enable)467 void TLevelReaderMov::enableRandomAccessRead(bool enable) {
468   QLocalSocket socket;
469   tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1,
470                              t32bitsrv::srvCmdline());
471 
472   tipc::Stream stream(&socket);
473   tipc::Message msg;
474 
475   stream << (msg << QString("$LRMovEnableRandomAccessRead") << m_id
476                  << QString(enable ? "true" : "false"));
477   QString res(tipc::readMessage(stream, msg));
478   assert(res == "ok");
479 }
480 
481 //------------------------------------------------------------------
482 
load(const TRasterP & ras,int frameIndex,const TPoint & pos,int shrinkX,int shrinkY)483 void TLevelReaderMov::load(const TRasterP &ras, int frameIndex,
484                            const TPoint &pos, int shrinkX, int shrinkY) {
485   QLocalSocket socket;
486   tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), -1,
487                              t32bitsrv::srvCmdline());
488 
489   tipc::Stream stream(&socket);
490   tipc::Message msg;
491 
492   unsigned int size = ras->getLx() * ras->getLy() * ras->getPixelSize();
493 
494   // Send the appropriate command to the 32-bit server
495   stream << (msg << QString("$LRMovImageRead") << m_id << ras->getLx()
496                  << ras->getLy() << ras->getPixelSize() << frameIndex << pos.x
497                  << pos.y << shrinkX << shrinkY);
498 
499   t32bitsrv::RasterExchanger<TPixel32> exch(ras);
500   if (!tipc::readShMemBuffer(stream, msg << tipc::clr, &exch))
501     throw TException("Couldn't load image");
502 }
503 
504 #endif  // x64
505