diff options
author | Ben Murdoch <benm@google.com> | 2011-06-02 12:07:03 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-06-10 10:47:21 +0100 |
commit | 2daae5fd11344eaa88a0d92b0f6d65f8d2255c00 (patch) | |
tree | e4964fbd1cb70599f7718ff03e50ea1dab33890b /Source/WebCore/platform/graphics/avfoundation | |
parent | 87bdf0060a247bfbe668342b87e0874182e0ffa9 (diff) | |
download | external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.zip external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.gz external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.bz2 |
Merge WebKit at r84325: Initial merge by git.
Change-Id: Ic1a909300ecc0a13ddc6b4e784371d2ac6e3d59b
Diffstat (limited to 'Source/WebCore/platform/graphics/avfoundation')
4 files changed, 119 insertions, 28 deletions
diff --git a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp index eb96532..681003f 100644 --- a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp +++ b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp @@ -74,6 +74,8 @@ MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation(MediaPlayer* play , m_cachedHasVideo(false) , m_cachedHasCaptions(false) , m_ignoreLoadStateChanges(false) + , m_haveReportedFirstVideoFrame(false) + , m_playWhenFramesAvailable(false) { LOG(Media, "MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation(%p)", this); } @@ -248,6 +250,25 @@ void MediaPlayerPrivateAVFoundation::prepareToPlay() checkPlayability(); } +void MediaPlayerPrivateAVFoundation::play() +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::play(%p)", this); + + // If the file has video, don't request playback until the first frame of video is ready to display + // or the audio may start playing before we can render video. + if (!m_cachedHasVideo || hasAvailableVideoFrame()) + platformPlay(); + else + m_playWhenFramesAvailable = true; +} + +void MediaPlayerPrivateAVFoundation::pause() +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::pause(%p)", this); + m_playWhenFramesAvailable = false; + platformPause(); +} + void MediaPlayerPrivateAVFoundation::paint(GraphicsContext*, const IntRect&) { // This is the base class, only need to remember that a frame has been drawn. @@ -285,6 +306,8 @@ void MediaPlayerPrivateAVFoundation::setRate(float rate) { LOG(Media, "MediaPlayerPrivateAVFoundation::setRate(%p) - seting to %f", this, rate); m_requestedRate = rate; + + updateRate(); } bool MediaPlayerPrivateAVFoundation::paused() const @@ -464,12 +487,22 @@ void MediaPlayerPrivateAVFoundation::updateStates() if (isReadyForVideoSetup() && currentRenderingMode() != preferredRenderingMode()) setUpVideoRendering(); + if (!m_haveReportedFirstVideoFrame && m_cachedHasVideo && hasAvailableVideoFrame()) { + m_haveReportedFirstVideoFrame = true; + m_player->firstVideoFrameAvailable(); + } + if (m_networkState != oldNetworkState) m_player->networkStateChanged(); if (m_readyState != oldReadyState) m_player->readyStateChanged(); + if (m_playWhenFramesAvailable && hasAvailableVideoFrame()) { + m_playWhenFramesAvailable = false; + platformPlay(); + } + LOG(Media, "MediaPlayerPrivateAVFoundation::updateStates(%p) - exiting with networkState = %i, readyState = %i", this, static_cast<int>(m_networkState), static_cast<int>(m_readyState)); } @@ -566,6 +599,14 @@ void MediaPlayerPrivateAVFoundation::timeChanged(double time) } } +void MediaPlayerPrivateAVFoundation::seekCompleted(bool finished) +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::seekCompleted(%p) - finished = %d", this, finished); + + if (finished) + m_seekTo = invalidTime; +} + void MediaPlayerPrivateAVFoundation::didEnd() { // Hang onto the current time and use it as duration from now on since we are definitely at @@ -629,12 +670,22 @@ void MediaPlayerPrivateAVFoundation::clearMainThreadPendingFlag() void MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(Notification::Type type, double time) { - LOG(Media, "MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(%p) - notification %d", this, static_cast<int>(type)); + scheduleMainThreadNotification(Notification(type, time)); +} + +void MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(Notification::Type type, bool finished) +{ + scheduleMainThreadNotification(Notification(type, finished)); +} + +void MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(Notification notification) +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(%p) - notification %d", this, static_cast<int>(notification.type())); m_queueMutex.lock(); // It is important to always process the properties in the order that we are notified, // so always go through the queue because notifications happen on different threads. - m_queuedNotifications.append(Notification(type, time)); + m_queuedNotifications.append(notification); bool delayDispatch = m_delayCallbacks || !isMainThread(); if (delayDispatch && !m_mainThreadCallPending) { @@ -714,6 +765,9 @@ void MediaPlayerPrivateAVFoundation::dispatchNotification() case Notification::PlayerTimeChanged: timeChanged(notification.time()); break; + case Notification::SeekCompleted: + seekCompleted(notification.finished()); + break; case Notification::AssetMetadataLoaded: metadataLoaded(); break; diff --git a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h index a768ab4..becba61 100644 --- a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h +++ b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h @@ -48,6 +48,7 @@ public: virtual void loadedTimeRangesChanged(); virtual void seekableTimeRangesChanged(); virtual void timeChanged(double); + virtual void seekCompleted(bool); virtual void didEnd(); class Notification { @@ -66,31 +67,45 @@ public: AssetMetadataLoaded, AssetPlayabilityKnown, PlayerRateChanged, - PlayerTimeChanged + PlayerTimeChanged, + SeekCompleted, }; Notification() : m_type(None) , m_time(0) + , m_finished(false) { } Notification(Type type, double time) : m_type(type) , m_time(time) + , m_finished(false) + { + } + + Notification(Type type, bool finished) + : m_type(type) + , m_time(0) + , m_finished(finished) { } Type type() { return m_type; } bool isValid() { return m_type != None; } double time() { return m_time; } + bool finished() { return m_finished; } private: Type m_type; double m_time; + bool m_finished; }; + void scheduleMainThreadNotification(Notification); void scheduleMainThreadNotification(Notification::Type, double time = 0); + void scheduleMainThreadNotification(Notification::Type, bool completed); void dispatchNotification(); void clearMainThreadPendingFlag(); @@ -105,8 +120,8 @@ protected: virtual void prepareToPlay(); virtual PlatformMedia platformMedia() const = 0; - virtual void play() = 0; - virtual void pause() = 0; + virtual void play(); + virtual void pause(); virtual IntSize naturalSize() const; virtual bool hasVideo() const { return m_cachedHasVideo; } @@ -169,7 +184,10 @@ protected: }; virtual AVAssetStatus assetStatus() const = 0; + virtual void platformPlay() = 0; + virtual void platformPause() = 0; virtual void checkPlayability() = 0; + virtual void updateRate() = 0; virtual float rate() const = 0; virtual void seekToTime(float time) = 0; virtual unsigned totalBytes() const = 0; @@ -254,6 +272,8 @@ private: bool m_cachedHasVideo; bool m_cachedHasCaptions; bool m_ignoreLoadStateChanges; + bool m_haveReportedFirstVideoFrame; + bool m_playWhenFramesAvailable; }; } diff --git a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h index cc00c15..7f214b8 100644 --- a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h +++ b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h @@ -73,8 +73,8 @@ private: virtual PlatformMedia platformMedia() const; - virtual void play(); - virtual void pause(); + virtual void platformPlay(); + virtual void platformPause(); virtual float currentTime() const; virtual void setVolume(float); virtual void setClosedCaptionsVisible(bool); @@ -93,6 +93,7 @@ private: virtual MediaPlayerPrivateAVFoundation::AVAssetStatus assetStatus() const; virtual void checkPlayability(); + virtual void updateRate(); virtual float rate() const; virtual void seekToTime(float time); virtual unsigned totalBytes() const; diff --git a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm index 55eb433..c4efb9f 100644 --- a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm +++ b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm @@ -100,6 +100,7 @@ enum MediaPlayerAVFoundationObservationContext { -(void)playableKnown; -(void)metadataLoaded; -(void)timeChanged:(double)time; +-(void)seekCompleted:(BOOL)finished; -(void)didEnd:(NSNotification *)notification; -(void)observeValueForKeyPath:keyPath ofObject:(id)object change:(NSDictionary *)change context:(MediaPlayerAVFoundationObservationContext)context; @end @@ -200,7 +201,7 @@ void MediaPlayerPrivateAVFoundationObjC::destroyContextVideoRenderer() if (!m_imageGenerator) return; - LOG(Media, "MediaPlayerPrivateAVFoundationObjC::destroyContextVideoRenderer(%p) - destroying", this, m_imageGenerator.get()); + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::destroyContextVideoRenderer(%p) - destroying %p", this, m_imageGenerator.get()); m_imageGenerator = 0; } @@ -213,7 +214,7 @@ void MediaPlayerPrivateAVFoundationObjC::createVideoLayer() if (!m_videoLayer) { m_videoLayer.adoptNS([[AVPlayerLayer alloc] init]); [m_videoLayer.get() setPlayer:m_avPlayer.get()]; - LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createVideoLayer(%p) - returning", this, m_videoLayer.get()); + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createVideoLayer(%p) - returning %p", this, m_videoLayer.get()); } } @@ -327,9 +328,9 @@ MediaPlayerPrivateAVFoundation::ItemStatus MediaPlayerPrivateAVFoundationObjC::p return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusFailed; if ([m_avPlayerItem.get() isPlaybackLikelyToKeepUp]) return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackLikelyToKeepUp; - if ([m_avPlayerItem.get() isPlaybackBufferFull]) + if (buffered()->contain(duration())) return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferFull; - if ([m_avPlayerItem.get() isPlaybackBufferEmpty]) + if (buffered()->contain(currentTime())) return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferEmpty; return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusReadyToPlay; @@ -350,9 +351,9 @@ PlatformLayer* MediaPlayerPrivateAVFoundationObjC::platformLayer() const return m_videoLayer.get(); } -void MediaPlayerPrivateAVFoundationObjC::play() +void MediaPlayerPrivateAVFoundationObjC::platformPlay() { - LOG(Media, "MediaPlayerPrivateAVFoundationObjC::play(%p)", this); + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::platformPlay(%p)", this); if (!metaDataAvailable()) return; @@ -361,9 +362,9 @@ void MediaPlayerPrivateAVFoundationObjC::play() setDelayCallbacks(false); } -void MediaPlayerPrivateAVFoundationObjC::pause() +void MediaPlayerPrivateAVFoundationObjC::platformPause() { - LOG(Media, "MediaPlayerPrivateAVFoundationObjC::pause(%p)", this); + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::platformPause(%p)", this); if (!metaDataAvailable()) return; @@ -408,14 +409,10 @@ void MediaPlayerPrivateAVFoundationObjC::seekToTime(float time) // setCurrentTime generates several event callbacks, update afterwards. setDelayCallbacks(true); - float now = currentTime(); - if (time != now) - [m_avPlayerItem.get() seekToTime:CMTimeMakeWithSeconds(time, 600) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero]; - else { - // Force a call to the "time changed" notifier manually because a seek to the current time is a noop - // so the seek will never seem to complete. - [m_objcObserver.get() timeChanged:now]; - } + WebCoreAVFMovieObserver *observer = m_objcObserver.get(); + [m_avPlayerItem.get() seekToTime:CMTimeMakeWithSeconds(time, 600) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) { + [observer seekCompleted:finished]; + }]; setDelayCallbacks(false); } @@ -437,6 +434,13 @@ void MediaPlayerPrivateAVFoundationObjC::setClosedCaptionsVisible(bool closedCap [m_avPlayer.get() setClosedCaptionDisplayEnabled:closedCaptionsVisible]; } +void MediaPlayerPrivateAVFoundationObjC::updateRate() +{ + setDelayCallbacks(true); + [m_avPlayer.get() setRate:requestedRate()]; + setDelayCallbacks(false); +} + float MediaPlayerPrivateAVFoundationObjC::rate() const { if (!metaDataAvailable()) @@ -621,12 +625,16 @@ void MediaPlayerPrivateAVFoundationObjC::getSupportedTypes(HashSet<String>& supp MediaPlayer::SupportsType MediaPlayerPrivateAVFoundationObjC::supportsType(const String& type, const String& codecs) { - // Only return "IsSupported" if there is no codecs parameter for now as there is no way to ask if it supports an - // extended MIME type until rdar://6220037 is fixed. - if (mimeTypeCache().contains(type)) - return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported; + if (!mimeTypeCache().contains(type)) + return MediaPlayer::IsNotSupported; + + // The spec says: + // "Implementors are encouraged to return "maybe" unless the type can be confidently established as being supported or not." + if (codecs.isEmpty()) + return MediaPlayer::MayBeSupported; - return MediaPlayer::IsNotSupported; + NSString *typeString = [NSString stringWithFormat:@"%@; codecs=\"%@\"", (NSString *)type, (NSString *)codecs]; + return [AVURLAsset isPlayableExtendedMIMEType:typeString] ? MediaPlayer::IsSupported : MediaPlayer::MayBeSupported;; } bool MediaPlayerPrivateAVFoundationObjC::isAvailable() @@ -758,6 +766,14 @@ NSArray* itemKVOProperties() m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::PlayerTimeChanged, time); } +- (void)seekCompleted:(BOOL)finished +{ + if (!m_callback) + return; + + m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::SeekCompleted, static_cast<bool>(finished)); +} + - (void)didEnd:(NSNotification *)unusedNotification { UNUSED_PARAM(unusedNotification); |