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