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