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 "QTMovieVisualContext.h"
28
29 #include "QTMovieTask.h"
30 #include <CVBase.h>
31 #include <CVHostTime.h>
32 #include <ImageCompression.h>
33 #include <Movies.h>
34 #include <windows.h>
35
36 struct QTCVTimeStamp {
37 CVTimeStamp t;
38 };
39
40 class QTMovieVisualContextPriv {
41 public:
42 QTMovieVisualContextPriv(QTMovieVisualContext* parent, QTMovieVisualContextClient* client, QTPixelBuffer::Type contextType);
43 ~QTMovieVisualContextPriv();
44
45 bool isImageAvailableForTime(const QTCVTimeStamp*) const;
46 QTPixelBuffer imageForTime(const QTCVTimeStamp*);
47 void task();
48
49 QTVisualContextRef visualContextRef();
50
51 void setMovie(PassRefPtr<QTMovie>);
52 QTMovie* movie() const;
53
54 static void imageAvailableCallback(QTVisualContextRef visualContext, const CVTimeStamp *timeStamp, void *refCon);
55
56 private:
57 QTMovieVisualContext* m_parent;
58 QTMovieVisualContextClient* m_client;
59 QTVisualContextRef m_visualContext;
60 RefPtr<QTMovie> m_movie;
61
62 };
63
createPixelBufferOptionsDictionary(QTPixelBuffer::Type contextType)64 static CFDictionaryRef createPixelBufferOptionsDictionary(QTPixelBuffer::Type contextType)
65 {
66 const void* key = kQTVisualContextPixelBufferAttributesKey;
67 const void* value = QTPixelBuffer::createPixelBufferAttributesDictionary(contextType);
68 CFDictionaryRef pixelBufferOptions = CFDictionaryCreate(kCFAllocatorDefault, &key, &value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
69 CFRelease(value);
70 return pixelBufferOptions;
71 }
72
pixelBufferCreationOptions(QTPixelBuffer::Type contextType)73 static CFDictionaryRef pixelBufferCreationOptions(QTPixelBuffer::Type contextType)
74 {
75 if (contextType == QTPixelBuffer::ConfigureForCAImageQueue) {
76 static CFDictionaryRef imageQueueOptions = createPixelBufferOptionsDictionary(contextType);
77 return imageQueueOptions;
78 }
79
80 ASSERT(contextType == QTPixelBuffer::ConfigureForCGImage);
81 static CFDictionaryRef cgImageOptions = createPixelBufferOptionsDictionary(contextType);
82 return cgImageOptions;
83 }
84
QTMovieVisualContextPriv(QTMovieVisualContext * parent,QTMovieVisualContextClient * client,QTPixelBuffer::Type contextType)85 QTMovieVisualContextPriv::QTMovieVisualContextPriv(QTMovieVisualContext* parent, QTMovieVisualContextClient* client, QTPixelBuffer::Type contextType)
86 : m_parent(parent)
87 , m_client(client)
88 , m_visualContext(0)
89 {
90 typedef OSStatus ( __cdecl *pfnQTPixelBufferContextCreate)(CFAllocatorRef, CFDictionaryRef, QTVisualContextRef*);
91 static pfnQTPixelBufferContextCreate pPixelBufferContextCreate = 0;
92 if (!pPixelBufferContextCreate) {
93 HMODULE qtmlDLL = ::LoadLibraryW(L"QTMLClient.dll");
94 if (!qtmlDLL)
95 return;
96 pPixelBufferContextCreate = reinterpret_cast<pfnQTPixelBufferContextCreate>(GetProcAddress(qtmlDLL, "QTPixelBufferContextCreate"));
97 if (!pPixelBufferContextCreate)
98 return;
99 }
100
101 OSStatus status = pPixelBufferContextCreate(kCFAllocatorDefault, pixelBufferCreationOptions(contextType), &m_visualContext);
102 if (status == noErr && m_visualContext)
103 QTVisualContextSetImageAvailableCallback(m_visualContext, &QTMovieVisualContextPriv::imageAvailableCallback, static_cast<void*>(this));
104 }
105
~QTMovieVisualContextPriv()106 QTMovieVisualContextPriv::~QTMovieVisualContextPriv()
107 {
108 if (m_visualContext)
109 QTVisualContextSetImageAvailableCallback(m_visualContext, 0, 0);
110 }
111
isImageAvailableForTime(const QTCVTimeStamp * timeStamp) const112 bool QTMovieVisualContextPriv::isImageAvailableForTime(const QTCVTimeStamp* timeStamp) const
113 {
114 if (!m_visualContext)
115 return false;
116
117 return QTVisualContextIsNewImageAvailable(m_visualContext, reinterpret_cast<const CVTimeStamp*>(timeStamp));
118 }
119
imageForTime(const QTCVTimeStamp * timeStamp)120 QTPixelBuffer QTMovieVisualContextPriv::imageForTime(const QTCVTimeStamp* timeStamp)
121 {
122 QTPixelBuffer pixelBuffer;
123 if (m_visualContext) {
124 CVImageBufferRef newImage = 0;
125 OSStatus status = QTVisualContextCopyImageForTime(m_visualContext, kCFAllocatorDefault, reinterpret_cast<const CVTimeStamp*>(timeStamp), &newImage);
126 if (status == noErr)
127 pixelBuffer.adopt(newImage);
128 }
129 return pixelBuffer;
130 }
131
task()132 void QTMovieVisualContextPriv::task()
133 {
134 if (m_visualContext)
135 QTVisualContextTask(m_visualContext);
136 }
137
visualContextRef()138 QTVisualContextRef QTMovieVisualContextPriv::visualContextRef()
139 {
140 return m_visualContext;
141 }
142
setMovie(PassRefPtr<QTMovie> movie)143 void QTMovieVisualContextPriv::setMovie(PassRefPtr<QTMovie> movie)
144 {
145 if (movie == m_movie)
146 return;
147
148 if (m_movie) {
149 SetMovieVisualContext(m_movie->getMovieHandle(), 0);
150 m_movie = 0;
151 }
152
153 if (movie)
154 OSStatus status = SetMovieVisualContext(movie->getMovieHandle(), m_visualContext);
155
156 m_movie = movie;
157 }
158
movie() const159 QTMovie* QTMovieVisualContextPriv::movie() const
160 {
161 return m_movie.get();
162 }
163
imageAvailableCallback(QTVisualContextRef visualContext,const CVTimeStamp * timeStamp,void * refCon)164 void QTMovieVisualContextPriv::imageAvailableCallback(QTVisualContextRef visualContext, const CVTimeStamp *timeStamp, void *refCon)
165 {
166 if (!refCon)
167 return;
168
169 QTMovieVisualContextPriv* vc = static_cast<QTMovieVisualContextPriv*>(refCon);
170 if (!vc->m_client)
171 return;
172
173 vc->m_client->imageAvailableForTime(reinterpret_cast<const QTCVTimeStamp*>(timeStamp));
174 }
175
create(QTMovieVisualContextClient * client,QTPixelBuffer::Type contextType)176 PassRefPtr<QTMovieVisualContext> QTMovieVisualContext::create(QTMovieVisualContextClient* client, QTPixelBuffer::Type contextType)
177 {
178 return adoptRef(new QTMovieVisualContext(client, contextType));
179 }
180
QTMovieVisualContext(QTMovieVisualContextClient * client,QTPixelBuffer::Type contextType)181 QTMovieVisualContext::QTMovieVisualContext(QTMovieVisualContextClient* client, QTPixelBuffer::Type contextType)
182 : m_private(new QTMovieVisualContextPriv(this, client, contextType))
183 {
184 }
185
~QTMovieVisualContext()186 QTMovieVisualContext::~QTMovieVisualContext()
187 {
188 }
189
isImageAvailableForTime(const QTCVTimeStamp * timeStamp) const190 bool QTMovieVisualContext::isImageAvailableForTime(const QTCVTimeStamp* timeStamp) const
191 {
192 return m_private->isImageAvailableForTime(timeStamp);
193 }
194
imageForTime(const QTCVTimeStamp * timeStamp)195 QTPixelBuffer QTMovieVisualContext::imageForTime(const QTCVTimeStamp* timeStamp)
196 {
197 return m_private->imageForTime(timeStamp);
198 }
199
task()200 void QTMovieVisualContext::task()
201 {
202 m_private->task();
203 }
204
visualContextRef()205 QTVisualContextRef QTMovieVisualContext::visualContextRef()
206 {
207 return m_private->visualContextRef();
208 }
209
setMovie(PassRefPtr<QTMovie> movie)210 void QTMovieVisualContext::setMovie(PassRefPtr<QTMovie> movie)
211 {
212 m_private->setMovie(movie);
213 }
214
movie() const215 QTMovie* QTMovieVisualContext::movie() const
216 {
217 return m_private->movie();
218 }
219
currentHostTime()220 double QTMovieVisualContext::currentHostTime()
221 {
222 return CVGetCurrentHostTime() / CVGetHostClockFrequency();
223 }
224