QTDecompressionSession.cpp [plain text]
#include "config.h"
#include "QTDecompressionSession.h"
#include <ImageCompression.h>
#include <algorithm>
class QTDecompressionSessionClient {
public:
static void trackingCallback(void *decompressionTrackingRefCon, OSStatus,
ICMDecompressionTrackingFlags decompressionTrackingFlags, CVPixelBufferRef pixelBuffer,
TimeValue64, TimeValue64, ICMValidTimeFlags, void *, void *)
{
QTDecompressionSession* session = static_cast<QTDecompressionSession*>(decompressionTrackingRefCon);
ASSERT(session);
if (decompressionTrackingFlags & kICMDecompressionTracking_FrameDecoded)
session->m_latestFrame = QTPixelBuffer(pixelBuffer);
}
};
PassOwnPtr<QTDecompressionSession> QTDecompressionSession::create(unsigned long pixelFormat, size_t width, size_t height)
{
return adoptPtr(new QTDecompressionSession(pixelFormat, width, height));
}
QTDecompressionSession::QTDecompressionSession(unsigned long pixelFormat, size_t width, size_t height)
: m_session(0)
, m_pixelFormat(pixelFormat)
, m_width(width)
, m_height(height)
{
initializeSession();
}
QTDecompressionSession::~QTDecompressionSession()
{
if (m_session)
ICMDecompressionSessionRelease(m_session);
}
void QTDecompressionSession::initializeSession()
{
if (m_session)
return;
ICMPixelFormatInfo pixelFormatInfo = {sizeof(ICMPixelFormatInfo), 0};
if (ICMGetPixelFormatInfo(m_pixelFormat, &pixelFormatInfo) != noErr) {
return;
}
bool isIndexed = pixelFormatInfo.formatFlags & kICMPixelFormatIsIndexed;
bool isQD = pixelFormatInfo.formatFlags & kICMPixelFormatIsSupportedByQD;
bool isMonochrome = pixelFormatInfo.formatFlags & kICMPixelFormatIsMonochrome;
bool hasAlpha = pixelFormatInfo.formatFlags & kICMPixelFormatHasAlphaChannel;
unsigned int depth = 24; if (hasAlpha)
depth = 32; else if (isMonochrome) {
depth = 32 + std::min<unsigned int>(8, pixelFormatInfo.bitsPerPixel[0]);
} else if (isIndexed) {
depth = pixelFormatInfo.bitsPerPixel[0];
}
unsigned long cType = isQD ? kRawCodecType : m_pixelFormat;
ImageDescriptionHandle description = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
(**description).idSize = sizeof(ImageDescription);
(**description).cType = cType;
(**description).version = 2;
(**description).spatialQuality = codecLosslessQuality;
(**description).width = m_width;
(**description).height = m_height;
(**description).hRes = 72 << 16; (**description).vRes = 72 << 16; (**description).frameCount = 1;
(**description).depth = depth;
(**description).clutID = -1;
ICMDecompressionSessionOptionsRef options = 0;
ICMDecompressionSessionOptionsCreate(kCFAllocatorDefault, &options);
CFDictionaryRef pixelBufferAttributes = QTPixelBuffer::createPixelBufferAttributesDictionary(QTPixelBuffer::ConfigureForCGImage);
ICMDecompressionTrackingCallbackRecord callback = {
QTDecompressionSessionClient::trackingCallback,
this,
};
ICMDecompressionSessionCreate(kCFAllocatorDefault,
description,
options,
pixelBufferAttributes,
&callback,
&m_session);
if (pixelBufferAttributes)
CFRelease(pixelBufferAttributes);
ICMDecompressionSessionOptionsRelease(options);
DisposeHandle((Handle)description);
}
bool QTDecompressionSession::canDecompress(QTPixelBuffer inBuffer)
{
return m_session
&& inBuffer.pixelFormatType() == m_pixelFormat
&& inBuffer.width() == m_width
&& inBuffer.height() == m_height;
}
QTPixelBuffer QTDecompressionSession::decompress(QTPixelBuffer inBuffer)
{
if (!canDecompress(inBuffer))
return QTPixelBuffer();
inBuffer.lockBaseAddress();
ICMDecompressionSessionDecodeFrame(m_session,
static_cast<UInt8*>(inBuffer.baseAddress()),
inBuffer.dataSize(),
0, 0, 0);
return m_latestFrame;
}