c6c412ae24bd796b229dedbf650ba1c1859a646c
[blender.git] / source / blender / quicktime / apple / quicktime_export.c
1 /**
2  * $Id$
3  *
4  * quicktime_export.c
5  *
6  * Code to create QuickTime Movies with Blender
7  *
8  * ***** BEGIN GPL LICENSE BLOCK *****
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  *
24  * The Original Code is written by Rob Haarsma (phase)
25  *
26  * Contributor(s): Stefan Gartner (sgefant)
27  *
28  * ***** END GPL LICENSE BLOCK *****
29  */
30
31 #ifdef WITH_QUICKTIME
32 #if defined(_WIN32) || defined(__APPLE__)
33
34 #include "DNA_scene_types.h"
35
36 #include "BKE_global.h"
37 #include "BKE_scene.h"
38
39 #include "BLI_blenlib.h"
40
41 #include "BLO_sys_types.h"
42
43 #include "IMB_imbuf.h"
44 #include "IMB_imbuf_types.h"
45
46 #include "MEM_guardedalloc.h"
47
48 #include "quicktime_import.h"
49 #include "quicktime_export.h"
50
51 #ifdef _WIN32
52 #include <QTML.h>
53 #include <Movies.h>
54 #include <QuickTimeComponents.h>
55 #include <TextUtils.h> 
56 #endif /* _WIN32 */
57
58 #ifdef __APPLE__
59 /* evil */
60 #ifndef __AIFF__
61 #define __AIFF__
62 #endif
63 #include <QuickTime/Movies.h>
64 #include <QuickTime/QuickTimeComponents.h>
65 #include <fcntl.h> /* open() */
66 #include <unistd.h> /* close() */
67 #include <sys/stat.h> /* file permissions */
68 #endif /* __APPLE__ */
69
70 #define kMyCreatorType  FOUR_CHAR_CODE('TVOD')
71 #define kTrackStart             0
72 #define kMediaStart             0
73
74 static void QT_StartAddVideoSamplesToMedia (const Rect *trackFrame, int rectx, int recty);
75 static void QT_DoAddVideoSamplesToMedia (int frame, int *pixels, int rectx, int recty);
76 static void QT_EndAddVideoSamplesToMedia (void);
77 static void QT_CreateMyVideoTrack (int rectx, int recty);
78 static void QT_EndCreateMyVideoTrack (void);
79 static void check_renderbutton_framerate(struct RenderData *rd);
80 static int get_qtcodec_settings(struct RenderData *rd);
81
82 typedef struct QuicktimeExport {
83
84         FSSpec          theSpec;
85         short           resRefNum;
86         Str255          qtfilename;
87
88         Media           theMedia;
89         Movie           theMovie;
90         Track           theTrack;
91
92         GWorldPtr                       theGWorld;
93         PixMapHandle            thePixMap;
94         ImageDescription        **anImageDescription;
95
96         ImBuf           *ibuf;  //imagedata for Quicktime's Gworld
97         ImBuf           *ibuf2; //copy of renderdata, to be Y-flipped
98
99 } QuicktimeExport;
100
101 typedef struct QuicktimeComponentData {
102
103         ComponentInstance       theComponent;
104         SCTemporalSettings  gTemporalSettings;
105         SCSpatialSettings   gSpatialSettings;
106         SCDataRateSettings  aDataRateSetting;
107         TimeValue                       duration;
108         long                            kVideoTimeScale;
109
110 } QuicktimeComponentData;
111
112 static struct QuicktimeExport *qtexport;
113 static struct QuicktimeComponentData *qtdata;
114
115 static int      sframe;
116
117 /* RNA functions */
118
119 static QuicktimeCodecTypeDesc qtCodecList[] = {
120         {kRawCodecType, 1, "Uncompressed"},
121         {kJPEGCodecType, 2, "JPEG"},
122         {kMotionJPEGACodecType, 3, "M-JPEG A"},
123         {kMotionJPEGBCodecType, 4, "M-JPEG B"},
124         {kDVCPALCodecType, 5, "DV PAL"},
125         {kDVCNTSCCodecType, 6, "DV/DVCPRO NTSC"},
126         {kDVCPROHD720pCodecType, 7, "DVCPRO HD 720p"},
127         {kDVCPROHD1080i50CodecType, 8, "DVCPRO HD 1080i50"},
128         {kDVCPROHD1080i60CodecType, 9, "DVCPRO HD 1080i60"},
129         {kMPEG4VisualCodecType, 10, "MPEG4"},
130         {kH263CodecType, 11, "H.263"},
131         {kH264CodecType, 12, "H.264"},
132         {0,0,NULL}};
133
134 static int qtCodecCount = 12;
135
136 int quicktime_get_num_codecs() {
137         return qtCodecCount;
138 }
139
140 QuicktimeCodecTypeDesc* quicktime_get_codecType_desc(int indexValue) {
141         if ((indexValue>=0) && (indexValue < qtCodecCount))
142                 return &qtCodecList[indexValue];
143         else
144                 return NULL;
145 }
146
147 int quicktime_rnatmpvalue_from_codectype(int codecType) {
148         int i;
149         for (i=0;i<qtCodecCount;i++) {
150                 if (qtCodecList[i].codecType == codecType)
151                         return qtCodecList[i].rnatmpvalue;
152         }
153         
154         return 0;
155 }
156
157 int quicktime_codecType_from_rnatmpvalue(int rnatmpvalue) {
158         int i;
159         for (i=0;i<qtCodecCount;i++) {
160                 if (qtCodecList[i].rnatmpvalue == rnatmpvalue)
161                         return qtCodecList[i].codecType;
162         }
163         
164         return 0;       
165 }
166
167
168
169 static void CheckError(OSErr err, char *msg)
170 {
171         if(err != noErr) printf("%s: %d\n", msg, err);
172 }
173
174
175 static OSErr QT_SaveCodecSettingsToScene(RenderData *rd)
176 {       
177         QTAtomContainer         myContainer = NULL;
178         ComponentResult         myErr = noErr;
179         Ptr                                     myPtr;
180         long                            mySize = 0;
181
182         CodecInfo                       ci;
183
184         QuicktimeCodecData *qcd = rd->qtcodecdata;
185         
186         // check if current scene already has qtcodec settings, and clear them
187         if (qcd) {
188                 free_qtcodecdata(qcd);
189         } else {
190                 qcd = rd->qtcodecdata = MEM_callocN(sizeof(QuicktimeCodecData), "QuicktimeCodecData");
191         }
192
193         // obtain all current codec settings
194         SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
195         SCSetInfo(qtdata->theComponent, scSpatialSettingsType,  &qtdata->gSpatialSettings);
196         SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
197
198         // retreive codecdata from quicktime in a atomcontainer
199         myErr = SCGetSettingsAsAtomContainer(qtdata->theComponent,  &myContainer);
200         if (myErr != noErr) {
201                 printf("Quicktime: SCGetSettingsAsAtomContainer failed\n"); 
202                 goto bail;
203         }
204
205         // get the size of the atomcontainer
206         mySize = GetHandleSize((Handle)myContainer);
207
208         // lock and convert the atomcontainer to a *valid* pointer
209         QTLockContainer(myContainer);
210         myPtr = *(Handle)myContainer;
211
212         // copy the Quicktime data into the blender qtcodecdata struct
213         if (myPtr) {
214                 qcd->cdParms = MEM_mallocN(mySize, "qt.cdParms");
215                 memcpy(qcd->cdParms, myPtr, mySize);
216                 qcd->cdSize = mySize;
217
218                 GetCodecInfo (&ci, qtdata->gSpatialSettings.codecType, 0);
219         } else {
220                 printf("Quicktime: QT_SaveCodecSettingsToScene failed\n"); 
221         }
222
223         QTUnlockContainer(myContainer);
224
225 bail:
226         if (myContainer != NULL)
227                 QTDisposeAtomContainer(myContainer);
228                 
229         return((OSErr)myErr);
230 }
231
232
233 static OSErr QT_GetCodecSettingsFromScene(RenderData *rd)
234 {       
235         Handle                          myHandle = NULL;
236         ComponentResult         myErr = noErr;
237
238         QuicktimeCodecData *qcd = rd->qtcodecdata;
239
240         // if there is codecdata in the blendfile, convert it to a Quicktime handle 
241         if (qcd) {
242                 myHandle = NewHandle(qcd->cdSize);
243                 PtrToHand( qcd->cdParms, &myHandle, qcd->cdSize);
244         }
245                 
246         // restore codecsettings to the quicktime component
247         if(qcd->cdParms && qcd->cdSize) {
248                 myErr = SCSetSettingsFromAtomContainer((GraphicsExportComponent)qtdata->theComponent, (QTAtomContainer)myHandle);
249                 if (myErr != noErr) {
250                         printf("Quicktime: SCSetSettingsFromAtomContainer failed\n"); 
251                         goto bail;
252                 }
253
254                 // update runtime codecsettings for use with the codec dialog
255                 SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
256                 SCGetInfo(qtdata->theComponent, scSpatialSettingsType,  &qtdata->gSpatialSettings);
257                 SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
258
259
260                 //Fill the render QuicktimeCodecSettigns struct
261                 rd->qtcodecsettings.codecTemporalQuality = (qtdata->gTemporalSettings.temporalQuality * 100) / codecLosslessQuality;
262                 //Do not override scene frame rate (qtdata->gTemporalSettings.framerate)
263                 rd->qtcodecsettings.keyFrameRate = qtdata->gTemporalSettings.keyFrameRate;
264                 
265                 rd->qtcodecsettings.codecType = qtdata->gSpatialSettings.codecType;
266                 rd->qtcodecsettings.codec = (int)qtdata->gSpatialSettings.codec;
267                 rd->qtcodecsettings.colorDepth = qtdata->gSpatialSettings.depth;
268                 rd->qtcodecsettings.codecSpatialQuality = (qtdata->gSpatialSettings.spatialQuality * 100) / codecLosslessQuality;
269                 
270                 rd->qtcodecsettings.bitRate = qtdata->aDataRateSetting.dataRate;
271                 rd->qtcodecsettings.minSpatialQuality = (qtdata->aDataRateSetting.minSpatialQuality * 100) / codecLosslessQuality;
272                 rd->qtcodecsettings.minTemporalQuality = (qtdata->aDataRateSetting.minTemporalQuality * 100) / codecLosslessQuality;
273                 //Frame duration is already known (qtdata->aDataRateSetting.frameDuration)
274                 
275         } else {
276                 printf("Quicktime: QT_GetCodecSettingsFromScene failed\n"); 
277         }
278 bail:
279         if (myHandle != NULL)
280                 DisposeHandle(myHandle);
281                 
282         return((OSErr)myErr);
283 }
284
285
286 static OSErr QT_AddUserDataTextToMovie (Movie theMovie, char *theText, OSType theType)
287 {
288         UserData                                        myUserData = NULL;
289         Handle                                          myHandle = NULL;
290         long                                            myLength = strlen(theText);
291         OSErr                                           myErr = noErr;
292
293         // get the movie's user data list
294         myUserData = GetMovieUserData(theMovie);
295         if (myUserData == NULL)
296                 return(paramErr);
297         
298         // copy the specified text into a new handle
299         myHandle = NewHandleClear(myLength);
300         if (myHandle == NULL)
301                 return(MemError());
302
303         BlockMoveData(theText, *myHandle, myLength);
304
305         // add the data to the movie's user data
306         myErr = AddUserDataText(myUserData, myHandle, theType, 1, (short)GetScriptManagerVariable(smRegionCode));
307
308         // clean up
309         DisposeHandle(myHandle);
310         return(myErr);
311 }
312
313
314 static void QT_CreateMyVideoTrack(int rectx, int recty)
315 {
316         OSErr err = noErr;
317         Rect trackFrame;
318 //      MatrixRecord myMatrix;
319
320         trackFrame.top = 0;
321         trackFrame.left = 0;
322         trackFrame.bottom = recty;
323         trackFrame.right = rectx;
324         
325         qtexport->theTrack = NewMovieTrack (qtexport->theMovie, 
326                                                         FixRatio(trackFrame.right,1),
327                                                         FixRatio(trackFrame.bottom,1), 
328                                                         0);
329         CheckError( GetMoviesError(), "NewMovieTrack error" );
330
331 //      SetIdentityMatrix(&myMatrix);
332 //      ScaleMatrix(&myMatrix, fixed1, Long2Fix(-1), 0, 0);
333 //      TranslateMatrix(&myMatrix, 0, Long2Fix(trackFrame.bottom));
334 //      SetMovieMatrix(qtexport->theMovie, &myMatrix);
335
336         qtexport->theMedia = NewTrackMedia (qtexport->theTrack,
337                                                         VideoMediaType,
338                                                         qtdata->kVideoTimeScale,
339                                                         nil,
340                                                         0);
341         CheckError( GetMoviesError(), "NewTrackMedia error" );
342
343         err = BeginMediaEdits (qtexport->theMedia);
344         CheckError( err, "BeginMediaEdits error" );
345
346         QT_StartAddVideoSamplesToMedia (&trackFrame, rectx, recty);
347
348
349
350 static void QT_EndCreateMyVideoTrack(void)
351 {
352         OSErr err = noErr;
353
354         QT_EndAddVideoSamplesToMedia ();
355
356         err = EndMediaEdits (qtexport->theMedia);
357         CheckError( err, "EndMediaEdits error" );
358
359         err = InsertMediaIntoTrack (qtexport->theTrack,
360                                                                 kTrackStart,/* track start time */
361                                                                 kMediaStart,/* media start time */
362                                                                 GetMediaDuration (qtexport->theMedia),
363                                                                 fixed1);
364         CheckError( err, "InsertMediaIntoTrack error" );
365
366
367
368 static void QT_StartAddVideoSamplesToMedia (const Rect *trackFrame, int rectx, int recty)
369 {
370         SCTemporalSettings gTemporalSettings;
371         OSErr err = noErr;
372
373         qtexport->ibuf = IMB_allocImBuf (rectx, recty, 32, IB_rect, 0);
374         qtexport->ibuf2 = IMB_allocImBuf (rectx, recty, 32, IB_rect, 0);
375
376         err = NewGWorldFromPtr( &qtexport->theGWorld,
377                                                         k32ARGBPixelFormat,
378                                                         trackFrame,
379                                                         NULL, NULL, 0,
380                                                         (Ptr)qtexport->ibuf->rect,
381                                                         rectx * 4 );
382         CheckError (err, "NewGWorldFromPtr error");
383
384         qtexport->thePixMap = GetGWorldPixMap(qtexport->theGWorld);
385         LockPixels(qtexport->thePixMap);
386
387         SCDefaultPixMapSettings (qtdata->theComponent, qtexport->thePixMap, true);
388
389         // workaround for crash with H.264, which requires an upgrade to
390         // the new callback based api for proper encoding, but that's not
391         // really compatible with rendering out frames sequentially
392         gTemporalSettings = qtdata->gTemporalSettings;
393         if(qtdata->gSpatialSettings.codecType == kH264CodecType) {
394                 if(gTemporalSettings.temporalQuality != codecMinQuality) {
395                         fprintf(stderr, "Only minimum quality compression supported for QuickTime H.264.\n");
396                         gTemporalSettings.temporalQuality = codecMinQuality;
397                 }
398         }
399
400         SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &gTemporalSettings);
401         SCSetInfo(qtdata->theComponent, scSpatialSettingsType,  &qtdata->gSpatialSettings);
402         SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
403
404         err = SCCompressSequenceBegin(qtdata->theComponent, qtexport->thePixMap, NULL, &qtexport->anImageDescription); 
405         CheckError (err, "SCCompressSequenceBegin error" );
406 }
407
408
409 static void QT_DoAddVideoSamplesToMedia (int frame, int *pixels, int rectx, int recty)
410 {
411         OSErr   err = noErr;
412         Rect    imageRect;
413
414         int             index;
415         int             boxsize;
416         unsigned char *from, *to;
417
418         short   syncFlag;
419         long    dataSize;
420         Handle  compressedData;
421         Ptr             myPtr;
422
423
424         //copy and flip renderdata
425         memcpy(qtexport->ibuf2->rect, pixels, 4*rectx*recty);
426         IMB_flipy(qtexport->ibuf2);
427
428         //get pointers to parse bitmapdata
429         myPtr = GetPixBaseAddr(qtexport->thePixMap);
430         imageRect = (**qtexport->thePixMap).bounds;
431
432         from = (unsigned char *) qtexport->ibuf2->rect;
433         to = (unsigned char *) myPtr;
434
435         //parse RGBA bitmap into Quicktime's ARGB GWorld
436         boxsize = rectx * recty;
437         for( index = 0; index < boxsize; index++) {
438                 to[0] = from[3];
439                 to[1] = from[0];
440                 to[2] = from[1];
441                 to[3] = from[2];
442                 to +=4, from += 4;
443         }
444
445         err = SCCompressSequenceFrame(qtdata->theComponent,
446                 qtexport->thePixMap,
447                 &imageRect,
448                 &compressedData,
449                 &dataSize,
450                 &syncFlag);
451         CheckError(err, "SCCompressSequenceFrame error");
452
453         err = AddMediaSample(qtexport->theMedia,
454                 compressedData,
455                 0,
456                 dataSize,
457                 qtdata->duration,
458                 (SampleDescriptionHandle)qtexport->anImageDescription,
459                 1,
460                 syncFlag,
461                 NULL);
462         CheckError(err, "AddMediaSample error");
463
464         printf ("added frame %3d (frame %3d in movie): ", frame, frame-sframe);
465 }
466
467
468 static void QT_EndAddVideoSamplesToMedia (void)
469 {
470         SCCompressSequenceEnd(qtdata->theComponent);
471
472         UnlockPixels(qtexport->thePixMap);
473         if (qtexport->theGWorld)
474                 DisposeGWorld (qtexport->theGWorld);
475
476         if (qtexport->ibuf)
477                 IMB_freeImBuf(qtexport->ibuf);
478
479         if (qtexport->ibuf2)
480                 IMB_freeImBuf(qtexport->ibuf2);
481
482
483
484 void makeqtstring (RenderData *rd, char *string) {
485         char txt[64];
486
487         if (string==0) return;
488
489         strcpy(string, rd->pic);
490         BLI_convertstringcode(string, G.sce);
491
492         BLI_make_existing_file(string);
493
494         if (BLI_strcasecmp(string + strlen(string) - 4, ".mov")) {
495                 sprintf(txt, "%04d_%04d.mov", (rd->sfra) , (rd->efra) );
496                 strcat(string, txt);
497         }
498 }
499
500
501 void start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty) {
502         OSErr err = noErr;
503
504         char name[2048];
505         char theFullPath[255];
506
507 #ifdef __APPLE__
508         int             myFile;
509         FSRef   myRef;
510 #else
511         char    *qtname;
512 #endif
513
514         if(qtexport == NULL) qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport");
515
516         if(qtdata) {
517                 if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
518                 free_qtcomponentdata();
519         }
520
521         qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeCodecDataExt");
522
523         if(rd->qtcodecdata == NULL || rd->qtcodecdata->cdParms == NULL) {
524                 get_qtcodec_settings(rd);
525         } else {
526                 qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
527
528                 QT_GetCodecSettingsFromScene(rd);
529                 check_renderbutton_framerate(rd);
530         }
531         
532         if (G.afbreek != 1) {
533                 sframe = (rd->sfra);
534
535                 makeqtstring(rd, name);
536
537 #ifdef __APPLE__
538                 EnterMoviesOnThread(0);
539                 sprintf(theFullPath, "%s", name);
540
541                 /* hack: create an empty file to make FSPathMakeRef() happy */
542                 myFile = open(theFullPath, O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRUSR|S_IWUSR);
543                 if (myFile < 0) {
544                         printf("error while creating file!\n");
545                         /* do something? */
546                 }
547                 close(myFile);
548                 err = FSPathMakeRef((const UInt8 *)theFullPath, &myRef, 0);
549                 CheckError(err, "FsPathMakeRef error");
550                 err = FSGetCatalogInfo(&myRef, kFSCatInfoNone, NULL, NULL, &qtexport->theSpec, NULL);
551                 CheckError(err, "FsGetCatalogInfoRef error");
552 #endif
553 #ifdef _WIN32
554                 qtname = get_valid_qtname(name);
555                 sprintf(theFullPath, "%s", qtname);
556                 strcpy(name, qtname);
557                 MEM_freeN(qtname);
558                 
559                 CopyCStringToPascal(theFullPath, qtexport->qtfilename);
560                 err = FSMakeFSSpec(0, 0L, qtexport->qtfilename, &qtexport->theSpec);
561 #endif
562
563                 err = CreateMovieFile (&qtexport->theSpec, 
564                                                         kMyCreatorType,
565                                                         smCurrentScript, 
566                                                         createMovieFileDeleteCurFile | createMovieFileDontCreateResFile,
567                                                         &qtexport->resRefNum, 
568                                                         &qtexport->theMovie );
569                 CheckError(err, "CreateMovieFile error");
570
571                 if(err != noErr) {
572                         G.afbreek = 1;
573 // XXX                  error("Unable to create Quicktime movie: %s", name);
574 #ifdef __APPLE__
575                         ExitMoviesOnThread();
576 #endif
577                 } else {
578                         printf("Created QuickTime movie: %s\n", name);
579
580                         QT_CreateMyVideoTrack(rectx, recty);
581                 }
582         }
583 }
584
585
586 void append_qt(struct RenderData *rd, int frame, int *pixels, int rectx, int recty) {
587         QT_DoAddVideoSamplesToMedia(frame, pixels, rectx, recty);
588 }
589
590
591 void end_qt(void) {
592         OSErr err = noErr;
593         short resId = movieInDataForkResID;
594
595         if(qtexport->theMovie) {
596                 QT_EndCreateMyVideoTrack();
597
598                 err = AddMovieResource (qtexport->theMovie, qtexport->resRefNum, &resId, qtexport->qtfilename);
599                 CheckError(err, "AddMovieResource error");
600
601                 err = QT_AddUserDataTextToMovie(qtexport->theMovie, "Made with Blender", kUserDataTextInformation);
602                 CheckError(err, "AddUserDataTextToMovie error");
603
604                 err = UpdateMovieResource(qtexport->theMovie, qtexport->resRefNum, resId, qtexport->qtfilename);
605                 CheckError(err, "UpdateMovieResource error");
606
607                 if(qtexport->resRefNum) CloseMovieFile(qtexport->resRefNum);
608
609                 DisposeMovie(qtexport->theMovie);
610
611                 printf("Finished QuickTime movie.\n");
612         }
613
614         ExitMoviesOnThread();
615         
616         if(qtexport) {
617                 MEM_freeN(qtexport);
618                 qtexport = NULL;
619         }
620 }
621
622
623 void free_qtcomponentdata(void) {
624         if(qtdata) {
625                 if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
626                 MEM_freeN(qtdata);
627                 qtdata = NULL;
628         }
629 }
630
631
632 static void check_renderbutton_framerate(RenderData *rd) 
633 {
634         // to keep float framerates consistent between the codec dialog and frs/sec button.
635         OSErr   err;    
636
637         err = SCGetInfo(qtdata->theComponent, scTemporalSettingsType,   &qtdata->gTemporalSettings);
638         CheckError(err, "SCGetInfo fr error");
639
640         if( (rd->frs_sec == 24 || rd->frs_sec == 30 || rd->frs_sec == 60) &&
641                 (qtdata->gTemporalSettings.frameRate == 1571553 ||
642                  qtdata->gTemporalSettings.frameRate == 1964113 ||
643                  qtdata->gTemporalSettings.frameRate == 3928227)) {;} 
644         else {
645                 if (rd->frs_sec_base > 0)
646                         qtdata->gTemporalSettings.frameRate = 
647                         ((float)(rd->frs_sec << 16) / rd->frs_sec_base) ;
648         }
649         
650         err = SCSetInfo(qtdata->theComponent, scTemporalSettingsType,   &qtdata->gTemporalSettings);
651         CheckError( err, "SCSetInfo error" );
652
653         if(qtdata->gTemporalSettings.frameRate == 1571553) {                    // 23.98 fps
654                 qtdata->kVideoTimeScale = 24000;
655                 qtdata->duration = 1001;
656         } else if (qtdata->gTemporalSettings.frameRate == 1964113) {    // 29.97 fps
657                 qtdata->kVideoTimeScale = 30000;
658                 qtdata->duration = 1001;
659         } else if (qtdata->gTemporalSettings.frameRate == 3928227) {    // 59.94 fps
660                 qtdata->kVideoTimeScale = 60000;
661                 qtdata->duration = 1001;
662         } else {
663                 qtdata->kVideoTimeScale = (qtdata->gTemporalSettings.frameRate >> 16) * 100;
664                 qtdata->duration = 100;
665         }
666 }
667
668 void quicktime_verify_image_type(RenderData *rd)
669 {
670         if (rd->imtype == R_QUICKTIME) {
671                 if ((rd->qtcodecsettings.codecType== 0) ||
672                         (rd->qtcodecsettings.codecSpatialQuality <0) ||
673                         (rd->qtcodecsettings.codecSpatialQuality > 100)) {
674                         
675                         rd->qtcodecsettings.codecType = kJPEGCodecType;
676                         rd->qtcodecsettings.codec = (int)anyCodec;
677                         rd->qtcodecsettings.codecSpatialQuality = (codecHighQuality*100)/codecLosslessQuality;
678                         rd->qtcodecsettings.codecTemporalQuality = (codecHighQuality*100)/codecLosslessQuality;
679                         rd->qtcodecsettings.keyFrameRate = 25;
680                         rd->qtcodecsettings.bitRate = 5000000; //5 Mbps
681                 }
682         }
683 }
684
685 int get_qtcodec_settings(RenderData *rd) 
686 {
687         OSErr err = noErr;
688                 // erase any existing codecsetting
689         if(qtdata) {
690                 if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
691                 free_qtcomponentdata();
692         }
693
694         // allocate new
695         qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeComponentData");
696         qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
697
698         // get previous selected codecsetting, from qtatom or detailed settings
699         if(rd->qtcodecdata && rd->qtcodecdata->cdParms) {
700                 QT_GetCodecSettingsFromScene(rd);
701         } else {
702                 SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
703                 SCGetInfo(qtdata->theComponent, scSpatialSettingsType,  &qtdata->gSpatialSettings);
704                 SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
705
706                 qtdata->gSpatialSettings.codecType = rd->qtcodecsettings.codecType;
707                 qtdata->gSpatialSettings.codec = (CodecComponent)rd->qtcodecsettings.codec;      
708                 qtdata->gSpatialSettings.spatialQuality = (rd->qtcodecsettings.codecSpatialQuality * codecLosslessQuality) /100;
709                 qtdata->gTemporalSettings.temporalQuality = (rd->qtcodecsettings.codecTemporalQuality * codecLosslessQuality) /100;
710                 qtdata->gTemporalSettings.keyFrameRate = rd->qtcodecsettings.keyFrameRate;   
711                 qtdata->aDataRateSetting.dataRate = rd->qtcodecsettings.bitRate;
712                 qtdata->gSpatialSettings.depth = rd->qtcodecsettings.colorDepth;
713                 qtdata->aDataRateSetting.minSpatialQuality = (rd->qtcodecsettings.minSpatialQuality * codecLosslessQuality) / 100;
714                 qtdata->aDataRateSetting.minTemporalQuality = (rd->qtcodecsettings.minTemporalQuality * codecLosslessQuality) / 100;
715                 
716                 qtdata->aDataRateSetting.frameDuration = rd->frs_sec;
717                 SetMovieTimeScale(qtexport->theMovie, rd->frs_sec_base*1000);
718                 
719                 
720                 err = SCSetInfo(qtdata->theComponent, scTemporalSettingsType,   &qtdata->gTemporalSettings);
721                 CheckError(err, "SCSetInfo1 error");
722                 err = SCSetInfo(qtdata->theComponent, scSpatialSettingsType,    &qtdata->gSpatialSettings);
723                 CheckError(err, "SCSetInfo2 error");
724                 err = SCSetInfo(qtdata->theComponent, scDataRateSettingsType,   &qtdata->aDataRateSetting);
725                 CheckError(err, "SCSetInfo3 error");
726         }
727
728         check_renderbutton_framerate(rd);
729         
730         return err;
731 }
732
733 int request_qtcodec_settings(RenderData *rd)
734 {
735         OSErr   err = noErr;
736
737                 // put up the dialog box - it needs to be called from the main thread
738         err = SCRequestSequenceSettings(qtdata->theComponent);
739  
740         if (err == scUserCancelled) {
741                 return 0;
742         }
743
744                 // update runtime codecsettings for use with the codec dialog
745         SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
746         SCGetInfo(qtdata->theComponent, scSpatialSettingsType,  &qtdata->gSpatialSettings);
747         SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
748         
749         
750                 //Fill the render QuicktimeCodecSettings struct
751         rd->qtcodecsettings.codecTemporalQuality = (qtdata->gTemporalSettings.temporalQuality * 100) / codecLosslessQuality;
752                 //Do not override scene frame rate (qtdata->gTemporalSettings.framerate)
753         rd->qtcodecsettings.keyFrameRate = qtdata->gTemporalSettings.keyFrameRate;
754         
755         rd->qtcodecsettings.codecType = qtdata->gSpatialSettings.codecType;
756         rd->qtcodecsettings.codec = (int)qtdata->gSpatialSettings.codec;
757         rd->qtcodecsettings.colorDepth = qtdata->gSpatialSettings.depth;
758         rd->qtcodecsettings.codecSpatialQuality = (qtdata->gSpatialSettings.spatialQuality * 100) / codecLosslessQuality;
759         
760         rd->qtcodecsettings.bitRate = qtdata->aDataRateSetting.dataRate;
761         rd->qtcodecsettings.minSpatialQuality = (qtdata->aDataRateSetting.minSpatialQuality * 100) / codecLosslessQuality;
762         rd->qtcodecsettings.minTemporalQuality = (qtdata->aDataRateSetting.minTemporalQuality * 100) / codecLosslessQuality;
763                 //Frame duration is already known (qtdata->aDataRateSetting.frameDuration)
764         
765         QT_SaveCodecSettingsToScene(rd);
766
767         // framerate jugglin'
768         if(qtdata->gTemporalSettings.frameRate == 1571553) {                    // 23.98 fps
769                 qtdata->kVideoTimeScale = 24000;
770                 qtdata->duration = 1001;
771
772                 rd->frs_sec = 24;
773                 rd->frs_sec_base = 1.001;
774         } else if (qtdata->gTemporalSettings.frameRate == 1964113) {    // 29.97 fps
775                 qtdata->kVideoTimeScale = 30000;
776                 qtdata->duration = 1001;
777
778                 rd->frs_sec = 30;
779                 rd->frs_sec_base = 1.001;
780         } else if (qtdata->gTemporalSettings.frameRate == 3928227) {    // 59.94 fps
781                 qtdata->kVideoTimeScale = 60000;
782                 qtdata->duration = 1001;
783
784                 rd->frs_sec = 60;
785                 rd->frs_sec_base = 1.001;
786         } else {
787                 double fps = qtdata->gTemporalSettings.frameRate;
788
789                 qtdata->kVideoTimeScale = 60000;
790                 qtdata->duration = qtdata->kVideoTimeScale / (qtdata->gTemporalSettings.frameRate / 65536);
791
792                 if ((qtdata->gTemporalSettings.frameRate & 0xffff) == 0) {
793                         rd->frs_sec = fps / 65536;
794                         rd->frs_sec_base = 1.0;
795                 } else {
796                         /* we do our very best... */
797                         rd->frs_sec = fps  / 65536;
798                         rd->frs_sec_base = 1.0;
799                 }
800         }
801
802         return 1;
803 }
804
805 #endif /* _WIN32 || __APPLE__ */
806 #endif /* WITH_QUICKTIME */
807