summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/graphics/avfoundation
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-06-02 12:07:03 +0100
committerBen Murdoch <benm@google.com>2011-06-10 10:47:21 +0100
commit2daae5fd11344eaa88a0d92b0f6d65f8d2255c00 (patch)
treee4964fbd1cb70599f7718ff03e50ea1dab33890b /Source/WebCore/platform/graphics/avfoundation
parent87bdf0060a247bfbe668342b87e0874182e0ffa9 (diff)
downloadexternal_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')
-rw-r--r--Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp58
-rw-r--r--Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h26
-rw-r--r--Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h5
-rw-r--r--Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm58
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);