initial import
[vuplus_webkit] / Source / WebCore / platform / graphics / avfoundation / cf / MediaPlayerPrivateAVFoundationCF.cpp
1 /*
2  * Copyright (C) 2011 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
26 #include "config.h"
27
28 #if PLATFORM(WIN)&& ENABLE(VIDEO) 
29
30 #if USE(AVFOUNDATION)
31
32 #include "MediaPlayerPrivateAVFoundationCF.h"
33
34 #include "ApplicationCacheResource.h"
35 #include "FloatConversion.h"
36 #include "FrameView.h"
37 #include "GraphicsContext.h"
38 #include "KURL.h"
39 #include "Logging.h"
40 #include "PlatformCALayer.h"
41 #include "SoftLinking.h"
42 #include "TimeRanges.h"
43
44 #include <AVFoundationCF/AVCFPlayerLayer.h>
45 #include <AVFoundationCF/AVFoundationCF.h>
46 #include <CoreMedia/CoreMedia.h>
47
48 #include <delayimp.h>
49 #include <dispatch/dispatch.h>
50 #include <wtf/HashMap.h>
51 #include <wtf/Threading.h>
52 #include <wtf/UnusedParam.h>
53
54 // The softlink header files must be included after the AVCF and CoreMedia header files.
55 #include "AVFoundationCFSoftLinking.h"
56 #include "CoreMediaSoftLinking.h"
57
58 // We don't bother softlinking against libdispatch since it's already been loaded by AAS.
59 #pragma comment(lib, "libdispatch.lib")
60
61 using namespace std;
62
63 namespace WebCore {
64
65 class LayerClient;
66
67 class AVFWrapper {
68 public:
69     AVFWrapper(MediaPlayerPrivateAVFoundationCF*);
70     ~AVFWrapper();
71
72     void scheduleDisconnectAndDelete();
73
74     void createAVCFVideoLayer();
75     void destroyVideoLayer();
76     PlatformLayer* platformLayer();
77
78     CACFLayerRef caVideoLayer() { return m_caVideoLayer.get(); }
79     PlatformLayer* videoLayerWrapper() { return m_videoLayerWrapper ? m_videoLayerWrapper->platformLayer() : 0; };
80     void setVideoLayerNeedsCommit();
81     void setVideoLayerHidden(bool);
82
83     void createImageGenerator();
84     void destroyImageGenerator();
85     RetainPtr<CGImageRef> createImageForTimeInRect(float, const IntRect&);
86
87     void createAssetForURL(const String& url);
88     void setAsset(AVCFURLAssetRef);
89     
90     void createPlayer();
91     void createPlayerItem();
92     
93     void checkPlayability();
94     void beginLoadingMetadata();
95     
96     void seekToTime(float);
97
98     static void loadMetadataCompletionCallback(AVCFAssetRef, void*);
99     static void loadPlayableCompletionCallback(AVCFAssetRef, void*);
100     static void periodicTimeObserverCallback(AVCFPlayerRef, CMTime, void*);
101     static void seekCompletedCallback(AVCFPlayerItemRef, Boolean, void*);
102     static void notificationCallback(CFNotificationCenterRef, void*, CFStringRef, const void*, CFDictionaryRef);
103
104     inline AVCFPlayerLayerRef videoLayer() const { return (AVCFPlayerLayerRef)m_avCFVideoLayer.get(); }
105     inline AVCFPlayerRef avPlayer() const { return (AVCFPlayerRef)m_avPlayer.get(); }
106     inline AVCFURLAssetRef avAsset() const { return (AVCFURLAssetRef)m_avAsset.get(); }
107     inline AVCFPlayerItemRef avPlayerItem() const { return (AVCFPlayerItemRef)m_avPlayerItem.get(); }
108     inline AVCFPlayerObserverRef timeObserver() const { return (AVCFPlayerObserverRef)m_timeObserver.get(); }
109     inline AVCFAssetImageGeneratorRef imageGenerator() const { return m_imageGenerator.get(); }
110     inline dispatch_queue_t dispatchQueue() const { return m_notificationQueue; }
111
112 private:
113     inline void* callbackContext() const { return reinterpret_cast<void*>(m_objectID); }
114
115     static Mutex& mapLock();
116     static HashMap<uintptr_t, AVFWrapper*>& map();
117     static AVFWrapper* avfWrapperForCallbackContext(void*);
118     void addToMap();
119     void removeFromMap() const;
120
121     static void disconnectAndDeleteAVFWrapper(void*);
122
123     static uintptr_t s_nextAVFWrapperObjectID;
124     uintptr_t m_objectID;
125
126     MediaPlayerPrivateAVFoundationCF* m_owner;
127
128     RetainPtr<AVCFPlayerRef> m_avPlayer;
129     RetainPtr<AVCFURLAssetRef> m_avAsset;
130     RetainPtr<AVCFPlayerItemRef> m_avPlayerItem;
131     RetainPtr<AVCFPlayerLayerRef> m_avCFVideoLayer;
132     RetainPtr<AVCFPlayerObserverRef> m_timeObserver;
133     RetainPtr<AVCFAssetImageGeneratorRef> m_imageGenerator;
134     dispatch_queue_t m_notificationQueue;
135
136     mutable RetainPtr<CACFLayerRef> m_caVideoLayer;
137     RefPtr<PlatformCALayer> m_videoLayerWrapper;
138
139     OwnPtr<LayerClient> m_layerClient;
140 };
141
142 uintptr_t AVFWrapper::s_nextAVFWrapperObjectID;
143
144 class LayerClient : public PlatformCALayerClient {
145 public:
146     LayerClient(AVFWrapper* parent) : m_parent(parent) { }
147     virtual ~LayerClient() { m_parent = 0; }
148
149 private:
150     virtual void platformCALayerLayoutSublayersOfLayer(PlatformCALayer*);
151     virtual bool platformCALayerRespondsToLayoutChanges() const { return true; }
152
153     virtual void platformCALayerAnimationStarted(CFTimeInterval beginTime) { }
154     virtual GraphicsLayer::CompositingCoordinatesOrientation platformCALayerContentsOrientation() const { return GraphicsLayer::CompositingCoordinatesBottomUp; }
155     virtual void platformCALayerPaintContents(GraphicsContext&, const IntRect& inClip) { }
156     virtual bool platformCALayerShowDebugBorders() const { return false; }
157     virtual bool platformCALayerShowRepaintCounter() const { return false; }
158     virtual int platformCALayerIncrementRepaintCount() { return 0; }
159
160     virtual bool platformCALayerContentsOpaque() const { return false; }
161     virtual bool platformCALayerDrawsContent() const { return false; }
162     virtual void platformCALayerLayerDidDisplay(PlatformLayer*) { }
163
164     AVFWrapper* m_parent;
165 };
166
167 #if !LOG_DISABLED
168 static const char* boolString(bool val)
169 {
170     return val ? "true" : "false";
171 }
172 #endif
173
174 static CFArrayRef createMetadataKeyNames()
175 {
176     static const CFStringRef keyNames[] = {
177         AVCFAssetPropertyDuration,
178         AVCFAssetPropertyNaturalSize,
179         AVCFAssetPropertyPreferredTransform,
180         AVCFAssetPropertyPreferredRate,
181         AVCFAssetPropertyPlayable,
182         AVCFAssetPropertyTracks 
183     };
184     
185     return CFArrayCreate(0, (const void**)keyNames, sizeof(keyNames) / sizeof(keyNames[0]), &kCFTypeArrayCallBacks);
186 }
187
188 static CFArrayRef metadataKeyNames()
189 {
190     static CFArrayRef keys = createMetadataKeyNames();
191     return keys;
192 }
193
194 // FIXME: It would be better if AVCFTimedMetadataGroup.h exported this key.
195 static CFStringRef CMTimeRangeStartKey()
196 {
197     DEFINE_STATIC_LOCAL(CFStringRef, key, (CFSTR("start")));
198     return key;
199 }
200
201 // FIXME: It would be better if AVCFTimedMetadataGroup.h exported this key.
202 static CFStringRef CMTimeRangeDurationKey()
203 {
204     DEFINE_STATIC_LOCAL(CFStringRef, key, (CFSTR("duration")));
205     return key;
206 }
207
208 // FIXME: It would be better if AVCF exported this notification name.
209 static CFStringRef CACFContextNeedsFlushNotification()
210 {
211     DEFINE_STATIC_LOCAL(CFStringRef, name, (CFSTR("kCACFContextNeedsFlushNotification")));
212     return name;
213 }
214
215 // Define AVCF object accessors as inline functions here instead of in MediaPlayerPrivateAVFoundationCF so we don't have
216 // to include the AVCF headers in MediaPlayerPrivateAVFoundationCF.h
217 inline AVCFPlayerLayerRef videoLayer(AVFWrapper* wrapper)
218
219     return wrapper ? wrapper->videoLayer() : 0; 
220 }
221
222 inline AVCFPlayerRef avPlayer(AVFWrapper* wrapper)
223
224     return wrapper ? wrapper->avPlayer() : 0; 
225 }
226
227 inline AVCFURLAssetRef avAsset(AVFWrapper* wrapper)
228
229     return wrapper ? wrapper->avAsset() : 0; 
230 }
231
232 inline AVCFPlayerItemRef avPlayerItem(AVFWrapper* wrapper)
233
234     return wrapper ? wrapper->avPlayerItem() : 0; 
235 }
236
237 inline AVCFAssetImageGeneratorRef imageGenerator(AVFWrapper* wrapper)
238
239     return wrapper ? wrapper->imageGenerator() : 0; 
240 }
241
242 PassOwnPtr<MediaPlayerPrivateInterface> MediaPlayerPrivateAVFoundationCF::create(MediaPlayer* player) 
243
244     return adoptPtr(new MediaPlayerPrivateAVFoundationCF(player));
245 }
246
247 void MediaPlayerPrivateAVFoundationCF::registerMediaEngine(MediaEngineRegistrar registrar)
248 {
249     if (isAvailable())
250         registrar(create, getSupportedTypes, supportsType, 0, 0, 0);
251 }
252
253 MediaPlayerPrivateAVFoundationCF::MediaPlayerPrivateAVFoundationCF(MediaPlayer* player)
254     : MediaPlayerPrivateAVFoundation(player)
255     , m_avfWrapper(0)
256     , m_videoFrameHasDrawn(false)
257 {
258     LOG(Media, "MediaPlayerPrivateAVFoundationCF::MediaPlayerPrivateAVFoundationCF(%p)", this);
259 }
260
261 MediaPlayerPrivateAVFoundationCF::~MediaPlayerPrivateAVFoundationCF()
262 {
263     LOG(Media, "MediaPlayerPrivateAVFoundationCF::~MediaPlayerPrivateAVFoundationCF(%p)", this);
264     cancelLoad();
265 }
266
267 void MediaPlayerPrivateAVFoundationCF::cancelLoad()
268 {
269     LOG(Media, "MediaPlayerPrivateAVFoundationCF::cancelLoad(%p)", this);
270
271     // Do nothing when our cancellation of pending loading calls its completion handler
272     setDelayCallbacks(true);
273     setIgnoreLoadStateChanges(true);
274
275     tearDownVideoRendering();
276
277     if (m_avfWrapper) {
278         // The AVCF objects have to be destroyed on the same dispatch queue used for notifications, so schedule a call to 
279         // disconnectAndDeleteAVFWrapper on that queue. 
280         m_avfWrapper->scheduleDisconnectAndDelete();
281         m_avfWrapper = 0;
282     }
283
284     setIgnoreLoadStateChanges(false);
285     setDelayCallbacks(false);
286 }
287
288 bool MediaPlayerPrivateAVFoundationCF::hasLayerRenderer() const
289 {
290     return videoLayer(m_avfWrapper);
291 }
292
293 bool MediaPlayerPrivateAVFoundationCF::hasContextRenderer() const
294 {
295     return imageGenerator(m_avfWrapper);
296 }
297
298 void MediaPlayerPrivateAVFoundationCF::createContextVideoRenderer()
299 {
300     LOG(Media, "MediaPlayerPrivateAVFoundationCF::createContextVideoRenderer(%p)", this);
301
302     if (imageGenerator(m_avfWrapper))
303         return;
304
305     if (m_avfWrapper)
306         m_avfWrapper->createImageGenerator();
307 }
308
309 void MediaPlayerPrivateAVFoundationCF::destroyContextVideoRenderer()
310 {
311     if (m_avfWrapper)
312         m_avfWrapper->destroyImageGenerator();
313 }
314
315 void MediaPlayerPrivateAVFoundationCF::createVideoLayer()
316 {
317     ASSERT(supportsAcceleratedRendering());
318
319     if (m_avfWrapper)
320         m_avfWrapper->createAVCFVideoLayer();
321 }
322
323 void MediaPlayerPrivateAVFoundationCF::destroyVideoLayer()
324 {
325     LOG(Media, "MediaPlayerPrivateAVFoundationCF::destroyVideoLayer(%p) - destroying %p", this, videoLayer(m_avfWrapper));
326     if (m_avfWrapper)
327         m_avfWrapper->destroyVideoLayer();
328 }
329
330 bool MediaPlayerPrivateAVFoundationCF::hasAvailableVideoFrame() const
331 {
332     return (m_videoFrameHasDrawn || (videoLayer(m_avfWrapper) && AVCFPlayerLayerIsReadyForDisplay(videoLayer(m_avfWrapper))));
333 }
334
335 void MediaPlayerPrivateAVFoundationCF::createAVPlayer()
336 {
337     ASSERT(m_avfWrapper);
338     
339     setDelayCallbacks(true);
340     m_avfWrapper->createPlayer();
341     setDelayCallbacks(false);
342 }
343
344 void MediaPlayerPrivateAVFoundationCF::createAVPlayerItem()
345 {
346     ASSERT(m_avfWrapper);
347     
348     setDelayCallbacks(true);
349     m_avfWrapper->createPlayerItem();
350     setDelayCallbacks(false);
351 }
352
353 void MediaPlayerPrivateAVFoundationCF::createAVAssetForURL(const String& url)
354 {
355     ASSERT(!m_avfWrapper);
356     
357     setDelayCallbacks(true);
358     m_avfWrapper = new AVFWrapper(this);
359     m_avfWrapper->createAssetForURL(url);
360     setDelayCallbacks(false);
361 }
362
363 void MediaPlayerPrivateAVFoundationCF::checkPlayability()
364 {
365     ASSERT(m_avfWrapper);
366     m_avfWrapper->checkPlayability();
367 }
368
369 void MediaPlayerPrivateAVFoundationCF::beginLoadingMetadata()
370 {
371     ASSERT(m_avfWrapper);
372     m_avfWrapper->beginLoadingMetadata();
373 }
374
375 MediaPlayerPrivateAVFoundation::ItemStatus MediaPlayerPrivateAVFoundationCF::playerItemStatus() const
376 {
377     if (!avPlayerItem(m_avfWrapper))
378         return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusDoesNotExist;
379
380     AVCFPlayerItemStatus status = AVCFPlayerItemGetStatus(avPlayerItem(m_avfWrapper), 0);
381     if (status == AVCFPlayerItemStatusUnknown)
382         return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusUnknown;
383     if (status == AVCFPlayerItemStatusFailed)
384         return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusFailed;
385     if (AVCFPlayerItemIsPlaybackLikelyToKeepUp(avPlayerItem(m_avfWrapper)))
386         return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackLikelyToKeepUp;
387     if (AVCFPlayerItemIsPlaybackBufferFull(avPlayerItem(m_avfWrapper)))
388         return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferFull;
389     if (AVCFPlayerItemIsPlaybackBufferEmpty(avPlayerItem(m_avfWrapper)))
390         return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferEmpty;
391     return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusReadyToPlay;
392 }
393
394 PlatformMedia MediaPlayerPrivateAVFoundationCF::platformMedia() const
395 {
396     LOG(Media, "MediaPlayerPrivateAVFoundationCF::platformMedia(%p)", this);
397     PlatformMedia pm;
398     pm.type = PlatformMedia::AVFoundationCFMediaPlayerType;
399     pm.media.avcfMediaPlayer = (AVCFPlayer*)avPlayer(m_avfWrapper);
400     return pm;
401 }
402
403 PlatformLayer* MediaPlayerPrivateAVFoundationCF::platformLayer() const
404 {
405     if (!m_avfWrapper)
406         return 0;
407
408     return m_avfWrapper->platformLayer();
409 }
410
411 void MediaPlayerPrivateAVFoundationCF::platformSetVisible(bool isVisible)
412 {
413     if (!m_avfWrapper)
414         return;
415     
416     // FIXME: We use a CATransaction here on the Mac, we need to figure out why this was done there and
417     // whether we're affected by the same issue.
418     setDelayCallbacks(true);
419     m_avfWrapper->setVideoLayerHidden(!isVisible);    
420     setDelayCallbacks(false);
421 }
422
423 void MediaPlayerPrivateAVFoundationCF::platformPlay()
424 {
425     LOG(Media, "MediaPlayerPrivateAVFoundationCF::play(%p)", this);
426     if (!metaDataAvailable() || !avPlayer(m_avfWrapper))
427         return;
428
429     setDelayCallbacks(true);
430     AVCFPlayerSetRate(avPlayer(m_avfWrapper), requestedRate());
431     setDelayCallbacks(false);
432 }
433
434 void MediaPlayerPrivateAVFoundationCF::platformPause()
435 {
436     LOG(Media, "MediaPlayerPrivateAVFoundationCF::pause(%p)", this);
437     if (!metaDataAvailable() || !avPlayer(m_avfWrapper))
438         return;
439
440     setDelayCallbacks(true);
441     AVCFPlayerSetRate(avPlayer(m_avfWrapper), 0);
442     setDelayCallbacks(false);
443 }
444
445 void MediaPlayerPrivateAVFoundationCF::updateRate()
446 {
447     LOG(Media, "MediaPlayerPrivateAVFoundationCF::updateRate(%p)", this);
448     if (!metaDataAvailable() || !avPlayer(m_avfWrapper))
449         return;
450
451     setDelayCallbacks(true);
452     AVCFPlayerSetRate(avPlayer(m_avfWrapper), requestedRate());
453     setDelayCallbacks(false);
454 }
455
456 float MediaPlayerPrivateAVFoundationCF::platformDuration() const
457 {
458     if (!metaDataAvailable() || !avAsset(m_avfWrapper))
459         return 0;
460
461     float duration;
462     CMTime cmDuration = AVCFAssetGetDuration(avAsset(m_avfWrapper));
463     if (CMTIME_IS_NUMERIC(cmDuration))
464         duration = narrowPrecisionToFloat(CMTimeGetSeconds(cmDuration));
465     else if (CMTIME_IS_INDEFINITE(cmDuration))
466         duration = numeric_limits<float>::infinity();
467     else {
468         LOG(Media, "MediaPlayerPrivateAVFMac::duration(%p) - invalid duration, returning 0", this);
469         return 0;
470     }
471
472     return duration;
473 }
474
475 float MediaPlayerPrivateAVFoundationCF::currentTime() const
476 {
477     if (!metaDataAvailable() || !avPlayerItem(m_avfWrapper))
478         return 0;
479
480     CMTime itemTime = AVCFPlayerItemGetCurrentTime(avPlayerItem(m_avfWrapper));
481     if (CMTIME_IS_NUMERIC(itemTime))
482         return narrowPrecisionToFloat(CMTimeGetSeconds(itemTime));
483
484     return 0;
485 }
486
487 void MediaPlayerPrivateAVFoundationCF::seekToTime(float time)
488 {
489     if (!m_avfWrapper)
490         return;
491     
492     // seekToTime generates several event callbacks, update afterwards.
493     setDelayCallbacks(true);
494     m_avfWrapper->seekToTime(time);
495     setDelayCallbacks(false);
496 }
497
498 void MediaPlayerPrivateAVFoundationCF::setVolume(float volume)
499 {
500     if (!metaDataAvailable() || !avPlayer(m_avfWrapper))
501         return;
502
503     AVCFPlayerSetVolume(avPlayer(m_avfWrapper), volume);
504 }
505
506 void MediaPlayerPrivateAVFoundationCF::setClosedCaptionsVisible(bool closedCaptionsVisible)
507 {
508     if (!metaDataAvailable() || !avPlayer(m_avfWrapper))
509         return;
510
511     LOG(Media, "MediaPlayerPrivateAVFoundationCF::setClosedCaptionsVisible(%p) - setting to %s", this, boolString(closedCaptionsVisible));
512     AVCFPlayerSetClosedCaptionDisplayEnabled(avPlayer(m_avfWrapper), closedCaptionsVisible);
513 }
514
515 float MediaPlayerPrivateAVFoundationCF::rate() const
516 {
517     if (!metaDataAvailable() || !avPlayer(m_avfWrapper))
518         return 0;
519
520     setDelayCallbacks(true);
521     float currentRate = AVCFPlayerGetRate(avPlayer(m_avfWrapper));
522     setDelayCallbacks(false);
523
524     return currentRate;
525 }
526
527 static bool timeRangeIsValidAndNotEmpty(CMTime start, CMTime duration)
528 {
529     // Is the range valid?
530     if (!CMTIME_IS_VALID(start) || !CMTIME_IS_VALID(duration) || duration.epoch || duration.value < 0)
531         return false;
532
533     if (CMTIME_COMPARE_INLINE(duration, ==, kCMTimeZero))
534         return false;
535
536     return true;
537 }
538
539 PassRefPtr<TimeRanges> MediaPlayerPrivateAVFoundationCF::platformBufferedTimeRanges() const
540 {
541     RefPtr<TimeRanges> timeRanges = TimeRanges::create();
542
543     if (!avPlayerItem(m_avfWrapper))
544         return timeRanges.release();
545
546     RetainPtr<CFArrayRef> loadedRanges(AdoptCF, AVCFPlayerItemCopyLoadedTimeRanges(avPlayerItem(m_avfWrapper)));
547     if (!loadedRanges)
548         return timeRanges.release();
549
550     CFIndex rangeCount = CFArrayGetCount(loadedRanges.get());
551     for (CFIndex i = 0; i < rangeCount; i++) {
552         CFDictionaryRef range = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(loadedRanges.get(), i));
553         CMTime start = CMTimeMakeFromDictionary(static_cast<CFDictionaryRef>(CFDictionaryGetValue(range, CMTimeRangeStartKey())));
554         CMTime duration = CMTimeMakeFromDictionary(static_cast<CFDictionaryRef>(CFDictionaryGetValue(range, CMTimeRangeDurationKey())));
555         
556         if (timeRangeIsValidAndNotEmpty(start, duration)) {
557             float rangeStart = narrowPrecisionToFloat(CMTimeGetSeconds(start));
558             float rangeEnd = narrowPrecisionToFloat(CMTimeGetSeconds(CMTimeAdd(start, duration)));
559             timeRanges->add(rangeStart, rangeEnd);
560         }
561     }
562
563     return timeRanges.release();
564 }
565
566 float MediaPlayerPrivateAVFoundationCF::platformMaxTimeSeekable() const
567 {
568     if (!avPlayerItem(m_avfWrapper))
569         return 0;
570
571     RetainPtr<CFArrayRef> seekableRanges(AdoptCF, AVCFPlayerItemCopySeekableTimeRanges(avPlayerItem(m_avfWrapper)));
572     if (!seekableRanges)
573         return 0;
574
575     float maxTimeSeekable = 0;
576     CFIndex rangeCount = CFArrayGetCount(seekableRanges.get());
577     for (CFIndex i = 0; i < rangeCount; i++) {
578         CFDictionaryRef range = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(seekableRanges.get(), i));
579         CMTime start = CMTimeMakeFromDictionary(static_cast<CFDictionaryRef>(CFDictionaryGetValue(range, CMTimeRangeStartKey())));
580         CMTime duration = CMTimeMakeFromDictionary(static_cast<CFDictionaryRef>(CFDictionaryGetValue(range, CMTimeRangeDurationKey())));
581         if (!timeRangeIsValidAndNotEmpty(start, duration))
582             continue;
583         
584         float endOfRange = narrowPrecisionToFloat(CMTimeGetSeconds(CMTimeAdd(start, duration)));
585         if (maxTimeSeekable < endOfRange)
586             maxTimeSeekable = endOfRange;
587     }
588
589     return maxTimeSeekable;   
590 }
591
592 float MediaPlayerPrivateAVFoundationCF::platformMaxTimeLoaded() const
593 {
594     if (!avPlayerItem(m_avfWrapper))
595         return 0;
596
597     RetainPtr<CFArrayRef> loadedRanges(AdoptCF, AVCFPlayerItemCopyLoadedTimeRanges(avPlayerItem(m_avfWrapper)));
598     if (!loadedRanges)
599         return 0;
600
601     float maxTimeLoaded = 0;
602     CFIndex rangeCount = CFArrayGetCount(loadedRanges.get());
603     for (CFIndex i = 0; i < rangeCount; i++) {
604         CFDictionaryRef range = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(loadedRanges.get(), i));
605         CMTime start = CMTimeMakeFromDictionary(static_cast<CFDictionaryRef>(CFDictionaryGetValue(range, CMTimeRangeStartKey())));
606         CMTime duration = CMTimeMakeFromDictionary(static_cast<CFDictionaryRef>(CFDictionaryGetValue(range, CMTimeRangeDurationKey())));
607         if (!timeRangeIsValidAndNotEmpty(start, duration))
608             continue;
609         
610         float endOfRange = narrowPrecisionToFloat(CMTimeGetSeconds(CMTimeAdd(start, duration)));
611         if (maxTimeLoaded < endOfRange)
612             maxTimeLoaded = endOfRange;
613     }
614
615     return maxTimeLoaded;   
616 }
617
618 unsigned MediaPlayerPrivateAVFoundationCF::totalBytes() const
619 {
620     if (!metaDataAvailable() || !avAsset(m_avfWrapper))
621         return 0;
622
623     int64_t totalMediaSize = 0;
624     RetainPtr<CFArrayRef> tracks(AdoptCF, AVCFAssetCopyAssetTracks(avAsset(m_avfWrapper)));
625     CFIndex trackCount = CFArrayGetCount(tracks.get());
626     for (CFIndex i = 0; i < trackCount; i++) {
627         AVCFAssetTrackRef assetTrack = (AVCFAssetTrackRef)CFArrayGetValueAtIndex(tracks.get(), i);
628         totalMediaSize += AVCFAssetTrackGetTotalSampleDataLength(assetTrack);
629     }
630
631     // FIXME: It doesn't seem safe to cast an int64_t to unsigned.
632     return static_cast<unsigned>(totalMediaSize);
633 }
634
635 MediaPlayerPrivateAVFoundation::AssetStatus MediaPlayerPrivateAVFoundationCF::assetStatus() const
636 {
637     if (!avAsset(m_avfWrapper))
638         return MediaPlayerAVAssetStatusDoesNotExist;
639
640     // First, make sure all metadata properties we rely on are loaded.
641     CFArrayRef keys = metadataKeyNames();
642     CFIndex keyCount = CFArrayGetCount(keys);
643     for (CFIndex i = 0; i < keyCount; i++) {
644         CFStringRef keyName = static_cast<CFStringRef>(CFArrayGetValueAtIndex(keys, i));
645         AVCFPropertyValueStatus keyStatus = AVCFAssetGetStatusOfValueForProperty(avAsset(m_avfWrapper), keyName, 0);
646         
647         if (keyStatus < AVCFPropertyValueStatusLoaded)
648             return MediaPlayerAVAssetStatusLoading;
649         if (keyStatus == AVCFPropertyValueStatusFailed)
650             return MediaPlayerAVAssetStatusFailed;
651         if (keyStatus == AVCFPropertyValueStatusCancelled)
652             return MediaPlayerAVAssetStatusCancelled;
653     }
654
655     if (AVCFAssetIsPlayable(avAsset(m_avfWrapper)))
656         return MediaPlayerAVAssetStatusPlayable;
657
658     return MediaPlayerAVAssetStatusLoaded;
659 }
660
661 void MediaPlayerPrivateAVFoundationCF::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& rect)
662 {
663     if (context->paintingDisabled())
664         return;
665
666     if (currentRenderingMode() == MediaRenderingToLayer && !imageGenerator(m_avfWrapper)) {
667         // We're being told to render into a context, but we already have the
668         // video layer, which probably means we've been called from <canvas>.
669         createContextVideoRenderer();
670     }
671
672     paint(context, rect);
673 }
674
675 void MediaPlayerPrivateAVFoundationCF::paint(GraphicsContext* context, const IntRect& rect)
676 {
677     if (context->paintingDisabled() || !imageGenerator(m_avfWrapper))
678         return;
679
680     LOG(Media, "MediaPlayerPrivateAVFoundationCF::paint(%p)", this);
681
682     setDelayCallbacks(true);
683     RetainPtr<CGImageRef> image = m_avfWrapper->createImageForTimeInRect(currentTime(), rect);
684     if (image) {
685         context->save();
686         context->translate(rect.x(), rect.y() + rect.height());
687         context->scale(FloatSize(1.0f, -1.0f));
688         context->setImageInterpolationQuality(InterpolationLow);
689         IntRect paintRect(IntPoint(0, 0), IntSize(rect.width(), rect.height()));
690         CGContextDrawImage(context->platformContext(), CGRectMake(0, 0, paintRect.width(), paintRect.height()), image.get());
691         context->restore();
692         image = 0;
693     }
694     setDelayCallbacks(false);
695     
696     m_videoFrameHasDrawn = true;
697 }
698
699 static HashSet<String> mimeTypeCache()
700 {
701     DEFINE_STATIC_LOCAL(HashSet<String>, cache, ());
702     static bool typeListInitialized = false;
703
704     if (typeListInitialized)
705         return cache;
706     typeListInitialized = true;
707     
708     RetainPtr<CFArrayRef> supportedTypes(AdoptCF, AVCFURLAssetCopyAudiovisualMIMETypes());
709     
710     ASSERT(supportedTypes);
711     if (!supportedTypes)
712         return cache;
713
714     CFIndex typeCount = CFArrayGetCount(supportedTypes.get());
715     for (CFIndex i = 0; i < typeCount; i++)
716         cache.add(static_cast<CFStringRef>(CFArrayGetValueAtIndex(supportedTypes.get(), i)));
717
718     return cache;
719
720
721 void MediaPlayerPrivateAVFoundationCF::getSupportedTypes(HashSet<String>& supportedTypes)
722 {
723     supportedTypes = mimeTypeCache();
724
725
726 MediaPlayer::SupportsType MediaPlayerPrivateAVFoundationCF::supportsType(const String& type, const String& codecs)
727 {
728     // Only return "IsSupported" if there is no codecs parameter for now as there is no way to ask if it supports an
729     // extended MIME type until rdar://8721715 is fixed.
730     if (mimeTypeCache().contains(type))
731         return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported;
732
733     return MediaPlayer::IsNotSupported;
734 }
735
736
737 bool MediaPlayerPrivateAVFoundationCF::isAvailable()
738 {
739     return AVFoundationCFLibrary() && CoreMediaLibrary();
740 }
741
742 float MediaPlayerPrivateAVFoundationCF::mediaTimeForTimeValue(float timeValue) const
743 {
744     if (!metaDataAvailable())
745         return timeValue;
746
747     // FIXME - can not implement until rdar://8721669 is fixed.
748     return timeValue;
749 }
750
751 void MediaPlayerPrivateAVFoundationCF::tracksChanged()
752 {
753     if (!avAsset(m_avfWrapper))
754         return;
755     
756     // This is called whenever the tracks collection changes so cache hasVideo and hasAudio since we are
757     // asked about those fairly frequently.
758     if (!avPlayerItem(m_avfWrapper)) {
759         // We don't have a player item yet, so check with the asset because some assets support inspection
760         // prior to becoming ready to play.
761         RetainPtr<CFArrayRef> visualTracks(AdoptCF, AVCFAssetCopyTracksWithMediaCharacteristic(avAsset(m_avfWrapper), AVCFMediaCharacteristicVisual));
762         setHasVideo(CFArrayGetCount(visualTracks.get()));
763
764         RetainPtr<CFArrayRef> audioTracks(AdoptCF, AVCFAssetCopyTracksWithMediaCharacteristic(avAsset(m_avfWrapper), AVCFMediaCharacteristicAudible));
765         setHasAudio(CFArrayGetCount(audioTracks.get()));
766
767         RetainPtr<CFArrayRef> captionTracks(AdoptCF, AVCFAssetCopyTracksWithMediaType(avAsset(m_avfWrapper), AVCFMediaTypeClosedCaption));
768         setHasAudio(CFArrayGetCount(captionTracks.get()));
769     } else {
770         bool hasVideo = false;
771         bool hasAudio = false;
772         bool hasCaptions = false;
773
774         RetainPtr<CFArrayRef> tracks(AdoptCF, AVCFPlayerItemCopyTracks(avPlayerItem(m_avfWrapper)));
775
776         CFIndex trackCount = CFArrayGetCount(tracks.get());
777         for (CFIndex i = 0; i < trackCount; i++) {
778             AVCFPlayerItemTrackRef track = (AVCFPlayerItemTrackRef)(CFArrayGetValueAtIndex(tracks.get(), i));
779             
780             if (AVCFPlayerItemTrackIsEnabled(track)) {
781                 RetainPtr<AVCFAssetTrackRef> assetTrack(AdoptCF, AVCFPlayerItemTrackCopyAssetTrack(track));
782                 CFStringRef mediaType = AVCFAssetTrackGetMediaType(assetTrack.get());
783                 if (!mediaType)
784                     continue;
785                 
786                 if (CFStringCompare(mediaType, AVCFMediaTypeVideo, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
787                     hasVideo = true;
788                 else if (CFStringCompare(mediaType, AVCFMediaTypeAudio, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
789                     hasAudio = true;
790                 else if (CFStringCompare(mediaType, AVCFMediaTypeClosedCaption, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
791                     hasCaptions = true;
792             }
793         }
794
795         setHasVideo(hasVideo);
796         setHasAudio(hasAudio);
797         setHasClosedCaptions(hasCaptions);
798     }
799
800     LOG(Media, "MediaPlayerPrivateAVFoundationCF:tracksChanged(%p) - hasVideo = %s, hasAudio = %s, hasCaptions = %s", 
801         this, boolString(hasVideo()), boolString(hasAudio()), boolString(hasClosedCaptions()));
802
803     sizeChanged();
804 }
805
806 void MediaPlayerPrivateAVFoundationCF::sizeChanged()
807 {
808     if (!avAsset(m_avfWrapper))
809         return;
810     
811     // AVAsset's 'naturalSize' property only considers the movie's first video track, so we need to compute
812     // the union of all visual track rects.
813     CGRect trackRectUnion = CGRectZero;
814     RetainPtr<CFArrayRef> tracks(AdoptCF, AVCFAssetCopyTracksWithMediaType(avAsset(m_avfWrapper), AVCFMediaCharacteristicVisual));
815     CFIndex trackCount = CFArrayGetCount(tracks.get());
816     for (CFIndex i = 0; i < trackCount; i++) {
817         AVCFAssetTrackRef assetTrack = (AVCFAssetTrackRef)(CFArrayGetValueAtIndex(tracks.get(), i));
818         
819         CGSize trackSize = AVCFAssetTrackGetNaturalSize(assetTrack);
820         CGRect trackRect = CGRectMake(0, 0, trackSize.width, trackSize.height);
821         trackRectUnion = CGRectUnion(trackRectUnion, CGRectApplyAffineTransform(trackRect, AVCFAssetTrackGetPreferredTransform(assetTrack)));
822     }
823     // The movie is always displayed at 0,0 so move the track rect to the origin before using width and height.
824     trackRectUnion = CGRectOffset(trackRectUnion, trackRectUnion.origin.x, trackRectUnion.origin.y);
825     CGSize naturalSize = trackRectUnion.size;
826
827     // Also look at the asset's preferred transform so we account for a movie matrix.
828     CGSize movieSize = CGSizeApplyAffineTransform(AVCFAssetGetNaturalSize(avAsset(m_avfWrapper)), AVCFAssetGetPreferredTransform(avAsset(m_avfWrapper)));
829     if (movieSize.width > naturalSize.width)
830         naturalSize.width = movieSize.width;
831     if (movieSize.height > naturalSize.height)
832         naturalSize.height = movieSize.height;
833     setNaturalSize(IntSize(naturalSize));
834 }
835
836 void MediaPlayerPrivateAVFoundationCF::contentsNeedsDisplay()
837 {
838     if (m_avfWrapper)
839         m_avfWrapper->setVideoLayerNeedsCommit();
840 }
841
842 AVFWrapper::AVFWrapper(MediaPlayerPrivateAVFoundationCF* owner)
843     : m_owner(owner)
844     , m_objectID(s_nextAVFWrapperObjectID++)
845 {
846     LOG(Media, "AVFWrapper::AVFWrapper(%p)", this);
847
848     m_notificationQueue = dispatch_queue_create("MediaPlayerPrivateAVFoundationCF.notificationQueue", 0);
849     addToMap();
850 }
851
852 AVFWrapper::~AVFWrapper()
853 {
854     LOG(Media, "AVFWrapper::~AVFWrapper(%p %d)", this, m_objectID);
855
856     destroyVideoLayer();
857     destroyImageGenerator();
858
859     if (m_notificationQueue)
860         dispatch_release(m_notificationQueue);
861
862     if (avAsset()) {
863         AVCFAssetCancelLoading(avAsset());
864         m_avAsset = 0;
865     }
866
867     m_avPlayerItem = 0;
868     m_timeObserver = 0;
869     m_avPlayer = 0;
870 }
871
872 Mutex& AVFWrapper::mapLock()
873 {
874     static Mutex mapLock;
875     return mapLock;
876 }
877
878 HashMap<uintptr_t, AVFWrapper*>& AVFWrapper::map()
879 {
880     static HashMap<uintptr_t, AVFWrapper*>& map = *new HashMap<uintptr_t, AVFWrapper*>;
881     return map;
882 }
883
884 void AVFWrapper::addToMap()
885 {
886     MutexLocker locker(mapLock());
887     
888     // HashMap doesn't like a key of 0, and also make sure we aren't
889     // using an object ID that's already in use.
890     while (!m_objectID || (map().find(m_objectID) != map().end()))
891         m_objectID = s_nextAVFWrapperObjectID++;
892        
893     LOG(Media, "AVFWrapper::addToMap(%p %d)", this, m_objectID);
894
895     map().add(m_objectID, this);
896 }
897
898 void AVFWrapper::removeFromMap() const
899 {
900     LOG(Media, "AVFWrapper::removeFromMap(%p %d)", this, m_objectID);
901
902     MutexLocker locker(mapLock());
903     map().remove(m_objectID);
904 }
905
906 AVFWrapper* AVFWrapper::avfWrapperForCallbackContext(void* context)
907 {
908     // Assumes caller has locked mapLock().
909     HashMap<uintptr_t, AVFWrapper*>::iterator it = map().find(reinterpret_cast<uintptr_t>(context));
910     if (it == map().end())
911         return 0;
912
913     return it->second;
914 }
915
916 void AVFWrapper::scheduleDisconnectAndDelete()
917 {
918     // Ignore any subsequent notifications we might receive in notificationCallback().
919     removeFromMap();
920
921     dispatch_async_f(dispatchQueue(), this, disconnectAndDeleteAVFWrapper);
922 }
923
924 void AVFWrapper::disconnectAndDeleteAVFWrapper(void* context)
925 {
926     AVFWrapper* avfWrapper = static_cast<AVFWrapper*>(context);
927
928     LOG(Media, "AVFWrapper::disconnectAndDeleteAVFWrapper(%p)", avfWrapper);
929
930     if (avfWrapper->avPlayerItem()) {
931         CFNotificationCenterRef center = CFNotificationCenterGetLocalCenter();
932         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemDidPlayToEndTimeNotification, avfWrapper->avPlayerItem());
933         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemStatusChangedNotification, avfWrapper->avPlayerItem());
934         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemTracksChangedNotification, avfWrapper->avPlayerItem());
935         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemSeekableTimeRangesChangedNotification, avfWrapper->avPlayerItem());
936         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemLoadedTimeRangesChangedNotification, avfWrapper->avPlayerItem());
937         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemIsPlaybackLikelyToKeepUpChangedNotification, avfWrapper->avPlayerItem());
938         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemIsPlaybackBufferEmptyChangedNotification, avfWrapper->avPlayerItem());
939         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemIsPlaybackBufferFullChangedNotification, avfWrapper->avPlayerItem());
940         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), CACFContextNeedsFlushNotification(), 0);
941     }
942
943     if (avfWrapper->avPlayer()) {
944         if (avfWrapper->timeObserver())
945             AVCFPlayerRemoveObserver(avfWrapper->avPlayer(), avfWrapper->timeObserver());
946
947         CFNotificationCenterRemoveObserver(CFNotificationCenterGetLocalCenter(), avfWrapper->callbackContext(), AVCFPlayerRateChangedNotification, avfWrapper->avPlayer());
948     }
949
950     delete avfWrapper;
951 }
952
953 void AVFWrapper::createAssetForURL(const String& url)
954 {
955     ASSERT(!avAsset());
956     
957     RetainPtr<CFURLRef> urlRef(AdoptCF, KURL(ParsedURLString, url).createCFURL());
958     AVCFURLAssetRef assetRef = AVCFURLAssetCreateWithURLAndOptions(kCFAllocatorDefault, urlRef.get(), 0, m_notificationQueue);
959     m_avAsset.adoptCF(assetRef);
960 }
961
962 void AVFWrapper::createPlayer()
963 {
964     ASSERT(!avPlayer() && avPlayerItem());
965
966     // FIXME: We need a way to create a AVPlayer without an AVPlayerItem, see <rdar://problem/9877730>.
967     AVCFPlayerRef playerRef = AVCFPlayerCreateWithPlayerItemAndOptions(kCFAllocatorDefault, avPlayerItem(), 0, m_notificationQueue);
968     m_avPlayer.adoptCF(playerRef);
969
970     CFNotificationCenterRef center = CFNotificationCenterGetLocalCenter();
971     ASSERT(center);
972
973     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerRateChangedNotification, playerRef, CFNotificationSuspensionBehaviorDeliverImmediately);
974
975     // Add a time observer, ask to be called infrequently because we don't really want periodic callbacks but
976     // our observer will also be called whenever a seek happens.
977     const double veryLongInterval = 60*60*60*24*30;
978     m_timeObserver.adoptCF(AVCFPlayerCreatePeriodicTimeObserverForInterval(playerRef, CMTimeMake(veryLongInterval, 10), m_notificationQueue, &periodicTimeObserverCallback, callbackContext()));
979 }
980
981 void AVFWrapper::createPlayerItem()
982 {
983     ASSERT(!avPlayerItem() && avAsset());
984
985     // Create the player item so we begin loading media data.
986     AVCFPlayerItemRef itemRef = AVCFPlayerItemCreateWithAsset(kCFAllocatorDefault, avAsset(), m_notificationQueue);
987     m_avPlayerItem.adoptCF(itemRef);
988
989     CFNotificationCenterRef center = CFNotificationCenterGetLocalCenter();
990     ASSERT(center);
991
992     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemDidPlayToEndTimeNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
993     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemStatusChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
994     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemTracksChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
995     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemSeekableTimeRangesChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
996     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemLoadedTimeRangesChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
997     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemIsPlaybackLikelyToKeepUpChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
998     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemIsPlaybackBufferEmptyChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
999     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemIsPlaybackBufferFullChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
1000
1001     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, CACFContextNeedsFlushNotification(), 0, CFNotificationSuspensionBehaviorDeliverImmediately);
1002 }
1003
1004 void AVFWrapper::periodicTimeObserverCallback(AVCFPlayerRef, CMTime cmTime, void* context)
1005 {
1006     MutexLocker locker(mapLock());
1007     AVFWrapper* self = avfWrapperForCallbackContext(context);
1008     if (!self) {
1009         LOG(Media, "AVFWrapper::periodicTimeObserverCallback invoked for deleted AVFWrapper %d", reinterpret_cast<uintptr_t>(context));
1010         return;
1011     }
1012
1013     double time = std::max(0.0, CMTimeGetSeconds(cmTime)); // Clamp to zero, negative values are sometimes reported.
1014     self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::PlayerTimeChanged, time);
1015 }
1016
1017 void AVFWrapper::notificationCallback(CFNotificationCenterRef, void* observer, CFStringRef propertyName, const void* object, CFDictionaryRef)
1018 {
1019     MutexLocker locker(mapLock());
1020     AVFWrapper* self = avfWrapperForCallbackContext(observer);
1021     
1022     if (!self) {
1023         LOG(Media, "AVFWrapper::notificationCallback invoked for deleted AVFWrapper %d", reinterpret_cast<uintptr_t>(observer));
1024         return;
1025     }
1026
1027 #if !LOG_DISABLED
1028     char notificationName[256];
1029     CFStringGetCString(propertyName, notificationName, sizeof(notificationName), kCFStringEncodingASCII);
1030     LOG(Media, "AVFWrapper::notificationCallback(%p) %s", self, notificationName);
1031 #endif
1032
1033     if (CFEqual(propertyName, AVCFPlayerItemDidPlayToEndTimeNotification))
1034         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemDidPlayToEndTime);
1035     else if (CFEqual(propertyName, AVCFPlayerItemTracksChangedNotification))
1036         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemTracksChanged);
1037     else if (CFEqual(propertyName, AVCFPlayerItemStatusChangedNotification)) {
1038         AVCFURLAssetRef asset = AVCFPlayerItemGetAsset(self->avPlayerItem());
1039         if (asset)
1040             self->setAsset(asset);
1041         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemStatusChanged);
1042     } else if (CFEqual(propertyName, AVCFPlayerItemSeekableTimeRangesChangedNotification))
1043         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemSeekableTimeRangesChanged);
1044     else if (CFEqual(propertyName, AVCFPlayerItemLoadedTimeRangesChangedNotification))
1045         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemLoadedTimeRangesChanged);
1046     else if (CFEqual(propertyName, AVCFPlayerItemPresentationSizeChangedNotification))
1047         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemPresentationSizeChanged);
1048     else if (CFEqual(propertyName, AVCFPlayerItemIsPlaybackLikelyToKeepUpChangedNotification))
1049         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemIsPlaybackLikelyToKeepUpChanged);
1050     else if (CFEqual(propertyName, AVCFPlayerItemIsPlaybackBufferEmptyChangedNotification))
1051         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemIsPlaybackBufferEmptyChanged);
1052     else if (CFEqual(propertyName, AVCFPlayerItemIsPlaybackBufferFullChangedNotification))
1053         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemIsPlaybackBufferFullChanged);
1054     else if (CFEqual(propertyName, AVCFPlayerRateChangedNotification))
1055         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::PlayerRateChanged);
1056     else if (CFEqual(propertyName, CACFContextNeedsFlushNotification()))
1057         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ContentsNeedsDisplay);
1058     else
1059         ASSERT_NOT_REACHED();
1060 }
1061
1062 void AVFWrapper::loadPlayableCompletionCallback(AVCFAssetRef, void* context)
1063 {
1064     MutexLocker locker(mapLock());
1065     AVFWrapper* self = avfWrapperForCallbackContext(context);
1066     if (!self) {
1067         LOG(Media, "AVFWrapper::loadPlayableCompletionCallback invoked for deleted AVFWrapper %d", reinterpret_cast<uintptr_t>(context));
1068         return;
1069     }
1070
1071     LOG(Media, "AVFWrapper::loadPlayableCompletionCallback(%p)", self);
1072     self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::AssetPlayabilityKnown);
1073 }
1074
1075 void AVFWrapper::checkPlayability()
1076 {
1077     LOG(Media, "AVFWrapper::checkPlayability(%p)", this);
1078
1079     static CFArrayRef propertyKeyName;
1080     if (!propertyKeyName) {
1081         static const CFStringRef keyNames[] = { 
1082             AVCFAssetPropertyPlayable
1083         };
1084         propertyKeyName = CFArrayCreate(0, (const void**)keyNames, sizeof(keyNames) / sizeof(keyNames[0]), &kCFTypeArrayCallBacks);
1085     }
1086
1087     AVCFAssetLoadValuesAsynchronouslyForProperties(avAsset(), propertyKeyName, loadPlayableCompletionCallback, callbackContext());
1088 }
1089
1090 void AVFWrapper::loadMetadataCompletionCallback(AVCFAssetRef, void* context)
1091 {
1092     MutexLocker locker(mapLock());
1093     AVFWrapper* self = avfWrapperForCallbackContext(context);
1094     if (!self) {
1095         LOG(Media, "AVFWrapper::loadMetadataCompletionCallback invoked for deleted AVFWrapper %d", reinterpret_cast<uintptr_t>(context));
1096         return;
1097     }
1098
1099     LOG(Media, "AVFWrapper::loadMetadataCompletionCallback(%p)", self);
1100     self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::AssetMetadataLoaded);
1101 }
1102
1103 void AVFWrapper::beginLoadingMetadata()
1104 {
1105     ASSERT(avAsset());
1106     LOG(Media, "AVFWrapper::beginLoadingMetadata(%p) - requesting metadata loading", this);
1107     AVCFAssetLoadValuesAsynchronouslyForProperties(avAsset(), metadataKeyNames(), loadMetadataCompletionCallback, callbackContext());
1108 }
1109
1110 void AVFWrapper::seekCompletedCallback(AVCFPlayerItemRef, Boolean finished, void* context)
1111 {
1112     MutexLocker locker(mapLock());
1113     AVFWrapper* self = avfWrapperForCallbackContext(context);
1114     if (!self) {
1115         LOG(Media, "AVFWrapper::seekCompletedCallback invoked for deleted AVFWrapper %d", reinterpret_cast<uintptr_t>(context));
1116         return;
1117     }
1118
1119     LOG(Media, "AVFWrapper::seekCompletedCallback(%p)", self);
1120     self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::SeekCompleted, static_cast<bool>(finished));
1121 }
1122
1123 void AVFWrapper::seekToTime(float time)
1124 {
1125     ASSERT(avPlayerItem());
1126     AVCFPlayerItemSeekToTimeWithToleranceAndCompletionCallback(avPlayerItem(), CMTimeMakeWithSeconds(time, 600),
1127         kCMTimeZero, kCMTimeZero, &seekCompletedCallback, callbackContext());
1128 }
1129
1130 void AVFWrapper::setAsset(AVCFURLAssetRef asset)
1131 {
1132     if (asset == avAsset())
1133         return;
1134
1135     AVCFAssetCancelLoading(avAsset());
1136     m_avAsset.adoptCF(asset);
1137 }
1138
1139 PlatformLayer* AVFWrapper::platformLayer()
1140 {
1141     if (m_videoLayerWrapper)
1142         return m_videoLayerWrapper->platformLayer();
1143
1144     if (!videoLayer())
1145         return 0;
1146
1147     // Create a PlatformCALayer so we can resize the video layer to match the element size.
1148     m_layerClient = adoptPtr(new LayerClient(this));
1149     if (!m_layerClient)
1150         return 0;
1151
1152     m_videoLayerWrapper = PlatformCALayer::create(PlatformCALayer::LayerTypeLayer, m_layerClient.get());
1153     if (!m_videoLayerWrapper)
1154         return 0;
1155
1156     CACFLayerRef layerRef = AVCFPlayerLayerCopyCACFLayer(m_avCFVideoLayer.get());
1157     m_caVideoLayer.adoptCF(layerRef);
1158
1159     CACFLayerInsertSublayer(m_videoLayerWrapper->platformLayer(), m_caVideoLayer.get(), 0);
1160     m_videoLayerWrapper->setAnchorPoint(FloatPoint3D());
1161     m_videoLayerWrapper->setNeedsLayout();
1162
1163     return m_videoLayerWrapper->platformLayer();
1164 }
1165
1166 void AVFWrapper::createAVCFVideoLayer()
1167 {
1168     if (!avPlayer() || m_avCFVideoLayer)
1169         return;
1170
1171     // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration().
1172     m_avCFVideoLayer.adoptCF(AVCFPlayerLayerCreateWithAVCFPlayer(kCFAllocatorDefault, avPlayer(), m_notificationQueue));
1173     LOG(Media, "AVFWrapper::createAVCFVideoLayer(%p) - returning %p", this, videoLayer());
1174 }
1175
1176 void AVFWrapper::destroyVideoLayer()
1177 {
1178     LOG(Media, "AVFWrapper::destroyVideoLayer(%p)", this);
1179     m_layerClient = nullptr;
1180     m_caVideoLayer = 0;
1181     m_videoLayerWrapper = 0;
1182     if (!m_avCFVideoLayer.get())
1183         return;
1184
1185     AVCFPlayerLayerSetPlayer((AVCFPlayerLayerRef)m_avCFVideoLayer.get(), 0);
1186     m_avCFVideoLayer = 0;
1187 }
1188
1189 void AVFWrapper::setVideoLayerNeedsCommit()
1190 {
1191     if (m_videoLayerWrapper)
1192         m_videoLayerWrapper->setNeedsCommit();
1193 }
1194
1195 void AVFWrapper::setVideoLayerHidden(bool value)
1196 {
1197     if (m_videoLayerWrapper)
1198         m_videoLayerWrapper->setHidden(value);
1199 }
1200
1201 void AVFWrapper::createImageGenerator()
1202 {
1203     if (!avAsset() || m_imageGenerator)
1204         return;
1205
1206     m_imageGenerator.adoptCF(AVCFAssetImageGeneratorCreateWithAsset(kCFAllocatorDefault, avAsset()));
1207
1208     AVCFAssetImageGeneratorSetApertureMode(m_imageGenerator.get(), AVCFAssetImageGeneratorApertureModeCleanAperture);
1209     AVCFAssetImageGeneratorSetRequestedTimeToleranceBefore(m_imageGenerator.get(), kCMTimeZero);
1210     AVCFAssetImageGeneratorSetRequestedTimeToleranceAfter(m_imageGenerator.get(), kCMTimeZero);
1211     AVCFAssetImageGeneratorSetAppliesPreferredTrackTransform(m_imageGenerator.get(), true);
1212
1213     LOG(Media, "AVFWrapper::createImageGenerator(%p) - returning %p", this, m_imageGenerator.get());
1214 }
1215
1216 void AVFWrapper::destroyImageGenerator()
1217 {
1218     LOG(Media, "AVFWrapper::destroyImageGenerator(%p)", this);
1219     m_imageGenerator = 0;
1220 }
1221
1222 RetainPtr<CGImageRef> AVFWrapper::createImageForTimeInRect(float time, const IntRect& rect)
1223 {
1224     if (!m_imageGenerator)
1225         return 0;
1226
1227 #if !LOG_DISABLED
1228     double start = WTF::currentTime();
1229 #endif
1230
1231     AVCFAssetImageGeneratorSetMaximumSize(m_imageGenerator.get(), CGSize(rect.size()));
1232     CGImageRef image = AVCFAssetImageGeneratorCopyCGImageAtTime(m_imageGenerator.get(), CMTimeMakeWithSeconds(time, 600), 0, 0);
1233
1234 #if !LOG_DISABLED
1235     double duration = WTF::currentTime() - start;
1236     LOG(Media, "AVFWrapper::createImageForTimeInRect(%p) - creating image took %.4f", this, narrowPrecisionToFloat(duration));
1237 #endif
1238
1239     return image;
1240 }
1241
1242 void LayerClient::platformCALayerLayoutSublayersOfLayer(PlatformCALayer* wrapperLayer)
1243 {
1244     ASSERT(m_parent);
1245     ASSERT(m_parent->videoLayerWrapper() == wrapperLayer->platformLayer());
1246
1247     CGRect bounds = wrapperLayer->bounds();
1248     CGPoint anchor = CACFLayerGetAnchorPoint(m_parent->caVideoLayer());
1249     FloatPoint position(bounds.size.width * anchor.x, bounds.size.height * anchor.y); 
1250
1251     CACFLayerSetPosition(m_parent->caVideoLayer(), position);
1252     CACFLayerSetBounds(m_parent->caVideoLayer(), bounds);
1253 }
1254
1255 } // namespace WebCore
1256
1257 #else
1258 // AVFoundation should always be enabled for Apple production builds.
1259 #if __PRODUCTION__ && !USE(AVFOUNDATION)
1260 #error AVFoundation is not enabled!
1261 #endif // __PRODUCTION__ && !USE(AVFOUNDATION)
1262 #endif // USE(AVFOUNDATION)
1263 #endif // PLATFORM(WIN) && ENABLE(VIDEO)