|
Blender
V2.59
|
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