Blender  V2.59
quicktime_export.c
Go to the documentation of this file.
00001 /*
00002  * $Id: quicktime_export.c 35235 2011-02-27 20:01:38Z jesterking $
00003  *
00004  * quicktime_export.c
00005  *
00006  * Code to create QuickTime Movies with Blender
00007  *
00008  * ***** BEGIN GPL LICENSE BLOCK *****
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU General Public License
00011  * as published by the Free Software Foundation; either version 2
00012  * of the License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software Foundation,
00021  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00022  *
00023  *
00024  * The Original Code is written by Rob Haarsma (phase)
00025  *
00026  * Contributor(s): Stefan Gartner (sgefant)
00027  *
00028  * ***** END GPL LICENSE BLOCK *****
00029  */
00030 
00036 #ifdef WITH_QUICKTIME
00037 #if defined(_WIN32) || defined(__APPLE__)
00038 #ifndef USE_QTKIT
00039 
00040 #include "DNA_scene_types.h"
00041 #include "DNA_windowmanager_types.h"
00042 
00043 #include "WM_api.h"
00044 #include "WM_types.h"
00045 
00046 #include "BKE_context.h"
00047 #include "BKE_global.h"
00048 #include "BKE_main.h"
00049 #include "BKE_report.h"
00050 #include "BKE_scene.h"
00051 
00052 #include "BLI_blenlib.h"
00053 
00054 #include "BLO_sys_types.h"
00055 
00056 #include "IMB_imbuf.h"
00057 #include "IMB_imbuf_types.h"
00058 
00059 #include "MEM_guardedalloc.h"
00060 
00061 #include "quicktime_import.h"
00062 #include "quicktime_export.h"
00063 
00064 #ifdef _WIN32
00065 #include <QTML.h>
00066 #include <Movies.h>
00067 #include <QuickTimeComponents.h>
00068 #include <TextUtils.h> 
00069 #include <string.h>
00070 #include <memory.h>
00071 
00072 #endif /* _WIN32 */
00073 
00074 #ifdef __APPLE__
00075 /* evil */
00076 #ifndef __AIFF__
00077 #define __AIFF__
00078 #endif
00079 #include <QuickTime/Movies.h>
00080 #include <QuickTime/QuickTimeComponents.h>
00081 #include <fcntl.h> /* open() */
00082 #include <unistd.h> /* close() */
00083 #include <sys/stat.h> /* file permissions */
00084 #endif /* __APPLE__ */
00085 
00086 #define kMyCreatorType  FOUR_CHAR_CODE('TVOD')
00087 #define kTrackStart             0
00088 #define kMediaStart             0
00089 
00090 static void QT_StartAddVideoSamplesToMedia (const Rect *trackFrame, int rectx, int recty, struct ReportList *reports);
00091 static void QT_DoAddVideoSamplesToMedia (int frame, int *pixels, int rectx, int recty, struct ReportList *reports);
00092 static void QT_EndAddVideoSamplesToMedia (void);
00093 static void QT_CreateMyVideoTrack (int rectx, int recty, struct ReportList *reports);
00094 static void QT_EndCreateMyVideoTrack (struct ReportList *reports);
00095 static void check_renderbutton_framerate(struct RenderData *rd, struct ReportList *reports);
00096 static int get_qtcodec_settings(struct RenderData *rd, struct ReportList *reports);
00097 
00098 typedef struct QuicktimeExport {
00099 
00100         FSSpec          theSpec;
00101         short           resRefNum;
00102         Str255          qtfilename;
00103 
00104         Media           theMedia;
00105         Movie           theMovie;
00106         Track           theTrack;
00107 
00108         GWorldPtr                       theGWorld;
00109         PixMapHandle            thePixMap;
00110         ImageDescription        **anImageDescription;
00111 
00112         ImBuf           *ibuf;  //imagedata for Quicktime's Gworld
00113         ImBuf           *ibuf2; //copy of renderdata, to be Y-flipped
00114 
00115 } QuicktimeExport;
00116 
00117 typedef struct QuicktimeComponentData {
00118 
00119         ComponentInstance       theComponent;
00120         SCTemporalSettings  gTemporalSettings;
00121         SCSpatialSettings   gSpatialSettings;
00122         SCDataRateSettings  aDataRateSetting;
00123         TimeValue                       duration;
00124         long                            kVideoTimeScale;
00125 
00126 } QuicktimeComponentData;
00127 
00128 static struct QuicktimeExport *qtexport;
00129 static struct QuicktimeComponentData *qtdata;
00130 
00131 static int      sframe;
00132 
00133 /* RNA functions */
00134 
00135 static QuicktimeCodecTypeDesc qtVideoCodecList[] = {
00136         {kRawCodecType, 1, "Uncompressed"},
00137         {kJPEGCodecType, 2, "JPEG"},
00138         {kMotionJPEGACodecType, 3, "M-JPEG A"},
00139         {kMotionJPEGBCodecType, 4, "M-JPEG B"},
00140         {kDVCPALCodecType, 5, "DV PAL"},
00141         {kDVCNTSCCodecType, 6, "DV/DVCPRO NTSC"},
00142         {kDVCPROHD720pCodecType, 7, "DVCPRO HD 720p"},
00143         {kDVCPROHD1080i50CodecType, 8, "DVCPRO HD 1080i50"},
00144         {kDVCPROHD1080i60CodecType, 9, "DVCPRO HD 1080i60"},
00145         {kMPEG4VisualCodecType, 10, "MPEG4"},
00146         {kH263CodecType, 11, "H.263"},
00147         {kH264CodecType, 12, "H.264"},
00148         {0,0,NULL}};
00149 
00150 static int qtVideoCodecCount = 12;
00151 
00152 int quicktime_get_num_videocodecs() {
00153         return qtVideoCodecCount;
00154 }
00155 
00156 QuicktimeCodecTypeDesc* quicktime_get_videocodecType_desc(int indexValue) {
00157         if ((indexValue>=0) && (indexValue < qtVideoCodecCount))
00158                 return &qtVideoCodecList[indexValue];
00159         else
00160                 return NULL;
00161 }
00162 
00163 int quicktime_rnatmpvalue_from_videocodectype(int codecType) {
00164         int i;
00165         for (i=0;i<qtVideoCodecCount;i++) {
00166                 if (qtVideoCodecList[i].codecType == codecType)
00167                         return qtVideoCodecList[i].rnatmpvalue;
00168         }
00169         
00170         return 0;
00171 }
00172 
00173 int quicktime_videocodecType_from_rnatmpvalue(int rnatmpvalue) {
00174         int i;
00175         for (i=0;i<qtVideoCodecCount;i++) {
00176                 if (qtVideoCodecList[i].rnatmpvalue == rnatmpvalue)
00177                         return qtVideoCodecList[i].codecType;
00178         }
00179         
00180         return 0;       
00181 }
00182 
00183 
00184 
00185 static void CheckError(OSErr err, char *msg, ReportList *reports)
00186 {
00187         if(err != noErr) {
00188                 BKE_reportf(reports, RPT_ERROR, "%s: %d", msg, err);
00189         }
00190 }
00191 
00192 
00193 static OSErr QT_SaveCodecSettingsToScene(RenderData *rd, ReportList *reports)
00194 {       
00195         QTAtomContainer         myContainer = NULL;
00196         ComponentResult         myErr = noErr;
00197         Ptr                                     myPtr;
00198         long                            mySize = 0;
00199 
00200         CodecInfo                       ci;
00201 
00202         QuicktimeCodecData *qcd = rd->qtcodecdata;
00203         
00204         // check if current scene already has qtcodec settings, and clear them
00205         if (qcd) {
00206                 free_qtcodecdata(qcd);
00207         } else {
00208                 qcd = rd->qtcodecdata = MEM_callocN(sizeof(QuicktimeCodecData), "QuicktimeCodecData");
00209         }
00210 
00211         // obtain all current codec settings
00212         SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
00213         SCSetInfo(qtdata->theComponent, scSpatialSettingsType,  &qtdata->gSpatialSettings);
00214         SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
00215 
00216         // retreive codecdata from quicktime in a atomcontainer
00217         myErr = SCGetSettingsAsAtomContainer(qtdata->theComponent,  &myContainer);
00218         if (myErr != noErr) {
00219                 BKE_reportf(reports, RPT_ERROR, "Quicktime: SCGetSettingsAsAtomContainer failed\n"); 
00220                 goto bail;
00221         }
00222 
00223         // get the size of the atomcontainer
00224         mySize = GetHandleSize((Handle)myContainer);
00225 
00226         // lock and convert the atomcontainer to a *valid* pointer
00227         QTLockContainer(myContainer);
00228         myPtr = *(Handle)myContainer;
00229 
00230         // copy the Quicktime data into the blender qtcodecdata struct
00231         if (myPtr) {
00232                 qcd->cdParms = MEM_mallocN(mySize, "qt.cdParms");
00233                 memcpy(qcd->cdParms, myPtr, mySize);
00234                 qcd->cdSize = mySize;
00235 
00236                 GetCodecInfo (&ci, qtdata->gSpatialSettings.codecType, 0);
00237         } else {
00238                 BKE_reportf(reports, RPT_ERROR, "Quicktime: QT_SaveCodecSettingsToScene failed\n"); 
00239         }
00240 
00241         QTUnlockContainer(myContainer);
00242 
00243 bail:
00244         if (myContainer != NULL)
00245                 QTDisposeAtomContainer(myContainer);
00246                 
00247         return((OSErr)myErr);
00248 }
00249 
00250 
00251 static OSErr QT_GetCodecSettingsFromScene(RenderData *rd, ReportList *reports)
00252 {       
00253         Handle                          myHandle = NULL;
00254         ComponentResult         myErr = noErr;
00255 
00256         QuicktimeCodecData *qcd = rd->qtcodecdata;
00257 
00258         // if there is codecdata in the blendfile, convert it to a Quicktime handle 
00259         if (qcd) {
00260                 myHandle = NewHandle(qcd->cdSize);
00261                 PtrToHand( qcd->cdParms, &myHandle, qcd->cdSize);
00262         }
00263                 
00264         // restore codecsettings to the quicktime component
00265         if(qcd->cdParms && qcd->cdSize) {
00266                 myErr = SCSetSettingsFromAtomContainer((GraphicsExportComponent)qtdata->theComponent, (QTAtomContainer)myHandle);
00267                 if (myErr != noErr) {
00268                         BKE_reportf(reports, RPT_ERROR, "Quicktime: SCSetSettingsFromAtomContainer failed\n"); 
00269                         goto bail;
00270                 }
00271 
00272                 // update runtime codecsettings for use with the codec dialog
00273                 SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
00274                 SCGetInfo(qtdata->theComponent, scSpatialSettingsType,  &qtdata->gSpatialSettings);
00275                 SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
00276 
00277 
00278                 //Fill the render QuicktimeCodecSettigns struct
00279                 rd->qtcodecsettings.codecTemporalQuality = (qtdata->gTemporalSettings.temporalQuality * 100) / codecLosslessQuality;
00280                 //Do not override scene frame rate (qtdata->gTemporalSettings.framerate)
00281                 rd->qtcodecsettings.keyFrameRate = qtdata->gTemporalSettings.keyFrameRate;
00282                 
00283                 rd->qtcodecsettings.codecType = qtdata->gSpatialSettings.codecType;
00284                 rd->qtcodecsettings.codec = (int)qtdata->gSpatialSettings.codec;
00285                 rd->qtcodecsettings.colorDepth = qtdata->gSpatialSettings.depth;
00286                 rd->qtcodecsettings.codecSpatialQuality = (qtdata->gSpatialSettings.spatialQuality * 100) / codecLosslessQuality;
00287                 
00288                 rd->qtcodecsettings.bitRate = qtdata->aDataRateSetting.dataRate;
00289                 rd->qtcodecsettings.minSpatialQuality = (qtdata->aDataRateSetting.minSpatialQuality * 100) / codecLosslessQuality;
00290                 rd->qtcodecsettings.minTemporalQuality = (qtdata->aDataRateSetting.minTemporalQuality * 100) / codecLosslessQuality;
00291                 //Frame duration is already known (qtdata->aDataRateSetting.frameDuration)
00292                 
00293         } else {
00294                 BKE_reportf(reports, RPT_ERROR, "Quicktime: QT_GetCodecSettingsFromScene failed\n"); 
00295         }
00296 bail:
00297         if (myHandle != NULL)
00298                 DisposeHandle(myHandle);
00299                 
00300         return((OSErr)myErr);
00301 }
00302 
00303 
00304 static OSErr QT_AddUserDataTextToMovie (Movie theMovie, char *theText, OSType theType)
00305 {
00306         UserData                                        myUserData = NULL;
00307         Handle                                          myHandle = NULL;
00308         long                                            myLength = strlen(theText);
00309         OSErr                                           myErr = noErr;
00310 
00311         // get the movie's user data list
00312         myUserData = GetMovieUserData(theMovie);
00313         if (myUserData == NULL)
00314                 return(paramErr);
00315         
00316         // copy the specified text into a new handle
00317         myHandle = NewHandleClear(myLength);
00318         if (myHandle == NULL)
00319                 return(MemError());
00320 
00321         BlockMoveData(theText, *myHandle, myLength);
00322 
00323         // add the data to the movie's user data
00324         myErr = AddUserDataText(myUserData, myHandle, theType, 1, (short)GetScriptManagerVariable(smRegionCode));
00325 
00326         // clean up
00327         DisposeHandle(myHandle);
00328         return(myErr);
00329 }
00330 
00331 
00332 static void QT_CreateMyVideoTrack(int rectx, int recty, ReportList *reports)
00333 {
00334         OSErr err = noErr;
00335         Rect trackFrame;
00336 //      MatrixRecord myMatrix;
00337 
00338         trackFrame.top = 0;
00339         trackFrame.left = 0;
00340         trackFrame.bottom = recty;
00341         trackFrame.right = rectx;
00342         
00343         qtexport->theTrack = NewMovieTrack (qtexport->theMovie, 
00344                                                         FixRatio(trackFrame.right,1),
00345                                                         FixRatio(trackFrame.bottom,1), 
00346                                                         0);
00347         CheckError( GetMoviesError(), "NewMovieTrack error", reports );
00348 
00349 //      SetIdentityMatrix(&myMatrix);
00350 //      ScaleMatrix(&myMatrix, fixed1, Long2Fix(-1), 0, 0);
00351 //      TranslateMatrix(&myMatrix, 0, Long2Fix(trackFrame.bottom));
00352 //      SetMovieMatrix(qtexport->theMovie, &myMatrix);
00353 
00354         qtexport->theMedia = NewTrackMedia (qtexport->theTrack,
00355                                                         VideoMediaType,
00356                                                         qtdata->kVideoTimeScale,
00357                                                         nil,
00358                                                         0);
00359         CheckError( GetMoviesError(), "NewTrackMedia error", reports );
00360 
00361         err = BeginMediaEdits (qtexport->theMedia);
00362         CheckError( err, "BeginMediaEdits error", reports );
00363 
00364         QT_StartAddVideoSamplesToMedia (&trackFrame, rectx, recty, reports);
00365 } 
00366 
00367 
00368 static void QT_EndCreateMyVideoTrack(ReportList *reports)
00369 {
00370         OSErr err = noErr;
00371 
00372         QT_EndAddVideoSamplesToMedia ();
00373 
00374         err = EndMediaEdits (qtexport->theMedia);
00375         CheckError( err, "EndMediaEdits error", reports );
00376 
00377         err = InsertMediaIntoTrack (qtexport->theTrack,
00378                                                                 kTrackStart,/* track start time */
00379                                                                 kMediaStart,/* media start time */
00380                                                                 GetMediaDuration (qtexport->theMedia),
00381                                                                 fixed1);
00382         CheckError( err, "InsertMediaIntoTrack error", reports );
00383 } 
00384 
00385 
00386 static void QT_StartAddVideoSamplesToMedia (const Rect *trackFrame, int rectx, int recty, ReportList *reports)
00387 {
00388         SCTemporalSettings gTemporalSettings;
00389         OSErr err = noErr;
00390 
00391         qtexport->ibuf = IMB_allocImBuf (rectx, recty, 32, IB_rect);
00392         qtexport->ibuf2 = IMB_allocImBuf (rectx, recty, 32, IB_rect);
00393 
00394         err = NewGWorldFromPtr( &qtexport->theGWorld,
00395                                                         k32ARGBPixelFormat,
00396                                                         trackFrame,
00397                                                         NULL, NULL, 0,
00398                                                         (Ptr)qtexport->ibuf->rect,
00399                                                         rectx * 4 );
00400         CheckError (err, "NewGWorldFromPtr error", reports);
00401 
00402         qtexport->thePixMap = GetGWorldPixMap(qtexport->theGWorld);
00403         LockPixels(qtexport->thePixMap);
00404 
00405         SCDefaultPixMapSettings (qtdata->theComponent, qtexport->thePixMap, true);
00406 
00407         // workaround for crash with H.264, which requires an upgrade to
00408         // the new callback based api for proper encoding, but that's not
00409         // really compatible with rendering out frames sequentially
00410         gTemporalSettings = qtdata->gTemporalSettings;
00411         if(qtdata->gSpatialSettings.codecType == kH264CodecType) {
00412                 if(gTemporalSettings.temporalQuality != codecMinQuality) {
00413                         BKE_reportf(reports, RPT_WARNING, "Only minimum quality compression supported for QuickTime H.264.\n");
00414                         gTemporalSettings.temporalQuality = codecMinQuality;
00415                 }
00416         }
00417 
00418         SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &gTemporalSettings);
00419         SCSetInfo(qtdata->theComponent, scSpatialSettingsType,  &qtdata->gSpatialSettings);
00420         SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
00421 
00422         err = SCCompressSequenceBegin(qtdata->theComponent, qtexport->thePixMap, NULL, &qtexport->anImageDescription); 
00423         CheckError (err, "SCCompressSequenceBegin error", reports );
00424 }
00425 
00426 
00427 static void QT_DoAddVideoSamplesToMedia (int frame, int *pixels, int rectx, int recty, ReportList *reports)
00428 {
00429         OSErr   err = noErr;
00430         Rect    imageRect;
00431 
00432         int             index;
00433         int             boxsize;
00434         unsigned char *from, *to;
00435 
00436         short   syncFlag;
00437         long    dataSize;
00438         Handle  compressedData;
00439         Ptr             myPtr;
00440 
00441 
00442         //copy and flip renderdata
00443         memcpy(qtexport->ibuf2->rect, pixels, 4*rectx*recty);
00444         IMB_flipy(qtexport->ibuf2);
00445 
00446         //get pointers to parse bitmapdata
00447         myPtr = GetPixBaseAddr(qtexport->thePixMap);
00448         imageRect = (**qtexport->thePixMap).bounds;
00449 
00450         from = (unsigned char *) qtexport->ibuf2->rect;
00451         to = (unsigned char *) myPtr;
00452 
00453         //parse RGBA bitmap into Quicktime's ARGB GWorld
00454         boxsize = rectx * recty;
00455         for( index = 0; index < boxsize; index++) {
00456                 to[0] = from[3];
00457                 to[1] = from[0];
00458                 to[2] = from[1];
00459                 to[3] = from[2];
00460                 to +=4, from += 4;
00461         }
00462 
00463         err = SCCompressSequenceFrame(qtdata->theComponent,
00464                 qtexport->thePixMap,
00465                 &imageRect,
00466                 &compressedData,
00467                 &dataSize,
00468                 &syncFlag);
00469         CheckError(err, "SCCompressSequenceFrame error", reports);
00470 
00471         err = AddMediaSample(qtexport->theMedia,
00472                 compressedData,
00473                 0,
00474                 dataSize,
00475                 qtdata->duration,
00476                 (SampleDescriptionHandle)qtexport->anImageDescription,
00477                 1,
00478                 syncFlag,
00479                 NULL);
00480         CheckError(err, "AddMediaSample error", reports);
00481 }
00482 
00483 
00484 static void QT_EndAddVideoSamplesToMedia (void)
00485 {
00486         SCCompressSequenceEnd(qtdata->theComponent);
00487 
00488         UnlockPixels(qtexport->thePixMap);
00489         if (qtexport->theGWorld)
00490                 DisposeGWorld (qtexport->theGWorld);
00491 
00492         if (qtexport->ibuf)
00493                 IMB_freeImBuf(qtexport->ibuf);
00494 
00495         if (qtexport->ibuf2)
00496                 IMB_freeImBuf(qtexport->ibuf2);
00497 } 
00498 
00499 
00500 void filepath_qt(char *string, RenderData *rd) {
00501         char txt[64];
00502 
00503         if (string==0) return;
00504 
00505         strcpy(string, rd->pic);
00506         BLI_path_abs(string, G.main->name);
00507 
00508         BLI_make_existing_file(string);
00509 
00510         if (BLI_strcasecmp(string + strlen(string) - 4, ".mov")) {
00511                 sprintf(txt, "%04d_%04d.mov", (rd->sfra) , (rd->efra) );
00512                 strcat(string, txt);
00513         }
00514 }
00515 
00516 
00517 int start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty, ReportList *reports) {
00518         OSErr err = noErr;
00519 
00520         char name[2048];
00521         char theFullPath[255];
00522 
00523 #ifdef __APPLE__
00524         int             myFile;
00525         FSRef   myRef;
00526 #else
00527         char    *qtname;
00528 #endif
00529         int success= 1;
00530 
00531         if(qtexport == NULL) qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport");
00532 
00533         if(qtdata) {
00534                 if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
00535                 free_qtcomponentdata();
00536         }
00537 
00538         qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeCodecDataExt");
00539 
00540         if(rd->qtcodecdata == NULL || rd->qtcodecdata->cdParms == NULL) {
00541                 get_qtcodec_settings(rd, reports);
00542         } else {
00543                 qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
00544 
00545                 QT_GetCodecSettingsFromScene(rd, reports);
00546                 check_renderbutton_framerate(rd, reports);
00547         }
00548         
00549         sframe = (rd->sfra);
00550 
00551         filepath_qt(name, rd);
00552 
00553 #ifdef __APPLE__
00554         EnterMoviesOnThread(0);
00555         sprintf(theFullPath, "%s", name);
00556 
00557         /* hack: create an empty file to make FSPathMakeRef() happy */
00558         myFile = open(theFullPath, O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRUSR|S_IWUSR);
00559         if (myFile < 0) {
00560                 BKE_reportf(reports, RPT_ERROR, "error while creating movie file!\n");
00561                 /* do something? */
00562         }
00563         close(myFile);
00564         err = FSPathMakeRef((const UInt8 *)theFullPath, &myRef, 0);
00565         CheckError(err, "FsPathMakeRef error", reports);
00566         err = FSGetCatalogInfo(&myRef, kFSCatInfoNone, NULL, NULL, &qtexport->theSpec, NULL);
00567         CheckError(err, "FsGetCatalogInfoRef error", reports);
00568 #endif
00569 #ifdef _WIN32
00570         qtname = get_valid_qtname(name);
00571         sprintf(theFullPath, "%s", qtname);
00572         strcpy(name, qtname);
00573         MEM_freeN(qtname);
00574         
00575         CopyCStringToPascal(theFullPath, qtexport->qtfilename);
00576         err = FSMakeFSSpec(0, 0L, qtexport->qtfilename, &qtexport->theSpec);
00577 #endif
00578 
00579         err = CreateMovieFile (&qtexport->theSpec, 
00580                                                 kMyCreatorType,
00581                                                 smCurrentScript, 
00582                                                 createMovieFileDeleteCurFile | createMovieFileDontCreateResFile,
00583                                                 &qtexport->resRefNum, 
00584                                                 &qtexport->theMovie );
00585         CheckError(err, "CreateMovieFile error", reports);
00586 
00587         if(err != noErr) {
00588                 BKE_reportf(reports, RPT_ERROR, "Unable to create Quicktime movie: %s", name);
00589                 success= 0;
00590 #ifdef __APPLE__
00591                 ExitMoviesOnThread();
00592 #endif
00593         } else {
00594                 //printf("Created QuickTime movie: %s\n", name);
00595 
00596                 QT_CreateMyVideoTrack(rectx, recty, reports);
00597         }
00598 
00599         return success;
00600 }
00601 
00602 
00603 int append_qt(struct RenderData *rd, int frame, int *pixels, int rectx, int recty, ReportList *reports) {
00604         QT_DoAddVideoSamplesToMedia(frame, pixels, rectx, recty, reports);
00605         return 1;
00606 }
00607 
00608 
00609 void end_qt(void) {
00610         OSErr err = noErr;
00611         short resId = movieInDataForkResID;
00612 
00613         if(qtexport->theMovie) {
00614                 QT_EndCreateMyVideoTrack(NULL);
00615 
00616                 err = AddMovieResource (qtexport->theMovie, qtexport->resRefNum, &resId, qtexport->qtfilename);
00617                 CheckError(err, "AddMovieResource error", NULL);
00618 
00619                 err = QT_AddUserDataTextToMovie(qtexport->theMovie, "Made with Blender", kUserDataTextInformation);
00620                 CheckError(err, "AddUserDataTextToMovie error", NULL);
00621 
00622                 err = UpdateMovieResource(qtexport->theMovie, qtexport->resRefNum, resId, qtexport->qtfilename);
00623                 CheckError(err, "UpdateMovieResource error", NULL);
00624 
00625                 if(qtexport->resRefNum) CloseMovieFile(qtexport->resRefNum);
00626 
00627                 DisposeMovie(qtexport->theMovie);
00628 
00629                 //printf("Finished QuickTime movie.\n");
00630         }
00631 
00632 #ifdef __APPLE__
00633                 ExitMoviesOnThread();
00634 #endif
00635         
00636         if(qtexport) {
00637                 MEM_freeN(qtexport);
00638                 qtexport = NULL;
00639         }
00640 }
00641 
00642 
00643 void free_qtcomponentdata(void) {
00644         if(qtdata) {
00645                 if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
00646                 MEM_freeN(qtdata);
00647                 qtdata = NULL;
00648         }
00649 }
00650 
00651 
00652 static void check_renderbutton_framerate(RenderData *rd, ReportList *reports) 
00653 {
00654         // to keep float framerates consistent between the codec dialog and frs/sec button.
00655         OSErr   err;    
00656 
00657         err = SCGetInfo(qtdata->theComponent, scTemporalSettingsType,   &qtdata->gTemporalSettings);
00658         CheckError(err, "SCGetInfo fr error", reports);
00659 
00660         if( (rd->frs_sec == 24 || rd->frs_sec == 30 || rd->frs_sec == 60) &&
00661                 (qtdata->gTemporalSettings.frameRate == 1571553 ||
00662                  qtdata->gTemporalSettings.frameRate == 1964113 ||
00663                  qtdata->gTemporalSettings.frameRate == 3928227)) {;} 
00664         else {
00665                 if (rd->frs_sec_base > 0)
00666                         qtdata->gTemporalSettings.frameRate = 
00667                         ((float)(rd->frs_sec << 16) / rd->frs_sec_base) ;
00668         }
00669         
00670         err = SCSetInfo(qtdata->theComponent, scTemporalSettingsType,   &qtdata->gTemporalSettings);
00671         CheckError( err, "SCSetInfo error", reports );
00672 
00673         if(qtdata->gTemporalSettings.frameRate == 1571553) {                    // 23.98 fps
00674                 qtdata->kVideoTimeScale = 24000;
00675                 qtdata->duration = 1001;
00676         } else if (qtdata->gTemporalSettings.frameRate == 1964113) {    // 29.97 fps
00677                 qtdata->kVideoTimeScale = 30000;
00678                 qtdata->duration = 1001;
00679         } else if (qtdata->gTemporalSettings.frameRate == 3928227) {    // 59.94 fps
00680                 qtdata->kVideoTimeScale = 60000;
00681                 qtdata->duration = 1001;
00682         } else {
00683                 qtdata->kVideoTimeScale = (qtdata->gTemporalSettings.frameRate >> 16) * 100;
00684                 qtdata->duration = 100;
00685         }
00686 }
00687 
00688 void quicktime_verify_image_type(RenderData *rd)
00689 {
00690         if (rd->imtype == R_QUICKTIME) {
00691                 if ((rd->qtcodecsettings.codecType== 0) ||
00692                         (rd->qtcodecsettings.codecSpatialQuality <0) ||
00693                         (rd->qtcodecsettings.codecSpatialQuality > 100)) {
00694                         
00695                         rd->qtcodecsettings.codecType = kJPEGCodecType;
00696                         rd->qtcodecsettings.codec = (int)anyCodec;
00697                         rd->qtcodecsettings.codecSpatialQuality = (codecHighQuality*100)/codecLosslessQuality;
00698                         rd->qtcodecsettings.codecTemporalQuality = (codecHighQuality*100)/codecLosslessQuality;
00699                         rd->qtcodecsettings.keyFrameRate = 25;
00700                         rd->qtcodecsettings.bitRate = 5000000; //5 Mbps
00701                 }
00702         }
00703 }
00704 
00705 int get_qtcodec_settings(RenderData *rd, ReportList *reports) 
00706 {
00707         OSErr err = noErr;
00708                 // erase any existing codecsetting
00709         if(qtdata) {
00710                 if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
00711                 free_qtcomponentdata();
00712         }
00713 
00714         // allocate new
00715         qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeComponentData");
00716         qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
00717 
00718         // get previous selected codecsetting, from qtatom or detailed settings
00719         if(rd->qtcodecdata && rd->qtcodecdata->cdParms) {
00720                 QT_GetCodecSettingsFromScene(rd, reports);
00721         } else {
00722                 SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
00723                 SCGetInfo(qtdata->theComponent, scSpatialSettingsType,  &qtdata->gSpatialSettings);
00724                 SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
00725 
00726                 qtdata->gSpatialSettings.codecType = rd->qtcodecsettings.codecType;
00727                 qtdata->gSpatialSettings.codec = (CodecComponent)rd->qtcodecsettings.codec;      
00728                 qtdata->gSpatialSettings.spatialQuality = (rd->qtcodecsettings.codecSpatialQuality * codecLosslessQuality) /100;
00729                 qtdata->gTemporalSettings.temporalQuality = (rd->qtcodecsettings.codecTemporalQuality * codecLosslessQuality) /100;
00730                 qtdata->gTemporalSettings.keyFrameRate = rd->qtcodecsettings.keyFrameRate;   
00731                 qtdata->aDataRateSetting.dataRate = rd->qtcodecsettings.bitRate;
00732                 qtdata->gSpatialSettings.depth = rd->qtcodecsettings.colorDepth;
00733                 qtdata->aDataRateSetting.minSpatialQuality = (rd->qtcodecsettings.minSpatialQuality * codecLosslessQuality) / 100;
00734                 qtdata->aDataRateSetting.minTemporalQuality = (rd->qtcodecsettings.minTemporalQuality * codecLosslessQuality) / 100;
00735                 
00736                 qtdata->aDataRateSetting.frameDuration = rd->frs_sec;
00737                 SetMovieTimeScale(qtexport->theMovie, rd->frs_sec_base*1000);
00738                 
00739                 
00740                 err = SCSetInfo(qtdata->theComponent, scTemporalSettingsType,   &qtdata->gTemporalSettings);
00741                 CheckError(err, "SCSetInfo1 error", reports);
00742                 err = SCSetInfo(qtdata->theComponent, scSpatialSettingsType,    &qtdata->gSpatialSettings);
00743                 CheckError(err, "SCSetInfo2 error", reports);
00744                 err = SCSetInfo(qtdata->theComponent, scDataRateSettingsType,   &qtdata->aDataRateSetting);
00745                 CheckError(err, "SCSetInfo3 error", reports);
00746         }
00747 
00748         check_renderbutton_framerate(rd, reports);
00749         
00750         return err;
00751 }
00752 
00753 static int request_qtcodec_settings(bContext *C, wmOperator *op)
00754 {
00755         OSErr   err = noErr;
00756         Scene *scene = CTX_data_scene(C);
00757         RenderData *rd = &scene->r;
00758 
00759         // erase any existing codecsetting
00760         if(qtdata) {
00761                 if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
00762                 free_qtcomponentdata();
00763         }
00764         
00765         // allocate new
00766         qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeComponentData");
00767         qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
00768         
00769         // get previous selected codecsetting, from qtatom or detailed settings
00770         if(rd->qtcodecdata && rd->qtcodecdata->cdParms) {
00771                 QT_GetCodecSettingsFromScene(rd, op->reports);
00772         } else {
00773                 SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
00774                 SCGetInfo(qtdata->theComponent, scSpatialSettingsType,  &qtdata->gSpatialSettings);
00775                 SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
00776                 
00777                 qtdata->gSpatialSettings.codecType = rd->qtcodecsettings.codecType;
00778                 qtdata->gSpatialSettings.codec = (CodecComponent)rd->qtcodecsettings.codec;      
00779                 qtdata->gSpatialSettings.spatialQuality = (rd->qtcodecsettings.codecSpatialQuality * codecLosslessQuality) /100;
00780                 qtdata->gTemporalSettings.temporalQuality = (rd->qtcodecsettings.codecTemporalQuality * codecLosslessQuality) /100;
00781                 qtdata->gTemporalSettings.keyFrameRate = rd->qtcodecsettings.keyFrameRate;
00782                 qtdata->gTemporalSettings.frameRate = ((float)(rd->frs_sec << 16) / rd->frs_sec_base);
00783                 qtdata->aDataRateSetting.dataRate = rd->qtcodecsettings.bitRate;
00784                 qtdata->gSpatialSettings.depth = rd->qtcodecsettings.colorDepth;
00785                 qtdata->aDataRateSetting.minSpatialQuality = (rd->qtcodecsettings.minSpatialQuality * codecLosslessQuality) / 100;
00786                 qtdata->aDataRateSetting.minTemporalQuality = (rd->qtcodecsettings.minTemporalQuality * codecLosslessQuality) / 100;
00787                 
00788                 qtdata->aDataRateSetting.frameDuration = rd->frs_sec;           
00789                 
00790                 err = SCSetInfo(qtdata->theComponent, scTemporalSettingsType,   &qtdata->gTemporalSettings);
00791                 CheckError(err, "SCSetInfo1 error", op->reports);
00792                 err = SCSetInfo(qtdata->theComponent, scSpatialSettingsType,    &qtdata->gSpatialSettings);
00793                 CheckError(err, "SCSetInfo2 error", op->reports);
00794                 err = SCSetInfo(qtdata->theComponent, scDataRateSettingsType,   &qtdata->aDataRateSetting);
00795                 CheckError(err, "SCSetInfo3 error", op->reports);
00796         }
00797                 // put up the dialog box - it needs to be called from the main thread
00798         err = SCRequestSequenceSettings(qtdata->theComponent);
00799  
00800         if (err == scUserCancelled) {
00801                 return OPERATOR_FINISHED;
00802         }
00803 
00804                 // update runtime codecsettings for use with the codec dialog
00805         SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
00806         SCGetInfo(qtdata->theComponent, scSpatialSettingsType,  &qtdata->gSpatialSettings);
00807         SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
00808         
00809         
00810                 //Fill the render QuicktimeCodecSettings struct
00811         rd->qtcodecsettings.codecTemporalQuality = (qtdata->gTemporalSettings.temporalQuality * 100) / codecLosslessQuality;
00812                 //Do not override scene frame rate (qtdata->gTemporalSettings.framerate)
00813         rd->qtcodecsettings.keyFrameRate = qtdata->gTemporalSettings.keyFrameRate;
00814         
00815         rd->qtcodecsettings.codecType = qtdata->gSpatialSettings.codecType;
00816         rd->qtcodecsettings.codec = (int)qtdata->gSpatialSettings.codec;
00817         rd->qtcodecsettings.colorDepth = qtdata->gSpatialSettings.depth;
00818         rd->qtcodecsettings.codecSpatialQuality = (qtdata->gSpatialSettings.spatialQuality * 100) / codecLosslessQuality;
00819         
00820         rd->qtcodecsettings.bitRate = qtdata->aDataRateSetting.dataRate;
00821         rd->qtcodecsettings.minSpatialQuality = (qtdata->aDataRateSetting.minSpatialQuality * 100) / codecLosslessQuality;
00822         rd->qtcodecsettings.minTemporalQuality = (qtdata->aDataRateSetting.minTemporalQuality * 100) / codecLosslessQuality;
00823                 //Frame duration is already known (qtdata->aDataRateSetting.frameDuration)
00824         
00825         QT_SaveCodecSettingsToScene(rd, op->reports);
00826 
00827         // framerate jugglin'
00828         if(qtdata->gTemporalSettings.frameRate == 1571553) {                    // 23.98 fps
00829                 qtdata->kVideoTimeScale = 24000;
00830                 qtdata->duration = 1001;
00831 
00832                 rd->frs_sec = 24;
00833                 rd->frs_sec_base = 1.001;
00834         } else if (qtdata->gTemporalSettings.frameRate == 1964113) {    // 29.97 fps
00835                 qtdata->kVideoTimeScale = 30000;
00836                 qtdata->duration = 1001;
00837 
00838                 rd->frs_sec = 30;
00839                 rd->frs_sec_base = 1.001;
00840         } else if (qtdata->gTemporalSettings.frameRate == 3928227) {    // 59.94 fps
00841                 qtdata->kVideoTimeScale = 60000;
00842                 qtdata->duration = 1001;
00843 
00844                 rd->frs_sec = 60;
00845                 rd->frs_sec_base = 1.001;
00846         } else {
00847                 double fps = qtdata->gTemporalSettings.frameRate;
00848 
00849                 qtdata->kVideoTimeScale = 60000;
00850                 qtdata->duration = qtdata->kVideoTimeScale / (qtdata->gTemporalSettings.frameRate / 65536);
00851 
00852                 if ((qtdata->gTemporalSettings.frameRate & 0xffff) == 0) {
00853                         rd->frs_sec = fps / 65536;
00854                         rd->frs_sec_base = 1.0;
00855                 } else {
00856                         /* we do our very best... */
00857                         rd->frs_sec = fps  / 65536;
00858                         rd->frs_sec_base = 1.0;
00859                 }
00860         }
00861 
00862         return OPERATOR_FINISHED;
00863 }
00864 
00865 static int ED_operator_setqtcodec(bContext *C)
00866 {
00867         return G.have_quicktime != FALSE;
00868 }
00869 
00870 #if defined(__APPLE__) && defined(GHOST_COCOA)
00871 //Need to set up a Cocoa NSAutoReleasePool to avoid memory leak
00872 //And it must be done in an objC file, so use a GHOST_SystemCocoa.mm function for that
00873 extern int cocoa_request_qtcodec_settings(bContext *C, wmOperator *op);
00874 
00875 int fromcocoa_request_qtcodec_settings(bContext *C, wmOperator *op)
00876 {
00877         return request_qtcodec_settings(C, op);
00878 }
00879 #endif
00880 
00881 
00882 void SCENE_OT_render_data_set_quicktime_codec(wmOperatorType *ot)
00883 {
00884         /* identifiers */
00885         ot->name= "Change codec";
00886         ot->description= "Change Quicktime codec Settings";
00887         ot->idname= "SCENE_OT_render_data_set_quicktime_codec";
00888         
00889         /* api callbacks */
00890 #if defined(__APPLE__) && defined(GHOST_COCOA)
00891         ot->exec = cocoa_request_qtcodec_settings;
00892 #else
00893         ot->exec= request_qtcodec_settings;
00894 #endif
00895         ot->poll= ED_operator_setqtcodec;
00896         
00897         /* flags */
00898         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00899 }
00900 
00901 #endif /* USE_QTKIT */
00902 #endif /* _WIN32 || __APPLE__ */
00903 #endif /* WITH_QUICKTIME */
00904