06082832b1e54994d2b759e64aa59174954662ad
[blender-staging.git] / source / blender / quicktime / apple / qtkit_export.m
1 /**
2  * $Id$
3  *
4  * qtkit_export.m
5  *
6  * Code to create QuickTime Movies with Blender
7  *
8  * ***** BEGIN GPL LICENSE BLOCK *****
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  *
23  *
24  * The Original Code is written by Rob Haarsma (phase)
25  *
26  * Contributor(s): Stefan Gartner (sgefant)
27  *                                 Damien Plisson 11/2009
28  *
29  * ***** END GPL LICENSE BLOCK *****
30  */
31
32 #ifdef WITH_QUICKTIME
33 #if defined(_WIN32) || defined(__APPLE__)
34
35 #include <stdio.h>
36 #include <string.h>
37
38 #include "DNA_scene_types.h"
39
40 #include "BKE_global.h"
41 #include "BKE_scene.h"
42 #include "BKE_report.h"
43
44 #include "BLI_blenlib.h"
45
46 #include "BLO_sys_types.h"
47
48 #include "IMB_imbuf.h"
49 #include "IMB_imbuf_types.h"
50
51 #include "MEM_guardedalloc.h"
52
53 #ifdef __APPLE__
54 /* evil */
55 #ifndef __AIFF__
56 #define __AIFF__
57 #endif
58 #import <Cocoa/Cocoa.h>
59 #import <QTKit/QTKit.h>
60
61 #if (MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4) || !__LP64__
62 #error 64 bit build & OSX 10.5 minimum are needed for QTKit
63 #endif
64
65 #include "quicktime_import.h"
66 #include "quicktime_export.h"
67
68 #endif /* __APPLE__ */
69
70 typedef struct QuicktimeExport {
71         QTMovie *movie;
72         
73         NSString *filename;
74
75         QTTime frameDuration;
76         NSDictionary *frameAttributes;
77 } QuicktimeExport;
78
79 static struct QuicktimeExport *qtexport;
80
81 #pragma mark rna helper functions
82
83
84 static QuicktimeCodecTypeDesc qtCodecList[] = {
85         {kRawCodecType, 1, "Uncompressed"},
86         {kJPEGCodecType, 2, "JPEG"},
87         {kMotionJPEGACodecType, 3, "M-JPEG A"},
88         {kMotionJPEGBCodecType, 4, "M-JPEG B"},
89         {kDVCPALCodecType, 5, "DV PAL"},
90         {kDVCNTSCCodecType, 6, "DV/DVCPRO NTSC"},
91         {kDVCPROHD720pCodecType, 7, "DVCPRO HD 720p"},
92         {kDVCPROHD1080i50CodecType, 8, "DVCPRO HD 1080i50"},
93         {kDVCPROHD1080i60CodecType, 9, "DVCPRO HD 1080i60"},
94         {kMPEG4VisualCodecType, 10, "MPEG4"},
95         {kH263CodecType, 11, "H.263"},
96         {kH264CodecType, 12, "H.264"},
97         {0,0,NULL}};
98
99 static int qtCodecCount = 12;
100
101 int quicktime_get_num_codecs() {
102         return qtCodecCount;
103 }
104
105 QuicktimeCodecTypeDesc* quicktime_get_codecType_desc(int indexValue) {
106         if ((indexValue>=0) && (indexValue < qtCodecCount))
107                 return &qtCodecList[indexValue];
108         else
109                 return NULL;
110 }
111
112 int quicktime_rnatmpvalue_from_codectype(int codecType) {
113         int i;
114         for (i=0;i<qtCodecCount;i++) {
115                 if (qtCodecList[i].codecType == codecType)
116                         return qtCodecList[i].rnatmpvalue;
117         }
118
119         return 0;
120 }
121
122 int quicktime_codecType_from_rnatmpvalue(int rnatmpvalue) {
123         int i;
124         for (i=0;i<qtCodecCount;i++) {
125                 if (qtCodecList[i].rnatmpvalue == rnatmpvalue)
126                         return qtCodecList[i].codecType;
127         }
128         
129         return 0;       
130 }
131
132
133 static NSString *stringWithCodecType(int codecType) {
134         char str[5];
135         
136         *((int*)str) = EndianU32_NtoB(codecType);
137         str[4] = 0;
138         
139         return [NSString stringWithCString:str encoding:NSASCIIStringEncoding];
140 }
141
142 void makeqtstring (RenderData *rd, char *string) {
143         char txt[64];
144
145         strcpy(string, rd->pic);
146         BLI_path_abs(string, G.sce);
147
148         BLI_make_existing_file(string);
149
150         if (BLI_strcasecmp(string + strlen(string) - 4, ".mov")) {
151                 sprintf(txt, "%04d_%04d.mov", (rd->sfra) , (rd->efra) );
152                 strcat(string, txt);
153         }
154 }
155
156 void filepath_qt(char *string, RenderData *rd) {
157         if (string==NULL) return;
158         
159         strcpy(string, rd->pic);
160         BLI_path_abs(string, G.sce);
161         
162         BLI_make_existing_file(string);
163         
164         if (!BLI_testextensie(string, ".mov")) {
165                 /* if we dont have any #'s to insert numbers into, use 4 numbers by default */
166                 if (strchr(string, '#')==NULL)
167                         strcat(string, "####"); /* 4 numbers */
168
169                 BLI_path_frame_range(string, rd->sfra, rd->efra, 4);
170                 strcat(string, ".mov");
171         }
172 }
173
174
175 #pragma mark export functions
176
177 int start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty, ReportList *reports)
178 {
179         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
180         NSError *error;
181         char name[2048];
182         int success= 1;
183
184         if(qtexport == NULL) qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport");
185         
186         [QTMovie enterQTKitOnThread];           
187         
188         /* Check first if the QuickTime 7.2.1 initToWritableFile: method is available */
189         if ([[[[QTMovie alloc] init] autorelease] respondsToSelector:@selector(initToWritableFile:error:)] != YES) {
190                 BKE_report(reports, RPT_ERROR, "\nUnable to create quicktime movie, need Quicktime rev 7.2.1 or later");
191                 success= 0;
192         }
193         else {
194                 makeqtstring(rd, name);
195                 qtexport->filename = [NSString stringWithCString:name
196                                                                   encoding:[NSString defaultCStringEncoding]];
197                 qtexport->movie = [[QTMovie alloc] initToWritableFile:qtexport->filename error:&error];
198                         
199                 if(qtexport->movie == nil) {
200                         BKE_report(reports, RPT_ERROR, "Unable to create quicktime movie.");
201                         success= 0;
202                         NSLog(@"Unable to create quicktime movie : %@",[error localizedDescription]);
203                         [QTMovie exitQTKitOnThread];
204                 } else {
205                         [qtexport->movie retain];
206                         [qtexport->filename retain];
207                         [qtexport->movie setAttribute:[NSNumber numberWithBool:YES] forKey:QTMovieEditableAttribute];
208                         [qtexport->movie setAttribute:@"Made with Blender" forKey:QTMovieCopyrightAttribute];
209                         
210                         qtexport->frameDuration = QTMakeTime(rd->frs_sec_base*1000, rd->frs_sec*1000);
211                         
212                         /* specifying the codec attributes : try to retrieve them from render data first*/
213                         if (rd->qtcodecsettings.codecType) {
214                                 qtexport->frameAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
215                                                                                          stringWithCodecType(rd->qtcodecsettings.codecType),
216                                                                                          QTAddImageCodecType,
217                                                                                          [NSNumber numberWithLong:((rd->qtcodecsettings.codecSpatialQuality)*codecLosslessQuality)/100],
218                                                                                          QTAddImageCodecQuality,
219                                                                                          nil];
220                         }
221                         else {
222                                 qtexport->frameAttributes = [NSDictionary dictionaryWithObjectsAndKeys:@"jpeg",
223                                                                                          QTAddImageCodecType,
224                                                                                          [NSNumber numberWithLong:codecHighQuality],
225                                                                                          QTAddImageCodecQuality,
226                                                                                          nil];
227                         }
228                         [qtexport->frameAttributes retain];
229                 }
230         }
231         
232         [pool drain];
233
234         return success;
235 }
236
237
238 int append_qt(struct RenderData *rd, int frame, int *pixels, int rectx, int recty, ReportList *reports)
239 {
240         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
241         NSBitmapImageRep *blBitmapFormatImage;
242         NSImage *frameImage;
243         unsigned char *from_Ptr,*to_Ptr;
244         int y,from_i,to_i;
245         
246         
247         /* Create bitmap image rep in blender format (32bit RGBA) */
248         blBitmapFormatImage = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
249                                                                                                                                   pixelsWide:rectx 
250                                                                                                                                   pixelsHigh:recty
251                                                                                                                            bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO
252                                                                                                                           colorSpaceName:NSCalibratedRGBColorSpace 
253                                                                                                                                 bitmapFormat:NSAlphaNonpremultipliedBitmapFormat
254                                                                                                                                  bytesPerRow:rectx*4
255                                                                                                                                 bitsPerPixel:32];
256         if (!blBitmapFormatImage) {
257                 [pool drain];
258                 return 0;
259         }
260         
261         from_Ptr = (unsigned char*)pixels;
262         to_Ptr = (unsigned char*)[blBitmapFormatImage bitmapData];
263         for (y = 0; y < recty; y++) {
264                 to_i = (recty-y-1)*rectx;
265                 from_i = y*rectx;
266                 memcpy(to_Ptr+4*to_i, from_Ptr+4*from_i, 4*rectx);
267         }
268         
269         frameImage = [[NSImage alloc] initWithSize:NSMakeSize(rectx, recty)];
270         [frameImage addRepresentation:blBitmapFormatImage];
271         
272         /* Add the image to the movie clip */
273         [qtexport->movie addImage:frameImage
274                                   forDuration:qtexport->frameDuration
275                            withAttributes:qtexport->frameAttributes];
276
277         [blBitmapFormatImage release];
278         [frameImage release];
279         [pool drain];   
280
281         return 1;
282 }
283
284
285 void end_qt(void)
286 {
287         if (qtexport->movie) {
288                 /* Flush update of the movie file */
289                 [qtexport->movie updateMovieFile];
290                 
291                 [qtexport->movie invalidate];
292                 
293                 /* Clean up movie structure */
294                 [qtexport->filename release];
295                 [qtexport->frameAttributes release];
296                 [qtexport->movie release];
297                 }
298         
299         [QTMovie exitQTKitOnThread];
300
301         if(qtexport) {
302                 MEM_freeN(qtexport);
303                 qtexport = NULL;
304         }
305 }
306
307
308 void free_qtcomponentdata(void) {
309 }
310
311 void quicktime_verify_image_type(RenderData *rd)
312 {
313         if (rd->imtype == R_QUICKTIME) {
314                 if ((rd->qtcodecsettings.codecType<= 0) ||
315                         (rd->qtcodecsettings.codecSpatialQuality <0) ||
316                         (rd->qtcodecsettings.codecSpatialQuality > 100)) {
317                         
318                         rd->qtcodecsettings.codecType = kJPEGCodecType;
319                         rd->qtcodecsettings.codecSpatialQuality = (codecHighQuality*100)/codecLosslessQuality;
320                 }
321         }
322 }
323
324 #endif /* _WIN32 || __APPLE__ */
325 #endif /* WITH_QUICKTIME */
326