Blender V2.61 - r43446

quicktime_export.c

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