Title: [93137] branches/safari-534.51-branch/Source/WebCore
Revision
93137
Author
lforsch...@apple.com
Date
2011-08-16 11:49:42 -0700 (Tue, 16 Aug 2011)

Log Message

Merge r92977.

Modified Paths

Diff

Modified: branches/safari-534.51-branch/Source/WebCore/ChangeLog (93136 => 93137)


--- branches/safari-534.51-branch/Source/WebCore/ChangeLog	2011-08-16 18:45:35 UTC (rev 93136)
+++ branches/safari-534.51-branch/Source/WebCore/ChangeLog	2011-08-16 18:49:42 UTC (rev 93137)
@@ -1,5 +1,46 @@
 2011-08-16  Lucas Forschler  <lforsch...@apple.com>
 
+    Merged 92977
+
+    2011-08-12  Jeff Miller  <je...@apple.com>
+
+            Need to handle kCACFContextNeedsFlushNotification notifications that arrive after the AVFWrapper has been disposed
+            https://bugs.webkit.org/show_bug.cgi?id=65724
+
+            Instead of using a pointer to the AVFWrapper object as the context for various callbacks, assign each object an
+            ID and use that instead. Keep track of the mapping between object IDs and AVFWrapper objects in a HashMap, and manage
+            access to this map using a Mutex since it can be accessed from multiple threads. This allows us to actually delete
+            AVFWrapper objects instead of leaking them (which we were doing before to prevent crashes).
+
+            Reviewed by Eric Carlson.
+
+            No new tests, uses existing media tests.
+
+            * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationCF.cpp:
+            (WebCore::AVFWrapper::callbackContext): Added.
+            (WebCore::AVFWrapper::AVFWrapper): Initialize m_objectID and add it to the HashMap.
+            (WebCore::AVFWrapper::~AVFWrapper): Log object ID and remove obsolete assert.
+            (WebCore::AVFWrapper::mapLock): Added.
+            (WebCore::AVFWrapper::map): Added.
+            (WebCore::AVFWrapper::addToMap): Added.
+            (WebCore::AVFWrapper::removeFromMap): Added.
+            (WebCore::AVFWrapper::avfWrapperForCallbackContext): Added.
+            (WebCore::AVFWrapper::scheduleDisconnectAndDelete): Remove AVFWrapper from HashMap instead of zeroing m_owner.
+            (WebCore::AVFWrapper::disconnectAndDeleteAVFWrapper): Use callbackContext(), delete the AVFWrapper here.
+            (WebCore::AVFWrapper::createPlayer): Use callbackContext().
+            (WebCore::AVFWrapper::createPlayerItem): Use callbackContext().
+            (WebCore::AVFWrapper::periodicTimeObserverCallback): Retrieve AVFWrapper using the HashMap.
+            (WebCore::AVFWrapper::notificationCallback): Retrieve AVFWrapper using the HashMap.
+            (WebCore::AVFWrapper::loadPlayableCompletionCallback): Retrieve AVFWrapper using the HashMap.
+            (WebCore::AVFWrapper::checkPlayability): Use callbackContext().
+            (WebCore::AVFWrapper::loadMetadataCompletionCallback): Retrieve AVFWrapper using the HashMap.
+            (WebCore::AVFWrapper::beginLoadingMetadata): Use callbackContext().
+            (WebCore::AVFWrapper::seekCompletedCallback): Retrieve AVFWrapper using the HashMap.
+            (WebCore::AVFWrapper::seekToTime): Use callbackContext().
+            (WebCore::AVFWrapper::platformLayer): Remove overly noisy LOG().
+
+2011-08-16  Lucas Forschler  <lforsch...@apple.com>
+
     Merged 88444
 
     2011-06-08  Mikołaj Małecki  <m.male...@samsung.com>

Modified: branches/safari-534.51-branch/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationCF.cpp (93136 => 93137)


--- branches/safari-534.51-branch/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationCF.cpp	2011-08-16 18:45:35 UTC (rev 93136)
+++ branches/safari-534.51-branch/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationCF.cpp	2011-08-16 18:49:42 UTC (rev 93137)
@@ -45,6 +45,7 @@
 
 #include <delayimp.h>
 #include <dispatch/dispatch.h>
+#include <wtf/HashMap.h>
 #include <wtf/Threading.h>
 #include <wtf/UnusedParam.h>
 
