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