blob: 44a1b0e9e146cb27714fc6c582d6338d3cf84362 [file] [log] [blame]
/*
* Copyright (C) 2007, 2008, 2009, 2010 Apple, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "QTPixelBuffer.h"
#include <CFNumber.h>
#include <CFString.h>
#include <CGColorSpace.h>
#include <CGImage.h>
#include <CVPixelBuffer.h>
#include <QuickDraw.h>
#include <memory.h>
static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, CFStringRef inKey, SInt32 inValue)
{
CFNumberRef number;
number = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &inValue);
if (!number)
return coreFoundationUnknownErr;
CFDictionarySetValue(inDict, inKey, number);
CFRelease(number);
return noErr;
}
CFDictionaryRef QTPixelBuffer::createPixelBufferAttributesDictionary(QTPixelBuffer::Type contextType)
{
static const CFStringRef kDirect3DCompatibilityKey = CFSTR("Direct3DCompatibility");
CFMutableDictionaryRef pixelBufferAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (contextType == QTPixelBuffer::ConfigureForCAImageQueue) {
// Ask for D3D compatible pixel buffers so no further work is needed.
CFDictionarySetValue(pixelBufferAttributes, kDirect3DCompatibilityKey, kCFBooleanTrue);
} else {
// Use the k32BGRAPixelFormat, as QuartzCore will be able to use the pixels directly,
// without needing an additional copy or rendering pass.
SetNumberValue(pixelBufferAttributes, kCVPixelBufferPixelFormatTypeKey, k32BGRAPixelFormat);
// Set kCVPixelBufferBytesPerRowAlignmentKey to 16 to ensure that each row of pixels
// starts at a 16 byte aligned address for most efficient data reading.
SetNumberValue(pixelBufferAttributes, kCVPixelBufferBytesPerRowAlignmentKey, 16);
CFDictionarySetValue(pixelBufferAttributes, kCVPixelBufferCGImageCompatibilityKey, kCFBooleanTrue);
}
return pixelBufferAttributes;
}
QTPixelBuffer::QTPixelBuffer()
: m_pixelBuffer(0)
{
}
QTPixelBuffer::QTPixelBuffer(const QTPixelBuffer& p)
: m_pixelBuffer(p.m_pixelBuffer)
{
CVPixelBufferRetain(m_pixelBuffer);
}
QTPixelBuffer::QTPixelBuffer(CVPixelBufferRef ref)
: m_pixelBuffer(ref)
{
CVPixelBufferRetain(m_pixelBuffer);
}
QTPixelBuffer::~QTPixelBuffer()
{
clear();
}
QTPixelBuffer& QTPixelBuffer::operator=(const QTPixelBuffer& p)
{
set(p.m_pixelBuffer);
return *this;
}
void QTPixelBuffer::set(CVPixelBufferRef ref)
{
CVPixelBufferRetain(ref);
CVPixelBufferRelease(m_pixelBuffer);
m_pixelBuffer = ref;
}
CVPixelBufferRef QTPixelBuffer::pixelBufferRef()
{
return m_pixelBuffer;
}
void QTPixelBuffer::adopt(CVPixelBufferRef ref)
{
if (ref == m_pixelBuffer)
return;
CVPixelBufferRelease(m_pixelBuffer);
m_pixelBuffer = ref;
}
void QTPixelBuffer::clear()
{
CVPixelBufferRelease(m_pixelBuffer);
m_pixelBuffer = 0;
}
CVReturn QTPixelBuffer::lockBaseAddress()
{
return CVPixelBufferLockBaseAddress(m_pixelBuffer, 0);
}
CVReturn QTPixelBuffer::unlockBaseAddress()
{
return CVPixelBufferUnlockBaseAddress(m_pixelBuffer, 0);
}
void* QTPixelBuffer::baseAddress()
{
return CVPixelBufferGetBaseAddress(m_pixelBuffer);
}
size_t QTPixelBuffer::width() const
{
return CVPixelBufferGetWidth(m_pixelBuffer);
}
size_t QTPixelBuffer::height() const
{
return CVPixelBufferGetHeight(m_pixelBuffer);
}
unsigned long QTPixelBuffer::pixelFormatType() const
{
return CVPixelBufferGetPixelFormatType(m_pixelBuffer);
}
bool QTPixelBuffer::pixelFormatIs32ARGB() const
{
return CVPixelBufferGetPixelFormatType(m_pixelBuffer) == k32ARGBPixelFormat;
}
bool QTPixelBuffer::pixelFormatIs32BGRA() const
{
return CVPixelBufferGetPixelFormatType(m_pixelBuffer) == k32BGRAPixelFormat;
}
size_t QTPixelBuffer::bytesPerRow() const
{
return CVPixelBufferGetBytesPerRow(m_pixelBuffer);
}
size_t QTPixelBuffer::dataSize() const
{
return CVPixelBufferGetDataSize(m_pixelBuffer);
}
bool QTPixelBuffer::isPlanar() const
{
return CVPixelBufferIsPlanar(m_pixelBuffer);
}
size_t QTPixelBuffer::planeCount() const
{
return CVPixelBufferGetPlaneCount(m_pixelBuffer);
}
size_t QTPixelBuffer::widthOfPlane(size_t plane) const
{
return CVPixelBufferGetWidthOfPlane(m_pixelBuffer, plane);
}
size_t QTPixelBuffer::heightOfPlane(size_t plane) const
{
return CVPixelBufferGetHeightOfPlane(m_pixelBuffer, plane);
}
void* QTPixelBuffer::baseAddressOfPlane(size_t plane) const
{
return CVPixelBufferGetBaseAddressOfPlane(m_pixelBuffer, plane);
}
size_t QTPixelBuffer::bytesPerRowOfPlane(size_t plane) const
{
return CVPixelBufferGetBytesPerRowOfPlane(m_pixelBuffer, plane);
}
void QTPixelBuffer::getExtendedPixels(size_t* left, size_t* right, size_t* top, size_t* bottom) const
{
return CVPixelBufferGetExtendedPixels(m_pixelBuffer, left, right, top, bottom);
}
CFDictionaryRef QTPixelBuffer::attachments() const
{
return CVBufferGetAttachments(m_pixelBuffer, kCVAttachmentMode_ShouldPropagate);
}
void QTPixelBuffer::retainCallback(void* refcon)
{
CVPixelBufferRetain(static_cast<CVPixelBufferRef>(refcon));
}
void QTPixelBuffer::releaseCallback(void* refcon)
{
CVPixelBufferRelease(static_cast<CVPixelBufferRef>(refcon));
}
void QTPixelBuffer::imageQueueReleaseCallback(unsigned int type, uint64_t id, void* refcon)
{
CVPixelBufferRelease(static_cast<CVPixelBufferRef>(refcon));
}
void QTPixelBuffer::dataProviderReleaseBytePointerCallback(void* refcon, const void* pointer)
{
CVPixelBufferUnlockBaseAddress(static_cast<CVPixelBufferRef>(refcon), 0);
}
const void* QTPixelBuffer::dataProviderGetBytePointerCallback(void* refcon)
{
CVPixelBufferLockBaseAddress(static_cast<CVPixelBufferRef>(refcon), 0);
return CVPixelBufferGetBaseAddress(static_cast<CVPixelBufferRef>(refcon));
}
size_t QTPixelBuffer::dataProviderGetBytesAtPositionCallback(void* refcon, void* buffer, size_t position, size_t count)
{
char* data = (char*)CVPixelBufferGetBaseAddress(static_cast<CVPixelBufferRef>(refcon));
size_t size = CVPixelBufferGetDataSize(static_cast<CVPixelBufferRef>(refcon));
if (size - position < count)
count = size - position;
memcpy(buffer, data+position, count);
return count;
}
void QTPixelBuffer::dataProviderReleaseInfoCallback(void* refcon)
{
CVPixelBufferRelease(static_cast<CVPixelBufferRef>(refcon));
}