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