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