2 * Copyright (C) 2007, 2008, 2009, 2010, 2011 Apple, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #include "QTMovieTask.h"
30 #include "QTMovieWinTimer.h"
35 #include <QuickTimeComponents.h>
36 #include <WebKitSystemInterface/WebKitSystemInterface.h>
37 #include <wtf/Assertions.h>
38 #include <wtf/MathExtras.h>
39 #include <wtf/Noncopyable.h>
40 #include <wtf/Vector.h>
44 static const long minimumQuickTimeVersion = 0x07300000; // 7.3
46 static const long closedCaptionTrackType = 'clcp';
47 static const long subTitleTrackType = 'sbtl';
48 static const long mpeg4ObjectDescriptionTrackType = 'odsm';
49 static const long mpeg4SceneDescriptionTrackType = 'sdsm';
50 static const long closedCaptionDisplayPropertyID = 'disp';
52 // Resizing GWorlds is slow, give them a minimum size so size of small
53 // videos can be animated smoothly
54 static const int cGWorldMinWidth = 640;
55 static const int cGWorldMinHeight = 360;
57 static const float cNonContinuousTimeChange = 0.2f;
64 static CFMutableArrayRef gSupportedTypes = 0;
65 static SInt32 quickTimeVersion = 0;
67 class QTMoviePrivate : public QTMovieTaskClient {
68 WTF_MAKE_NONCOPYABLE(QTMoviePrivate);
76 void createMovieController();
77 void cacheMovieScale();
81 MovieController m_movieController;
84 Vector<QTMovieClient*> m_clients;
88 float m_lastMediaTime;
89 double m_lastLoadStateCheckTime;
94 float m_widthScaleFactor;
95 float m_heightScaleFactor;
96 CFURLRef m_currentURL;
97 float m_timeToRestore;
98 float m_rateToRestore;
99 bool m_privateBrowsing;
105 QTMoviePrivate::QTMoviePrivate()
108 , m_movieController(0)
114 , m_lastLoadStateCheckTime(0)
119 , m_widthScaleFactor(1)
120 , m_heightScaleFactor(1)
122 , m_timeToRestore(-1.0f)
123 , m_rateToRestore(-1.0f)
125 , m_privateBrowsing(false)
127 , m_scaleCached(false)
132 QTMoviePrivate::~QTMoviePrivate()
135 if (m_movieController)
136 DisposeMovieController(m_movieController);
138 DisposeMovie(m_movie);
140 CFRelease(m_currentURL);
143 void QTMoviePrivate::startTask()
146 QTMovieTask::sharedTask()->addTaskClient(this);
149 QTMovieTask::sharedTask()->updateTaskTimer();
152 void QTMoviePrivate::endTask()
155 QTMovieTask::sharedTask()->removeTaskClient(this);
158 QTMovieTask::sharedTask()->updateTaskTimer();
161 void QTMoviePrivate::task()
166 if (m_movieController)
167 MCIdle(m_movieController);
169 MoviesTask(m_movie, 0);
172 // GetMovieLoadState documentation says that you should not call it more often than every quarter of a second.
173 if (systemTime() >= m_lastLoadStateCheckTime + 0.25 || m_loadError) {
174 // If load fails QT's load state is QTMovieLoadStateComplete.
175 // This is different from QTKit API and seems strange.
176 long loadState = m_loadError ? QTMovieLoadStateError : GetMovieLoadState(m_movie);
177 if (loadState != m_loadState) {
178 // we only need to erase the movie gworld when the load state changes to loaded while it
179 // is visible as the gworld is destroyed/created when visibility changes
180 bool shouldRestorePlaybackState = false;
181 bool movieNewlyPlayable = loadState >= QTMovieLoadStateLoaded && m_loadState < QTMovieLoadStateLoaded;
182 m_loadState = loadState;
183 if (movieNewlyPlayable) {
185 shouldRestorePlaybackState = true;
188 if (!m_movieController && m_loadState >= QTMovieLoadStateLoaded)
189 createMovieController();
191 for (size_t i = 0; i < m_clients.size(); ++i)
192 m_clients[i]->movieLoadStateChanged(m_movieWin);
194 if (shouldRestorePlaybackState && m_timeToRestore != -1.0f) {
195 m_movieWin->setCurrentTime(m_timeToRestore);
196 m_timeToRestore = -1.0f;
197 m_movieWin->setRate(m_rateToRestore);
198 m_rateToRestore = -1.0f;
206 m_lastLoadStateCheckTime = systemTime();
209 bool ended = !!IsMovieDone(m_movie);
210 if (ended != m_ended) {
213 for (size_t i = 0; i < m_clients.size(); ++i)
214 m_clients[i]->movieEnded(m_movieWin);
218 float time = m_movieWin->currentTime();
219 if (time < m_lastMediaTime || time >= m_lastMediaTime + cNonContinuousTimeChange || m_seeking) {
221 for (size_t i = 0; i < m_clients.size(); ++i)
222 m_clients[i]->movieTimeChanged(m_movieWin);
224 m_lastMediaTime = time;
229 QTMovieTask::sharedTask()->updateTaskTimer();
232 void QTMoviePrivate::createMovieController()
240 if (m_movieController)
241 DisposeMovieController(m_movieController);
243 GetMovieBox(m_movie, &bounds);
244 flags = mcTopLeftMovie | mcNotVisible;
245 m_movieController = NewMovieController(m_movie, &bounds, flags);
246 if (!m_movieController)
249 // Disable automatic looping.
250 MCDoAction(m_movieController, mcActionSetLooping, 0);
253 void QTMoviePrivate::cacheMovieScale()
258 GetMovieNaturalBoundsRect(m_movie, &naturalRect);
259 GetMovieBox(m_movie, &initialRect);
261 float naturalWidth = naturalRect.right - naturalRect.left;
262 float naturalHeight = naturalRect.bottom - naturalRect.top;
265 m_widthScaleFactor = (initialRect.right - initialRect.left) / naturalWidth;
267 m_heightScaleFactor = (initialRect.bottom - initialRect.top) / naturalHeight;
269 m_scaleCached = true;
273 QTMovie::QTMovie(QTMovieClient* client)
274 : m_private(new QTMoviePrivate())
276 m_private->m_movieWin = this;
278 m_private->m_clients.append(client);
279 initializeQuickTime();
287 void QTMovie::disableComponent(uint32_t cd[5])
289 ComponentDescription nullDesc = {'null', 'base', kAppleManufacturer, 0, 0};
290 Component nullComp = FindNextComponent(0, &nullDesc);
291 Component disabledComp = 0;
293 while (disabledComp = FindNextComponent(disabledComp, (ComponentDescription*)&cd[0]))
294 CaptureComponent(disabledComp, nullComp);
297 void QTMovie::addClient(QTMovieClient* client)
300 m_private->m_clients.append(client);
303 void QTMovie::removeClient(QTMovieClient* client)
305 size_t indexOfClient = m_private->m_clients.find(client);
306 if (indexOfClient != notFound)
307 m_private->m_clients.remove(indexOfClient);
312 m_private->m_timeToRestore = -1.0f;
314 if (m_private->m_movieController)
315 MCDoAction(m_private->m_movieController, mcActionPrerollAndPlay, (void *)GetMoviePreferredRate(m_private->m_movie));
317 StartMovie(m_private->m_movie);
318 m_private->startTask();
321 void QTMovie::pause()
323 m_private->m_timeToRestore = -1.0f;
325 if (m_private->m_movieController)
326 MCDoAction(m_private->m_movieController, mcActionPlay, 0);
328 StopMovie(m_private->m_movie);
329 QTMovieTask::sharedTask()->updateTaskTimer();
332 float QTMovie::rate() const
334 if (!m_private->m_movie)
336 return FixedToFloat(GetMovieRate(m_private->m_movie));
339 void QTMovie::setRate(float rate)
341 if (!m_private->m_movie)
343 m_private->m_timeToRestore = -1.0f;
345 if (m_private->m_movieController)
346 MCDoAction(m_private->m_movieController, mcActionPrerollAndPlay, (void *)FloatToFixed(rate));
348 SetMovieRate(m_private->m_movie, FloatToFixed(rate));
349 QTMovieTask::sharedTask()->updateTaskTimer();
352 float QTMovie::duration() const
354 if (!m_private->m_movie)
356 TimeValue val = GetMovieDuration(m_private->m_movie);
357 TimeScale scale = GetMovieTimeScale(m_private->m_movie);
358 return static_cast<float>(val) / scale;
361 float QTMovie::currentTime() const
363 if (!m_private->m_movie)
365 TimeValue val = GetMovieTime(m_private->m_movie, 0);
366 TimeScale scale = GetMovieTimeScale(m_private->m_movie);
367 return static_cast<float>(val) / scale;
370 void QTMovie::setCurrentTime(float time) const
372 if (!m_private->m_movie)
375 m_private->m_timeToRestore = -1.0f;
377 m_private->m_seeking = true;
378 TimeScale scale = GetMovieTimeScale(m_private->m_movie);
379 if (m_private->m_movieController) {
380 QTRestartAtTimeRecord restart = { lroundf(time * scale) , 0 };
381 MCDoAction(m_private->m_movieController, mcActionRestartAtTime, (void *)&restart);
383 SetMovieTimeValue(m_private->m_movie, TimeValue(lroundf(time * scale)));
384 QTMovieTask::sharedTask()->updateTaskTimer();
387 void QTMovie::setVolume(float volume)
389 if (!m_private->m_movie)
391 SetMovieVolume(m_private->m_movie, static_cast<short>(volume * 256));
394 void QTMovie::setPreservesPitch(bool preservesPitch)
396 if (!m_private->m_movie || !m_private->m_currentURL)
402 error = QTGetMovieProperty(m_private->m_movie, kQTPropertyClass_Audio, kQTAudioPropertyID_RateChangesPreservePitch,
403 sizeof(kQTAudioPropertyID_RateChangesPreservePitch), static_cast<QTPropertyValuePtr>(&prop), 0);
405 if (error || prop == preservesPitch)
408 m_private->m_timeToRestore = currentTime();
409 m_private->m_rateToRestore = rate();
410 load(m_private->m_currentURL, preservesPitch);
413 unsigned QTMovie::dataSize() const
415 if (!m_private->m_movie)
417 return GetMovieDataSize(m_private->m_movie, 0, GetMovieDuration(m_private->m_movie));
420 float QTMovie::maxTimeLoaded() const
422 if (!m_private->m_movie)
425 GetMaxLoadedTimeInMovie(m_private->m_movie, &val);
426 TimeScale scale = GetMovieTimeScale(m_private->m_movie);
427 return static_cast<float>(val) / scale;
430 long QTMovie::loadState() const
432 return m_private->m_loadState;
435 void QTMovie::getNaturalSize(int& width, int& height)
439 if (m_private->m_movie)
440 GetMovieNaturalBoundsRect(m_private->m_movie, &rect);
441 width = (rect.right - rect.left) * m_private->m_widthScaleFactor;
442 height = (rect.bottom - rect.top) * m_private->m_heightScaleFactor;
445 void QTMovie::loadPath(const UChar* url, int len, bool preservesPitch)
447 CFStringRef urlStringRef = CFStringCreateWithCharacters(kCFAllocatorDefault, reinterpret_cast<const UniChar*>(url), len);
448 CFURLRef cfURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, urlStringRef, kCFURLWindowsPathStyle, false);
450 load(cfURL, preservesPitch);
455 CFRelease(urlStringRef);
458 void QTMovie::load(const UChar* url, int len, bool preservesPitch)
460 CFStringRef urlStringRef = CFStringCreateWithCharacters(kCFAllocatorDefault, reinterpret_cast<const UniChar*>(url), len);
461 CFURLRef cfURL = CFURLCreateWithString(kCFAllocatorDefault, urlStringRef, 0);
463 load(cfURL, preservesPitch);
468 CFRelease(urlStringRef);
471 void QTMovie::load(CFURLRef url, bool preservesPitch)
476 if (m_private->m_movie) {
477 m_private->endTask();
478 if (m_private->m_movieController)
479 DisposeMovieController(m_private->m_movieController);
480 m_private->m_movieController = 0;
481 DisposeMovie(m_private->m_movie);
482 m_private->m_movie = 0;
483 m_private->m_loadState = 0;
486 // Define a property array for NewMovieFromProperties.
487 QTNewMoviePropertyElement movieProps[9];
488 ItemCount moviePropCount = 0;
490 bool boolTrue = true;
492 // Disable streaming support for now.
493 CFStringRef scheme = CFURLCopyScheme(url);
494 bool isRTSP = CFStringHasPrefix(scheme, CFSTR("rtsp:"));
498 m_private->m_loadError = noMovieFound;
502 if (m_private->m_currentURL) {
503 if (m_private->m_currentURL != url) {
504 CFRelease(m_private->m_currentURL);
505 m_private->m_currentURL = url;
509 m_private->m_currentURL = url;
513 // Add the movie data location to the property array
514 movieProps[moviePropCount].propClass = kQTPropertyClass_DataLocation;
515 movieProps[moviePropCount].propID = kQTDataLocationPropertyID_CFURL;
516 movieProps[moviePropCount].propValueSize = sizeof(m_private->m_currentURL);
517 movieProps[moviePropCount].propValueAddress = &(m_private->m_currentURL);
518 movieProps[moviePropCount].propStatus = 0;
521 movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation;
522 movieProps[moviePropCount].propID = kQTMovieInstantiationPropertyID_DontAskUnresolvedDataRefs;
523 movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
524 movieProps[moviePropCount].propValueAddress = &boolTrue;
525 movieProps[moviePropCount].propStatus = 0;
528 movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation;
529 movieProps[moviePropCount].propID = kQTMovieInstantiationPropertyID_AsyncOK;
530 movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
531 movieProps[moviePropCount].propValueAddress = &boolTrue;
532 movieProps[moviePropCount].propStatus = 0;
535 movieProps[moviePropCount].propClass = kQTPropertyClass_NewMovieProperty;
536 movieProps[moviePropCount].propID = kQTNewMoviePropertyID_Active;
537 movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
538 movieProps[moviePropCount].propValueAddress = &boolTrue;
539 movieProps[moviePropCount].propStatus = 0;
542 movieProps[moviePropCount].propClass = kQTPropertyClass_NewMovieProperty;
543 movieProps[moviePropCount].propID = kQTNewMoviePropertyID_DontInteractWithUser;
544 movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
545 movieProps[moviePropCount].propValueAddress = &boolTrue;
546 movieProps[moviePropCount].propStatus = 0;
549 movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation;
550 movieProps[moviePropCount].propID = '!url';
551 movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
552 movieProps[moviePropCount].propValueAddress = &boolTrue;
553 movieProps[moviePropCount].propStatus = 0;
556 movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation;
557 movieProps[moviePropCount].propID = 'site';
558 movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
559 movieProps[moviePropCount].propValueAddress = &boolTrue;
560 movieProps[moviePropCount].propStatus = 0;
563 movieProps[moviePropCount].propClass = kQTPropertyClass_Audio;
564 movieProps[moviePropCount].propID = kQTAudioPropertyID_RateChangesPreservePitch;
565 movieProps[moviePropCount].propValueSize = sizeof(preservesPitch);
566 movieProps[moviePropCount].propValueAddress = &preservesPitch;
567 movieProps[moviePropCount].propStatus = 0;
570 bool allowCaching = !m_private->m_privateBrowsing;
571 movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation;
572 movieProps[moviePropCount].propID = 'pers';
573 movieProps[moviePropCount].propValueSize = sizeof(allowCaching);
574 movieProps[moviePropCount].propValueAddress = &allowCaching;
575 movieProps[moviePropCount].propStatus = 0;
578 ASSERT(moviePropCount <= WTF_ARRAY_LENGTH(movieProps));
579 m_private->m_loadError = NewMovieFromProperties(moviePropCount, movieProps, 0, 0, &m_private->m_movie);
582 m_private->startTask();
583 // get the load fail callback quickly
584 if (m_private->m_loadError)
585 QTMovieTask::sharedTask()->updateTaskTimer(0);
587 OSType mode = kQTApertureMode_CleanAperture;
589 // Set the aperture mode property on a movie to signal that we want aspect ratio
590 // and clean aperture dimensions. Don't worry about errors, we can't do anything if
591 // the installed version of QT doesn't support it and it isn't serious enough to
593 QTSetMovieProperty(m_private->m_movie, kQTPropertyClass_Visual, kQTVisualPropertyID_ApertureMode, sizeof(mode), &mode);
597 void QTMovie::disableUnsupportedTracks(unsigned& enabledTrackCount, unsigned& totalTrackCount)
599 if (!m_private->m_movie) {
601 enabledTrackCount = 0;
605 static HashSet<OSType>* allowedTrackTypes = 0;
606 if (!allowedTrackTypes) {
607 allowedTrackTypes = new HashSet<OSType>;
608 allowedTrackTypes->add(VideoMediaType);
609 allowedTrackTypes->add(SoundMediaType);
610 allowedTrackTypes->add(TextMediaType);
611 allowedTrackTypes->add(BaseMediaType);
612 allowedTrackTypes->add(closedCaptionTrackType);
613 allowedTrackTypes->add(subTitleTrackType);
614 allowedTrackTypes->add(mpeg4ObjectDescriptionTrackType);
615 allowedTrackTypes->add(mpeg4SceneDescriptionTrackType);
616 allowedTrackTypes->add(TimeCodeMediaType);
617 allowedTrackTypes->add(TimeCode64MediaType);
620 long trackCount = GetMovieTrackCount(m_private->m_movie);
621 enabledTrackCount = trackCount;
622 totalTrackCount = trackCount;
624 // Track indexes are 1-based. yuck. These things must descend from old-
625 // school mac resources or something.
626 for (long trackIndex = 1; trackIndex <= trackCount; trackIndex++) {
627 // Grab the track at the current index. If there isn't one there, then
628 // we can move onto the next one.
629 Track currentTrack = GetMovieIndTrack(m_private->m_movie, trackIndex);
633 // Check to see if the track is disabled already, we should move along.
634 // We don't need to re-disable it.
635 if (!GetTrackEnabled(currentTrack))
638 // Grab the track's media. We're going to check to see if we need to
639 // disable the tracks. They could be unsupported.
640 Media trackMedia = GetTrackMedia(currentTrack);
644 // Grab the media type for this track. Make sure that we don't
645 // get an error in doing so. If we do, then something really funky is
648 GetMediaHandlerDescription(trackMedia, &mediaType, nil, nil);
649 OSErr mediaErr = GetMoviesError();
650 if (mediaErr != noErr)
653 if (!allowedTrackTypes->contains(mediaType)) {
655 // Different mpeg variants import as different track types so check for the "mpeg
656 // characteristic" instead of hard coding the (current) list of mpeg media types.
657 if (GetMovieIndTrackType(m_private->m_movie, 1, 'mpeg', movieTrackCharacteristic | movieTrackEnabledOnly))
660 SetTrackEnabled(currentTrack, false);
664 // Grab the track reference count for chapters. This will tell us if it
665 // has chapter tracks in it. If there aren't any references, then we
666 // can move on the next track.
667 long referenceCount = GetTrackReferenceCount(currentTrack, kTrackReferenceChapterList);
668 if (referenceCount <= 0)
671 long referenceIndex = 0;
673 // If we get nothing here, we've overstepped our bounds and can stop
674 // looking. Chapter indices here are 1-based as well - hence, the
677 Track chapterTrack = GetTrackReference(currentTrack, kTrackReferenceChapterList, referenceIndex);
681 // Try to grab the media for the track.
682 Media chapterMedia = GetTrackMedia(chapterTrack);
686 // Grab the media type for this track. Make sure that we don't
687 // get an error in doing so. If we do, then something really
690 GetMediaHandlerDescription(chapterMedia, &mediaType, nil, nil);
691 OSErr mediaErr = GetMoviesError();
692 if (mediaErr != noErr)
695 // Check to see if the track is a video track. We don't care about
696 // other non-video tracks.
697 if (mediaType != VideoMediaType)
700 // Check to see if the track is already disabled. If it is, we
701 // should move along.
702 if (!GetTrackEnabled(chapterTrack))
705 // Disabled the evil, evil track.
706 SetTrackEnabled(chapterTrack, false);
712 bool QTMovie::isDisabled() const
714 return m_private->m_disabled;
717 void QTMovie::setDisabled(bool b)
719 m_private->m_disabled = b;
723 bool QTMovie::hasVideo() const
725 if (!m_private->m_movie)
727 return (GetMovieIndTrackType(m_private->m_movie, 1, VisualMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly));
730 bool QTMovie::hasAudio() const
732 if (!m_private->m_movie)
734 return (GetMovieIndTrackType(m_private->m_movie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly));
737 QTTrackArray QTMovie::videoTracks() const
742 while (Track theTrack = GetMovieIndTrackType(m_private->m_movie, trackIndex++, VisualMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly))
743 tracks.append(QTTrack::create(theTrack));
748 bool QTMovie::hasClosedCaptions() const
750 if (!m_private->m_movie)
752 return GetMovieIndTrackType(m_private->m_movie, 1, closedCaptionTrackType, movieTrackMediaType);
755 void QTMovie::setClosedCaptionsVisible(bool visible)
757 if (!m_private->m_movie)
760 Track ccTrack = GetMovieIndTrackType(m_private->m_movie, 1, closedCaptionTrackType, movieTrackMediaType);
764 Boolean doDisplay = visible;
765 QTSetTrackProperty(ccTrack, closedCaptionTrackType, closedCaptionDisplayPropertyID, sizeof(doDisplay), &doDisplay);
768 long QTMovie::timeScale() const
770 if (!m_private->m_movie)
773 return GetMovieTimeScale(m_private->m_movie);
776 static void getMIMETypeCallBack(const char* type);
778 static void initializeSupportedTypes()
783 gSupportedTypes = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
784 if (quickTimeVersion < minimumQuickTimeVersion) {
785 LOG_ERROR("QuickTime version %x detected, at least %x required. Returning empty list of supported media MIME types.", quickTimeVersion, minimumQuickTimeVersion);
789 // QuickTime doesn't have an importer for video/quicktime. Add it manually.
790 CFArrayAppendValue(gSupportedTypes, CFSTR("video/quicktime"));
792 wkGetQuickTimeMIMETypeList(getMIMETypeCallBack);
795 static void getMIMETypeCallBack(const char* type)
798 CFStringRef cfType = CFStringCreateWithCString(kCFAllocatorDefault, type, kCFStringEncodingMacRoman);
802 // Filter out all non-audio or -video MIME Types, and only add each type once:
803 if (CFStringHasPrefix(cfType, CFSTR("audio/")) || CFStringHasPrefix(cfType, CFSTR("video/"))) {
804 CFRange range = CFRangeMake(0, CFArrayGetCount(gSupportedTypes));
805 if (!CFArrayContainsValue(gSupportedTypes, range, cfType))
806 CFArrayAppendValue(gSupportedTypes, cfType);
812 unsigned QTMovie::countSupportedTypes()
814 initializeSupportedTypes();
815 return static_cast<unsigned>(CFArrayGetCount(gSupportedTypes));
818 void QTMovie::getSupportedType(unsigned index, const UChar*& str, unsigned& len)
820 initializeSupportedTypes();
821 ASSERT(index < CFArrayGetCount(gSupportedTypes));
823 // Allocate sufficient buffer to hold any MIME type
824 static UniChar* staticBuffer = 0;
826 staticBuffer = new UniChar[32];
828 CFStringRef cfstr = (CFStringRef)CFArrayGetValueAtIndex(gSupportedTypes, index);
829 len = CFStringGetLength(cfstr);
830 CFRange range = { 0, len };
831 CFStringGetCharacters(cfstr, range, staticBuffer);
832 str = reinterpret_cast<const UChar*>(staticBuffer);
836 CGAffineTransform QTMovie::getTransform() const
838 ASSERT(m_private->m_movie);
839 MatrixRecord m = {0};
840 GetMovieMatrix(m_private->m_movie, &m);
842 ASSERT(!m.matrix[0][2]);
843 ASSERT(!m.matrix[1][2]);
844 CGAffineTransform transform = CGAffineTransformMake(
845 Fix2X(m.matrix[0][0]),
846 Fix2X(m.matrix[0][1]),
847 Fix2X(m.matrix[1][0]),
848 Fix2X(m.matrix[1][1]),
849 Fix2X(m.matrix[2][0]),
850 Fix2X(m.matrix[2][1]));
854 void QTMovie::setTransform(CGAffineTransform t)
856 ASSERT(m_private->m_movie);
858 {X2Fix(t.a), X2Fix(t.b), 0},
859 {X2Fix(t.c), X2Fix(t.d), 0},
860 {X2Fix(t.tx), X2Fix(t.ty), fract1},
863 SetMovieMatrix(m_private->m_movie, &m);
864 m_private->cacheMovieScale();
867 void QTMovie::resetTransform()
869 ASSERT(m_private->m_movie);
870 SetMovieMatrix(m_private->m_movie, 0);
871 m_private->cacheMovieScale();
874 void QTMovie::setPrivateBrowsingMode(bool privateBrowsing)
876 m_private->m_privateBrowsing = privateBrowsing;
877 if (m_private->m_movie) {
878 bool allowCaching = !m_private->m_privateBrowsing;
879 QTSetMovieProperty(m_private->m_movie, 'cach', 'pers', sizeof(allowCaching), &allowCaching);
883 bool QTMovie::initializeQuickTime()
885 static bool initialized = false;
886 static bool initializationSucceeded = false;
889 // Initialize and check QuickTime version
890 OSErr result = InitializeQTML(kInitializeQTMLEnableDoubleBufferedSurface);
892 result = Gestalt(gestaltQuickTime, &quickTimeVersion);
893 if (result != noErr) {
894 LOG_ERROR("No QuickTime available. Disabling <video> and <audio> support.");
897 if (quickTimeVersion < minimumQuickTimeVersion) {
898 LOG_ERROR("QuickTime version %x detected, at least %x required. Disabling <video> and <audio> support.", quickTimeVersion, minimumQuickTimeVersion);
902 initializationSucceeded = true;
904 return initializationSucceeded;
907 Movie QTMovie::getMovieHandle() const
909 return m_private->m_movie;
912 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
915 case DLL_PROCESS_ATTACH:
917 case DLL_PROCESS_DETACH:
918 case DLL_THREAD_ATTACH:
919 case DLL_THREAD_DETACH:
922 ASSERT_NOT_REACHED();