@@ -122,9 +123,19 @@
     inline dispatch_queue_t dispatchQueue() const { return m_notificationQueue; }
 
 private:
+    inline void* callbackContext() const { return reinterpret_cast<void*>(m_objectID); }
+
+    static Mutex& mapLock();
+    static HashMap<uintptr_t, AVFWrapper*>& map();
+    static AVFWrapper* avfWrapperForCallbackContext(void*);
+    void addToMap();
+    void removeFromMap() const;
+
     static void disconnectAndDeleteAVFWrapper(void*);
-    static void deleteAVFWrapper(void*);
 
+    static uintptr_t s_nextAVFWrapperObjectID;
+    uintptr_t m_objectID;
+
     MediaPlayerPrivateAVFoundationCF* m_owner;
 
     RetainPtr<AVCFPlayerRef> m_avPlayer;
@@ -141,6 +152,8 @@
     OwnPtr<LayerClient> m_layerClient;
 };
 
+uintptr_t AVFWrapper::s_nextAVFWrapperObjectID;
+
 class LayerClient : public PlatformCALayerClient {
 public:
     LayerClient(AVFWrapper* parent) : m_parent(parent) { }
@@ -845,16 +858,17 @@
 
 AVFWrapper::AVFWrapper(MediaPlayerPrivateAVFoundationCF* owner)
     : m_owner(owner)
+    , m_objectID(s_nextAVFWrapperObjectID++)
 {
     LOG(Media, "AVFWrapper::AVFWrapper(%p)", this);
 
     m_notificationQueue = dispatch_queue_create("MediaPlayerPrivateAVFoundationCF.notificationQueue", 0);
+    addToMap();
 }
 
 AVFWrapper::~AVFWrapper()
 {
-    LOG(Media, "AVFWrapper::~AVFWrapper(%p)", this);
-    ASSERT(!m_owner);
+    LOG(Media, "AVFWrapper::~AVFWrapper(%p %d)", this, m_objectID);
 
     destroyVideoLayer();
     destroyImageGenerator();
@@ -872,10 +886,55 @@
     m_avPlayer = 0;
 }
 
+Mutex& AVFWrapper::mapLock()
+{
+    static Mutex mapLock;
+    return mapLock;
+}
+
+HashMap<uintptr_t, AVFWrapper*>& AVFWrapper::map()
+{
+    static HashMap<uintptr_t, AVFWrapper*>& map = *new HashMap<uintptr_t, AVFWrapper*>;
+    return map;
+}
+
+void AVFWrapper::addToMap()
+{
+    MutexLocker locker(mapLock());
+    
+    // HashMap doesn't like a key of 0, and also make sure we aren't
+    // using an object ID that's already in use.
+    while (!m_objectID || (map().find(m_objectID) != map().end()))
+        m_objectID = s_nextAVFWrapperObjectID++;
+       
+    LOG(Media, "AVFWrapper::addToMap(%p %d)", this, m_objectID);
+
+    map().add(m_objectID, this);
+}
+
+void AVFWrapper::removeFromMap() const
+{
+    LOG(Media, "AVFWrapper::removeFromMap(%p %d)", this, m_objectID);
+
+    MutexLocker locker(mapLock());
+    map().remove(m_objectID);
+}
+
+AVFWrapper* AVFWrapper::avfWrapperForCallbackContext(void* context)
+{
+    // Assumes caller has locked mapLock().
+    HashMap<uintptr_t, AVFWrapper*>::iterator it = map().find(reinterpret_cast<uintptr_t>(context));
+    if (it == map().end())
+        return 0;
+
+    return it->second;
+}
+
 void AVFWrapper::scheduleDisconnectAndDelete()
 {
     // Ignore any subsequent notifications we might receive in notificationCallback().
-    m_owner = 0;
+    removeFromMap();
+
     dispatch_async_f(dispatchQueue(), this, disconnectAndDeleteAVFWrapper);
 }
 
@@ -887,52 +946,27 @@
 
     if (avfWrapper->avPlayerItem()) {
         CFNotificationCenterRef center = CFNotificationCenterGetLocalCenter();
-        CFNotificationCenterRemoveObserver(center, avfWrapper, AVCFPlayerItemDidPlayToEndTimeNotification, avfWrapper->avPlayerItem());
-        CFNotificationCenterRemoveObserver(center, avfWrapper, AVCFPlayerItemStatusChangedNotification, avfWrapper->avPlayerItem());
-        CFNotificationCenterRemoveObserver(center, avfWrapper, AVCFPlayerItemTracksChangedNotification, avfWrapper->avPlayerItem());
-        CFNotificationCenterRemoveObserver(center, avfWrapper, AVCFPlayerItemSeekableTimeRangesChangedNotification, avfWrapper->avPlayerItem());
-        CFNotificationCenterRemoveObserver(center, avfWrapper, AVCFPlayerItemLoadedTimeRangesChangedNotification, avfWrapper->avPlayerItem());
-        CFNotificationCenterRemoveObserver(center, avfWrapper, AVCFPlayerItemIsPlaybackLikelyToKeepUpChangedNotification, avfWrapper->avPlayerItem());
-        CFNotificationCenterRemoveObserver(center, avfWrapper, AVCFPlayerItemIsPlaybackBufferEmptyChangedNotification, avfWrapper->avPlayerItem());
-        CFNotificationCenterRemoveObserver(center, avfWrapper, AVCFPlayerItemIsPlaybackBufferFullChangedNotification, avfWrapper->avPlayerItem());
-        CFNotificationCenterRemoveObserver(center, avfWrapper, CACFContextNeedsFlushNotification(), avfWrapper->avPlayerItem());
+        CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemDidPlayToEndTimeNotification, avfWrapper->avPlayerItem());
+        CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemStatusChangedNotification, avfWrapper->avPlayerItem());
+        CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemTracksChangedNotification, avfWrapper->avPlayerItem());
+        CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemSeekableTimeRangesChangedNotification, avfWrapper->avPlayerItem());
+        CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemLoadedTimeRangesChangedNotification, avfWrapper->avPlayerItem());
+        CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemIsPlaybackLikelyToKeepUpChangedNotification, avfWrapper->avPlayerItem());
+        CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemIsPlaybackBufferEmptyChangedNotification, avfWrapper->avPlayerItem());
+        CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), AVCFPlayerItemIsPlaybackBufferFullChangedNotification, avfWrapper->avPlayerItem());
+        CFNotificationCenterRemoveObserver(center, avfWrapper->callbackContext(), CACFContextNeedsFlushNotification(), 0);
     }
 
     if (avfWrapper->avPlayer()) {
         if (avfWrapper->timeObserver())
             AVCFPlayerRemoveObserver(avfWrapper->avPlayer(), avfWrapper->timeObserver());
 
-        CFNotificationCenterRemoveObserver(CFNotificationCenterGetLocalCenter(), avfWrapper, AVCFPlayerRateChangedNotification, avfWrapper->avPlayer());
+        CFNotificationCenterRemoveObserver(CFNotificationCenterGetLocalCenter(), avfWrapper->callbackContext(), AVCFPlayerRateChangedNotification, avfWrapper->avPlayer());
     }
 
