This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/imbuf/intern/anim.c
Rob Haarsma 706ccc0401 Added Quicktime support for OSX and Windows.
This code allows you to load Quicktime images and movies as textures
and render animations to Quicktime movies.
Note that the selected output codec is *not* saved in the blendfile.

To enable Quicktime functionality you need the SDK from Apple:
OSX: ftp://ftp.apple.com/developer/Development_Kits/QT6SDK_Mac.hqx
Win: ftp://ftp.apple.com/developer/Development_Kits/QT6SDK_Win.hqx
Add the \QTDevWin\CIncludes and \QTDevWin\Libraries directories
from this SDK to your build environment.

Enable the WITH_QUICKTIME compile flag in the following directories:
bf\blender\source\blender\imbuf
bf\blender\source\blender\src
bf\blender\source\blender\render
bf\blender\source\creator
2003-04-28 02:15:46 +00:00

615 lines
14 KiB
C

/**
* anim.c
*
* $Id$
*
* ***** 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 Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL/BL DUAL LICENSE BLOCK *****
*/
#ifdef _WIN32
#define INC_OLE2
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <memory.h>
#include <commdlg.h>
#ifndef FREE_WINDOWS
#include <vfw.h>
#endif
#undef AVIIF_KEYFRAME // redefined in AVI_avi.h
#undef AVIIF_LIST // redefined in AVI_avi.h
#define FIXCC(fcc) if (fcc == 0) fcc = mmioFOURCC('N', 'o', 'n', 'e'); \
if (fcc == BI_RLE8) fcc = mmioFOURCC('R', 'l', 'e', '8');
#endif
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#ifndef _WIN32
#include <dirent.h>
#else
#include <io.h>
#include "BLI_winstuff.h"
#endif
#include "BLI_blenlib.h" /* BLI_remlink BLI_filesize BLI_addtail
BLI_countlist BLI_stringdec */
#include "DNA_userdef_types.h"
#include "BKE_global.h"
#include "imbuf.h"
#include "imbuf_patch.h"
#include "AVI_avi.h"
#ifdef WITH_QUICKTIME
#if defined(_WIN32) || defined(__APPLE__)
#include "quicktime_import.h"
#endif /* _WIN32 || __APPLE__ */
#ifdef linux
#include "quicktime_import_linux.h"
#endif /* linux */
#endif /* WITH_QUICKTIME */
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "IMB_allocimbuf.h"
#include "IMB_bitplanes.h"
#include "IMB_anim.h"
#include "IMB_anim5.h"
/****/
#ifdef __sgi
#include <dmedia/moviefile.h>
static void movie_printerror(char * str) {
const char * errstr = mvGetErrorStr(mvGetErrno());
if (str) {
if (errstr) printf("%s: %s\n", str, errstr);
else printf("%s: returned error\n", str);
} else printf("%s\n", errstr);
}
static int startmovie(struct anim * anim) {
if (anim == 0) return(-1);
if ( mvOpenFile (anim->name, O_BINARY|O_RDONLY, &anim->movie ) != DM_SUCCESS ) {
printf("Can't open movie: %s\n", anim->name);
return(-1);
}
if ( mvFindTrackByMedium (anim->movie, DM_IMAGE, &anim->track) != DM_SUCCESS ) {
printf("No image track in movie: %s\n", anim->name);
mvClose(anim->movie);
return(-1);
}
anim->duration = mvGetTrackLength (anim->track);
anim->params = mvGetParams( anim->track );
anim->x = dmParamsGetInt( anim->params, DM_IMAGE_WIDTH);
anim->y = dmParamsGetInt( anim->params, DM_IMAGE_HEIGHT);
anim->interlacing = dmParamsGetEnum (anim->params, DM_IMAGE_INTERLACING);
anim->orientation = dmParamsGetEnum (anim->params, DM_IMAGE_ORIENTATION);
anim->framesize = dmImageFrameSize(anim->params);
anim->curposition = 0;
/*printf("x:%d y:%d size:%d interl:%d dur:%d\n", anim->x, anim->y, anim->framesize, anim->interlacing, anim->duration);*/
return (0);
}
static ImBuf * movie_fetchibuf(struct anim * anim, int position) {
ImBuf * ibuf;
/* extern rectcpy(); */
int size;
unsigned int *rect1, *rect2;
if (anim == 0) return (0);
ibuf = IMB_allocImBuf(anim->x, anim->y, 24, IB_rect, 0);
if ( mvReadFrames(anim->track, position, 1, ibuf->x * ibuf->y *
sizeof(int), ibuf->rect ) != DM_SUCCESS ) {
movie_printerror("mvReadFrames");
IMB_freeImBuf(ibuf);
return(0);
}
/*
if (anim->interlacing == DM_IMAGE_INTERLACED_EVEN)
{
rect1 = ibuf->rect + (ibuf->x * ibuf->y) - 1;
rect2 = rect1 - ibuf->x;
for (size = ibuf->x * (ibuf->y - 1); size > 0; size--){
*rect1-- = *rect2--;
}
}
*/
if (anim->interlacing == DM_IMAGE_INTERLACED_EVEN)
{
rect1 = ibuf->rect;
rect2 = rect1 + ibuf->x;
for (size = ibuf->x * (ibuf->y - 1); size > 0; size--){
*rect1++ = *rect2++;
}
}
/*if (anim->orientation == DM_TOP_TO_BOTTOM) IMB_flipy(ibuf);*/
return(ibuf);
}
static void free_anim_movie(struct anim * anim) {
if (anim == NULL) return;
if (anim->movie) {
mvClose(anim->movie);
anim->movie = NULL;
}
anim->duration = 0;
}
int ismovie(char *name) {
return (mvIsMovieFile(name) == DM_TRUE);
}
#else
int ismovie(char *name) {
return 0;
}
/* never called, just keep the linker happy */
static int startmovie(struct anim * anim) { return 1; }
static ImBuf * movie_fetchibuf(struct anim * anim, int position) { return NULL; }
static void free_anim_movie(struct anim * anim) { ; }
#endif
static int an_stringdec(char *string, char* kop, char *staart,unsigned short *numlen) {
unsigned short len,nums,nume;
short i,found=FALSE;
len=strlen(string);
for(i=len-1;i>=0;i--){
if (string[i]=='/') break;
if (isdigit(string[i])) {
if (found){
nums=i;
} else{
nume=i;
nums=i;
found=TRUE;
}
} else{
if (found) break;
}
}
if (found){
strcpy(staart,&string[nume+1]);
strcpy(kop,string);
kop[nums]=0;
*numlen=nume-nums+1;
return ((int)atoi(&(string[nums])));
}
staart[0]=0;
strcpy(kop,string);
*numlen=0;
return (1);
}
static void an_stringenc(char *string, char *kop, char *staart,
unsigned short numlen, int pic) {
char numstr[10];
unsigned short len,i;
len=sprintf(numstr,"%d",pic);
strcpy(string,kop);
for(i=len;i<numlen;i++){
strcat(string,"0");
}
strcat(string,numstr);
strcat(string,staart);
}
static void free_anim_avi (struct anim *anim) {
int i;
if (anim == NULL) return;
if (anim->avi == NULL) return;
AVI_close (anim->avi);
MEM_freeN (anim->avi);
anim->avi = NULL;
#if defined(_WIN32) && !defined(FREE_WINDOWS)
if (anim->pgf) {
AVIStreamGetFrameClose(anim->pgf);
anim->pgf = NULL;
}
for (i = 0; i < anim->avistreams; i++){
AVIStreamRelease(anim->pavi[i]);
}
anim->avistreams = 0;
if (anim->pfileopen) {
AVIFileRelease(anim->pfile);
anim->pfileopen = 0;
AVIFileExit();
}
#endif
anim->duration = 0;
}
void IMB_free_anim_ibuf(struct anim * anim) {
if (anim == NULL) return;
if (anim->ibuf1) IMB_freeImBuf(anim->ibuf1);
if (anim->ibuf2) IMB_freeImBuf(anim->ibuf2);
anim->ibuf1 = anim->ibuf2 = NULL;
}
void IMB_free_anim(struct anim * anim) {
if (anim == NULL) {
printf("free anim, anim == NULL\n");
return;
}
IMB_free_anim_ibuf(anim);
free_anim_anim5(anim);
free_anim_movie(anim);
free_anim_avi(anim);
#ifdef WITH_QUICKTIME
free_anim_quicktime(anim);
#endif
free(anim);
}
void IMB_close_anim(struct anim * anim) {
if (anim == 0) return;
IMB_free_anim(anim);
}
struct anim * IMB_open_anim(char * name, int ib_flags) {
struct anim * anim;
anim = (struct anim*)MEM_callocN(sizeof(struct anim), "anim struct");
if (anim != NULL) {
strcpy(anim->name, name);
anim->ib_flags = ib_flags;
}
return(anim);
}
static int startavi (struct anim *anim) {
AviError avierror;
#if defined(_WIN32) && !defined(FREE_WINDOWS)
HRESULT hr;
int i, firstvideo = -1;
BYTE abFormat[1024];
LONG l;
LPBITMAPINFOHEADER lpbi;
AVISTREAMINFO avis;
#endif
anim->avi = MEM_callocN (sizeof(AviMovie),"animavi");
if (anim->avi == NULL) {
printf("Can't open avi: %s\n", anim->name);
return -1;
}
avierror = AVI_open_movie (anim->name, anim->avi);
#if defined(_WIN32) && !defined(FREE_WINDOWS)
if (avierror == AVI_ERROR_COMPRESSION) {
AVIFileInit();
hr = AVIFileOpen(&anim->pfile, anim->name, OF_READ, 0L);
if (hr == 0) {
anim->pfileopen = 1;
for (i = 0; i < MAXNUMSTREAMS; i++) {
if (AVIFileGetStream(anim->pfile, &anim->pavi[i], 0L, i) != AVIERR_OK) {
break;
}
AVIStreamInfo(anim->pavi[i], &avis, sizeof(avis));
if ((avis.fccType == streamtypeVIDEO) && (firstvideo == -1)) {
anim->pgf = AVIStreamGetFrameOpen(anim->pavi[i], NULL);
if (anim->pgf) {
firstvideo = i;
// get stream length
anim->avi->header->TotalFrames = AVIStreamLength(anim->pavi[i]);
// get information about images inside the stream
l = sizeof(abFormat);
AVIStreamReadFormat(anim->pavi[i], 0, &abFormat, &l);
lpbi = (LPBITMAPINFOHEADER)abFormat;
anim->avi->header->Height = lpbi->biHeight;
anim->avi->header->Width = lpbi->biWidth;
} else {
FIXCC(avis.fccHandler);
FIXCC(avis.fccType);
printf("Can't find AVI decoder for type : %4.4hs/%4.4hs\n",
(LPSTR)&avis.fccType,
(LPSTR)&avis.fccHandler);
}
}
}
// register number of opened avistreams
anim->avistreams = i;
//
// Couldn't get any video streams out of this file
//
if ((anim->avistreams == 0) || (firstvideo == -1)) {
avierror = AVI_ERROR_FORMAT;
} else {
avierror = AVI_ERROR_NONE;
anim->firstvideo = firstvideo;
}
} else {
AVIFileExit();
}
}
#endif
if (avierror != AVI_ERROR_NONE) {
AVI_print_error(avierror);
printf ("Error loading avi: %s\n", anim->name);
free_anim_avi(anim);
return -1;
}
anim->duration = anim->avi->header->TotalFrames;
anim->params = 0;
anim->x = anim->avi->header->Width;
anim->y = anim->avi->header->Height;
anim->interlacing = 0;
anim->orientation = 0;
anim->framesize = anim->x * anim->y * 4;
anim->curposition = 0;
/* printf("x:%d y:%d size:%d interl:%d dur:%d\n", anim->x, anim->y, anim->framesize, anim->interlacing, anim->duration);*/
return 0;
}
static ImBuf * avi_fetchibuf (struct anim *anim, int position) {
ImBuf *ibuf = NULL;
int *tmp;
int y;
if (anim == NULL) return (NULL);
#if defined(_WIN32) && !defined(FREE_WINDOWS)
if (anim->avistreams) {
LPBITMAPINFOHEADER lpbi;
if (anim->pgf) {
lpbi = AVIStreamGetFrame(anim->pgf, position + AVIStreamStart(anim->pavi[anim->firstvideo]));
if (lpbi) {
ibuf = IMB_ibImageFromMemory((int *) lpbi, 100, IB_rect);
//Oh brother...
}
}
} else {
#else
if (1) {
#endif
ibuf = IMB_allocImBuf (anim->x, anim->y, 24, IB_rect, 0);
tmp = AVI_read_frame (anim->avi, AVI_FORMAT_RGB32, position,
AVI_get_stream(anim->avi, AVIST_VIDEO, 0));
if (tmp == NULL) {
printf ("Error reading frame from AVI");
IMB_freeImBuf (ibuf);
return NULL;
}
for (y=0; y < anim->y; y++) {
memcpy (&(ibuf->rect)[((anim->y-y)-1)*anim->x], &tmp[y*anim->x],
anim->x * 4);
}
MEM_freeN (tmp);
}
return ibuf;
}
/* probeer volgende plaatje te lezen */
/* Geen plaatje, probeer dan volgende animatie te openen */
/* gelukt, haal dan eerste plaatje van animatie */
static struct ImBuf * anim_getnew(struct anim * anim) {
struct ImBuf *ibuf = 0;
if (anim == NULL) return(0);
free_anim_anim5(anim);
free_anim_movie(anim);
free_anim_avi(anim);
#ifdef WITH_QUICKTIME
free_anim_quicktime(anim);
#endif
if (anim->curtype != 0) return (0);
anim->curtype = imb_get_anim_type(anim->name);
switch (anim->curtype) {
case ANIM_ANIM5:
if (startanim5(anim)) return (0);
ibuf = anim5_fetchibuf(anim);
break;
case ANIM_SEQUENCE:
ibuf = IMB_loadiffname(anim->name, anim->ib_flags);
if (ibuf) {
strcpy(anim->first, anim->name);
anim->duration = 1;
}
break;
case ANIM_MOVIE:
if (startmovie(anim)) return (0);
ibuf = IMB_allocImBuf (anim->x, anim->y, 24, 0, 0); /* fake */
break;
case ANIM_AVI:
if (startavi(anim)) {
printf("couldnt start avi\n");
return (0);
}
ibuf = IMB_allocImBuf (anim->x, anim->y, 24, 0, 0);
break;
#ifdef WITH_QUICKTIME
case ANIM_QTIME:
if (startquicktime(anim)) return (0);
ibuf = IMB_allocImBuf (anim->x, anim->y, 24, 0, 0);
break;
#endif
}
return(ibuf);
}
struct ImBuf * IMB_anim_absolute(struct anim * anim, int position) {
struct ImBuf * ibuf = 0;
char head[256], tail[256];
unsigned short digits;
int pic;
if (anim == NULL) return(0);
if (anim->curtype == 0) {
ibuf = anim_getnew(anim);
if (ibuf == NULL) {
return (0);
}
IMB_freeImBuf(ibuf); /* ???? */
}
if (position < 0) return(0);
if (position >= anim->duration) return(0);
switch(anim->curtype) {
case ANIM_ANIM5:
if (anim->curposition > position) rewindanim5(anim);
while (anim->curposition < position) {
if (nextanim5(anim)) return (0);
}
ibuf = anim5_fetchibuf(anim);
break;
case ANIM_SEQUENCE:
pic = an_stringdec(anim->first, head, tail, &digits);
pic += position;
an_stringenc(anim->name, head, tail, digits, pic);
ibuf = IMB_loadiffname(anim->name, LI_rect);
if (ibuf) {
anim->curposition = position;
/* patch... by freeing the cmap you prevent a double apply cmap... */
/* probably the IB_CMAP option isn't working proper
* after the abgr->rgba reconstruction
*/
IMB_freecmapImBuf(ibuf);
}
break;
case ANIM_MOVIE:
ibuf = movie_fetchibuf(anim, position);
if (ibuf) {
anim->curposition = position;
IMB_convert_rgba_to_abgr(ibuf->x*ibuf->y, ibuf->rect);
}
break;
case ANIM_AVI:
ibuf = avi_fetchibuf(anim, position);
if (ibuf) anim->curposition = position;
break;
#ifdef WITH_QUICKTIME
case ANIM_QTIME:
ibuf = qtime_fetchibuf(anim, position);
if (ibuf) anim->curposition = position;
break;
#endif
}
if (ibuf) {
if (anim->ib_flags & IB_ttob) IMB_flipy(ibuf);
sprintf(ibuf->name, "%s.%04d", anim->name, anim->curposition + 1);
}
return(ibuf);
}
struct ImBuf * IMB_anim_nextpic(struct anim * anim) {
struct ImBuf * ibuf = 0;
if (anim == 0) return(0);
ibuf = IMB_anim_absolute(anim, anim->curposition + 1);
return(ibuf);
}
/***/
int IMB_anim_get_duration(struct anim *anim) {
return anim->duration;
}