Unreviewed build fix for Windows.
[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 "Frame.h"
35 #include "FrameView.h"
36 #include "GraphicsContext.h"
37 #include "InbandTextTrackPrivateAVF.h"
38 #include "InbandTextTrackPrivateClient.h"
39 #include "URL.h"
40 #include "Logging.h"
41 #include "PlatformLayer.h"
42 #include "PlatformTimeRanges.h"
43 #include "Settings.h"
44 #include "SoftLinking.h"
45 #include <CoreMedia/CoreMedia.h>
46 #include <runtime/DataView.h>
47 #include <runtime/Uint16Array.h>
48 #include <wtf/MainThread.h>
49 #include <wtf/text/CString.h>
50 #include <wtf/StringPrintStream.h>
51
52 namespace WebCore {
53
54 MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation(MediaPlayer* player)
55     : m_player(player)
56     , m_weakPtrFactory(this)
57     , m_queuedNotifications()
58     , m_queueMutex()
59     , m_networkState(MediaPlayer::Empty)
60     , m_readyState(MediaPlayer::HaveNothing)
61     , m_preload(MediaPlayer::Auto)
62     , m_cachedDuration(MediaTime::invalidTime())
63     , m_reportedDuration(MediaTime::invalidTime())
64     , m_maxTimeLoadedAtLastDidLoadingProgress(MediaTime::invalidTime())
65     , m_requestedRate(1)
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     cancelCallOnMainThread(mainThreadCallback, this);
92 }
93
94 MediaPlayerPrivateAVFoundation::MediaRenderingMode MediaPlayerPrivateAVFoundation::currentRenderingMode() const
95 {
96     if (platformLayer())
97         return MediaRenderingToLayer;
98
99     if (hasContextRenderer())
100         return MediaRenderingToContext;
101
102     return MediaRenderingNone;
103 }
104
105 MediaPlayerPrivateAVFoundation::MediaRenderingMode MediaPlayerPrivateAVFoundation::preferredRenderingMode() const
106 {
107     if (!m_player->visible() || !m_player->frameView() || assetStatus() == MediaPlayerAVAssetStatusUnknown)
108         return MediaRenderingNone;
109
110     if (supportsAcceleratedRendering() && m_player->mediaPlayerClient()->mediaPlayerRenderingCanBeAccelerated(m_player))
111         return MediaRenderingToLayer;
112
113     return MediaRenderingToContext;
114 }
115
116 void MediaPlayerPrivateAVFoundation::setUpVideoRendering()
117 {
118     if (!isReadyForVideoSetup())
119         return;
120
121     MediaRenderingMode currentMode = currentRenderingMode();
122     MediaRenderingMode preferredMode = preferredRenderingMode();
123
124     if (preferredMode == MediaRenderingNone)
125         preferredMode = MediaRenderingToContext;
126
127     if (currentMode == preferredMode && currentMode != MediaRenderingNone)
128         return;
129
130     LOG(Media, "MediaPlayerPrivateAVFoundation::setUpVideoRendering(%p) - current mode = %d, preferred mode = %d", 
131         this, static_cast<int>(currentMode), static_cast<int>(preferredMode));
132
133     if (currentMode != MediaRenderingNone)  
134         tearDownVideoRendering();
135
136     switch (preferredMode) {
137     case MediaRenderingNone:
138     case MediaRenderingToContext:
139         createContextVideoRenderer();
140         break;
141
142     case MediaRenderingToLayer:
143         createVideoLayer();
144         break;
145     }
146
147     // If using a movie layer, inform the client so the compositing tree is updated.
148     if (currentMode == MediaRenderingToLayer || preferredMode == MediaRenderingToLayer) {
149         LOG(Media, "MediaPlayerPrivateAVFoundation::setUpVideoRendering(%p) - calling mediaPlayerRenderingModeChanged()", this);
150         m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
151     }
152 }
153
154 void MediaPlayerPrivateAVFoundation::tearDownVideoRendering()
155 {
156     LOG(Media, "MediaPlayerPrivateAVFoundation::tearDownVideoRendering(%p)", this);
157
158     destroyContextVideoRenderer();
159
160     if (platformLayer())
161         destroyVideoLayer();
162 }
163
164 bool MediaPlayerPrivateAVFoundation::hasSetUpVideoRendering() const
165 {
166     return hasLayerRenderer() || hasContextRenderer();
167 }
168
169 void MediaPlayerPrivateAVFoundation::load(const String& url)
170 {
171     LOG(Media, "MediaPlayerPrivateAVFoundation::load(%p)", this);
172
173     if (m_networkState != MediaPlayer::Loading) {
174         m_networkState = MediaPlayer::Loading;
175         m_player->networkStateChanged();
176     }
177     if (m_readyState != MediaPlayer::HaveNothing) {
178         m_readyState = MediaPlayer::HaveNothing;
179         m_player->readyStateChanged();
180     }
181
182     m_assetURL = url;
183
184     // Don't do any more work if the url is empty.
185     if (!url.length())
186         return;
187
188     setPreload(m_preload);
189 }
190
191 #if ENABLE(MEDIA_SOURCE)
192 void MediaPlayerPrivateAVFoundation::load(const String&, MediaSourcePrivateClient*)
193 {
194     m_networkState = MediaPlayer::FormatError;
195     m_player->networkStateChanged();
196 }
197 #endif
198
199
200 void MediaPlayerPrivateAVFoundation::playabilityKnown()
201 {
202     LOG(Media, "MediaPlayerPrivateAVFoundation::playabilityKnown(%p)", this);
203
204     if (m_assetIsPlayable)
205         return;
206
207     // Nothing more to do if we already have all of the item's metadata.
208     if (assetStatus() > MediaPlayerAVAssetStatusLoading) {
209         LOG(Media, "MediaPlayerPrivateAVFoundation::playabilityKnown(%p) - all metadata loaded", this);
210         return;
211     }
212
213     // At this point we are supposed to load metadata. It is OK to ask the asset to load the same 
214     // information multiple times, because if it has already been loaded the completion handler 
215     // will just be called synchronously.
216     m_loadingMetadata = true;
217     beginLoadingMetadata();
218 }
219
220 void MediaPlayerPrivateAVFoundation::prepareToPlay()
221 {
222     LOG(Media, "MediaPlayerPrivateAVFoundation::prepareToPlay(%p)", this);
223
224     setPreload(MediaPlayer::Auto);
225 }
226
227 void MediaPlayerPrivateAVFoundation::play()
228 {
229     LOG(Media, "MediaPlayerPrivateAVFoundation::play(%p)", this);
230
231     // If the file has video, don't request playback until the first frame of video is ready to display
232     // or the audio may start playing before we can render video.
233     if (!m_cachedHasVideo || hasAvailableVideoFrame())
234         platformPlay();
235     else
236         m_playWhenFramesAvailable = true;
237 }
238
239 void MediaPlayerPrivateAVFoundation::pause()
240 {
241     LOG(Media, "MediaPlayerPrivateAVFoundation::pause(%p)", this);
242     m_playWhenFramesAvailable = false;
243     platformPause();
244 }
245
246 MediaTime MediaPlayerPrivateAVFoundation::durationMediaTime() const
247 {
248     if (m_cachedDuration.isValid())
249         return m_cachedDuration;
250
251     MediaTime duration = platformDuration();
252     if (!duration || duration.isInvalid())
253         return MediaTime::zeroTime();
254
255     m_cachedDuration = duration;
256     LOG(Media, "MediaPlayerPrivateAVFoundation::duration(%p) - caching %s", this, toString(m_cachedDuration).utf8().data());
257     return m_cachedDuration;
258 }
259
260 void MediaPlayerPrivateAVFoundation::seek(const MediaTime& time)
261 {
262     seekWithTolerance(time, MediaTime::zeroTime(), MediaTime::zeroTime());
263 }
264
265 void MediaPlayerPrivateAVFoundation::seekWithTolerance(const MediaTime& mediaTime, const MediaTime& negativeTolerance, const MediaTime& positiveTolerance)
266 {
267     MediaTime time = mediaTime;
268
269     if (m_seeking) {
270         LOG(Media, "MediaPlayerPrivateAVFoundation::seekWithTolerance(%p) - save pending seek", this);
271         m_pendingSeek = [this, time, negativeTolerance, positiveTolerance]() {
272             seekWithTolerance(time, negativeTolerance, positiveTolerance);
273         };
274         return;
275     }
276     m_seeking = true;
277
278     if (!metaDataAvailable())
279         return;
280
281     if (time > durationMediaTime())
282         time = durationMediaTime();
283
284     if (currentMediaTime() == time)
285         return;
286
287     if (currentTextTrack())
288         currentTextTrack()->beginSeeking();
289
290     LOG(Media, "MediaPlayerPrivateAVFoundation::seek(%p) - seeking to %s", this, toString(time).utf8().data());
291
292     seekToTime(time, negativeTolerance, positiveTolerance);
293 }
294
295 void MediaPlayerPrivateAVFoundation::setRate(float rate)
296 {
297     LOG(Media, "MediaPlayerPrivateAVFoundation::setRate(%p) - seting to %f", this, rate);
298     m_requestedRate = rate;
299
300     updateRate();
301 }
302
303 bool MediaPlayerPrivateAVFoundation::paused() const
304 {
305     if (!metaDataAvailable())
306         return true;
307
308     return rate() == 0;
309 }
310
311 bool MediaPlayerPrivateAVFoundation::seeking() const
312 {
313     if (!metaDataAvailable())
314         return false;
315
316     return m_seeking;
317 }
318
319 IntSize MediaPlayerPrivateAVFoundation::naturalSize() const
320 {
321     if (!metaDataAvailable())
322         return IntSize();
323
324     // In spite of the name of this method, return the natural size transformed by the 
325     // initial movie scale because the spec says intrinsic size is:
326     //
327     //    ... the dimensions of the resource in CSS pixels after taking into account the resource's 
328     //    dimensions, aspect ratio, clean aperture, resolution, and so forth, as defined for the 
329     //    format used by the resource
330
331     return m_cachedNaturalSize;
332 }
333
334 void MediaPlayerPrivateAVFoundation::setNaturalSize(IntSize size)
335 {
336     LOG(Media, "MediaPlayerPrivateAVFoundation:setNaturalSize(%p) - size = %d x %d", this, size.width(), size.height());
337
338     IntSize oldSize = m_cachedNaturalSize;
339     m_cachedNaturalSize = size;
340     if (oldSize != m_cachedNaturalSize)
341         m_player->sizeChanged();
342 }
343
344 void MediaPlayerPrivateAVFoundation::setHasVideo(bool b)
345 {
346     if (m_cachedHasVideo != b) {
347         m_cachedHasVideo = b;
348         characteristicsChanged();
349     }
350 }
351
352 void MediaPlayerPrivateAVFoundation::setHasAudio(bool b)
353 {
354     if (m_cachedHasAudio != b) {
355         m_cachedHasAudio = b;
356         characteristicsChanged();
357     }
358 }
359
360 void MediaPlayerPrivateAVFoundation::setHasClosedCaptions(bool b)
361 {
362     if (m_cachedHasCaptions != b) {
363         m_cachedHasCaptions = b;
364         characteristicsChanged();
365     }
366 }
367
368 void MediaPlayerPrivateAVFoundation::characteristicsChanged()
369 {
370     if (m_delayCharacteristicsChangedNotification) {
371         m_characteristicsChanged = true;
372         return;
373     }
374
375     m_characteristicsChanged = false;
376     m_player->characteristicChanged();
377 }
378
379 void MediaPlayerPrivateAVFoundation::setDelayCharacteristicsChangedNotification(bool delay)
380 {
381     if (delay) {
382         m_delayCharacteristicsChangedNotification++;
383         return;
384     }
385     
386     ASSERT(m_delayCharacteristicsChangedNotification);
387     m_delayCharacteristicsChangedNotification--;
388     if (!m_delayCharacteristicsChangedNotification && m_characteristicsChanged)
389         characteristicsChanged();
390 }
391
392 std::unique_ptr<PlatformTimeRanges> MediaPlayerPrivateAVFoundation::buffered() const
393 {
394     if (!m_cachedLoadedTimeRanges)
395         m_cachedLoadedTimeRanges = platformBufferedTimeRanges();
396
397     return PlatformTimeRanges::create(*m_cachedLoadedTimeRanges);
398 }
399
400 MediaTime MediaPlayerPrivateAVFoundation::maxMediaTimeSeekable() const
401 {
402     if (!metaDataAvailable())
403         return MediaTime::zeroTime();
404
405     if (!m_cachedMaxTimeSeekable)
406         m_cachedMaxTimeSeekable = platformMaxTimeSeekable();
407
408     LOG(Media, "MediaPlayerPrivateAVFoundation::maxTimeSeekable(%p) - returning %s", this, toString(m_cachedMaxTimeSeekable).utf8().data());
409     return m_cachedMaxTimeSeekable;   
410 }
411
412 MediaTime MediaPlayerPrivateAVFoundation::minMediaTimeSeekable() const
413 {
414     if (!metaDataAvailable())
415         return MediaTime::zeroTime();
416
417     if (!m_cachedMinTimeSeekable)
418         m_cachedMinTimeSeekable = platformMinTimeSeekable();
419
420     LOG(Media, "MediaPlayerPrivateAVFoundation::minTimeSeekable(%p) - returning %s", this, toString(m_cachedMinTimeSeekable).utf8().data());
421     return m_cachedMinTimeSeekable;
422 }
423
424 MediaTime MediaPlayerPrivateAVFoundation::maxTimeLoaded() const
425 {
426     if (!metaDataAvailable())
427         return MediaTime::zeroTime();
428
429     if (!m_cachedMaxTimeLoaded)
430         m_cachedMaxTimeLoaded = platformMaxTimeLoaded();
431
432     return m_cachedMaxTimeLoaded;   
433 }
434
435 bool MediaPlayerPrivateAVFoundation::didLoadingProgress() const
436 {
437     if (!duration() || !totalBytes())
438         return false;
439     MediaTime currentMaxTimeLoaded = maxTimeLoaded();
440     bool didLoadingProgress = currentMaxTimeLoaded != m_maxTimeLoadedAtLastDidLoadingProgress;
441     m_maxTimeLoadedAtLastDidLoadingProgress = currentMaxTimeLoaded;
442
443     return didLoadingProgress;
444 }
445
446 bool MediaPlayerPrivateAVFoundation::isReadyForVideoSetup() const
447 {
448     // AVFoundation will not return true for firstVideoFrameAvailable until
449     // an AVPlayerLayer has been added to the AVPlayerItem, so allow video setup
450     // here if a video track to trigger allocation of a AVPlayerLayer.
451     return (m_isAllowedToRender || m_cachedHasVideo) && m_readyState >= MediaPlayer::HaveMetadata && m_player->visible();
452 }
453
454 void MediaPlayerPrivateAVFoundation::prepareForRendering()
455 {
456     if (m_isAllowedToRender)
457         return;
458     m_isAllowedToRender = true;
459
460     setUpVideoRendering();
461
462     if (currentRenderingMode() == MediaRenderingToLayer || preferredRenderingMode() == MediaRenderingToLayer)
463         m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
464 }
465
466 bool MediaPlayerPrivateAVFoundation::supportsFullscreen() const
467 {
468 #if ENABLE(FULLSCREEN_API)
469     return true;
470 #else
471     // FIXME: WebVideoFullscreenController assumes a QTKit/QuickTime media engine
472 #if PLATFORM(IOS)
473     if (Settings::avKitEnabled())
474         return true;
475 #endif
476     return false;
477 #endif
478 }
479
480 void MediaPlayerPrivateAVFoundation::updateStates()
481 {
482     if (m_ignoreLoadStateChanges)
483         return;
484
485     MediaPlayer::NetworkState oldNetworkState = m_networkState;
486     MediaPlayer::ReadyState oldReadyState = m_readyState;
487
488     if (m_loadingMetadata)
489         m_networkState = MediaPlayer::Loading;
490     else {
491         // -loadValuesAsynchronouslyForKeys:completionHandler: has invoked its handler; test status of keys and determine state.
492         AssetStatus assetStatus = this->assetStatus();
493         ItemStatus itemStatus = playerItemStatus();
494         
495         m_assetIsPlayable = (assetStatus == MediaPlayerAVAssetStatusPlayable);
496         if (m_readyState < MediaPlayer::HaveMetadata && assetStatus > MediaPlayerAVAssetStatusLoading) {
497             if (m_assetIsPlayable) {
498                 if (assetStatus >= MediaPlayerAVAssetStatusLoaded)
499                     m_readyState = MediaPlayer::HaveMetadata;
500                 if (itemStatus <= MediaPlayerAVPlayerItemStatusUnknown) {
501                     if (assetStatus == MediaPlayerAVAssetStatusFailed || m_preload > MediaPlayer::MetaData || isLiveStream()) {
502                         // The asset is playable but doesn't support inspection prior to playback (eg. streaming files),
503                         // or we are supposed to prepare for playback immediately, so create the player item now.
504                         m_networkState = MediaPlayer::Loading;
505                         prepareToPlay();
506                     } else
507                         m_networkState = MediaPlayer::Idle;
508                 }
509             } else {
510                 // FIX ME: fetch the error associated with the @"playable" key to distinguish between format 
511                 // and network errors.
512                 m_networkState = MediaPlayer::FormatError;
513             }
514         }
515         
516         if (assetStatus >= MediaPlayerAVAssetStatusLoaded && itemStatus > MediaPlayerAVPlayerItemStatusUnknown) {
517             switch (itemStatus) {
518             case MediaPlayerAVPlayerItemStatusDoesNotExist:
519             case MediaPlayerAVPlayerItemStatusUnknown:
520             case MediaPlayerAVPlayerItemStatusFailed:
521                 break;
522
523             case MediaPlayerAVPlayerItemStatusPlaybackLikelyToKeepUp:
524             case MediaPlayerAVPlayerItemStatusPlaybackBufferFull:
525                 // If the status becomes PlaybackBufferFull, loading stops and the status will not
526                 // progress to LikelyToKeepUp. Set the readyState to  HAVE_ENOUGH_DATA, on the
527                 // presumption that if the playback buffer is full, playback will probably not stall.
528                 m_readyState = MediaPlayer::HaveEnoughData;
529                 break;
530
531             case MediaPlayerAVPlayerItemStatusReadyToPlay:
532                 // If the readyState is already HaveEnoughData, don't go lower because of this state change.
533                 if (m_readyState == MediaPlayer::HaveEnoughData)
534                     break;
535                 FALLTHROUGH;
536
537             case MediaPlayerAVPlayerItemStatusPlaybackBufferEmpty:
538                 if (maxTimeLoaded() > currentMediaTime())
539                     m_readyState = MediaPlayer::HaveFutureData;
540                 else
541                     m_readyState = MediaPlayer::HaveCurrentData;
542                 break;
543             }
544
545             if (itemStatus == MediaPlayerAVPlayerItemStatusPlaybackBufferFull)
546                 m_networkState = MediaPlayer::Idle;
547             else if (itemStatus == MediaPlayerAVPlayerItemStatusFailed)
548                 m_networkState = MediaPlayer::DecodeError;
549             else if (itemStatus != MediaPlayerAVPlayerItemStatusPlaybackBufferFull && itemStatus >= MediaPlayerAVPlayerItemStatusReadyToPlay)
550                 m_networkState = (maxTimeLoaded() == durationMediaTime()) ? MediaPlayer::Loaded : MediaPlayer::Loading;
551         }
552     }
553
554     if (isReadyForVideoSetup() && currentRenderingMode() != preferredRenderingMode())
555         setUpVideoRendering();
556
557     if (!m_haveReportedFirstVideoFrame && m_cachedHasVideo && hasAvailableVideoFrame()) {
558         if (m_readyState < MediaPlayer::HaveCurrentData)
559             m_readyState = MediaPlayer::HaveCurrentData;
560         m_haveReportedFirstVideoFrame = true;
561         m_player->firstVideoFrameAvailable();
562     }
563
564     if (m_networkState != oldNetworkState)
565         m_player->networkStateChanged();
566
567     if (m_readyState != oldReadyState)
568         m_player->readyStateChanged();
569
570     if (m_playWhenFramesAvailable && hasAvailableVideoFrame()) {
571         m_playWhenFramesAvailable = false;
572         platformPlay();
573     }
574
575 #if !LOG_DISABLED
576     if (m_networkState != oldNetworkState || oldReadyState != m_readyState) {
577         LOG(Media, "MediaPlayerPrivateAVFoundation::updateStates(%p) - entered with networkState = %i, readyState = %i,  exiting with networkState = %i, readyState = %i",
578             this, static_cast<int>(oldNetworkState), static_cast<int>(oldReadyState), static_cast<int>(m_networkState), static_cast<int>(m_readyState));
579     }
580 #endif
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(IOS_AIRPLAY)
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     LOG(Media, "MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(%p) - notification %s", this, notificationName(notification));
792     m_queueMutex.lock();
793
794     // It is important to always process the properties in the order that we are notified, 
795     // so always go through the queue because notifications happen on different threads.
796     m_queuedNotifications.append(notification);
797
798 #if OS(WINDOWS)
799     bool delayDispatch = true;
800 #else
801     bool delayDispatch = m_delayCallbacks || !isMainThread();
802 #endif
803     if (delayDispatch && !m_mainThreadCallPending) {
804         m_mainThreadCallPending = true;
805         callOnMainThread(mainThreadCallback, this);
806     }
807
808     m_queueMutex.unlock();
809
810     if (delayDispatch) {
811         LOG(Media, "MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(%p) - early return", this);
812         return;
813     }
814
815     dispatchNotification();
816 }
817
818 void MediaPlayerPrivateAVFoundation::dispatchNotification()
819 {
820     ASSERT(isMainThread());
821
822     Notification notification = Notification();
823     {
824         MutexLocker lock(m_queueMutex);
825         
826         if (m_queuedNotifications.isEmpty())
827             return;
828         
829         if (!m_delayCallbacks) {
830             // Only dispatch one notification callback per invocation because they can cause recursion.
831             notification = m_queuedNotifications.first();
832             m_queuedNotifications.remove(0);
833         }
834         
835         if (!m_queuedNotifications.isEmpty() && !m_mainThreadCallPending)
836             callOnMainThread(mainThreadCallback, this);
837
838         if (!notification.isValid())
839             return;
840     }
841
842     LOG(Media, "MediaPlayerPrivateAVFoundation::dispatchNotification(%p) - dispatching %s", this, notificationName(notification));
843
844     switch (notification.type()) {
845     case Notification::ItemDidPlayToEndTime:
846         didEnd();
847         break;
848     case Notification::ItemTracksChanged:
849         tracksChanged();
850         updateStates();
851         break;
852     case Notification::ItemStatusChanged:
853         updateStates();
854         break;
855     case Notification::ItemSeekableTimeRangesChanged:
856         seekableTimeRangesChanged();
857         updateStates();
858         break;
859     case Notification::ItemLoadedTimeRangesChanged:
860         loadedTimeRangesChanged();
861         updateStates();
862         break;
863     case Notification::ItemPresentationSizeChanged:
864         sizeChanged();
865         updateStates();
866         break;
867     case Notification::ItemIsPlaybackLikelyToKeepUpChanged:
868         updateStates();
869         break;
870     case Notification::ItemIsPlaybackBufferEmptyChanged:
871         updateStates();
872         break;
873     case Notification::ItemIsPlaybackBufferFullChanged:
874         updateStates();
875         break;
876     case Notification::PlayerRateChanged:
877         updateStates();
878         rateChanged();
879         break;
880     case Notification::PlayerTimeChanged:
881         timeChanged(notification.time());
882         break;
883     case Notification::SeekCompleted:
884         seekCompleted(notification.finished());
885         break;
886     case Notification::AssetMetadataLoaded:
887         metadataLoaded();
888         updateStates();
889         break;
890     case Notification::AssetPlayabilityKnown:
891         updateStates();
892         playabilityKnown();
893         break;
894     case Notification::DurationChanged:
895         invalidateCachedDuration();
896         break;
897     case Notification::ContentsNeedsDisplay:
898         contentsNeedsDisplay();
899         break;
900     case Notification::InbandTracksNeedConfiguration:
901         m_inbandTrackConfigurationPending = false;
902         configureInbandTracks();
903         break;
904     case Notification::FunctionType:
905         notification.function()();
906         break;
907     case Notification::TargetIsWirelessChanged:
908 #if ENABLE(IOS_AIRPLAY)
909         playbackTargetIsWirelessChanged();
910 #endif
911         break;
912
913     case Notification::None:
914         ASSERT_NOT_REACHED();
915         break;
916     }
917 }
918
919 void MediaPlayerPrivateAVFoundation::configureInbandTracks()
920 {
921     RefPtr<InbandTextTrackPrivateAVF> trackToEnable;
922     
923 #if ENABLE(AVF_CAPTIONS)
924     synchronizeTextTrackState();
925 #endif
926
927     // AVFoundation can only emit cues for one track at a time, so enable the first track that is showing, or the first that
928     // is hidden if none are showing. Otherwise disable all tracks.
929     for (unsigned i = 0; i < m_textTracks.size(); ++i) {
930         RefPtr<InbandTextTrackPrivateAVF> track = m_textTracks[i];
931         if (track->mode() == InbandTextTrackPrivate::Showing) {
932             trackToEnable = track;
933             break;
934         }
935         if (track->mode() == InbandTextTrackPrivate::Hidden)
936             trackToEnable = track;
937     }
938
939     setCurrentTextTrack(trackToEnable.get());
940 }
941
942 void MediaPlayerPrivateAVFoundation::trackModeChanged()
943 {
944     if (m_inbandTrackConfigurationPending)
945         return;
946     m_inbandTrackConfigurationPending = true;
947     scheduleMainThreadNotification(Notification::InbandTracksNeedConfiguration);
948 }
949
950 size_t MediaPlayerPrivateAVFoundation::extraMemoryCost() const
951 {
952     MediaTime duration = this->durationMediaTime();
953     if (!duration)
954         return 0;
955
956     unsigned long long extra = totalBytes() * buffered()->totalDuration().toDouble() / duration.toDouble();
957     return static_cast<unsigned>(extra);
958 }
959
960 void MediaPlayerPrivateAVFoundation::clearTextTracks()
961 {
962     for (unsigned i = 0; i < m_textTracks.size(); ++i) {
963         RefPtr<InbandTextTrackPrivateAVF> track = m_textTracks[i];
964         player()->removeTextTrack(track);
965         track->disconnect();
966     }
967     m_textTracks.clear();
968 }
969
970 void MediaPlayerPrivateAVFoundation::processNewAndRemovedTextTracks(const Vector<RefPtr<InbandTextTrackPrivateAVF>>& removedTextTracks)
971 {
972     if (removedTextTracks.size()) {
973         for (unsigned i = 0; i < m_textTracks.size(); ++i) {
974             if (!removedTextTracks.contains(m_textTracks[i]))
975                 continue;
976             
977             player()->removeTextTrack(removedTextTracks[i].get());
978             m_textTracks.remove(i);
979         }
980     }
981
982     unsigned inBandCount = 0;
983     for (unsigned i = 0; i < m_textTracks.size(); ++i) {
984         RefPtr<InbandTextTrackPrivateAVF> track = m_textTracks[i];
985
986 #if ENABLE(AVF_CAPTIONS)
987         if (track->textTrackCategory() == InbandTextTrackPrivateAVF::OutOfBand)
988             continue;
989 #endif
990
991         track->setTextTrackIndex(inBandCount);
992         ++inBandCount;
993         if (track->hasBeenReported())
994             continue;
995         
996         track->setHasBeenReported(true);
997         player()->addTextTrack(track.get());
998     }
999     LOG(Media, "MediaPlayerPrivateAVFoundation::processNewAndRemovedTextTracks(%p) - found %lu text tracks", this, m_textTracks.size());
1000 }
1001
1002 #if ENABLE(IOS_AIRPLAY)
1003 void MediaPlayerPrivateAVFoundation::playbackTargetIsWirelessChanged()
1004 {
1005     if (m_player)
1006         m_player->currentPlaybackTargetIsWirelessChanged();
1007 }
1008 #endif
1009
1010 #if ENABLE(ENCRYPTED_MEDIA) || ENABLE(ENCRYPTED_MEDIA_V2)
1011 bool MediaPlayerPrivateAVFoundation::extractKeyURIKeyIDAndCertificateFromInitData(Uint8Array* initData, String& keyURI, String& keyID, RefPtr<Uint8Array>& certificate)
1012 {
1013     // initData should have the following layout:
1014     // [4 bytes: keyURI length][N bytes: keyURI][4 bytes: contentID length], [N bytes: contentID], [4 bytes: certificate length][N bytes: certificate]
1015     if (initData->byteLength() < 4)
1016         return false;
1017
1018     RefPtr<ArrayBuffer> initDataBuffer = initData->buffer();
1019
1020     // Use a DataView to read uint32 values from the buffer, as Uint32Array requires the reads be aligned on 4-byte boundaries. 
1021     RefPtr<JSC::DataView> initDataView = JSC::DataView::create(initDataBuffer, 0, initDataBuffer->byteLength());
1022     uint32_t offset = 0;
1023     bool status = true;
1024
1025     uint32_t keyURILength = initDataView->get<uint32_t>(offset, true, &status);
1026     offset += 4;
1027     if (!status || offset + keyURILength > initData->length())
1028         return false;
1029
1030     RefPtr<Uint16Array> keyURIArray = Uint16Array::create(initDataBuffer, offset, keyURILength);
1031     if (!keyURIArray)
1032         return false;
1033
1034     keyURI = String(reinterpret_cast<UChar*>(keyURIArray->data()), keyURILength / sizeof(unsigned short));
1035     offset += keyURILength;
1036
1037     uint32_t keyIDLength = initDataView->get<uint32_t>(offset, true, &status);
1038     offset += 4;
1039     if (!status || offset + keyIDLength > initData->length())
1040         return false;
1041
1042     RefPtr<Uint16Array> keyIDArray = Uint16Array::create(initDataBuffer, offset, keyIDLength);
1043     if (!keyIDArray)
1044         return false;
1045
1046     keyID = String(reinterpret_cast<UChar*>(keyIDArray->data()), keyIDLength / sizeof(unsigned short));
1047     offset += keyIDLength;
1048
1049     uint32_t certificateLength = initDataView->get<uint32_t>(offset, true, &status);
1050     offset += 4;
1051     if (!status || offset + certificateLength > initData->length())
1052         return false;
1053
1054     certificate = Uint8Array::create(initDataBuffer, offset, certificateLength);
1055     if (!certificate)
1056         return false;
1057
1058     return true;
1059 }
1060 #endif
1061
1062 } // namespace WebCore
1063
1064 #endif