1/*
2 * Copyright (C) 2007, 2008, 2009, 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 "QTPixelBuffer.h"
28
29#include <CFNumber.h>
30#include <CFString.h>
31#include <CGColorSpace.h>
32#include <CGImage.h>
33#include <CVPixelBuffer.h>
34#include <QuickDraw.h>
35#include <memory.h>
36
37static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, CFStringRef inKey, SInt32 inValue)
38{
39    CFNumberRef number;
40
41    number = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &inValue);
42    if (!number)
43        return coreFoundationUnknownErr;
44
45    CFDictionarySetValue(inDict, inKey, number);
46    CFRelease(number);
47
48    return noErr;
49}
50
51CFDictionaryRef QTPixelBuffer::createPixelBufferAttributesDictionary(QTPixelBuffer::Type contextType)
52{
53    static const CFStringRef kDirect3DCompatibilityKey = CFSTR("Direct3DCompatibility");
54
55    CFMutableDictionaryRef pixelBufferAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
56    if (contextType == QTPixelBuffer::ConfigureForCAImageQueue) {
57        // Ask for D3D compatible pixel buffers so no further work is needed.
58        CFDictionarySetValue(pixelBufferAttributes, kDirect3DCompatibilityKey, kCFBooleanTrue);
59    } else {
60        // Use the k32BGRAPixelFormat, as QuartzCore will be able to use the pixels directly,
61        // without needing an additional copy or rendering pass.
62        SetNumberValue(pixelBufferAttributes, kCVPixelBufferPixelFormatTypeKey, k32BGRAPixelFormat);
63
64        // Set kCVPixelBufferBytesPerRowAlignmentKey to 16 to ensure that each row of pixels
65        // starts at a 16 byte aligned address for most efficient data reading.
66        SetNumberValue(pixelBufferAttributes, kCVPixelBufferBytesPerRowAlignmentKey, 16);
67        CFDictionarySetValue(pixelBufferAttributes, kCVPixelBufferCGImageCompatibilityKey, kCFBooleanTrue);
68    }
69    return pixelBufferAttributes;
70}
71
72QTPixelBuffer::QTPixelBuffer()
73    : m_pixelBuffer(0)
74{
75}
76
77QTPixelBuffer::QTPixelBuffer(const QTPixelBuffer& p)
78    : m_pixelBuffer(p.m_pixelBuffer)
79{
80    CVPixelBufferRetain(m_pixelBuffer);
81}
82
83QTPixelBuffer::QTPixelBuffer(CVPixelBufferRef ref)
84    : m_pixelBuffer(ref)
85{
86    CVPixelBufferRetain(m_pixelBuffer);
87}
88
89QTPixelBuffer::~QTPixelBuffer()
90{
91    clear();
92}
93
94QTPixelBuffer& QTPixelBuffer::operator=(const QTPixelBuffer& p)
95{
96    set(p.m_pixelBuffer);
97    return *this;
98}
99
100void QTPixelBuffer::set(CVPixelBufferRef ref)
101{
102    CVPixelBufferRetain(ref);
103    CVPixelBufferRelease(m_pixelBuffer);
104    m_pixelBuffer = ref;
105}
106
107CVPixelBufferRef QTPixelBuffer::pixelBufferRef()
108{
109    return m_pixelBuffer;
110}
111
112void QTPixelBuffer::adopt(CVPixelBufferRef ref)
113{
114    if (ref == m_pixelBuffer)
115        return;
116    CVPixelBufferRelease(m_pixelBuffer);
117    m_pixelBuffer = ref;
118}
119
120void QTPixelBuffer::clear()
121{
122    CVPixelBufferRelease(m_pixelBuffer);
123    m_pixelBuffer = 0;
124}
125
126CVReturn QTPixelBuffer::lockBaseAddress()
127{
128    return CVPixelBufferLockBaseAddress(m_pixelBuffer, 0);
129}
130
131CVReturn QTPixelBuffer::unlockBaseAddress()
132{
133    return CVPixelBufferUnlockBaseAddress(m_pixelBuffer, 0);
134}
135
136void* QTPixelBuffer::baseAddress()
137{
138    return CVPixelBufferGetBaseAddress(m_pixelBuffer);
139}
140
141size_t QTPixelBuffer::width() const
142{
143    return CVPixelBufferGetWidth(m_pixelBuffer);
144}
145
146size_t QTPixelBuffer::height() const
147{
148    return CVPixelBufferGetHeight(m_pixelBuffer);
149}
150
151unsigned long QTPixelBuffer::pixelFormatType() const
152{
153    return CVPixelBufferGetPixelFormatType(m_pixelBuffer);
154}
155
156bool QTPixelBuffer::pixelFormatIs32ARGB() const
157{
158    return CVPixelBufferGetPixelFormatType(m_pixelBuffer) == k32ARGBPixelFormat;
159}
160
161bool QTPixelBuffer::pixelFormatIs32BGRA() const
162{
163    return CVPixelBufferGetPixelFormatType(m_pixelBuffer) == k32BGRAPixelFormat;
164}
165
166size_t QTPixelBuffer::bytesPerRow() const
167{
168    return CVPixelBufferGetBytesPerRow(m_pixelBuffer);
169}
170
171size_t QTPixelBuffer::dataSize() const
172{
173    return CVPixelBufferGetDataSize(m_pixelBuffer);
174}
175
176bool QTPixelBuffer::isPlanar() const
177{
178    return CVPixelBufferIsPlanar(m_pixelBuffer);
179}
180
181size_t QTPixelBuffer::planeCount() const
182{
183    return CVPixelBufferGetPlaneCount(m_pixelBuffer);
184}
185
186size_t QTPixelBuffer::widthOfPlane(size_t plane) const
187{
188    return CVPixelBufferGetWidthOfPlane(m_pixelBuffer, plane);
189}
190
191size_t QTPixelBuffer::heightOfPlane(size_t plane) const
192{
193    return CVPixelBufferGetHeightOfPlane(m_pixelBuffer, plane);
194}
195
196void* QTPixelBuffer::baseAddressOfPlane(size_t plane) const
197{
198    return CVPixelBufferGetBaseAddressOfPlane(m_pixelBuffer, plane);
199}
200
201size_t QTPixelBuffer::bytesPerRowOfPlane(size_t plane) const
202{
203    return CVPixelBufferGetBytesPerRowOfPlane(m_pixelBuffer, plane);
204}
205
206void QTPixelBuffer::getExtendedPixels(size_t* left, size_t* right, size_t* top, size_t* bottom) const
207{
208    return CVPixelBufferGetExtendedPixels(m_pixelBuffer, left, right, top, bottom);
209}
210
211CFDictionaryRef QTPixelBuffer::attachments() const
212{
213    return CVBufferGetAttachments(m_pixelBuffer, kCVAttachmentMode_ShouldPropagate);
214}
215
216void QTPixelBuffer::retainCallback(void* refcon)
217{
218    CVPixelBufferRetain(static_cast<CVPixelBufferRef>(refcon));
219}
220
221void QTPixelBuffer::releaseCallback(void* refcon)
222{
223    CVPixelBufferRelease(static_cast<CVPixelBufferRef>(refcon));
224}
225
226void QTPixelBuffer::imageQueueReleaseCallback(unsigned int type, uint64_t id, void* refcon)
227{
228    CVPixelBufferRelease(static_cast<CVPixelBufferRef>(refcon));
229}
230
231void QTPixelBuffer::dataProviderReleaseBytePointerCallback(void* refcon, const void* pointer)
232{
233    CVPixelBufferUnlockBaseAddress(static_cast<CVPixelBufferRef>(refcon), 0);
234}
235
236const void* QTPixelBuffer::dataProviderGetBytePointerCallback(void* refcon)
237{
238    CVPixelBufferLockBaseAddress(static_cast<CVPixelBufferRef>(refcon), 0);
239    return CVPixelBufferGetBaseAddress(static_cast<CVPixelBufferRef>(refcon));
240}
241
242size_t QTPixelBuffer::dataProviderGetBytesAtPositionCallback(void* refcon, void* buffer, size_t position, size_t count)
243{
244    char* data = (char*)CVPixelBufferGetBaseAddress(static_cast<CVPixelBufferRef>(refcon));
245    size_t size = CVPixelBufferGetDataSize(static_cast<CVPixelBufferRef>(refcon));
246    if (size - position < count)
247        count = size - position;
248
249    memcpy(buffer, data+position, count);
250    return count;
251}
252
253void QTPixelBuffer::dataProviderReleaseInfoCallback(void* refcon)
254{
255    CVPixelBufferRelease(static_cast<CVPixelBufferRef>(refcon));
256}
257