~ubuntu-branches/ubuntu/trusty/openscenegraph/trusty

« back to all changes in this revision

Viewing changes to OpenSceneGraph/src/osgPlugins/quicktime/QTImportExport.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Cyril Brulebois
  • Date: 2008-07-29 04:34:38 UTC
  • mfrom: (1.1.6 upstream) (2.1.3 lenny)
  • Revision ID: james.westby@ubuntu.com-20080729043438-no1h9h0dpsrlzp1y
* Non-maintainer upload.
* No longer try to detect (using /proc/cpuinfo when available) how many
  CPUs are available, fixing the FTBFS (due to -j0) on various platforms
  (Closes: #477353). The right way to do it is to support parallel=n in
  DEB_BUILD_OPTIONS (see Debian Policy §4.9.1), and adequate support has
  been implemented.
* Add patch to fix FTBFS due to the build system now refusing to handle
  whitespaces (Policy CMP0004 say the logs), thanks to Andreas Putzo who
  provided it (Closes: #482239):
   - debian/patches/fix-cmp0004-build-failure.dpatch
* Remove myself from Uploaders, as requested a while ago, done by Luk in
  his 2.2.0-2.1 NMU, which was never acknowledged.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  QTImportExport.cpp
 
3
 *  cefix
 
4
 *
 
5
 *  Created by Stephan Huber on 07.02.08.
 
6
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
 
7
 *
 
8
 */
 
9
#include <map>
 
10
#include <sstream>
 
11
#include "QTImportExport.h"
 
12
#include "QTUtils.h"
 
13
 
 
14
#include <osgDB/FileNameUtils>
 
15
 
 
16
 
 
17
/** small exception class bundling a error-message */
 
18
class QTImportExportException : public std::exception {
 
19
 
 
20
    public:
 
21
        QTImportExportException(int err, const std::string& msg) : std::exception(), _err(err), _msg(msg) {}
 
22
        
 
23
        virtual const char* what() { return _msg.c_str(); }
 
24
        int getErrorCode() { return _err; }
 
25
        
 
26
        virtual ~QTImportExportException() throw () {}
 
27
        
 
28
    private:
 
29
        int _err;
 
30
        std::string _msg;
 
31
};
 
32
 
 
33
QuicktimeImportExport::QuicktimeImportExport() 
 
34
:    _error(0), 
 
35
    _lastError("")
 
36
{
 
37
    initQuicktime();
 
38
}
 
39
 
 
40
 
 
41
// ----------------------------------------------------------------------------------------------------------
 
42
// flipImage
 
43
// ----------------------------------------------------------------------------------------------------------
 
44
 
 
45
void QuicktimeImportExport::flipImage(unsigned char* pixels, int bytesPerPixel, unsigned int width, unsigned height) 
 
46
{
 
47
    // Flip the image
 
48
    unsigned imageSize = width * height * bytesPerPixel;
 
49
    char *tBuffer = new char [imageSize];
 
50
    unsigned int rowBytes = width * bytesPerPixel;
 
51
    unsigned int i,j;
 
52
    for (i = 0, j = imageSize - rowBytes; i < imageSize; i += rowBytes, j -= rowBytes)
 
53
        memcpy( &tBuffer[j], &pixels[i], (size_t)rowBytes );
 
54
 
 
55
    memcpy(pixels, tBuffer, (size_t)imageSize);
 
56
    delete[] tBuffer;
 
57
}
 
58
 
 
59
 
 
60
 
 
61
 
 
62
// ----------------------------------------------------------------------------------------------------------
 
63
// prepareBufferForOSG
 
64
// ----------------------------------------------------------------------------------------------------------
 
65
 
 
66
unsigned char* QuicktimeImportExport::pepareBufferForOSG(unsigned char * buffer, int bytesPerPixel, unsigned int width, unsigned int height)
 
67
{
 
68
    unsigned char *pixels = new unsigned char [height * width * 4];
 
69
    unsigned char *dstp = pixels;
 
70
    unsigned char *srcp = buffer;
 
71
    unsigned int i, j;
 
72
    
 
73
    int roffset, goffset, boffset, aoffset;
 
74
    aoffset = -1;
 
75
    int sourceStep;
 
76
    
 
77
    switch (bytesPerPixel) {
 
78
        case 1:
 
79
            sourceStep = 1;
 
80
            roffset = goffset = boffset = 0;
 
81
            break;
 
82
        case 3:
 
83
            sourceStep = 3;
 
84
            roffset = 0;
 
85
            goffset = 1;
 
86
            boffset = 2;
 
87
            break;
 
88
        case 4:
 
89
            sourceStep = 4;
 
90
            aoffset = 1;
 
91
            roffset = 2;
 
92
            goffset = 3;
 
93
            boffset = 0;
 
94
            break;
 
95
            
 
96
    }
 
97
                    
 
98
    for (i = 0; i < height; ++i ) 
 
99
    {
 
100
        for (j = 0; j < width; ++j ) 
 
101
        {
 
102
            dstp[0] = (aoffset < 0) ? 0 : srcp[aoffset];
 
103
            dstp[1] = srcp[roffset];
 
104
            dstp[2] = srcp[goffset];
 
105
            dstp[3] = srcp[boffset];
 
106
            srcp+=sourceStep;
 
107
            dstp+=4;
 
108
            
 
109
        }
 
110
    }
 
111
    
 
112
    flipImage(pixels, bytesPerPixel, width, height);
 
113
    return pixels;
 
114
 
 
115
}
 
116
 
 
117
 
 
118
 
 
119
// ----------------------------------------------------------------------------------------------------------
 
120
// prepareBufferForQuicktime
 
121
// ----------------------------------------------------------------------------------------------------------
 
122
 
 
123
unsigned char* QuicktimeImportExport::prepareBufferForQuicktime(unsigned char* buffer, GLenum pixelFormat, int bytesPerPixel, unsigned int width, unsigned int height) 
 
124
{
 
125
    unsigned char *pixels = new unsigned char [height * width * 4];
 
126
    unsigned char *dstp = pixels;
 
127
    unsigned char *srcp = buffer;
 
128
    unsigned int i, j;
 
129
    
 
130
    int roffset, goffset, boffset, aoffset;
 
131
    aoffset = -1;
 
132
    int sourceStep;
 
133
    
 
134
    switch (bytesPerPixel) {
 
135
        case 1:
 
136
            sourceStep = 1;
 
137
            roffset = goffset = boffset = 0;
 
138
            break;
 
139
        case 3:
 
140
            sourceStep = 3;
 
141
            roffset = 0;
 
142
            goffset = 1;
 
143
            boffset = 2;
 
144
            break;
 
145
        case 4:
 
146
            sourceStep = 4;
 
147
            switch (pixelFormat) {
 
148
                case GL_RGBA:
 
149
                    aoffset = 3;
 
150
                    roffset = 0;
 
151
                    goffset = 1;
 
152
                    boffset = 2;
 
153
                    break;
 
154
                
 
155
                case GL_BGRA_EXT:
 
156
                    aoffset = 0;
 
157
                    roffset = 1;
 
158
                    goffset = 2;
 
159
                    boffset = 3;
 
160
                    break;
 
161
            }
 
162
    }
 
163
                    
 
164
            
 
165
    for (i = 0; i < height; ++i ) 
 
166
    {
 
167
        for (j = 0; j < width; ++j ) 
 
168
        {
 
169
            dstp[0] = (aoffset < 0) ? 0 : srcp[aoffset];
 
170
            dstp[1] = srcp[roffset];
 
171
            dstp[2] = srcp[goffset];
 
172
            dstp[3] = srcp[boffset];
 
173
            srcp+=sourceStep;
 
174
            dstp+=4;
 
175
            
 
176
        }
 
177
    }
 
178
    
 
179
    flipImage(pixels, 4, width, height);
 
180
    
 
181
    return pixels;
 
182
 
 
183
}
 
184
 
 
185
// ----------------------------------------------------------------------------------------------------------
 
186
// readFromStream
 
187
// ----------------------------------------------------------------------------------------------------------
 
188
 
 
189
osg::Image* QuicktimeImportExport::readFromStream(std::istream & inStream, const std::string& fileTypeHint, long sizeHint) 
 
190
{
 
191
    char* content = NULL;
 
192
    long length = 0;
 
193
     if (sizeHint != 0) 
 
194
    {
 
195
        length = sizeHint;
 
196
        content = new char[length];
 
197
        inStream.read (content,length);
 
198
    }
 
199
    else 
 
200
    {
 
201
        int readBytes(0), newBytes(0);
 
202
        
 
203
        char buffer[10240];
 
204
        
 
205
        while (!inStream.eof()) {
 
206
            inStream.read(buffer, 10240);
 
207
            newBytes = inStream.gcount();
 
208
            if (newBytes > 0) {
 
209
                char* newcontent = new char[readBytes + newBytes];
 
210
            
 
211
                if (readBytes > 0)
 
212
                    memcpy(newcontent, content, readBytes);
 
213
                
 
214
                memcpy(&newcontent[readBytes], &buffer, newBytes);
 
215
                readBytes += newBytes;
 
216
                if (content) delete[] content;
 
217
                content = newcontent;
 
218
            }
 
219
        }
 
220
        length = readBytes;
 
221
    }
 
222
    
 
223
    osg::Image* img = doImport(reinterpret_cast<unsigned char*>(content), length, fileTypeHint);
 
224
    
 
225
    if (content) delete[] content;
 
226
    return img;
 
227
 }
 
228
 
 
229
 
 
230
Handle getPtrDataRef(unsigned char *data, unsigned int size, const std::string &filename)
 
231
{
 
232
     // Load Data Reference
 
233
     Handle dataRef;
 
234
     Handle fileNameHandle;
 
235
     PointerDataRefRecord ptrDataRefRec;
 
236
     ComponentInstance dataRefHandler;
 
237
     unsigned char pstr[255];
 
238
 
 
239
     ptrDataRefRec.data = data;
 
240
     ptrDataRefRec.dataLength = size;
 
241
 
 
242
     /*err = */PtrToHand(&ptrDataRefRec, &dataRef, sizeof(PointerDataRefRecord));
 
243
 
 
244
     // Open a Data Handler for the Data Reference
 
245
     /*err = */OpenADataHandler(dataRef, PointerDataHandlerSubType, NULL,
 
246
         (OSType)0, NULL, kDataHCanRead, &dataRefHandler);
 
247
 
 
248
     // Convert From CString in filename to a PascalString in pstr
 
249
     if (filename.length() > 255) {
 
250
         CopyCStringToPascal(filename.c_str(), pstr);
 
251
         //hmm...not good, pascal string limit is 255!
 
252
         //do some error handling maybe?!
 
253
     }
 
254
 
 
255
    // Add filename extension
 
256
     /*err = */PtrToHand(pstr, &fileNameHandle, filename.length() + 1);
 
257
     /*err = */DataHSetDataRefExtension(dataRefHandler, fileNameHandle,
 
258
         kDataRefExtensionFileName);
 
259
     DisposeHandle(fileNameHandle);
 
260
 
 
261
     // Release old handler which does not have the extensions
 
262
     DisposeHandle(dataRef);
 
263
 
 
264
     // Grab the SAFE_NEW version of the data ref from the data handler
 
265
     /*err = */ DataHGetDataRef(dataRefHandler, &dataRef);
 
266
     
 
267
     CloseComponent(dataRefHandler);
 
268
     
 
269
     return dataRef;
 
270
}
 
271
 
 
272
 
 
273
osg::Image* QuicktimeImportExport::doImport(unsigned char* data, unsigned int sizeData, const std::string& fileTypeHint)
 
274
{
 
275
    GWorldPtr gworld = 0;
 
276
    OSType pixelFormat;
 
277
    int rowStride;
 
278
    GraphicsImportComponent gicomp = 0;
 
279
    Rect rectImage;
 
280
    GDHandle origDevice = 0;
 
281
    CGrafPtr origPort = 0;
 
282
    ImageDescriptionHandle desc = 0;
 
283
    int depth = 32;
 
284
    unsigned int xsize, ysize;
 
285
    unsigned char* imageData;
 
286
    
 
287
    // Data Handle for file data ( & load data from file )
 
288
    Handle dataRef = getPtrDataRef(data, sizeData, fileTypeHint);
 
289
    
 
290
    try {
 
291
        OSErr err = noErr;
 
292
        
 
293
        // GraphicsImporter - Get Importer for our filetype
 
294
        GetGraphicsImporterForDataRef(dataRef, 'ptr ', &gicomp);
 
295
 
 
296
        // GWorld - Get Texture Info
 
297
        err = GraphicsImportGetNaturalBounds(gicomp, &rectImage);
 
298
        if (err != noErr) {
 
299
            throw QTImportExportException(err, "GraphicsImportGetNaturalBounds failed");
 
300
            
 
301
        }
 
302
        xsize = (unsigned int)(rectImage.right - rectImage.left);
 
303
        ysize = (unsigned int)(rectImage.bottom - rectImage.top);
 
304
 
 
305
        // ImageDescription - Get Image Description
 
306
        err = GraphicsImportGetImageDescription(gicomp, &desc);
 
307
        if (err != noErr) {
 
308
            throw QTImportExportException(err, "GraphicsImportGetImageDescription failed");
 
309
        }
 
310
 
 
311
        // ImageDescription - Get Bit Depth
 
312
        HLock(reinterpret_cast<char **>(desc));
 
313
        
 
314
 
 
315
        // GWorld - Pixel Format stuff
 
316
        pixelFormat = k32ARGBPixelFormat; // Make sure its forced...NOTE: i'm pretty sure this cannot be RGBA!
 
317
 
 
318
        // GWorld - Row stride
 
319
        rowStride = xsize * 4; // (width * depth_bpp / 8)
 
320
 
 
321
        // GWorld - Allocate output buffer
 
322
        imageData = new unsigned char[rowStride * ysize];
 
323
 
 
324
        // GWorld - Actually Create IT!
 
325
        QTNewGWorldFromPtr(&gworld, pixelFormat, &rectImage, 0, 0, 0, imageData, rowStride);
 
326
        if (!gworld) {
 
327
            throw QTImportExportException(-1, "QTNewGWorldFromPtr failed");
 
328
        }
 
329
 
 
330
        // Save old Graphics Device and Graphics Port to reset to later
 
331
        GetGWorld (&origPort, &origDevice);
 
332
 
 
333
        // GraphicsImporter - Set Destination GWorld (our buffer)
 
334
        err = GraphicsImportSetGWorld(gicomp, gworld, 0);
 
335
        if (err != noErr) {
 
336
            throw QTImportExportException(err, "GraphicsImportSetGWorld failed");
 
337
        }
 
338
 
 
339
        // GraphicsImporter - Set Quality Level
 
340
        err = GraphicsImportSetQuality(gicomp, codecLosslessQuality);
 
341
        if (err != noErr) {
 
342
            throw QTImportExportException(err, "GraphicsImportSetQuality failed");
 
343
        }
 
344
 
 
345
        // Lock pixels so that we can draw to our memory texture
 
346
        if (!GetGWorldPixMap(gworld) || !LockPixels(GetGWorldPixMap(gworld))) {
 
347
            throw QTImportExportException(0, "GetGWorldPixMap failed");
 
348
        }
 
349
        
 
350
           
 
351
        //*** Draw GWorld into our Memory Texture!
 
352
        GraphicsImportDraw(gicomp);
 
353
 
 
354
        // Clean up
 
355
        UnlockPixels(GetGWorldPixMap(gworld));
 
356
        SetGWorld(origPort, origDevice); // set graphics port to offscreen (we don't need it now)
 
357
        DisposeGWorld(gworld);
 
358
        CloseComponent(gicomp);
 
359
        DisposeHandle(reinterpret_cast<char **>(desc));
 
360
        DisposeHandle(dataRef);
 
361
    } 
 
362
    catch (QTImportExportException e) 
 
363
    {
 
364
        setError(e.what());
 
365
        
 
366
        if (gworld) {
 
367
            UnlockPixels(GetGWorldPixMap(gworld));
 
368
            SetGWorld(origPort, origDevice); // set graphics port to offscreen (we don't need it now)
 
369
            DisposeGWorld(gworld);
 
370
        }
 
371
        if (gicomp)
 
372
            CloseComponent(gicomp);
 
373
        if (desc) 
 
374
            DisposeHandle(reinterpret_cast<char **>(desc));
 
375
        
 
376
        if (imageData) 
 
377
            delete[] imageData;
 
378
        if (dataRef)
 
379
            DisposeHandle(dataRef);
 
380
            
 
381
        return NULL;
 
382
    }
 
383
    
 
384
 
 
385
    
 
386
    unsigned int glpixelFormat;
 
387
            
 
388
    switch(depth >> 3) {
 
389
        case 3 :
 
390
            glpixelFormat = GL_RGB;
 
391
            break;
 
392
        case 4 :
 
393
            glpixelFormat = GL_RGBA;
 
394
            break;
 
395
        default :
 
396
            delete imageData;
 
397
            setError("unknown pixelformat");
 
398
            return NULL;
 
399
            break;
 
400
    }
 
401
    
 
402
    unsigned char* swizzled = pepareBufferForOSG(imageData, depth >> 3, xsize, ysize);
 
403
    
 
404
    delete[] imageData;
 
405
 
 
406
    osg::Image* image = new osg::Image();
 
407
    image->setFileName(fileTypeHint.c_str());
 
408
    image->setImage(xsize,ysize,1,
 
409
        depth >> 3,
 
410
        glpixelFormat,
 
411
        GL_UNSIGNED_BYTE,
 
412
        swizzled,
 
413
        osg::Image::USE_NEW_DELETE );
 
414
    
 
415
 
 
416
    return image;
 
417
}
 
418
 
 
419
 
 
420
 void QuicktimeImportExport::writeToStream(std::ostream& outStream, osg::Image* image, const std::string& fileTypeHint) 
 
421
 {
 
422
 
 
423
    std::string ext = osgDB::getFileExtension(fileTypeHint);
 
424
    //Build map  of extension <-> osFileTypes
 
425
    static std::map<std::string, OSType> extmap;
 
426
    if (extmap.size() == 0) {
 
427
        extmap["jpg"]  = kQTFileTypeJPEG;
 
428
        extmap["jpeg"] = kQTFileTypeJPEG;
 
429
        extmap["bmp"]  = kQTFileTypeBMP;
 
430
        extmap["tif"]  = kQTFileTypeTIFF;
 
431
        extmap["tiff"] = kQTFileTypeTIFF;
 
432
        extmap["png"]  = kQTFileTypePNG;
 
433
        extmap["gif"]  = kQTFileTypeGIF;
 
434
        extmap["psd"]  = kQTFileTypePhotoShop;
 
435
        extmap["sgi"]  = kQTFileTypeSGIImage;
 
436
        extmap["rgb"]  = kQTFileTypeSGIImage;
 
437
        extmap["rgba"] = kQTFileTypeSGIImage;
 
438
    }
 
439
 
 
440
    
 
441
    std::map<std::string, OSType>::iterator cur = extmap.find(ext);
 
442
    
 
443
    // can not handle this type of file, perhaps a movie?
 
444
    if (cur == extmap.end())
 
445
        return;
 
446
    
 
447
    unsigned int numBytes = image->computeNumComponents(image->getPixelFormat());
 
448
    unsigned char* pixels = prepareBufferForQuicktime(
 
449
        image->data(),
 
450
        image->getPixelFormat(), 
 
451
        numBytes,
 
452
        image->s(),
 
453
        image->t()
 
454
    );
 
455
    
 
456
        
 
457
    OSType desiredType = cur->second;
 
458
    GraphicsExportComponent geComp = NULL;
 
459
    GWorldPtr gw = 0;
 
460
    Handle dataHandle;
 
461
    dataHandle = NewHandle(0);
 
462
 
 
463
    try {
 
464
        OSErr err = OpenADefaultComponent(GraphicsExporterComponentType, desiredType, &geComp);
 
465
        Rect bounds = {0,0, image->t(), image->s()};
 
466
        
 
467
        err = QTNewGWorldFromPtr(&gw, k32ARGBPixelFormat, &bounds, 0,0,0, pixels, image->s()*4);
 
468
        if (err != noErr) {
 
469
            throw QTImportExportException(err,  "could not create gworld for type " + ext);
 
470
        }
 
471
        
 
472
        err = GraphicsExportSetInputGWorld(geComp, gw);
 
473
        if (err != noErr) {
 
474
            throw QTImportExportException(err, "could not set input gworld for type " + ext);
 
475
        }
 
476
        
 
477
        err = GraphicsExportSetOutputHandle( geComp, dataHandle);
 
478
        if (err != noErr) {
 
479
            throw QTImportExportException(err, "could not set output file for type " + ext);
 
480
        } 
 
481
        
 
482
        // Set the compression quality (needed for JPEG, not necessarily for other formats)
 
483
        if (desiredType == kQTFileTypeJPEG) {
 
484
            err = GraphicsExportSetCompressionQuality(geComp, codecLosslessQuality);
 
485
            if (err != noErr) {
 
486
                throw QTImportExportException(err, "could not set compression for type " + ext);
 
487
            }
 
488
        }
 
489
        
 
490
        if(4 == numBytes)
 
491
        {
 
492
            err = GraphicsExportSetDepth( geComp, k32ARGBPixelFormat );    // depth
 
493
        }
 
494
        // else k24RGBPixelFormat???
 
495
        
 
496
        // do the export
 
497
        err = GraphicsExportDoExport(geComp, NULL);
 
498
        if (err != noErr) {
 
499
            throw QTImportExportException(err, "could not do the export for type " + ext);
 
500
        } 
 
501
        
 
502
        if (geComp != NULL)
 
503
            CloseComponent(geComp);
 
504
            
 
505
        if (gw) DisposeGWorld (gw);
 
506
        if (pixels) free(pixels);
 
507
        
 
508
        outStream.write(*dataHandle, GetHandleSize(dataHandle));
 
509
        DisposeHandle(dataHandle);
 
510
    }
 
511
    
 
512
    
 
513
    catch (QTImportExportException e) 
 
514
    {
 
515
        setError(e.what());
 
516
        
 
517
        if (geComp != NULL) CloseComponent(geComp);      
 
518
        if (gw != NULL) DisposeGWorld (gw);
 
519
        if (pixels) free(pixels);
 
520
        
 
521
        DisposeHandle(dataHandle);
 
522
 
 
523
    }
 
524
 
 
525
}
 
526