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