a49a9a2fdc81a81e927853705ca76fbfc3a6cca7
[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 #include "BIF_toolbox.h"        /* error() */
41
42 #include "BLO_sys_types.h"
43
44 #include "IMB_imbuf.h"
45 #include "IMB_imbuf_types.h"
46
47 #include "MEM_guardedalloc.h"
48
49 #include "quicktime_import.h"
50 #include "quicktime_export.h"
51
52 #ifdef _WIN32
53 #include <QTML.h>
54 #include <Movies.h>
55 #include <QuickTimeComponents.h>
56 #include <TextUtils.h> 
57 #endif /* _WIN32 */
58
59 #ifdef __APPLE__
60 /* evil */
61 #ifndef __AIFF__
62 #define __AIFF__
63 #endif
64 #include <QuickTime/Movies.h>
65 #include <QuickTime/QuickTimeComponents.h>
66 #include <fcntl.h> /* open() */
67 #include <unistd.h> /* close() */
68 #include <sys/stat.h> /* file permissions */
69 #endif /* __APPLE__ */
70
71 #define kMyCreatorType  FOUR_CHAR_CODE('TVOD')
72 #define kTrackStart             0
73 #define kMediaStart             0
74
75 static void QT_StartAddVideoSamplesToMedia (const Rect *trackFrame, int rectx, int recty);
76 static void QT_DoAddVideoSamplesToMedia (int frame, int *pixels, int rectx, int recty);
77 static void QT_EndAddVideoSamplesToMedia (void);
78 static void QT_CreateMyVideoTrack (int rectx, int recty);
79 static void QT_EndCreateMyVideoTrack (void);
80 static void check_renderbutton_framerate(void);
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
118 static void CheckError(OSErr err, char *msg)
119 {
120         if(err != noErr) printf("%s: %d\n", msg, err);
121 }
122
123
124 static OSErr QT_SaveCodecSettingsToScene(void)
125 {       
126         QTAtomContainer         myContainer = NULL;
127         ComponentResult         myErr = noErr;
128         Ptr                                     myPtr;
129         long                            mySize = 0;
130
131         CodecInfo                       ci;
132         char str[255];
133
134         QuicktimeCodecData *qcd = G.scene->r.qtcodecdata;
135
136         // check if current scene already has qtcodec settings, and clear them
137         if (qcd) {
138                 free_qtcodecdata(qcd);
139         } else {
140                 qcd = G.scene->r.qtcodecdata = MEM_callocN(sizeof(QuicktimeCodecData), "QuicktimeCodecData");
141         }
142
143         // obtain all current codec settings
144         SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
145         SCSetInfo(qtdata->theComponent, scSpatialSettingsType,  &qtdata->gSpatialSettings);
146         SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
147
148         // retreive codecdata from quicktime in a atomcontainer
149         myErr = SCGetSettingsAsAtomContainer(qtdata->theComponent,  &myContainer);
150         if (myErr != noErr) {
151                 printf("Quicktime: SCGetSettingsAsAtomContainer failed\n"); 
152                 goto bail;
153         }
154
155         // get the size of the atomcontainer
156         mySize = GetHandleSize((Handle)myContainer);
157
158         // lock and convert the atomcontainer to a *valid* pointer
159         QTLockContainer(myContainer);
160         myPtr = *(Handle)myContainer;
161
162         // copy the Quicktime data into the blender qtcodecdata struct
163         if (myPtr) {
164                 qcd->cdParms = MEM_mallocN(mySize, "qt.cdParms");
165                 memcpy(qcd->cdParms, myPtr, mySize);
166                 qcd->cdSize = mySize;
167
168                 GetCodecInfo (&ci, qtdata->gSpatialSettings.codecType, 0);
169                 CopyPascalStringToC(ci.typeName, str);
170                 sprintf(qcd->qtcodecname, "Codec: %s", str);
171         } else {
172                 printf("Quicktime: QT_SaveCodecSettingsToScene failed\n"); 
173         }
174
175         QTUnlockContainer(myContainer);
176
177 bail:
178         if (myContainer != NULL)
179                 QTDisposeAtomContainer(myContainer);
180                 
181         return((OSErr)myErr);
182 }
183
184
185 static OSErr QT_GetCodecSettingsFromScene(void)
186 {       
187         Handle                          myHandle = NULL;
188         ComponentResult         myErr = noErr;
189 //      CodecInfo ci;
190 //      char str[255];
191
192         QuicktimeCodecData *qcd = G.scene->r.qtcodecdata;
193
194         // if there is codecdata in the blendfile, convert it to a Quicktime handle 
195         if (qcd) {
196                 myHandle = NewHandle(qcd->cdSize);
197                 PtrToHand( qcd->cdParms, &myHandle, qcd->cdSize);
198         }
199                 
200         // restore codecsettings to the quicktime component
201         if(qcd->cdParms && qcd->cdSize) {
202                 myErr = SCSetSettingsFromAtomContainer((GraphicsExportComponent)qtdata->theComponent, (QTAtomContainer)myHandle);
203                 if (myErr != noErr) {
204                         printf("Quicktime: SCSetSettingsFromAtomContainer failed\n"); 
205                         goto bail;
206                 }
207
208                 // update runtime codecsettings for use with the codec dialog
209                 SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
210                 SCGetInfo(qtdata->theComponent, scSpatialSettingsType,  &qtdata->gSpatialSettings);
211                 SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
212
213 //              GetCodecInfo (&ci, qtdata->gSpatialSettings.codecType, 0);
214 //              CopyPascalStringToC(ci.typeName, str);
215 //              printf("restored Codec: %s\n", str);
216         } else {
217                 printf("Quicktime: QT_GetCodecSettingsFromScene failed\n"); 
218         }
219 bail:
220         if (myHandle != NULL)
221                 DisposeHandle(myHandle);
222                 
223         return((OSErr)myErr);
224 }
225
226
227 static OSErr QT_AddUserDataTextToMovie (Movie theMovie, char *theText, OSType theType)
228 {
229         UserData                                        myUserData = NULL;
230         Handle                                          myHandle = NULL;
231         long                                            myLength = strlen(theText);
232         OSErr                                           myErr = noErr;
233
234         // get the movie's user data list
235         myUserData = GetMovieUserData(theMovie);
236         if (myUserData == NULL)
237                 return(paramErr);
238         
239         // copy the specified text into a new handle
240         myHandle = NewHandleClear(myLength);
241         if (myHandle == NULL)
242                 return(MemError());
243
244         BlockMoveData(theText, *myHandle, myLength);
245
246         // add the data to the movie's user data
247         myErr = AddUserDataText(myUserData, myHandle, theType, 1, (short)GetScriptManagerVariable(smRegionCode));
248
249         // clean up
250         DisposeHandle(myHandle);
251         return(myErr);
252 }
253
254
255 static void QT_CreateMyVideoTrack(int rectx, int recty)
256 {
257         OSErr err = noErr;
258         Rect trackFrame;
259 //      MatrixRecord myMatrix;
260
261         trackFrame.top = 0;
262         trackFrame.left = 0;
263         trackFrame.bottom = recty;
264         trackFrame.right = rectx;
265         
266         qtexport->theTrack = NewMovieTrack (qtexport->theMovie, 
267                                                         FixRatio(trackFrame.right,1),
268                                                         FixRatio(trackFrame.bottom,1), 
269                                                         0);
270         CheckError( GetMoviesError(), "NewMovieTrack error" );
271
272 //      SetIdentityMatrix(&myMatrix);
273 //      ScaleMatrix(&myMatrix, fixed1, Long2Fix(-1), 0, 0);
274 //      TranslateMatrix(&myMatrix, 0, Long2Fix(trackFrame.bottom));
275 //      SetMovieMatrix(qtexport->theMovie, &myMatrix);
276
277         qtexport->theMedia = NewTrackMedia (qtexport->theTrack,
278                                                         VideoMediaType,
279                                                         qtdata->kVideoTimeScale,
280                                                         nil,
281                                                         0);
282         CheckError( GetMoviesError(), "NewTrackMedia error" );
283
284         err = BeginMediaEdits (qtexport->theMedia);
285         CheckError( err, "BeginMediaEdits error" );
286
287         QT_StartAddVideoSamplesToMedia (&trackFrame, rectx, recty);
288
289
290
291 static void QT_EndCreateMyVideoTrack(void)
292 {
293         OSErr err = noErr;
294
295         QT_EndAddVideoSamplesToMedia ();
296
297         err = EndMediaEdits (qtexport->theMedia);
298         CheckError( err, "EndMediaEdits error" );
299
300         err = InsertMediaIntoTrack (qtexport->theTrack,
301                                                                 kTrackStart,/* track start time */
302                                                                 kMediaStart,/* media start time */
303                                                                 GetMediaDuration (qtexport->theMedia),
304                                                                 fixed1);
305         CheckError( err, "InsertMediaIntoTrack error" );
306
307
308
309 static void QT_StartAddVideoSamplesToMedia (const Rect *trackFrame, int rectx, int recty)
310 {
311         SCTemporalSettings gTemporalSettings;
312         OSErr err = noErr;
313
314         qtexport->ibuf = IMB_allocImBuf (rectx, recty, 32, IB_rect, 0);
315         qtexport->ibuf2 = IMB_allocImBuf (rectx, recty, 32, IB_rect, 0);
316
317         err = NewGWorldFromPtr( &qtexport->theGWorld,
318                                                         k32ARGBPixelFormat,
319                                                         trackFrame,
320                                                         NULL, NULL, 0,
321                                                         (unsigned char *)qtexport->ibuf->rect,
322                                                         rectx * 4 );
323         CheckError (err, "NewGWorldFromPtr error");
324
325         qtexport->thePixMap = GetGWorldPixMap(qtexport->theGWorld);
326         LockPixels(qtexport->thePixMap);
327
328         SCDefaultPixMapSettings (qtdata->theComponent, qtexport->thePixMap, true);
329
330         // workaround for crash with H.264, which requires an upgrade to
331         // the new callback based api for proper encoding, but that's not
332         // really compatible with rendering out frames sequentially
333         gTemporalSettings = qtdata->gTemporalSettings;
334         if(qtdata->gSpatialSettings.codecType == kH264CodecType) {
335                 if(gTemporalSettings.temporalQuality != codecMinQuality) {
336                         fprintf(stderr, "Only minimum quality compression supported for QuickTime H.264.\n");
337                         gTemporalSettings.temporalQuality = codecMinQuality;
338                 }
339         }
340
341         SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &gTemporalSettings);
342         SCSetInfo(qtdata->theComponent, scSpatialSettingsType,  &qtdata->gSpatialSettings);
343         SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
344
345         err = SCCompressSequenceBegin(qtdata->theComponent, qtexport->thePixMap, NULL, &qtexport->anImageDescription); 
346         CheckError (err, "SCCompressSequenceBegin error" );
347 }
348
349
350 static void QT_DoAddVideoSamplesToMedia (int frame, int *pixels, int rectx, int recty)
351 {
352         OSErr   err = noErr;
353         Rect    imageRect;
354
355         int             index;
356         int             boxsize;
357         unsigned char *from, *to;
358
359         short   syncFlag;
360         long    dataSize;
361         Handle  compressedData;
362         Ptr             myPtr;
363
364
365         //copy and flip renderdata
366         memcpy(qtexport->ibuf2->rect, pixels, 4*rectx*recty);
367         IMB_flipy(qtexport->ibuf2);
368
369         //get pointers to parse bitmapdata
370         myPtr = GetPixBaseAddr(qtexport->thePixMap);
371         imageRect = (**qtexport->thePixMap).bounds;
372
373         from = (unsigned char *) qtexport->ibuf2->rect;
374         to = (unsigned char *) myPtr;
375
376         //parse RGBA bitmap into Quicktime's ARGB GWorld
377         boxsize = rectx * recty;
378         for( index = 0; index < boxsize; index++) {
379                 to[0] = from[3];
380                 to[1] = from[0];
381                 to[2] = from[1];
382                 to[3] = from[2];
383                 to +=4, from += 4;
384         }
385
386         err = SCCompressSequenceFrame(qtdata->theComponent,
387                 qtexport->thePixMap,
388                 &imageRect,
389                 &compressedData,
390                 &dataSize,
391                 &syncFlag);
392         CheckError(err, "SCCompressSequenceFrame error");
393
394         err = AddMediaSample(qtexport->theMedia,
395                 compressedData,
396                 0,
397                 dataSize,
398                 qtdata->duration,
399                 (SampleDescriptionHandle)qtexport->anImageDescription,
400                 1,
401                 syncFlag,
402                 NULL);
403         CheckError(err, "AddMediaSample error");
404
405         printf ("added frame %3d (frame %3d in movie): ", frame, frame-sframe);
406 }
407
408
409 static void QT_EndAddVideoSamplesToMedia (void)
410 {
411         SCCompressSequenceEnd(qtdata->theComponent);
412
413         UnlockPixels(qtexport->thePixMap);
414         if (qtexport->theGWorld)
415                 DisposeGWorld (qtexport->theGWorld);
416
417         if (qtexport->ibuf)
418                 IMB_freeImBuf(qtexport->ibuf);
419
420         if (qtexport->ibuf2)
421                 IMB_freeImBuf(qtexport->ibuf2);
422
423
424
425 void makeqtstring (char *string) {
426         char txt[64];
427
428         if (string==0) return;
429
430         strcpy(string, G.scene->r.pic);
431         BLI_convertstringcode(string, G.sce, G.scene->r.cfra);
432
433         BLI_make_existing_file(string);
434
435         if (BLI_strcasecmp(string + strlen(string) - 4, ".mov")) {
436                 sprintf(txt, "%04d_%04d.mov", (G.scene->r.sfra) , (G.scene->r.efra) );
437                 strcat(string, txt);
438         }
439 }
440
441
442 void start_qt(struct RenderData *rd, int rectx, int recty) {
443         OSErr err = noErr;
444
445         char name[2048];
446         char theFullPath[255];
447
448 #ifdef __APPLE__
449         int             myFile;
450         FSRef   myRef;
451 #else
452         char    *qtname;
453 #endif
454
455         if(qtexport == NULL) qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport");
456
457         if(qtdata) {
458                 if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
459                 free_qtcomponentdata();
460         }
461
462         qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeCodecDataExt");
463
464         if(rd->qtcodecdata == NULL && rd->qtcodecdata->cdParms == NULL) {
465                 get_qtcodec_settings();
466         } else {
467                 qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
468
469                 QT_GetCodecSettingsFromScene();
470                 check_renderbutton_framerate();
471         }
472         
473         if (G.afbreek != 1) {
474                 sframe = (rd->sfra);
475
476                 makeqtstring(name);
477
478 #ifdef __APPLE__
479                 sprintf(theFullPath, "%s", name);
480
481                 /* hack: create an empty file to make FSPathMakeRef() happy */
482                 myFile = open(theFullPath, O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRUSR|S_IWUSR);
483                 if (myFile < 0) {
484                         printf("error while creating file!\n");
485                         /* do something? */
486                 }
487                 close(myFile);
488                 err = FSPathMakeRef(theFullPath, &myRef, 0);
489                 CheckError(err, "FsPathMakeRef error");
490                 err = FSGetCatalogInfo(&myRef, kFSCatInfoNone, NULL, NULL, &qtexport->theSpec, NULL);
491                 CheckError(err, "FsGetCatalogInfoRef error");
492 #endif
493 #ifdef _WIN32
494                 qtname = get_valid_qtname(name);
495                 sprintf(theFullPath, "%s", qtname);
496                 strcpy(name, qtname);
497                 MEM_freeN(qtname);
498                 
499                 CopyCStringToPascal(theFullPath, qtexport->qtfilename);
500                 err = FSMakeFSSpec(0, 0L, qtexport->qtfilename, &qtexport->theSpec);
501 #endif
502
503                 err = CreateMovieFile (&qtexport->theSpec, 
504                                                         kMyCreatorType,
505                                                         smCurrentScript, 
506                                                         createMovieFileDeleteCurFile | createMovieFileDontCreateResFile,
507                                                         &qtexport->resRefNum, 
508                                                         &qtexport->theMovie );
509                 CheckError(err, "CreateMovieFile error");
510
511                 if(err != noErr) {
512                         G.afbreek = 1;
513                         error("Unable to create Quicktime movie: %s", name);
514                 } else {
515                         printf("Created QuickTime movie: %s\n", name);
516
517                         QT_CreateMyVideoTrack(rectx, recty);
518                 }
519         }
520 }
521
522
523 void append_qt(int frame, int *pixels, int rectx, int recty) {
524         QT_DoAddVideoSamplesToMedia(frame, pixels, rectx, recty);
525 }
526
527
528 void end_qt(void) {
529         OSErr err = noErr;
530         short resId = movieInDataForkResID;
531
532         if(qtexport->theMovie) {
533                 QT_EndCreateMyVideoTrack();
534
535                 err = AddMovieResource (qtexport->theMovie, qtexport->resRefNum, &resId, qtexport->qtfilename);
536                 CheckError(err, "AddMovieResource error");
537
538                 err = QT_AddUserDataTextToMovie(qtexport->theMovie, "Made with Blender", kUserDataTextInformation);
539                 CheckError(err, "AddUserDataTextToMovie error");
540
541                 err = UpdateMovieResource(qtexport->theMovie, qtexport->resRefNum, resId, qtexport->qtfilename);
542                 CheckError(err, "UpdateMovieResource error");
543
544                 if(qtexport->resRefNum) CloseMovieFile(qtexport->resRefNum);
545
546                 DisposeMovie(qtexport->theMovie);
547
548                 printf("Finished QuickTime movie.\n");
549         }
550
551         if(qtexport) {
552                 MEM_freeN(qtexport);
553                 qtexport = NULL;
554         }
555 }
556
557
558 void free_qtcomponentdata(void) {
559         if(qtdata) {
560                 if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
561                 MEM_freeN(qtdata);
562                 qtdata = NULL;
563         }
564 }
565
566
567 static void check_renderbutton_framerate(void) {
568         // to keep float framerates consistent between the codec dialog and frs/sec button.
569         OSErr   err;    
570
571         err = SCGetInfo(qtdata->theComponent, scTemporalSettingsType,   &qtdata->gTemporalSettings);
572         CheckError(err, "SCGetInfo fr error");
573
574         if( (G.scene->r.frs_sec == 24 || G.scene->r.frs_sec == 30 || G.scene->r.frs_sec == 60) &&
575                 (qtdata->gTemporalSettings.frameRate == 1571553 ||
576                  qtdata->gTemporalSettings.frameRate == 1964113 ||
577                  qtdata->gTemporalSettings.frameRate == 3928227)) {;} else
578         qtdata->gTemporalSettings.frameRate = 
579                 (G.scene->r.frs_sec << 16) / G.scene->r.frs_sec_base ;
580
581         err = SCSetInfo(qtdata->theComponent, scTemporalSettingsType,   &qtdata->gTemporalSettings);
582         CheckError( err, "SCSetInfo error" );
583
584         if(qtdata->gTemporalSettings.frameRate == 1571553) {                    // 23.98 fps
585                 qtdata->kVideoTimeScale = 24000;
586                 qtdata->duration = 1001;
587         } else if (qtdata->gTemporalSettings.frameRate == 1964113) {    // 29.97 fps
588                 qtdata->kVideoTimeScale = 30000;
589                 qtdata->duration = 1001;
590         } else if (qtdata->gTemporalSettings.frameRate == 3928227) {    // 59.94 fps
591                 qtdata->kVideoTimeScale = 60000;
592                 qtdata->duration = 1001;
593         } else {
594                 qtdata->kVideoTimeScale = (qtdata->gTemporalSettings.frameRate >> 16) * 100;
595                 qtdata->duration = 100;
596         }
597 }
598
599
600 int get_qtcodec_settings(void) 
601 {
602         OSErr   err = noErr;
603
604         // erase any existing codecsetting
605         if(qtdata) {
606                 if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
607                 free_qtcomponentdata();
608         }
609
610         // allocate new
611         qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeComponentData");
612         qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
613
614         // get previous selected codecsetting, if any 
615         if(G.scene->r.qtcodecdata && G.scene->r.qtcodecdata->cdParms) {
616                 QT_GetCodecSettingsFromScene();
617                 check_renderbutton_framerate();
618         } else {
619                 // configure the standard image compression dialog box
620                 // set some default settings
621                 qtdata->gSpatialSettings.codec = anyCodec;         
622                 qtdata->gSpatialSettings.spatialQuality = codecMaxQuality;
623                 qtdata->gTemporalSettings.temporalQuality = codecMaxQuality;
624                 qtdata->gTemporalSettings.keyFrameRate = 25;   
625                 qtdata->aDataRateSetting.dataRate = 90 * 1024;          
626
627                 err = SCSetInfo(qtdata->theComponent, scTemporalSettingsType,   &qtdata->gTemporalSettings);
628                 CheckError(err, "SCSetInfo1 error");
629                 err = SCSetInfo(qtdata->theComponent, scSpatialSettingsType,    &qtdata->gSpatialSettings);
630                 CheckError(err, "SCSetInfo2 error");
631                 err = SCSetInfo(qtdata->theComponent, scDataRateSettingsType,   &qtdata->aDataRateSetting);
632                 CheckError(err, "SCSetInfo3 error");
633         }
634
635         check_renderbutton_framerate();
636
637         // put up the dialog box
638         err = SCRequestSequenceSettings(qtdata->theComponent);
639  
640         if (err == scUserCancelled) {
641                 G.afbreek = 1;
642                 return 0;
643         }
644
645         // get user selected data
646         SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
647         SCGetInfo(qtdata->theComponent, scSpatialSettingsType,  &qtdata->gSpatialSettings);
648         SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
649
650         QT_SaveCodecSettingsToScene();
651
652         // framerate jugglin'
653         if(qtdata->gTemporalSettings.frameRate == 1571553) {                    // 23.98 fps
654                 qtdata->kVideoTimeScale = 24000;
655                 qtdata->duration = 1001;
656
657                 G.scene->r.frs_sec = 24;
658                 G.scene->r.frs_sec_base = 1.001;
659         } else if (qtdata->gTemporalSettings.frameRate == 1964113) {    // 29.97 fps
660                 qtdata->kVideoTimeScale = 30000;
661                 qtdata->duration = 1001;
662
663                 G.scene->r.frs_sec = 30;
664                 G.scene->r.frs_sec_base = 1.001;
665         } else if (qtdata->gTemporalSettings.frameRate == 3928227) {    // 59.94 fps
666                 qtdata->kVideoTimeScale = 60000;
667                 qtdata->duration = 1001;
668
669                 G.scene->r.frs_sec = 60;
670                 G.scene->r.frs_sec_base = 1.001;
671         } else {
672                 double fps = qtdata->gTemporalSettings.frameRate;
673
674                 qtdata->kVideoTimeScale = 60000;
675                 qtdata->duration = qtdata->kVideoTimeScale / (qtdata->gTemporalSettings.frameRate / 65536);
676
677                 if ((qtdata->gTemporalSettings.frameRate & 0xffff) == 0) {
678                         G.scene->r.frs_sec = fps / 65536;
679                         G.scene->r.frs_sec_base = 1;
680                 } else {
681                         /* we do our very best... */
682                         G.scene->r.frs_sec = (fps * 10000 / 65536);
683                         G.scene->r.frs_sec_base = 10000;
684                 }
685         }
686
687         return 1;
688 }
689
690 #endif /* _WIN32 || __APPLE__ */
691 #endif /* WITH_QUICKTIME */
692