2003-04-28 02:15:46 +00:00
|
|
|
/**
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* quicktime_export.c
|
|
|
|
*
|
|
|
|
* Code to create QuickTime Movies with Blender
|
|
|
|
*
|
|
|
|
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version. The Blender
|
|
|
|
* Foundation also sells licenses for use in proprietary software under
|
|
|
|
* the Blender License. See http://www.blender.org/BL/ for information
|
|
|
|
* about this.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* The Original Code is written by Rob Haarsma (phase)
|
|
|
|
*
|
|
|
|
* Contributor(s): Stefan Gartner (sgefant)
|
|
|
|
*
|
|
|
|
* ***** END GPL/BL DUAL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef WITH_QUICKTIME
|
|
|
|
#if defined(_WIN32) || defined(__APPLE__)
|
|
|
|
|
|
|
|
#include "BKE_global.h"
|
|
|
|
#include "BKE_scene.h"
|
|
|
|
#include "BLI_blenlib.h"
|
2004-12-10 12:55:53 +00:00
|
|
|
#include "BIF_toolbox.h" /* error() */
|
2003-04-28 02:15:46 +00:00
|
|
|
#include "BLO_sys_types.h"
|
|
|
|
#include "IMB_imbuf.h"
|
|
|
|
#include "IMB_imbuf_types.h"
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "render.h"
|
2004-12-10 01:28:28 +00:00
|
|
|
#include "quicktime_import.h"
|
2003-04-28 02:15:46 +00:00
|
|
|
#include "quicktime_export.h"
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
#include <QTML.h>
|
2003-05-02 13:36:56 +00:00
|
|
|
#include <Movies.h>
|
|
|
|
#include <QuicktimeComponents.h>
|
2005-01-11 10:58:58 +00:00
|
|
|
#include <TextUtils.h>
|
2003-04-28 02:15:46 +00:00
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
|
|
|
#ifdef __APPLE__
|
2004-01-08 16:26:30 +00:00
|
|
|
/* evil */
|
|
|
|
#ifndef __AIFF__
|
|
|
|
#define __AIFF__
|
|
|
|
#endif
|
2003-05-02 13:36:56 +00:00
|
|
|
#include <QuickTime/Movies.h>
|
|
|
|
#include <QuickTime/QuicktimeComponents.h>
|
2003-04-28 02:15:46 +00:00
|
|
|
#include <fcntl.h> /* open() */
|
|
|
|
#include <unistd.h> /* close() */
|
|
|
|
#include <sys/stat.h> /* file permissions */
|
|
|
|
#endif /* __APPLE__ */
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
#define kMyCreatorType FOUR_CHAR_CODE('TVOD')
|
|
|
|
#define kTrackStart 0
|
|
|
|
#define kMediaStart 0
|
2003-04-28 02:15:46 +00:00
|
|
|
|
|
|
|
static void QT_StartAddVideoSamplesToMedia (const Rect *trackFrame);
|
|
|
|
static void QT_DoAddVideoSamplesToMedia (int frame);
|
|
|
|
static void QT_EndAddVideoSamplesToMedia (void);
|
|
|
|
static void QT_CreateMyVideoTrack (void);
|
|
|
|
static void QT_EndCreateMyVideoTrack (void);
|
|
|
|
static void check_renderbutton_framerate(void);
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
typedef struct QuicktimeExport {
|
2003-04-28 02:15:46 +00:00
|
|
|
|
|
|
|
FSSpec theSpec;
|
|
|
|
short resRefNum;
|
|
|
|
Str255 qtfilename;
|
|
|
|
|
|
|
|
Media theMedia;
|
|
|
|
Movie theMovie;
|
|
|
|
Track theTrack;
|
|
|
|
|
2005-01-12 10:18:47 +00:00
|
|
|
GWorldPtr theGWorld;
|
|
|
|
PixMapHandle thePixMap;
|
2003-04-28 02:15:46 +00:00
|
|
|
ImageDescription **anImageDescription;
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
ImBuf *ibuf; //imagedata for Quicktime's Gworld
|
2005-02-19 10:46:52 +00:00
|
|
|
ImBuf *ibuf2; //copy of renderdata, to be Y-flipped
|
2003-04-28 02:15:46 +00:00
|
|
|
|
|
|
|
} QuicktimeExport;
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
typedef struct QuicktimeComponentData {
|
2003-04-28 02:15:46 +00:00
|
|
|
|
|
|
|
ComponentInstance theComponent;
|
|
|
|
SCTemporalSettings gTemporalSettings;
|
|
|
|
SCSpatialSettings gSpatialSettings;
|
|
|
|
SCDataRateSettings aDataRateSetting;
|
|
|
|
TimeValue duration;
|
|
|
|
long kVideoTimeScale;
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
} QuicktimeComponentData;
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
static struct QuicktimeExport *qtexport;
|
|
|
|
static struct QuicktimeComponentData *qtdata;
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2003-05-21 01:21:07 +00:00
|
|
|
static int sframe;
|
|
|
|
|
|
|
|
|
2005-03-09 19:45:59 +00:00
|
|
|
static void CheckError(OSErr err, char *msg)
|
2005-01-11 10:58:58 +00:00
|
|
|
{
|
|
|
|
if(err != noErr) printf("%s: %d\n", msg, err);
|
|
|
|
}
|
|
|
|
|
2003-05-21 01:21:07 +00:00
|
|
|
|
2005-03-09 19:45:59 +00:00
|
|
|
static OSErr QT_SaveCodecSettingsToScene(void)
|
2003-05-21 01:21:07 +00:00
|
|
|
{
|
|
|
|
QTAtomContainer myContainer = NULL;
|
|
|
|
ComponentResult myErr = noErr;
|
|
|
|
Ptr myPtr;
|
|
|
|
long mySize = 0;
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
CodecInfo ci;
|
|
|
|
char str[255];
|
|
|
|
|
|
|
|
QuicktimeCodecData *qcd = G.scene->r.qtcodecdata;
|
|
|
|
|
|
|
|
// check if current scene already has qtcodec settings, and clear them
|
2003-05-21 01:21:07 +00:00
|
|
|
if (qcd) {
|
|
|
|
free_qtcodecdata(qcd);
|
|
|
|
} else {
|
|
|
|
qcd = G.scene->r.qtcodecdata = MEM_callocN(sizeof(QuicktimeCodecData), "QuicktimeCodecData");
|
|
|
|
}
|
|
|
|
|
|
|
|
// obtain all current codec settings
|
2005-01-11 10:58:58 +00:00
|
|
|
SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
|
|
|
|
SCSetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
|
|
|
|
SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
|
2003-05-21 01:21:07 +00:00
|
|
|
|
|
|
|
// retreive codecdata from quicktime in a atomcontainer
|
2005-01-11 10:58:58 +00:00
|
|
|
myErr = SCGetSettingsAsAtomContainer(qtdata->theComponent, &myContainer);
|
2003-05-21 01:21:07 +00:00
|
|
|
if (myErr != noErr) {
|
|
|
|
printf("Quicktime: SCGetSettingsAsAtomContainer failed\n");
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the size of the atomcontainer
|
|
|
|
mySize = GetHandleSize((Handle)myContainer);
|
|
|
|
|
|
|
|
// lock and convert the atomcontainer to a *valid* pointer
|
|
|
|
QTLockContainer(myContainer);
|
2003-05-21 21:42:36 +00:00
|
|
|
myPtr = *(Handle)myContainer;
|
2003-05-21 01:21:07 +00:00
|
|
|
|
|
|
|
// copy the Quicktime data into the blender qtcodecdata struct
|
|
|
|
if (myPtr) {
|
|
|
|
qcd->cdParms = MEM_mallocN(mySize, "qt.cdParms");
|
|
|
|
memcpy(qcd->cdParms, myPtr, mySize);
|
|
|
|
qcd->cdSize = mySize;
|
2005-01-11 10:58:58 +00:00
|
|
|
|
|
|
|
GetCodecInfo (&ci, qtdata->gSpatialSettings.codecType, 0);
|
|
|
|
CopyPascalStringToC(ci.typeName, str);
|
|
|
|
sprintf(qcd->qtcodecname, "Codec: %s", str);
|
2003-05-21 01:21:07 +00:00
|
|
|
} else {
|
2005-01-12 10:18:47 +00:00
|
|
|
printf("Quicktime: QT_SaveCodecSettingsToScene failed\n");
|
2003-05-21 01:21:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QTUnlockContainer(myContainer);
|
|
|
|
|
|
|
|
bail:
|
|
|
|
if (myContainer != NULL)
|
|
|
|
QTDisposeAtomContainer(myContainer);
|
|
|
|
|
|
|
|
return((OSErr)myErr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-09 19:45:59 +00:00
|
|
|
static OSErr QT_GetCodecSettingsFromScene(void)
|
2003-05-21 01:21:07 +00:00
|
|
|
{
|
|
|
|
Handle myHandle = NULL;
|
|
|
|
ComponentResult myErr = noErr;
|
|
|
|
// CodecInfo ci;
|
|
|
|
// char str[255];
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
QuicktimeCodecData *qcd = G.scene->r.qtcodecdata;
|
|
|
|
|
2003-05-21 01:21:07 +00:00
|
|
|
// if there is codecdata in the blendfile, convert it to a Quicktime handle
|
|
|
|
if (qcd) {
|
|
|
|
myHandle = NewHandle(qcd->cdSize);
|
|
|
|
PtrToHand( qcd->cdParms, &myHandle, qcd->cdSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
// restore codecsettings to the quicktime component
|
|
|
|
if(qcd->cdParms && qcd->cdSize) {
|
2005-01-11 10:58:58 +00:00
|
|
|
myErr = SCSetSettingsFromAtomContainer((GraphicsExportComponent)qtdata->theComponent, (QTAtomContainer)myHandle);
|
2003-05-21 01:21:07 +00:00
|
|
|
if (myErr != noErr) {
|
|
|
|
printf("Quicktime: SCSetSettingsFromAtomContainer failed\n");
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
|
|
|
|
// update runtime codecsettings for use with the codec dialog
|
2005-01-11 10:58:58 +00:00
|
|
|
SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
|
|
|
|
SCGetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
|
|
|
|
SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
|
2003-05-21 01:21:07 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
// GetCodecInfo (&ci, qtdata->gSpatialSettings.codecType, 0);
|
2003-05-21 01:21:07 +00:00
|
|
|
// CopyPascalStringToC(ci.typeName, str);
|
|
|
|
// printf("restored Codec: %s\n", str);
|
|
|
|
} else {
|
2005-01-12 10:18:47 +00:00
|
|
|
printf("Quicktime: QT_GetCodecSettingsFromScene failed\n");
|
2003-05-21 01:21:07 +00:00
|
|
|
}
|
|
|
|
bail:
|
|
|
|
if (myHandle != NULL)
|
|
|
|
DisposeHandle(myHandle);
|
|
|
|
|
|
|
|
return((OSErr)myErr);
|
|
|
|
}
|
2003-04-28 02:15:46 +00:00
|
|
|
|
|
|
|
|
2005-03-09 19:45:59 +00:00
|
|
|
static OSErr QT_AddUserDataTextToMovie (Movie theMovie, char *theText, OSType theType)
|
2003-04-28 02:15:46 +00:00
|
|
|
{
|
2005-01-11 10:58:58 +00:00
|
|
|
UserData myUserData = NULL;
|
|
|
|
Handle myHandle = NULL;
|
|
|
|
long myLength = strlen(theText);
|
|
|
|
OSErr myErr = noErr;
|
|
|
|
|
|
|
|
// get the movie's user data list
|
|
|
|
myUserData = GetMovieUserData(theMovie);
|
|
|
|
if (myUserData == NULL)
|
|
|
|
return(paramErr);
|
|
|
|
|
|
|
|
// copy the specified text into a new handle
|
|
|
|
myHandle = NewHandleClear(myLength);
|
|
|
|
if (myHandle == NULL)
|
|
|
|
return(MemError());
|
|
|
|
|
|
|
|
BlockMoveData(theText, *myHandle, myLength);
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
// add the data to the movie's user data
|
|
|
|
myErr = AddUserDataText(myUserData, myHandle, theType, 1, (short)GetScriptManagerVariable(smRegionCode));
|
|
|
|
|
|
|
|
// clean up
|
|
|
|
DisposeHandle(myHandle);
|
|
|
|
return(myErr);
|
|
|
|
}
|
2003-04-28 02:15:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
static void QT_CreateMyVideoTrack(void)
|
|
|
|
{
|
|
|
|
OSErr err = noErr;
|
|
|
|
Rect trackFrame;
|
2005-02-19 10:46:52 +00:00
|
|
|
// MatrixRecord myMatrix;
|
2003-04-28 02:15:46 +00:00
|
|
|
|
|
|
|
trackFrame.top = 0;
|
|
|
|
trackFrame.left = 0;
|
|
|
|
trackFrame.bottom = R.recty;
|
|
|
|
trackFrame.right = R.rectx;
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
qtexport->theTrack = NewMovieTrack (qtexport->theMovie,
|
2003-04-28 02:15:46 +00:00
|
|
|
FixRatio(trackFrame.right,1),
|
|
|
|
FixRatio(trackFrame.bottom,1),
|
|
|
|
kNoVolume);
|
|
|
|
CheckError( GetMoviesError(), "NewMovieTrack error" );
|
|
|
|
|
2005-02-19 10:46:52 +00:00
|
|
|
// SetIdentityMatrix(&myMatrix);
|
|
|
|
// ScaleMatrix(&myMatrix, fixed1, Long2Fix(-1), 0, 0);
|
|
|
|
// TranslateMatrix(&myMatrix, 0, Long2Fix(trackFrame.bottom));
|
|
|
|
// SetMovieMatrix(qtexport->theMovie, &myMatrix);
|
2005-01-11 10:58:58 +00:00
|
|
|
|
|
|
|
qtexport->theMedia = NewTrackMedia (qtexport->theTrack,
|
2003-04-28 02:15:46 +00:00
|
|
|
VideoMediaType,
|
2005-01-11 10:58:58 +00:00
|
|
|
qtdata->kVideoTimeScale,
|
2003-04-28 02:15:46 +00:00
|
|
|
nil,
|
|
|
|
0);
|
|
|
|
CheckError( GetMoviesError(), "NewTrackMedia error" );
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
err = BeginMediaEdits (qtexport->theMedia);
|
2003-04-28 02:15:46 +00:00
|
|
|
CheckError( err, "BeginMediaEdits error" );
|
|
|
|
|
|
|
|
QT_StartAddVideoSamplesToMedia (&trackFrame);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void QT_EndCreateMyVideoTrack(void)
|
|
|
|
{
|
|
|
|
OSErr err = noErr;
|
|
|
|
|
|
|
|
QT_EndAddVideoSamplesToMedia ();
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
err = EndMediaEdits (qtexport->theMedia);
|
2003-04-28 02:15:46 +00:00
|
|
|
CheckError( err, "EndMediaEdits error" );
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
err = InsertMediaIntoTrack (qtexport->theTrack,
|
2003-04-28 02:15:46 +00:00
|
|
|
kTrackStart,/* track start time */
|
|
|
|
kMediaStart,/* media start time */
|
2005-01-11 10:58:58 +00:00
|
|
|
GetMediaDuration (qtexport->theMedia),
|
2003-04-28 02:15:46 +00:00
|
|
|
fixed1);
|
|
|
|
CheckError( err, "InsertMediaIntoTrack error" );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void QT_StartAddVideoSamplesToMedia (const Rect *trackFrame)
|
|
|
|
{
|
|
|
|
OSErr err = noErr;
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
qtexport->ibuf = IMB_allocImBuf (R.rectx, R.recty, 32, IB_rect, 0);
|
2005-02-19 10:46:52 +00:00
|
|
|
qtexport->ibuf2 = IMB_allocImBuf (R.rectx, R.recty, 32, IB_rect, 0);
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
err = NewGWorldFromPtr( &qtexport->theGWorld,
|
2005-01-12 11:03:25 +00:00
|
|
|
k32ARGBPixelFormat,
|
2003-04-28 02:15:46 +00:00
|
|
|
trackFrame,
|
|
|
|
NULL, NULL, 0,
|
2005-01-11 10:58:58 +00:00
|
|
|
(unsigned char *)qtexport->ibuf->rect,
|
2003-04-28 02:15:46 +00:00
|
|
|
R.rectx * 4 );
|
|
|
|
CheckError (err, "NewGWorldFromPtr error");
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
qtexport->thePixMap = GetGWorldPixMap(qtexport->theGWorld);
|
|
|
|
LockPixels(qtexport->thePixMap);
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
SCDefaultPixMapSettings (qtdata->theComponent, qtexport->thePixMap, true);
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
|
|
|
|
SCSetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
|
|
|
|
SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
err = SCCompressSequenceBegin(qtdata->theComponent, qtexport->thePixMap, NULL, &qtexport->anImageDescription);
|
2003-04-28 02:15:46 +00:00
|
|
|
CheckError (err, "SCCompressSequenceBegin error" );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void QT_DoAddVideoSamplesToMedia (int frame)
|
|
|
|
{
|
|
|
|
OSErr err = noErr;
|
|
|
|
Rect imageRect;
|
|
|
|
|
2005-02-19 10:46:52 +00:00
|
|
|
int index;
|
|
|
|
int boxsize;
|
|
|
|
unsigned char *from, *to;
|
2003-04-28 02:15:46 +00:00
|
|
|
|
|
|
|
short syncFlag;
|
|
|
|
long dataSize;
|
|
|
|
Handle compressedData;
|
2005-02-19 10:46:52 +00:00
|
|
|
Ptr myPtr;
|
|
|
|
|
|
|
|
|
|
|
|
//copy and flip renderdata
|
|
|
|
memcpy(qtexport->ibuf2->rect, R.rectot, 4*R.rectx*R.recty);
|
|
|
|
IMB_flipy(qtexport->ibuf2);
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
//get pointers to parse bitmapdata
|
|
|
|
myPtr = GetPixBaseAddr(qtexport->thePixMap);
|
|
|
|
imageRect = (**qtexport->thePixMap).bounds;
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2005-02-19 10:46:52 +00:00
|
|
|
from = (unsigned char *) qtexport->ibuf2->rect;
|
|
|
|
to = (unsigned char *) myPtr;
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2005-02-19 10:46:52 +00:00
|
|
|
//parse RGBA bitmap into Quicktime's ARGB GWorld
|
|
|
|
boxsize = R.rectx * R.recty;
|
|
|
|
for( index = 0; index < boxsize; index++) {
|
|
|
|
to[0] = from[3];
|
|
|
|
to[1] = from[0];
|
|
|
|
to[2] = from[1];
|
|
|
|
to[3] = from[2];
|
|
|
|
to +=4, from += 4;
|
|
|
|
}
|
2005-01-12 11:03:25 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
err = SCCompressSequenceFrame(qtdata->theComponent,
|
|
|
|
qtexport->thePixMap,
|
2003-04-28 02:15:46 +00:00
|
|
|
&imageRect,
|
|
|
|
&compressedData,
|
|
|
|
&dataSize,
|
|
|
|
&syncFlag);
|
|
|
|
CheckError(err, "SCCompressSequenceFrame error");
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
err = AddMediaSample(qtexport->theMedia,
|
2003-04-28 02:15:46 +00:00
|
|
|
compressedData,
|
|
|
|
0,
|
|
|
|
dataSize,
|
2005-01-11 10:58:58 +00:00
|
|
|
qtdata->duration,
|
|
|
|
(SampleDescriptionHandle)qtexport->anImageDescription,
|
2003-04-28 02:15:46 +00:00
|
|
|
1,
|
|
|
|
syncFlag,
|
|
|
|
NULL);
|
|
|
|
CheckError(err, "AddMediaSample error");
|
|
|
|
|
|
|
|
printf ("added frame %3d (frame %3d in movie): ", frame, frame-sframe);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void QT_EndAddVideoSamplesToMedia (void)
|
|
|
|
{
|
2005-01-11 10:58:58 +00:00
|
|
|
SCCompressSequenceEnd(qtdata->theComponent);
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
UnlockPixels(qtexport->thePixMap);
|
2005-02-19 10:46:52 +00:00
|
|
|
if (qtexport->theGWorld)
|
|
|
|
DisposeGWorld (qtexport->theGWorld);
|
|
|
|
|
|
|
|
if (qtexport->ibuf)
|
|
|
|
IMB_freeImBuf(qtexport->ibuf);
|
|
|
|
|
|
|
|
if (qtexport->ibuf2)
|
|
|
|
IMB_freeImBuf(qtexport->ibuf2);
|
2003-04-28 02:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void makeqtstring (char *string) {
|
|
|
|
char txt[64];
|
|
|
|
|
|
|
|
if (string==0) return;
|
|
|
|
|
|
|
|
strcpy(string, G.scene->r.pic);
|
|
|
|
BLI_convertstringcode(string, G.sce, G.scene->r.cfra);
|
|
|
|
|
|
|
|
RE_make_existing_file(string);
|
|
|
|
|
2005-04-02 15:36:57 +00:00
|
|
|
if (BLI_strcasecmp(string + strlen(string) - 4, ".mov")) {
|
2003-04-28 02:15:46 +00:00
|
|
|
sprintf(txt, "%04d_%04d.mov", (G.scene->r.sfra) , (G.scene->r.efra) );
|
|
|
|
strcat(string, txt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void start_qt(void) {
|
|
|
|
OSErr err = noErr;
|
|
|
|
|
|
|
|
char name[2048];
|
|
|
|
char theFullPath[255];
|
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
int myFile;
|
|
|
|
FSRef myRef;
|
2004-12-10 01:28:28 +00:00
|
|
|
#else
|
|
|
|
char *qtname;
|
2003-04-28 02:15:46 +00:00
|
|
|
#endif
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
if(qtexport == NULL) qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport");
|
2003-05-21 01:21:07 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
if(qtdata) {
|
|
|
|
if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
|
|
|
|
free_qtcomponentdata();
|
2003-05-21 01:21:07 +00:00
|
|
|
}
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeCodecDataExt");
|
2003-05-21 01:21:07 +00:00
|
|
|
|
|
|
|
if(G.scene->r.qtcodecdata == NULL && G.scene->r.qtcodecdata->cdParms == NULL) {
|
|
|
|
get_qtcodec_settings();
|
|
|
|
} else {
|
2005-01-11 10:58:58 +00:00
|
|
|
qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
|
2003-05-21 01:21:07 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
QT_GetCodecSettingsFromScene();
|
2003-05-21 01:21:07 +00:00
|
|
|
check_renderbutton_framerate();
|
|
|
|
}
|
2003-04-28 02:15:46 +00:00
|
|
|
|
|
|
|
if (G.afbreek != 1) {
|
|
|
|
sframe = (G.scene->r.sfra);
|
|
|
|
|
|
|
|
makeqtstring(name);
|
|
|
|
|
|
|
|
#ifdef __APPLE__
|
2004-12-10 01:28:28 +00:00
|
|
|
sprintf(theFullPath, "%s", name);
|
|
|
|
|
2003-04-28 02:15:46 +00:00
|
|
|
/* hack: create an empty file to make FSPathMakeRef() happy */
|
|
|
|
myFile = open(theFullPath, O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRUSR|S_IWUSR);
|
|
|
|
if (myFile < 0) {
|
|
|
|
printf("error while creating file!\n");
|
|
|
|
/* do something? */
|
|
|
|
}
|
|
|
|
close(myFile);
|
|
|
|
err = FSPathMakeRef(theFullPath, &myRef, 0);
|
|
|
|
CheckError(err, "FsPathMakeRef error");
|
2005-01-11 10:58:58 +00:00
|
|
|
err = FSGetCatalogInfo(&myRef, kFSCatInfoNone, NULL, NULL, &qtexport->theSpec, NULL);
|
2003-04-28 02:15:46 +00:00
|
|
|
CheckError(err, "FsGetCatalogInfoRef error");
|
2005-02-19 10:46:52 +00:00
|
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
2004-12-10 01:28:28 +00:00
|
|
|
qtname = get_valid_qtname(name);
|
|
|
|
sprintf(theFullPath, "%s", qtname);
|
2005-02-19 10:46:52 +00:00
|
|
|
strcpy(name, qtname);
|
|
|
|
MEM_freeN(qtname);
|
2004-12-10 01:28:28 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
CopyCStringToPascal(theFullPath, qtexport->qtfilename);
|
|
|
|
err = FSMakeFSSpec(0, 0L, qtexport->qtfilename, &qtexport->theSpec);
|
2003-04-28 02:15:46 +00:00
|
|
|
#endif
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
err = CreateMovieFile (&qtexport->theSpec,
|
2003-04-28 02:15:46 +00:00
|
|
|
kMyCreatorType,
|
|
|
|
smCurrentScript,
|
|
|
|
createMovieFileDeleteCurFile | createMovieFileDontCreateResFile,
|
2005-01-11 10:58:58 +00:00
|
|
|
&qtexport->resRefNum,
|
|
|
|
&qtexport->theMovie );
|
2003-04-28 02:15:46 +00:00
|
|
|
CheckError(err, "CreateMovieFile error");
|
|
|
|
|
2004-12-10 12:55:53 +00:00
|
|
|
if(err != noErr) {
|
|
|
|
G.afbreek = 1;
|
|
|
|
error("Unable to create Quicktime movie: %s\n", name);
|
|
|
|
} else {
|
|
|
|
printf("Created QuickTime movie: %s\n", name);
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2004-12-10 12:55:53 +00:00
|
|
|
QT_CreateMyVideoTrack();
|
|
|
|
}
|
2003-04-28 02:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void append_qt(int frame) {
|
|
|
|
QT_DoAddVideoSamplesToMedia(frame);
|
|
|
|
}
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
|
2003-04-28 02:15:46 +00:00
|
|
|
void end_qt(void) {
|
|
|
|
OSErr err = noErr;
|
2005-01-12 10:18:47 +00:00
|
|
|
short resId = movieInDataForkResID;
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
if(qtexport->theMovie) {
|
2005-01-12 10:18:47 +00:00
|
|
|
QT_EndCreateMyVideoTrack();
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2005-01-12 10:18:47 +00:00
|
|
|
err = AddMovieResource (qtexport->theMovie, qtexport->resRefNum, &resId, qtexport->qtfilename);
|
2003-04-28 02:15:46 +00:00
|
|
|
CheckError(err, "AddMovieResource error");
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
err = QT_AddUserDataTextToMovie(qtexport->theMovie, "Made with Blender", kUserDataTextInformation);
|
|
|
|
CheckError(err, "AddUserDataTextToMovie error");
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2005-01-12 10:18:47 +00:00
|
|
|
err = UpdateMovieResource(qtexport->theMovie, qtexport->resRefNum, resId, qtexport->qtfilename);
|
2005-01-11 10:58:58 +00:00
|
|
|
CheckError(err, "UpdateMovieResource error");
|
|
|
|
|
|
|
|
if(qtexport->resRefNum) CloseMovieFile(qtexport->resRefNum);
|
|
|
|
|
|
|
|
DisposeMovie(qtexport->theMovie);
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
printf("Finished QuickTime movie.\n");
|
2003-04-28 02:15:46 +00:00
|
|
|
}
|
2005-01-11 10:58:58 +00:00
|
|
|
|
|
|
|
if(qtexport) {
|
|
|
|
MEM_freeN(qtexport);
|
|
|
|
qtexport = NULL;
|
2003-04-28 02:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
void free_qtcomponentdata(void) {
|
|
|
|
if(qtdata) {
|
|
|
|
if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
|
|
|
|
MEM_freeN(qtdata);
|
|
|
|
qtdata = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-04-28 02:15:46 +00:00
|
|
|
|
|
|
|
static void check_renderbutton_framerate(void) {
|
2005-01-12 10:18:47 +00:00
|
|
|
// to keep float framerates consistent between the codec dialog and frs/sec button.
|
2003-04-28 02:15:46 +00:00
|
|
|
OSErr err;
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
err = SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
|
2003-05-21 01:21:07 +00:00
|
|
|
CheckError(err, "SCGetInfo fr error");
|
2003-04-28 02:15:46 +00:00
|
|
|
|
|
|
|
if( (G.scene->r.frs_sec == 24 || G.scene->r.frs_sec == 30 || G.scene->r.frs_sec == 60) &&
|
2005-01-11 10:58:58 +00:00
|
|
|
(qtdata->gTemporalSettings.frameRate == 1571553 ||
|
|
|
|
qtdata->gTemporalSettings.frameRate == 1964113 ||
|
|
|
|
qtdata->gTemporalSettings.frameRate == 3928227)) {;} else
|
|
|
|
qtdata->gTemporalSettings.frameRate = G.scene->r.frs_sec << 16;
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
err = SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
|
2003-04-28 02:15:46 +00:00
|
|
|
CheckError( err, "SCSetInfo error" );
|
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
if(qtdata->gTemporalSettings.frameRate == 1571553) { // 23.98 fps
|
|
|
|
qtdata->kVideoTimeScale = 2398;
|
|
|
|
qtdata->duration = 100;
|
|
|
|
} else if (qtdata->gTemporalSettings.frameRate == 1964113) { // 29.97 fps
|
|
|
|
qtdata->kVideoTimeScale = 2997;
|
|
|
|
qtdata->duration = 100;
|
|
|
|
} else if (qtdata->gTemporalSettings.frameRate == 3928227) { // 59.94 fps
|
|
|
|
qtdata->kVideoTimeScale = 5994;
|
|
|
|
qtdata->duration = 100;
|
2003-04-28 02:15:46 +00:00
|
|
|
} else {
|
2005-01-11 10:58:58 +00:00
|
|
|
qtdata->kVideoTimeScale = (qtdata->gTemporalSettings.frameRate >> 16) * 100;
|
|
|
|
qtdata->duration = 100;
|
2003-04-28 02:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
2003-05-21 01:21:07 +00:00
|
|
|
|
2003-04-28 02:15:46 +00:00
|
|
|
|
|
|
|
int get_qtcodec_settings(void)
|
|
|
|
{
|
|
|
|
OSErr err = noErr;
|
2003-05-09 11:24:55 +00:00
|
|
|
|
2003-05-21 01:21:07 +00:00
|
|
|
// erase any existing codecsetting
|
2005-01-11 10:58:58 +00:00
|
|
|
if(qtdata) {
|
|
|
|
if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
|
|
|
|
free_qtcomponentdata();
|
2003-04-28 02:15:46 +00:00
|
|
|
}
|
|
|
|
|
2003-05-21 01:21:07 +00:00
|
|
|
// allocate new
|
2005-01-11 10:58:58 +00:00
|
|
|
qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeComponentData");
|
|
|
|
qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2003-05-21 01:21:07 +00:00
|
|
|
// get previous selected codecsetting, if any
|
|
|
|
if(G.scene->r.qtcodecdata && G.scene->r.qtcodecdata->cdParms) {
|
2005-01-11 10:58:58 +00:00
|
|
|
QT_GetCodecSettingsFromScene();
|
2003-05-21 01:21:07 +00:00
|
|
|
check_renderbutton_framerate();
|
|
|
|
} else {
|
2005-01-12 10:18:47 +00:00
|
|
|
// configure the standard image compression dialog box
|
|
|
|
// set some default settings
|
2005-01-11 10:58:58 +00:00
|
|
|
qtdata->gSpatialSettings.codec = anyCodec;
|
|
|
|
qtdata->gSpatialSettings.spatialQuality = codecMaxQuality;
|
|
|
|
qtdata->gTemporalSettings.temporalQuality = codecMaxQuality;
|
|
|
|
qtdata->gTemporalSettings.keyFrameRate = 25;
|
|
|
|
qtdata->aDataRateSetting.dataRate = 90 * 1024;
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
err = SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
|
2003-04-28 02:15:46 +00:00
|
|
|
CheckError(err, "SCSetInfo1 error");
|
2005-01-11 10:58:58 +00:00
|
|
|
err = SCSetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
|
2003-04-28 02:15:46 +00:00
|
|
|
CheckError(err, "SCSetInfo2 error");
|
2005-01-11 10:58:58 +00:00
|
|
|
err = SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
|
2003-04-28 02:15:46 +00:00
|
|
|
CheckError(err, "SCSetInfo3 error");
|
|
|
|
}
|
2003-05-21 02:26:45 +00:00
|
|
|
|
|
|
|
check_renderbutton_framerate();
|
|
|
|
|
2003-04-28 02:15:46 +00:00
|
|
|
// put up the dialog box
|
2005-01-11 10:58:58 +00:00
|
|
|
err = SCRequestSequenceSettings(qtdata->theComponent);
|
2003-05-09 11:24:55 +00:00
|
|
|
|
2003-05-09 12:45:59 +00:00
|
|
|
if (err == scUserCancelled) {
|
2003-04-28 02:15:46 +00:00
|
|
|
G.afbreek = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get user selected data
|
2005-01-11 10:58:58 +00:00
|
|
|
SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
|
|
|
|
SCGetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
|
|
|
|
SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
|
2003-05-08 16:24:58 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
QT_SaveCodecSettingsToScene();
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2003-05-21 01:21:07 +00:00
|
|
|
// framerate jugglin'
|
2005-01-11 10:58:58 +00:00
|
|
|
if(qtdata->gTemporalSettings.frameRate == 1571553) { // 23.98 fps
|
|
|
|
qtdata->kVideoTimeScale = 2398;
|
|
|
|
qtdata->duration = 100;
|
2003-04-28 02:15:46 +00:00
|
|
|
|
|
|
|
G.scene->r.frs_sec = 24;
|
2005-01-11 10:58:58 +00:00
|
|
|
} else if (qtdata->gTemporalSettings.frameRate == 1964113) { // 29.97 fps
|
|
|
|
qtdata->kVideoTimeScale = 2997;
|
|
|
|
qtdata->duration = 100;
|
2003-04-28 02:15:46 +00:00
|
|
|
|
|
|
|
G.scene->r.frs_sec = 30;
|
2005-01-11 10:58:58 +00:00
|
|
|
} else if (qtdata->gTemporalSettings.frameRate == 3928227) { // 59.94 fps
|
|
|
|
qtdata->kVideoTimeScale = 5994;
|
|
|
|
qtdata->duration = 100;
|
2003-04-28 02:15:46 +00:00
|
|
|
|
|
|
|
G.scene->r.frs_sec = 60;
|
|
|
|
} else {
|
2005-01-11 10:58:58 +00:00
|
|
|
qtdata->kVideoTimeScale = 600;
|
|
|
|
qtdata->duration = qtdata->kVideoTimeScale / (qtdata->gTemporalSettings.frameRate / 65536);
|
2003-04-28 02:15:46 +00:00
|
|
|
|
2005-01-11 10:58:58 +00:00
|
|
|
G.scene->r.frs_sec = (qtdata->gTemporalSettings.frameRate / 65536);
|
2003-04-28 02:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* _WIN32 || __APPLE__ */
|
|
|
|
#endif /* WITH_QUICKTIME */
|
|
|
|
|