[JSC] Drop PassRefPtr from ArrayBuffer
[WebKit-https.git] / Source / WebCore / platform / graphics / avfoundation / MediaPlayerPrivateAVFoundation.cpp
1 /*
2  * Copyright (C) 2011-2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27
28 #if ENABLE(VIDEO) && USE(AVFOUNDATION)
29
30 #include "MediaPlayerPrivateAVFoundation.h"
31
32 #include "DocumentLoader.h"
33 #include "FloatConversion.h"
34 #include "GraphicsContext.h"
35 #include "InbandTextTrackPrivateAVF.h"
36 #include "InbandTextTrackPrivateClient.h"
37 #include "URL.h"
38 #include "Logging.h"
39 #include "PlatformLayer.h"
40 #include "PlatformTimeRanges.h"
41 #include "Settings.h"
42 #include "SoftLinking.h"
43 #include <CoreMedia/CoreMedia.h>
44 #include <heap/HeapInlines.h>
45 #include <runtime/DataView.h>
46 #include <runtime/TypedArrayInlines.h>
47 #include <runtime/Uint16Array.h>
48 #include <wtf/MainThread.h>
49 #include <wtf/NeverDestroyed.h>
50 #include <wtf/text/CString.h>
51 #include <wtf/StringPrintStream.h>
52
53 namespace WebCore {
54
55 MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation(MediaPlayer* player)
56     : m_player(player)
57     , m_weakPtrFactory(this)
58     , m_queuedNotifications()
59     , m_queueMutex()
60     , m_networkState(MediaPlayer::Empty)
61     , m_readyState(MediaPlayer::HaveNothing)
62     , m_preload(MediaPlayer::Auto)
63     , m_cachedDuration(MediaTime::invalidTime())
64     , m_reportedDuration(MediaTime::invalidTime())
65     , m_maxTimeLoadedAtLastDidLoadingProgress(MediaTime::invalidTime())
66     , m_delayCallbacks(0)
67     , m_delayCharacteristicsChangedNotification(0)
68     , m_mainThreadCallPending(false)
69     , m_assetIsPlayable(false)
70     , m_visible(false)
71     , m_loadingMetadata(false)
72     , m_isAllowedToRender(false)
73     , m_cachedHasAudio(false)
74     , m_cachedHasVideo(false)
75     , m_cachedHasCaptions(false)
76     , m_ignoreLoadStateChanges(false)
77     , m_haveReportedFirstVideoFrame(false)
78     , m_playWhenFramesAvailable(false)
79     , m_inbandTrackConfigurationPending(false)
80     , m_characteristicsChanged(false)
81     , m_shouldMaintainAspectRatio(true)
82     , m_seeking(false)
83 {
84     LOG(Media, "MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation(%p)", this);
85 }
86
87 MediaPlayerPrivateAVFoundation::~MediaPlayerPrivateAVFoundation()
88 {
89     LOG(Media, "MediaPlayerPrivateAVFoundation::~MediaPlayerPrivateAVFoundation(%p)", this);
90     setIgnoreLoadStateChanges(true);
91 }
92
93 MediaPlayerPrivateAVFoundation::MediaRenderingMode MediaPlayerPrivateAVFoundation::currentRenderingMode() const
94 {
95     if (platformLayer())
96         return MediaRenderingToLayer;
97
98     if (hasContextRenderer())
99         return MediaRenderingToContext;
100
101     return MediaRenderingNone;
102 }
103
104 MediaPlayerPrivateAVFoundation::MediaRenderingMode MediaPlayerPrivateAVFoundation::preferredRenderingMode() const
105 {
106     if (!m_player->visible() || assetStatus() == MediaPlayerAVAssetStatusUnknown)
107         return MediaRenderingNone;
108
109     if (supportsAcceleratedRendering() && m_player->client().mediaPlayerRenderingCanBeAccelerated(m_player))
110         return MediaRenderingToLayer;
111
112     return MediaRenderingToContext;
113 }
114
115 void MediaPlayerPrivateAVFoundation::setUpVideoRendering()
116 {
117     if (!isReadyForVideoSetup())
118         return;
119
120     MediaRenderingMode currentMode = currentRenderingMode();
121     MediaRenderingMode preferredMode = preferredRenderingMode();
122
123     if (preferredMode == MediaRenderingNone)
124         preferredMode = MediaRenderingToContext;
125
126     if (currentMode == preferredMode && currentMode != MediaRenderingNone)
127         return;
128
129     LOG(Media, "MediaPlayerPrivateAVFoundation::setUpVideoRendering(%p) - current mode = %d, preferred mode = %d", 
130         this, static_cast<int>(currentMode), static_cast<int>(preferredMode));
131
132     if (currentMode != MediaRenderingNone)  
133         tearDownVideoRendering();
134
135     switch (preferredMode) {
136     case MediaRenderingNone:
137     case MediaRenderingToContext:
138         createContextVideoRenderer();
139         break;
140
141     case MediaRenderingToLayer:
142         createVideoLayer();
143         break;
144     }
145
146     // If using a movie layer, inform the client so the compositing tree is updated.
147     if (currentMode == MediaRenderingToLayer || preferredMode == MediaRenderingToLayer) {
148         LOG(Media, "MediaPlayerPrivateAVFoundation::setUpVideoRendering(%p) - calling mediaPlayerRenderingModeChanged()", this);
149         m_player->client().mediaPlayerRenderingModeChanged(m_player);
150     }
151 }
152
153 void MediaPlayerPrivateAVFoundation::tearDownVideoRendering()
154 {
155     LOG(Media, "MediaPlayerPrivateAVFoundation::tearDownVideoRendering(%p)", this);
156
157     destroyContextVideoRenderer();
158
159     if (platformLayer())
160         destroyVideoLayer();
161 }
162
163 bool MediaPlayerPrivateAVFoundation::hasSetUpVideoRendering() const
164 {
165     return hasLayerRenderer() || hasContextRenderer();
166 }
167
168 void MediaPlayerPrivateAVFoundation::load(const String& url)
169 {
170     LOG(Media, "MediaPlayerPrivateAVFoundation::load(%p)", this);
171
172     setNetworkState(m_preload == MediaPlayer::None ? MediaPlayer::Idle : MediaPlayer::Loading);
173     setReadyState(MediaPlayer::HaveNothing);
174
175     m_assetURL = url;
176
177     // Don't do any more work if the url is empty.
178     if (!url.length())
179         return;
180
181     setPreload(m_preload);
182 }
183
184 #if ENABLE(MEDIA_SOURCE)
185 void MediaPlayerPrivateAVFoundation::load(const String&, MediaSourcePrivateClient*)
186 {
187     setNetworkState(MediaPlayer::FormatError);
188 }
189 #endif
190
191
192 void MediaPlayerPrivateAVFoundation::playabilityKnown()
193 {
194     LOG(Media, "MediaPlayerPrivateAVFoundation::playabilityKnown(%p)", this);
195
196     if (m_assetIsPlayable)
197         return;
198
199     // Nothing more to do if we already have all of the item's metadata.
200     if (assetStatus() > MediaPlayerAVAssetStatusLoading) {
201         LOG(Media, "MediaPlayerPrivateAVFoundation::playabilityKnown(%p) - all metadata loaded", this);
202         return;
203     }
204
205     // At this point we are supposed to load metadata. It is OK to ask the asset to load the same 
206     // information multiple times, because if it has already been loaded the completion handler 
207     // will just be called synchronously.
208     m_loadingMetadata = true;
209     beginLoadingMetadata();
210 }
211
212 void MediaPlayerPrivateAVFoundation::prepareToPlay()
213 {
214     LOG(Media, "MediaPlayerPrivateAVFoundation::prepareToPlay(%p)", this);
215
216     setPreload(MediaPlayer::Auto);
217 }
218
219 void MediaPlayerPrivateAVFoundation::play()
220 {
221     LOG(Media, "MediaPlayerPrivateAVFoundation::play(%p)", this);
222
223     // If the file has video, don't request playback until the first frame of video is ready to display
224     // or the audio may start playing before we can render video.
225     if (!m_cachedHasVideo || hasAvailableVideoFrame())
226         platformPlay();
227     else {
228         LOG(Media, "MediaPlayerPrivateAVFoundation::play(%p) - waiting for first video frame", this);
229         m_playWhenFramesAvailable = true;
230     }
231 }
232
233 void MediaPlayerPrivateAVFoundation::pause()
234 {
235     LOG(Media, "MediaPlayerPrivateAVFoundation::pause(%p)", this);
236     m_playWhenFramesAvailable = false;
237     platformPause();
238 }
239
240 MediaTime MediaPlayerPrivateAVFoundation::durationMediaTime() const
241 {
242     if (m_cachedDuration.isValid())
243         return m_cachedDuration;
244
245     MediaTime duration = platformDuration();
246     if (!duration || duration.isInvalid())
247         return MediaTime::zeroTime();
248
249     m_cachedDuration = duration;
250     LOG(Media, "MediaPlayerPrivateAVFoundation::duration(%p) - caching %s", this, toString(m_cachedDuration).utf8().data());
251     return m_cachedDuration;
252 }
253
254 void MediaPlayerPrivateAVFoundation::seek(const MediaTime& time)
255 {
256     seekWithTolerance(time, MediaTime::zeroTime(), MediaTime::zeroTime());
257 }
258
259 void MediaPlayerPrivateAVFoundation::seekWithTolerance(const MediaTime& mediaTime, const MediaTime& negativeTolerance, const MediaTime& positiveTolerance)
260 {
261     MediaTime time = mediaTime;
262
263     if (m_seeking) {
264         LOG(Media, "MediaPlayerPrivateAVFoundation::seekWithTolerance(%p) - save pending seek", this);
265         m_pendingSeek = [this, time, negativeTolerance, positiveTolerance]() {
266             seekWithTolerance(time, negativeTolerance, positiveTolerance);
267         };
268         return;
269     }
270     m_seeking = true;
271
272     if (!metaDataAvailable())
273         return;
274
275     if (time > durationMediaTime())
276         time = durationMediaTime();
277
278     if (currentTextTrack())
279         currentTextTrack()->beginSeeking();
280
281     LOG(Media, "MediaPlayerPrivateAVFoundation::seek(%p) - seeking to %s", this, toString(time).utf8().data());
282
283     seekToTime(time, negativeTolerance, positiveTolerance);
284 }
285
286 bool MediaPlayerPrivateAVFoundation::paused() const
287 {
288     if (!metaDataAvailable())
289         return true;
290
291     return rate() == 0;
292 }
293
294 bool MediaPlayerPrivateAVFoundation::seeking() const
295 {
296     if (!metaDataAvailable())
297         return false;
298
299     return m_seeking;
300 }
301
302 FloatSize MediaPlayerPrivateAVFoundation::naturalSize() const
303 {
304     if (!metaDataAvailable())
305         return IntSize();
306
307     // In spite of the name of this method, return the natural size transformed by the 
308     // initial movie scale because the spec says intrinsic size is:
309     //
310     //    ... the dimensions of the resource in CSS pixels after taking into account the resource's 
311     //    dimensions, aspect ratio, clean aperture, resolution, and so forth, as defined for the 
312     //    format used by the resource
313
314     return m_cachedNaturalSize;
315 }
316
317 void MediaPlayerPrivateAVFoundation::setNaturalSize(FloatSize size)
318 {
319     LOG(Media, "MediaPlayerPrivateAVFoundation:setNaturalSize(%p) - size = %f x %f", this, size.width(), size.height());
320
321     FloatSize oldSize = m_cachedNaturalSize;
322     m_cachedNaturalSize = size;
323     if (oldSize != m_cachedNaturalSize)
324         m_player->sizeChanged();
325 }
326
327 void MediaPlayerPrivateAVFoundation::setHasVideo(bool b)
328 {
329     if (m_cachedHasVideo != b) {
330         m_cachedHasVideo = b;
331         characteristicsChanged();
332     }
333 }
334
335 void MediaPlayerPrivateAVFoundation::setHasAudio(bool b)
336 {
337     if (m_cachedHasAudio != b) {
338         m_cachedHasAudio = b;
339         characteristicsChanged();
340     }
341 }
342
343 void MediaPlayerPrivateAVFoundation::setHasClosedCaptions(bool b)
344 {
345     if (m_cachedHasCaptions != b) {
346         m_cachedHasCaptions = b;
347         characteristicsChanged();
348     }
349 }
350
351 void MediaPlayerPrivateAVFoundation::setNetworkState(MediaPlayer::NetworkState state)
352 {
353     if (state == m_networkState)
354         return;
355
356     m_networkState = state;
357     m_player->networkStateChanged();
358 }
359
360 void MediaPlayerPrivateAVFoundation::setReadyState(MediaPlayer::ReadyState state)
361 {
362     if (state == m_readyState)
363         return;
364
365     m_readyState = state;
366     m_player->readyStateChanged();
367 }
368
369 void MediaPlayerPrivateAVFoundation::characteristicsChanged()
370 {
371     if (m_delayCharacteristicsChangedNotification) {
372         m_characteristicsChanged = true;
373         return;
374     }
375
376     m_characteristicsChanged = false;
377     m_player->characteristicChanged();
378 }
379
380 void MediaPlayerPrivateAVFoundation::setDelayCharacteristicsChangedNotification(bool delay)
381 {
382     if (delay) {
383         m_delayCharacteristicsChangedNotification++;
384         return;
385     }
386     
387     ASSERT(m_delayCharacteristicsChangedNotification);
388     m_delayCharacteristicsChangedNotification--;
389     if (!m_delayCharacteristicsChangedNotification && m_characteristicsChanged)
390         characteristicsChanged();
391 }
392
393 std::unique_ptr<PlatformTimeRanges> MediaPlayerPrivateAVFoundation::buffered() const
394 {
395     if (!m_cachedLoadedTimeRanges)
396         m_cachedLoadedTimeRanges = platformBufferedTimeRanges();
397
398     return std::make_unique<PlatformTimeRanges>(*m_cachedLoadedTimeRanges);
399 }
400
401 MediaTime MediaPlayerPrivateAVFoundation::maxMediaTimeSeekable() const
402 {
403     if (!metaDataAvailable())
404         return MediaTime::zeroTime();
405
406     if (!m_cachedMaxTimeSeekable)
407         m_cachedMaxTimeSeekable = platformMaxTimeSeekable();
408
409     LOG(Media, "MediaPlayerPrivateAVFoundation::maxTimeSeekable(%p) - returning %s", this, toString(m_cachedMaxTimeSeekable).utf8().data());
410     return m_cachedMaxTimeSeekable;   
411 }
412
413 MediaTime MediaPlayerPrivateAVFoundation::minMediaTimeSeekable() const
414 {
415     if (!metaDataAvailable())
416         return MediaTime::zeroTime();
417
418     if (!m_cachedMinTimeSeekable)
419         m_cachedMinTimeSeekable = platformMinTimeSeekable();
420
421     LOG(Media, "MediaPlayerPrivateAVFoundation::minTimeSeekable(%p) - returning %s", this, toString(m_cachedMinTimeSeekable).utf8().data());
422     return m_cachedMinTimeSeekable;
423 }
424
425 double MediaPlayerPrivateAVFoundation::requestedRate() const
426 {
427     return m_player->requestedRate();
428 }
429
430 MediaTime MediaPlayerPrivateAVFoundation::maxTimeLoaded() const
431 {
432     if (!metaDataAvailable())
433         return MediaTime::zeroTime();
434
435     if (!m_cachedMaxTimeLoaded)
436         m_cachedMaxTimeLoaded = platformMaxTimeLoaded();
437
438     return m_cachedMaxTimeLoaded;   
439 }
440
441 bool MediaPlayerPrivateAVFoundation::didLoadingProgress() const
442 {
443     if (!durationMediaTime())
444         return false;
445     MediaTime currentMaxTimeLoaded = maxTimeLoaded();
446     bool didLoadingProgress = currentMaxTimeLoaded != m_maxTimeLoadedAtLastDidLoadingProgress;
447     m_maxTimeLoadedAtLastDidLoadingProgress = currentMaxTimeLoaded;
448
449     return didLoadingProgress;
450 }
451
452 bool MediaPlayerPrivateAVFoundation::isReadyForVideoSetup() const
453 {
454     // AVFoundation will not return true for firstVideoFrameAvailable until
455     // an AVPlayerLayer has been added to the AVPlayerItem, so allow video setup
456     // here if a video track to trigger allocation of a AVPlayerLayer.
457     return (m_isAllowedToRender || m_cachedHasVideo) && m_readyState >= MediaPlayer::HaveMetadata && m_player->visible();
458 }
459
460 void MediaPlayerPrivateAVFoundation::prepareForRendering()
461 {
462     if (m_isAllowedToRender)
463         return;
464     m_isAllowedToRender = true;
465
466     setUpVideoRendering();
467
468     if (currentRenderingMode() == MediaRenderingToLayer || preferredRenderingMode() == MediaRenderingToLayer)
469         m_player->client().mediaPlayerRenderingModeChanged(m_player);
470 }
471
472 bool MediaPlayerPrivateAVFoundation::supportsFullscreen() const
473 {
474 #if ENABLE(FULLSCREEN_API)
475     return true;
476 #else
477     // FIXME: WebVideoFullscreenController assumes a QTKit/QuickTime media engine
478 #if PLATFORM(IOS)
479     if (Settings::avKitEnabled())
480         return true;
481 #endif
482     return false;
483 #endif
484 }
485
486 void MediaPlayerPrivateAVFoundation::updateStates()
487 {
488     if (m_ignoreLoadStateChanges)
489         return;
490
491     MediaPlayer::NetworkState newNetworkState = m_networkState;
492     MediaPlayer::ReadyState newReadyState = m_readyState;
493
494     if (m_loadingMetadata)
495         newNetworkState = MediaPlayer::Loading;
496     else {
497         // -loadValuesAsynchronouslyForKeys:completionHandler: has invoked its handler; test status of keys and determine state.
498         AssetStatus assetStatus = this->assetStatus();
499         ItemStatus itemStatus = playerItemStatus();
500         
501         m_assetIsPlayable = (assetStatus == MediaPlayerAVAssetStatusPlayable);
502         if (m_readyState < MediaPlayer::HaveMetadata && assetStatus > MediaPlayerAVAssetStatusLoading) {
503             if (m_assetIsPlayable) {
504                 if (assetStatus >= MediaPlayerAVAssetStatusLoaded)
505                     newReadyState = MediaPlayer::HaveMetadata;
506                 if (itemStatus <= MediaPlayerAVPlayerItemStatusUnknown) {
507                     if (assetStatus == MediaPlayerAVAssetStatusFailed || m_preload > MediaPlayer::MetaData || isLiveStream()) {
508                         // The asset is playable but doesn't support inspection prior to playback (eg. streaming files),
509                         // or we are supposed to prepare for playback immediately, so create the player item now.
510                         newNetworkState = MediaPlayer::Loading;
511                         prepareToPlay();
512                     } else
513                         newNetworkState = MediaPlayer::Idle;
514                 }
515             } else {
516                 // FIX ME: fetch the error associated with the @"playable" key to distinguish between format 
517                 // and network errors.
518                 newNetworkState = MediaPlayer::FormatError;
519             }
520         }
521         
522         if (assetStatus >= MediaPlayerAVAssetStatusLoaded && itemStatus > MediaPlayerAVPlayerItemStatusUnknown) {
523             switch (itemStatus) {
524             case MediaPlayerAVPlayerItemStatusDoesNotExist:
525             case MediaPlayerAVPlayerItemStatusUnknown:
526             case MediaPlayerAVPlayerItemStatusFailed:
527                 break;
528
529             case MediaPlayerAVPlayerItemStatusPlaybackLikelyToKeepUp:
530             case MediaPlayerAVPlayerItemStatusPlaybackBufferFull:
531                 // If the status becomes PlaybackBufferFull, loading stops and the status will not
532                 // progress to LikelyToKeepUp. Set the readyState to  HAVE_ENOUGH_DATA, on the
533                 // presumption that if the playback buffer is full, playback will probably not stall.
534                 newReadyState = MediaPlayer::HaveEnoughData;
535                 break;
536
537             case MediaPlayerAVPlayerItemStatusReadyToPlay:
538                 if (m_readyState != MediaPlayer::HaveEnoughData && maxTimeLoaded() > currentMediaTime())
539                     newReadyState = MediaPlayer::HaveFutureData;
540                 break;
541
542             case MediaPlayerAVPlayerItemStatusPlaybackBufferEmpty:
543                 newReadyState = MediaPlayer::HaveCurrentData;
544                 break;
545             }
546
547             if (itemStatus == MediaPlayerAVPlayerItemStatusPlaybackBufferFull)
548                 newNetworkState = MediaPlayer::Idle;
549             else if (itemStatus == MediaPlayerAVPlayerItemStatusFailed)
550                 newNetworkState = MediaPlayer::DecodeError;
551             else if (itemStatus != MediaPlayerAVPlayerItemStatusPlaybackBufferFull && itemStatus >= MediaPlayerAVPlayerItemStatusReadyToPlay)
552                 newNetworkState = (maxTimeLoaded() == durationMediaTime()) ? MediaPlayer::Loaded : MediaPlayer::Loading;
553         }
554     }
555
556     if (isReadyForVideoSetup() && currentRenderingMode() != preferredRenderingMode())
557         setUpVideoRendering();
558
559     if (!m_haveReportedFirstVideoFrame && m_cachedHasVideo && hasAvailableVideoFrame()) {
560         if (m_readyState < MediaPlayer::HaveCurrentData)
561             newReadyState = MediaPlayer::HaveCurrentData;
562         m_haveReportedFirstVideoFrame = true;
563         m_player->firstVideoFrameAvailable();
564     }
565
566 #if !LOG_DISABLED
567     if (m_networkState != newNetworkState || m_readyState != newReadyState) {
568         LOG(Media, "MediaPlayerPrivateAVFoundation::updateStates(%p) - entered with networkState = %i, readyState = %i,  exiting with networkState = %i, readyState = %i",
569             this, static_cast<int>(m_networkState), static_cast<int>(m_readyState), static_cast<int>(newNetworkState), static_cast<int>(newReadyState));
570     }
571 #endif
572
573     setNetworkState(newNetworkState);
574     setReadyState(newReadyState);
575
576     if (m_playWhenFramesAvailable && hasAvailableVideoFrame()) {
577         m_playWhenFramesAvailable = false;
578         platformPlay();
579     }
580 }
581
582 void MediaPlayerPrivateAVFoundation::setSize(const IntSize&) 
583
584 }
585
586 void MediaPlayerPrivateAVFoundation::setVisible(bool visible)
587 {
588     if (m_visible == visible)
589         return;
590
591     m_visible = visible;
592     if (visible)
593         setUpVideoRendering();
594     
595     platformSetVisible(visible);
596 }
597
598 void MediaPlayerPrivateAVFoundation::acceleratedRenderingStateChanged()
599 {
600     // Set up or change the rendering path if necessary.
601     setUpVideoRendering();
602 }
603
604 void MediaPlayerPrivateAVFoundation::setShouldMaintainAspectRatio(bool maintainAspectRatio)
605 {
606     if (maintainAspectRatio == m_shouldMaintainAspectRatio)
607         return;
608
609     m_shouldMaintainAspectRatio = maintainAspectRatio;
610     updateVideoLayerGravity();
611 }
612
613 void MediaPlayerPrivateAVFoundation::metadataLoaded()
614 {
615     m_loadingMetadata = false;
616     tracksChanged();
617 }
618
619 void MediaPlayerPrivateAVFoundation::rateChanged()
620 {
621 #if ENABLE(WIRELESS_PLAYBACK_TARGET) && PLATFORM(IOS)
622     LOG(Media, "MediaPlayerPrivateAVFoundation::rateChanged(%p) - rate = %f, requested rate = %f, item status = %i", this, rate(), requestedRate(), playerItemStatus());
623     if (isCurrentPlaybackTargetWireless() && playerItemStatus() >= MediaPlayerAVPlayerItemStatusPlaybackBufferFull) {
624         double rate = this->rate();
625         if (rate != requestedRate()) {
626             m_player->handlePlaybackCommand(rate ? PlatformMediaSession::PlayCommand : PlatformMediaSession::PauseCommand);
627             return;
628         }
629     }
630 #endif
631
632     m_player->rateChanged();
633 }
634
635 void MediaPlayerPrivateAVFoundation::loadedTimeRangesChanged()
636 {
637     m_cachedLoadedTimeRanges = nullptr;
638     m_cachedMaxTimeLoaded = MediaTime::zeroTime();
639     invalidateCachedDuration();
640 }
641
642 void MediaPlayerPrivateAVFoundation::seekableTimeRangesChanged()
643 {
644     m_cachedMaxTimeSeekable = MediaTime::zeroTime();
645     m_cachedMinTimeSeekable = MediaTime::zeroTime();
646 }
647
648 void MediaPlayerPrivateAVFoundation::timeChanged(const MediaTime& time)
649 {
650     LOG(Media, "MediaPlayerPrivateAVFoundation::timeChanged(%p) - time = %s", this, toString(time).utf8().data());
651     UNUSED_PARAM(time);
652 }
653
654 void MediaPlayerPrivateAVFoundation::seekCompleted(bool finished)
655 {
656     LOG(Media, "MediaPlayerPrivateAVFoundation::seekCompleted(%p) - finished = %d", this, finished);
657     UNUSED_PARAM(finished);
658
659     m_seeking = false;
660
661     std::function<void()> pendingSeek;
662     std::swap(pendingSeek, m_pendingSeek);
663
664     if (pendingSeek) {
665         LOG(Media, "MediaPlayerPrivateAVFoundation::seekCompleted(%p) - issuing pending seek", this);
666         pendingSeek();
667         return;
668     }
669
670     if (currentTextTrack())
671         currentTextTrack()->endSeeking();
672
673     updateStates();
674     m_player->timeChanged();
675 }
676
677 void MediaPlayerPrivateAVFoundation::didEnd()
678 {
679     // Hang onto the current time and use it as duration from now on since we are definitely at
680     // the end of the movie. Do this because the initial duration is sometimes an estimate.
681     MediaTime now = currentMediaTime();
682     if (now > MediaTime::zeroTime() && !m_seeking)
683         m_cachedDuration = now;
684
685     updateStates();
686     m_player->timeChanged();
687 }
688
689 void MediaPlayerPrivateAVFoundation::invalidateCachedDuration()
690 {
691     m_cachedDuration = MediaTime::invalidTime();
692
693     // For some media files, reported duration is estimated and updated as media is loaded
694     // so report duration changed when the estimate is upated.
695     MediaTime duration = this->durationMediaTime();
696     if (duration != m_reportedDuration) {
697         if (m_reportedDuration.isValid())
698             m_player->durationChanged();
699         m_reportedDuration = duration;
700     }
701     
702 }
703
704 void MediaPlayerPrivateAVFoundation::repaint()
705 {
706     m_player->repaint();
707 }
708
709 MediaPlayer::MovieLoadType MediaPlayerPrivateAVFoundation::movieLoadType() const
710 {
711     if (!metaDataAvailable() || assetStatus() == MediaPlayerAVAssetStatusUnknown)
712         return MediaPlayer::Unknown;
713
714     if (isLiveStream())
715         return MediaPlayer::LiveStream;
716
717     return MediaPlayer::Download;
718 }
719
720 void MediaPlayerPrivateAVFoundation::setPreload(MediaPlayer::Preload preload)
721 {
722     m_preload = preload;
723     if (!m_assetURL.length())
724         return;
725
726     setDelayCallbacks(true);
727
728     if (m_preload >= MediaPlayer::MetaData && assetStatus() == MediaPlayerAVAssetStatusDoesNotExist) {
729         createAVAssetForURL(m_assetURL);
730         checkPlayability();
731     }
732
733     // Don't force creation of the player and player item unless we already know that the asset is playable. If we aren't
734     // there yet, or if we already know it is not playable, creating them now won't help.
735     if (m_preload == MediaPlayer::Auto && m_assetIsPlayable) {
736         createAVPlayerItem();
737         createAVPlayer();
738     }
739
740     setDelayCallbacks(false);
741 }
742
743 void MediaPlayerPrivateAVFoundation::setDelayCallbacks(bool delay) const
744 {
745     LockHolder lock(m_queueMutex);
746     if (delay)
747         ++m_delayCallbacks;
748     else {
749         ASSERT(m_delayCallbacks);
750         --m_delayCallbacks;
751     }
752 }
753
754 void MediaPlayerPrivateAVFoundation::mainThreadCallback()
755 {
756     LOG(Media, "MediaPlayerPrivateAVFoundation::mainThreadCallback(%p)", this);
757
758     clearMainThreadPendingFlag();
759     dispatchNotification();
760 }
761
762 void MediaPlayerPrivateAVFoundation::clearMainThreadPendingFlag()
763 {
764     LockHolder lock(m_queueMutex);
765     m_mainThreadCallPending = false;
766 }
767
768 void MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(Notification::Type type, const MediaTime& time)
769 {
770     scheduleMainThreadNotification(Notification(type, time));
771 }
772
773 void MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(Notification::Type type, bool finished)
774 {
775     scheduleMainThreadNotification(Notification(type, finished));
776 }
777
778 #if !LOG_DISABLED
779 static const char* notificationName(MediaPlayerPrivateAVFoundation::Notification& notification)
780 {
781 #define DEFINE_TYPE_STRING_CASE(type) case MediaPlayerPrivateAVFoundation::Notification::type: return #type;
782     switch (notification.type()) {
783     FOR_EACH_MEDIAPLAYERPRIVATEAVFOUNDATION_NOTIFICATION_TYPE(DEFINE_TYPE_STRING_CASE)
784     case MediaPlayerPrivateAVFoundation::Notification::FunctionType: return "FunctionType";
785     default: ASSERT_NOT_REACHED(); return "";
786     }
787 #undef DEFINE_TYPE_STRING_CASE
788 }
789 #endif // !LOG_DISABLED
790     
791
792 void MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(Notification notification)
793 {
794     if (notification.type() != Notification::FunctionType)
795         LOG(Media, "MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(%p) - notification %s", this, notificationName(notification));
796
797     m_queueMutex.lock();
798
799     // It is important to always process the properties in the order that we are notified,
800     // so always go through the queue because notifications happen on different threads.
801     m_queuedNotifications.append(notification);
802
803 #if OS(WINDOWS)
804     bool delayDispatch = true;
805 #else
806     bool delayDispatch = m_delayCallbacks || !isMainThread();
807 #endif
808     if (delayDispatch && !m_mainThreadCallPending) {
809         m_mainThreadCallPending = true;
810
811         callOnMainThread([weakThis = createWeakPtr()] {
812             if (!weakThis)
813                 return;
814
815             weakThis->mainThreadCallback();
816         });
817     }
818
819     m_queueMutex.unlock();
820
821     if (delayDispatch) {
822         if (notification.type() != Notification::FunctionType)
823             LOG(Media, "MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(%p) - early return", this);
824         return;
825     }
826
827     dispatchNotification();
828 }
829
830 void MediaPlayerPrivateAVFoundation::dispatchNotification()
831 {
832     ASSERT(isMainThread());
833
834     Notification notification = Notification();
835     {
836         LockHolder lock(m_queueMutex);
837         
838         if (m_queuedNotifications.isEmpty())
839             return;
840         
841         if (!m_delayCallbacks) {
842             // Only dispatch one notification callback per invocation because they can cause recursion.
843             notification = m_queuedNotifications.first();
844             m_queuedNotifications.remove(0);
845         }
846         
847         if (!m_queuedNotifications.isEmpty() && !m_mainThreadCallPending) {
848             callOnMainThread([weakThis = createWeakPtr()] {
849                 if (!weakThis)
850                     return;
851
852                 weakThis->mainThreadCallback();
853             });
854         }
855
856         if (!notification.isValid())
857             return;
858     }
859
860     if (notification.type() != Notification::FunctionType)
861         LOG(Media, "MediaPlayerPrivateAVFoundation::dispatchNotification(%p) - dispatching %s", this, notificationName(notification));
862
863     switch (notification.type()) {
864     case Notification::ItemDidPlayToEndTime:
865         didEnd();
866         break;
867     case Notification::ItemTracksChanged:
868         tracksChanged();
869         updateStates();
870         break;
871     case Notification::ItemStatusChanged:
872         updateStates();
873         break;
874     case Notification::ItemSeekableTimeRangesChanged:
875         seekableTimeRangesChanged();
876         updateStates();
877         break;
878     case Notification::ItemLoadedTimeRangesChanged:
879         loadedTimeRangesChanged();
880         updateStates();
881         break;
882     case Notification::ItemPresentationSizeChanged:
883         sizeChanged();
884         updateStates();
885         break;
886     case Notification::ItemIsPlaybackLikelyToKeepUpChanged:
887         updateStates();
888         break;
889     case Notification::ItemIsPlaybackBufferEmptyChanged:
890         updateStates();
891         break;
892     case Notification::ItemIsPlaybackBufferFullChanged:
893         updateStates();
894         break;
895     case Notification::PlayerRateChanged:
896         updateStates();
897         rateChanged();
898         break;
899     case Notification::PlayerTimeChanged:
900         timeChanged(notification.time());
901         break;
902     case Notification::SeekCompleted:
903         seekCompleted(notification.finished());
904         break;
905     case Notification::AssetMetadataLoaded:
906         metadataLoaded();
907         updateStates();
908         break;
909     case Notification::AssetPlayabilityKnown:
910         updateStates();
911         playabilityKnown();
912         break;
913     case Notification::DurationChanged:
914         invalidateCachedDuration();
915         break;
916     case Notification::ContentsNeedsDisplay:
917         contentsNeedsDisplay();
918         break;
919     case Notification::InbandTracksNeedConfiguration:
920         m_inbandTrackConfigurationPending = false;
921         configureInbandTracks();
922         break;
923     case Notification::FunctionType:
924         notification.function()();
925         break;
926     case Notification::TargetIsWirelessChanged:
927 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
928         playbackTargetIsWirelessChanged();
929 #endif
930         break;
931
932     case Notification::None:
933         ASSERT_NOT_REACHED();
934         break;
935     }
936 }
937
938 void MediaPlayerPrivateAVFoundation::configureInbandTracks()
939 {
940     RefPtr<InbandTextTrackPrivateAVF> trackToEnable;
941     
942 #if ENABLE(AVF_CAPTIONS)
943     synchronizeTextTrackState();
944 #endif
945
946     // AVFoundation can only emit cues for one track at a time, so enable the first track that is showing, or the first that
947     // is hidden if none are showing. Otherwise disable all tracks.
948     for (unsigned i = 0; i < m_textTracks.size(); ++i) {
949         RefPtr<InbandTextTrackPrivateAVF> track = m_textTracks[i];
950         if (track->mode() == InbandTextTrackPrivate::Showing) {
951             trackToEnable = track;
952             break;
953         }
954         if (track->mode() == InbandTextTrackPrivate::Hidden)
955             trackToEnable = track;
956     }
957
958     setCurrentTextTrack(trackToEnable.get());
959 }
960
961 void MediaPlayerPrivateAVFoundation::trackModeChanged()
962 {
963     if (m_inbandTrackConfigurationPending)
964         return;
965     m_inbandTrackConfigurationPending = true;
966     scheduleMainThreadNotification(Notification::InbandTracksNeedConfiguration);
967 }
968
969 void MediaPlayerPrivateAVFoundation::clearTextTracks()
970 {
971     for (auto& track : m_textTracks) {
972         player()->removeTextTrack(*track);
973         track->disconnect();
974     }
975     m_textTracks.clear();
976 }
977
978 void MediaPlayerPrivateAVFoundation::processNewAndRemovedTextTracks(const Vector<RefPtr<InbandTextTrackPrivateAVF>>& removedTextTracks)
979 {
980     if (removedTextTracks.size()) {
981         for (unsigned i = 0; i < m_textTracks.size(); ) {
982             if (!removedTextTracks.contains(m_textTracks[i])) {
983                 ++i;
984                 continue;
985             }
986             player()->removeTextTrack(*m_textTracks[i]);
987             m_textTracks.remove(i);
988         }
989     }
990
991     unsigned inBandCount = 0;
992     for (unsigned i = 0; i < m_textTracks.size(); ++i) {
993         RefPtr<InbandTextTrackPrivateAVF> track = m_textTracks[i];
994
995 #if ENABLE(AVF_CAPTIONS)
996         if (track->textTrackCategory() == InbandTextTrackPrivateAVF::OutOfBand)
997             continue;
998 #endif
999
1000         track->setTextTrackIndex(inBandCount);
1001         ++inBandCount;
1002         if (track->hasBeenReported())
1003             continue;
1004         
1005         track->setHasBeenReported(true);
1006         player()->addTextTrack(*track);
1007     }
1008     LOG(Media, "MediaPlayerPrivateAVFoundation::processNewAndRemovedTextTracks(%p) - found %lu text tracks", this, m_textTracks.size());
1009 }
1010
1011 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
1012
1013 void MediaPlayerPrivateAVFoundation::playbackTargetIsWirelessChanged()
1014 {
1015     if (m_player)
1016         m_player->currentPlaybackTargetIsWirelessChanged();
1017 }
1018
1019 #endif
1020
1021 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
1022
1023 bool MediaPlayerPrivateAVFoundation::extractKeyURIKeyIDAndCertificateFromInitData(Uint8Array* initData, String& keyURI, String& keyID, RefPtr<Uint8Array>& certificate)
1024 {
1025     // initData should have the following layout:
1026     // [4 bytes: keyURI length][N bytes: keyURI][4 bytes: contentID length], [N bytes: contentID], [4 bytes: certificate length][N bytes: certificate]
1027     if (initData->byteLength() < 4)
1028         return false;
1029
1030     RefPtr<ArrayBuffer> initDataBuffer = initData->unsharedBuffer();
1031
1032     // Use a DataView to read uint32 values from the buffer, as Uint32Array requires the reads be aligned on 4-byte boundaries. 
1033     RefPtr<JSC::DataView> initDataView = JSC::DataView::create(initDataBuffer.copyRef(), 0, initDataBuffer->byteLength());
1034     uint32_t offset = 0;
1035     bool status = true;
1036
1037     uint32_t keyURILength = initDataView->get<uint32_t>(offset, true, &status);
1038     offset += 4;
1039     if (!status || offset + keyURILength > initData->length())
1040         return false;
1041
1042     RefPtr<Uint16Array> keyURIArray = Uint16Array::create(initDataBuffer.copyRef(), offset, keyURILength);
1043     if (!keyURIArray)
1044         return false;
1045
1046     keyURI = String(reinterpret_cast<UChar*>(keyURIArray->data()), keyURILength / sizeof(unsigned short));
1047     offset += keyURILength;
1048
1049     uint32_t keyIDLength = initDataView->get<uint32_t>(offset, true, &status);
1050     offset += 4;
1051     if (!status || offset + keyIDLength > initData->length())
1052         return false;
1053
1054     RefPtr<Uint8Array> keyIDArray = Uint8Array::create(initDataBuffer.copyRef(), offset, keyIDLength);
1055     if (!keyIDArray)
1056         return false;
1057
1058     keyID = String(reinterpret_cast<UChar*>(keyIDArray->data()), keyIDLength / sizeof(unsigned short));
1059     offset += keyIDLength;
1060
1061     uint32_t certificateLength = initDataView->get<uint32_t>(offset, true, &status);
1062     offset += 4;
1063     if (!status || offset + certificateLength > initData->length())
1064         return false;
1065
1066     certificate = Uint8Array::create(WTFMove(initDataBuffer), offset, certificateLength);
1067     if (!certificate)
1068         return false;
1069
1070     return true;
1071 }
1072
1073 #endif
1074
1075 URL MediaPlayerPrivateAVFoundation::resolvedURL() const
1076 {
1077     if (!m_assetURL.length())
1078         return URL();
1079
1080     return URL(ParsedURLString, m_assetURL);
1081 }
1082
1083 bool MediaPlayerPrivateAVFoundation::canSaveMediaData() const
1084 {
1085     URL url = resolvedURL();
1086
1087     if (url.isLocalFile())
1088         return true;
1089
1090     if (!url.protocolIsInHTTPFamily())
1091         return false;
1092
1093     if (isLiveStream())
1094         return false;
1095
1096     return true;
1097 }
1098
1099 bool MediaPlayerPrivateAVFoundation::isUnsupportedMIMEType(const String& type)
1100 {
1101     String lowerCaseType = type.convertToASCIILowercase();
1102
1103     // AVFoundation will return non-video MIME types which it claims to support, but which we
1104     // do not support in the <video> element. Reject all non video/, audio/, and application/ types.
1105     if (!lowerCaseType.startsWith("video/") && !lowerCaseType.startsWith("audio/") && !lowerCaseType.startsWith("application/"))
1106         return true;
1107
1108     // Reject types we know AVFoundation does not support that sites commonly ask about.
1109     if (lowerCaseType == "video/webm" || lowerCaseType == "audio/webm" || lowerCaseType == "video/x-webm")
1110         return true;
1111
1112     if (lowerCaseType == "video/x-flv")
1113         return true;
1114
1115     if (lowerCaseType == "audio/ogg" || lowerCaseType == "video/ogg" || lowerCaseType == "application/ogg")
1116         return true;
1117
1118     if (lowerCaseType == "video/h264")
1119         return true;
1120
1121     return false;
1122 }
1123
1124 const HashSet<String, ASCIICaseInsensitiveHash>& MediaPlayerPrivateAVFoundation::staticMIMETypeList()
1125 {
1126     static NeverDestroyed<HashSet<String, ASCIICaseInsensitiveHash>> cache = []() {
1127         HashSet<String, ASCIICaseInsensitiveHash> types;
1128
1129         static const char* const typeNames[] = {
1130             "application/vnd.apple.mpegurl",
1131             "application/x-mpegurl",
1132             "audio/3gpp",
1133             "audio/aac",
1134             "audio/aacp",
1135             "audio/aiff",
1136             "audio/basic",
1137             "audio/mp3",
1138             "audio/mp4",
1139             "audio/mpeg",
1140             "audio/mpeg3",
1141             "audio/mpegurl",
1142             "audio/mpg",
1143             "audio/wav",
1144             "audio/wave",
1145             "audio/x-aac",
1146             "audio/x-aiff",
1147             "audio/x-m4a",
1148             "audio/x-mpegurl",
1149             "audio/x-wav",
1150             "video/3gpp",
1151             "video/3gpp2",
1152             "video/mp4",
1153             "video/mpeg",
1154             "video/mpeg2",
1155             "video/mpg",
1156             "video/quicktime",
1157             "video/x-m4v",
1158             "video/x-mpeg",
1159             "video/x-mpg",
1160         };
1161         for (auto& type : typeNames)
1162             types.add(type);
1163
1164         return types;
1165     }();
1166
1167     return cache;
1168 }
1169
1170 } // namespace WebCore
1171
1172 #endif