Initial commit of imagebrowser in trunk. BIG COMMIT! Main changes: * completely reworked imasel space * creation and storage of the preview images for materials, textures, world and lamp * thumbnails of images and movie files when browsing in the file system * loading previews from external .blend when linking or appending * thumbnail caching according to the Thumbnail Managing Standard: http://jens.triq.net/thumbnail-spec/ * for now just kept imasel access mostly as old imgbrowser (CTRL+F4, CTRL+F1) a bit hidden still. * filtering of file types (images, movies, .blend, py,...) * preliminary managing of bookmarks ('B' button to add, XKEY while bookmark active to delete) More detailed info which will be updated here: http://wiki.blender.org/index.php/User:Elubie/PreviewImageBrowser Places that need special review (and probably fixes): * BLO_blendhandle_get_previews in readblenentry * readfile.c: do_version and refactorings of do_library_append * UI integration TODO and known issues still: * Accented characters do not display correctly with international fonts * Crash was reported when browsing in directory with movie files * Bookmark management still needs some UI work (second scrollbar?), feedback here is welcome! Credits: Samir Bharadwaj (samirbharadwaj@yahoo.com) for the icon images. Many thanks to everyone who gave feedback and helped so far!
		
			
				
	
	
		
			780 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			780 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**
 | |
|  * $Id$
 | |
|  *
 | |
|  * quicktime_import.c
 | |
|  *
 | |
|  * Code to use Quicktime to load images/movies as texture.
 | |
|  *
 | |
|  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 | |
|  * This program is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU General Public License
 | |
|  * as published by the Free Software Foundation; either version 2
 | |
|  * of the License, or (at your option) any later version. The Blender
 | |
|  * Foundation also sells licenses for use in proprietary software under
 | |
|  * the Blender License.  See http://www.blender.org/BL/ for information
 | |
|  * about this.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program; if not, write to the Free Software Foundation,
 | |
|  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 | |
|  *
 | |
|  *
 | |
|  * The Original Code is written by Rob Haarsma (phase)
 | |
|  *
 | |
|  * Contributor(s): Stefan Gartner (sgefant)
 | |
|  *
 | |
|  * ***** END GPL/BL DUAL LICENSE BLOCK *****
 | |
|  */
 | |
| #ifdef WITH_QUICKTIME
 | |
| 
 | |
| #if defined(_WIN32) || defined(__APPLE__)
 | |
| 
 | |
| #include "IMB_anim.h"
 | |
| #include "BLO_sys_types.h"
 | |
| #include "BKE_global.h"
 | |
| #include "BLI_dynstr.h"
 | |
| 
 | |
| #ifdef __APPLE__
 | |
| #include <QuickTime/Movies.h>
 | |
| #include <QuickTime/QuickTimeComponents.h>
 | |
| #endif
 | |
| 
 | |
| #ifdef _WIN32
 | |
| #include <Movies.h>
 | |
| #include <QTML.h>
 | |
| #include <TextUtils.h>
 | |
| #include <QuickTimeComponents.h>
 | |
| #endif /* _WIN32 */
 | |
| 
 | |
| 
 | |
| #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
 | |
| 
 | |
| 
 | |
| void quicktime_init(void)
 | |
