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 36struct QTCVTimeStamp { 37 CVTimeStamp t; 38}; 39 40class QTMovieVisualContextPriv { 41public: 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 56private: 57 QTMovieVisualContext* m_parent; 58 QTMovieVisualContextClient* m_client; 59 QTVisualContextRef m_visualContext; 60 RefPtr<QTMovie> m_movie; 61 62}; 63 64static 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 73static 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 85QTMovieVisualContextPriv::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 106QTMovieVisualContextPriv::~QTMovieVisualContextPriv() 107{ 108 if (m_visualContext) 109 QTVisualContextSetImageAvailableCallback(m_visualContext, 0, 0); 110} 111 112bool 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 120QTPixelBuffer 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 132void QTMovieVisualContextPriv::task() 133{ 134 if (m_visualContext) 135 QTVisualContextTask(m_visualContext); 136} 137 138QTVisualContextRef QTMovieVisualContextPriv::visualContextRef() 139{ 140 return m_visualContext; 141} 142 143void 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 159QTMovie* QTMovieVisualContextPriv::movie() const 160{ 161 return m_movie.get(); 162} 163 164void 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 176PassRefPtr<QTMovieVisualContext> QTMovieVisualContext::create(QTMovieVisualContextClient* client, QTPixelBuffer::Type contextType) 177{ 178 return adoptRef(new QTMovieVisualContext(client, contextType)); 179} 180 181QTMovieVisualContext::QTMovieVisualContext(QTMovieVisualContextClient* client, QTPixelBuffer::Type contextType) 182 : m_private(new QTMovieVisualContextPriv(this, client, contextType)) 183{ 184} 185 186QTMovieVisualContext::~QTMovieVisualContext() 187{ 188} 189 190bool QTMovieVisualContext::isImageAvailableForTime(const QTCVTimeStamp* timeStamp) const 191{ 192 return m_private->isImageAvailableForTime(timeStamp); 193} 194 195QTPixelBuffer QTMovieVisualContext::imageForTime(const QTCVTimeStamp* timeStamp) 196{ 197 return m_private->imageForTime(timeStamp); 198} 199 200void QTMovieVisualContext::task() 201{ 202 m_private->task(); 203} 204 205QTVisualContextRef QTMovieVisualContext::visualContextRef() 206{ 207 return m_private->visualContextRef(); 208} 209 210void QTMovieVisualContext::setMovie(PassRefPtr<QTMovie> movie) 211{ 212 m_private->setMovie(movie); 213} 214 215QTMovie* QTMovieVisualContext::movie() const 216{ 217 return m_private->movie(); 218} 219 220double QTMovieVisualContext::currentHostTime() 221{ 222 return CVGetCurrentHostTime() / CVGetHostClockFrequency(); 223} 224