2009-11-18 09:49:42 +00:00
|
|
|
/**
|
2009-11-18 18:45:38 +00:00
|
|
|
* $Id$
|
2009-11-18 09:49:42 +00:00
|
|
|
*
|
|
|
|
|
* 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__)
|
|
|
|
|
|
2009-11-18 15:01:59 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
2009-11-18 09:49:42 +00:00
|
|
|
#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
|
2009-11-18 15:01:59 +00:00
|
|
|
#import <Cocoa/Cocoa.h>
|
|
|
|
|
#import <QTKit/QTKit.h>
|
2009-11-28 18:16:27 +00:00
|
|
|
|
|
|
|
|
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
|
|
|
|
|
#error OSX 10.5 minimum is needed for QTKit
|
|
|
|
|
#endif
|
|
|
|
|
|
2009-11-18 09:49:42 +00:00
|
|
|
#endif /* __APPLE__ */
|
|
|
|
|
|
|
|
|
|
typedef struct QuicktimeExport {
|
2009-11-18 15:01:59 +00:00
|
|
|
QTMovie *movie;
|
|
|
|
|
|
|
|
|
|
NSString *filename;
|
2009-11-18 09:49:42 +00:00
|
|
|
|
2009-11-18 15:01:59 +00:00
|
|
|
QTTime frameDuration;
|
|
|
|
|
NSDictionary *frameAttributes;
|
2009-11-18 09:49:42 +00:00
|
|
|
} QuicktimeExport;
|
|
|
|
|
|
|
|
|
|
static struct QuicktimeExport *qtexport;
|
|
|
|
|
|
|
|
|
|
|
2009-11-20 10:37:50 +00:00
|
|
|
static NSString *stringWithCodecType(int codecType) {
|
|
|
|
|
switch (codecType) {
|
|
|
|
|
case QT_CODECTYPE_RAW:
|
|
|
|
|
return @"raw ";
|
|
|
|
|
case QT_CODECTYPE_MJPEGA:
|
|
|
|
|
return @"mjpa";
|
|
|
|
|
case QT_CODECTYPE_MJPEGB:
|
|
|
|
|
return @"mjpb";
|
|
|
|
|
case QT_CODECTYPE_DVCPAL:
|
|
|
|
|
return @"dvcp";
|
|
|
|
|
case QT_CODECTYPE_DVCNTSC:
|
|
|
|
|
return @"dvc ";
|
|
|
|
|
case QT_CODECTYPE_MPEG4:
|
|
|
|
|
return @"mp4v";
|
|
|
|
|
case QT_CODECTYPE_H263:
|
|
|
|
|
return @"h263";
|
|
|
|
|
case QT_CODECTYPE_H264:
|
|
|
|
|
return @"avc1";
|
|
|
|
|
case QT_CODECTYPE_DVCPROHD720p:
|
|
|
|
|
return @"dvhp";
|
|
|
|
|
case QT_CODECTYPE_DVCPROHD1080i50:
|
|
|
|
|
return @"dvh5";
|
|
|
|
|
case QT_CODECTYPE_DVCPROHD1080i60:
|
|
|
|
|
return @"dvh6";
|
|
|
|
|
|
|
|
|
|
case QT_CODECTYPE_JPEG:
|
|
|
|
|
default:
|
|
|
|
|
return @"jpeg";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-18 09:49:42 +00:00
|
|
|
void makeqtstring (RenderData *rd, char *string) {
|
|
|
|
|
char txt[64];
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-11-18 15:01:59 +00:00
|
|
|
void start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty)
|
|
|
|
|
{
|
|
|
|
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
|
|
|
|
NSError *error;
|
2009-11-18 09:49:42 +00:00
|
|
|
char name[2048];
|
|
|
|
|
|
2009-11-18 15:01:59 +00:00
|
|
|
|
2009-11-18 09:49:42 +00:00
|
|
|
if (G.afbreek != 1) {
|
2009-11-28 18:16:27 +00:00
|
|
|
|
|
|
|
|
if(qtexport == NULL) qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport");
|
|
|
|
|
|
|
|
|
|
[QTMovie enterQTKitOnThread];
|
|
|
|
|
|
2009-11-18 15:01:59 +00:00
|
|
|
/* Check first if the QuickTime 7.2.1 initToWritableFile: method is available */
|
|
|
|
|
if ([[[[QTMovie alloc] init] autorelease] respondsToSelector:@selector(initToWritableFile:error:)] != YES) {
|
2009-11-18 09:49:42 +00:00
|
|
|
G.afbreek = 1;
|
2009-11-18 15:01:59 +00:00
|
|
|
fprintf(stderr, "\nUnable to create quicktime movie, need Quicktime rev 7.2.1 or later");
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
makeqtstring(rd, name);
|
|
|
|
|
qtexport->filename = [NSString stringWithCString:name
|
|
|
|
|
encoding:[NSString defaultCStringEncoding]];
|
|
|
|
|
qtexport->movie = [[QTMovie alloc] initToWritableFile:qtexport->filename error:&error];
|
|
|
|
|
|
|
|
|
|
if(qtexport->movie == nil) {
|
|
|
|
|
G.afbreek = 1;
|
|
|
|
|
NSLog(@"Unable to create quicktime movie : %@",[error localizedDescription]);
|
2009-11-28 18:16:27 +00:00
|
|
|
[QTMovie exitQTKitOnThread];
|
2009-11-18 15:01:59 +00:00
|
|
|
} else {
|
|
|
|
|
[qtexport->movie retain];
|
|
|
|
|
[qtexport->filename retain];
|
|
|
|
|
[qtexport->movie setAttribute:[NSNumber numberWithBool:YES] forKey:QTMovieEditableAttribute];
|
|
|
|
|
[qtexport->movie setAttribute:@"Made with Blender" forKey:QTMovieCopyrightAttribute];
|
|
|
|
|
|
|
|
|
|
qtexport->frameDuration = QTMakeTime(rd->frs_sec_base*1000, rd->frs_sec*1000);
|
|
|
|
|
|
2009-11-20 10:37:50 +00:00
|
|
|
/* specifying the codec attributes : try to retrieve them from render data first*/
|
|
|
|
|
if (rd->qtcodecsettings.codecType) {
|
|
|
|
|
qtexport->frameAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
|
|
|
stringWithCodecType(rd->qtcodecsettings.codecType),
|
|
|
|
|
QTAddImageCodecType,
|
|
|
|
|
[NSNumber numberWithLong:((rd->qtcodecsettings.codecSpatialQuality)*codecLosslessQuality)/100],
|
|
|
|
|
QTAddImageCodecQuality,
|
|
|
|
|
nil];
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
qtexport->frameAttributes = [NSDictionary dictionaryWithObjectsAndKeys:@"jpeg",
|
|
|
|
|
QTAddImageCodecType,
|
|
|
|
|
[NSNumber numberWithLong:codecHighQuality],
|
|
|
|
|
QTAddImageCodecQuality,
|
|
|
|
|
nil];
|
|
|
|
|
}
|
2009-11-18 15:01:59 +00:00
|
|
|
[qtexport->frameAttributes retain];
|
|
|
|
|
}
|
2009-11-18 09:49:42 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-11-18 15:01:59 +00:00
|
|
|
|
|
|
|
|
[pool drain];
|
2009-11-18 09:49:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-11-18 15:01:59 +00:00
|
|
|
void append_qt(struct RenderData *rd, int frame, int *pixels, int rectx, int recty)
|
|
|
|
|
{
|
|
|
|
|
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
|
|
|
|
NSBitmapImageRep *blBitmapFormatImage;
|
|
|
|
|
NSImage *frameImage;
|
|
|
|
|
unsigned char *from_Ptr,*to_Ptr;
|
|
|
|
|
int y,from_i,to_i;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Create bitmap image rep in blender format (32bit RGBA) */
|
|
|
|
|
blBitmapFormatImage = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
|
|
|
|
|
pixelsWide:rectx
|
|
|
|
|
pixelsHigh:recty
|
|
|
|
|
bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO
|
|
|
|
|
colorSpaceName:NSCalibratedRGBColorSpace
|
|
|
|
|
bitmapFormat:NSAlphaNonpremultipliedBitmapFormat
|
|
|
|
|
bytesPerRow:rectx*4
|
|
|
|
|
bitsPerPixel:32];
|
|
|
|
|
if (!blBitmapFormatImage) {
|
|
|
|
|
[pool drain];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
from_Ptr = (unsigned char*)pixels;
|
|
|
|
|
to_Ptr = (unsigned char*)[blBitmapFormatImage bitmapData];
|
|
|
|
|
for (y = 0; y < recty; y++) {
|
|
|
|
|
to_i = (recty-y-1)*rectx;
|
|
|
|
|
from_i = y*rectx;
|
|
|
|
|
memcpy(to_Ptr+4*to_i, from_Ptr+4*from_i, 4*rectx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
frameImage = [[NSImage alloc] initWithSize:NSMakeSize(rectx, recty)];
|
|
|
|
|
[frameImage addRepresentation:blBitmapFormatImage];
|
|
|
|
|
|
|
|
|
|
/* Add the image to the movie clip */
|
|
|
|
|
[qtexport->movie addImage:frameImage
|
|
|
|
|
forDuration:qtexport->frameDuration
|
|
|
|
|
withAttributes:qtexport->frameAttributes];
|
|
|
|
|
|
|
|
|
|
[blBitmapFormatImage release];
|
|
|
|
|
[frameImage release];
|
|
|
|
|
[pool drain];
|
2009-11-18 09:49:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-11-18 15:01:59 +00:00
|
|
|
void end_qt(void)
|
|
|
|
|
{
|
|
|
|
|
if (qtexport->movie) {
|
|
|
|
|
/* Flush update of the movie file */
|
|
|
|
|
[qtexport->movie updateMovieFile];
|
2009-11-18 19:35:03 +00:00
|
|
|
|
|
|
|
|
[qtexport->movie invalidate];
|
|
|
|
|
|
2009-11-18 15:01:59 +00:00
|
|
|
/* Clean up movie structure */
|
|
|
|
|
[qtexport->filename release];
|
|
|
|
|
[qtexport->frameAttributes release];
|
|
|
|
|
[qtexport->movie release];
|
|
|
|
|
}
|
2009-11-28 18:16:27 +00:00
|
|
|
|
|
|
|
|
[QTMovie exitQTKitOnThread];
|
2009-11-18 09:49:42 +00:00
|
|
|
|
|
|
|
|
if(qtexport) {
|
|
|
|
|
MEM_freeN(qtexport);
|
|
|
|
|
qtexport = NULL;
|
2009-11-18 15:01:59 +00:00
|
|
|
}
|
2009-11-18 09:49:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void free_qtcomponentdata(void) {
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-20 10:37:50 +00:00
|
|
|
void quicktime_verify_image_type(RenderData *rd)
|
2009-11-18 09:49:42 +00:00
|
|
|
{
|
2009-11-20 10:37:50 +00:00
|
|
|
if (rd->imtype == R_QUICKTIME) {
|
|
|
|
|
if ((rd->qtcodecsettings.codecType<= 0) ||
|
|
|
|
|
(rd->qtcodecsettings.codecSpatialQuality <0) ||
|
|
|
|
|
(rd->qtcodecsettings.codecSpatialQuality > 100)) {
|
2009-11-18 15:01:59 +00:00
|
|
|
|
2009-11-20 10:37:50 +00:00
|
|
|
rd->qtcodecsettings.codecType = QT_CODECTYPE_JPEG;
|
|
|
|
|
rd->qtcodecsettings.codecSpatialQuality = (codecHighQuality*100)/codecLosslessQuality;
|
2009-11-18 09:49:42 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* _WIN32 || __APPLE__ */
|
|
|
|
|
#endif /* WITH_QUICKTIME */
|
|
|
|
|
|