| {
 | |
| #ifdef _WIN32
 | |
| 	if (InitializeQTML(0) != noErr)
 | |
| 		G.have_quicktime = FALSE;
 | |
| 	else
 | |
| 		G.have_quicktime = TRUE;
 | |
| #endif /* _WIN32 */
 | |
| 
 | |
| 	/* Initialize QuickTime */
 | |
| #if defined(_WIN32) || defined (__APPLE__)
 | |
| 	if (EnterMovies() != noErr)
 | |
| 		G.have_quicktime = FALSE;
 | |
| 	else
 | |
| #endif /* _WIN32 || __APPLE__ */
 | |
| #ifdef __linux__
 | |
| 	/* inititalize quicktime codec registry */
 | |
| 		lqt_registry_init();
 | |
| #endif
 | |
| 	G.have_quicktime = TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| void quicktime_exit(void)
 | |
| {
 | |
| #if defined(_WIN32) || defined(__APPLE__)
 | |
| #ifdef WITH_QUICKTIME
 | |
| 	if(G.have_quicktime) {
 | |
| 		free_qtcomponentdata();
 | |
| 		ExitMovies();
 | |
| #ifdef _WIN32
 | |
| 		TerminateQTML();
 | |
| #endif /* _WIN32 */
 | |
| 	}
 | |
| #endif /* WITH_QUICKTIME */
 | |
| #endif /* _WIN32 || __APPLE__ */
 | |
| }
 | |
| 
 | |
| 
 | |
| #ifdef _WIN32
 | |
| char *get_valid_qtname(char *name)
 | |
| {
 | |
| 	TCHAR Buffer[MAX_PATH];
 | |
| 	DWORD dwRet;
 | |
| 	char *qtname;
 | |
| 	DynStr *ds= BLI_dynstr_new();
 | |
| 
 | |
| 	dwRet = GetCurrentDirectory(MAX_PATH, Buffer);
 | |
| 
 | |
| 	if(name[1] != ':') {
 | |
| 		char drive[2];
 | |
| 
 | |
| 		if(name[0] == '/' || name[0] == '\\') {
 | |
| 			drive[0] = Buffer[0];
 | |
| 			drive[1] = '\0';
 | |
| 
 | |
| 			BLI_dynstr_append(ds, drive);
 | |
| 			BLI_dynstr_append(ds, ":");
 | |
| 			BLI_dynstr_append(ds, name);
 | |
| 		} else {
 | |
| 			BLI_dynstr_append(ds, Buffer);
 | |
| 			BLI_dynstr_append(ds, "/");
 | |
| 			BLI_dynstr_append(ds, name);
 | |
| 		}
 | |
| 	} else {
 | |
| 		BLI_dynstr_append(ds, name);
 | |
| 	}
 | |
| 
 | |
| 	qtname= BLI_dynstr_get_cstring(ds);
 | |
| 	BLI_dynstr_free(ds);
 | |
| 
 | |
| 	return qtname;
 | |
| }
 | |
| #endif /* _WIN32 */
 | |
| 
 | |
| 
 | |
| int anim_is_quicktime (char *name)
 | |
| {
 | |
| 	FSSpec	theFSSpec;
 | |
| 	char	theFullPath[255];
 | |
| 
 | |
| 	Boolean						isMovieFile = false;
 | |
| 	AliasHandle					myAlias = NULL;
 | |
| 	Component					myImporter = NULL;
 | |
| #ifdef __APPLE__
 | |
| 	FInfo						myFinderInfo;
 | |
| 	FSRef						myRef;
 | |
| #else
 | |
| 	char *qtname;
 | |
| 	Str255  dst;
 | |
| #endif
 | |
| 	OSErr						err = noErr;
 | |
| 			
 | |
| 	// 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, ".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);
 | |
| 
 | |
| #ifdef __APPLE__
 | |
| 	sprintf(theFullPath, "%s", name);
 | |
| 
 | |
| 	err = FSPathMakeRef(theFullPath, &myRef, 0);
 | |
| 	err = FSGetCatalogInfo(&myRef, kFSCatInfoNone, NULL, NULL, &theFSSpec, NULL);
 | |
| #else
 | |
| 	qtname = get_valid_qtname(name);
 | |
| 	sprintf(theFullPath, "%s", qtname);
 | |
| 	MEM_freeN(qtname);
 | |
| 
 | |
| 	CopyCStringToPascal(theFullPath, dst);
 | |
| 	err = FSMakeFSSpec(0, 0L, dst, &theFSSpec);
 | |
| #endif
 | |
| 
 | |
| #ifdef __APPLE__
 | |
| 	// see whether the file type is MovieFileType; to do this, get the Finder information
 | |
| 	err = FSpGetFInfo(&theFSSpec, &myFinderInfo);
 | |
| 	if (err == noErr) {
 | |
| 		if (myFinderInfo.fdType == kQTFileTypeMovie) {
 | |
| 			return(true);
 | |
| 		}
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| /* on mac os x this results in using quicktime for other formats as well
 | |
|  * not sure whether this is intended
 | |
|  */
 | |
| 	// if it isn't a movie file, see whether the file can be imported as a movie
 | |
| 	err = QTNewAlias(&theFSSpec, &myAlias, true);
 | |
| 	if (err == noErr) {
 | |
| 		if (myAlias != NULL) {
 | |
| 			err = GetMovieImporterForDataRef(rAliasType, (Handle)myAlias, kGetMovieImporterDontConsiderGraphicsImporters, &myImporter);
 | |
| 			DisposeHandle((Handle)myAlias);
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	if ((err == noErr) && (myImporter != NULL)) {		// this file is a movie file
 | |
| 		isMovieFile = true;
 | |
| 	}
 | |
| 
 | |
| 	return(isMovieFile);
 | |
| }
 | |
| 
 | |
| 
 | |
| void free_anim_quicktime (struct anim *anim) {
 | |
| 	if (anim == NULL) return;
 | |
| 	if (anim->qtime == NULL) return;
 | |
| 
 | |
| 	UnlockPixels(anim->qtime->offscreenPixMap);
 | |
| 
 | |
| 	if(anim->qtime->have_gw)
 | |
| 		DisposeGWorld( anim->qtime->offscreenGWorld );
 | |
| 	if(anim->qtime->ibuf)
 | |
| 		IMB_freeImBuf(anim->qtime->ibuf);
 | |
| 
 | |
| 	DisposeMovie( anim->qtime->movie );
 | |
| 	CloseMovieFile( anim->qtime->movieRefNum );
 | |
| 
 | |
| 	if(anim->qtime->frameIndex) MEM_freeN (anim->qtime->frameIndex);
 | |
| 	if(anim->qtime) MEM_freeN (anim->qtime);
 | |
| 
 | |
| 	anim->qtime = NULL;
 | |
| 
 | |
| 	anim->duration = 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| static OSErr QT_get_frameIndexes(struct anim *anim)
 | |
| {
 | |
| 	int i;
 | |
| 	OSErr	anErr = noErr;
 | |
| 	OSType	media = VideoMediaType;
 | |
| 	TimeValue nextTime = 0;
 | |
| 	TimeValue	startPoint;
 | |
| 	TimeValue	tmpstartPoint;
 | |
| 	long sampleCount = 0;
 | |
| 
 | |
| 	startPoint = -1;
 | |
| 
 | |
| 	GetMovieNextInterestingTime(anim->qtime->movie, nextTimeMediaSample+nextTimeEdgeOK, (TimeValue)1, &media, 0, 
 | |
| 								1, &startPoint, NULL);
 | |
| 
 | |
| 	tmpstartPoint = startPoint;
 | |
| 
 | |
| 	anim->qtime->framecount = 0;
 | |
| 
 | |
| 	sampleCount = GetMediaSampleCount(anim->qtime->theMedia);
 | |
| 	anErr = GetMoviesError();
 | |
| 	if (anErr != noErr) return anErr;
 | |
| 
 | |
| 	anim->qtime->framecount = sampleCount;
 | |
| 
 | |
| 	anim->qtime->frameIndex = (TimeValue *) MEM_callocN(sizeof(TimeValue) * anim->qtime->framecount, "qtframeindex");
 | |
| 
 | |
| 	//rewind
 | |
| 	GetMovieNextInterestingTime(anim->qtime->movie, nextTimeMediaSample, 1, &media, (TimeValue)1, 0, &tmpstartPoint, NULL);
 | |
| 
 | |
| 	anim->qtime->frameIndex[0] = startPoint;
 | |
| 	for(i = 1; i < anim->qtime->framecount; i++) {
 | |
| 		nextTime = 0;
 | |
| 		GetMovieNextInterestingTime(anim->qtime->movie, nextTimeMediaSample, 1, &media, startPoint, 0, &nextTime, NULL);
 | |
| 		startPoint = nextTime;
 | |
| 		anim->qtime->frameIndex[i] = nextTime;
 | |
| 	}
 | |
| 
 | |
| 	anErr = GetMoviesError();
 | |
| 	return anErr;
 | |
| }
 | |
| 
 | |
| 
 | |
| ImBuf * qtime_fetchibuf (struct anim *anim, int position)
 | |
| {
 | |
| 	PixMapHandle			myPixMap = NULL;
 | |
| 	Ptr						myPtr;
 | |
| 
 | |
| 	register int		index;
 | |
| 	register int		boxsize;
 | |
| 
 | |
| 	register uint32_t	*readPos;
 | |
| 	register uint32_t	*changePos;
 | |
| 
 | |
| 	ImBuf *ibuf = NULL;
 | |
| 	unsigned int *rect;
 | |
| 	unsigned char *from, *to;
 | |
| #ifdef _WIN32
 | |
| 	unsigned char *crect;
 | |
| #endif
 | |
| 
 | |
| 	if (anim == NULL) {
 | |
| 		return (NULL);
 | |
| 	}
 | |
| 
 | |
| 	ibuf = IMB_allocImBuf (anim->x, anim->y, 32, IB_rect, 0);
 | |
| 	rect = ibuf->rect;
 | |
| 
 | |
| 	SetMovieTimeValue(anim->qtime->movie, anim->qtime->frameIndex[position]);
 | |
| 	UpdateMovie(anim->qtime->movie);
 | |
| 	MoviesTask(anim->qtime->movie, 0);
 | |
| 
 | |
| 
 | |
| 	myPixMap = GetGWorldPixMap(anim->qtime->offscreenGWorld);
 | |
| 	myPtr = GetPixBaseAddr(myPixMap);
 | |
| 
 | |
| 	if (myPtr == NULL) {
 | |
| 		printf ("Error reading frame from Quicktime");
 | |
| 		IMB_freeImBuf (ibuf);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	boxsize = anim->x * anim->y;
 | |
| 	readPos = (uint32_t *) myPtr;
 | |
| 	changePos = (uint32_t *) rect; //textureIMBuf *THE* data pointerrr
 | |
| 
 | |
| #ifdef __APPLE__
 | |
| 	// Swap alpha byte to the end, so ARGB become RGBA;
 | |
| 	from= (unsigned char *)readPos;
 | |
| 	to= (unsigned char *)changePos;
 | |
| 	
 | |
| 	for( index = 0; index < boxsize; index++, from+=4, to+=4 ) {
 | |
| 		to[3] = from[0];
 | |
| 		to[0] = from[1];
 | |
| 		to[1] = from[2];
 | |
| 		to[2] = from[3];
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| #ifdef _WIN32
 | |
| 	for( index = 0; index < boxsize; index++, changePos++, readPos++ )
 | |
| 		*( changePos ) =  *(readPos );
 | |
| 
 | |
| 	if(anim->qtime->depth < 32) {
 | |
| 		//add alpha to ibuf
 | |
| 		boxsize = anim->x * anim->y * 4;
 | |
| 		crect = (unsigned char *) rect;
 | |
| 		for( index = 0; index < boxsize; index+=4, crect+=4 )
 | |
| 			 crect[3] = 0xFF;
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	IMB_flipy(ibuf);
 | |
| 	return ibuf;
 | |
| }
 | |
| 
 | |
| 
 | |
| // following two functions only here to get movie pixeldepth
 | |
| 
 | |
| static int GetFirstVideoMedia(struct anim *anim)
 | |
| {
 | |
| 	long    numTracks;
 | |
| 	OSType  mediaType;
 | |
| 
 | |
| 	numTracks = GetMovieTrackCount(anim->qtime->movie);
 | |
| 
 | |
| 	for (anim->qtime->trackIndex=1; anim->qtime->trackIndex<=numTracks; (anim->qtime->trackIndex)++) {
 | |
| 		anim->qtime->theTrack = GetMovieIndTrack(anim->qtime->movie, anim->qtime->trackIndex);
 | |
| 
 | |
| 		if (anim->qtime->theTrack)
 | |
| 			anim->qtime->theMedia = GetTrackMedia(anim->qtime->theTrack);
 | |
| 
 | |
| 		if (anim->qtime->theMedia)
 | |
| 			GetMediaHandlerDescription(anim->qtime->theMedia,&mediaType, nil, nil);
 | |
| 		if (mediaType == VideoMediaType) return 1;
 | |
| 	}
 | |
| 
 | |
| 	anim->qtime->trackIndex = 0;  // trackIndex can't be 0
 | |
| 	return 0;      // went through all tracks and no video
 | |
| }
 | |
| 
 | |
| static short GetFirstVideoTrackPixelDepth(struct anim *anim)
 | |
| {
 | |
| 	SampleDescriptionHandle imageDescH =	(SampleDescriptionHandle)NewHandle(sizeof(Handle));
 | |
| //	long	trackIndex = 0; /*unused*/
 | |
| 	
 | |
| 	if(!GetFirstVideoMedia(anim))
 | |
| 		return -1;
 | |
| 
 | |
| 	if (!anim->qtime->trackIndex || !anim->qtime->theMedia) return -1;  // we need both
 | |
| 	GetMediaSampleDescription(anim->qtime->theMedia, anim->qtime->trackIndex, imageDescH);
 | |
| 
 | |
| 	return (*(ImageDescriptionHandle)imageDescH)->depth;
 | |
| }
 | |
| 
 | |
| 
 | |
| int startquicktime (struct anim *anim)
 | |
| {
 | |
| 	FSSpec		theFSSpec;
 | |
| 
 | |
| 	OSErr		err = noErr;
 | |
| 	char		theFullPath[255];
 | |
| #ifdef __APPLE__
 | |
| 	FSRef		myRef;
 | |
| #else
 | |
| 	char		*qtname;
 | |
| 	Str255		dst;
 | |
| #endif
 | |
| 	short depth = 0;
 | |
| 
 | |
| 	anim->qtime = MEM_callocN (sizeof(QuicktimeMovie),"animqt");
 | |
| 	anim->qtime->have_gw = FALSE;
 | |
| 
 | |
| 	if (anim->qtime == NULL) {
 | |
| 		if(QTIME_DEBUG) printf("Can't alloc qtime: %s\n", anim->name);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	if(QTIME_DEBUG) printf("qt: attempting to load as movie %s\n", anim->name);
 | |
| 	
 | |
| #ifdef __APPLE__
 | |
| 	sprintf(theFullPath, "%s", anim->name);
 | |
| 
 | |
| 	err = FSPathMakeRef(theFullPath, &myRef, 0);
 | |
| 	err = FSGetCatalogInfo(&myRef, kFSCatInfoNone, NULL, NULL, &theFSSpec, NULL);
 | |
| #else
 | |
| 	qtname = get_valid_qtname(anim->name);
 | |
| 	sprintf(theFullPath, "%s", qtname);
 | |
| 	MEM_freeN(qtname);
 | |
| 
 | |
| 	CopyCStringToPascal(theFullPath, dst);
 | |
| 	FSMakeFSSpec(0, 0L, dst, &theFSSpec);
 | |
| #endif
 | |
| 	
 | |
| 	err = OpenMovieFile(&theFSSpec, &anim->qtime->movieRefNum, fsRdPerm);
 | |
| 
 | |
| 	if (err == noErr) {
 | |
| 		if(QTIME_DEBUG) printf("qt: movie opened\n");
 | |
| 		err = NewMovieFromFile(&anim->qtime->movie,
 | |
| 						   anim->qtime->movieRefNum,
 | |
| 						   &anim->qtime->movieResId, NULL, newMovieActive, NULL);
 | |
| 	}
 | |
| 
 | |
| 	if (err) {
 | |
| 		if(QTIME_DEBUG) printf("qt: bad movie %s\n", anim->name);
 | |
| 		if (anim->qtime->movie) {
 | |
| 			DisposeMovie(anim->qtime->movie);
 | |
| 			MEM_freeN(anim->qtime);
 | |
| 			if(QTIME_DEBUG) printf("qt: can't load %s\n", anim->name);
 | |
| 			return -1;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	GetMovieBox(anim->qtime->movie, &anim->qtime->movieBounds);
 | |
| 	anim->x = anim->qtime->movWidth = RECT_WIDTH(anim->qtime->movieBounds);
 | |
| 	anim->y = anim->qtime->movHeight = RECT_HEIGHT(anim->qtime->movieBounds);
 | |
| 	if(QTIME_DEBUG) printf("qt: got bounds %s\n", anim->name);
 | |
| 
 | |
| 	if(anim->x == 0 && anim->y == 0) {
 | |
| 		if(QTIME_DEBUG) printf("qt: error, no dimensions\n");
 | |
| 		free_anim_quicktime(anim);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	anim->qtime->ibuf = IMB_allocImBuf (anim->x, anim->y, 32, IB_rect, 0);
 | |
| 
 | |
| #ifdef _WIN32
 | |
| 	err = NewGWorldFromPtr(&anim->qtime->offscreenGWorld,
 | |
| 		 k32RGBAPixelFormat,
 | |
| 		 &anim->qtime->movieBounds,
 | |
| 		 NULL, NULL, 0,
 | |
| 		(unsigned char *)anim->qtime->ibuf->rect,
 | |
| 		anim->x * 4);
 | |
| #else
 | |
| 	err = NewGWorldFromPtr(&anim->qtime->offscreenGWorld,
 | |
| 		 k32ARGBPixelFormat,
 | |
| 		 &anim->qtime->movieBounds,
 | |
| 		 NULL, NULL, 0,
 | |
| 		(unsigned char *)anim->qtime->ibuf->rect,
 | |
| 		anim->x * 4);
 | |
| #endif /* _WIN32 */
 | |
| 
 | |
| 	if(err == noErr) {
 | |
| 		anim->qtime->have_gw = TRUE;
 | |
| 
 | |
| 		SetMovieGWorld(anim->qtime->movie,
 | |
| 				 anim->qtime->offscreenGWorld,
 | |
| 				 GetGWorldDevice(anim->qtime->offscreenGWorld));
 | |
| 		SetMoviePlayHints(anim->qtime->movie, hintsHighQuality, hintsHighQuality);
 | |
| 		
 | |
| 		// sets Media and Track!
 | |
| 		depth = GetFirstVideoTrackPixelDepth(anim);
 | |
| 
 | |
| 		QT_get_frameIndexes(anim);
 | |
| 	}
 | |
| 
 | |
| 	anim->qtime->offscreenPixMap = GetGWorldPixMap(anim->qtime->offscreenGWorld);
 | |
| 	LockPixels(anim->qtime->offscreenPixMap);
 | |
| 
 | |
| 	//fill blender's anim struct
 | |
| 	anim->qtime->depth = depth;
 | |
| 	
 | |
| 	anim->duration = anim->qtime->framecount;
 | |
| 	anim->params = 0;
 | |
| 
 | |
| 	anim->interlacing = 0;
 | |
| 	anim->orientation = 0;
 | |
| 	anim->framesize = anim->x * anim->y * 4;
 | |
| 
 | |
| 	anim->curposition = 0;
 | |
| 
 | |
| 	if(QTIME_DEBUG) printf("qt: load %s %dx%dx%d frames %d\n", anim->name, anim->qtime->movWidth,
 | |
| 		anim->qtime->movHeight, anim->qtime->depth, anim->qtime->framecount);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int imb_is_a_quicktime (char *name)
 | |
| {
 | |
| 	GraphicsImportComponent		theImporter = NULL;
 | |
| 
 | |
| 	FSSpec	theFSSpec;
 | |
| #ifdef _WIN32
 | |
| 	Str255  dst; /*unused*/
 | |
| #endif
 | |
| 	char	theFullPath[255];
 | |
| 
 | |
| //	Boolean						isMovieFile = false; /*unused*/
 | |
| //	AliasHandle					myAlias = NULL; /*unused*/
 | |
| //	Component					myImporter = NULL; /*unused*/
 | |
| #ifdef __APPLE__
 | |
| //	FInfo						myFinderInfo; /*unused*/
 | |
| 	FSRef						myRef;
 | |
| #endif
 | |
| 	OSErr						err = noErr;
 | |
| 
 | |
| 	if(QTIME_DEBUG) printf("qt: checking as image %s\n", name);
 | |
| 
 | |
| 	// 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;
 | |
| 
 | |
| 	sprintf(theFullPath, "%s", name);
 | |
| #ifdef __APPLE__
 | |
| 	err = FSPathMakeRef(theFullPath, &myRef, 0);
 | |
| 	err = FSGetCatalogInfo(&myRef, kFSCatInfoNone, NULL, NULL, &theFSSpec, NULL);
 | |
| #else
 | |
| 	CopyCStringToPascal(theFullPath, dst);
 | |
| 	err = FSMakeFSSpec(0, 0L, dst, &theFSSpec);
 | |
| #endif
 | |
| 
 | |
| 	GetGraphicsImporterForFile(&theFSSpec, &theImporter);
 | |
| 
 | |
| 	if (theImporter != NULL) {
 | |
| 		if(QTIME_DEBUG) printf("qt: %s valid\n", name);
 | |
| 		CloseComponent(theImporter);
 | |
| 		return 1;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| ImBuf  *imb_quicktime_decode(unsigned char *mem, int size, int flags)
 | |
| {
 | |
| 	Rect						myRect;
 | |
| 	OSErr						err = noErr;
 | |
| 	GraphicsImportComponent		gImporter = NULL;
 | |
| 
 | |
| 	ImageDescriptionHandle		desc;
 | |
| 
 | |
| 	ComponentInstance			dataHandler;
 | |
| 	PointerDataRef dataref = (PointerDataRef)NewHandle(sizeof(PointerDataRefRecord));
 | |
| 
 | |
| 	int x, y, depth;
 | |
| 	int have_gw = FALSE;
 | |
| 	ImBuf *ibuf = NULL;
 | |
| //	ImBuf *imbuf = NULL; /*unused*/
 | |
| 	GWorldPtr	offGWorld;
 | |
| 	PixMapHandle		myPixMap = NULL;
 | |
| 
 | |
| #ifdef __APPLE__
 | |
| 	Ptr					myPtr;
 | |
| 
 | |
| 	register int		index;
 | |
| 	register int		boxsize;
 | |
| 
 | |
| 	register uint32_t	*readPos;
 | |
| 	register uint32_t	*changePos;
 | |
| 
 | |
| 	ImBuf *wbuf = NULL;
 | |
| 	unsigned int *rect;
 | |
| 	unsigned char *from, *to;
 | |
| #endif
 | |
| 
 | |
| 	if (mem == NULL)
 | |
| 		goto bail;
 | |
| 	
 | |
| 	if(QTIME_DEBUG) printf("qt: attempt to load mem as image\n");
 | |
| 
 | |
| 	(**dataref).data = mem;
 | |
| 	(**dataref).dataLength = size;
 | |
| 
 | |
| 	err = OpenADataHandler((Handle)dataref,
 | |
| 							PointerDataHandlerSubType,
 | |
| 							nil,
 | |
| 							(OSType)0,
 | |
| 							nil,
 | |
| 							kDataHCanRead,
 | |
| 							&dataHandler);
 | |
| 	if (err != noErr) {
 | |
| 		if(QTIME_DEBUG) printf("no datahandler\n");
 | |
| 		goto bail;
 | |
| 	}
 | |
| 
 | |
| 	err = GetGraphicsImporterForDataRef((Handle)dataref, PointerDataHandlerSubType, &gImporter);
 | |
| 	if (err != noErr) {
 | |
| 		if(QTIME_DEBUG) printf("no graphimport\n");
 | |
| 		goto bail;
 | |
| 	}
 | |
| 
 | |
| 	err = GraphicsImportGetNaturalBounds(gImporter, &myRect);
 | |
| 	if (err != noErr) {
 | |
| 		if(QTIME_DEBUG) printf("no bounds\n");
 | |
| 		goto bail;
 | |
| 	}
 | |
| 
 | |
| 	err = GraphicsImportGetImageDescription (gImporter, &desc );
 | |
| 	if (err != noErr) {
 | |
| 		if(QTIME_DEBUG) printf("no imagedescription\n");
 | |
| 		goto bail;
 | |
| 	}
 | |
| 
 | |
| 	x = RECT_WIDTH(myRect);
 | |
| 	y = RECT_HEIGHT(myRect);
 | |
| 	depth = (**desc).depth;
 | |
| 
 | |
| 	if (flags & IB_test) {
 | |
| 		ibuf = IMB_allocImBuf(x, y, depth, 0, 0);
 | |
| 		ibuf->ftype = QUICKTIME;
 | |
| 		DisposeHandle((Handle)dataref);
 | |
| 		if (gImporter != NULL)	CloseComponent(gImporter);
 | |
| 		return ibuf;
 | |
| 	}
 | |
| 
 | |
| #ifdef __APPLE__
 | |
| 	ibuf = IMB_allocImBuf (x, y, 32, IB_rect, 0);
 | |
| 	wbuf = IMB_allocImBuf (x, y, 32, IB_rect, 0);
 | |
| 
 | |
| 	err = NewGWorldFromPtr(&offGWorld,
 | |
| 						k32ARGBPixelFormat,
 | |
| 						&myRect, NULL, NULL, 0,
 | |
| 						(unsigned char *)wbuf->rect, x * 4);
 | |
| #else
 | |
| 
 | |
| 	ibuf = IMB_allocImBuf (x, y, 32, IB_rect, 0);	
 | |
| 
 | |
| 	err = NewGWorldFromPtr(&offGWorld,
 | |
| 							k32RGBAPixelFormat,
 | |
| 							&myRect, NULL, NULL, 0,
 | |
| 							(unsigned char *)ibuf->rect, x * 4);
 | |
| #endif
 | |
| 	
 | |
| 	if (err != noErr) {
 | |
| 		if(QTIME_DEBUG) printf("no newgworld\n");
 | |
| 		goto bail;
 | |
| 	} else {
 | |
| 		have_gw = TRUE;
 | |
| 	}
 | |
| 
 | |
| 	GraphicsImportSetGWorld(gImporter, offGWorld, NULL);
 | |
| 	GraphicsImportDraw(gImporter);
 | |
| 
 | |
| #ifdef __APPLE__
 | |
| 	rect = ibuf->rect;
 | |
| 
 | |
| 	myPixMap = GetGWorldPixMap(offGWorld);
 | |
| 	LockPixels(myPixMap);
 | |
| 	myPtr = GetPixBaseAddr(myPixMap);
 | |
| 
 | |
| 	if (myPtr == NULL) {
 | |
| 		printf ("Error reading frame from Quicktime");
 | |
| 		IMB_freeImBuf (ibuf);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	boxsize = x * y;
 | |
| 	readPos = (uint32_t *) myPtr;
 | |
| 	changePos = (uint32_t *) rect;
 | |
| 
 | |
| 	// Swap alpha byte to the end, so ARGB become RGBA;
 | |
| 	from= (unsigned char *)readPos;
 | |
| 	to= (unsigned char *)changePos;
 | |
| 	
 | |
| 	for( index = 0; index < boxsize; index++, from+=4, to+=4 ) {
 | |
| 		to[3] = from[0];
 | |
| 		to[0] = from[1];
 | |
| 		to[1] = from[2];
 | |
| 		to[2] = from[3];
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| bail:
 | |
| 
 | |
| 	DisposeHandle((Handle)dataref);
 | |
| 	UnlockPixels(myPixMap);
 | |
| 	if(have_gw) DisposeGWorld(offGWorld);
 | |
| 
 | |
| #ifdef __APPLE__
 | |
| 	if (wbuf) {
 | |
| 		IMB_freeImBuf (wbuf);
 | |
| 		wbuf = NULL;
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	if (gImporter != NULL)	CloseComponent(gImporter);
 | |
| 
 | |
| 	if (err != noErr) {
 | |
| 		if(QTIME_DEBUG) printf("quicktime import unsuccesfull\n");
 | |
| 		if (ibuf) {
 | |
| 			IMB_freeImBuf (ibuf);
 | |
| 			ibuf = NULL;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if(ibuf) {
 | |
| 
 | |
| #ifdef _WIN32
 | |
| // add non transparent alpha layer, so images without alpha show up in the sequence editor
 | |
| // exception for GIF images since these can be transparent without being 32 bit
 | |
| // (might also be nescessary for OSX)
 | |
| 		int i;
 | |
| 		int box = x * y;
 | |
| 		unsigned char *arect = (unsigned char *) ibuf->rect;
 | |
| 
 | |
| 		if( depth < 32 && (**desc).cType != kGIFCodecType) {
 | |
| 			for(i = 0; i < box; i++, arect+=4)
 | |
| 				 arect[3] = 0xFF;
 | |
| 		}
 | |
| #endif
 | |
| 
 | |
| 		IMB_flipy(ibuf);
 | |
| 		ibuf->ftype = QUICKTIME;
 | |
| 	}
 | |
| 	return ibuf;
 | |
| }
 | |
| 
 | |
| #endif /* _WIN32 || __APPLE__ */
 | |
| 
 | |
| #endif /* WITH_QUICKTIME */
 | |
| 
 | |
| 
 | |
| #if 0
 | |
| 
 | |
| struct ImageDescription {
 | |
|      long         idSize;
 | |
|      CodecType    cType;
 | |
|      long         resvd1;
 | |
|      short        resvd2;
 | |
|      short        dataRefIndex;
 | |
|      short        version;
 | |
|      short        revisionLevel;
 | |
|      long         vendor;
 | |
|      CodecQ       temporalQuality;
 | |
|      CodecQ       spatialQuality;
 | |
|      short        width;
 | |
|      short        height;
 | |
|      Fixed        hRes;
 | |
|      Fixed        vRes;
 | |
|      long         dataSize;
 | |
|      short        frameCount;
 | |
|      Str31        name;
 | |
|      short        depth;
 | |
|      short        clutID;
 | |
| };
 | |
| 
 | |
| #endif // 0
 |