6 * Code to create QuickTime Movies with Blender
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.
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.
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.
24 * The Original Code is written by Rob Haarsma (phase)
26 * Contributor(s): Stefan Gartner (sgefant)
28 * ***** END GPL LICENSE BLOCK *****
32 #if defined(_WIN32) || defined(__APPLE__)
34 #include "DNA_scene_types.h"
35 #include "DNA_windowmanager_types.h"
40 #include "BKE_global.h"
41 #include "BKE_scene.h"
42 #include "BKE_context.h"
44 #include "BLI_blenlib.h"
46 #include "BLO_sys_types.h"
48 #include "IMB_imbuf.h"
49 #include "IMB_imbuf_types.h"
51 #include "MEM_guardedalloc.h"
53 #include "quicktime_import.h"
54 #include "quicktime_export.h"
59 #include <QuickTimeComponents.h>
60 #include <TextUtils.h>
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__ */
75 #define kMyCreatorType FOUR_CHAR_CODE('TVOD')
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);
87 typedef struct QuicktimeExport {
98 PixMapHandle thePixMap;
99 ImageDescription **anImageDescription;
101 ImBuf *ibuf; //imagedata for Quicktime's Gworld
102 ImBuf *ibuf2; //copy of renderdata, to be Y-flipped
106 typedef struct QuicktimeComponentData {
108 ComponentInstance theComponent;
109 SCTemporalSettings gTemporalSettings;
110 SCSpatialSettings gSpatialSettings;
111 SCDataRateSettings aDataRateSetting;
113 long kVideoTimeScale;
115 } QuicktimeComponentData;
117 static struct QuicktimeExport *qtexport;
118 static struct QuicktimeComponentData *qtdata;
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"},
139 static int qtCodecCount = 12;
141 int quicktime_get_num_codecs() {
145 QuicktimeCodecTypeDesc* quicktime_get_codecType_desc(int indexValue) {
146 if ((indexValue>=0) && (indexValue < qtCodecCount))
147 return &qtCodecList[indexValue];
152 int quicktime_rnatmpvalue_from_codectype(int codecType) {
154 for (i=0;i<qtCodecCount;i++) {
155 if (qtCodecList[i].codecType == codecType)
156 return qtCodecList[i].rnatmpvalue;
162 int quicktime_codecType_from_rnatmpvalue(int rnatmpvalue) {
164 for (i=0;i<qtCodecCount;i++) {
165 if (qtCodecList[i].rnatmpvalue == rnatmpvalue)
166 return qtCodecList[i].codecType;
174 static void CheckError(OSErr err, char *msg)
176 if(err != noErr) printf("%s: %d\n", msg, err);
180 static OSErr QT_SaveCodecSettingsToScene(RenderData *rd)
182 QTAtomContainer myContainer = NULL;
183 ComponentResult myErr = noErr;
189 QuicktimeCodecData *qcd = rd->qtcodecdata;
191 // check if current scene already has qtcodec settings, and clear them
193 free_qtcodecdata(qcd);
195 qcd = rd->qtcodecdata = MEM_callocN(sizeof(QuicktimeCodecData), "QuicktimeCodecData");
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);
203 // retreive codecdata from quicktime in a atomcontainer
204 myErr = SCGetSettingsAsAtomContainer(qtdata->theComponent, &myContainer);
205 if (myErr != noErr) {
206 printf("Quicktime: SCGetSettingsAsAtomContainer failed\n");
210 // get the size of the atomcontainer
211 mySize = GetHandleSize((Handle)myContainer);
213 // lock and convert the atomcontainer to a *valid* pointer
214 QTLockContainer(myContainer);
215 myPtr = *(Handle)myContainer;
217 // copy the Quicktime data into the blender qtcodecdata struct
219 qcd->cdParms = MEM_mallocN(mySize, "qt.cdParms");
220 memcpy(qcd->cdParms, myPtr, mySize);
221 qcd->cdSize = mySize;
223 GetCodecInfo (&ci, qtdata->gSpatialSettings.codecType, 0);
225 printf("Quicktime: QT_SaveCodecSettingsToScene failed\n");
228 QTUnlockContainer(myContainer);
231 if (myContainer != NULL)
232 QTDisposeAtomContainer(myContainer);
234 return((OSErr)myErr);
238 static OSErr QT_GetCodecSettingsFromScene(RenderData *rd)
240 Handle myHandle = NULL;
241 ComponentResult myErr = noErr;
243 QuicktimeCodecData *qcd = rd->qtcodecdata;
245 // if there is codecdata in the blendfile, convert it to a Quicktime handle
247 myHandle = NewHandle(qcd->cdSize);
248 PtrToHand( qcd->cdParms, &myHandle, qcd->cdSize);
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");
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);
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;
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;
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)
281 printf("Quicktime: QT_GetCodecSettingsFromScene failed\n");
284 if (myHandle != NULL)
285 DisposeHandle(myHandle);
287 return((OSErr)myErr);
291 static OSErr QT_AddUserDataTextToMovie (Movie theMovie, char *theText, OSType theType)
293 UserData myUserData = NULL;
294 Handle myHandle = NULL;
295 long myLength = strlen(theText);
298 // get the movie's user data list
299 myUserData = GetMovieUserData(theMovie);
300 if (myUserData == NULL)
303 // copy the specified text into a new handle
304 myHandle = NewHandleClear(myLength);
305 if (myHandle == NULL)
308 BlockMoveData(theText, *myHandle, myLength);
310 // add the data to the movie's user data
311 myErr = AddUserDataText(myUserData, myHandle, theType, 1, (short)GetScriptManagerVariable(smRegionCode));
314 DisposeHandle(myHandle);
319 static void QT_CreateMyVideoTrack(int rectx, int recty)
323 // MatrixRecord myMatrix;
327 trackFrame.bottom = recty;
328 trackFrame.right = rectx;
330 qtexport->theTrack = NewMovieTrack (qtexport->theMovie,
331 FixRatio(trackFrame.right,1),
332 FixRatio(trackFrame.bottom,1),
334 CheckError( GetMoviesError(), "NewMovieTrack error" );
336 // SetIdentityMatrix(&myMatrix);
337 // ScaleMatrix(&myMatrix, fixed1, Long2Fix(-1), 0, 0);
338 // TranslateMatrix(&myMatrix, 0, Long2Fix(trackFrame.bottom));
339 // SetMovieMatrix(qtexport->theMovie, &myMatrix);
341 qtexport->theMedia = NewTrackMedia (qtexport->theTrack,
343 qtdata->kVideoTimeScale,
346 CheckError( GetMoviesError(), "NewTrackMedia error" );
348 err = BeginMediaEdits (qtexport->theMedia);
349 CheckError( err, "BeginMediaEdits error" );
351 QT_StartAddVideoSamplesToMedia (&trackFrame, rectx, recty);
355 static void QT_EndCreateMyVideoTrack(void)
359 QT_EndAddVideoSamplesToMedia ();
361 err = EndMediaEdits (qtexport->theMedia);
362 CheckError( err, "EndMediaEdits error" );
364 err = InsertMediaIntoTrack (qtexport->theTrack,
365 kTrackStart,/* track start time */
366 kMediaStart,/* media start time */
367 GetMediaDuration (qtexport->theMedia),
369 CheckError( err, "InsertMediaIntoTrack error" );
373 static void QT_StartAddVideoSamplesToMedia (const Rect *trackFrame, int rectx, int recty)
375 SCTemporalSettings gTemporalSettings;
378 qtexport->ibuf = IMB_allocImBuf (rectx, recty, 32, IB_rect, 0);
379 qtexport->ibuf2 = IMB_allocImBuf (rectx, recty, 32, IB_rect, 0);
381 err = NewGWorldFromPtr( &qtexport->theGWorld,
385 (Ptr)qtexport->ibuf->rect,
387 CheckError (err, "NewGWorldFromPtr error");
389 qtexport->thePixMap = GetGWorldPixMap(qtexport->theGWorld);
390 LockPixels(qtexport->thePixMap);
392 SCDefaultPixMapSettings (qtdata->theComponent, qtexport->thePixMap, true);
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;
405 SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &gTemporalSettings);
406 SCSetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
407 SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
409 err = SCCompressSequenceBegin(qtdata->theComponent, qtexport->thePixMap, NULL, &qtexport->anImageDescription);
410 CheckError (err, "SCCompressSequenceBegin error" );
414 static void QT_DoAddVideoSamplesToMedia (int frame, int *pixels, int rectx, int recty)
421 unsigned char *from, *to;
425 Handle compressedData;
429 //copy and flip renderdata
430 memcpy(qtexport->ibuf2->rect, pixels, 4*rectx*recty);
431 IMB_flipy(qtexport->ibuf2);
433 //get pointers to parse bitmapdata
434 myPtr = GetPixBaseAddr(qtexport->thePixMap);
435 imageRect = (**qtexport->thePixMap).bounds;
437 from = (unsigned char *) qtexport->ibuf2->rect;
438 to = (unsigned char *) myPtr;
440 //parse RGBA bitmap into Quicktime's ARGB GWorld
441 boxsize = rectx * recty;
442 for( index = 0; index < boxsize; index++) {
450 err = SCCompressSequenceFrame(qtdata->theComponent,
456 CheckError(err, "SCCompressSequenceFrame error");
458 err = AddMediaSample(qtexport->theMedia,
463 (SampleDescriptionHandle)qtexport->anImageDescription,
467 CheckError(err, "AddMediaSample error");
469 printf ("added frame %3d (frame %3d in movie): ", frame, frame-sframe);
473 static void QT_EndAddVideoSamplesToMedia (void)
475 SCCompressSequenceEnd(qtdata->theComponent);
477 UnlockPixels(qtexport->thePixMap);
478 if (qtexport->theGWorld)
479 DisposeGWorld (qtexport->theGWorld);
482 IMB_freeImBuf(qtexport->ibuf);
485 IMB_freeImBuf(qtexport->ibuf2);
489 void makeqtstring (RenderData *rd, char *string) {
492 if (string==0) return;
494 strcpy(string, rd->pic);
495 BLI_convertstringcode(string, G.sce);
497 BLI_make_existing_file(string);
499 if (BLI_strcasecmp(string + strlen(string) - 4, ".mov")) {
500 sprintf(txt, "%04d_%04d.mov", (rd->sfra) , (rd->efra) );
506 void start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty) {
510 char theFullPath[255];
519 if(qtexport == NULL) qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport");
522 if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
523 free_qtcomponentdata();
526 qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeCodecDataExt");
528 if(rd->qtcodecdata == NULL || rd->qtcodecdata->cdParms == NULL) {
529 get_qtcodec_settings(rd);
531 qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
533 QT_GetCodecSettingsFromScene(rd);
534 check_renderbutton_framerate(rd);
537 if (G.afbreek != 1) {
540 makeqtstring(rd, name);
543 EnterMoviesOnThread(0);
544 sprintf(theFullPath, "%s", name);
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);
549 printf("error while creating file!\n");
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");
559 qtname = get_valid_qtname(name);
560 sprintf(theFullPath, "%s", qtname);
561 strcpy(name, qtname);
564 CopyCStringToPascal(theFullPath, qtexport->qtfilename);
565 err = FSMakeFSSpec(0, 0L, qtexport->qtfilename, &qtexport->theSpec);
568 err = CreateMovieFile (&qtexport->theSpec,
571 createMovieFileDeleteCurFile | createMovieFileDontCreateResFile,
572 &qtexport->resRefNum,
573 &qtexport->theMovie );
574 CheckError(err, "CreateMovieFile error");
578 // XXX error("Unable to create Quicktime movie: %s", name);
580 ExitMoviesOnThread();
583 printf("Created QuickTime movie: %s\n", name);
585 QT_CreateMyVideoTrack(rectx, recty);
591 void append_qt(struct RenderData *rd, int frame, int *pixels, int rectx, int recty) {
592 QT_DoAddVideoSamplesToMedia(frame, pixels, rectx, recty);
598 short resId = movieInDataForkResID;
600 if(qtexport->theMovie) {
601 QT_EndCreateMyVideoTrack();
603 err = AddMovieResource (qtexport->theMovie, qtexport->resRefNum, &resId, qtexport->qtfilename);
604 CheckError(err, "AddMovieResource error");
606 err = QT_AddUserDataTextToMovie(qtexport->theMovie, "Made with Blender", kUserDataTextInformation);
607 CheckError(err, "AddUserDataTextToMovie error");
609 err = UpdateMovieResource(qtexport->theMovie, qtexport->resRefNum, resId, qtexport->qtfilename);
610 CheckError(err, "UpdateMovieResource error");
612 if(qtexport->resRefNum) CloseMovieFile(qtexport->resRefNum);
614 DisposeMovie(qtexport->theMovie);
616 printf("Finished QuickTime movie.\n");
619 ExitMoviesOnThread();
628 void free_qtcomponentdata(void) {
630 if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
637 static void check_renderbutton_framerate(RenderData *rd)
639 // to keep float framerates consistent between the codec dialog and frs/sec button.
642 err = SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
643 CheckError(err, "SCGetInfo fr error");
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)) {;}
650 if (rd->frs_sec_base > 0)
651 qtdata->gTemporalSettings.frameRate =
652 ((float)(rd->frs_sec << 16) / rd->frs_sec_base) ;
655 err = SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
656 CheckError( err, "SCSetInfo error" );
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;
668 qtdata->kVideoTimeScale = (qtdata->gTemporalSettings.frameRate >> 16) * 100;
669 qtdata->duration = 100;
673 void quicktime_verify_image_type(RenderData *rd)
675 if (rd->imtype == R_QUICKTIME) {
676 if ((rd->qtcodecsettings.codecType== 0) ||
677 (rd->qtcodecsettings.codecSpatialQuality <0) ||
678 (rd->qtcodecsettings.codecSpatialQuality > 100)) {
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
690 int get_qtcodec_settings(RenderData *rd)
693 // erase any existing codecsetting
695 if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
696 free_qtcomponentdata();
700 qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeComponentData");
701 qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
703 // get previous selected codecsetting, from qtatom or detailed settings
704 if(rd->qtcodecdata && rd->qtcodecdata->cdParms) {
705 QT_GetCodecSettingsFromScene(rd);
707 SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
708 SCGetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
709 SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
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;
721 qtdata->aDataRateSetting.frameDuration = rd->frs_sec;
722 SetMovieTimeScale(qtexport->theMovie, rd->frs_sec_base*1000);
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");
733 check_renderbutton_framerate(rd);
738 static int request_qtcodec_settings(bContext *C, wmOperator *op)
741 Scene *scene = CTX_data_scene(C);
742 RenderData *rd = &scene->r;
744 // erase any existing codecsetting
746 if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
747 free_qtcomponentdata();
751 qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeComponentData");
752 qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
754 // get previous selected codecsetting, from qtatom or detailed settings
755 if(rd->qtcodecdata && rd->qtcodecdata->cdParms) {
756 QT_GetCodecSettingsFromScene(rd);
758 SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
759 SCGetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
760 SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
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;
773 qtdata->aDataRateSetting.frameDuration = rd->frs_sec;
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");
782 // put up the dialog box - it needs to be called from the main thread
783 err = SCRequestSequenceSettings(qtdata->theComponent);
785 if (err == scUserCancelled) {
786 return OPERATOR_FINISHED;
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);
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;
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;
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)
810 QT_SaveCodecSettingsToScene(rd);
812 // framerate jugglin'
813 if(qtdata->gTemporalSettings.frameRate == 1571553) { // 23.98 fps
814 qtdata->kVideoTimeScale = 24000;
815 qtdata->duration = 1001;
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;
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;
830 rd->frs_sec_base = 1.001;
832 double fps = qtdata->gTemporalSettings.frameRate;
834 qtdata->kVideoTimeScale = 60000;
835 qtdata->duration = qtdata->kVideoTimeScale / (qtdata->gTemporalSettings.frameRate / 65536);
837 if ((qtdata->gTemporalSettings.frameRate & 0xffff) == 0) {
838 rd->frs_sec = fps / 65536;
839 rd->frs_sec_base = 1.0;
841 /* we do our very best... */
842 rd->frs_sec = fps / 65536;
843 rd->frs_sec_base = 1.0;
847 return OPERATOR_FINISHED;
850 static int ED_operator_setqtcodec(bContext *C)
852 return G.have_quicktime != FALSE;
855 #if defined(__APPLE__) && defined(GHOST_COCOA)
856 //Need to set up a Cocoa NSAutoReleasePool to avoid memory leak
857 //And it must be done in an objC file, so use a GHOST_SystemCocoa.mm function for that
858 extern int cocoa_request_qtcodec_settings(bContext *C, wmOperator *op);
860 int fromcocoa_request_qtcodec_settings(bContext *C, wmOperator *op)
862 return request_qtcodec_settings(C, op);
867 void SCENE_OT_render_data_set_quicktime_codec(wmOperatorType *ot)
870 ot->name= "Change codec";
871 ot->description= "Change Quicktime codec Settings";
872 ot->idname= "SCENE_OT_render_data_set_quicktime_codec";
875 #if defined(__APPLE__) && defined(GHOST_COCOA)
876 ot->exec = cocoa_request_qtcodec_settings;
878 ot->exec= request_qtcodec_settings;
880 ot->poll= ED_operator_setqtcodec;
883 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
886 #endif /* _WIN32 || __APPLE__ */
887 #endif /* WITH_QUICKTIME */