Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright (C) 2010 Apple, Inc.  All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 #include "config.h"
     26 
     27 #include "QTDecompressionSession.h"
     28 
     29 #include <ImageCompression.h>
     30 #include <algorithm>
     31 
     32 class QTDecompressionSessionClient {
     33 public:
     34     static void trackingCallback(void *decompressionTrackingRefCon, OSStatus,
     35         ICMDecompressionTrackingFlags decompressionTrackingFlags, CVPixelBufferRef pixelBuffer,
     36         TimeValue64, TimeValue64, ICMValidTimeFlags, void *, void *)
     37     {
     38         QTDecompressionSession* session = static_cast<QTDecompressionSession*>(decompressionTrackingRefCon);
     39         ASSERT(session);
     40 
     41         if (decompressionTrackingFlags & kICMDecompressionTracking_FrameDecoded)
     42             session->m_latestFrame = QTPixelBuffer(pixelBuffer);
     43     }
     44 };
     45 
     46 PassOwnPtr<QTDecompressionSession> QTDecompressionSession::create(unsigned long pixelFormat, size_t width, size_t height)
     47 {
     48     return adoptPtr(new QTDecompressionSession(pixelFormat, width, height));
     49 }
     50 
     51 QTDecompressionSession::QTDecompressionSession(unsigned long pixelFormat, size_t width, size_t height)
     52     : m_session(0)
     53     , m_pixelFormat(pixelFormat)
     54     , m_width(width)
     55     , m_height(height)
     56 {
     57     initializeSession();
     58 }
     59 
     60 QTDecompressionSession::~QTDecompressionSession()
     61 {
     62     if (m_session)
     63         ICMDecompressionSessionRelease(m_session);
     64 }
     65 
     66 void QTDecompressionSession::initializeSession()
     67 {
     68     if (m_session)
     69         return;
     70 
     71     ICMPixelFormatInfo pixelFormatInfo = {sizeof(ICMPixelFormatInfo), 0};
     72     if (ICMGetPixelFormatInfo(m_pixelFormat, &pixelFormatInfo) != noErr) {
     73         // The ICM does not know anything about the pixelFormat contained in
     74         // the pixel buffer, so it won't be able to convert it to RGBA.
     75         return;
     76     }
     77 
     78     // The depth and cType fields of the ImageDescriptionHandle are filled
     79     // out according to the instructions in Technical Q&A QA1183:
     80     // http://developer.apple.com/library/mac/#qa/qa2001/qa1183.html
     81     bool isIndexed = pixelFormatInfo.formatFlags & kICMPixelFormatIsIndexed;
     82     bool isQD = pixelFormatInfo.formatFlags & kICMPixelFormatIsSupportedByQD;
     83     bool isMonochrome = pixelFormatInfo.formatFlags & kICMPixelFormatIsMonochrome;
     84     bool hasAlpha = pixelFormatInfo.formatFlags & kICMPixelFormatHasAlphaChannel;
     85 
     86     unsigned int depth = 24; // The default depth is 24.
     87     if (hasAlpha)
     88         depth = 32; // Any pixel format with alpha gets a depth of 32.
     89     else if (isMonochrome) {
     90         // Grayscale pixel formats get depths 33 through 40, depending
     91         // on their bits per pixel. Yes, this means that 16-bit grayscale
     92         // and 8-bit grayscale have the same pixel depth.
     93         depth = 32 + std::min<unsigned int>(8, pixelFormatInfo.bitsPerPixel[0]);
     94     } else if (isIndexed) {
     95         // Indexed pixel formats get a depth of 1 through 8, depending on
     96         // the their bits per pixel.
     97         depth = pixelFormatInfo.bitsPerPixel[0];
     98     }
     99 
    100     // If QuickDraw supports the given pixel format, the cType should be kRawCodecType.
    101     // Otherwise, use the pixel format code for the cType.  We are assuming the pixel
    102     // buffer is uncompressed.
    103     unsigned long cType = isQD ? kRawCodecType : m_pixelFormat;
    104 
    105     ImageDescriptionHandle description = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
    106     (**description).idSize = sizeof(ImageDescription);
    107     (**description).cType = cType;
    108     (**description).version = 2;
    109     (**description).spatialQuality = codecLosslessQuality;
    110     (**description).width = m_width;
    111     (**description).height = m_height;
    112     (**description).hRes = 72 << 16; // 72 DPI as a fixed-point number
    113     (**description).vRes = 72 << 16; // 72 DPI as a fixed-point number
    114     (**description).frameCount = 1;
    115     (**description).depth =  depth;
    116     (**description).clutID = -1;
    117 
    118     // Create the mandatory ICMDecompressionSessionOptions, but leave
    119     // all the default values.
    120     ICMDecompressionSessionOptionsRef options = 0;
    121     ICMDecompressionSessionOptionsCreate(kCFAllocatorDefault, &options);
    122 
    123     CFDictionaryRef pixelBufferAttributes = QTPixelBuffer::createPixelBufferAttributesDictionary(QTPixelBuffer::ConfigureForCGImage);
    124 
    125     ICMDecompressionTrackingCallbackRecord callback = {
    126         QTDecompressionSessionClient::trackingCallback,
    127         this,
    128     };
    129 
    130     ICMDecompressionSessionCreate(kCFAllocatorDefault,
    131         description,
    132         options,
    133         pixelBufferAttributes,
    134         &callback,
    135         &m_session);
    136 
    137     if (pixelBufferAttributes)
    138         CFRelease(pixelBufferAttributes);
    139 
    140     ICMDecompressionSessionOptionsRelease(options);
    141     DisposeHandle((Handle)description);
    142 }
    143 
    144 bool QTDecompressionSession::canDecompress(QTPixelBuffer inBuffer)
    145 {
    146     return m_session
    147         && inBuffer.pixelFormatType() == m_pixelFormat
    148         && inBuffer.width() == m_width
    149         && inBuffer.height() == m_height;
    150 }
    151 
    152 QTPixelBuffer QTDecompressionSession::decompress(QTPixelBuffer inBuffer)
    153 {
    154     if (!canDecompress(inBuffer))
    155         return QTPixelBuffer();
    156 
    157     inBuffer.lockBaseAddress();
    158     ICMDecompressionSessionDecodeFrame(m_session,
    159         static_cast<UInt8*>(inBuffer.baseAddress()),
    160         inBuffer.dataSize(),
    161         0, // frameOptions
    162         0, // frameTime
    163         0); // sourceFrameRefCon
    164 
    165     // Because we passed in 0 for frameTime, the above function
    166     // is synchronous, and the client callback will have been
    167     // called before the function returns, and m_latestFrame
    168     // will contain the newly decompressed frame.
    169     return m_latestFrame;
    170 }
    171