Unreviewed build failure; update MediaPlayerPrivateAVFFoundationCF::seekToTime after...
[WebKit-https.git] / Source / WebCore / platform / graphics / avfoundation / cf / MediaPlayerPrivateAVFoundationCF.cpp
1 /*
2  * Copyright (C) 2011, 2012, 2013 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 #if HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT)
40 #include "InbandTextTrackPrivateAVCF.h"
41 #else
42 #include "InbandTextTrackPrivateLegacyAVCF.h"
43 #endif
44 #include "URL.h"
45 #include "Logging.h"
46 #include "PlatformCALayerWin.h"
47 #include "SoftLinking.h"
48 #include "TimeRanges.h"
49
50 #include <AVFoundationCF/AVCFPlayerItem.h>
51 #if HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT)
52 #include <AVFoundationCF/AVCFPlayerItemLegibleOutput.h>
53 #endif
54 #include <AVFoundationCF/AVCFPlayerLayer.h>
55 #include <AVFoundationCF/AVFoundationCF.h>
56 #include <CoreMedia/CoreMedia.h>
57 #include <d3d9.h>
58 #include <delayimp.h>
59 #include <dispatch/dispatch.h>
60 #include <wtf/HashMap.h>
61 #include <wtf/Threading.h>
62 #include <wtf/text/CString.h>
63
64 // The softlink header files must be included after the AVCF and CoreMedia header files.
65 #include "AVFoundationCFSoftLinking.h"
66 #include "CoreMediaSoftLinking.h"
67
68 // We don't bother softlinking against libdispatch since it's already been loaded by AAS.
69 #ifdef DEBUG_ALL
70 #pragma comment(lib, "libdispatch_debug.lib")
71 #else
72 #pragma comment(lib, "libdispatch.lib")
73 #endif
74
75 using namespace std;
76
77 namespace WebCore {
78
79 class LayerClient;
80
81 class AVFWrapper {
82 public:
83     AVFWrapper(MediaPlayerPrivateAVFoundationCF*);
84     ~AVFWrapper();
85
86     void scheduleDisconnectAndDelete();
87
88     void createAVCFVideoLayer();
89     void destroyVideoLayer();
90     PlatformLayer* platformLayer();
91
92     CACFLayerRef caVideoLayer() { return m_caVideoLayer.get(); }
93     PlatformLayer* videoLayerWrapper() { return m_videoLayerWrapper ? m_videoLayerWrapper->platformLayer() : 0; };
94     void setVideoLayerNeedsCommit();
95     void setVideoLayerHidden(bool);
96
97     void createImageGenerator();
98     void destroyImageGenerator();
99     RetainPtr<CGImageRef> createImageForTimeInRect(float, const IntRect&);
100
101     void createAssetForURL(const String& url);
102     void setAsset(AVCFURLAssetRef);
103     
104     void createPlayer(IDirect3DDevice9*);
105     void createPlayerItem();
106     
107     void checkPlayability();
108     void beginLoadingMetadata();
109     
110     void seekToTime(double, double, double);
111     void updateVideoLayerGravity();
112
113     void setCurrentTrack(InbandTextTrackPrivateAVF*);
114     InbandTextTrackPrivateAVF* currentTrack() const { return m_currentTrack; }
115
116 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP) && HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT)
117     static void legibleOutputCallback(void* context, AVCFPlayerItemLegibleOutputRef, CFArrayRef attributedString, CFArrayRef nativeSampleBuffers, CMTime itemTime);
118     static void processCue(void* context);
119 #endif
120     static void loadMetadataCompletionCallback(AVCFAssetRef, void*);
121     static void loadPlayableCompletionCallback(AVCFAssetRef, void*);
122     static void periodicTimeObserverCallback(AVCFPlayerRef, CMTime, void*);
123     static void seekCompletedCallback(AVCFPlayerItemRef, Boolean, void*);
124     static void notificationCallback(CFNotificationCenterRef, void*, CFStringRef, const void*, CFDictionaryRef);
125
126     inline AVCFPlayerLayerRef videoLayer() const { return (AVCFPlayerLayerRef)m_avCFVideoLayer.get(); }
127     inline AVCFPlayerRef avPlayer() const { return (AVCFPlayerRef)m_avPlayer.get(); }
128     inline AVCFURLAssetRef avAsset() const { return (AVCFURLAssetRef)m_avAsset.get(); }
129     inline AVCFPlayerItemRef avPlayerItem() const { return (AVCFPlayerItemRef)m_avPlayerItem.get(); }
130     inline AVCFPlayerObserverRef timeObserver() const { return (AVCFPlayerObserverRef)m_timeObserver.get(); }
131     inline AVCFAssetImageGeneratorRef imageGenerator() const { return m_imageGenerator.get(); }
132 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP) && HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT)
133     inline AVCFPlayerItemLegibleOutputRef legibleOutput() const { return m_legibleOutput.get(); }
134     AVCFMediaSelectionGroupRef safeMediaSelectionGroupForLegibleMedia() const;
135 #endif
136     inline dispatch_queue_t dispatchQueue() const { return m_notificationQueue; }
137
138 private:
139     inline void* callbackContext() const { return reinterpret_cast<void*>(m_objectID); }
140
141     static Mutex& mapLock();
142     static HashMap<uintptr_t, AVFWrapper*>& map();
143     static AVFWrapper* avfWrapperForCallbackContext(void*);
144     void addToMap();
145     void removeFromMap() const;
146
147     static void disconnectAndDeleteAVFWrapper(void*);
148
149     static uintptr_t s_nextAVFWrapperObjectID;
150     uintptr_t m_objectID;
151
152     MediaPlayerPrivateAVFoundationCF* m_owner;
153
154     RetainPtr<AVCFPlayerRef> m_avPlayer;
155     RetainPtr<AVCFURLAssetRef> m_avAsset;
156     RetainPtr<AVCFPlayerItemRef> m_avPlayerItem;
157     RetainPtr<AVCFPlayerLayerRef> m_avCFVideoLayer;
158     RetainPtr<AVCFPlayerObserverRef> m_timeObserver;
159     RetainPtr<AVCFAssetImageGeneratorRef> m_imageGenerator;
160 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP) && HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT)
161     RetainPtr<AVCFPlayerItemLegibleOutputRef> m_legibleOutput;
162     RetainPtr<AVCFMediaSelectionGroupRef> m_selectionGroup;
163 #endif
164     dispatch_queue_t m_notificationQueue;
165
166     mutable RetainPtr<CACFLayerRef> m_caVideoLayer;
167     RefPtr<PlatformCALayer> m_videoLayerWrapper;
168
169     OwnPtr<LayerClient> m_layerClient;
170     COMPtr<IDirect3DDevice9Ex> m_d3dDevice;
171
172     InbandTextTrackPrivateAVF* m_currentTrack;
173 };
174
175 uintptr_t AVFWrapper::s_nextAVFWrapperObjectID;
176
177 class LayerClient : public PlatformCALayerClient {
178 public:
179     LayerClient(AVFWrapper* parent) : m_parent(parent) { }
180     virtual ~LayerClient() { m_parent = 0; }
181
182 private:
183     virtual void platformCALayerLayoutSublayersOfLayer(PlatformCALayer*);
184     virtual bool platformCALayerRespondsToLayoutChanges() const { return true; }
185
186     virtual void platformCALayerAnimationStarted(CFTimeInterval beginTime) { }
187     virtual GraphicsLayer::CompositingCoordinatesOrientation platformCALayerContentsOrientation() const { return GraphicsLayer::CompositingCoordinatesBottomUp; }
188     virtual void platformCALayerPaintContents(PlatformCALayer*, GraphicsContext&, const IntRect& inClip) { }
189     virtual bool platformCALayerShowDebugBorders() const { return false; }
190     virtual bool platformCALayerShowRepaintCounter(PlatformCALayer*) const { return false; }
191     virtual int platformCALayerIncrementRepaintCount(PlatformCALayer*) { return 0; }
192
193     virtual bool platformCALayerContentsOpaque() const { return false; }
194     virtual bool platformCALayerDrawsContent() const { return false; }
195     virtual void platformCALayerLayerDidDisplay(PlatformLayer*) { }
196     virtual float platformCALayerDeviceScaleFactor() const { return 1; }
197
198     AVFWrapper* m_parent;
199 };
200
201 #if !LOG_DISABLED
202 static const char* boolString(bool val)
203 {
204     return val ? "true" : "false";
205 }
206 #endif
207
208 static CFArrayRef createMetadataKeyNames()
209 {
210     static const CFStringRef keyNames[] = {
211         AVCFAssetPropertyDuration,
212         AVCFAssetPropertyNaturalSize,
213         AVCFAssetPropertyPreferredTransform,
214         AVCFAssetPropertyPreferredRate,
215         AVCFAssetPropertyPlayable,
216         AVCFAssetPropertyTracks,
217 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
218         AVCFAssetPropertyAvailableMediaCharacteristicsWithMediaSelectionOptions,
219 #endif
220     };
221     
222     return CFArrayCreate(0, (const void**)keyNames, sizeof(keyNames) / sizeof(keyNames[0]), &kCFTypeArrayCallBacks);
223 }
224
225 static CFArrayRef metadataKeyNames()
226 {
227     static CFArrayRef keys = createMetadataKeyNames();
228     return keys;
229 }
230
231 // FIXME: It would be better if AVCFTimedMetadataGroup.h exported this key.
232 static CFStringRef CMTimeRangeStartKey()
233 {
234     DEFINE_STATIC_LOCAL(CFStringRef, key, (CFSTR("start")));
235     return key;
236 }
237
238 // FIXME: It would be better if AVCFTimedMetadataGroup.h exported this key.
239 static CFStringRef CMTimeRangeDurationKey()
240 {
241     DEFINE_STATIC_LOCAL(CFStringRef, key, (CFSTR("duration")));
242     return key;
243 }
244
245 // FIXME: It would be better if AVCF exported this notification name.
246 static CFStringRef CACFContextNeedsFlushNotification()
247 {
248     DEFINE_STATIC_LOCAL(CFStringRef, name, (CFSTR("kCACFContextNeedsFlushNotification")));
249     return name;
250 }
251
252 // Define AVCF object accessors as inline functions here instead of in MediaPlayerPrivateAVFoundationCF so we don't have
253 // to include the AVCF headers in MediaPlayerPrivateAVFoundationCF.h
254 inline AVCFPlayerLayerRef videoLayer(AVFWrapper* wrapper)
255
256     return wrapper ? wrapper->videoLayer() : 0; 
257 }
258
259 inline AVCFPlayerRef avPlayer(AVFWrapper* wrapper)
260
261     return wrapper ? wrapper->avPlayer() : 0; 
262 }
263
264 inline AVCFURLAssetRef avAsset(AVFWrapper* wrapper)
265
266     return wrapper ? wrapper->avAsset() : 0; 
267 }
268
269 inline AVCFPlayerItemRef avPlayerItem(AVFWrapper* wrapper)
270
271     return wrapper ? wrapper->avPlayerItem() : 0; 
272 }
273
274 inline AVCFAssetImageGeneratorRef imageGenerator(AVFWrapper* wrapper)
275
276     return wrapper ? wrapper->imageGenerator() : 0; 
277 }
278
279 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP) && HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT)
280 inline AVCFPlayerItemLegibleOutputRef avLegibleOutput(AVFWrapper* wrapper)
281 {
282     return wrapper ? wrapper->legibleOutput() : 0;
283 }
284
285 inline AVCFMediaSelectionGroupRef safeMediaSelectionGroupForLegibleMedia(AVFWrapper* wrapper)
286 {
287     return wrapper ? wrapper->safeMediaSelectionGroupForLegibleMedia() : 0;
288 }
289 #endif
290
291 PassOwnPtr<MediaPlayerPrivateInterface> MediaPlayerPrivateAVFoundationCF::create(MediaPlayer* player) 
292
293     return adoptPtr(new MediaPlayerPrivateAVFoundationCF(player));
294 }
295
296 void MediaPlayerPrivateAVFoundationCF::registerMediaEngine(MediaEngineRegistrar registrar)
297 {
298     if (isAvailable())
299         registrar(create, getSupportedTypes, supportsType, 0, 0, 0);
300 }
301
302 MediaPlayerPrivateAVFoundationCF::MediaPlayerPrivateAVFoundationCF(MediaPlayer* player)
303     : MediaPlayerPrivateAVFoundation(player)
304     , m_avfWrapper(0)
305     , m_videoFrameHasDrawn(false)
306 {
307     LOG(Media, "MediaPlayerPrivateAVFoundationCF::MediaPlayerPrivateAVFoundationCF(%p)", this);
308 }
309
310 MediaPlayerPrivateAVFoundationCF::~MediaPlayerPrivateAVFoundationCF()
311 {
312     LOG(Media, "MediaPlayerPrivateAVFoundationCF::~MediaPlayerPrivateAVFoundationCF(%p)", this);
313     cancelLoad();
314 }
315
316 void MediaPlayerPrivateAVFoundationCF::cancelLoad()
317 {
318     LOG(Media, "MediaPlayerPrivateAVFoundationCF::cancelLoad(%p)", this);
319
320     // Do nothing when our cancellation of pending loading calls its completion handler
321     setDelayCallbacks(true);
322     setIgnoreLoadStateChanges(true);
323
324     tearDownVideoRendering();
325
326     clearTextTracks();
327
328     if (m_avfWrapper) {
329         // The AVCF objects have to be destroyed on the same dispatch queue used for notifications, so schedule a call to 
330         // disconnectAndDeleteAVFWrapper on that queue. 
331         m_avfWrapper->scheduleDisconnectAndDelete();
332         m_avfWrapper = 0;
333     }
334
335     setIgnoreLoadStateChanges(false);
336     setDelayCallbacks(false);
337 }
338
339 void MediaPlayerPrivateAVFoundationCF::updateVideoLayerGravity()
340 {
341     ASSERT(supportsAcceleratedRendering());
342
343     if (m_avfWrapper)
344         m_avfWrapper->updateVideoLayerGravity();
345 }
346
347 bool MediaPlayerPrivateAVFoundationCF::hasLayerRenderer() const
348 {
349     return videoLayer(m_avfWrapper);
350 }
351
352 bool MediaPlayerPrivateAVFoundationCF::hasContextRenderer() const
353 {
354     return imageGenerator(m_avfWrapper);
355 }
356
357 void MediaPlayerPrivateAVFoundationCF::createContextVideoRenderer()
358 {
359     LOG(Media, "MediaPlayerPrivateAVFoundationCF::createContextVideoRenderer(%p)", this);
360
361     if (imageGenerator(m_avfWrapper))
362         return;
363
364     if (m_avfWrapper)
365         m_avfWrapper->createImageGenerator();
366 }
367
368 void MediaPlayerPrivateAVFoundationCF::destroyContextVideoRenderer()
369 {
370     if (m_avfWrapper)
371         m_avfWrapper->destroyImageGenerator();
372 }
373
374 void MediaPlayerPrivateAVFoundationCF::createVideoLayer()
375 {
376     ASSERT(supportsAcceleratedRendering());
377
378     if (m_avfWrapper)
379         m_avfWrapper->createAVCFVideoLayer();
380 }
381
382 void MediaPlayerPrivateAVFoundationCF::destroyVideoLayer()
383 {
384     LOG(Media, "MediaPlayerPrivateAVFoundationCF::destroyVideoLayer(%p) - destroying %p", this, videoLayer(m_avfWrapper));
385     if (m_avfWrapper)
386         m_avfWrapper->destroyVideoLayer();
387 }
388
389 bool MediaPlayerPrivateAVFoundationCF::hasAvailableVideoFrame() const
390 {
391     return (m_videoFrameHasDrawn || (videoLayer(m_avfWrapper) && AVCFPlayerLayerIsReadyForDisplay(videoLayer(m_avfWrapper))));
392 }
393
394 void MediaPlayerPrivateAVFoundationCF::setCurrentTrack(InbandTextTrackPrivateAVF* track)
395 {
396     if (m_avfWrapper)
397         m_avfWrapper->setCurrentTrack(track);
398 }
399
400 InbandTextTrackPrivateAVF* MediaPlayerPrivateAVFoundationCF::currentTrack() const
401 {
402     if (m_avfWrapper)
403         return m_avfWrapper->currentTrack();
404
405     return 0;
406 }
407
408 void MediaPlayerPrivateAVFoundationCF::createAVAssetForURL(const String& url)
409 {
410     ASSERT(!m_avfWrapper);
411
412     setDelayCallbacks(true);
413
414     m_avfWrapper = new AVFWrapper(this);
415     m_avfWrapper->createAssetForURL(url);
416     setDelayCallbacks(false);
417 }
418
419 void MediaPlayerPrivateAVFoundationCF::createAVPlayer()
420 {
421     ASSERT(m_avfWrapper);
422     
423     setDelayCallbacks(true);
424     m_avfWrapper->createPlayer(reinterpret_cast<IDirect3DDevice9*>(player()->graphicsDeviceAdapter()));
425     setDelayCallbacks(false);
426 }
427
428 void MediaPlayerPrivateAVFoundationCF::createAVPlayerItem()
429 {
430     ASSERT(m_avfWrapper);
431     
432     setDelayCallbacks(true);
433     m_avfWrapper->createPlayerItem();
434
435     setDelayCallbacks(false);
436 }
437
438 void MediaPlayerPrivateAVFoundationCF::checkPlayability()
439 {
440     ASSERT(m_avfWrapper);
441     m_avfWrapper->checkPlayability();
442 }
443
444 void MediaPlayerPrivateAVFoundationCF::beginLoadingMetadata()
445 {
446     ASSERT(m_avfWrapper);
447     m_avfWrapper->beginLoadingMetadata();
448 }
449
450 MediaPlayerPrivateAVFoundation::ItemStatus MediaPlayerPrivateAVFoundationCF::playerItemStatus() const
451 {
452     if (!avPlayerItem(m_avfWrapper))
453         return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusDoesNotExist;
454
455     AVCFPlayerItemStatus status = AVCFPlayerItemGetStatus(avPlayerItem(m_avfWrapper), 0);
456     if (status == AVCFPlayerItemStatusUnknown)
457         return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusUnknown;
458     if (status == AVCFPlayerItemStatusFailed)
459         return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusFailed;
460     if (AVCFPlayerItemIsPlaybackLikelyToKeepUp(avPlayerItem(m_avfWrapper)))
461         return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackLikelyToKeepUp;
462     if (AVCFPlayerItemIsPlaybackBufferFull(avPlayerItem(m_avfWrapper)))
463         return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferFull;
464     if (AVCFPlayerItemIsPlaybackBufferEmpty(avPlayerItem(m_avfWrapper)))
465         return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferEmpty;
466     return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusReadyToPlay;
467 }
468
469 PlatformMedia MediaPlayerPrivateAVFoundationCF::platformMedia() const
470 {
471     LOG(Media, "MediaPlayerPrivateAVFoundationCF::platformMedia(%p)", this);
472     PlatformMedia pm;
473     pm.type = PlatformMedia::AVFoundationCFMediaPlayerType;
474     pm.media.avcfMediaPlayer = (AVCFPlayer*)avPlayer(m_avfWrapper);
475     return pm;
476 }
477
478 PlatformLayer* MediaPlayerPrivateAVFoundationCF::platformLayer() const
479 {
480     if (!m_avfWrapper)
481         return 0;
482
483     return m_avfWrapper->platformLayer();
484 }
485
486 void MediaPlayerPrivateAVFoundationCF::platformSetVisible(bool isVisible)
487 {
488     if (!m_avfWrapper)
489         return;
490     
491     // FIXME: We use a CATransaction here on the Mac, we need to figure out why this was done there and
492     // whether we're affected by the same issue.
493     setDelayCallbacks(true);
494     m_avfWrapper->setVideoLayerHidden(!isVisible);    
495     if (!isVisible)
496         tearDownVideoRendering();
497     setDelayCallbacks(false);
498 }
499
500 void MediaPlayerPrivateAVFoundationCF::platformPlay()
501 {
502     LOG(Media, "MediaPlayerPrivateAVFoundationCF::play(%p)", this);
503     if (!metaDataAvailable() || !avPlayer(m_avfWrapper))
504         return;
505
506     setDelayCallbacks(true);
507     AVCFPlayerSetRate(avPlayer(m_avfWrapper), requestedRate());
508     setDelayCallbacks(false);
509 }
510
511 void MediaPlayerPrivateAVFoundationCF::platformPause()
512 {
513     LOG(Media, "MediaPlayerPrivateAVFoundationCF::pause(%p)", this);
514     if (!metaDataAvailable() || !avPlayer(m_avfWrapper))
515         return;
516
517     setDelayCallbacks(true);
518     AVCFPlayerSetRate(avPlayer(m_avfWrapper), 0);
519     setDelayCallbacks(false);
520 }
521
522 float MediaPlayerPrivateAVFoundationCF::platformDuration() const
523 {
524     if (!metaDataAvailable() || !avAsset(m_avfWrapper))
525         return 0;
526
527     CMTime cmDuration;
528
529     // Check the AVItem if we have one and it has loaded duration, some assets never report duration.
530     if (avPlayerItem(m_avfWrapper) && playerItemStatus() >= MediaPlayerAVPlayerItemStatusReadyToPlay)
531         cmDuration = AVCFPlayerItemGetDuration(avPlayerItem(m_avfWrapper));
532     else
533         cmDuration = AVCFAssetGetDuration(avAsset(m_avfWrapper));
534
535     if (CMTIME_IS_NUMERIC(cmDuration))
536         return narrowPrecisionToFloat(CMTimeGetSeconds(cmDuration));
537
538     if (CMTIME_IS_INDEFINITE(cmDuration))
539         return numeric_limits<float>::infinity();
540
541     LOG(Media, "MediaPlayerPrivateAVFoundationCF::platformDuration(%p) - invalid duration, returning %.0f", this, static_cast<float>(MediaPlayer::invalidTime()));
542     return static_cast<float>(MediaPlayer::invalidTime());
543 }
544
545 float MediaPlayerPrivateAVFoundationCF::currentTime() const
546 {
547     if (!metaDataAvailable() || !avPlayerItem(m_avfWrapper))
548         return 0;
549
550     CMTime itemTime = AVCFPlayerItemGetCurrentTime(avPlayerItem(m_avfWrapper));
551     if (CMTIME_IS_NUMERIC(itemTime))
552         return max(narrowPrecisionToFloat(CMTimeGetSeconds(itemTime)), 0.0f);
553
554     return 0;
555 }
556
557 void MediaPlayerPrivateAVFoundationCF::seekToTime(double time, double negativeTolerance, double positiveTolerance)
558 {
559     if (!m_avfWrapper)
560         return;
561     
562     // seekToTime generates several event callbacks, update afterwards.
563     setDelayCallbacks(true);
564     m_avfWrapper->seekToTime(time, negativeTolerance, positiveTolerance);
565     setDelayCallbacks(false);
566 }
567
568 void MediaPlayerPrivateAVFoundationCF::setVolume(float volume)
569 {
570     if (!metaDataAvailable() || !avPlayer(m_avfWrapper))
571         return;
572
573     AVCFPlayerSetVolume(avPlayer(m_avfWrapper), volume);
574 }
575
576 void MediaPlayerPrivateAVFoundationCF::setClosedCaptionsVisible(bool closedCaptionsVisible)
577 {
578     if (!metaDataAvailable() || !avPlayer(m_avfWrapper))
579         return;
580
581     LOG(Media, "MediaPlayerPrivateAVFoundationCF::setClosedCaptionsVisible(%p) - setting to %s", this, boolString(closedCaptionsVisible));
582     AVCFPlayerSetClosedCaptionDisplayEnabled(avPlayer(m_avfWrapper), closedCaptionsVisible);
583 }
584
585 void MediaPlayerPrivateAVFoundationCF::updateRate()
586 {
587     LOG(Media, "MediaPlayerPrivateAVFoundationCF::updateRate(%p)", this);
588     if (!metaDataAvailable() || !avPlayer(m_avfWrapper))
589         return;
590
591     setDelayCallbacks(true);
592     AVCFPlayerSetRate(avPlayer(m_avfWrapper), requestedRate());
593     setDelayCallbacks(false);
594 }
595
596 float MediaPlayerPrivateAVFoundationCF::rate() const
597 {
598     if (!metaDataAvailable() || !avPlayer(m_avfWrapper))
599         return 0;
600
601     setDelayCallbacks(true);
602     float currentRate = AVCFPlayerGetRate(avPlayer(m_avfWrapper));
603     setDelayCallbacks(false);
604
605     return currentRate;
606 }
607
608 static bool timeRangeIsValidAndNotEmpty(CMTime start, CMTime duration)
609 {
610     // Is the range valid?
611     if (!CMTIME_IS_VALID(start) || !CMTIME_IS_VALID(duration) || duration.epoch || duration.value < 0)
612         return false;
613
614     if (CMTIME_COMPARE_INLINE(duration, ==, kCMTimeZero))
615         return false;
616
617     return true;
618 }
619
620 PassRefPtr<TimeRanges> MediaPlayerPrivateAVFoundationCF::platformBufferedTimeRanges() const
621 {
622     RefPtr<TimeRanges> timeRanges = TimeRanges::create();
623
624     if (!avPlayerItem(m_avfWrapper))
625         return timeRanges.release();
626
627     RetainPtr<CFArrayRef> loadedRanges = adoptCF(AVCFPlayerItemCopyLoadedTimeRanges(avPlayerItem(m_avfWrapper)));
628     if (!loadedRanges)
629         return timeRanges.release();
630
631     CFIndex rangeCount = CFArrayGetCount(loadedRanges.get());
632     for (CFIndex i = 0; i < rangeCount; i++) {
633         CFDictionaryRef range = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(loadedRanges.get(), i));
634         CMTime start = CMTimeMakeFromDictionary(static_cast<CFDictionaryRef>(CFDictionaryGetValue(range, CMTimeRangeStartKey())));
635         CMTime duration = CMTimeMakeFromDictionary(static_cast<CFDictionaryRef>(CFDictionaryGetValue(range, CMTimeRangeDurationKey())));
636         
637         if (timeRangeIsValidAndNotEmpty(start, duration)) {
638             float rangeStart = narrowPrecisionToFloat(CMTimeGetSeconds(start));
639             float rangeEnd = narrowPrecisionToFloat(CMTimeGetSeconds(CMTimeAdd(start, duration)));
640             timeRanges->add(rangeStart, rangeEnd);
641         }
642     }
643
644     return timeRanges.release();
645 }
646
647 double MediaPlayerPrivateAVFoundationCF::platformMinTimeSeekable() const 
648
649     RetainPtr<CFArrayRef> seekableRanges = adoptCF(AVCFPlayerItemCopySeekableTimeRanges(avPlayerItem(m_avfWrapper)));
650     if (!seekableRanges) 
651         return 0; 
652
653     double minTimeSeekable = std::numeric_limits<double>::infinity(); 
654     bool hasValidRange = false; 
655     CFIndex rangeCount = CFArrayGetCount(seekableRanges.get());
656     for (CFIndex i = 0; i < rangeCount; i++) {
657         CFDictionaryRef range = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(seekableRanges.get(), i));
658         CMTime start = CMTimeMakeFromDictionary(static_cast<CFDictionaryRef>(CFDictionaryGetValue(range, CMTimeRangeStartKey())));
659         CMTime duration = CMTimeMakeFromDictionary(static_cast<CFDictionaryRef>(CFDictionaryGetValue(range, CMTimeRangeDurationKey())));
660         if (!timeRangeIsValidAndNotEmpty(start, duration))
661             continue;
662
663         hasValidRange = true; 
664         double startOfRange = CMTimeGetSeconds(start); 
665         if (minTimeSeekable > startOfRange) 
666             minTimeSeekable = startOfRange; 
667     } 
668     return hasValidRange ? minTimeSeekable : 0; 
669
670
671 double MediaPlayerPrivateAVFoundationCF::platformMaxTimeSeekable() const
672 {
673     if (!avPlayerItem(m_avfWrapper))
674         return 0;
675
676     RetainPtr<CFArrayRef> seekableRanges = adoptCF(AVCFPlayerItemCopySeekableTimeRanges(avPlayerItem(m_avfWrapper)));
677     if (!seekableRanges)
678         return 0;
679
680     double maxTimeSeekable = 0;
681     CFIndex rangeCount = CFArrayGetCount(seekableRanges.get());
682     for (CFIndex i = 0; i < rangeCount; i++) {
683         CFDictionaryRef range = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(seekableRanges.get(), i));
684         CMTime start = CMTimeMakeFromDictionary(static_cast<CFDictionaryRef>(CFDictionaryGetValue(range, CMTimeRangeStartKey())));
685         CMTime duration = CMTimeMakeFromDictionary(static_cast<CFDictionaryRef>(CFDictionaryGetValue(range, CMTimeRangeDurationKey())));
686         if (!timeRangeIsValidAndNotEmpty(start, duration))
687             continue;
688         
689         double endOfRange = CMTimeGetSeconds(CMTimeAdd(start, duration));
690         if (maxTimeSeekable < endOfRange)
691             maxTimeSeekable = endOfRange;
692     }
693
694     return maxTimeSeekable;   
695 }
696
697 float MediaPlayerPrivateAVFoundationCF::platformMaxTimeLoaded() const
698 {
699     if (!avPlayerItem(m_avfWrapper))
700         return 0;
701
702     RetainPtr<CFArrayRef> loadedRanges = adoptCF(AVCFPlayerItemCopyLoadedTimeRanges(avPlayerItem(m_avfWrapper)));
703     if (!loadedRanges)
704         return 0;
705
706     float maxTimeLoaded = 0;
707     CFIndex rangeCount = CFArrayGetCount(loadedRanges.get());
708     for (CFIndex i = 0; i < rangeCount; i++) {
709         CFDictionaryRef range = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(loadedRanges.get(), i));
710         CMTime start = CMTimeMakeFromDictionary(static_cast<CFDictionaryRef>(CFDictionaryGetValue(range, CMTimeRangeStartKey())));
711         CMTime duration = CMTimeMakeFromDictionary(static_cast<CFDictionaryRef>(CFDictionaryGetValue(range, CMTimeRangeDurationKey())));
712         if (!timeRangeIsValidAndNotEmpty(start, duration))
713             continue;
714         
715         float endOfRange = narrowPrecisionToFloat(CMTimeGetSeconds(CMTimeAdd(start, duration)));
716         if (maxTimeLoaded < endOfRange)
717             maxTimeLoaded = endOfRange;
718     }
719
720     return maxTimeLoaded;   
721 }
722
723 unsigned MediaPlayerPrivateAVFoundationCF::totalBytes() const
724 {
725     if (!metaDataAvailable() || !avAsset(m_avfWrapper))
726         return 0;
727
728     int64_t totalMediaSize = 0;
729     RetainPtr<CFArrayRef> tracks = adoptCF(AVCFAssetCopyAssetTracks(avAsset(m_avfWrapper)));
730     CFIndex trackCount = CFArrayGetCount(tracks.get());
731     for (CFIndex i = 0; i < trackCount; i++) {
732         AVCFAssetTrackRef assetTrack = (AVCFAssetTrackRef)CFArrayGetValueAtIndex(tracks.get(), i);
733         totalMediaSize += AVCFAssetTrackGetTotalSampleDataLength(assetTrack);
734     }
735
736     // FIXME: It doesn't seem safe to cast an int64_t to unsigned.
737     return static_cast<unsigned>(totalMediaSize);
738 }
739
740 MediaPlayerPrivateAVFoundation::AssetStatus MediaPlayerPrivateAVFoundationCF::assetStatus() const
741 {
742     if (!avAsset(m_avfWrapper))
743         return MediaPlayerAVAssetStatusDoesNotExist;
744
745     // First, make sure all metadata properties we rely on are loaded.
746     CFArrayRef keys = metadataKeyNames();
747     CFIndex keyCount = CFArrayGetCount(keys);
748     for (CFIndex i = 0; i < keyCount; i++) {
749         CFStringRef keyName = static_cast<CFStringRef>(CFArrayGetValueAtIndex(keys, i));
750         AVCFPropertyValueStatus keyStatus = AVCFAssetGetStatusOfValueForProperty(avAsset(m_avfWrapper), keyName, 0);
751
752         if (keyStatus < AVCFPropertyValueStatusLoaded)
753             return MediaPlayerAVAssetStatusLoading;
754         if (keyStatus == AVCFPropertyValueStatusFailed)
755             return MediaPlayerAVAssetStatusFailed;
756         if (keyStatus == AVCFPropertyValueStatusCancelled)
757             return MediaPlayerAVAssetStatusCancelled;
758     }
759
760     if (AVCFAssetIsPlayable(avAsset(m_avfWrapper)))
761         return MediaPlayerAVAssetStatusPlayable;
762
763     return MediaPlayerAVAssetStatusLoaded;
764 }
765
766 void MediaPlayerPrivateAVFoundationCF::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& rect)
767 {
768     if (!metaDataAvailable() || context->paintingDisabled())
769         return;
770
771     if (currentRenderingMode() == MediaRenderingToLayer && !imageGenerator(m_avfWrapper)) {
772         // We're being told to render into a context, but we already have the
773         // video layer, which probably means we've been called from <canvas>.
774         createContextVideoRenderer();
775     }
776
777     paint(context, rect);
778 }
779
780 void MediaPlayerPrivateAVFoundationCF::paint(GraphicsContext* context, const IntRect& rect)
781 {
782     if (!metaDataAvailable() || context->paintingDisabled() || !imageGenerator(m_avfWrapper))
783         return;
784
785     LOG(Media, "MediaPlayerPrivateAVFoundationCF::paint(%p)", this);
786
787     setDelayCallbacks(true);
788     RetainPtr<CGImageRef> image = m_avfWrapper->createImageForTimeInRect(currentTime(), rect);
789     if (image) {
790         context->save();
791         context->translate(rect.x(), rect.y() + rect.height());
792         context->scale(FloatSize(1.0f, -1.0f));
793         context->setImageInterpolationQuality(InterpolationLow);
794         IntRect paintRect(IntPoint(0, 0), IntSize(rect.width(), rect.height()));
795         CGContextDrawImage(context->platformContext(), CGRectMake(0, 0, paintRect.width(), paintRect.height()), image.get());
796         context->restore();
797         image = 0;
798     }
799     setDelayCallbacks(false);
800     
801     m_videoFrameHasDrawn = true;
802 }
803
804 static HashSet<String> mimeTypeCache()
805 {
806     DEFINE_STATIC_LOCAL(HashSet<String>, cache, ());
807     static bool typeListInitialized = false;
808
809     if (typeListInitialized)
810         return cache;
811     typeListInitialized = true;
812
813     RetainPtr<CFArrayRef> supportedTypes = adoptCF(AVCFURLAssetCopyAudiovisualMIMETypes());
814     
815     ASSERT(supportedTypes);
816     if (!supportedTypes)
817         return cache;
818
819     CFIndex typeCount = CFArrayGetCount(supportedTypes.get());
820     for (CFIndex i = 0; i < typeCount; i++)
821         cache.add(static_cast<CFStringRef>(CFArrayGetValueAtIndex(supportedTypes.get(), i)));
822
823     return cache;
824
825
826 void MediaPlayerPrivateAVFoundationCF::getSupportedTypes(HashSet<String>& supportedTypes)
827 {
828     supportedTypes = mimeTypeCache();
829
830
831 MediaPlayer::SupportsType MediaPlayerPrivateAVFoundationCF::supportsType(const MediaEngineSupportParameters& parameters)
832 {
833     // Only return "IsSupported" if there is no codecs parameter for now as there is no way to ask if it supports an
834     // extended MIME type until rdar://8721715 is fixed.
835     if (mimeTypeCache().contains(parameters.type))
836         return parameters.codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported;
837
838     return MediaPlayer::IsNotSupported;
839 }
840
841
842 bool MediaPlayerPrivateAVFoundationCF::isAvailable()
843 {
844     return AVFoundationCFLibrary() && CoreMediaLibrary();
845 }
846
847 float MediaPlayerPrivateAVFoundationCF::mediaTimeForTimeValue(float timeValue) const
848 {
849     if (!metaDataAvailable())
850         return timeValue;
851
852     // FIXME - can not implement until rdar://8721669 is fixed.
853     return timeValue;
854 }
855
856 void MediaPlayerPrivateAVFoundationCF::tracksChanged()
857 {
858     String primaryAudioTrackLanguage = m_languageOfPrimaryAudioTrack;
859     m_languageOfPrimaryAudioTrack = String();
860
861     if (!avAsset(m_avfWrapper))
862         return;
863
864     setDelayCharacteristicsChangedNotification(true);
865
866     bool haveCCTrack = false;
867     bool hasCaptions = false;
868
869     // This is called whenever the tracks collection changes so cache hasVideo and hasAudio since we are
870     // asked about those fairly frequently.
871     if (!avPlayerItem(m_avfWrapper)) {
872         // We don't have a player item yet, so check with the asset because some assets support inspection
873         // prior to becoming ready to play.
874         RetainPtr<CFArrayRef> visualTracks = adoptCF(AVCFAssetCopyTracksWithMediaCharacteristic(avAsset(m_avfWrapper), AVCFMediaCharacteristicVisual));
875         setHasVideo(CFArrayGetCount(visualTracks.get()));
876
877         RetainPtr<CFArrayRef> audioTracks = adoptCF(AVCFAssetCopyTracksWithMediaCharacteristic(avAsset(m_avfWrapper), AVCFMediaCharacteristicAudible));
878         setHasAudio(CFArrayGetCount(audioTracks.get()));
879
880 #if !HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
881         RetainPtr<CFArrayRef> captionTracks = adoptCF(AVCFAssetCopyTracksWithMediaType(avAsset(m_avfWrapper), AVCFMediaTypeClosedCaption));
882         hasCaptions = CFArrayGetCount(captionTracks.get());
883 #endif
884     } else {
885         bool hasVideo = false;
886         bool hasAudio = false;
887
888         RetainPtr<CFArrayRef> tracks = adoptCF(AVCFPlayerItemCopyTracks(avPlayerItem(m_avfWrapper)));
889
890         CFIndex trackCount = CFArrayGetCount(tracks.get());
891         for (CFIndex i = 0; i < trackCount; i++) {
892             AVCFPlayerItemTrackRef track = (AVCFPlayerItemTrackRef)(CFArrayGetValueAtIndex(tracks.get(), i));
893             
894             if (AVCFPlayerItemTrackIsEnabled(track)) {
895                 RetainPtr<AVCFAssetTrackRef> assetTrack = adoptCF(AVCFPlayerItemTrackCopyAssetTrack(track));
896                 CFStringRef mediaType = AVCFAssetTrackGetMediaType(assetTrack.get());
897                 if (!mediaType)
898                     continue;
899                 
900                 if (CFStringCompare(mediaType, AVCFMediaTypeVideo, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
901                     hasVideo = true;
902                 else if (CFStringCompare(mediaType, AVCFMediaTypeAudio, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
903                     hasAudio = true;
904                 else if (CFStringCompare(mediaType, AVCFMediaTypeClosedCaption, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
905 #if !HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
906                     hasCaptions = true;
907 #endif
908                     haveCCTrack = true;
909                 }
910             }
911         }
912
913         setHasVideo(hasVideo);
914         setHasAudio(hasAudio);
915     }
916
917 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
918     AVCFMediaSelectionGroupRef legibleGroup = safeMediaSelectionGroupForLegibleMedia(m_avfWrapper);
919     if (legibleGroup) {
920         RetainPtr<CFArrayRef> playableOptions = adoptCF(AVCFMediaSelectionCopyPlayableOptionsFromArray(AVCFMediaSelectionGroupGetOptions(legibleGroup)));
921         hasCaptions = CFArrayGetCount(playableOptions.get());
922         if (hasCaptions)
923             processMediaSelectionOptions();
924     }
925 #endif
926
927 #if !HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT)
928     if (haveCCTrack)
929         processLegacyClosedCaptionsTracks();
930 #endif
931
932     setHasClosedCaptions(hasCaptions);
933
934     LOG(Media, "MediaPlayerPrivateAVFoundationCF:tracksChanged(%p) - hasVideo = %s, hasAudio = %s, hasCaptions = %s", 
935         this, boolString(hasVideo()), boolString(hasAudio()), boolString(hasClosedCaptions()));
936
937     sizeChanged();
938
939     if (primaryAudioTrackLanguage != languageOfPrimaryAudioTrack())
940         characteristicsChanged();
941
942     setDelayCharacteristicsChangedNotification(false);
943 }
944
945 void MediaPlayerPrivateAVFoundationCF::sizeChanged()
946 {
947     if (!avAsset(m_avfWrapper))
948         return;
949     
950     // AVAsset's 'naturalSize' property only considers the movie's first video track, so we need to compute
951     // the union of all visual track rects.
952     CGRect trackRectUnion = CGRectZero;
953     RetainPtr<CFArrayRef> tracks = adoptCF(AVCFAssetCopyTracksWithMediaType(avAsset(m_avfWrapper), AVCFMediaCharacteristicVisual));
954     CFIndex trackCount = CFArrayGetCount(tracks.get());
955     for (CFIndex i = 0; i < trackCount; i++) {
956         AVCFAssetTrackRef assetTrack = (AVCFAssetTrackRef)(CFArrayGetValueAtIndex(tracks.get(), i));
957         
958         CGSize trackSize = AVCFAssetTrackGetNaturalSize(assetTrack);
959         CGRect trackRect = CGRectMake(0, 0, trackSize.width, trackSize.height);
960         trackRectUnion = CGRectUnion(trackRectUnion, CGRectApplyAffineTransform(trackRect, AVCFAssetTrackGetPreferredTransform(assetTrack)));
961     }
962     // The movie is always displayed at 0,0 so move the track rect to the origin before using width and height.
963     trackRectUnion = CGRectOffset(trackRectUnion, trackRectUnion.origin.x, trackRectUnion.origin.y);
964     CGSize naturalSize = trackRectUnion.size;
965
966     // Also look at the asset's preferred transform so we account for a movie matrix.
967     CGSize movieSize = CGSizeApplyAffineTransform(AVCFAssetGetNaturalSize(avAsset(m_avfWrapper)), AVCFAssetGetPreferredTransform(avAsset(m_avfWrapper)));
968     if (movieSize.width > naturalSize.width)
969         naturalSize.width = movieSize.width;
970     if (movieSize.height > naturalSize.height)
971         naturalSize.height = movieSize.height;
972     setNaturalSize(IntSize(naturalSize));
973 }
974
975 bool MediaPlayerPrivateAVFoundationCF::requiresImmediateCompositing() const
976 {
977     // The AVFoundationCF player needs to have the root compositor available at construction time
978     // so it can attach to the rendering device. Otherwise it falls back to CPU-only mode.
979     //
980     // It would be nice if AVCFPlayer had some way to switch to hardware-accelerated mode
981     // when asked, then we could follow AVFoundation's model and switch to compositing
982     // mode when beginning to play media.
983     return true;
984 }
985
986 #if !HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT)
987 void MediaPlayerPrivateAVFoundationCF::processLegacyClosedCaptionsTracks()
988 {
989 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
990     AVCFPlayerItemSelectMediaOptionInMediaSelectionGroup(avPlayerItem(m_avfWrapper), 0, safeMediaSelectionGroupForLegibleMedia(m_avfWrapper));
991 #endif
992
993     Vector<RefPtr<InbandTextTrackPrivateAVF> > removedTextTracks = m_textTracks;
994     RetainPtr<CFArrayRef> tracks = adoptCF(AVCFPlayerItemCopyTracks(avPlayerItem(m_avfWrapper)));
995     CFIndex trackCount = CFArrayGetCount(tracks.get());
996     for (CFIndex i = 0; i < trackCount; ++i) {
997         AVCFPlayerItemTrackRef playerItemTrack = (AVCFPlayerItemTrackRef)(CFArrayGetValueAtIndex(tracks.get(), i));
998
999         RetainPtr<AVCFAssetTrackRef> assetTrack = adoptCF(AVCFPlayerItemTrackCopyAssetTrack(playerItemTrack));
1000         CFStringRef mediaType = AVCFAssetTrackGetMediaType(assetTrack.get());
1001         if (!mediaType)
1002             continue;
1003                 
1004         if (CFStringCompare(mediaType, AVCFMediaTypeClosedCaption, kCFCompareCaseInsensitive) != kCFCompareEqualTo)
1005             continue;
1006
1007         bool newCCTrack = true;
1008         for (unsigned i = removedTextTracks.size(); i > 0; --i) {
1009             if (!removedTextTracks[i - 1]->isLegacyClosedCaptionsTrack())
1010                 continue;
1011
1012             RefPtr<InbandTextTrackPrivateLegacyAVCF> track = static_cast<InbandTextTrackPrivateLegacyAVCF*>(m_textTracks[i - 1].get());
1013             if (track->avPlayerItemTrack() == playerItemTrack) {
1014                 removedTextTracks.remove(i - 1);
1015                 newCCTrack = false;
1016                 break;
1017             }
1018         }
1019
1020         if (!newCCTrack)
1021             continue;
1022         
1023         m_textTracks.append(InbandTextTrackPrivateLegacyAVCF::create(this, playerItemTrack));
1024     }
1025
1026     processNewAndRemovedTextTracks(removedTextTracks);
1027 }
1028 #endif
1029
1030 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
1031 void MediaPlayerPrivateAVFoundationCF::processMediaSelectionOptions()
1032 {
1033     AVCFMediaSelectionGroupRef legibleGroup = safeMediaSelectionGroupForLegibleMedia(m_avfWrapper);
1034     if (!legibleGroup) {
1035         LOG(Media, "MediaPlayerPrivateAVFoundationCF::processMediaSelectionOptions(%p) - nil mediaSelectionGroup", this);
1036         return;
1037     }
1038
1039     // We enabled automatic media selection because we want alternate audio tracks to be enabled/disabled automatically,
1040     // but set the selected legible track to nil so text tracks will not be automatically configured.
1041     if (!m_textTracks.size()) {
1042         ASSERT(AVCFMediaSelectionGroupAllowsEmptySelection(legibleGroup));
1043         AVCFPlayerItemRef playerItem = avPlayerItem(m_avfWrapper);
1044
1045         if (playerItem)
1046             AVCFPlayerItemSelectMediaOptionInMediaSelectionGroup(playerItem, 0, legibleGroup);
1047     }
1048
1049     Vector<RefPtr<InbandTextTrackPrivateAVF> > removedTextTracks = m_textTracks;
1050     RetainPtr<CFArrayRef> legibleOptions = adoptCF(AVCFMediaSelectionCopyPlayableOptionsFromArray(AVCFMediaSelectionGroupGetOptions(legibleGroup)));
1051     CFIndex legibleOptionsCount = CFArrayGetCount(legibleOptions.get());
1052     for (CFIndex i = 0; i < legibleOptionsCount; ++i) {
1053         AVCFMediaSelectionOptionRef option = static_cast<AVCFMediaSelectionOptionRef>(CFArrayGetValueAtIndex(legibleOptions.get(), i));
1054         bool newTrack = true;
1055         for (unsigned i = removedTextTracks.size(); i > 0; --i) {
1056             if (removedTextTracks[i - 1]->isLegacyClosedCaptionsTrack())
1057                 continue;
1058
1059             RefPtr<InbandTextTrackPrivateAVCF> track = static_cast<InbandTextTrackPrivateAVCF*>(removedTextTracks[i - 1].get());
1060             if (CFEqual(track->mediaSelectionOption(), option)) {
1061                 removedTextTracks.remove(i - 1);
1062                 newTrack = false;
1063                 break;
1064             }
1065         }
1066         if (!newTrack)
1067             continue;
1068
1069         m_textTracks.append(InbandTextTrackPrivateAVCF::create(this, option));
1070     }
1071
1072     processNewAndRemovedTextTracks(removedTextTracks);
1073 }
1074
1075 #endif // HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
1076
1077 void AVFWrapper::setCurrentTrack(InbandTextTrackPrivateAVF* track)
1078 {
1079     if (m_currentTrack == track)
1080         return;
1081
1082     LOG(Media, "MediaPlayerPrivateAVFoundationCF::setCurrentTrack(%p) - selecting track %p, language = %s", this, track, track ? track->language().string().utf8().data() : "");
1083         
1084     m_currentTrack = track;
1085
1086     if (track) {
1087         if (track->isLegacyClosedCaptionsTrack())
1088             AVCFPlayerSetClosedCaptionDisplayEnabled(avPlayer(), TRUE);
1089 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
1090         else
1091             AVCFPlayerItemSelectMediaOptionInMediaSelectionGroup(avPlayerItem(), static_cast<InbandTextTrackPrivateAVCF*>(track)->mediaSelectionOption(), safeMediaSelectionGroupForLegibleMedia());
1092 #endif
1093     } else {
1094 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
1095         AVCFPlayerItemSelectMediaOptionInMediaSelectionGroup(avPlayerItem(), 0, safeMediaSelectionGroupForLegibleMedia());
1096 #endif
1097         AVCFPlayerSetClosedCaptionDisplayEnabled(avPlayer(), FALSE);
1098     }
1099 }
1100
1101 String MediaPlayerPrivateAVFoundationCF::languageOfPrimaryAudioTrack() const
1102 {
1103     if (!m_languageOfPrimaryAudioTrack.isNull())
1104         return m_languageOfPrimaryAudioTrack;
1105
1106     if (!avPlayerItem(m_avfWrapper))
1107         return emptyString();
1108
1109 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
1110     // If AVFoundation has an audible group, return the language of the currently selected audible option.
1111     AVCFMediaSelectionGroupRef audibleGroup = AVCFAssetGetSelectionGroupForMediaCharacteristic(avAsset(m_avfWrapper), AVCFMediaCharacteristicAudible);
1112     AVCFMediaSelectionOptionRef currentlySelectedAudibleOption = AVCFPlayerItemGetSelectedMediaOptionInMediaSelectionGroup(avPlayerItem(m_avfWrapper), audibleGroup);
1113     if (currentlySelectedAudibleOption) {
1114         RetainPtr<CFLocaleRef> audibleOptionLocale = adoptCF(AVCFMediaSelectionOptionCopyLocale(currentlySelectedAudibleOption));
1115         m_languageOfPrimaryAudioTrack = CFLocaleGetIdentifier(audibleOptionLocale.get());
1116         LOG(Media, "MediaPlayerPrivateAVFoundationCF::languageOfPrimaryAudioTrack(%p) - returning language of selected audible option: %s", this, m_languageOfPrimaryAudioTrack.utf8().data());
1117
1118         return m_languageOfPrimaryAudioTrack;
1119     }
1120 #endif // HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
1121
1122     // AVFoundation synthesizes an audible group when there is only one ungrouped audio track if there is also a legible group (one or
1123     // more in-band text tracks). It doesn't know about out-of-band tracks, so if there is a single audio track return its language.
1124     RetainPtr<CFArrayRef> tracks = adoptCF(AVCFAssetCopyTracksWithMediaType(avAsset(m_avfWrapper), AVCFMediaTypeAudio));
1125     CFIndex trackCount = CFArrayGetCount(tracks.get());
1126     if (!tracks || trackCount != 1) {
1127         m_languageOfPrimaryAudioTrack = emptyString();
1128         LOG(Media, "MediaPlayerPrivateAVFoundationCF::languageOfPrimaryAudioTrack(%p) - %i audio tracks, returning emptyString()", this, (tracks ? trackCount : 0));
1129         return m_languageOfPrimaryAudioTrack;
1130     }
1131
1132     AVCFAssetTrackRef track = (AVCFAssetTrackRef)CFArrayGetValueAtIndex(tracks.get(), 0);
1133     RetainPtr<CFStringRef> language = adoptCF(AVCFAssetTrackCopyExtendedLanguageTag(track));
1134
1135     // If the language code is stored as a QuickTime 5-bit packed code there aren't enough bits for a full
1136     // RFC 4646 language tag so extendedLanguageTag returns null. In this case languageCode will return the
1137     // ISO 639-2/T language code so check it.
1138     if (!language)
1139         language = adoptCF(AVCFAssetTrackCopyLanguageCode(track));
1140
1141     // Some legacy tracks have "und" as a language, treat that the same as no language at all.
1142     if (language && CFStringCompare(language.get(), CFSTR("und"), kCFCompareCaseInsensitive) != kCFCompareEqualTo) {
1143         m_languageOfPrimaryAudioTrack = language.get();
1144         LOG(Media, "MediaPlayerPrivateAVFoundationCF::languageOfPrimaryAudioTrack(%p) - returning language of single audio track: %s", this, m_languageOfPrimaryAudioTrack.utf8().data());
1145         return m_languageOfPrimaryAudioTrack;
1146     }
1147
1148     LOG(Media, "MediaPlayerPrivateAVFoundationCF::languageOfPrimaryAudioTrack(%p) - single audio track has no language, returning emptyString()", this);
1149     m_languageOfPrimaryAudioTrack = emptyString();
1150     return m_languageOfPrimaryAudioTrack;
1151 }
1152
1153 void MediaPlayerPrivateAVFoundationCF::contentsNeedsDisplay()
1154 {
1155     if (m_avfWrapper)
1156         m_avfWrapper->setVideoLayerNeedsCommit();
1157 }
1158
1159 AVFWrapper::AVFWrapper(MediaPlayerPrivateAVFoundationCF* owner)
1160     : m_owner(owner)
1161     , m_objectID(s_nextAVFWrapperObjectID++)
1162     , m_currentTrack(0)
1163 {
1164     ASSERT(isMainThread());
1165     ASSERT(dispatch_get_main_queue() == dispatch_get_current_queue());
1166     LOG(Media, "AVFWrapper::AVFWrapper(%p)", this);
1167
1168     m_notificationQueue = dispatch_queue_create("MediaPlayerPrivateAVFoundationCF.notificationQueue", 0);
1169     addToMap();
1170 }
1171
1172 AVFWrapper::~AVFWrapper()
1173 {
1174     ASSERT(isMainThread());
1175     ASSERT(dispatch_get_main_queue() == dispatch_get_current_queue());
1176     LOG(Media, "AVFWrapper::~AVFWrapper(%p %d)", this, m_objectID);
1177
1178     destroyVideoLayer();
1179     destroyImageGenerator();
1180
1181     if (m_notificationQueue)
1182         dispatch_release(m_notificationQueue);
1183
1184     if (avAsset()) {
1185         AVCFAssetCancelLoading(avAsset());
1186         m_avAsset = 0;
1187     }
1188
1189 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP) && HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT)
1190     if (legibleOutput()) {
1191         if (avPlayerItem())
1192             AVCFPlayerItemRemoveOutput(avPlayerItem(), legibleOutput());
1193         m_legibleOutput = 0;
1194     }
1195 #endif
1196
1197     m_avPlayerItem = 0;
1198     m_timeObserver = 0;
1199     m_avPlayer = 0;
1200 }
1201
1202 Mutex& AVFWrapper::mapLock()
1203 {
1204     static Mutex mapLock;
1205     return mapLock;
1206 }
1207
1208 HashMap<uintptr_t, AVFWrapper*>& AVFWrapper::map()
1209 {
1210     static HashMap<uintptr_t, AVFWrapper*>& map = *new HashMap<uintptr_t, AVFWrapper*>;
1211     return map;
1212 }
1213
1214 void AVFWrapper::addToMap()
1215 {
1216     MutexLocker locker(mapLock());
1217     
1218     // HashMap doesn't like a key of 0, and also make sure we aren't
1219     // using an object ID that's already in use.
1220     while (!m_objectID || (map().find(m_objectID) != map().end()))
1221         m_objectID = s_nextAVFWrapperObjectID++;
1222        
1223     LOG(Media, "AVFWrapper::addToMap(%p %d)", this, m_objectID);
1224
1225     map().add(m_objectID, this);
1226 }
1227
1228 void AVFWrapper::removeFromMap() const
1229 {
1230     LOG(Media, "AVFWrapper::removeFromMap(%p %d)", this, m_objectID);
1231
1232     MutexLocker locker(mapLock());
1233     map().remove(m_objectID);
1234 }
1235
1236 AVFWrapper* AVFWrapper::avfWrapperForCallbackContext(void* context)
1237 {
1238     // Assumes caller has locked mapLock().
1239     HashMap<uintptr_t, AVFWrapper*>::iterator it = map().find(reinterpret_cast<uintptr_t>(context));
1240     if (it == map().end())
1241         return 0;
1242
1243     return it->value;
1244 }
1245
1246 void AVFWrapper::scheduleDisconnectAndDelete()
1247 {
1248     // Ignore any subsequent notifications we might receive in notificationCallback().
1249     removeFromMap();
1250
1251     dispatch_async_f(dispatchQueue(), this, disconnectAndDeleteAVFWrapper);
1252 }
1253
1254 static void destroyAVFWrapper(void* context)
1255 {
1256     ASSERT(isMainThread());
1257     ASSERT(dispatch_get_main_queue() == dispatch_get_current_queue());
1258     AVFWrapper* avfWrapper = static_cast<AVFWrapper*>(context);
1259     if (!avfWrapper)
1260         return;
1261
1262     delete avfWrapper;
1263 }
1264
1265 void AVFWrapper::disconnectAndDeleteAVFWrapper(void* context)
1266 {
1267     AVFWrapper* avfWrapper = static_cast<AVFWrapper*>(context);
1268
1269     LOG(Media, "AVFWrapper::disconnectAndDeleteAVFWrapper(%p)", avfWrapper);
1270
1271     if (avfWrapper->avPlayerItem()) {
1272         CFNotificationCenterRef center = CFNotificationCenterGetLocalCenter();
1273         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemDidPlayToEndTimeNotification, avfWrapper->avPlayerItem());
1274         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemStatusChangedNotification, avfWrapper->avPlayerItem());
1275         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemTracksChangedNotification, avfWrapper->avPlayerItem());
1276         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemSeekableTimeRangesChangedNotification, avfWrapper->avPlayerItem());
1277         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemLoadedTimeRangesChangedNotification, avfWrapper->avPlayerItem());
1278         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemPresentationSizeChangedNotification, avfWrapper->avPlayerItem());
1279         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemIsPlaybackLikelyToKeepUpChangedNotification, avfWrapper->avPlayerItem());
1280         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemIsPlaybackBufferEmptyChangedNotification, avfWrapper->avPlayerItem());
1281         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemIsPlaybackBufferFullChangedNotification, avfWrapper->avPlayerItem());
1282         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemDurationChangedNotification, avfWrapper->avPlayerItem());
1283         CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), CACFContextNeedsFlushNotification(), 0);
1284     }
1285
1286     if (avfWrapper->avPlayer()) {
1287         if (avfWrapper->timeObserver())
1288             AVCFPlayerRemoveObserver(avfWrapper->avPlayer(), avfWrapper->timeObserver());
1289
1290         CFNotificationCenterRemoveObserver(CFNotificationCenterGetLocalCenter(), avfWrapper->callbackContext(), AVCFPlayerRateChangedNotification, avfWrapper->avPlayer());
1291     }
1292
1293 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP) && HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT)
1294     AVCFPlayerItemRemoveOutput(avfWrapper->avPlayerItem(), avfWrapper->legibleOutput());
1295 #endif
1296
1297     // We must release the AVCFPlayer and other items on the same thread that created them.
1298     dispatch_async_f(dispatch_get_main_queue(), context, destroyAVFWrapper);
1299 }
1300
1301 void AVFWrapper::createAssetForURL(const String& url)
1302 {
1303     ASSERT(!avAsset());
1304
1305     RetainPtr<CFURLRef> urlRef = URL(ParsedURLString, url).createCFURL();
1306
1307     AVCFURLAssetRef assetRef = AVCFURLAssetCreateWithURLAndOptions(kCFAllocatorDefault, urlRef.get(), 0, m_notificationQueue);
1308     m_avAsset = adoptCF(assetRef);
1309 }
1310
1311 void AVFWrapper::createPlayer(IDirect3DDevice9* d3dDevice)
1312 {
1313     ASSERT(isMainThread());
1314     ASSERT(dispatch_get_main_queue() == dispatch_get_current_queue());
1315     ASSERT(!avPlayer() && avPlayerItem());
1316
1317     RetainPtr<CFMutableDictionaryRef> optionsRef = adoptCF(CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
1318
1319     if (d3dDevice) {
1320         // QI for an IDirect3DDevice9Ex interface, it is required to do HW video decoding.
1321         COMPtr<IDirect3DDevice9Ex> d3dEx(Query, d3dDevice);
1322         m_d3dDevice = d3dEx;
1323     } else
1324         m_d3dDevice = 0;
1325
1326     if (m_d3dDevice && AVCFPlayerEnableHardwareAcceleratedVideoDecoderKey)
1327         CFDictionarySetValue(optionsRef.get(), AVCFPlayerEnableHardwareAcceleratedVideoDecoderKey, kCFBooleanTrue);
1328
1329 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP) && HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT)
1330     CFDictionarySetValue(optionsRef.get(), AVCFPlayerAppliesMediaSelectionCriteriaAutomaticallyKey, kCFBooleanTrue);
1331 #endif
1332
1333     // FIXME: We need a way to create a AVPlayer without an AVPlayerItem, see <rdar://problem/9877730>.
1334     AVCFPlayerRef playerRef = AVCFPlayerCreateWithPlayerItemAndOptions(kCFAllocatorDefault, avPlayerItem(), optionsRef.get(), m_notificationQueue);
1335     m_avPlayer = adoptCF(playerRef);
1336 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP) && HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT)
1337     AVCFPlayerSetClosedCaptionDisplayEnabled(playerRef, FALSE);
1338 #endif
1339
1340     if (m_d3dDevice && AVCFPlayerSetDirect3DDevicePtr())
1341         AVCFPlayerSetDirect3DDevicePtr()(playerRef, m_d3dDevice.get());
1342
1343     CFNotificationCenterRef center = CFNotificationCenterGetLocalCenter();
1344     ASSERT(center);
1345
1346     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerRateChangedNotification, playerRef, CFNotificationSuspensionBehaviorDeliverImmediately);
1347
1348     // Add a time observer, ask to be called infrequently because we don't really want periodic callbacks but
1349     // our observer will also be called whenever a seek happens.
1350     const double veryLongInterval = 60*60*60*24*30;
1351     m_timeObserver = adoptCF(AVCFPlayerCreatePeriodicTimeObserverForInterval(playerRef, CMTimeMake(veryLongInterval, 10), m_notificationQueue, &periodicTimeObserverCallback, callbackContext()));
1352 }
1353
1354 void AVFWrapper::createPlayerItem()
1355 {
1356     ASSERT(isMainThread());
1357     ASSERT(dispatch_get_main_queue() == dispatch_get_current_queue());
1358     ASSERT(!avPlayerItem() && avAsset());
1359
1360     // Create the player item so we begin loading media data.
1361     AVCFPlayerItemRef itemRef = AVCFPlayerItemCreateWithAsset(kCFAllocatorDefault, avAsset(), m_notificationQueue);
1362     m_avPlayerItem = adoptCF(itemRef);
1363
1364     CFNotificationCenterRef center = CFNotificationCenterGetLocalCenter();
1365     ASSERT(center);
1366
1367     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemDidPlayToEndTimeNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
1368     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemStatusChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
1369     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemTracksChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
1370     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemSeekableTimeRangesChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
1371     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemLoadedTimeRangesChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
1372     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemPresentationSizeChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
1373     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemIsPlaybackLikelyToKeepUpChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
1374     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemIsPlaybackBufferEmptyChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
1375     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemIsPlaybackBufferFullChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
1376     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemDurationChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
1377     // FIXME: Are there other legible output things we need to register for? asset and hasEnabledAudio are not exposed by AVCF
1378
1379     CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, CACFContextNeedsFlushNotification(), 0, CFNotificationSuspensionBehaviorDeliverImmediately);
1380
1381 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP) && HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT)
1382     const CFTimeInterval legibleOutputAdvanceInterval = 2;
1383
1384     m_legibleOutput = adoptCF(AVCFPlayerItemLegibleOutputCreateWithMediaSubtypesForNativeRepresentation(kCFAllocatorDefault, 0));
1385     AVCFPlayerItemOutputSetSuppressPlayerRendering(m_legibleOutput.get(), TRUE);
1386
1387     AVCFPlayerItemLegibleOutputCallbacks callbackInfo;
1388     callbackInfo.version = kAVCFPlayerItemLegibleOutput_CallbacksVersion_1;
1389     ASSERT(callbackContext());
1390     callbackInfo.context = callbackContext();
1391     callbackInfo.legibleOutputCallback = AVFWrapper::legibleOutputCallback;
1392
1393     AVCFPlayerItemLegibleOutputSetCallbacks(m_legibleOutput.get(), &callbackInfo, dispatchQueue());
1394     AVCFPlayerItemLegibleOutputSetAdvanceIntervalForCallbackInvocation(m_legibleOutput.get(), legibleOutputAdvanceInterval);
1395     AVCFPlayerItemLegibleOutputSetTextStylingResolution(m_legibleOutput.get(), AVCFPlayerItemLegibleOutputTextStylingResolutionSourceAndRulesOnly);
1396     AVCFPlayerItemAddOutput(m_avPlayerItem.get(), m_legibleOutput.get());
1397 #endif
1398 }
1399
1400 void AVFWrapper::periodicTimeObserverCallback(AVCFPlayerRef, CMTime cmTime, void* context)
1401 {
1402     MutexLocker locker(mapLock());
1403     AVFWrapper* self = avfWrapperForCallbackContext(context);
1404     if (!self) {
1405         LOG(Media, "AVFWrapper::periodicTimeObserverCallback invoked for deleted AVFWrapper %d", reinterpret_cast<uintptr_t>(context));
1406         return;
1407     }
1408
1409     double time = std::max(0.0, CMTimeGetSeconds(cmTime)); // Clamp to zero, negative values are sometimes reported.
1410     self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::PlayerTimeChanged, time);
1411 }
1412
1413 void AVFWrapper::notificationCallback(CFNotificationCenterRef, void* observer, CFStringRef propertyName, const void* object, CFDictionaryRef)
1414 {
1415     MutexLocker locker(mapLock());
1416     AVFWrapper* self = avfWrapperForCallbackContext(observer);
1417     
1418     if (!self) {
1419         LOG(Media, "AVFWrapper::notificationCallback invoked for deleted AVFWrapper %d", reinterpret_cast<uintptr_t>(observer));
1420         return;
1421     }
1422
1423 #if !LOG_DISABLED
1424     char notificationName[256];
1425     CFStringGetCString(propertyName, notificationName, sizeof(notificationName), kCFStringEncodingASCII);
1426     LOG(Media, "AVFWrapper::notificationCallback(%p) %s", self, notificationName);
1427 #endif
1428
1429     if (CFEqual(propertyName, AVCFPlayerItemDidPlayToEndTimeNotification))
1430         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemDidPlayToEndTime);
1431     else if (CFEqual(propertyName, AVCFPlayerItemTracksChangedNotification))
1432         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemTracksChanged);
1433     else if (CFEqual(propertyName, AVCFPlayerItemStatusChangedNotification)) {
1434         AVCFURLAssetRef asset = AVCFPlayerItemGetAsset(self->avPlayerItem());
1435         if (asset)
1436             self->setAsset(asset);
1437         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemStatusChanged);
1438     } else if (CFEqual(propertyName, AVCFPlayerItemSeekableTimeRangesChangedNotification))
1439         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemSeekableTimeRangesChanged);
1440     else if (CFEqual(propertyName, AVCFPlayerItemLoadedTimeRangesChangedNotification))
1441         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemLoadedTimeRangesChanged);
1442     else if (CFEqual(propertyName, AVCFPlayerItemPresentationSizeChangedNotification))
1443         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemPresentationSizeChanged);
1444     else if (CFEqual(propertyName, AVCFPlayerItemIsPlaybackLikelyToKeepUpChangedNotification))
1445         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemIsPlaybackLikelyToKeepUpChanged);
1446     else if (CFEqual(propertyName, AVCFPlayerItemIsPlaybackBufferEmptyChangedNotification))
1447         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemIsPlaybackBufferEmptyChanged);
1448     else if (CFEqual(propertyName, AVCFPlayerItemIsPlaybackBufferFullChangedNotification))
1449         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemIsPlaybackBufferFullChanged);
1450     else if (CFEqual(propertyName, AVCFPlayerRateChangedNotification))
1451         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::PlayerRateChanged);
1452     else if (CFEqual(propertyName, CACFContextNeedsFlushNotification()))
1453         self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ContentsNeedsDisplay);
1454     else
1455         ASSERT_NOT_REACHED();
1456 }
1457
1458 void AVFWrapper::loadPlayableCompletionCallback(AVCFAssetRef, void* context)
1459 {
1460     MutexLocker locker(mapLock());
1461     AVFWrapper* self = avfWrapperForCallbackContext(context);
1462     if (!self) {
1463         LOG(Media, "AVFWrapper::loadPlayableCompletionCallback invoked for deleted AVFWrapper %d", reinterpret_cast<uintptr_t>(context));
1464         return;
1465     }
1466
1467     LOG(Media, "AVFWrapper::loadPlayableCompletionCallback(%p)", self);
1468     self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::AssetPlayabilityKnown);
1469 }
1470
1471 void AVFWrapper::checkPlayability()
1472 {
1473     LOG(Media, "AVFWrapper::checkPlayability(%p)", this);
1474
1475     static CFArrayRef propertyKeyName;
1476     if (!propertyKeyName) {
1477         static const CFStringRef keyNames[] = { 
1478             AVCFAssetPropertyPlayable
1479         };
1480         propertyKeyName = CFArrayCreate(0, (const void**)keyNames, sizeof(keyNames) / sizeof(keyNames[0]), &kCFTypeArrayCallBacks);
1481     }
1482
1483     AVCFAssetLoadValuesAsynchronouslyForProperties(avAsset(), propertyKeyName, loadPlayableCompletionCallback, callbackContext());
1484 }
1485
1486 void AVFWrapper::loadMetadataCompletionCallback(AVCFAssetRef, void* context)
1487 {
1488     MutexLocker locker(mapLock());
1489     AVFWrapper* self = avfWrapperForCallbackContext(context);
1490     if (!self) {
1491         LOG(Media, "AVFWrapper::loadMetadataCompletionCallback invoked for deleted AVFWrapper %d", reinterpret_cast<uintptr_t>(context));
1492         return;
1493     }
1494
1495     LOG(Media, "AVFWrapper::loadMetadataCompletionCallback(%p)", self);
1496     self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::AssetMetadataLoaded);
1497 }
1498
1499 void AVFWrapper::beginLoadingMetadata()
1500 {
1501     ASSERT(avAsset());
1502     LOG(Media, "AVFWrapper::beginLoadingMetadata(%p) - requesting metadata loading", this);
1503     AVCFAssetLoadValuesAsynchronouslyForProperties(avAsset(), metadataKeyNames(), loadMetadataCompletionCallback, callbackContext());
1504 }
1505
1506 void AVFWrapper::seekCompletedCallback(AVCFPlayerItemRef, Boolean finished, void* context)
1507 {
1508     MutexLocker locker(mapLock());
1509     AVFWrapper* self = avfWrapperForCallbackContext(context);
1510     if (!self) {
1511         LOG(Media, "AVFWrapper::seekCompletedCallback invoked for deleted AVFWrapper %d", reinterpret_cast<uintptr_t>(context));
1512         return;
1513     }
1514
1515     LOG(Media, "AVFWrapper::seekCompletedCallback(%p)", self);
1516     self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::SeekCompleted, static_cast<bool>(finished));
1517 }
1518
1519 void AVFWrapper::seekToTime(double time, double negativeTolerance, double positiveTolerance)
1520 {
1521     ASSERT(avPlayerItem());
1522     CMTime cmTime = CMTimeMakeWithSeconds(time, 600);
1523     CMTime cmBefore = CMTimeMakeWithSeconds(negativeTolerance, 600);
1524     CMTime cmAfter = CMTimeMakeWithSeconds(positiveTolerance, 600);
1525     AVCFPlayerItemSeekToTimeWithToleranceAndCompletionCallback(avPlayerItem(), cmTime, cmBefore, cmAfter, &seekCompletedCallback, callbackContext());
1526 }
1527
1528 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP) && HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT)
1529 struct LegibleOutputData {
1530     RetainPtr<CFArrayRef> m_attributedStrings;
1531     double m_time;
1532     void* m_context;
1533
1534     LegibleOutputData(CFArrayRef strings, double time, void* context)
1535         : m_attributedStrings(strings), m_time(time), m_context(context)
1536     {
1537     }
1538 };
1539
1540 void AVFWrapper::processCue(void* context)
1541 {
1542     ASSERT(dispatch_get_main_queue() == dispatch_get_current_queue());
1543     ASSERT(context);
1544
1545     if (!context)
1546         return;
1547
1548     OwnPtr<LegibleOutputData> legibleOutputData = adoptPtr(reinterpret_cast<LegibleOutputData*>(context));
1549
1550     MutexLocker locker(mapLock());
1551     AVFWrapper* self = avfWrapperForCallbackContext(legibleOutputData->m_context);
1552     if (!self) {
1553         LOG(Media, "AVFWrapper::processCue invoked for deleted AVFWrapper %d", reinterpret_cast<uintptr_t>(context));
1554         return;
1555     }
1556
1557     if (!self->m_currentTrack)
1558         return;
1559
1560     self->m_currentTrack->processCue(legibleOutputData->m_attributedStrings.get(), legibleOutputData->m_time);
1561 }
1562
1563 void AVFWrapper::legibleOutputCallback(void* context, AVCFPlayerItemLegibleOutputRef legibleOutput, CFArrayRef attributedStrings, CFArrayRef /*nativeSampleBuffers*/, CMTime itemTime)
1564 {
1565     ASSERT(dispatch_get_main_queue() == dispatch_get_current_queue());
1566     MutexLocker locker(mapLock());
1567     AVFWrapper* self = avfWrapperForCallbackContext(context);
1568     if (!self) {
1569         LOG(Media, "AVFWrapper::legibleOutputCallback invoked for deleted AVFWrapper %d", reinterpret_cast<uintptr_t>(context));
1570         return;
1571     }
1572
1573     LOG(Media, "AVFWrapper::legibleOutputCallback(%p)", self);
1574
1575     ASSERT(legibleOutput == self->m_legibleOutput);
1576
1577     OwnPtr<LegibleOutputData> legibleOutputData = adoptPtr(new LegibleOutputData(attributedStrings, CMTimeGetSeconds(itemTime), context));
1578
1579     dispatch_async_f(dispatch_get_main_queue(), legibleOutputData.leakPtr(), processCue);
1580 }
1581 #endif
1582
1583 void AVFWrapper::setAsset(AVCFURLAssetRef asset)
1584 {
1585     if (asset == avAsset())
1586         return;
1587
1588     AVCFAssetCancelLoading(avAsset());
1589     m_avAsset = adoptCF(asset);
1590 }
1591
1592 PlatformLayer* AVFWrapper::platformLayer()
1593 {
1594     if (m_videoLayerWrapper)
1595         return m_videoLayerWrapper->platformLayer();
1596
1597     if (!videoLayer())
1598         return 0;
1599
1600     // Create a PlatformCALayer so we can resize the video layer to match the element size.
1601     m_layerClient = adoptPtr(new LayerClient(this));
1602     if (!m_layerClient)
1603         return 0;
1604
1605     m_videoLayerWrapper = PlatformCALayerWin::create(PlatformCALayer::LayerTypeLayer, m_layerClient.get());
1606     if (!m_videoLayerWrapper)
1607         return 0;
1608
1609     m_caVideoLayer = adoptCF(AVCFPlayerLayerCopyCACFLayer(m_avCFVideoLayer.get()));
1610
1611     CACFLayerInsertSublayer(m_videoLayerWrapper->platformLayer(), m_caVideoLayer.get(), 0);
1612     m_videoLayerWrapper->setAnchorPoint(FloatPoint3D());
1613     m_videoLayerWrapper->setNeedsLayout();
1614     updateVideoLayerGravity();
1615
1616     return m_videoLayerWrapper->platformLayer();
1617 }
1618
1619 void AVFWrapper::createAVCFVideoLayer()
1620 {
1621     ASSERT(isMainThread());
1622     ASSERT(dispatch_get_main_queue() == dispatch_get_current_queue());
1623     if (!avPlayer() || m_avCFVideoLayer)
1624         return;
1625
1626     // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration().
1627     m_avCFVideoLayer = adoptCF(AVCFPlayerLayerCreateWithAVCFPlayer(kCFAllocatorDefault, avPlayer(), m_notificationQueue));
1628     LOG(Media, "AVFWrapper::createAVCFVideoLayer(%p) - returning %p", this, videoLayer());
1629 }
1630
1631 void AVFWrapper::destroyVideoLayer()
1632 {
1633     ASSERT(isMainThread());
1634     ASSERT(dispatch_get_main_queue() == dispatch_get_current_queue());
1635     LOG(Media, "AVFWrapper::destroyVideoLayer(%p)", this);
1636     m_layerClient = nullptr;
1637     m_caVideoLayer = 0;
1638     m_videoLayerWrapper = 0;
1639     if (!m_avCFVideoLayer.get())
1640         return;
1641
1642     AVCFPlayerLayerSetPlayer((AVCFPlayerLayerRef)m_avCFVideoLayer.get(), 0);
1643     m_avCFVideoLayer = 0;
1644 }
1645
1646 void AVFWrapper::setVideoLayerNeedsCommit()
1647 {
1648     if (m_videoLayerWrapper)
1649         m_videoLayerWrapper->setNeedsCommit();
1650 }
1651
1652 void AVFWrapper::setVideoLayerHidden(bool value)
1653 {
1654     if (m_videoLayerWrapper)
1655         m_videoLayerWrapper->setHidden(value);
1656 }
1657
1658 void AVFWrapper::createImageGenerator()
1659 {
1660     ASSERT(isMainThread());
1661     ASSERT(dispatch_get_main_queue() == dispatch_get_current_queue());
1662     if (!avAsset() || m_imageGenerator)
1663         return;
1664
1665     m_imageGenerator = adoptCF(AVCFAssetImageGeneratorCreateWithAsset(kCFAllocatorDefault, avAsset()));
1666
1667     AVCFAssetImageGeneratorSetApertureMode(m_imageGenerator.get(), AVCFAssetImageGeneratorApertureModeCleanAperture);
1668     AVCFAssetImageGeneratorSetRequestedTimeToleranceBefore(m_imageGenerator.get(), kCMTimeZero);
1669     AVCFAssetImageGeneratorSetRequestedTimeToleranceAfter(m_imageGenerator.get(), kCMTimeZero);
1670     AVCFAssetImageGeneratorSetAppliesPreferredTrackTransform(m_imageGenerator.get(), true);
1671
1672     LOG(Media, "AVFWrapper::createImageGenerator(%p) - returning %p", this, m_imageGenerator.get());
1673 }
1674
1675 void AVFWrapper::destroyImageGenerator()
1676 {
1677     ASSERT(isMainThread());
1678     ASSERT(dispatch_get_main_queue() == dispatch_get_current_queue());
1679     LOG(Media, "AVFWrapper::destroyImageGenerator(%p)", this);
1680     m_imageGenerator = 0;
1681 }
1682
1683 RetainPtr<CGImageRef> AVFWrapper::createImageForTimeInRect(float time, const IntRect& rect)
1684 {
1685     if (!m_imageGenerator)
1686         return 0;
1687
1688 #if !LOG_DISABLED
1689     double start = monotonicallyIncreasingTime();
1690 #endif
1691
1692     AVCFAssetImageGeneratorSetMaximumSize(m_imageGenerator.get(), CGSize(rect.size()));
1693     CGImageRef rawimage = AVCFAssetImageGeneratorCopyCGImageAtTime(m_imageGenerator.get(), CMTimeMakeWithSeconds(time, 600), 0, 0);
1694     CGImageRef image = CGImageCreateCopyWithColorSpace(rawimage,  CGColorSpaceCreateDeviceRGB());
1695 #if !LOG_DISABLED
1696     double duration = monotonicallyIncreasingTime() - start;
1697     LOG(Media, "AVFWrapper::createImageForTimeInRect(%p) - creating image took %.4f", this, narrowPrecisionToFloat(duration));
1698 #endif
1699
1700     return image;
1701 }
1702
1703 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP)
1704 AVCFMediaSelectionGroupRef AVFWrapper::safeMediaSelectionGroupForLegibleMedia() const
1705 {
1706     if (!avAsset())
1707         return 0;
1708
1709     if (AVCFAssetGetStatusOfValueForProperty(avAsset(), AVCFAssetPropertyAvailableMediaCharacteristicsWithMediaSelectionOptions, 0) != AVCFPropertyValueStatusLoaded)
1710         return 0;
1711
1712     return AVCFAssetGetSelectionGroupForMediaCharacteristic(avAsset(), AVCFMediaCharacteristicLegible);
1713 }
1714 #endif
1715
1716 void AVFWrapper::updateVideoLayerGravity()
1717 {
1718     // We should call AVCFPlayerLayerSetVideoGravity() here, but it is not yet implemented.
1719     // FIXME: <rdar://problem/14884340>
1720 }
1721
1722 void LayerClient::platformCALayerLayoutSublayersOfLayer(PlatformCALayer* wrapperLayer)
1723 {
1724     ASSERT(m_parent);
1725     ASSERT(m_parent->videoLayerWrapper() == wrapperLayer->platformLayer());
1726
1727     CGRect bounds = wrapperLayer->bounds();
1728     CGPoint anchor = CACFLayerGetAnchorPoint(m_parent->caVideoLayer());
1729     FloatPoint position(bounds.size.width * anchor.x, bounds.size.height * anchor.y); 
1730
1731     CACFLayerSetPosition(m_parent->caVideoLayer(), position);
1732     CACFLayerSetBounds(m_parent->caVideoLayer(), bounds);
1733
1734     AVCFPlayerLayerSetFrame(m_parent->videoLayer(), CGRectMake(0, 0, bounds.size.width, bounds.size.height));
1735 }
1736
1737 } // namespace WebCore
1738
1739 #else
1740 // AVFoundation should always be enabled for Apple production builds.
1741 #if __PRODUCTION__ && !USE(AVFOUNDATION)
1742 #error AVFoundation is not enabled!
1743 #endif // __PRODUCTION__ && !USE(AVFOUNDATION)
1744 #endif // USE(AVFOUNDATION)
1745 #endif // PLATFORM(WIN) && ENABLE(VIDEO)