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