root/OpenSceneGraph/trunk/src/osgPlugins/quicktime/QTImportExport.cpp @ 9769

Revision 9769, 15.8 kB (checked in by robert, 6 years ago)

From Riccardo Corsi, "in attach you'll find a patch to cleanup a little bit the (de)initialization code of QuickTime? environment from the quickTime pluging.
It basically removes the static init() and exit() functions,and move them inside the observer class (the one that cleans everything up when the last media is unloaded).

It also add an extra check to clean up on exit if the QuickTime? env is initialized, but no media is succesfully loaded / written (it might happens with streaming resources).

I tested it under WinXP with zero, one and multiple videos.

Stephan reads in copy: could you kindly check if everything runs smooth under OSX as well? Also, have you got a chance to test it with streaming media?
"

RevLine 
[8132]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 */
18class 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
33QuicktimeImportExport::QuicktimeImportExport()
34:    _error(0),
35    _lastError("")
36{
37}
38
39
40// ----------------------------------------------------------------------------------------------------------
41// flipImage
42// ----------------------------------------------------------------------------------------------------------
43
44void QuicktimeImportExport::flipImage(unsigned char* pixels, int bytesPerPixel, unsigned int width, unsigned height)
45{
46    // Flip the image
47    unsigned imageSize = width * height * bytesPerPixel;
48    char *tBuffer = new char [imageSize];
49    unsigned int rowBytes = width * bytesPerPixel;
50    unsigned int i,j;
51    for (i = 0, j = imageSize - rowBytes; i < imageSize; i += rowBytes, j -= rowBytes)
52        memcpy( &tBuffer[j], &pixels[i], (size_t)rowBytes );
53
54    memcpy(pixels, tBuffer, (size_t)imageSize);
55    delete[] tBuffer;
56}
57
58
59
60
61// ----------------------------------------------------------------------------------------------------------
62// prepareBufferForOSG
63// ----------------------------------------------------------------------------------------------------------
64
65unsigned char* QuicktimeImportExport::pepareBufferForOSG(unsigned char * buffer, int bytesPerPixel, unsigned int width, unsigned int height)
66{
67    unsigned char *pixels = new unsigned char [height * width * 4];
68    unsigned char *dstp = pixels;
69    unsigned char *srcp = buffer;
70    unsigned int i, j;
71   
72    int roffset, goffset, boffset, aoffset;
73    aoffset = -1;
74    int sourceStep;
75   
76    switch (bytesPerPixel) {
77        case 1:
78            sourceStep = 1;
79            roffset = goffset = boffset = 0;
80            break;
81        case 3:
82            sourceStep = 3;
83            roffset = 0;
84            goffset = 1;
85            boffset = 2;
86            break;
87        case 4:
88            sourceStep = 4;
89            aoffset = 1;
90            roffset = 2;
91            goffset = 3;
92            boffset = 0;
93            break;
94           
95    }
96                   
97    for (i = 0; i < height; ++i )
98    {
99        for (j = 0; j < width; ++j )
100        {
101            dstp[0] = (aoffset < 0) ? 0 : srcp[aoffset];
102            dstp[1] = srcp[roffset];
103            dstp[2] = srcp[goffset];
104            dstp[3] = srcp[boffset];
105            srcp+=sourceStep;
106            dstp+=4;
107           
108        }
109    }
110   
111    flipImage(pixels, bytesPerPixel, width, height);
112    return pixels;
113
114}
115
116
117
118// ----------------------------------------------------------------------------------------------------------
119// prepareBufferForQuicktime
120// ----------------------------------------------------------------------------------------------------------
121
122unsigned char* QuicktimeImportExport::prepareBufferForQuicktime(unsigned char* buffer, GLenum pixelFormat, int bytesPerPixel, unsigned int width, unsigned int height)
123{
124    unsigned char *pixels = new unsigned char [height * width * 4];
125    unsigned char *dstp = pixels;
126    unsigned char *srcp = buffer;
127    unsigned int i, j;
128   
129    int roffset, goffset, boffset, aoffset;
130    aoffset = -1;
131    int sourceStep;
132   
133    switch (bytesPerPixel) {
134        case 1:
135            sourceStep = 1;
136            roffset = goffset = boffset = 0;
137            break;
138        case 3:
139            sourceStep = 3;
140            roffset = 0;
141            goffset = 1;
142            boffset = 2;
143            break;
144        case 4:
145            sourceStep = 4;
146            switch (pixelFormat) {
147                case GL_RGBA:
148                    aoffset = 3;
149                    roffset = 0;
150                    goffset = 1;
151                    boffset = 2;
152                    break;
153               
154                case GL_BGRA_EXT:
155                    aoffset = 0;
156                    roffset = 1;
157                    goffset = 2;
158                    boffset = 3;
159                    break;
160            }
161    }
162                   
163           
164    for (i = 0; i < height; ++i )
165    {
166        for (j = 0; j < width; ++j )
167        {
168            dstp[0] = (aoffset < 0) ? 0 : srcp[aoffset];
169            dstp[1] = srcp[roffset];
170            dstp[2] = srcp[goffset];
171            dstp[3] = srcp[boffset];
172            srcp+=sourceStep;
173            dstp+=4;
174           
175        }
176    }
177   
178    flipImage(pixels, 4, width, height);
179   
180    return pixels;
181
182}
183
184// ----------------------------------------------------------------------------------------------------------
185// readFromStream
186// ----------------------------------------------------------------------------------------------------------
187
188osg::Image* QuicktimeImportExport::readFromStream(std::istream & inStream, const std::string& fileTypeHint, long sizeHint)
189{
190    char* content = NULL;
191    long length = 0;
192     if (sizeHint != 0)
193    {
194        length = sizeHint;
195        content = new char[length];
196        inStream.read (content,length);
197    }
198    else 
199    {
200        int readBytes(0), newBytes(0);
201       
202        char buffer[10240];
203       
204        while (!inStream.eof()) {
205            inStream.read(buffer, 10240);
206            newBytes = inStream.gcount();
207            if (newBytes > 0) {
208                char* newcontent = new char[readBytes + newBytes];
209           
210                if (readBytes > 0)
211                    memcpy(newcontent, content, readBytes);
212               
213                memcpy(&newcontent[readBytes], &buffer, newBytes);
214                readBytes += newBytes;
215                if (content) delete[] content;
216                content = newcontent;
217            }
218        }
219        length = readBytes;
220    }
221   
222    osg::Image* img = doImport(reinterpret_cast<unsigned char*>(content), length, fileTypeHint);
223   
224    if (content) delete[] content;
225    return img;
226 }
227 
228 
229Handle getPtrDataRef(unsigned char *data, unsigned int size, const std::string &filename)
230{
231     // Load Data Reference
232     Handle dataRef;
233     Handle fileNameHandle;
234     PointerDataRefRecord ptrDataRefRec;
235     ComponentInstance dataRefHandler;
236     unsigned char pstr[255];
237 
238     ptrDataRefRec.data = data;
239     ptrDataRefRec.dataLength = size;
240 
241     /*err = */PtrToHand(&ptrDataRefRec, &dataRef, sizeof(PointerDataRefRecord));
242 
243     // Open a Data Handler for the Data Reference
244     /*err = */OpenADataHandler(dataRef, PointerDataHandlerSubType, NULL,
245         (OSType)0, NULL, kDataHCanRead, &dataRefHandler);
246 
247     // Convert From CString in filename to a PascalString in pstr
248     if (filename.length() > 255) {
249         //hmm...not good, pascal string limit is 255!
250         //do some error handling maybe?!
[8712]251         throw QTImportExportException(0, "filename length limit exceeded");
[8132]252     }
[8712]253     CopyCStringToPascal(filename.c_str(), pstr);
[8132]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
273osg::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;
[8712]285    unsigned char* imageData = 0;
[8132]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    }
[8712]362    catch (QTImportExportException& e)
[8132]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   
[8712]386    unsigned int bytesPerPixel = depth / 8;
[8132]387    unsigned int glpixelFormat;
[8712]388    switch(bytesPerPixel) {
[8132]389        case 3 :
390            glpixelFormat = GL_RGB;
391            break;
392        case 4 :
393            glpixelFormat = GL_RGBA;
394            break;
395        default :
[8712]396            delete[] imageData;
[8132]397            setError("unknown pixelformat");
398            return NULL;
399            break;
400    }
401   
[8712]402    unsigned char* swizzled = pepareBufferForOSG(imageData, bytesPerPixel, xsize, ysize);
[8132]403   
404    delete[] imageData;
405 
406    osg::Image* image = new osg::Image();
407    image->setFileName(fileTypeHint.c_str());
408    image->setImage(xsize,ysize,1,
[8712]409        bytesPerPixel,
[8132]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   
[8712]513    catch (QTImportExportException& e)
[8132]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}
Note: See TracBrowser for help on using the browser.