141
104
TimeValue duration;
142
105
long kVideoTimeScale;
144
} QuicktimeCodecDataExt; //qtopts
147
struct _QuicktimeExport *qte;
148
struct _QuicktimeCodecDataExt *qcdx;
150
/************************************************************
154
*************************************************************/
156
#define kMyCreatorType FOUR_CHAR_CODE('TVOD')
157
#define kPixelDepth 32 /* use 32-bit depth */
158
#define kTrackStart 0
159
#define kMediaStart 0
107
} QuicktimeComponentData;
109
static struct QuicktimeExport *qtexport;
110
static struct QuicktimeComponentData *qtdata;
161
112
static int sframe;
162
static char qtcdname[128];
165
/************************************************************
167
* SaveExporterSettingsToMem *
169
*************************************************************/
171
OSErr SaveExporterSettingsToMem (QuicktimeCodecData *qcd)
115
static void CheckError(OSErr err, char *msg)
117
if(err != noErr) printf("%s: %d\n", msg, err);
121
static OSErr QT_SaveCodecSettingsToScene(void)
173
123
QTAtomContainer myContainer = NULL;
174
124
ComponentResult myErr = noErr;
178
// check if current scene already has qtcodec settings, and erase them
131
QuicktimeCodecData *qcd = G.scene->r.qtcodecdata;
133
// check if current scene already has qtcodec settings, and clear them
180
135
free_qtcodecdata(qcd);
242
197
// restore codecsettings to the quicktime component
243
198
if(qcd->cdParms && qcd->cdSize) {
244
myErr = SCSetSettingsFromAtomContainer((GraphicsExportComponent)qcdx->theComponent, (QTAtomContainer)myHandle);
199
myErr = SCSetSettingsFromAtomContainer((GraphicsExportComponent)qtdata->theComponent, (QTAtomContainer)myHandle);
245
200
if (myErr != noErr) {
246
201
printf("Quicktime: SCSetSettingsFromAtomContainer failed\n");
250
205
// update runtime codecsettings for use with the codec dialog
251
SCGetInfo(qcdx->theComponent, scDataRateSettingsType, &qcdx->aDataRateSetting);
252
SCGetInfo(qcdx->theComponent, scSpatialSettingsType, &qcdx->gSpatialSettings);
253
SCGetInfo(qcdx->theComponent, scTemporalSettingsType, &qcdx->gTemporalSettings);
206
SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
207
SCGetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
208
SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
255
// GetCodecInfo (&ci, qcdx->gSpatialSettings.codecType, 0);
210
// GetCodecInfo (&ci, qtdata->gSpatialSettings.codecType, 0);
256
211
// CopyPascalStringToC(ci.typeName, str);
257
212
// printf("restored Codec: %s\n", str);
259
printf("Quicktime: GetExporterSettingsFromMem failed\n");
214
printf("Quicktime: QT_GetCodecSettingsFromScene failed\n");
262
217
if (myHandle != NULL)
269
/************************************************************
271
* CheckError(OSErr err, char *msg) *
273
* prints errors in console, doesnt interrupt Blender *
275
*************************************************************/
277
void CheckError(OSErr err, char *msg)
224
static OSErr QT_AddUserDataTextToMovie (Movie theMovie, char *theText, OSType theType)
279
if(err != noErr) printf("%s: %d\n", msg, err);
226
UserData myUserData = NULL;
227
Handle myHandle = NULL;
228
long myLength = strlen(theText);
231
// get the movie's user data list
232
myUserData = GetMovieUserData(theMovie);
233
if (myUserData == NULL)
236
// copy the specified text into a new handle
237
myHandle = NewHandleClear(myLength);
238
if (myHandle == NULL)
241
BlockMoveData(theText, *myHandle, myLength);
243
// add the data to the movie's user data
244
myErr = AddUserDataText(myUserData, myHandle, theType, 1, (short)GetScriptManagerVariable(smRegionCode));
247
DisposeHandle(myHandle);
283
/************************************************************
285
* QT_CreateMyVideoTrack() *
286
* QT_EndCreateMyVideoTrack() *
288
* Creates/finishes a video track for the QuickTime movie *
290
*************************************************************/
292
252
static void QT_CreateMyVideoTrack(void)
294
254
OSErr err = noErr;
256
// MatrixRecord myMatrix;
297
258
trackFrame.top = 0;
298
259
trackFrame.left = 0;
299
260
trackFrame.bottom = R.recty;
300
261
trackFrame.right = R.rectx;
302
qte->theTrack = NewMovieTrack (qte->theMovie,
263
qtexport->theTrack = NewMovieTrack (qtexport->theMovie,
303
264
FixRatio(trackFrame.right,1),
304
265
FixRatio(trackFrame.bottom,1),
306
267
CheckError( GetMoviesError(), "NewMovieTrack error" );
308
qte->theMedia = NewTrackMedia (qte->theTrack,
269
// SetIdentityMatrix(&myMatrix);
270
// ScaleMatrix(&myMatrix, fixed1, Long2Fix(-1), 0, 0);
271
// TranslateMatrix(&myMatrix, 0, Long2Fix(trackFrame.bottom));
272
// SetMovieMatrix(qtexport->theMovie, &myMatrix);
274
qtexport->theMedia = NewTrackMedia (qtexport->theTrack,
310
qcdx->kVideoTimeScale,
276
qtdata->kVideoTimeScale,
313
279
CheckError( GetMoviesError(), "NewTrackMedia error" );
315
err = BeginMediaEdits (qte->theMedia);
281
err = BeginMediaEdits (qtexport->theMedia);
316
282
CheckError( err, "BeginMediaEdits error" );
318
284
QT_StartAddVideoSamplesToMedia (&trackFrame);
326
292
QT_EndAddVideoSamplesToMedia ();
328
err = EndMediaEdits (qte->theMedia);
294
err = EndMediaEdits (qtexport->theMedia);
329
295
CheckError( err, "EndMediaEdits error" );
331
err = InsertMediaIntoTrack (qte->theTrack,
297
err = InsertMediaIntoTrack (qtexport->theTrack,
332
298
kTrackStart,/* track start time */
333
299
kMediaStart,/* media start time */
334
GetMediaDuration (qte->theMedia),
300
GetMediaDuration (qtexport->theMedia),
336
302
CheckError( err, "InsertMediaIntoTrack error" );
340
/************************************************************
342
* QT_StartAddVideoSamplesToMedia() *
343
* QT_DoAddVideoSamplesToMedia() *
344
* QT_EndAddVideoSamplesToMedia() *
346
* Creates video samples for the media in a track *
348
*************************************************************/
350
306
static void QT_StartAddVideoSamplesToMedia (const Rect *trackFrame)
352
308
OSErr err = noErr;
354
qte->ibuf = IMB_allocImBuf (R.rectx, R.recty, 32, IB_rect, 0);
355
qte->ibuf2 = IMB_allocImBuf (R.rectx, R.recty, 32, IB_rect, 0);
310
qtexport->ibuf = IMB_allocImBuf (R.rectx, R.recty, 32, IB_rect, 0);
311
qtexport->ibuf2 = IMB_allocImBuf (R.rectx, R.recty, 32, IB_rect, 0);
357
err = NewGWorldFromPtr( &qte->theGWorld,
313
err = NewGWorldFromPtr( &qtexport->theGWorld,
358
314
k32ARGBPixelFormat,
361
(unsigned char *)qte->ibuf->rect,
317
(unsigned char *)qtexport->ibuf->rect,
363
319
CheckError (err, "NewGWorldFromPtr error");
365
qte->thePixMap = GetGWorldPixMap(qte->theGWorld);
366
LockPixels(qte->thePixMap);
368
SCDefaultPixMapSettings (qcdx->theComponent, qte->thePixMap, true);
370
SCSetInfo(qcdx->theComponent, scTemporalSettingsType, &qcdx->gTemporalSettings);
371
SCSetInfo(qcdx->theComponent, scSpatialSettingsType, &qcdx->gSpatialSettings);
372
SCSetInfo(qcdx->theComponent, scDataRateSettingsType, &qcdx->aDataRateSetting);
374
err = SCCompressSequenceBegin(qcdx->theComponent, qte->thePixMap, NULL, &qte->anImageDescription);
321
qtexport->thePixMap = GetGWorldPixMap(qtexport->theGWorld);
322
LockPixels(qtexport->thePixMap);
324
SCDefaultPixMapSettings (qtdata->theComponent, qtexport->thePixMap, true);
326
SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
327
SCSetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
328
SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
330
err = SCCompressSequenceBegin(qtdata->theComponent, qtexport->thePixMap, NULL, &qtexport->anImageDescription);
375
331
CheckError (err, "SCCompressSequenceBegin error" );
381
337
OSErr err = noErr;
385
register int boxsize;
386
register uint32_t *readPos;
387
register uint32_t *changePos;
342
unsigned char *from, *to;
392
346
Handle compressedData;
394
// copy and flip the renderdata
396
memcpy(qte->ibuf2->rect, R.rectot, 4*R.rectx*R.recty);
397
IMB_flipy(qte->ibuf2);
400
//get pointers to parse bitmapdata
401
myPtr = GetPixBaseAddr(qte->thePixMap);
402
imageRect = (**qte->thePixMap).bounds;
350
//copy and flip renderdata
351
memcpy(qtexport->ibuf2->rect, R.rectot, 4*R.rectx*R.recty);
352
IMB_flipy(qtexport->ibuf2);
354
//get pointers to parse bitmapdata
355
myPtr = GetPixBaseAddr(qtexport->thePixMap);
356
imageRect = (**qtexport->thePixMap).bounds;
358
from = (unsigned char *) qtexport->ibuf2->rect;
359
to = (unsigned char *) myPtr;
361
//parse RGBA bitmap into Quicktime's ARGB GWorld
404
362
boxsize = R.rectx * R.recty;
405
readPos = (uint32_t *) qte->ibuf2->rect;
406
changePos = (uint32_t *) myPtr;
409
// Swap alpha byte to the end, so ARGB become RGBA; note this is big endian-centric.
410
for( index = 0; index < boxsize; index++, changePos++, readPos++ )
411
*( changePos ) = ( ( *readPos & 0xFFFFFFFF ) >> 8 ) |
412
( ( *readPos << 24 ) & 0xFF );
416
// poked around a little... this seems to work for windows, dunno if it's legal
417
for( index = 0; index < boxsize; index++, changePos++, readPos++ )
418
*( changePos ) = ( ( *readPos & 0xFFFFFFFF ) << 8 ) |
419
( ( *readPos >> 24 ) & 0xFF ); // & ( ( *readPos << 8 ) & 0xFF );
422
err = SCCompressSequenceFrame(qcdx->theComponent,
363
for( index = 0; index < boxsize; index++) {
371
err = SCCompressSequenceFrame(qtdata->theComponent,
428
377
CheckError(err, "SCCompressSequenceFrame error");
430
err = AddMediaSample(qte->theMedia,
379
err = AddMediaSample(qtexport->theMedia,
435
(SampleDescriptionHandle)qte->anImageDescription,
384
(SampleDescriptionHandle)qtexport->anImageDescription,
535
473
err = FSPathMakeRef(theFullPath, &myRef, 0);
536
474
CheckError(err, "FsPathMakeRef error");
537
err = FSGetCatalogInfo(&myRef, kFSCatInfoNone, NULL, NULL, &qte->theSpec, NULL);
475
err = FSGetCatalogInfo(&myRef, kFSCatInfoNone, NULL, NULL, &qtexport->theSpec, NULL);
538
476
CheckError(err, "FsGetCatalogInfoRef error");
540
CopyCStringToPascal(theFullPath, qte->qtfilename);
541
err = FSMakeFSSpec(0, 0L, qte->qtfilename, &qte->theSpec);
479
qtname = get_valid_qtname(name);
480
sprintf(theFullPath, "%s", qtname);
481
strcpy(name, qtname);
484
CopyCStringToPascal(theFullPath, qtexport->qtfilename);
485
err = FSMakeFSSpec(0, 0L, qtexport->qtfilename, &qtexport->theSpec);
544
err = CreateMovieFile (&qte->theSpec,
488
err = CreateMovieFile (&qtexport->theSpec,
547
491
createMovieFileDeleteCurFile | createMovieFileDontCreateResFile,
492
&qtexport->resRefNum,
493
&qtexport->theMovie );
550
494
CheckError(err, "CreateMovieFile error");
552
printf("Created QuickTime movie: %s\n", name);
498
error("Unable to create Quicktime movie: %s\n", name);
500
printf("Created QuickTime movie: %s\n", name);
554
QT_CreateMyVideoTrack();
502
QT_CreateMyVideoTrack();
560
509
QT_DoAddVideoSamplesToMedia(frame);
563
513
void end_qt(void) {
564
514
OSErr err = noErr;
567
QT_EndCreateMyVideoTrack ();
569
qte->resId = movieInDataForkResID;
570
err = AddMovieResource (qte->theMovie, qte->resRefNum, &qte->resId, qte->qtfilename);
515
short resId = movieInDataForkResID;
517
if(qtexport->theMovie) {
518
QT_EndCreateMyVideoTrack();
520
err = AddMovieResource (qtexport->theMovie, qtexport->resRefNum, &resId, qtexport->qtfilename);
571
521
CheckError(err, "AddMovieResource error");
573
if (qte->resRefNum) CloseMovieFile (qte->resRefNum);
575
DisposeMovie (qte->theMovie);
585
/************************************************************
587
* free_qtcodecdataExt(void) *
589
* Function to release codec memory, since it remains *
590
* resident after allocation. *
592
*************************************************************/
594
void free_qtcodecdataExt(void) {
596
if(qcdx->theComponent) CloseComponent(qcdx->theComponent);
603
/************************************************************
605
* check_renderbutton_framerate ( void ) *
607
* To keep float framerates consistent between the codec *
608
* dialog and frs/sec button. *
610
*************************************************************/
523
err = QT_AddUserDataTextToMovie(qtexport->theMovie, "Made with Blender", kUserDataTextInformation);
524
CheckError(err, "AddUserDataTextToMovie error");
526
err = UpdateMovieResource(qtexport->theMovie, qtexport->resRefNum, resId, qtexport->qtfilename);
527
CheckError(err, "UpdateMovieResource error");
529
if(qtexport->resRefNum) CloseMovieFile(qtexport->resRefNum);
531
DisposeMovie(qtexport->theMovie);
533
printf("Finished QuickTime movie.\n");
543
void free_qtcomponentdata(void) {
545
if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
612
552
static void check_renderbutton_framerate(void) {
553
// to keep float framerates consistent between the codec dialog and frs/sec button.
615
err = SCGetInfo(qcdx->theComponent, scTemporalSettingsType, &qcdx->gTemporalSettings);
556
err = SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
616
557
CheckError(err, "SCGetInfo fr error");
618
559
if( (G.scene->r.frs_sec == 24 || G.scene->r.frs_sec == 30 || G.scene->r.frs_sec == 60) &&
619
(qcdx->gTemporalSettings.frameRate == 1571553 ||
620
qcdx->gTemporalSettings.frameRate == 1964113 ||
621
qcdx->gTemporalSettings.frameRate == 3928227)) {;} else
622
qcdx->gTemporalSettings.frameRate = G.scene->r.frs_sec << 16;
560
(qtdata->gTemporalSettings.frameRate == 1571553 ||
561
qtdata->gTemporalSettings.frameRate == 1964113 ||
562
qtdata->gTemporalSettings.frameRate == 3928227)) {;} else
563
qtdata->gTemporalSettings.frameRate = G.scene->r.frs_sec << 16;
624
err = SCSetInfo(qcdx->theComponent, scTemporalSettingsType, &qcdx->gTemporalSettings);
565
err = SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
625
566
CheckError( err, "SCSetInfo error" );
627
if(qcdx->gTemporalSettings.frameRate == 1571553) { // 23.98 fps
628
qcdx->kVideoTimeScale = 2398;
629
qcdx->duration = 100;
630
} else if (qcdx->gTemporalSettings.frameRate == 1964113) { // 29.97 fps
631
qcdx->kVideoTimeScale = 2997;
632
qcdx->duration = 100;
633
} else if (qcdx->gTemporalSettings.frameRate == 3928227) { // 59.94 fps
634
qcdx->kVideoTimeScale = 5994;
635
qcdx->duration = 100;
568
if(qtdata->gTemporalSettings.frameRate == 1571553) { // 23.98 fps
569
qtdata->kVideoTimeScale = 2398;
570
qtdata->duration = 100;
571
} else if (qtdata->gTemporalSettings.frameRate == 1964113) { // 29.97 fps
572
qtdata->kVideoTimeScale = 2997;
573
qtdata->duration = 100;
574
} else if (qtdata->gTemporalSettings.frameRate == 3928227) { // 59.94 fps
575
qtdata->kVideoTimeScale = 5994;
576
qtdata->duration = 100;
637
qcdx->kVideoTimeScale = (qcdx->gTemporalSettings.frameRate >> 16) * 100;
638
qcdx->duration = 100;
578
qtdata->kVideoTimeScale = (qtdata->gTemporalSettings.frameRate >> 16) * 100;
579
qtdata->duration = 100;
642
/********************************************************************
644
* get_qtcodec_settings() *
646
* Displays Codec Dialog and retrieves Quicktime Codec settings. *
648
********************************************************************/
650
584
int get_qtcodec_settings(void)
652
586
OSErr err = noErr;
656
588
// erase any existing codecsetting
658
if(qcdx->theComponent) CloseComponent(qcdx->theComponent);
659
free_qtcodecdataExt();
590
if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
591
free_qtcomponentdata();
663
qcdx = MEM_callocN(sizeof(QuicktimeCodecDataExt), "QuicktimeCodecDataExt");
664
qcdx->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
595
qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeComponentData");
596
qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
666
598
// get previous selected codecsetting, if any
667
599
if(G.scene->r.qtcodecdata && G.scene->r.qtcodecdata->cdParms) {
668
// printf("getting from MEM\n");
669
GetExporterSettingsFromMem (G.scene->r.qtcodecdata);
600
QT_GetCodecSettingsFromScene();
670
601
check_renderbutton_framerate();
673
// configure the standard image compression dialog box
674
// set some default settings
675
// qcdx->gSpatialSettings.codecType = nil;
676
qcdx->gSpatialSettings.codec = anyCodec;
677
// qcdx->gSpatialSettings.depth;
678
qcdx->gSpatialSettings.spatialQuality = codecMaxQuality;
680
qcdx->gTemporalSettings.temporalQuality = codecMaxQuality;
681
// qcdx->gTemporalSettings.frameRate;
682
qcdx->gTemporalSettings.keyFrameRate = 25;
684
qcdx->aDataRateSetting.dataRate = 90 * 1024;
685
// qcdx->aDataRateSetting.frameDuration;
686
// qcdx->aDataRateSetting.minSpatialQuality;
687
// qcdx->aDataRateSetting.minTemporalQuality;
689
err = SCSetInfo(qcdx->theComponent, scTemporalSettingsType, &qcdx->gTemporalSettings);
603
// configure the standard image compression dialog box
604
// set some default settings
605
qtdata->gSpatialSettings.codec = anyCodec;
606
qtdata->gSpatialSettings.spatialQuality = codecMaxQuality;
607
qtdata->gTemporalSettings.temporalQuality = codecMaxQuality;
608
qtdata->gTemporalSettings.keyFrameRate = 25;
609
qtdata->aDataRateSetting.dataRate = 90 * 1024;
611
err = SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
690
612
CheckError(err, "SCSetInfo1 error");
691
err = SCSetInfo(qcdx->theComponent, scSpatialSettingsType, &qcdx->gSpatialSettings);
613
err = SCSetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
692
614
CheckError(err, "SCSetInfo2 error");
693
err = SCSetInfo(qcdx->theComponent, scDataRateSettingsType, &qcdx->aDataRateSetting);
615
err = SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
694
616
CheckError(err, "SCSetInfo3 error");
697
619
check_renderbutton_framerate();
699
621
// put up the dialog box
700
err = SCRequestSequenceSettings(qcdx->theComponent);
622
err = SCRequestSequenceSettings(qtdata->theComponent);
702
624
if (err == scUserCancelled) {
707
629
// get user selected data
708
SCGetInfo(qcdx->theComponent, scTemporalSettingsType, &qcdx->gTemporalSettings);
709
SCGetInfo(qcdx->theComponent, scSpatialSettingsType, &qcdx->gSpatialSettings);
710
SCGetInfo(qcdx->theComponent, scDataRateSettingsType, &qcdx->aDataRateSetting);
712
GetCodecInfo (&ci, qcdx->gSpatialSettings.codecType, 0);
713
CopyPascalStringToC(ci.typeName, str);
714
sprintf(qtcdname,"Codec: %s", str);
716
SaveExporterSettingsToMem(G.scene->r.qtcodecdata);
630
SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
631
SCGetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
632
SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
634
QT_SaveCodecSettingsToScene();
718
636
// framerate jugglin'
719
if(qcdx->gTemporalSettings.frameRate == 1571553) { // 23.98 fps
720
qcdx->kVideoTimeScale = 2398;
721
qcdx->duration = 100;
637
if(qtdata->gTemporalSettings.frameRate == 1571553) { // 23.98 fps
638
qtdata->kVideoTimeScale = 2398;
639
qtdata->duration = 100;
723
641
G.scene->r.frs_sec = 24;
724
} else if (qcdx->gTemporalSettings.frameRate == 1964113) { // 29.97 fps
725
qcdx->kVideoTimeScale = 2997;
726
qcdx->duration = 100;
642
} else if (qtdata->gTemporalSettings.frameRate == 1964113) { // 29.97 fps
643
qtdata->kVideoTimeScale = 2997;
644
qtdata->duration = 100;
728
646
G.scene->r.frs_sec = 30;
729
} else if (qcdx->gTemporalSettings.frameRate == 3928227) { // 59.94 fps
730
qcdx->kVideoTimeScale = 5994;
731
qcdx->duration = 100;
647
} else if (qtdata->gTemporalSettings.frameRate == 3928227) { // 59.94 fps
648
qtdata->kVideoTimeScale = 5994;
649
qtdata->duration = 100;
733
651
G.scene->r.frs_sec = 60;
735
qcdx->kVideoTimeScale = 600;
736
qcdx->duration = qcdx->kVideoTimeScale / (qcdx->gTemporalSettings.frameRate / 65536);
653
qtdata->kVideoTimeScale = 600;
654
qtdata->duration = qtdata->kVideoTimeScale / (qtdata->gTemporalSettings.frameRate / 65536);
738
G.scene->r.frs_sec = (qcdx->gTemporalSettings.frameRate / 65536);
656
G.scene->r.frs_sec = (qtdata->gTemporalSettings.frameRate / 65536);
744
662
#endif /* _WIN32 || __APPLE__ */
746
663
#endif /* WITH_QUICKTIME */