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