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:
@@ -84,6 +84,7 @@ OPTION(WITH_OPENCOLLADA "Enable OpenCollada Support (http://www.opencollada.org
|
|||||||
|
|
||||||
IF (APPLE)
|
IF (APPLE)
|
||||||
OPTION(WITH_COCOA "Use Cocoa framework instead of deprecated Carbon" ON)
|
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)
|
OPTION(WITH_LIBS10.5 "Use 10.5 libs (needed for 64bit builds)" OFF)
|
||||||
ENDIF (APPLE)
|
ENDIF (APPLE)
|
||||||
|
|
||||||
@@ -525,7 +526,15 @@ IF(APPLE)
|
|||||||
|
|
||||||
IF (WITH_COCOA)
|
IF (WITH_COCOA)
|
||||||
SET(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing -DGHOST_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)
|
ELSE (WITH_COCOA)
|
||||||
SET(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
|
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")
|
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);
|
if(UTIL_DEBUG) printf("in getanimtype: %s\n", name);
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
# ifdef WITH_QUICKTIME
|
||||||
|
if (isqtime(name)) return (ANIM_QTIME);
|
||||||
|
# endif
|
||||||
# ifdef WITH_FFMPEG
|
# ifdef WITH_FFMPEG
|
||||||
/* stat test below fails on large files > 4GB */
|
/* stat test below fails on large files > 4GB */
|
||||||
if (isffmpeg(name)) return (ANIM_FFMPEG);
|
if (isffmpeg(name)) return (ANIM_FFMPEG);
|
||||||
@@ -394,9 +397,6 @@ int imb_get_anim_type(char * name) {
|
|||||||
if (isavi(name)) return (ANIM_AVI);
|
if (isavi(name)) return (ANIM_AVI);
|
||||||
|
|
||||||
if (ismovie(name)) return (ANIM_MOVIE);
|
if (ismovie(name)) return (ANIM_MOVIE);
|
||||||
# ifdef WITH_QUICKTIME
|
|
||||||
if (isqtime(name)) return (ANIM_QTIME);
|
|
||||||
# endif
|
|
||||||
#else
|
#else
|
||||||
if (ib_stat(name,&st) == -1) return(0);
|
if (ib_stat(name,&st) == -1) return(0);
|
||||||
if (((st.st_mode) & S_IFMT) != S_IFREG) return(0);
|
if (((st.st_mode) & S_IFMT) != S_IFREG) return(0);
|
||||||
|
@@ -24,7 +24,11 @@
|
|||||||
#
|
#
|
||||||
# ***** END GPL LICENSE BLOCK *****
|
# ***** 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
|
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_import.h"
|
||||||
#include "quicktime_export.h"
|
#include "quicktime_export.h"
|
||||||
|
|
||||||
|
|
||||||
#define RECT_WIDTH(r) (r.right-r.left)
|
#define RECT_WIDTH(r) (r.right-r.left)
|
||||||
#define RECT_HEIGHT(r) (r.bottom-r.top)
|
#define RECT_HEIGHT(r) (r.bottom-r.top)
|
||||||
|
|
||||||
#define QTIME_DEBUG 0
|
#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)
|
void quicktime_init(void)
|
||||||
{
|
{
|
||||||
|
@@ -42,6 +42,7 @@
|
|||||||
#include "../imbuf/IMB_imbuf.h"
|
#include "../imbuf/IMB_imbuf.h"
|
||||||
#include "../imbuf/IMB_imbuf_types.h"
|
#include "../imbuf/IMB_imbuf_types.h"
|
||||||
|
|
||||||
|
#ifndef USE_QTKIT
|
||||||
#ifndef __MOVIES__
|
#ifndef __MOVIES__
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <Movies.h>
|
#include <Movies.h>
|
||||||
@@ -50,7 +51,8 @@
|
|||||||
#import <Carbon/Carbon.h>
|
#import <Carbon/Carbon.h>
|
||||||
#include <QuickTime/Movies.h>
|
#include <QuickTime/Movies.h>
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif //__MOVIES__
|
||||||
|
#endif //USE_QTKIT
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#ifndef __FIXMATH__
|
#ifndef __FIXMATH__
|
||||||
@@ -58,31 +60,6 @@
|
|||||||
#endif /* __FIXMATH__ */
|
#endif /* __FIXMATH__ */
|
||||||
#endif /* _WIN32 _ */
|
#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);
|
char *get_valid_qtname(char *name);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user