1
2
3 #include "texception.h"
4 #include "tpropertytype.h"
5 //#include "timageinfo.h"
6 //#include "tlevel_io.h"
7 #include "tproperty.h"
8 #include "tiio.h"
9
10 #if !defined(x64) && !defined(__LP64__) && !(defined(LINUX) || defined(FREEBSD)) && !(defined(__GNUC__) && defined(_WIN32))
11
12 //*******************************************************************************
13 // 32-bit version
14 //*******************************************************************************
15
16 #ifdef _WIN32
17 #ifdef _MSC_VER
18 #pragma warning(disable : 4996)
19 #endif
20
21 #define list QuickTime_list
22 #define map QuickTime_map
23 #define iterator QuickTime_iterator
24 #define float_t QuickTime_float_t
25 #define GetProcessInformation QuickTime_GetProcessInformation
26 #define int_fast8_t QuickTime_int_fast8_t
27 #define int_fast16_t QuickTime_int_fast16_t
28 #define uint_fast16_t QuickTime_uint_fast16_t
29
30 #include "QTML.h"
31 #include "Movies.h"
32 #include "Script.h"
33 #include "FixMath.h"
34 #include "Sound.h"
35
36 #include "QuickTimeComponents.h"
37 #include "tquicktime.h"
38
39 #undef list
40 #undef map
41 #undef iterator
42 #undef float_t
43 #undef GetProcessInformation
44 #undef int_fast8_t
45 #undef int_fast16_t
46 #undef uint_fast16_t
47
48 #else
49
50 #define list List
51 #define map Map
52 #define iterator Iterator
53 #define float_t Float_t
54 #include <Carbon/Carbon.h>
55 #include <QuickTime/Movies.h>
56 #include <QuickTime/ImageCompression.h>
57 #include <QuickTime/QuickTimeComponents.h>
58
59 #undef list
60 #undef map
61 #undef iterator
62 #undef float_t
63
64 #endif
65 /*
66 questo file gestisce il salvataggio in un .tnz e il caricamento dei setting dei
67 mov.
68 viene usato il popup fornito da quicktime, con tutti i suoi setting e i sotto
69 settings.
70 i setting sono memorizzati da quicktime in un componentInstance. Da qui, possono
71 essere convertiti in un atomContainer,
72 che e' una struttura simile alla nostra propertyGroup, ma con gli atomi
73 strutturati ad albero.
74 sono state scritte due funzioni di conversione da atomContainer a propertygroup
75 e viceversa
76 ogni atom ha un type, id, e numero figli. se numero figli=0 allora l'atomo e'una
77 foglia,
78 e quindi ha un buffer di dati di valori char.
79
80 ogni atomo viene trasformato in una stringProperty. il nome della stringProperty
81 e'
82 "type id numeroFigli"
83 se numerofigli>0, allora la stringProperty ha un valore nullo, e le prossime
84 numerofigli property contengono i figli;
85 se numerofigli==0, allora il valore della property contiene il buffer di dati,
86 convertito in stringa.
87 ecco coem viene convertito il buffer in stringa:
88 se ad esempio il buffer e' composto di 3 bytes, buf[0] = 13 buf[1]=0 buf[2]=231
89 allora la strnga valore sara' "13 0 231"
90 se ci sono piu 0 consecutivi, vengono memorizzati per salvare spazio come "z
91 count" in cui count e' il numero di 0.
92 esempio: buf[0] = 13 buf[1]=0 buf[2]=0 buf[3]=0 buf[4]=0 buf5]=231
93 allora str = "13 z 4 231"
94 */
95
96 #include "movsettings.h"
97
98 //------------------------------------------------
99
visitAtoms(const QTAtomContainer & atoms,const QTAtom & parent,TPropertyGroup & pg)100 void visitAtoms(const QTAtomContainer &atoms, const QTAtom &parent,
101 TPropertyGroup &pg) {
102 QTAtom curr = 0;
103
104 do {
105 if (QTNextChildAnyType(atoms, parent, curr, &curr) != noErr) assert(false);
106
107 if (curr == 0) break;
108 QTAtomType atomType;
109 QTAtomID id;
110
111 QTGetAtomTypeAndID(atoms, curr, &atomType, &id);
112 int sonCount = QTCountChildrenOfType(atoms, curr, 0);
113
114 char buffer[1024];
115 snprintf(buffer, sizeof(buffer), "%d %d %d",
116 (int)atomType, (int)id, sonCount);
117 string str(buffer);
118
119 if (sonCount > 0) {
120 pg.add(new TStringProperty(str, TString()));
121 visitAtoms(atoms, curr, pg);
122 }
123
124 else {
125 long size;
126 UCHAR *atomData;
127 if (QTGetAtomDataPtr(atoms, curr, &size, (char **)&atomData) != noErr)
128 assert(false);
129
130 string strapp;
131 for (int i = 0; i < size; i++) {
132 string num;
133 if (atomData[i] == 0) {
134 int count = 1;
135 while ((i + 1) < size && atomData[i + 1] == 0) i++, count++;
136 if (count > 1) {
137 num = std::to_string(count);
138 strapp = strapp + "z " + num + " ";
139 continue;
140 }
141 }
142 num = std::to_string(atomData[i]);
143
144 strapp = strapp + string(num) + " ";
145 }
146
147 // unsigned short*buffer = new unsigned short[size];
148 // buffer[size]=0;
149 // for (i=0; i<size; i++)
150 // buffer[i] = atomData[i]+1;
151
152 wstring data = ::to_wstring(strapp);
153
154 pg.add(new TStringProperty(str, data));
155 }
156 } while (curr != 0);
157 }
158
159 //------------------------------------------------
160 namespace {
compareAtoms(const QTAtomContainer & atoms1,QTAtom parent1,const QTAtomContainer & atoms2,QTAtom parent2)161 void compareAtoms(const QTAtomContainer &atoms1, QTAtom parent1,
162 const QTAtomContainer &atoms2, QTAtom parent2) {
163 QTAtom curr1 = 0, curr2 = 0;
164
165 assert(QTCountChildrenOfType(atoms1, parent1, 0) ==
166 QTCountChildrenOfType(atoms2, parent2, 0));
167
168 do {
169 if (QTNextChildAnyType(atoms1, parent1, curr1, &curr1) != noErr)
170 assert(false);
171
172 if (QTNextChildAnyType(atoms2, parent2, curr2, &curr2) != noErr)
173 assert(false);
174 assert((curr1 != 0 && curr2 != 0) || (curr1 == 0 && curr2 == 0));
175
176 if (curr1 == 0 || curr2 == 0) break;
177
178 QTAtomType atomType1, atomType2;
179 QTAtomID id1, id2;
180
181 QTGetAtomTypeAndID(atoms1, curr1, &atomType1, &id1);
182 QTGetAtomTypeAndID(atoms2, curr2, &atomType2, &id2);
183 assert(atomType1 == atomType2);
184
185 int sonCount1 = QTCountChildrenOfType(atoms1, curr1, 0);
186 int sonCount2 = QTCountChildrenOfType(atoms2, curr2, 0);
187 assert(sonCount1 == sonCount2);
188 if (sonCount1 > 0)
189 compareAtoms(atoms1, curr1, atoms2, curr2);
190 else {
191 long size1;
192 UCHAR *atomData1;
193 long size2;
194 UCHAR *atomData2;
195 if (QTGetAtomDataPtr(atoms1, curr1, &size1, (char **)&atomData1) != noErr)
196 assert(false);
197 if (QTGetAtomDataPtr(atoms2, curr2, &size2, (char **)&atomData2) != noErr)
198 assert(false);
199 assert(size1 == size2);
200 for (int i = 0; i < size1; i++) assert(atomData1[i] == atomData2[i]);
201 }
202 } while (curr1 != 0 && curr2 != 0);
203 }
204 }
205
206 //------------------------------------------------
207
fromAtomsToProperties(const QTAtomContainer & atoms,TPropertyGroup & pg)208 void fromAtomsToProperties(const QTAtomContainer &atoms, TPropertyGroup &pg) {
209 pg.clear();
210 visitAtoms(atoms, kParentAtomIsContainer, pg);
211 }
212
213 //------------------------------------------------
visitprops(TPropertyGroup & pg,int & index,QTAtomContainer & atoms,QTAtom parent)214 void visitprops(TPropertyGroup &pg, int &index, QTAtomContainer &atoms,
215 QTAtom parent) {
216 int count = pg.getPropertyCount();
217 while (index < count) {
218 TStringProperty *p = (TStringProperty *)pg.getProperty(index++);
219 string str0 = p->getName();
220 const char *buf = str0.c_str();
221 int atomType, id, sonCount;
222 sscanf(buf, "%d %d %d", &atomType, &id, &sonCount);
223 QTAtom newAtom;
224 if (sonCount == 0) {
225 wstring appow = p->getValue();
226 string appo = ::to_string(appow);
227 const char *str = appo.c_str();
228
229 vector<UCHAR> buf;
230 while (strlen(str) > 0) {
231 if (str[0] == 'z') {
232 int count = atoi(str + 1);
233 str += (count < 10) ? 4 : ((count < 100) ? 5 : 6);
234 while (count--) buf.push_back(0);
235 } else {
236 int val = atoi(str);
237 assert(val >= 0 && val < 256);
238
239 str += (val < 10) ? 2 : ((val < 100) ? 3 : 4);
240 buf.push_back(val);
241 }
242 }
243 // const unsigned short*bufs = str1.c_str();
244 // UCHAR *bufc = new UCHAR[size];
245 // for (int i=0; i<size; i++)
246 // {
247 // assert(bufs[i]<257);
248 // bufc[i] = (UCHAR)(bufs[i]-1);
249 // }
250 void *ptr = 0;
251 if (buf.size() != 0) {
252 ptr = &(buf[0]);
253 }
254 QTInsertChild(atoms, parent, (QTAtomType)atomType, (QTAtomID)id, 0,
255 buf.size(), (void *)ptr, 0);
256 } else {
257 QTInsertChild(atoms, parent, (QTAtomType)atomType, (QTAtomID)id, 0, 0, 0,
258 &newAtom);
259 visitprops(pg, index, atoms, newAtom);
260 }
261 }
262 }
263
264 //------------------------------------------------
265
fromPropertiesToAtoms(TPropertyGroup & pg,QTAtomContainer & atoms)266 void fromPropertiesToAtoms(TPropertyGroup &pg, QTAtomContainer &atoms) {
267 int index = 0;
268 visitprops(pg, index, atoms, kParentAtomIsContainer);
269 }
270
271 //------------------------------------------------
272 /*
273 #ifdef MACOSX
274
275 SCExtendedProcs gProcStruct, ptr;
276
277 static Boolean QTCmpr_FilterProc
278 (DialogPtr theDialog, EventRecord *theEvent,
279 short *theItemHit, long theRefCon)
280 {
281 #pragma unused(theItemHit, theRefCon)
282 Boolean myEventHandled = false;
283 WindowRef myEventWindow = NULL;
284 WindowRef myDialogWindow = NULL;
285
286 myDialogWindow = GetDialogWindow(theDialog);
287
288 switch (theEvent->what) {
289 case updateEvt:
290 myEventWindow = (WindowRef)theEvent->message;
291 // Change the window class
292 HIWindowChangeClass(myEventWindow,kUtilityWindowClass);
293 // Activate the window scope
294 SetWindowActivationScope(myEventWindow,kWindowActivationScopeAll);
295 // Set the brushed metal theme on the window
296 SetThemeWindowBackground(myEventWindow,kThemeBrushUtilityWindowBackgroundActive,true);
297
298 break;
299 }
300
301 return(myEventHandled);
302 }
303
304 #endif
305 */
306 //------------------------------------------------
307
openMovSettingsPopup(TPropertyGroup * props,bool macBringToFront)308 void openMovSettingsPopup(TPropertyGroup *props, bool macBringToFront) {
309 #ifdef _WIN32
310 if (InitializeQTML(0) != noErr) return;
311 #endif
312
313 ComponentInstance ci =
314 OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
315
316 QTAtomContainer atoms;
317 QTNewAtomContainer(&atoms);
318
319 fromPropertiesToAtoms(*props, atoms);
320
321 ComponentResult err;
322
323 if ((err = SCSetSettingsFromAtomContainer(ci, atoms)) != noErr) {
324 CloseComponent(ci);
325 ci = OpenDefaultComponent(StandardCompressionType,
326 StandardCompressionSubType);
327 assert(false);
328 }
329
330 QTDisposeAtomContainer(atoms);
331
332 #ifdef MACOSX
333
334 // Install an external procedure to use a callback filter on the request
335 // settings dialog
336 // On MACOSX we need to change the dialog appearance in order to pop-up in front
337 // of the
338 // toonz main window.
339 /*
340 gProcStruct.filterProc = NewSCModalFilterUPP(QTCmpr_FilterProc);
341 // I don't install any hook
342 gProcStruct.hookProc = NULL;
343 gProcStruct.customName[0] = 0;
344 // I don't use refcon
345 gProcStruct.refcon = 0;
346
347 // set the current extended procs
348 SCSetInfo(ci, scExtendedProcsType, &gProcStruct);
349 */
350 #endif
351
352 err = SCRequestSequenceSettings(ci);
353 // assert(err==noErr);
354 QTAtomContainer atomsOut;
355
356 if (SCGetSettingsAsAtomContainer(ci, &atomsOut) != noErr) assert(false);
357
358 fromAtomsToProperties(atomsOut, *props);
359
360 QTDisposeAtomContainer(atomsOut);
361 CloseComponent(ci);
362
363 // int dataSize=0, numChildren = 0, numLevels=0;
364 // retrieveData(settings, kParentAtomIsContainer, dataSize, numChildren,
365 // numLevels);
366 }
367
isQuicktimeInstalled()368 bool Tiio::isQuicktimeInstalled() {
369 #ifdef MACOSX
370 return true;
371 #else
372
373 static int ret = -1;
374 if (ret == -1) ret = (InitializeQTML(0) == noErr) ? 1 : 0;
375
376 return (ret == 1);
377
378 #endif
379 }
380
381 #else // x64
382
383 //*******************************************************************************
384 // 64-bit proxied version
385 //*******************************************************************************
386
387 // Toonz includes
388 #include "tfilepath.h"
389 #include "tstream.h"
390
391 // tipc includes
392 #include "tipc.h"
393 #include "t32bitsrv_wrap.h"
394
395 // MAC-Specific includes
396 #ifdef MACOSX
397 #include <ApplicationServices/ApplicationServices.h>
398 #endif
399
400 #include "movsettings.h"
401
402 //---------------------------------------------------------------------------
403
404 // Using 32-bit background server correspondence to achieve the same result
openMovSettingsPopup(TPropertyGroup * props,bool unused)405 void openMovSettingsPopup(TPropertyGroup *props, bool unused) {
406 QLocalSocket socket;
407 if (!tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), 3000,
408 t32bitsrv::srvCmdline(), "_main"))
409 return;
410
411 // Send the appropriate commands to the server
412 tipc::Stream stream(&socket);
413 tipc::Message msg;
414
415 // We'll communicate through temporary files.
416 stream << (msg << QString("$tmpfile_request") << QString("openMovSets"));
417 QString res(tipc::readMessage(stream, msg));
418
419 QString fp;
420 msg >> fp;
421 assert(res == "ok" && !fp.isEmpty());
422
423 TFilePath tfp(fp.toStdWString());
424 {
425 // Save the input props to the temporary file
426 TOStream os(tfp);
427 props->saveData(os);
428 }
429
430 // Invoke the settings popup
431 stream << (msg << tipc::clr << QString("$openMovSettingsPopup") << fp);
432 res =
433 tipc::readMessageNB(stream, msg, -1, QEventLoop::ExcludeUserInputEvents);
434 assert(res == "ok");
435
436 #ifdef MACOSX
437
438 // Bring this application back to front
439 ProcessSerialNumber psn = {0, kCurrentProcess};
440 SetFrontProcess(&psn);
441
442 #endif // MACOSX
443
444 props->clear();
445 {
446 // Save the input props to the temporary file
447 TIStream is(tfp);
448 props->loadData(is);
449 }
450
451 // Release the temporary file
452 stream << (msg << tipc::clr << QString("$tmpfile_release")
453 << QString("openMovSets"));
454 res = tipc::readMessage(stream, msg);
455 assert(res == "ok");
456 }
457
458 //---------------------------------------------------------------------------
459
isQuicktimeInstalled()460 bool Tiio::isQuicktimeInstalled() {
461 // NOTE: This is *NOT* the same function as IsQuickTimeInstalled(), which is
462 // implemented locally in the image lib and used there. This function here is
463 // actually NEVER USED throughout Toonz, so we're placing a dummy
464 // implementation here.
465
466 assert(false);
467 return false;
468 }
469
470 #endif // else
471