Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm (160824 => 160825)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm 2013-12-19 06:12:09 UTC (rev 160824)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm 2013-12-19 07:01:59 UTC (rev 160825)
@@ -30,6 +30,7 @@
#import "HTMLMediaSource.h"
#import "MediaSourcePrivateAVFObjC.h"
+#import "MediaTimeMac.h"
#import "PlatformClockCM.h"
#import "SoftLinking.h"
#import <AVFoundation/AVSampleBufferDisplayLayer.h>
@@ -50,11 +51,22 @@
SOFT_LINK_CLASS_OPTIONAL(AVFoundation, AVURLAsset)
SOFT_LINK_CLASS_OPTIONAL(AVFoundation, AVSampleBufferAudioRenderer)
SOFT_LINK_CLASS_OPTIONAL(AVFoundation, AVSampleBufferDisplayLayer)
+SOFT_LINK_CLASS_OPTIONAL(AVFoundation, AVSampleBufferRenderSynchronizer)
SOFT_LINK_CLASS_OPTIONAL(AVFoundation, AVStreamDataParser)
SOFT_LINK_CLASS_OPTIONAL(AVFoundation, AVVideoPerformanceMetrics)
-SOFT_LINK(CoreMedia, FigReadOnlyTimebaseSetTargetTimebase, OSStatus, (CMTimebaseRef timebase, CMTimebaseRef newTargetTimebase), (timebase, newTargetTimebase))
+typedef struct opaqueCMNotificationCenter *CMNotificationCenterRef;
+typedef void (*CMNotificationCallback)(CMNotificationCenterRef inCenter, const void *inListener, CFStringRef inNotificationName, const void *inNotifyingObject, CFTypeRef inNotificationPayload);
+SOFT_LINK(CoreMedia, CMNotificationCenterGetDefaultLocalCenter, CMNotificationCenterRef, (void), ());
+SOFT_LINK(CoreMedia, CMNotificationCenterAddListener, OSStatus, (CMNotificationCenterRef center, const void* listener, CMNotificationCallback callback, CFStringRef notification, const void* object, UInt32 flags), (center, listener, callback, notification, object, flags))
+SOFT_LINK(CoreMedia, CMNotificationCenterRemoveListener, OSStatus, (CMNotificationCenterRef center, const void* listener, CMNotificationCallback callback, CFStringRef notification, const void* object), (center, listener, callback, notification, object))
+SOFT_LINK(CoreMedia, CMTimeGetSeconds, Float64, (CMTime time), (time))
+SOFT_LINK(CoreMedia, CMTimebaseGetTime, CMTime, (CMTimebaseRef timebase), (timebase))
+
+SOFT_LINK_CONSTANT(CoreMedia, kCMTimebaseNotification_EffectiveRateChanged, CFStringRef)
+#define kCMTimebaseNotification_EffectiveRateChanged getkCMTimebaseNotification_EffectiveRateChanged()
+
#pragma mark -
#pragma mark AVVideoPerformanceMetrics
@@ -81,23 +93,63 @@
@end
#endif
+#pragma mark -
+#pragma mark AVSampleBufferRenderSynchronizer
+
+@interface AVSampleBufferRenderSynchronizer : NSObject
+- (CMTimebaseRef)timebase;
+- (float)rate;
+- (void)setRate:(float)rate;
+- (void)setRate:(float)rate time:(CMTime)time;
+- (NSArray *)renderers;
+- (void)addRenderer:(id)renderer;
+- (void)removeRenderer:(id)renderer atTime:(CMTime)time withCompletionHandler:(void (^)(BOOL didRemoveRenderer))completionHandler;
+- (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block;
+- (void)removeTimeObserver:(id)observer;
+@end
+
namespace WebCore {
#pragma mark -
#pragma mark MediaPlayerPrivateMediaSourceAVFObjC
+static void CMTimebaseEffectiveRateChangedCallback(CMNotificationCenterRef, const void *listener, CFStringRef, const void *, CFTypeRef)
+{
+ MediaPlayerPrivateMediaSourceAVFObjC* player = (MediaPlayerPrivateMediaSourceAVFObjC*)listener;
+ callOnMainThread(bind(&MediaPlayerPrivateMediaSourceAVFObjC::effectiveRateChanged, player));
+}
+
MediaPlayerPrivateMediaSourceAVFObjC::MediaPlayerPrivateMediaSourceAVFObjC(MediaPlayer* player)
: m_player(player)
- , m_clock(new PlatformClockCM())
+ , m_synchronizer(adoptNS([[getAVSampleBufferRenderSynchronizerClass() alloc] init]))
, m_networkState(MediaPlayer::Empty)
, m_readyState(MediaPlayer::HaveNothing)
+ , m_rate(1)
+ , m_playing(0)
, m_seeking(false)
, m_loadingProgressed(false)
{
+ CMTimebaseRef timebase = [m_synchronizer timebase];
+ CMNotificationCenterRef nc = CMNotificationCenterGetDefaultLocalCenter();
+ CMNotificationCenterAddListener(nc, this, CMTimebaseEffectiveRateChangedCallback, kCMTimebaseNotification_EffectiveRateChanged, timebase, 0);
+
+ // addPeriodicTimeObserverForInterval: throws an exception if you pass a non-numeric CMTime, so just use
+ // an arbitrarily large time value of once an hour:
+ m_timeJumpedObserver = [m_synchronizer addPeriodicTimeObserverForInterval:toCMTime(MediaTime::createWithDouble(3600)) queue:dispatch_get_main_queue() usingBlock:^(CMTime){
+ if (m_seeking) {
+ m_seeking = false;
+ m_player->timeChanged();
+ }
+ }];
}
MediaPlayerPrivateMediaSourceAVFObjC::~MediaPlayerPrivateMediaSourceAVFObjC()
{
+ CMTimebaseRef timebase = [m_synchronizer timebase];
+ CMNotificationCenterRef nc = CMNotificationCenterGetDefaultLocalCenter();
+ CMNotificationCenterRemoveListener(nc, this, CMTimebaseEffectiveRateChangedCallback, kCMTimebaseNotification_EffectiveRateChanged, timebase);
+
+ [m_synchronizer removeTimeObserver:m_timeJumpedObserver.get()];
}
#pragma mark -
@@ -116,7 +168,7 @@
bool MediaPlayerPrivateMediaSourceAVFObjC::isAvailable()
{
- return AVFoundationLibrary() && CoreMediaLibrary() && getAVStreamDataParserClass() && getAVSampleBufferAudioRendererClass();
+ return AVFoundationLibrary() && CoreMediaLibrary() && getAVStreamDataParserClass() && getAVSampleBufferAudioRendererClass() && getAVSampleBufferRenderSynchronizerClass();
}
static HashSet<String> mimeTypeCache()
@@ -206,8 +258,8 @@
void MediaPlayerPrivateMediaSourceAVFObjC::playInternal()
{
- m_clock->start();
- m_player->rateChanged();
+ m_playing = true;
+ [m_synchronizer setRate:m_rate];
}
void MediaPlayerPrivateMediaSourceAVFObjC::pause()
@@ -217,13 +269,13 @@
void MediaPlayerPrivateMediaSourceAVFObjC::pauseInternal()
{
- m_clock->stop();
- m_player->rateChanged();
+ m_playing = false;
+ [m_synchronizer setRate:0];
}
bool MediaPlayerPrivateMediaSourceAVFObjC::paused() const
{
- return !m_clock->isRunning();
+ return !m_playing;
}
void MediaPlayerPrivateMediaSourceAVFObjC::setVolume(float volume)
@@ -271,7 +323,7 @@
double MediaPlayerPrivateMediaSourceAVFObjC::currentTimeDouble() const
{
- return m_clock->currentTime();
+ return CMTimeGetSeconds(CMTimebaseGetTime([m_synchronizer timebase]));
}
double MediaPlayerPrivateMediaSourceAVFObjC::startTimeDouble() const
@@ -293,9 +345,8 @@
void MediaPlayerPrivateMediaSourceAVFObjC::seekInternal(double time, double negativeThreshold, double positiveThreshold)
{
MediaTime seekTime = m_mediaSourcePrivate->seekToTime(MediaTime::createWithDouble(time), MediaTime::createWithDouble(positiveThreshold), MediaTime::createWithDouble(negativeThreshold));
- m_clock->setCurrentMediaTime(seekTime);
- m_seeking = false;
- m_player->timeChanged();
+
+ [m_synchronizer setRate:(m_playing ? m_rate : 0) time:toCMTime(seekTime)];
}
bool MediaPlayerPrivateMediaSourceAVFObjC::seeking() const
@@ -305,8 +356,9 @@
void MediaPlayerPrivateMediaSourceAVFObjC::setRateDouble(double rate)
{
- m_clock->setPlayRate(rate);
- m_player->rateChanged();
+ m_rate = rate;
+ if (m_playing)
+ [m_synchronizer setRate:m_rate];
}
MediaPlayer::NetworkState MediaPlayerPrivateMediaSourceAVFObjC::networkState() const
@@ -437,7 +489,7 @@
return;
m_sampleBufferDisplayLayer = adoptNS([[getAVSampleBufferDisplayLayerClass() alloc] init]);
- [m_sampleBufferDisplayLayer setControlTimebase:m_clock->timebase()];
+ [m_synchronizer addRenderer:m_sampleBufferDisplayLayer.get()];
}
void MediaPlayerPrivateMediaSourceAVFObjC::destroyLayer()
@@ -445,7 +497,10 @@
if (!m_sampleBufferDisplayLayer)
return;
- [m_sampleBufferDisplayLayer setControlTimebase:0];
+ CMTime currentTime = CMTimebaseGetTime([m_synchronizer timebase]);
+ [m_synchronizer removeRenderer:m_sampleBufferDisplayLayer.get() atTime:currentTime withCompletionHandler:^(BOOL){
+ // No-op.
+ }];
m_sampleBufferDisplayLayer = nullptr;
}
@@ -454,6 +509,11 @@
m_player->durationChanged();
}
+void MediaPlayerPrivateMediaSourceAVFObjC::effectiveRateChanged()
+{
+ m_player->rateChanged();
+}
+
void MediaPlayerPrivateMediaSourceAVFObjC::setReadyState(MediaPlayer::ReadyState readyState)
{
if (m_readyState == readyState)
@@ -479,7 +539,7 @@
return;
m_sampleBufferDisplayLayer = displayLayer;
- [m_sampleBufferDisplayLayer setControlTimebase:m_clock->timebase()];
+ [m_synchronizer addRenderer:m_sampleBufferDisplayLayer.get()];
m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
// FIXME: move this somewhere appropriate:
@@ -491,6 +551,11 @@
if (displayLayer != m_sampleBufferDisplayLayer)
return;
+ CMTime currentTime = CMTimebaseGetTime([m_synchronizer timebase]);
+ [m_synchronizer removeRenderer:m_sampleBufferDisplayLayer.get() atTime:currentTime withCompletionHandler:^(BOOL){
+ // No-op.
+ }];
+
m_sampleBufferDisplayLayer = nullptr;
m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
}
@@ -501,7 +566,7 @@
return;
m_sampleBufferAudioRenderers.append(audioRenderer);
- FigReadOnlyTimebaseSetTargetTimebase([audioRenderer timebase], m_clock->timebase());
+ [m_synchronizer addRenderer:audioRenderer];
m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
}
@@ -511,6 +576,11 @@
if (pos == notFound)
return;
+ CMTime currentTime = CMTimebaseGetTime([m_synchronizer timebase]);
+ [m_synchronizer removeRenderer:audioRenderer atTime:currentTime withCompletionHandler:^(BOOL){
+ // No-op.
+ }];
+
m_sampleBufferAudioRenderers.remove(pos);
m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
}
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm (160824 => 160825)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm 2013-12-19 06:12:09 UTC (rev 160824)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm 2013-12-19 07:01:59 UTC (rev 160825)
@@ -358,18 +358,11 @@
const String& mediaType;
};
-static OSStatus callProcessCodedFrameForEachSample(CMSampleBufferRef sampleBuffer, CMItemCount, void *refcon)
-{
- ProcessCodedFrameInfo* info = static_cast<ProcessCodedFrameInfo*>(refcon);
- return info->sourceBuffer->processCodedFrame(info->trackID, sampleBuffer, info->mediaType) ? noErr : paramErr;
-}
-
void SourceBufferPrivateAVFObjC::didProvideMediaDataForTrackID(int trackID, CMSampleBufferRef sampleBuffer, const String& mediaType, unsigned flags)
{
UNUSED_PARAM(flags);
- ProcessCodedFrameInfo info = {this, trackID, mediaType};
- CMSampleBufferCallForEachSample(sampleBuffer, &callProcessCodedFrameForEachSample, &info);
+ processCodedFrame(trackID, sampleBuffer, mediaType);
}
bool SourceBufferPrivateAVFObjC::processCodedFrame(int trackID, CMSampleBufferRef sampleBuffer, const String&)