-    dispatch_async_f(avfWrapper->dispatchQueue(), avfWrapper, deleteAVFWrapper);
+    delete avfWrapper;
 }
 
-void AVFWrapper::deleteAVFWrapper(void* context)
-{
-    AVFWrapper* avfWrapper = static_cast<AVFWrapper*>(context);
-    LOG(Media, "AVFWrapper::deleteAVFWrapper(%p)", avfWrapper);
-    
-    // FIXME: Leak AVFWrapper until <rdar://problem/9885505> is fixed, but clean up its ivars.
-    // delete avfWrapper;
-    avfWrapper->destroyVideoLayer();
-    avfWrapper->destroyImageGenerator();
-
-    if (avfWrapper->m_notificationQueue) {
-        dispatch_release(avfWrapper->m_notificationQueue);
-        avfWrapper->m_notificationQueue = 0;
-    }
-
-    if (avfWrapper->avAsset()) {
-        AVCFAssetCancelLoading(avfWrapper->avAsset());
-        avfWrapper->m_avAsset = 0;
-    }
-
-    avfWrapper->m_avPlayerItem = 0;
-    avfWrapper->m_timeObserver = 0;
-    avfWrapper->m_avPlayer = 0;
-}
-
 void AVFWrapper::createAssetForURL(const String& url)
 {
     ASSERT(!avAsset());
@@ -953,12 +987,12 @@
     CFNotificationCenterRef center = CFNotificationCenterGetLocalCenter();
     ASSERT(center);
 
-    CFNotificationCenterAddObserver(center, this, notificationCallback, AVCFPlayerRateChangedNotification, playerRef, CFNotificationSuspensionBehaviorDeliverImmediately);
+    CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerRateChangedNotification, playerRef, CFNotificationSuspensionBehaviorDeliverImmediately);
 
     // Add a time observer, ask to be called infrequently because we don't really want periodic callbacks but
     // our observer will also be called whenever a seek happens.
     const double veryLongInterval = 60*60*60*24*30;
