forked from bartvdbraak/blender
Quicktime for Cocoa : import part
This makes quicktime import (.mov & quicktime handled image files such as .gif) available also for 64bit OSX Unfortunately, Apple currently incomplete implementation of QTKit has much lower performance than old Carbon Quicktime. FYI, it spawns a 32bit process "QTKitserver" to place calls to Quicktime 7. So this is mostly meant as a "backup" for 64bit OSX builds, until Apple releases full Quicktime X. Export part will come just after. CMake scripts updated: set WITH_QUICKTIME and USE_QTKIT to ON
This commit is contained in:
parent
22e8616a27
commit
624cd67d55
@ -84,6 +84,7 @@ OPTION(WITH_OPENCOLLADA "Enable OpenCollada Support (http://www.opencollada.org
|
||||
|
||||
IF (APPLE)
|
||||
OPTION(WITH_COCOA "Use Cocoa framework instead of deprecated Carbon" ON)
|
||||
OPTION(USE_QTKIT "Use QtKit instead of Carbon quicktime (needed for having partial quicktime for 64bit)" OFF)
|
||||
OPTION(WITH_LIBS10.5 "Use 10.5 libs (needed for 64bit builds)" OFF)
|
||||
ENDIF (APPLE)
|
||||
|
||||
@ -525,7 +526,15 @@ IF(APPLE)
|
||||
|
||||
IF (WITH_COCOA)
|
||||
SET(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing -DGHOST_COCOA")
|
||||
SET(PLATFORM_LINKFLAGS "-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Cocoa -framework Carbon -framework AudioUnit -framework AudioToolbox -framework CoreAudio -framework QuickTime")
|
||||
SET(PLATFORM_LINKFLAGS "-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Cocoa -framework Carbon -framework AudioUnit -framework AudioToolbox -framework CoreAudio")
|
||||
IF(USE_QTKIT)
|
||||
SET(PLATFORM_CFLAGS "${PLATFORM_CFLAGS} -DUSE_QTKIT")
|
||||
SET(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -framework QTKit")
|
||||
ELSE(USE_QTKIT)
|
||||
IF(WITH_QUICKTIME)
|
||||
SET(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -framework QuickTime")
|
||||
ENDIF(WITH_QUICKTIME)
|
||||
ENDIF(USE_QTKIT)
|
||||
ELSE (WITH_COCOA)
|
||||
SET(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
|
||||
SET(PLATFORM_LINKFLAGS "-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Carbon -framework AGL -framework AudioUnit -framework AudioToolbox -framework CoreAudio -framework QuickTime")
|
||||
|
@ -384,6 +384,9 @@ int imb_get_anim_type(char * name) {
|
||||
if(UTIL_DEBUG) printf("in getanimtype: %s\n", name);
|
||||
|
||||
#ifndef _WIN32
|
||||
# ifdef WITH_QUICKTIME
|
||||
if (isqtime(name)) return (ANIM_QTIME);
|
||||
# endif
|
||||
# ifdef WITH_FFMPEG
|
||||
/* stat test below fails on large files > 4GB */
|
||||
if (isffmpeg(name)) return (ANIM_FFMPEG);
|
||||
@ -394,9 +397,6 @@ int imb_get_anim_type(char * name) {
|
||||
if (isavi(name)) return (ANIM_AVI);
|
||||
|
||||
if (ismovie(name)) return (ANIM_MOVIE);
|
||||
# ifdef WITH_QUICKTIME
|
||||
if (isqtime(name)) return (ANIM_QTIME);
|
||||
# endif
|
||||
#else
|
||||
if (ib_stat(name,&st) == -1) return(0);
|
||||
if (((st.st_mode) & S_IFMT) != S_IFREG) return(0);
|
||||
|
@ -24,7 +24,11 @@
|
||||
#
|
||||
# ***** END GPL LICENSE BLOCK *****
|
||||
|
||||
SET(SRC apple/quicktime_import.c apple/quicktime_export.c)
|
||||
IF(USE_QTKIT)
|
||||
SET(SRC apple/qtkit_import.m apple/qtkit_export.m)
|
||||
ELSE(USE_QTKIT)
|
||||
SET(SRC apple/quicktime_import.c apple/quicktime_export.c)
|
||||
ENDIF(USE_QTKIT)
|
||||
|
||||
SET(INC
|
||||
.
|
||||
|
665
source/blender/quicktime/apple/qtkit_export.m
Normal file
665
source/blender/quicktime/apple/qtkit_export.m
Normal file
@ -0,0 +1,665 @@
|
||||
/**
|
||||
* $Id: qtkit_export.m 24424 2009-11-09 17:06:48Z damien78 $
|
||||
*
|
||||
* qtkit_export.m
|
||||
*
|
||||
* Code to create QuickTime Movies with Blender
|
||||
*
|
||||
* ***** BEGIN GPL 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.
|
||||
*
|
||||
* 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)
|
||||
* Damien Plisson 11/2009
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifdef WITH_QUICKTIME
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
|
||||
#include "BLO_sys_types.h"
|
||||
|
||||
#include "IMB_imbuf.h"
|
||||
#include "IMB_imbuf_types.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "quicktime_import.h"
|
||||
#include "quicktime_export.h"
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
/* evil */
|
||||
#ifndef __AIFF__
|
||||
#define __AIFF__
|
||||
#endif
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
#define kMyCreatorType FOUR_CHAR_CODE('TVOD')
|
||||
#define kTrackStart 0
|
||||
#define kMediaStart 0
|
||||
|
||||
//static void QT_StartAddVideoSamplesToMedia (const Rect *trackFrame, int rectx, int recty);
|
||||
static void QT_DoAddVideoSamplesToMedia (int frame, int *pixels, int rectx, int recty);
|
||||
static void QT_EndAddVideoSamplesToMedia (void);
|
||||
static void QT_CreateMyVideoTrack (int rectx, int recty);
|
||||
static void QT_EndCreateMyVideoTrack (void);
|
||||
static void check_renderbutton_framerate(struct RenderData *rd);
|
||||
|
||||
typedef struct QuicktimeExport {
|
||||
|
||||
/*FSSpec theSpec;
|
||||
short resRefNum;
|
||||
Str255 qtfilename;
|
||||
|
||||
Media theMedia;
|
||||
Movie theMovie;
|
||||
Track theTrack;
|
||||
|
||||
GWorldPtr theGWorld;
|
||||
PixMapHandle thePixMap;
|
||||
ImageDescription **anImageDescription;*/
|
||||
|
||||
ImBuf *ibuf; //imagedata for Quicktime's Gworld
|
||||
ImBuf *ibuf2; //copy of renderdata, to be Y-flipped
|
||||
|
||||
} QuicktimeExport;
|
||||
|
||||
typedef struct QuicktimeComponentData {
|
||||
|
||||
/*ComponentInstance theComponent;
|
||||
SCTemporalSettings gTemporalSettings;
|
||||
SCSpatialSettings gSpatialSettings;
|
||||
SCDataRateSettings aDataRateSetting;
|
||||
TimeValue duration;
|
||||
long kVideoTimeScale;*/
|
||||
|
||||
} QuicktimeComponentData;
|
||||
|
||||
static struct QuicktimeExport *qtexport;
|
||||
static struct QuicktimeComponentData *qtdata;
|
||||
|
||||
static int sframe;
|
||||
|
||||
#if 0
|
||||
|
||||
static OSErr QT_SaveCodecSettingsToScene(RenderData *rd)
|
||||
{
|
||||
QTAtomContainer myContainer = NULL;
|
||||
ComponentResult myErr = noErr;
|
||||
Ptr myPtr;
|
||||
long mySize = 0;
|
||||
|
||||
CodecInfo ci;
|
||||
char str[255];
|
||||
|
||||
QuicktimeCodecData *qcd = rd->qtcodecdata;
|
||||
|
||||
// check if current scene already has qtcodec settings, and clear them
|
||||
if (qcd) {
|
||||
free_qtcodecdata(qcd);
|
||||
} else {
|
||||
qcd = rd->qtcodecdata = MEM_callocN(sizeof(QuicktimeCodecData), "QuicktimeCodecData");
|
||||
}
|
||||
|
||||
// obtain all current codec settings
|
||||
SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
|
||||
SCSetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
|
||||
SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
|
||||
|
||||
// retreive codecdata from quicktime in a atomcontainer
|
||||
myErr = SCGetSettingsAsAtomContainer(qtdata->theComponent, &myContainer);
|
||||
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);
|
||||
myPtr = *(Handle)myContainer;
|
||||
|
||||
// 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;
|
||||
|
||||
GetCodecInfo (&ci, qtdata->gSpatialSettings.codecType, 0);
|
||||
CopyPascalStringToC(ci.typeName, str);
|
||||
sprintf(qcd->qtcodecname, "Codec: %s", str);
|
||||
} else {
|
||||
printf("Quicktime: QT_SaveCodecSettingsToScene failed\n");
|
||||
}
|
||||
|
||||
QTUnlockContainer(myContainer);
|
||||
|
||||
bail:
|
||||
if (myContainer != NULL)
|
||||
QTDisposeAtomContainer(myContainer);
|
||||
|
||||
return((OSErr)myErr);
|
||||
}
|
||||
|
||||
|
||||
static OSErr QT_GetCodecSettingsFromScene(RenderData *rd)
|
||||
{
|
||||
Handle myHandle = NULL;
|
||||
ComponentResult myErr = noErr;
|
||||
// CodecInfo ci;
|
||||
// char str[255];
|
||||
|
||||
QuicktimeCodecData *qcd = rd->qtcodecdata;
|
||||
|
||||
// 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) {
|
||||
myErr = SCSetSettingsFromAtomContainer((GraphicsExportComponent)qtdata->theComponent, (QTAtomContainer)myHandle);
|
||||
if (myErr != noErr) {
|
||||
printf("Quicktime: SCSetSettingsFromAtomContainer failed\n");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
// update runtime codecsettings for use with the codec dialog
|
||||
SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
|
||||
SCGetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
|
||||
SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
|
||||
|
||||
// GetCodecInfo (&ci, qtdata->gSpatialSettings.codecType, 0);
|
||||
// CopyPascalStringToC(ci.typeName, str);
|
||||
// printf("restored Codec: %s\n", str);
|
||||
} else {
|
||||
printf("Quicktime: QT_GetCodecSettingsFromScene failed\n");
|
||||
}
|
||||
bail:
|
||||
if (myHandle != NULL)
|
||||
DisposeHandle(myHandle);
|
||||
|
||||
return((OSErr)myErr);
|
||||
}
|
||||
|
||||
|
||||
static OSErr QT_AddUserDataTextToMovie (Movie theMovie, char *theText, OSType theType)
|
||||
{
|
||||
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);
|
||||
|
||||
// add the data to the movie's user data
|
||||
myErr = AddUserDataText(myUserData, myHandle, theType, 1, (short)GetScriptManagerVariable(smRegionCode));
|
||||
|
||||
// clean up
|
||||
DisposeHandle(myHandle);
|
||||
return(myErr);
|
||||
}
|
||||
|
||||
|
||||
static void QT_CreateMyVideoTrack(int rectx, int recty)
|
||||
{
|
||||
OSErr err = noErr;
|
||||
Rect trackFrame;
|
||||
// MatrixRecord myMatrix;
|
||||
|
||||
trackFrame.top = 0;
|
||||
trackFrame.left = 0;
|
||||
trackFrame.bottom = recty;
|
||||
trackFrame.right = rectx;
|
||||
|
||||
qtexport->theTrack = NewMovieTrack (qtexport->theMovie,
|
||||
FixRatio(trackFrame.right,1),
|
||||
FixRatio(trackFrame.bottom,1),
|
||||
0);
|
||||
CheckError( GetMoviesError(), "NewMovieTrack error" );
|
||||
|
||||
// SetIdentityMatrix(&myMatrix);
|
||||
// ScaleMatrix(&myMatrix, fixed1, Long2Fix(-1), 0, 0);
|
||||
// TranslateMatrix(&myMatrix, 0, Long2Fix(trackFrame.bottom));
|
||||
// SetMovieMatrix(qtexport->theMovie, &myMatrix);
|
||||
|
||||
qtexport->theMedia = NewTrackMedia (qtexport->theTrack,
|
||||
VideoMediaType,
|
||||
qtdata->kVideoTimeScale,
|
||||
nil,
|
||||
0);
|
||||
CheckError( GetMoviesError(), "NewTrackMedia error" );
|
||||
|
||||
err = BeginMediaEdits (qtexport->theMedia);
|
||||
CheckError( err, "BeginMediaEdits error" );
|
||||
|
||||
QT_StartAddVideoSamplesToMedia (&trackFrame, rectx, recty);
|
||||
}
|
||||
|
||||
|
||||
static void QT_EndCreateMyVideoTrack(void)
|
||||
{
|
||||
OSErr err = noErr;
|
||||
|
||||
QT_EndAddVideoSamplesToMedia ();
|
||||
|
||||
err = EndMediaEdits (qtexport->theMedia);
|
||||
CheckError( err, "EndMediaEdits error" );
|
||||
|
||||
err = InsertMediaIntoTrack (qtexport->theTrack,
|
||||
kTrackStart,/* track start time */
|
||||
kMediaStart,/* media start time */
|
||||
GetMediaDuration (qtexport->theMedia),
|
||||
fixed1);
|
||||
CheckError( err, "InsertMediaIntoTrack error" );
|
||||
}
|
||||
|
||||
|
||||
static void QT_StartAddVideoSamplesToMedia (const Rect *trackFrame, int rectx, int recty)
|
||||
{
|
||||
SCTemporalSettings gTemporalSettings;
|
||||
OSErr err = noErr;
|
||||
|
||||
qtexport->ibuf = IMB_allocImBuf (rectx, recty, 32, IB_rect, 0);
|
||||
qtexport->ibuf2 = IMB_allocImBuf (rectx, recty, 32, IB_rect, 0);
|
||||
|
||||
err = NewGWorldFromPtr( &qtexport->theGWorld,
|
||||
k32ARGBPixelFormat,
|
||||
trackFrame,
|
||||
NULL, NULL, 0,
|
||||
(Ptr)qtexport->ibuf->rect,
|
||||
rectx * 4 );
|
||||
CheckError (err, "NewGWorldFromPtr error");
|
||||
|
||||
qtexport->thePixMap = GetGWorldPixMap(qtexport->theGWorld);
|
||||
LockPixels(qtexport->thePixMap);
|
||||
|
||||
SCDefaultPixMapSettings (qtdata->theComponent, qtexport->thePixMap, true);
|
||||
|
||||
// workaround for crash with H.264, which requires an upgrade to
|
||||
// the new callback based api for proper encoding, but that's not
|
||||
// really compatible with rendering out frames sequentially
|
||||
gTemporalSettings = qtdata->gTemporalSettings;
|
||||
if(qtdata->gSpatialSettings.codecType == kH264CodecType) {
|
||||
if(gTemporalSettings.temporalQuality != codecMinQuality) {
|
||||
fprintf(stderr, "Only minimum quality compression supported for QuickTime H.264.\n");
|
||||
gTemporalSettings.temporalQuality = codecMinQuality;
|
||||
}
|
||||
}
|
||||
|
||||
SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &gTemporalSettings);
|
||||
SCSetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
|
||||
SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
|
||||
|
||||
err = SCCompressSequenceBegin(qtdata->theComponent, qtexport->thePixMap, NULL, &qtexport->anImageDescription);
|
||||
CheckError (err, "SCCompressSequenceBegin error" );
|
||||
}
|
||||
|
||||
|
||||
static void QT_DoAddVideoSamplesToMedia (int frame, int *pixels, int rectx, int recty)
|
||||
{
|
||||
OSErr err = noErr;
|
||||
Rect imageRect;
|
||||
|
||||
int index;
|
||||
int boxsize;
|
||||
unsigned char *from, *to;
|
||||
|
||||
short syncFlag;
|
||||
long dataSize;
|
||||
Handle compressedData;
|
||||
Ptr myPtr;
|
||||
|
||||
|
||||
//copy and flip renderdata
|
||||
memcpy(qtexport->ibuf2->rect, pixels, 4*rectx*recty);
|
||||
IMB_flipy(qtexport->ibuf2);
|
||||
|
||||
//get pointers to parse bitmapdata
|
||||
myPtr = GetPixBaseAddr(qtexport->thePixMap);
|
||||
imageRect = (**qtexport->thePixMap).bounds;
|
||||
|
||||
from = (unsigned char *) qtexport->ibuf2->rect;
|
||||
to = (unsigned char *) myPtr;
|
||||
|
||||
//parse RGBA bitmap into Quicktime's ARGB GWorld
|
||||
boxsize = rectx * 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;
|
||||
}
|
||||
|
||||
err = SCCompressSequenceFrame(qtdata->theComponent,
|
||||
qtexport->thePixMap,
|
||||
&imageRect,
|
||||
&compressedData,
|
||||
&dataSize,
|
||||
&syncFlag);
|
||||
CheckError(err, "SCCompressSequenceFrame error");
|
||||
|
||||
err = AddMediaSample(qtexport->theMedia,
|
||||
compressedData,
|
||||
0,
|
||||
dataSize,
|
||||
qtdata->duration,
|
||||
(SampleDescriptionHandle)qtexport->anImageDescription,
|
||||
1,
|
||||
syncFlag,
|
||||
NULL);
|
||||
CheckError(err, "AddMediaSample error");
|
||||
|
||||
printf ("added frame %3d (frame %3d in movie): ", frame, frame-sframe);
|
||||
}
|
||||
|
||||
|
||||
static void QT_EndAddVideoSamplesToMedia (void)
|
||||
{
|
||||
SCCompressSequenceEnd(qtdata->theComponent);
|
||||
|
||||
UnlockPixels(qtexport->thePixMap);
|
||||
if (qtexport->theGWorld)
|
||||
DisposeGWorld (qtexport->theGWorld);
|
||||
|
||||
if (qtexport->ibuf)
|
||||
IMB_freeImBuf(qtexport->ibuf);
|
||||
|
||||
if (qtexport->ibuf2)
|
||||
IMB_freeImBuf(qtexport->ibuf2);
|
||||
}
|
||||
#endif //0
|
||||
|
||||
void makeqtstring (RenderData *rd, char *string) {
|
||||
char txt[64];
|
||||
|
||||
if (string==0) return;
|
||||
|
||||
strcpy(string, rd->pic);
|
||||
BLI_convertstringcode(string, G.sce);
|
||||
|
||||
BLI_make_existing_file(string);
|
||||
|
||||
if (BLI_strcasecmp(string + strlen(string) - 4, ".mov")) {
|
||||
sprintf(txt, "%04d_%04d.mov", (rd->sfra) , (rd->efra) );
|
||||
strcat(string, txt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty) {
|
||||
#if 0
|
||||
OSErr err = noErr;
|
||||
|
||||
char name[2048];
|
||||
char theFullPath[255];
|
||||
|
||||
|
||||
if(qtexport == NULL) qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport");
|
||||
|
||||
if(qtdata) {
|
||||
if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
|
||||
free_qtcomponentdata();
|
||||
}
|
||||
|
||||
qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeCodecDataExt");
|
||||
|
||||
if(rd->qtcodecdata == NULL || rd->qtcodecdata->cdParms == NULL) {
|
||||
get_qtcodec_settings(rd);
|
||||
} else {
|
||||
qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
|
||||
|
||||
QT_GetCodecSettingsFromScene(rd);
|
||||
check_renderbutton_framerate(rd);
|
||||
}
|
||||
|
||||
if (G.afbreek != 1) {
|
||||
sframe = (rd->sfra);
|
||||
|
||||
makeqtstring(rd, name);
|
||||
|
||||
sprintf(theFullPath, "%s", name);
|
||||
|
||||
/* 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((const UInt8 *)theFullPath, &myRef, 0);
|
||||
CheckError(err, "FsPathMakeRef error");
|
||||
err = FSGetCatalogInfo(&myRef, kFSCatInfoNone, NULL, NULL, &qtexport->theSpec, NULL);
|
||||
CheckError(err, "FsGetCatalogInfoRef error");
|
||||
|
||||
err = CreateMovieFile (&qtexport->theSpec,
|
||||
kMyCreatorType,
|
||||
smCurrentScript,
|
||||
createMovieFileDeleteCurFile | createMovieFileDontCreateResFile,
|
||||
&qtexport->resRefNum,
|
||||
&qtexport->theMovie );
|
||||
CheckError(err, "CreateMovieFile error");
|
||||
|
||||
if(err != noErr) {
|
||||
G.afbreek = 1;
|
||||
// XXX error("Unable to create Quicktime movie: %s", name);
|
||||
} else {
|
||||
printf("Created QuickTime movie: %s\n", name);
|
||||
|
||||
QT_CreateMyVideoTrack(rectx, recty);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void append_qt(struct RenderData *rd, int frame, int *pixels, int rectx, int recty) {
|
||||
//QT_DoAddVideoSamplesToMedia(frame, pixels, rectx, recty);
|
||||
}
|
||||
|
||||
|
||||
void end_qt(void) {
|
||||
/* OSErr err = noErr;
|
||||
short resId = movieInDataForkResID;
|
||||
|
||||
if(qtexport->theMovie) {
|
||||
QT_EndCreateMyVideoTrack();
|
||||
|
||||
err = AddMovieResource (qtexport->theMovie, qtexport->resRefNum, &resId, qtexport->qtfilename);
|
||||
CheckError(err, "AddMovieResource error");
|
||||
|
||||
err = QT_AddUserDataTextToMovie(qtexport->theMovie, "Made with Blender", kUserDataTextInformation);
|
||||
CheckError(err, "AddUserDataTextToMovie error");
|
||||
|
||||
err = UpdateMovieResource(qtexport->theMovie, qtexport->resRefNum, resId, qtexport->qtfilename);
|
||||
CheckError(err, "UpdateMovieResource error");
|
||||
|
||||
if(qtexport->resRefNum) CloseMovieFile(qtexport->resRefNum);
|
||||
|
||||
DisposeMovie(qtexport->theMovie);
|
||||
|
||||
printf("Finished QuickTime movie.\n");
|
||||
}
|
||||
|
||||
if(qtexport) {
|
||||
MEM_freeN(qtexport);
|
||||
qtexport = NULL;
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
void free_qtcomponentdata(void) {
|
||||
/*if(qtdata) {
|
||||
if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
|
||||
MEM_freeN(qtdata);
|
||||
qtdata = NULL;
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
static void check_renderbutton_framerate(RenderData *rd)
|
||||
{
|
||||
// to keep float framerates consistent between the codec dialog and frs/sec button.
|
||||
/* OSErr err;
|
||||
|
||||
//err = SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
|
||||
CheckError(err, "SCGetInfo fr error");
|
||||
|
||||
if( (rd->frs_sec == 24 || rd->frs_sec == 30 || rd->frs_sec == 60) &&
|
||||
(qtdata->gTemporalSettings.frameRate == 1571553 ||
|
||||
qtdata->gTemporalSettings.frameRate == 1964113 ||
|
||||
qtdata->gTemporalSettings.frameRate == 3928227)) {;}
|
||||
else {
|
||||
if (rd->frs_sec_base > 0)
|
||||
qtdata->gTemporalSettings.frameRate =
|
||||
(rd->frs_sec << 16) / rd->frs_sec_base ;
|
||||
}
|
||||
|
||||
//err = SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
|
||||
CheckError( err, "SCSetInfo error" );
|
||||
|
||||
if(qtdata->gTemporalSettings.frameRate == 1571553) { // 23.98 fps
|
||||
qtdata->kVideoTimeScale = 24000;
|
||||
qtdata->duration = 1001;
|
||||
} else if (qtdata->gTemporalSettings.frameRate == 1964113) { // 29.97 fps
|
||||
qtdata->kVideoTimeScale = 30000;
|
||||
qtdata->duration = 1001;
|
||||
} else if (qtdata->gTemporalSettings.frameRate == 3928227) { // 59.94 fps
|
||||
qtdata->kVideoTimeScale = 60000;
|
||||
qtdata->duration = 1001;
|
||||
} else {
|
||||
qtdata->kVideoTimeScale = (qtdata->gTemporalSettings.frameRate >> 16) * 100;
|
||||
qtdata->duration = 100;
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
int get_qtcodec_settings(RenderData *rd)
|
||||
{
|
||||
/* OSErr err = noErr;
|
||||
|
||||
// erase any existing codecsetting
|
||||
if(qtdata) {
|
||||
if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
|
||||
free_qtcomponentdata();
|
||||
}
|
||||
|
||||
// allocate new
|
||||
qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeComponentData");
|
||||
qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
|
||||
|
||||
// get previous selected codecsetting, if any
|
||||
if(rd->qtcodecdata && rd->qtcodecdata->cdParms) {
|
||||
QT_GetCodecSettingsFromScene(rd);
|
||||
check_renderbutton_framerate(rd);
|
||||
} else {
|
||||
// configure the standard image compression dialog box
|
||||
// set some default settings
|
||||
qtdata->gSpatialSettings.codec = anyCodec;
|
||||
qtdata->gSpatialSettings.spatialQuality = codecMaxQuality;
|
||||
qtdata->gTemporalSettings.temporalQuality = codecMaxQuality;
|
||||
qtdata->gTemporalSettings.keyFrameRate = 25;
|
||||
qtdata->aDataRateSetting.dataRate = 90 * 1024;
|
||||
|
||||
err = SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
|
||||
CheckError(err, "SCSetInfo1 error");
|
||||
err = SCSetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
|
||||
CheckError(err, "SCSetInfo2 error");
|
||||
err = SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
|
||||
CheckError(err, "SCSetInfo3 error");
|
||||
}
|
||||
|
||||
check_renderbutton_framerate(rd);
|
||||
|
||||
// put up the dialog box - it needs to be called from the main thread
|
||||
err = SCRequestSequenceSettings(qtdata->theComponent);
|
||||
|
||||
if (err == scUserCancelled) {
|
||||
G.afbreek = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get user selected data
|
||||
SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
|
||||
SCGetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
|
||||
SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
|
||||
|
||||
QT_SaveCodecSettingsToScene(rd);
|
||||
|
||||
// framerate jugglin'
|
||||
if(qtdata->gTemporalSettings.frameRate == 1571553) { // 23.98 fps
|
||||
qtdata->kVideoTimeScale = 24000;
|
||||
qtdata->duration = 1001;
|
||||
|
||||
rd->frs_sec = 24;
|
||||
rd->frs_sec_base = 1.001;
|
||||
} else if (qtdata->gTemporalSettings.frameRate == 1964113) { // 29.97 fps
|
||||
qtdata->kVideoTimeScale = 30000;
|
||||
qtdata->duration = 1001;
|
||||
|
||||
rd->frs_sec = 30;
|
||||
rd->frs_sec_base = 1.001;
|
||||
} else if (qtdata->gTemporalSettings.frameRate == 3928227) { // 59.94 fps
|
||||
qtdata->kVideoTimeScale = 60000;
|
||||
qtdata->duration = 1001;
|
||||
|
||||
rd->frs_sec = 60;
|
||||
rd->frs_sec_base = 1.001;
|
||||
} else {
|
||||
double fps = qtdata->gTemporalSettings.frameRate;
|
||||
|
||||
qtdata->kVideoTimeScale = 60000;
|
||||
qtdata->duration = qtdata->kVideoTimeScale / (qtdata->gTemporalSettings.frameRate / 65536);
|
||||
|
||||
if ((qtdata->gTemporalSettings.frameRate & 0xffff) == 0) {
|
||||
rd->frs_sec = fps / 65536;
|
||||
rd->frs_sec_base = 1;
|
||||
} else {
|
||||
// we do our very best...
|
||||
rd->frs_sec = (fps * 10000 / 65536);
|
||||
rd->frs_sec_base = 10000;
|
||||
}
|
||||
}
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* _WIN32 || __APPLE__ */
|
||||
#endif /* WITH_QUICKTIME */
|
||||
|
526
source/blender/quicktime/apple/qtkit_import.m
Normal file
526
source/blender/quicktime/apple/qtkit_import.m
Normal file
@ -0,0 +1,526 @@
|
||||
/**
|
||||
* $Id: qtkit_import.m 19323 2009-03-17 21:44:58Z blendix $
|
||||
*
|
||||
* qtkit_import.m
|
||||
*
|
||||
* Code to use Quicktime to load images/movies as texture.
|
||||
*
|
||||
* ***** BEGIN GPL 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.
|
||||
*
|
||||
* 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)
|
||||
* Damien Plisson 11/2009
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
#ifdef WITH_QUICKTIME
|
||||
|
||||
#include "IMB_anim.h"
|
||||
#include "BLO_sys_types.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BLI_dynstr.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <QTKit/QTKit.h>
|
||||
|
||||
#include "quicktime_import.h"
|
||||
#include "quicktime_export.h"
|
||||
|
||||
// quicktime structure definition
|
||||
// this structure is part of the anim struct
|
||||
|
||||
typedef struct _QuicktimeMovie {
|
||||
QTMovie *movie;
|
||||
QTMedia *media;
|
||||
|
||||
long durationTime;
|
||||
long durationScale;
|
||||
long framecount;
|
||||
|
||||
|
||||
ImBuf *ibuf;
|
||||
|
||||
long previousPosition;
|
||||
|
||||
} QuicktimeMovie;
|
||||
|
||||
|
||||
#define QTIME_DEBUG 0
|
||||
|
||||
|
||||
void quicktime_init(void)
|
||||
{
|
||||
G.have_quicktime = TRUE;
|
||||
}
|
||||
|
||||
|
||||
void quicktime_exit(void)
|
||||
{
|
||||
if(G.have_quicktime) {
|
||||
free_qtcomponentdata();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int anim_is_quicktime (char *name)
|
||||
{
|
||||
NSAutoreleasePool *pool;
|
||||
|
||||
// dont let quicktime movie import handle these
|
||||
if( BLI_testextensie(name, ".swf") ||
|
||||
BLI_testextensie(name, ".txt") ||
|
||||
BLI_testextensie(name, ".mpg") ||
|
||||
BLI_testextensie(name, ".avi") || // wouldnt be appropriate ;)
|
||||
BLI_testextensie(name, ".tga") ||
|
||||
BLI_testextensie(name, ".png") ||
|
||||
BLI_testextensie(name, ".bmp") ||
|
||||
BLI_testextensie(name, ".jpg") ||
|
||||
BLI_testextensie(name, ".wav") ||
|
||||
BLI_testextensie(name, ".zip") ||
|
||||
BLI_testextensie(name, ".mp3")) return 0;
|
||||
|
||||
if(QTIME_DEBUG) printf("qt: checking as movie: %s\n", name);
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
if([QTMovie canInitWithFile:[NSString stringWithUTF8String:name]])
|
||||
{
|
||||
[pool drain];
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
[pool drain];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void free_anim_quicktime (struct anim *anim) {
|
||||
if (anim == NULL) return;
|
||||
if (anim->qtime == NULL) return;
|
||||
|
||||
if(anim->qtime->ibuf)
|
||||
IMB_freeImBuf(anim->qtime->ibuf);
|
||||
|
||||
[anim->qtime->media release];
|
||||
[anim->qtime->movie release];
|
||||
|
||||
if(anim->qtime) MEM_freeN (anim->qtime);
|
||||
|
||||
anim->qtime = NULL;
|
||||
|
||||
anim->duration = 0;
|
||||
}
|
||||
|
||||
static ImBuf * nsImageToiBuf(NSImage *sourceImage, int width, int height)
|
||||
{
|
||||
ImBuf *ibuf = NULL;
|
||||
uchar *rasterRGB = NULL;
|
||||
uchar *rasterRGBA = NULL;
|
||||
uchar *toIBuf = NULL;
|
||||
int x, y, to_i, from_i;
|
||||
NSSize bitmapSize;
|
||||
NSBitmapImageRep *blBitmapFormatImageRGB,*blBitmapFormatImageRGBA,*bitmapImage;
|
||||
NSEnumerator *enumerator;
|
||||
NSImageRep *representation;
|
||||
|
||||
ibuf = IMB_allocImBuf (width, height, 32, IB_rect, 0);
|
||||
if (!ibuf) {
|
||||
if(QTIME_DEBUG) printf("quicktime_import: could not allocate memory for the " \
|
||||
"image.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*Get the bitmap of the image*/
|
||||
enumerator = [[sourceImage representations] objectEnumerator];
|
||||
while (representation = [enumerator nextObject]) {
|
||||
if ([representation isKindOfClass:[NSBitmapImageRep class]]) {
|
||||
bitmapImage = (NSBitmapImageRep *)representation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (([bitmapImage bitmapFormat] & 0x5) == 0) {
|
||||
/* Try a fast copy if the image is a planar RGBA 32bit bitmap*/
|
||||
toIBuf = (uchar*)ibuf->rect;
|
||||
rasterRGB = (uchar*)[bitmapImage bitmapData];
|
||||
for (y = 0; y < height; y++) {
|
||||
to_i = (height-y-1)*width;
|
||||
from_i = y*width;
|
||||
memcpy(toIBuf+4*to_i, rasterRGB+4*from_i, 4*width);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
bitmapSize.width = width;
|
||||
bitmapSize.height = height;
|
||||
|
||||
/* Tell cocoa image resolution is same as current system one */
|
||||
[bitmapImage setSize:bitmapSize];
|
||||
|
||||
/* Convert the image in a RGBA 32bit format */
|
||||
/* As Core Graphics does not support contextes with non premutliplied alpha,
|
||||
we need to get alpha key values in a separate batch */
|
||||
|
||||
/* First get RGB values w/o Alpha to avoid pre-multiplication, 32bit but last byte is unused */
|
||||
blBitmapFormatImageRGB = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
|
||||
pixelsWide:width
|
||||
pixelsHigh:height
|
||||
bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO
|
||||
colorSpaceName:NSCalibratedRGBColorSpace
|
||||
bitmapFormat:0
|
||||
bytesPerRow:4*width
|
||||
bitsPerPixel:32/*RGB format padded to 32bits*/];
|
||||
|
||||
[NSGraphicsContext saveGraphicsState];
|
||||
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGB]];
|
||||
[bitmapImage draw];
|
||||
[NSGraphicsContext restoreGraphicsState];
|
||||
|
||||
rasterRGB = (uchar*)[blBitmapFormatImageRGB bitmapData];
|
||||
if (rasterRGB == NULL) {
|
||||
[bitmapImage release];
|
||||
[blBitmapFormatImageRGB release];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Then get Alpha values by getting the RGBA image (that is premultiplied btw) */
|
||||
blBitmapFormatImageRGBA = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
|
||||
pixelsWide:width
|
||||
pixelsHigh:height
|
||||
bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO
|
||||
colorSpaceName:NSCalibratedRGBColorSpace
|
||||
bitmapFormat:0
|
||||
bytesPerRow:4*width
|
||||
bitsPerPixel:32/* RGBA */];
|
||||
|
||||
[NSGraphicsContext saveGraphicsState];
|
||||
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGBA]];
|
||||
[bitmapImage draw];
|
||||
[NSGraphicsContext restoreGraphicsState];
|
||||
|
||||
rasterRGBA = (uchar*)[blBitmapFormatImageRGBA bitmapData];
|
||||
if (rasterRGBA == NULL) {
|
||||
[bitmapImage release];
|
||||
[blBitmapFormatImageRGB release];
|
||||
[blBitmapFormatImageRGBA release];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*Copy the image to ibuf, flipping it vertically*/
|
||||
toIBuf = (uchar*)ibuf->rect;
|
||||
for (x = 0; x < width; x++) {
|
||||
for (y = 0; y < height; y++) {
|
||||
to_i = (height-y-1)*width + x;
|
||||
from_i = y*width + x;
|
||||
|
||||
toIBuf[4*to_i] = rasterRGB[4*from_i]; /* R */
|
||||
toIBuf[4*to_i+1] = rasterRGB[4*from_i+1]; /* G */
|
||||
toIBuf[4*to_i+2] = rasterRGB[4*from_i+2]; /* B */
|
||||
toIBuf[4*to_i+3] = rasterRGBA[4*from_i+3]; /* A */
|
||||
}
|
||||
}
|
||||
|
||||
[blBitmapFormatImageRGB release];
|
||||
[blBitmapFormatImageRGBA release];
|
||||
}
|
||||
|
||||
return ibuf;
|
||||
}
|
||||
|
||||
ImBuf * qtime_fetchibuf (struct anim *anim, int position)
|
||||
{
|
||||
NSImage *frameImage;
|
||||
QTTime time;
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
ImBuf *ibuf;
|
||||
|
||||
if (anim == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (position == anim->qtime->previousPosition+1) { //Optimize sequential read
|
||||
[anim->qtime->movie stepForward];
|
||||
frameImage = [anim->qtime->movie currentFrameImage];
|
||||
anim->qtime->previousPosition++;
|
||||
}
|
||||
else {
|
||||
time.timeScale = anim->qtime->durationScale;
|
||||
time.timeValue = (anim->qtime->durationTime * position) / anim->qtime->framecount;
|
||||
|
||||
[anim->qtime->movie setCurrentTime:time];
|
||||
frameImage = [anim->qtime->movie currentFrameImage];
|
||||
|
||||
anim->qtime->previousPosition = position;
|
||||
}
|
||||
|
||||
if (frameImage == nil) {
|
||||
if(QTIME_DEBUG) printf ("Error reading frame from Quicktime");
|
||||
[pool drain];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ibuf = nsImageToiBuf(frameImage,anim->x, anim->y);
|
||||
[pool drain];
|
||||
return ibuf;
|
||||
}
|
||||
|
||||
|
||||
int startquicktime (struct anim *anim)
|
||||
{
|
||||
NSAutoreleasePool *pool;
|
||||
NSArray* videoTracks;
|
||||
NSSize frameSize;
|
||||
QTTime qtTimeDuration;
|
||||
NSDictionary *attributes;
|
||||
|
||||
anim->qtime = MEM_callocN (sizeof(QuicktimeMovie),"animqt");
|
||||
|
||||
if (anim->qtime == NULL) {
|
||||
if(QTIME_DEBUG) printf("Can't alloc qtime: %s\n", anim->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
attributes = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSString stringWithUTF8String:anim->name], QTMovieFileNameAttribute,
|
||||
[NSNumber numberWithBool:NO], QTMovieEditableAttribute,
|
||||
nil];
|
||||
|
||||
anim->qtime->movie = [QTMovie movieWithAttributes:attributes error:NULL];
|
||||
|
||||
if (!anim->qtime->movie) {
|
||||
if(QTIME_DEBUG) printf("qt: bad movie %s\n", anim->name);
|
||||
MEM_freeN(anim->qtime);
|
||||
if(QTIME_DEBUG) printf("qt: can't load %s\n", anim->name);
|
||||
[pool drain];
|
||||
return -1;
|
||||
}
|
||||
[anim->qtime->movie retain];
|
||||
|
||||
// sets Media and Track!
|
||||
|
||||
videoTracks = [anim->qtime->movie tracksOfMediaType:QTMediaTypeVideo];
|
||||
|
||||
if([videoTracks count] == 0) {
|
||||
if(QTIME_DEBUG) printf("qt: no video tracks for movie %s\n", anim->name);
|
||||
[anim->qtime->movie release];
|
||||
MEM_freeN(anim->qtime);
|
||||
if(QTIME_DEBUG) printf("qt: can't load %s\n", anim->name);
|
||||
[pool drain];
|
||||
return -1;
|
||||
}
|
||||
|
||||
anim->qtime->media = [[videoTracks objectAtIndex:0] media];
|
||||
[anim->qtime->media retain];
|
||||
|
||||
|
||||
frameSize = [[anim->qtime->movie attributeForKey:QTMovieCurrentSizeAttribute] sizeValue];
|
||||
anim->x = frameSize.width;
|
||||
anim->y = frameSize.height;
|
||||
|
||||
if(anim->x == 0 && anim->y == 0) {
|
||||
if(QTIME_DEBUG) printf("qt: error, no dimensions\n");
|
||||
free_anim_quicktime(anim);
|
||||
[pool drain];
|
||||
return -1;
|
||||
}
|
||||
|
||||
anim->qtime->ibuf = IMB_allocImBuf (anim->x, anim->y, 32, IB_rect, 0);
|
||||
|
||||
qtTimeDuration = [[anim->qtime->media attributeForKey:QTMediaDurationAttribute] QTTimeValue];
|
||||
anim->qtime->durationTime = qtTimeDuration.timeValue;
|
||||
anim->qtime->durationScale = qtTimeDuration.timeScale;
|
||||
|
||||
anim->qtime->framecount = [[anim->qtime->media attributeForKey:QTMediaSampleCountAttribute] longValue];
|
||||
anim->qtime->previousPosition = -2; //Force seeking for first read
|
||||
|
||||
//fill blender's anim struct
|
||||
|
||||
anim->duration = anim->qtime->framecount;
|
||||
anim->params = 0;
|
||||
|
||||
anim->interlacing = 0;
|
||||
anim->orientation = 0;
|
||||
anim->framesize = anim->x * anim->y * 4;
|
||||
|
||||
anim->curposition = 0;
|
||||
|
||||
[pool drain];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int imb_is_a_quicktime (char *name)
|
||||
{
|
||||
NSImage *image;
|
||||
int result;
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
// dont let quicktime image import handle these
|
||||
if( BLI_testextensie(name, ".swf") ||
|
||||
BLI_testextensie(name, ".txt") ||
|
||||
BLI_testextensie(name, ".mpg") ||
|
||||
BLI_testextensie(name, ".wav") ||
|
||||
BLI_testextensie(name, ".mov") || // not as image, doesn't work
|
||||
BLI_testextensie(name, ".avi") ||
|
||||
BLI_testextensie(name, ".mp3")) return 0;
|
||||
|
||||
|
||||
image = [NSImage alloc];
|
||||
if ([image initWithContentsOfFile:[NSString stringWithUTF8String:name]])
|
||||
result = true;
|
||||
else
|
||||
result = false;
|
||||
|
||||
[image release];
|
||||
[pool drain];
|
||||
return result;
|
||||
}
|
||||
|
||||
ImBuf *imb_quicktime_decode(unsigned char *mem, int size, int flags)
|
||||
{
|
||||
struct ImBuf *ibuf = NULL;
|
||||
NSSize bitmapSize;
|
||||
uchar *rasterRGB = NULL;
|
||||
uchar *rasterRGBA = NULL;
|
||||
uchar *toIBuf = NULL;
|
||||
int x, y, to_i, from_i;
|
||||
NSData *data;
|
||||
NSBitmapImageRep *bitmapImage;
|
||||
NSBitmapImageRep *blBitmapFormatImageRGB,*blBitmapFormatImageRGBA;
|
||||
NSAutoreleasePool *pool;
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
data = [NSData dataWithBytes:mem length:size];
|
||||
bitmapImage = [[NSBitmapImageRep alloc] initWithData:data];
|
||||
|
||||
if (!bitmapImage) {
|
||||
fprintf(stderr, "imb_cocoaLoadImage: error loading image\n");
|
||||
[pool drain];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bitmapSize.width = [bitmapImage pixelsWide];
|
||||
bitmapSize.height = [bitmapImage pixelsHigh];
|
||||
|
||||
/* Tell cocoa image resolution is same as current system one */
|
||||
[bitmapImage setSize:bitmapSize];
|
||||
|
||||
/* allocate the image buffer */
|
||||
ibuf = IMB_allocImBuf(bitmapSize.width, bitmapSize.height, 32/*RGBA*/, 0, 0);
|
||||
if (!ibuf) {
|
||||
fprintf(stderr,
|
||||
"imb_cocoaLoadImage: could not allocate memory for the " \
|
||||
"image.\n");
|
||||
[bitmapImage release];
|
||||
[pool drain];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* read in the image data */
|
||||
if (!(flags & IB_test)) {
|
||||
|
||||
/* allocate memory for the ibuf->rect */
|
||||
imb_addrectImBuf(ibuf);
|
||||
|
||||
/* Convert the image in a RGBA 32bit format */
|
||||
/* As Core Graphics does not support contextes with non premutliplied alpha,
|
||||
we need to get alpha key values in a separate batch */
|
||||
|
||||
/* First get RGB values w/o Alpha to avoid pre-multiplication, 32bit but last byte is unused */
|
||||
blBitmapFormatImageRGB = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
|
||||
pixelsWide:bitmapSize.width
|
||||
pixelsHigh:bitmapSize.height
|
||||
bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO
|
||||
colorSpaceName:NSCalibratedRGBColorSpace
|
||||
bitmapFormat:0
|
||||
bytesPerRow:4*bitmapSize.width
|
||||
bitsPerPixel:32/*RGB format padded to 32bits*/];
|
||||
|
||||
[NSGraphicsContext saveGraphicsState];
|
||||
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGB]];
|
||||
[bitmapImage draw];
|
||||
[NSGraphicsContext restoreGraphicsState];
|
||||
|
||||
rasterRGB = (uchar*)[blBitmapFormatImageRGB bitmapData];
|
||||
if (rasterRGB == NULL) {
|
||||
[bitmapImage release];
|
||||
[blBitmapFormatImageRGB release];
|
||||
[pool drain];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Then get Alpha values by getting the RGBA image (that is premultiplied btw) */
|
||||
blBitmapFormatImageRGBA = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
|
||||
pixelsWide:bitmapSize.width
|
||||
pixelsHigh:bitmapSize.height
|
||||
bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO
|
||||
colorSpaceName:NSCalibratedRGBColorSpace
|
||||
bitmapFormat:0
|
||||
bytesPerRow:4*bitmapSize.width
|
||||
bitsPerPixel:32/* RGBA */];
|
||||
|
||||
[NSGraphicsContext saveGraphicsState];
|
||||
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGBA]];
|
||||
[bitmapImage draw];
|
||||
[NSGraphicsContext restoreGraphicsState];
|
||||
|
||||
rasterRGBA = (uchar*)[blBitmapFormatImageRGBA bitmapData];
|
||||
if (rasterRGBA == NULL) {
|
||||
[bitmapImage release];
|
||||
[blBitmapFormatImageRGB release];
|
||||
[blBitmapFormatImageRGBA release];
|
||||
[pool drain];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*Copy the image to ibuf, flipping it vertically*/
|
||||
toIBuf = (uchar*)ibuf->rect;
|
||||
for (x = 0; x < bitmapSize.width; x++) {
|
||||
for (y = 0; y < bitmapSize.height; y++) {
|
||||
to_i = (bitmapSize.height-y-1)*bitmapSize.width + x;
|
||||
from_i = y*bitmapSize.width + x;
|
||||
|
||||
toIBuf[4*to_i] = rasterRGB[4*from_i]; /* R */
|
||||
toIBuf[4*to_i+1] = rasterRGB[4*from_i+1]; /* G */
|
||||
toIBuf[4*to_i+2] = rasterRGB[4*from_i+2]; /* B */
|
||||
toIBuf[4*to_i+3] = rasterRGBA[4*from_i+3]; /* A */
|
||||
}
|
||||
}
|
||||
|
||||
[blBitmapFormatImageRGB release];
|
||||
[blBitmapFormatImageRGBA release];
|
||||
}
|
||||
|
||||
/* release the cocoa objects */
|
||||
[bitmapImage release];
|
||||
[pool drain];
|
||||
|
||||
if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
|
||||
|
||||
/* return successfully */
|
||||
return (ibuf);
|
||||
}
|
||||
|
||||
|
||||
#endif /* WITH_QUICKTIME */
|
||||
|
@ -52,12 +52,38 @@
|
||||
#include "quicktime_import.h"
|
||||
#include "quicktime_export.h"
|
||||
|
||||
|
||||
#define RECT_WIDTH(r) (r.right-r.left)
|
||||
#define RECT_HEIGHT(r) (r.bottom-r.top)
|
||||
|
||||
#define QTIME_DEBUG 0
|
||||
|
||||
typedef struct _QuicktimeMovie {
|
||||
|
||||
GWorldPtr offscreenGWorld;
|
||||
PixMapHandle offscreenPixMap;
|
||||
Movie movie;
|
||||
Rect movieBounds;
|
||||
short movieRefNum;
|
||||
short movieResId;
|
||||
int movWidth, movHeight;
|
||||
|
||||
|
||||
int framecount;
|
||||
|
||||
|
||||
ImBuf *ibuf;
|
||||
|
||||
|
||||
TimeValue *frameIndex;
|
||||
Media theMedia;
|
||||
Track theTrack;
|
||||
long trackIndex;
|
||||
short depth;
|
||||
|
||||
int have_gw; //ugly
|
||||
} QuicktimeMovie;
|
||||
|
||||
|
||||
|
||||
void quicktime_init(void)
|
||||
{
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "../imbuf/IMB_imbuf.h"
|
||||
#include "../imbuf/IMB_imbuf_types.h"
|
||||
|
||||
#ifndef USE_QTKIT
|
||||
#ifndef __MOVIES__
|
||||
#ifdef _WIN32
|
||||
#include <Movies.h>
|
||||
@ -50,7 +51,8 @@
|
||||
#import <Carbon/Carbon.h>
|
||||
#include <QuickTime/Movies.h>
|
||||
#endif
|
||||
#endif
|
||||
#endif //__MOVIES__
|
||||
#endif //USE_QTKIT
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef __FIXMATH__
|
||||
@ -58,31 +60,6 @@
|
||||
#endif /* __FIXMATH__ */
|
||||
#endif /* _WIN32 _ */
|
||||
|
||||
// quicktime structure definition
|
||||
// this structure is part of the anim struct
|
||||
|
||||
typedef struct _QuicktimeMovie {
|
||||
GWorldPtr offscreenGWorld;
|
||||
PixMapHandle offscreenPixMap;
|
||||
|
||||
Movie movie;
|
||||
short movieRefNum;
|
||||
short movieResId;
|
||||
int movWidth, movHeight;
|
||||
Rect movieBounds;
|
||||
|
||||
int framecount;
|
||||
|
||||
TimeValue *frameIndex;
|
||||
ImBuf *ibuf;
|
||||
|
||||
Media theMedia;
|
||||
Track theTrack;
|
||||
long trackIndex;
|
||||
short depth;
|
||||
|
||||
int have_gw; //ugly
|
||||
} QuicktimeMovie;
|
||||
|
||||
char *get_valid_qtname(char *name);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user