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