API:
[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
81 typedef struct QuicktimeExport {
82
83         FSSpec          theSpec;
84         short           resRefNum;
85         Str255          qtfilename;
86
87         Media           theMedia;
88         Movie           theMovie;
89         Track           theTrack;
90
91         GWorldPtr                       theGWorld;
92         PixMapHandle            thePixMap;
93         ImageDescription        **anImageDescription;
94
95         ImBuf           *ibuf;  //imagedata for Quicktime's Gworld
96         ImBuf           *ibuf2; //copy of renderdata, to be Y-flipped
97
98 } QuicktimeExport;
99
100 typedef struct QuicktimeComponentData {
101
102         ComponentInstance       theComponent;
103         SCTemporalSettings  gTemporalSettings;
104         SCSpatialSettings   gSpatialSettings;
105         SCDataRateSettings  aDataRateSetting;
106         TimeValue                       duration;
107         long                            kVideoTimeScale;
108
109 } QuicktimeComponentData;
110
111 static struct QuicktimeExport *qtexport;
112 static struct QuicktimeComponentData *qtdata;
113
114 static int      sframe;
115
116
117 static void CheckError(OSErr err, char *msg)
118 {
119         if(err != noErr) printf("%s: %d\n", msg, err);
120 }
121
122
123 static OSErr QT_SaveCodecSettingsToScene(RenderData *rd)
124 {       
125         QTAtomContainer         myContainer = NULL;
126         ComponentResult         myErr = noErr;
127         Ptr                                     myPtr;
128         long                            mySize = 0;
129
130         CodecInfo                       ci;
131         char str[255];
132
133         QuicktimeCodecData *qcd = rd->qtcodecdata;
134
135         // check if current scene already has qtcodec settings, and clear them
136         if (qcd) {
137                 free_qtcodecdata(qcd);
138         } else {
139                 qcd = rd->qtcodecdata = MEM_callocN(sizeof(QuicktimeCodecData), "QuicktimeCodecData");
140         }
141
142         // obtain all current codec settings
143         SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
144         SCSetInfo(qtdata->theComponent, scSpatialSettingsType,  &qtdata->gSpatialSettings);
145         SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
146
147         // retreive codecdata from quicktime in a atomcontainer
148         myErr = SCGetSettingsAsAtomContainer(qtdata->theComponent,  &myContainer);
149         if (myErr != noErr) {
150                 printf("Quicktime: SCGetSettingsAsAtomContainer failed\n"); 
151                 goto bail;
152         }
153
154         // get the size of the atomcontainer
155         mySize = GetHandleSize((Handle)myContainer);
156
157         // lock and convert the atomcontainer to a *valid* pointer
158         QTLockContainer(myContainer);
159         myPtr = *(Handle)myContainer;
160
161         // copy the Quicktime data into the blender qtcodecdata struct
162         if (myPtr) {
163                 qcd->cdParms = MEM_mallocN(mySize, "qt.cdParms");
164                 memcpy(qcd->cdParms, myPtr, mySize);
165                 qcd->cdSize = mySize;
166
167                 GetCodecInfo (&ci, qtdata->gSpatialSettings.codecType, 0);
168                 CopyPascalStringToC(ci.typeName, str);
169                 sprintf(qcd->qtcodecname, "Codec: %s", str);
170         } else {
171                 printf("Quicktime: QT_SaveCodecSettingsToScene failed\n"); 
172         }
173
174         QTUnlockContainer(myContainer);
175
176 bail:
177         if (myContainer != NULL)
178                 QTDisposeAtomContainer(myContainer);
179                 
180         return((OSErr)myErr);
181 }
182
183
184 static OSErr QT_GetCodecSettingsFromScene(RenderData *rd)
185 {       
186         Handle                          myHandle = NULL;
187         ComponentResult         myErr = noErr;
188 //      CodecInfo ci;
189 //      char str[255];
190
191         QuicktimeCodecData *qcd = rd->qtcodecdata;
192
193         // if there is codecdata in the blendfile, convert it to a Quicktime handle 
194         if (qcd) {
195                 myHandle = NewHandle(qcd->cdSize);
196                 PtrToHand( qcd->cdParms, &myHandle, qcd->cdSize);
197         }
198                 
199         // restore codecsettings to the quicktime component
200         if(qcd->cdParms && qcd->cdSize) {
201                 myErr = SCSetSettingsFromAtomContainer((GraphicsExportComponent)qtdata->theComponent, (QTAtomContainer)myHandle);
202                 if (myErr != noErr) {
203                         printf("Quicktime: SCSetSettingsFromAtomContainer failed\n"); 
204                         goto bail;
205                 }
206
207                 // update runtime codecsettings for use with the codec dialog
208                 SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
209                 SCGetInfo(qtdata->theComponent, scSpatialSettingsType,  &qtdata->gSpatialSettings);
210                 SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
211
212 //              GetCodecInfo (&ci, qtdata->gSpatialSettings.codecType, 0);
213 //              CopyPascalStringToC(ci.typeName, str);
214 //              printf("restored Codec: %s\n", str);
215         } else {
216                 printf("Quicktime: QT_GetCodecSettingsFromScene failed\n"); 
217         }
218 bail:
219         if (myHandle != NULL)
220                 DisposeHandle(myHandle);
221                 
222         return((OSErr)myErr);
223 }
224
225
226 static OSErr QT_AddUserDataTextToMovie (Movie theMovie, char *theText, OSType theType)
227 {
228         UserData                                        myUserData = NULL;
229         Handle                                          myHandle = NULL;
230         long                                            myLength = strlen(theText);
231         OSErr                                           myErr = noErr;
232
233         // get the movie's user data list
234         myUserData = GetMovieUserData(theMovie);
235         if (myUserData == NULL)
236                 return(paramErr);
237         
238         // copy the specified text into a new handle
239         myHandle = NewHandleClear(myLength);
240         if (myHandle == NULL)
241                 return(MemError());
242
243         BlockMoveData(theText, *myHandle, myLength);
244
245         // add the data to the movie's user data
246         myErr = AddUserDataText(myUserData, myHandle, theType, 1, (short)GetScriptManagerVariable(smRegionCode));
247
248         // clean up
249         DisposeHandle(myHandle);
250         return(myErr);
251 }
252
253
254 static void QT_CreateMyVideoTrack(int rectx, int recty)
255 {
256         OSErr err = noErr;
257         Rect trackFrame;
258 //      MatrixRecord myMatrix;
259
260         trackFrame.top = 0;
261         trackFrame.left = 0;
262         trackFrame.bottom = recty;
263         trackFrame.right = rectx;
264         
265         qtexport->theTrack = NewMovieTrack (qtexport->theMovie, 
266                                                         FixRatio(trackFrame.right,1),
267                                                         FixRatio(trackFrame.bottom,1), 
268                                                         0);
269         CheckError( GetMoviesError(), "NewMovieTrack error" );
270
271 //      SetIdentityMatrix(&myMatrix);
272 //      ScaleMatrix(&myMatrix, fixed1, Long2Fix(-1), 0, 0);
273 //      TranslateMatrix(&myMatrix, 0, Long2Fix(trackFrame.bottom));
274 //      SetMovieMatrix(qtexport->theMovie, &myMatrix);
275
276         qtexport->theMedia = NewTrackMedia (qtexport->theTrack,
277                                                         VideoMediaType,
278                                                         qtdata->kVideoTimeScale,
279                                                         nil,
280                                                         0);
281         CheckError( GetMoviesError(), "NewTrackMedia error" );
282
283         err = BeginMediaEdits (qtexport->theMedia);
284         CheckError( err, "BeginMediaEdits error" );
285
286         QT_StartAddVideoSamplesToMedia (&trackFrame, rectx, recty);
287
288
289
290 static void QT_EndCreateMyVideoTrack(void)
291 {
292         OSErr err = noErr;
293
294         QT_EndAddVideoSamplesToMedia ();
295
296         err = EndMediaEdits (qtexport->theMedia);
297         CheckError( err, "EndMediaEdits error" );
298
299         err = InsertMediaIntoTrack (qtexport->theTrack,
300                                                                 kTrackStart,/* track start time */
301                                                                 kMediaStart,/* media start time */
302                                                                 GetMediaDuration (qtexport->theMedia),
303                                                                 fixed1);
304         CheckError( err, "InsertMediaIntoTrack error" );
305
306
307
308 static void QT_StartAddVideoSamplesToMedia (const Rect *trackFrame, int rectx, int recty)
309 {
310         SCTemporalSettings gTemporalSettings;
311         OSErr err = noErr;
312
313         qtexport->ibuf = IMB_allocImBuf (rectx, recty, 32, IB_rect, 0);
314         qtexport->ibuf2 = IMB_allocImBuf (rectx, recty, 32, IB_rect, 0);
315
316         err = NewGWorldFromPtr( &qtexport->theGWorld,
317                                                         k32ARGBPixelFormat,
318                                                         trackFrame,
319                                                         NULL, NULL, 0,
320                                                         (unsigned char *)qtexport->ibuf->rect,
321                                                         rectx * 4 );
322         CheckError (err, "NewGWorldFromPtr error");
323
324         qtexport->thePixMap = GetGWorldPixMap(qtexport->theGWorld);
325         LockPixels(qtexport->thePixMap);
326
327         SCDefaultPixMapSettings (qtdata->theComponent, qtexport->thePixMap, true);
328
329         // workaround for crash with H.264, which requires an upgrade to
330         // the new callback based api for proper encoding, but that's not
331         // really compatible with rendering out frames sequentially
332         gTemporalSettings = qtdata->gTemporalSettings;
333         if(qtdata->gSpatialSettings.codecType == kH264CodecType) {
334                 if(gTemporalSettings.temporalQuality != codecMinQuality) {
335                         fprintf(stderr, "Only minimum quality compression supported for QuickTime H.264.\n");
336                         gTemporalSettings.temporalQuality = codecMinQuality;
337                 }
338         }
339
340         SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &gTemporalSettings);
341         SCSetInfo(qtdata->theComponent, scSpatialSettingsType,  &qtdata->gSpatialSettings);
342         SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
343
344         err = SCCompressSequenceBegin(qtdata->theComponent, qtexport->thePixMap, NULL, &qtexport->anImageDescription); 
345         CheckError (err, "SCCompressSequenceBegin error" );
346 }
347
348
349 static void QT_DoAddVideoSamplesToMedia (int frame, int *pixels, int rectx, int recty)
350 {
351         OSErr   err = noErr;
352         Rect    imageRect;
353
354         int             index;
355         int             boxsize;
356         unsigned char *from, *to;
357
358         short   syncFlag;
359         long    dataSize;
360         Handle  compressedData;
361         Ptr             myPtr;
362
363
364         //copy and flip renderdata
365         memcpy(qtexport->ibuf2->rect, pixels, 4*rectx*recty);
366         IMB_flipy(qtexport->ibuf2);
367
368         //get pointers to parse bitmapdata
369         myPtr = GetPixBaseAddr(qtexport->thePixMap);
370         imageRect = (**qtexport->thePixMap).bounds;
371
372         from = (unsigned char *) qtexport->ibuf2->rect;
373         to = (unsigned char *) myPtr;
374
375         //parse RGBA bitmap into Quicktime's ARGB GWorld
376         boxsize = rectx * recty;
377         for( index = 0; index < boxsize; index++) {
378                 to[0] = from[3];
379                 to[1] = from[0];
380                 to[2] = from[1];
381                 to[3] = from[2];
382                 to +=4, from += 4;
383         }
384
385         err = SCCompressSequenceFrame(qtdata->theComponent,
386                 qtexport->thePixMap,
387                 &imageRect,
388                 &compressedData,
389                 &dataSize,
390                 &syncFlag);
391         CheckError(err, "SCCompressSequenceFrame error");
392
393         err = AddMediaSample(qtexport->theMedia,
394                 compressedData,
395                 0,
396                 dataSize,
397                 qtdata->duration,
398                 (SampleDescriptionHandle)qtexport->anImageDescription,
399                 1,
400                 syncFlag,
401                 NULL);
402         CheckError(err, "AddMediaSample error");
403
404         printf ("added frame %3d (frame %3d in movie): ", frame, frame-sframe);
405 }
406
407
408 static void QT_EndAddVideoSamplesToMedia (void)
409 {
410         SCCompressSequenceEnd(qtdata->theComponent);
411
412         UnlockPixels(qtexport->thePixMap);
413         if (qtexport->theGWorld)
414                 DisposeGWorld (qtexport->theGWorld);
415
416         if (qtexport->ibuf)
417                 IMB_freeImBuf(qtexport->ibuf);
418
419         if (qtexport->ibuf2)
420                 IMB_freeImBuf(qtexport->ibuf2);
421
422
423
424 void makeqtstring (RenderData *rd, char *string) {
425         char txt[64];
426
427         if (string==0) return;
428
429         strcpy(string, rd->pic);
430         BLI_convertstringcode(string, G.sce);
431
432         BLI_make_existing_file(string);
433
434         if (BLI_strcasecmp(string + strlen(string) - 4, ".mov")) {
435                 sprintf(txt, "%04d_%04d.mov", (rd->sfra) , (rd->efra) );
436                 strcat(string, txt);
437         }
438 }
439
440
441 void start_qt(struct RenderData *rd, int rectx, int recty) {
442         OSErr err = noErr;
443
444         char name[2048];
445         char theFullPath[255];
446
447 #ifdef __APPLE__
448         int             myFile;
449         FSRef   myRef;
450 #else
451         char    *qtname;
452 #endif
453
454         if(qtexport == NULL) qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport");
455
456         if(qtdata) {
457                 if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
458                 free_qtcomponentdata();
459         }
460
461         qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeCodecDataExt");
462
463         if(rd->qtcodecdata == NULL && rd->qtcodecdata->cdParms == NULL) {
464                 get_qtcodec_settings(rd);
465         } else {
466                 qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
467
468                 QT_GetCodecSettingsFromScene(rd);
469                 check_renderbutton_framerate(rd);
470         }
471         
472         if (G.afbreek != 1) {
473                 sframe = (rd->sfra);
474
475                 makeqtstring(rd, name);
476
477 #ifdef __APPLE__
478                 sprintf(theFullPath, "%s", name);
479
480                 /* hack: create an empty file to make FSPathMakeRef() happy */
481                 myFile = open(theFullPath, O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRUSR|S_IWUSR);
482                 if (myFile < 0) {
483                         printf("error while creating file!\n");
484                         /* do something? */
485                 }
486                 close(myFile);
487                 err = FSPathMakeRef(theFullPath, &myRef, 0);
488                 CheckError(err, "FsPathMakeRef error");
489                 err = FSGetCatalogInfo(&myRef, kFSCatInfoNone, NULL, NULL, &qtexport->theSpec, NULL);
490                 CheckError(err, "FsGetCatalogInfoRef error");
491 #endif
492 #ifdef _WIN32
493                 qtname = get_valid_qtname(name);
494                 sprintf(theFullPath, "%s", qtname);
495                 strcpy(name, qtname);
496                 MEM_freeN(qtname);
497                 
498                 CopyCStringToPascal(theFullPath, qtexport->qtfilename);
499                 err = FSMakeFSSpec(0, 0L, qtexport->qtfilename, &qtexport->theSpec);
500 #endif
501
502                 err = CreateMovieFile (&qtexport->theSpec, 
503                                                         kMyCreatorType,
504                                                         smCurrentScript, 
505                                                         createMovieFileDeleteCurFile | createMovieFileDontCreateResFile,
506                                                         &qtexport->resRefNum, 
507                                                         &qtexport->theMovie );
508                 CheckError(err, "CreateMovieFile error");
509
510                 if(err != noErr) {
511                         G.afbreek = 1;
512 // XXX                  error("Unable to create Quicktime movie: %s", name);
513                 } else {
514                         printf("Created QuickTime movie: %s\n", name);
515
516                         QT_CreateMyVideoTrack(rectx, recty);
517                 }
518         }
519 }
520
521
522 void append_qt(struct RenderData *rd, int frame, int *pixels, int rectx, int recty) {
523         QT_DoAddVideoSamplesToMedia(frame, pixels, rectx, recty);
524 }
525
526
527 void end_qt(void) {
528         OSErr err = noErr;
529         short resId = movieInDataForkResID;
530
531         if(qtexport->theMovie) {
532                 QT_EndCreateMyVideoTrack();
533
534                 err = AddMovieResource (qtexport->theMovie, qtexport->resRefNum, &resId, qtexport->qtfilename);
535                 CheckError(err, "AddMovieResource error");
536
537                 err = QT_AddUserDataTextToMovie(qtexport->theMovie, "Made with Blender", kUserDataTextInformation);
538                 CheckError(err, "AddUserDataTextToMovie error");
539
540                 err = UpdateMovieResource(qtexport->theMovie, qtexport->resRefNum, resId, qtexport->qtfilename);
541                 CheckError(err, "UpdateMovieResource error");
542
543                 if(qtexport->resRefNum) CloseMovieFile(qtexport->resRefNum);
544
545                 DisposeMovie(qtexport->theMovie);
546
547                 printf("Finished QuickTime movie.\n");
548         }
549
550         if(qtexport) {
551                 MEM_freeN(qtexport);
552                 qtexport = NULL;
553         }
554 }
555
556
557 void free_qtcomponentdata(void) {
558         if(qtdata) {
559                 if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
560                 MEM_freeN(qtdata);
561                 qtdata = NULL;
562         }
563 }
564
565
566 static void check_renderbutton_framerate(RenderData *rd) 
567 {
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( (rd->frs_sec == 24 || rd->frs_sec == 30 || rd->frs_sec == 60) &&
575                 (qtdata->gTemporalSettings.frameRate == 1571553 ||
576                  qtdata->gTemporalSettings.frameRate == 1964113 ||
577                  qtdata->gTemporalSettings.frameRate == 3928227)) {;} else
578         qtdata->gTemporalSettings.frameRate = 
579                 (rd->frs_sec << 16) / rd->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(RenderData *rd) 
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(rd->qtcodecdata && rd->qtcodecdata->cdParms) {
616                 QT_GetCodecSettingsFromScene(rd);
617                 check_renderbutton_framerate(rd);
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(rd);
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(rd);
651
652         // framerate jugglin'
653         if(qtdata->gTemporalSettings.frameRate == 1571553) {                    // 23.98 fps
654                 qtdata->kVideoTimeScale = 24000;
655                 qtdata->duration = 1001;
656
657                 rd->frs_sec = 24;
658                 rd->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                 rd->frs_sec = 30;
664                 rd->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                 rd->frs_sec = 60;
670                 rd->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                         rd->frs_sec = fps / 65536;
679                         rd->frs_sec_base = 1;
680                 } else {
681                         /* we do our very best... */
682                         rd->frs_sec = (fps * 10000 / 65536);
683                         rd->frs_sec_base = 10000;
684                 }
685         }
686
687         return 1;
688 }
689
690 #endif /* _WIN32 || __APPLE__ */
691 #endif /* WITH_QUICKTIME */
692