diff options
author | Damien Plisson <damien.plisson@yahoo.fr> | 2009-11-18 12:49:42 +0300 |
---|---|---|
committer | Damien Plisson <damien.plisson@yahoo.fr> | 2009-11-18 12:49:42 +0300 |
commit | 624cd67d5571c7e6597151d124416a17a2095d3a (patch) | |
tree | e612a036a1390128b4640e86b015f8003bff100c /source | |
parent | 22e8616a270f3d78467bf136a98f13b2551e020a (diff) |
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
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/imbuf/intern/util.c | 6 | ||||
-rw-r--r-- | source/blender/quicktime/CMakeLists.txt | 6 | ||||
-rw-r--r-- | source/blender/quicktime/apple/qtkit_export.m | 665 | ||||
-rw-r--r-- | source/blender/quicktime/apple/qtkit_import.m | 526 | ||||
-rw-r--r-- | source/blender/quicktime/apple/quicktime_import.c | 28 | ||||
-rw-r--r-- | source/blender/quicktime/quicktime_import.h | 29 |
6 files changed, 1229 insertions, 31 deletions
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c index 26434583118..5bcdd6c9670 100644 --- a/source/blender/imbuf/intern/util.c +++ b/source/blender/imbuf/intern/util.c @@ -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); diff --git a/source/blender/quicktime/CMakeLists.txt b/source/blender/quicktime/CMakeLists.txt index ac503bb62cb..14589ca4c5b 100644 --- a/source/blender/quicktime/CMakeLists.txt +++ b/source/blender/quicktime/CMakeLists.txt @@ -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 . diff --git a/source/blender/quicktime/apple/qtkit_export.m b/source/blender/quicktime/apple/qtkit_export.m new file mode 100644 index 00000000000..c5e878c6ebc --- /dev/null +++ b/source/blender/quicktime/apple/qtkit_export.m @@ -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 */ + diff --git a/source/blender/quicktime/apple/qtkit_import.m b/source/blender/quicktime/apple/qtkit_import.m new file mode 100644 index 00000000000..2da66e6daa6 --- /dev/null +++ b/source/blender/quicktime/apple/qtkit_import.m @@ -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 */ + diff --git a/source/blender/quicktime/apple/quicktime_import.c b/source/blender/quicktime/apple/quicktime_import.c index 1f3071f114c..571da92a292 100644 --- a/source/blender/quicktime/apple/quicktime_import.c +++ b/source/blender/quicktime/apple/quicktime_import.c @@ -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) { diff --git a/source/blender/quicktime/quicktime_import.h b/source/blender/quicktime/quicktime_import.h index 1444827e12e..6dea5956195 100644 --- a/source/blender/quicktime/quicktime_import.h +++ b/source/blender/quicktime/quicktime_import.h @@ -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); |