Blender V2.61 - r43446
|
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