-    m_timeObserver.adoptCF(AVCFPlayerCreatePeriodicTimeObserverForInterval(playerRef, CMTimeMake(veryLongInterval, 10), m_notificationQueue, &periodicTimeObserverCallback, this));
+    m_timeObserver.adoptCF(AVCFPlayerCreatePeriodicTimeObserverForInterval(playerRef, CMTimeMake(veryLongInterval, 10), m_notificationQueue, &periodicTimeObserverCallback, callbackContext()));
 }
 
 void AVFWrapper::createPlayerItem()
@@ -972,23 +1006,26 @@
     CFNotificationCenterRef center = CFNotificationCenterGetLocalCenter();
     ASSERT(center);
 
-    CFNotificationCenterAddObserver(center, this, notificationCallback, AVCFPlayerItemDidPlayToEndTimeNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
-    CFNotificationCenterAddObserver(center, this, notificationCallback, AVCFPlayerItemStatusChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
-    CFNotificationCenterAddObserver(center, this, notificationCallback, AVCFPlayerItemTracksChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
-    CFNotificationCenterAddObserver(center, this, notificationCallback, AVCFPlayerItemSeekableTimeRangesChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
-    CFNotificationCenterAddObserver(center, this, notificationCallback, AVCFPlayerItemLoadedTimeRangesChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
-    CFNotificationCenterAddObserver(center, this, notificationCallback, AVCFPlayerItemIsPlaybackLikelyToKeepUpChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
-    CFNotificationCenterAddObserver(center, this, notificationCallback, AVCFPlayerItemIsPlaybackBufferEmptyChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
-    CFNotificationCenterAddObserver(center, this, notificationCallback, AVCFPlayerItemIsPlaybackBufferFullChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
+    CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemDidPlayToEndTimeNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
+    CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemStatusChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
+    CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemTracksChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
+    CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemSeekableTimeRangesChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
+    CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemLoadedTimeRangesChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
+    CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemIsPlaybackLikelyToKeepUpChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
+    CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemIsPlaybackBufferEmptyChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
+    CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, AVCFPlayerItemIsPlaybackBufferFullChangedNotification, itemRef, CFNotificationSuspensionBehaviorDeliverImmediately);
 
-    CFNotificationCenterAddObserver(center, this, notificationCallback, CACFContextNeedsFlushNotification(), 0, CFNotificationSuspensionBehaviorDeliverImmediately);
+    CFNotificationCenterAddObserver(center, callbackContext(), notificationCallback, CACFContextNeedsFlushNotification(), 0, CFNotificationSuspensionBehaviorDeliverImmediately);
 }
 
 void AVFWrapper::periodicTimeObserverCallback(AVCFPlayerRef, CMTime cmTime, void* context)
 {
-    AVFWrapper* self = static_cast<AVFWrapper*>(context);
-    if (!self->m_owner)
+    MutexLocker locker(mapLock());
+    AVFWrapper* self = avfWrapperForCallbackContext(context);
+    if (!self) {
+        LOG(Media, "AVFWrapper::periodicTimeObserverCallback invoked for deleted AVFWrapper %d", reinterpret_cast<uintptr_t>(context));
         return;
+    }
 
     double time = std::max(0.0, CMTimeGetSeconds(cmTime)); // Clamp to zero, negative values are sometimes reported.
     self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::PlayerTimeChanged, time);
@@ -996,10 +1033,13 @@
 
 void AVFWrapper::notificationCallback(CFNotificationCenterRef, void* observer, CFStringRef propertyName, const void* object, CFDictionaryRef)
 {
-    AVFWrapper* self = static_cast<AVFWrapper*>(observer);
+    MutexLocker locker(mapLock());
+    AVFWrapper* self = avfWrapperForCallbackContext(observer);
     
-    if (!self->m_owner)
+    if (!self) {
+        LOG(Media, "AVFWrapper::notificationCallback invoked for deleted AVFWrapper %d", reinterpret_cast<uintptr_t>(observer));
         return;
+    }
 
     LOG(Media, "AVFWrapper::notificationCallback(%p)", self);
 
@@ -1036,10 +1076,14 @@
 
 void AVFWrapper::loadPlayableCompletionCallback(AVCFAssetRef, void* context)
 {
-    AVFWrapper* self = static_cast<AVFWrapper*>(context);
+    MutexLocker locker(mapLock());
+    AVFWrapper* self = avfWrapperForCallbackContext(context);
+    if (!self) {
+        LOG(Media, "AVFWrapper::loadPlayableCompletionCallback invoked for deleted AVFWrapper %d", reinterpret_cast<uintptr_t>(context));
+        return;
+    }
 
-    if (!self->m_owner)
-        return;
+    LOG(Media, "AVFWrapper::loadPlayableCompletionCallback(%p)", self);
     self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::AssetPlayabilityKnown);
 }
 
@@ -1055,16 +1099,19 @@
         propertyKeyName = CFArrayCreate(0, (const void**)keyNames, sizeof(keyNames) / sizeof(keyNames[0]), &kCFTypeArrayCallBacks);
     }
 
-    AVCFAssetLoadValuesAsynchronouslyForProperties(avAsset(), propertyKeyName, loadPlayableCompletionCallback, this);
+    AVCFAssetLoadValuesAsynchronouslyForProperties(avAsset(), propertyKeyName, loadPlayableCompletionCallback, callbackContext());
 }
 
 void AVFWrapper::loadMetadataCompletionCallback(AVCFAssetRef, void* context)
 {
-    LOG(Media, "AVFWrapper::loadMetadataCompletionCallback(%p)", context);
-    AVFWrapper* self = static_cast<AVFWrapper*>(context);
+    MutexLocker locker(mapLock());
+    AVFWrapper* self = avfWrapperForCallbackContext(context);
+    if (!self) {
+        LOG(Media, "AVFWrapper::loadMetadataCompletionCallback invoked for deleted AVFWrapper %d", reinterpret_cast<uintptr_t>(context));
+        return;
+    }
 
-    if (!self->m_owner)
-        return;
+    LOG(Media, "AVFWrapper::loadMetadataCompletionCallback(%p)", self);
     self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::AssetMetadataLoaded);
 }
 
@@ -1072,15 +1119,19 @@
 {
     ASSERT(avAsset());
     LOG(Media, "AVFWrapper::beginLoadingMetadata(%p) - requesting metadata loading", this);
-    AVCFAssetLoadValuesAsynchronouslyForProperties(avAsset(), metadataKeyNames(), loadMetadataCompletionCallback, this);
+    AVCFAssetLoadValuesAsynchronouslyForProperties(avAsset(), metadataKeyNames(), loadMetadataCompletionCallback, callbackContext());
 }
 
 void AVFWrapper::seekCompletedCallback(AVCFPlayerItemRef, Boolean finished, void* context)
 {
-    AVFWrapper* self = static_cast<AVFWrapper*>(context);
-    if (!self->m_owner)
+    MutexLocker locker(mapLock());
+    AVFWrapper* self = avfWrapperForCallbackContext(context);
+    if (!self) {
+        LOG(Media, "AVFWrapper::seekCompletedCallback invoked for deleted AVFWrapper %d", reinterpret_cast<uintptr_t>(context));
         return;
+    }
 
+    LOG(Media, "AVFWrapper::seekCompletedCallback(%p)", self);
     self->m_owner->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::SeekCompleted, static_cast<bool>(finished));
 }
 
@@ -1088,7 +1139,7 @@
 {
     ASSERT(avPlayerItem());
     AVCFPlayerItemSeekToTimeWithToleranceAndCompletionCallback(avPlayerItem(), CMTimeMakeWithSeconds(time, 600),
-        kCMTimeZero, kCMTimeZero, &seekCompletedCallback, this);
+        kCMTimeZero, kCMTimeZero, &seekCompletedCallback, callbackContext());
 }
 
 void AVFWrapper::setAsset(AVCFURLAssetRef asset)
@@ -1102,8 +1153,6 @@
 
 PlatformLayer* AVFWrapper::platformLayer()
 {
-    LOG(Media, "AVFWrapper::platformLayer(%p)", this);
-
     if (m_videoLayerWrapper)
         return m_videoLayerWrapper->platformLayer();
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to