Bug 862182 - Revert bug 862183 due to frequent orange in 459439 crashtest. CLOSED TREE. r=philor
authorChris Pearce <cpearce@mozilla.com>
Wed, 01 May 2013 13:33:33 +1200
changeset 141383 6a0618f70be66acd5df7e40a76d41c2d95fc70cb
parent 141382 d5db4e09eeef840fd81294ab2a2a0344ea0cde96
child 141384 b20baaf5024edfa34e1e458de448088ef6a2323f
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersphilor
bugs862182, 862183, 459439
milestone23.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 862182 - Revert bug 862183 due to frequent orange in 459439 crashtest. CLOSED TREE. r=philor
content/html/content/src/HTMLMediaElement.cpp
content/media/BufferMediaResource.h
content/media/MediaCache.cpp
content/media/MediaCache.h
content/media/MediaDecoder.cpp
content/media/MediaDecoder.h
content/media/MediaResource.cpp
content/media/MediaResource.h
content/media/omx/MPAPI.h
content/media/omx/MediaOmxReader.cpp
content/media/omx/OmxDecoder.cpp
content/media/omx/OmxDecoder.h
content/media/plugins/MediaPluginHost.cpp
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -2358,17 +2358,17 @@ nsresult HTMLMediaElement::InitializeDec
 
   double duration = aOriginal->GetDuration();
   if (duration >= 0) {
     decoder->SetDuration(duration);
     decoder->SetTransportSeekable(aOriginal->IsTransportSeekable());
     decoder->SetMediaSeekable(aOriginal->IsMediaSeekable());
   }
 
-  nsRefPtr<MediaResource> resource = originalResource->CloneData(decoder);
+  MediaResource* resource = originalResource->CloneData(decoder);
   if (!resource) {
     LOG(PR_LOG_DEBUG, ("%p Failed to cloned stream for decoder %p", this, decoder.get()));
     return NS_ERROR_FAILURE;
   }
 
   return FinishDecoderSetup(decoder, resource, nullptr, aOriginal);
 }
 
@@ -2390,17 +2390,17 @@ nsresult HTMLMediaElement::InitializeDec
     NS_ConvertUTF8toUTF16 mimeUTF16(mimeType);
     const PRUnichar* params[] = { mimeUTF16.get(), src.get() };
     ReportLoadError("MediaLoadUnsupportedMimeType", params, ArrayLength(params));
     return NS_ERROR_FAILURE;
   }
 
   LOG(PR_LOG_DEBUG, ("%p Created decoder %p for type %s", this, decoder.get(), mimeType.get()));
 
-  nsRefPtr<MediaResource> resource = MediaResource::Create(decoder, aChannel);
+  MediaResource* resource = MediaResource::Create(decoder, aChannel);
   if (!resource)
     return NS_ERROR_OUT_OF_MEMORY;
 
   // stream successfully created, the stream now owns the channel.
   mChannel = nullptr;
 
   return FinishDecoderSetup(decoder, resource, aListener, nullptr);
 }
--- a/content/media/BufferMediaResource.h
+++ b/content/media/BufferMediaResource.h
@@ -43,17 +43,17 @@ public:
   virtual void Resume() {}
   // Get the current principal for the channel
   virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal()
   {
     nsCOMPtr<nsIPrincipal> principal = mPrincipal;
     return principal.forget();
   }
   virtual bool CanClone() { return false; }
-  virtual already_AddRefed<MediaResource> CloneData(MediaDecoder* aDecoder)
+  virtual MediaResource* CloneData(MediaDecoder* aDecoder)
   {
     return nullptr;
   }
 
   // These methods are called off the main thread.
   // The mode is initially MODE_PLAYBACK.
   virtual void SetReadMode(MediaCacheStream::ReadMode aMode) {}
   virtual void SetPlaybackRate(uint32_t aBytesPerSecond) {}
@@ -97,17 +97,17 @@ public:
 
   virtual void Pin() {}
   virtual void Unpin() {}
   virtual double GetDownloadRate(bool* aIsReliable) { return 0.; }
   virtual int64_t GetLength() { return mLength; }
   virtual int64_t GetNextCachedData(int64_t aOffset) { return aOffset; }
   virtual int64_t GetCachedDataEnd(int64_t aOffset) { return mLength; }
   virtual bool IsDataCachedToEndOfResource(int64_t aOffset) { return true; }
-  virtual bool IsSuspendedByCache() { return false; }
+  virtual bool IsSuspendedByCache(MediaResource** aActiveResource) { return false; }
   virtual bool IsSuspended() { return false; }
   virtual nsresult ReadFromCache(char* aBuffer,
                                  int64_t aOffset,
                                  uint32_t aCount)
   {
     if (aOffset < 0) {
       return NS_ERROR_FAILURE;
     }
--- a/content/media/MediaCache.cpp
+++ b/content/media/MediaCache.cpp
@@ -1825,36 +1825,42 @@ MediaCacheStream::SetTransportSeekable(b
 bool
 MediaCacheStream::IsTransportSeekable()
 {
   ReentrantMonitorAutoEnter mon(gMediaCache->GetReentrantMonitor());
   return mIsTransportSeekable;
 }
 
 bool
-MediaCacheStream::AreAllStreamsForResourceSuspended()
+MediaCacheStream::AreAllStreamsForResourceSuspended(MediaResource** aActiveStream)
 {
   ReentrantMonitorAutoEnter mon(gMediaCache->GetReentrantMonitor());
   MediaCache::ResourceStreamIterator iter(mResourceID);
   // Look for a stream that's able to read the data we need
   int64_t dataOffset = -1;
   while (MediaCacheStream* stream = iter.Next()) {
     if (stream->mCacheSuspended || stream->mChannelEnded || stream->mClosed) {
       continue;
     }
     if (dataOffset < 0) {
       dataOffset = GetCachedDataEndInternal(mStreamOffset);
     }
     // Ignore streams that are reading beyond the data we need
     if (stream->mChannelOffset > dataOffset) {
       continue;
     }
+    if (aActiveStream) {
+      *aActiveStream = stream->mClient;
+    }
     return false;
   }
 
+  if (aActiveStream) {
+    *aActiveStream = nullptr;
+  }
   return true;
 }
 
 void
 MediaCacheStream::Close()
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
--- a/content/media/MediaCache.h
+++ b/content/media/MediaCache.h
@@ -326,17 +326,19 @@ public:
   // because it doesn't know when the decoder was paused, buffering, etc.
   // Do not pass zero.
   void SetPlaybackRate(uint32_t aBytesPerSecond);
   // Returns the last set value of SetTransportSeekable.
   bool IsTransportSeekable();
 
   // Returns true when all streams for this resource are suspended or their
   // channel has ended.
-  bool AreAllStreamsForResourceSuspended();
+  // If aActiveResource is non-null, fills it with a pointer to a stream
+  // for this resource that is not suspended or ended.
+  bool AreAllStreamsForResourceSuspended(MediaResource** aActiveResource);
 
   // These methods must be called on a different thread from the main
   // thread. They should always be called on the same thread for a given
   // stream.
   // This can fail when aWhence is NS_SEEK_END and no stream length
   // is known.
   nsresult Seek(int32_t aWhence, int64_t aOffset);
   int64_t Tell();
--- a/content/media/MediaDecoder.cpp
+++ b/content/media/MediaDecoder.cpp
@@ -404,32 +404,33 @@ MediaDecoder::~MediaDecoder()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MediaMemoryReporter::RemoveMediaDecoder(this);
   UnpinForSeek();
   MOZ_COUNT_DTOR(MediaDecoder);
 }
 
 nsresult MediaDecoder::OpenResource(MediaResource* aResource,
-                                    nsIStreamListener** aStreamListener)
+                                        nsIStreamListener** aStreamListener)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (aStreamListener) {
     *aStreamListener = nullptr;
   }
 
   {
     // Hold the lock while we do this to set proper lock ordering
     // expectations for dynamic deadlock detectors: decoder lock(s)
     // should be grabbed before the cache lock
     ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
 
     nsresult rv = aResource->Open(aStreamListener);
     if (NS_FAILED(rv)) {
       LOG(PR_LOG_DEBUG, ("%p Failed to open stream!", this));
+      delete aResource;
       return rv;
     }
 
     mResource = aResource;
   }
   return NS_OK;
 }
 
@@ -942,17 +943,19 @@ void MediaDecoder::UpdatePlaybackRate()
   mResource->SetPlaybackRate(rate);
 }
 
 void MediaDecoder::NotifySuspendedStatusChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!mResource)
     return;
-  bool suspended = mResource->IsSuspendedByCache();
+  MediaResource* activeStream;
+  bool suspended = mResource->IsSuspendedByCache(&activeStream);
+
   if (mOwner) {
     mOwner->NotifySuspendedByCache(suspended);
     UpdateReadyStateForData();
   }
 }
 
 void MediaDecoder::NotifyBytesDownloaded()
 {
--- a/content/media/MediaDecoder.h
+++ b/content/media/MediaDecoder.h
@@ -291,22 +291,16 @@ public:
   // Called when the video file has completed downloading.
   virtual void ResourceLoaded();
 
   // Called if the media file encounters a network error.
   virtual void NetworkError();
 
   // Get the current MediaResource being used. Its URI will be returned
   // by currentSrc. Returns what was passed to Load(), if Load() has been called.
-  // Note: The MediaResource is refcounted, but it outlives the MediaDecoder,
-  // so it's OK to use the reference returned by this function without
-  // refcounting, *unless* you need to store and use the reference after the
-  // MediaDecoder has been destroyed. You might need to do this if you're
-  // wrapping the MediaResource in some kind of byte stream interface to be
-  // passed to a platform decoder.
   MediaResource* GetResource() const MOZ_FINAL MOZ_OVERRIDE
   {
     return mResource;
   }
 
   // Return the principal of the current URI being played or downloaded.
   virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
 
--- a/content/media/MediaResource.cpp
+++ b/content/media/MediaResource.cpp
@@ -708,39 +708,38 @@ already_AddRefed<nsIPrincipal> ChannelMe
   return principal.forget();
 }
 
 bool ChannelMediaResource::CanClone()
 {
   return mCacheStream.IsAvailableForSharing();
 }
 
-already_AddRefed<MediaResource> ChannelMediaResource::CloneData(MediaDecoder* aDecoder)
+MediaResource* ChannelMediaResource::CloneData(MediaDecoder* aDecoder)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
   NS_ASSERTION(mCacheStream.IsAvailableForSharing(), "Stream can't be cloned");
 
-  nsRefPtr<ChannelMediaResource> resource =
-    new ChannelMediaResource(aDecoder,
-                             nullptr,
-                             mURI,
-                             GetContentType());
+  ChannelMediaResource* resource = new ChannelMediaResource(aDecoder,
+                                                            nullptr,
+                                                            mURI,
+                                                            GetContentType());
   if (resource) {
     // Initially the clone is treated as suspended by the cache, because
     // we don't have a channel. If the cache needs to read data from the clone
     // it will call CacheClientResume (or CacheClientSeek with aResume true)
     // which will recreate the channel. This way, if all of the media data
     // is already in the cache we don't create an unnecessary HTTP channel
     // and perform a useless HTTP transaction.
     resource->mSuspendCount = 1;
     resource->mCacheStream.InitAsClone(&mCacheStream);
     resource->mChannelStatistics = new MediaChannelStatistics(mChannelStatistics);
     resource->mChannelStatistics->Stop();
   }
-  return resource.forget();
+  return resource;
 }
 
 void ChannelMediaResource::CloseChannel()
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   {
     MutexAutoLock lock(mLock);
@@ -1183,19 +1182,19 @@ ChannelMediaResource::IsDataCachedToEndO
 
 void
 ChannelMediaResource::EnsureCacheUpToDate()
 {
   mCacheStream.EnsureCacheUpdate();
 }
 
 bool
-ChannelMediaResource::IsSuspendedByCache()
+ChannelMediaResource::IsSuspendedByCache(MediaResource** aActiveResource)
 {
-  return mCacheStream.AreAllStreamsForResourceSuspended();
+  return mCacheStream.AreAllStreamsForResourceSuspended(aActiveResource);
 }
 
 bool
 ChannelMediaResource::IsSuspended()
 {
   MutexAutoLock lock(mLock);
   return mSuspendCount > 0;
 }
@@ -1279,17 +1278,17 @@ public:
 
   // Main thread
   virtual nsresult Open(nsIStreamListener** aStreamListener);
   virtual nsresult Close();
   virtual void     Suspend(bool aCloseImmediately) {}
   virtual void     Resume() {}
   virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
   virtual bool     CanClone();
-  virtual already_AddRefed<MediaResource> CloneData(MediaDecoder* aDecoder);
+  virtual MediaResource* CloneData(MediaDecoder* aDecoder);
   virtual nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount);
 
   // These methods are called off the main thread.
 
   // Other thread
   virtual void     SetReadMode(MediaCacheStream::ReadMode aMode) {}
   virtual void     SetPlaybackRate(uint32_t aBytesPerSecond) {}
   virtual nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes);
@@ -1322,17 +1321,23 @@ public:
   }
   virtual int64_t GetCachedDataEnd(int64_t aOffset) {
     MutexAutoLock lock(mLock);
 
     EnsureSizeInitialized();
     return std::max(aOffset, mSize);
   }
   virtual bool    IsDataCachedToEndOfResource(int64_t aOffset) { return true; }
-  virtual bool    IsSuspendedByCache() { return false; }
+  virtual bool    IsSuspendedByCache(MediaResource** aActiveResource)
+  {
+    if (aActiveResource) {
+      *aActiveResource = nullptr;
+    }
+    return false;
+  }
   virtual bool    IsSuspended() { return false; }
   virtual bool    IsTransportSeekable() MOZ_OVERRIDE { return true; }
 
   nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges);
 
 private:
   // Ensures mSize is initialized, if it can be.
   // mLock must be held when this is called, and mInput must be non-null.
@@ -1494,17 +1499,17 @@ already_AddRefed<nsIPrincipal> FileMedia
   return principal.forget();
 }
 
 bool FileMediaResource::CanClone()
 {
   return true;
 }
 
-already_AddRefed<MediaResource> FileMediaResource::CloneData(MediaDecoder* aDecoder)
+MediaResource* FileMediaResource::CloneData(MediaDecoder* aDecoder)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
   if (!owner) {
     // The decoder is being shut down, so we can't clone
     return nullptr;
   }
@@ -1517,18 +1522,17 @@ already_AddRefed<MediaResource> FileMedi
   NS_ENSURE_TRUE(loadGroup, nullptr);
 
   nsCOMPtr<nsIChannel> channel;
   nsresult rv =
     NS_NewChannel(getter_AddRefs(channel), mURI, nullptr, loadGroup, nullptr, 0);
   if (NS_FAILED(rv))
     return nullptr;
 
-  nsRefPtr<MediaResource> resource(new FileMediaResource(aDecoder, channel, mURI, GetContentType()));
-  return resource.forget();
+  return new FileMediaResource(aDecoder, channel, mURI, GetContentType());
 }
 
 nsresult FileMediaResource::ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount)
 {
   MutexAutoLock lock(mLock);
 
   EnsureSizeInitialized();
   int64_t offset = 0;
@@ -1583,39 +1587,37 @@ int64_t FileMediaResource::Tell()
     return 0;
   EnsureSizeInitialized();
 
   int64_t offset = 0;
   mSeekable->Tell(&offset);
   return offset;
 }
 
-already_AddRefed<MediaResource>
+MediaResource*
 MediaResource::Create(MediaDecoder* aDecoder, nsIChannel* aChannel)
 {
   NS_ASSERTION(NS_IsMainThread(),
                "MediaResource::Open called on non-main thread");
 
   // If the channel was redirected, we want the post-redirect URI;
   // but if the URI scheme was expanded, say from chrome: to jar:file:,
   // we want the original URI.
   nsCOMPtr<nsIURI> uri;
   nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   nsAutoCString contentType;
   aChannel->GetContentType(contentType);
 
   nsCOMPtr<nsIFileChannel> fc = do_QueryInterface(aChannel);
-  nsRefPtr<MediaResource> resource;
   if (fc || IsBlobURI(uri)) {
-    resource = new FileMediaResource(aDecoder, aChannel, uri, contentType);
+    return new FileMediaResource(aDecoder, aChannel, uri, contentType);
   }
-  resource = new ChannelMediaResource(aDecoder, aChannel, uri, contentType);
-  return resource.forget();
+  return new ChannelMediaResource(aDecoder, aChannel, uri, contentType);
 }
 
 void BaseMediaResource::MoveLoadsToBackground() {
   NS_ASSERTION(!mLoadInBackground, "Why are you calling this more than once?");
   mLoadInBackground = true;
   if (!mChannel) {
     // No channel, resource is probably already loaded.
     return;
--- a/content/media/MediaResource.h
+++ b/content/media/MediaResource.h
@@ -191,16 +191,18 @@ inline MediaByteRange::MediaByteRange(Ti
  * MediaResource::Create automatically chooses the best implementation class.
  */
 class MediaResource
 {
 public:
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaResource)
 
+  virtual ~MediaResource() {}
+
   // The following can be called on the main thread only:
   // Get the URI
   virtual nsIURI* URI() const { return nullptr; }
   // Close the resource, stop any listeners, channels, etc.
   // Cancels any currently blocking Read request and forces that request to
   // return an error.
   virtual nsresult Close() = 0;
   // Suspend any downloads that are in progress.
@@ -217,17 +219,17 @@ public:
   // because its underlying resources are not suitable for reuse (e.g.
   // because the underlying connection has been lost, or this resource
   // just can't be safely cloned). If this returns true, CloneData could
   // still fail. If this returns false, CloneData should not be called.
   virtual bool CanClone() { return false; }
   // Create a new stream of the same type that refers to the same URI
   // with a new channel. Any cached data associated with the original
   // stream should be accessible in the new stream too.
-  virtual already_AddRefed<MediaResource> CloneData(MediaDecoder* aDecoder) = 0;
+  virtual MediaResource* CloneData(MediaDecoder* aDecoder) = 0;
   // Set statistics to be recorded to the object passed in.
   virtual void RecordStatisticsTo(MediaChannelStatistics *aStatistics) { }
 
   // These methods are called off the main thread.
   // The mode is initially MODE_PLAYBACK.
   virtual void SetReadMode(MediaCacheStream::ReadMode aMode) = 0;
   // This is the client's estimate of the playback rate assuming
   // the media plays continuously. The cache can't guess this itself
@@ -306,17 +308,19 @@ public:
   virtual bool IsDataCachedToEndOfResource(int64_t aOffset) = 0;
   // Returns true if this stream is suspended by the cache because the
   // cache is full. If true then the decoder should try to start consuming
   // data, otherwise we may not be able to make progress.
   // MediaDecoder::NotifySuspendedStatusChanged is called when this
   // changes.
   // For resources using the media cache, this returns true only when all
   // streams for the same resource are all suspended.
-  virtual bool IsSuspendedByCache() = 0;
+  // If aActiveResource is non-null, fills it with a pointer to a stream
+  // for this resource that is not suspended or ended.
+  virtual bool IsSuspendedByCache(MediaResource** aActiveResource) = 0;
   // Returns true if this stream has been suspended.
   virtual bool IsSuspended() = 0;
   // Reads only data which is cached in the media cache. If you try to read
   // any data which overlaps uncached data, or if aCount bytes otherwise can't
   // be read, this function will return failure. This function be called from
   // any thread, and it is the only read operation which is safe to call on
   // the main thread, since it's guaranteed to be non blocking.
   virtual nsresult ReadFromCache(char* aBuffer,
@@ -326,17 +330,17 @@ public:
   // for an HTTP network stream this returns true if HTTP1.1 Byte Range
   // requests are supported by the connection/server.
   virtual bool IsTransportSeekable() = 0;
 
   /**
    * Create a resource, reading data from the channel. Call on main thread only.
    * The caller must follow up by calling resource->Open().
    */
-  static already_AddRefed<MediaResource> Create(MediaDecoder* aDecoder, nsIChannel* aChannel);
+  static MediaResource* Create(MediaDecoder* aDecoder, nsIChannel* aChannel);
 
   /**
    * Open the stream. This creates a stream listener and returns it in
    * aStreamListener; this listener needs to be notified of incoming data.
    */
   virtual nsresult Open(nsIStreamListener** aStreamListener) = 0;
 
 #ifdef MOZ_DASH
@@ -365,18 +369,16 @@ public:
 
   // Notify that the last data byte range was loaded.
   virtual void NotifyLastByteRange() { }
 
   // Returns the content type of the resource. This is copied from the
   // nsIChannel when the MediaResource is created. Safe to call from
   // any thread.
   virtual const nsCString& GetContentType() const = 0;
-protected:
-  virtual ~MediaResource() {};
 };
 
 class BaseMediaResource : public MediaResource {
 public:
   virtual nsIURI* URI() const { return mURI; }
   virtual void MoveLoadsToBackground();
 
 protected:
@@ -489,17 +491,17 @@ public:
 #endif
   virtual nsresult Close();
   virtual void     Suspend(bool aCloseImmediately);
   virtual void     Resume();
   virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
   // Return true if the stream has been closed.
   bool IsClosed() const { return mCacheStream.IsClosed(); }
   virtual bool     CanClone();
-  virtual already_AddRefed<MediaResource> CloneData(MediaDecoder* aDecoder);
+  virtual MediaResource* CloneData(MediaDecoder* aDecoder);
   // Set statistics to be recorded to the object passed in. If not called,
   // |ChannelMediaResource| will create it's own statistics objects in |Open|.
   void RecordStatisticsTo(MediaChannelStatistics *aStatistics) MOZ_OVERRIDE {
     NS_ASSERTION(aStatistics, "Statistics param cannot be null!");
     MutexAutoLock lock(mLock);
     if (!mChannelStatistics) {
       mChannelStatistics = aStatistics;
     }
@@ -519,17 +521,17 @@ public:
   // Any thread
   virtual void    Pin();
   virtual void    Unpin();
   virtual double  GetDownloadRate(bool* aIsReliable);
   virtual int64_t GetLength();
   virtual int64_t GetNextCachedData(int64_t aOffset);
   virtual int64_t GetCachedDataEnd(int64_t aOffset);
   virtual bool    IsDataCachedToEndOfResource(int64_t aOffset);
-  virtual bool    IsSuspendedByCache();
+  virtual bool    IsSuspendedByCache(MediaResource** aActiveResource);
   virtual bool    IsSuspended();
   virtual bool    IsTransportSeekable() MOZ_OVERRIDE;
 
   class Listener MOZ_FINAL : public nsIStreamListener,
                              public nsIInterfaceRequestor,
                              public nsIChannelEventSink
   {
   public:
@@ -540,17 +542,17 @@ public:
     NS_DECL_NSIREQUESTOBSERVER
     NS_DECL_NSISTREAMLISTENER
     NS_DECL_NSICHANNELEVENTSINK
     NS_DECL_NSIINTERFACEREQUESTOR
 
     void Revoke() { mResource = nullptr; }
 
   private:
-    nsRefPtr<ChannelMediaResource> mResource;
+    ChannelMediaResource* mResource;
   };
   friend class Listener;
 
   nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges);
 
 protected:
   // These are called on the main thread by Listener.
   nsresult OnStartRequest(nsIRequest* aRequest);
--- a/content/media/omx/MPAPI.h
+++ b/content/media/omx/MPAPI.h
@@ -17,16 +17,17 @@ struct VideoPlane {
   int32_t mWidth;
   int32_t mHeight;
   int32_t mOffset;
   int32_t mSkip;
 };
 
 struct VideoFrame {
   int64_t mTimeUs;
+  int64_t mEndTimeUs;
   bool mKeyFrame;
   bool mShouldSkip;
   void *mData;
   size_t mSize;
   int32_t mStride;
   int32_t mSliceHeight;
   int32_t mRotation;
   VideoPlane Y;
--- a/content/media/omx/MediaOmxReader.cpp
+++ b/content/media/omx/MediaOmxReader.cpp
@@ -38,17 +38,17 @@ MediaOmxReader::~MediaOmxReader()
 }
 
 nsresult MediaOmxReader::Init(MediaDecoderReader* aCloneDonor)
 {
   return NS_OK;
 }
 
 nsresult MediaOmxReader::ReadMetadata(VideoInfo* aInfo,
-                                      MetadataTags** aTags)
+                                        MetadataTags** aTags)
 {
   NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
 
   *aTags = nullptr;
 
   if (!mOmxDecoder.get()) {
     mOmxDecoder = new OmxDecoder(mDecoder->GetResource(), mDecoder);
     if (!mOmxDecoder->Init()) {
@@ -113,17 +113,17 @@ nsresult MediaOmxReader::ResetDecode()
     container->ClearCurrentFrame();
   }
 
   mOmxDecoder.clear();
   return NS_OK;
 }
 
 bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip,
-                                      int64_t aTimeThreshold)
+                                        int64_t aTimeThreshold)
 {
   // Record number of frames decoded and parsed. Automatically update the
   // stats counters using the AutoNotifyDecoded stack-based class.
   uint32_t parsed = 0, decoded = 0;
   AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
 
   bool doSeek = mVideoSeekTimeUs != -1;
   if (doSeek) {
@@ -334,15 +334,15 @@ nsresult MediaOmxReader::GetBuffered(moz
 void MediaOmxReader::OnDecodeThreadFinish() {
   if (mOmxDecoder.get()) {
     mOmxDecoder->Pause();
   }
 }
 
 void MediaOmxReader::OnDecodeThreadStart() {
   if (mOmxDecoder.get()) {
-    DebugOnly<nsresult> result = mOmxDecoder->Play();
+    nsresult result = mOmxDecoder->Play();
     NS_ASSERTION(result == NS_OK, "OmxDecoder should be in play state to continue decoding");
   }
 }
 
 } // namespace mozilla
 
--- a/content/media/omx/OmxDecoder.cpp
+++ b/content/media/omx/OmxDecoder.cpp
@@ -34,18 +34,18 @@ using namespace mozilla;
 
 namespace mozilla {
 namespace layers {
 
 VideoGraphicBuffer::VideoGraphicBuffer(const android::wp<android::OmxDecoder> aOmxDecoder,
                                        android::MediaBuffer *aBuffer,
                                        SurfaceDescriptor *aDescriptor)
   : GraphicBufferLocked(*aDescriptor),
-    mMediaBuffer(aBuffer),
-    mOmxDecoder(aOmxDecoder)
+    mOmxDecoder(aOmxDecoder),
+    mMediaBuffer(aBuffer)
 {
   mMediaBuffer->add_ref();
 }
 
 VideoGraphicBuffer::~VideoGraphicBuffer()
 {
   if (mMediaBuffer) {
     mMediaBuffer->release();
@@ -69,17 +69,17 @@ VideoGraphicBuffer::Unlock()
 
 }
 }
 
 namespace android {
 
 MediaStreamSource::MediaStreamSource(MediaResource *aResource,
                                      AbstractMediaDecoder *aDecoder) :
-  mResource(aResource), mDecoder(aDecoder)
+  mDecoder(aDecoder), mResource(aResource)
 {
 }
 
 MediaStreamSource::~MediaStreamSource()
 {
 }
 
 status_t MediaStreamSource::initCheck() const
@@ -122,32 +122,32 @@ status_t MediaStreamSource::getSize(off6
 }
 
 }  // namespace android
 
 using namespace android;
 
 OmxDecoder::OmxDecoder(MediaResource *aResource,
                        AbstractMediaDecoder *aDecoder) :
+  mResource(aResource),
   mDecoder(aDecoder),
-  mResource(aResource),
   mVideoWidth(0),
   mVideoHeight(0),
   mVideoColorFormat(0),
   mVideoStride(0),
   mVideoSliceHeight(0),
   mVideoRotation(0),
   mAudioChannels(-1),
   mAudioSampleRate(-1),
   mDurationUs(-1),
   mVideoBuffer(nullptr),
   mAudioBuffer(nullptr),
   mIsVideoSeeking(false),
-  mAudioMetadataRead(false),
-  mPaused(false)
+  mPaused(false),
+  mAudioMetadataRead(false)
 {
 }
 
 OmxDecoder::~OmxDecoder()
 {
   ReleaseVideoBuffer();
   ReleaseAudioBuffer();
 
@@ -229,17 +229,17 @@ bool OmxDecoder::Init() {
   int64_t totalDurationUs = 0;
 
   mNativeWindow = new GonkNativeWindow();
   mNativeWindowClient = new GonkNativeWindowClient(mNativeWindow);
 
   // OMXClient::connect() always returns OK and abort's fatally if
   // it can't connect.
   OMXClient client;
-  DebugOnly<status_t> err = client.connect();
+  status_t err = client.connect();
   NS_ASSERTION(err == OK, "Failed to connect to OMX in mediaserver.");
   sp<IOMX> omx = client.interface();
 
   sp<MediaSource> videoTrack;
   sp<MediaSource> videoSource;
   if (videoTrackIndex != -1 && (videoTrack = extractor->getTrack(videoTrackIndex)) != nullptr) {
     // Experience with OMX codecs is that only the HW decoders are
     // worth bothering with, at least on the platforms where this code
@@ -507,16 +507,17 @@ bool OmxDecoder::ReadVideo(VideoFrame *a
       ReleaseAllPendingVideoBuffersLocked();
     }
   } else {
     err = mVideoSource->read(&mVideoBuffer);
   }
 
   if (err == OK && mVideoBuffer->range_length() > 0) {
     int64_t timeUs;
+    int64_t durationUs;
     int32_t unreadable;
     int32_t keyFrame;
 
     if (!mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs) ) {
       NS_WARNING("OMX decoder did not return frame time");
       return false;
     }
 
@@ -539,30 +540,33 @@ bool OmxDecoder::ReadVideo(VideoFrame *a
       // See Bug 850566.
       const mozilla::layers::SurfaceDescriptorGralloc& grallocDesc = descriptor->get_SurfaceDescriptorGralloc();
       mozilla::layers::SurfaceDescriptor newDescriptor = mozilla::layers::SurfaceDescriptorGralloc(grallocDesc.bufferParent(),
                                                                grallocDesc.bufferChild(), nsIntSize(mVideoWidth, mVideoHeight), grallocDesc.external());
 
       aFrame->mGraphicBuffer = new mozilla::layers::VideoGraphicBuffer(this, mVideoBuffer, &newDescriptor);
       aFrame->mRotation = mVideoRotation;
       aFrame->mTimeUs = timeUs;
+      aFrame->mEndTimeUs = timeUs + durationUs;
       aFrame->mKeyFrame = keyFrame;
       aFrame->Y.mWidth = mVideoWidth;
       aFrame->Y.mHeight = mVideoHeight;
     } else {
       char *data = static_cast<char *>(mVideoBuffer->data()) + mVideoBuffer->range_offset();
       size_t length = mVideoBuffer->range_length();
 
       if (unreadable) {
         LOG(PR_LOG_DEBUG, "video frame is unreadable");
       }
 
       if (!ToVideoFrame(aFrame, timeUs, data, length, keyFrame)) {
         return false;
       }
+
+      aFrame->mEndTimeUs = timeUs + durationUs;
     }
 
     if (aKeyframeSkip && timeUs < aTimeUs) {
       aFrame->mShouldSkip = true;
     }
 
   }
   else if (err == INFO_FORMAT_CHANGED) {
@@ -687,9 +691,8 @@ void OmxDecoder::Pause() {
     mVideoSource->pause();
   }
 
   if (mAudioSource.get()) {
     mAudioSource->pause();
   }
   mPaused = true;
 }
-
--- a/content/media/omx/OmxDecoder.h
+++ b/content/media/omx/OmxDecoder.h
@@ -33,20 +33,20 @@ class VideoGraphicBuffer : public Graphi
 
 namespace android {
 
 // MediaStreamSource is a DataSource that reads from a MPAPI media stream.
 class MediaStreamSource : public DataSource {
   typedef mozilla::MediaResource MediaResource;
   typedef mozilla::AbstractMediaDecoder AbstractMediaDecoder;
 
-  nsRefPtr<MediaResource> mResource;
+  MediaResource *mResource;
   AbstractMediaDecoder *mDecoder;
 public:
-  MediaStreamSource(MediaResource* aResource,
+  MediaStreamSource(MediaResource *aResource,
                     AbstractMediaDecoder *aDecoder);
 
   virtual status_t initCheck() const;
   virtual ssize_t readAt(off64_t offset, void *data, size_t size);
   virtual ssize_t readAt(off_t offset, void *data, size_t size) {
     return readAt(static_cast<off64_t>(offset), data, size);
   }
   virtual status_t getSize(off_t *size) {
@@ -75,17 +75,17 @@ class OmxDecoder : public RefBase {
 
   enum {
     kPreferSoftwareCodecs = 1,
     kSoftwareCodecsOnly = 8,
     kHardwareCodecsOnly = 16,
   };
 
   AbstractMediaDecoder *mDecoder;
-  nsRefPtr<MediaResource> mResource;
+  MediaResource *mResource;
   sp<GonkNativeWindow> mNativeWindow;
   sp<GonkNativeWindowClient> mNativeWindowClient;
   sp<MediaSource> mVideoTrack;
   sp<MediaSource> mVideoSource;
   sp<MediaSource> mAudioTrack;
   sp<MediaSource> mAudioSource;
   int32_t mVideoWidth;
   int32_t mVideoHeight;
--- a/content/media/plugins/MediaPluginHost.cpp
+++ b/content/media/plugins/MediaPluginHost.cpp
@@ -268,50 +268,42 @@ bool MediaPluginHost::FindDecoder(const 
       return true;
     }
   }
   return false;
 }
 
 MPAPI::Decoder *MediaPluginHost::CreateDecoder(MediaResource *aResource, const nsACString& aMimeType)
 {
-  NS_ENSURE_TRUE(aResource, nullptr);
+  const char *chars;
+  size_t len = NS_CStringGetData(aMimeType, &chars, nullptr);
 
-  nsAutoPtr<Decoder> decoder(new Decoder());
+  Decoder *decoder = new Decoder();
   if (!decoder) {
     return nullptr;
   }
   decoder->mResource = aResource;
 
-  const char *chars;
-  size_t len = NS_CStringGetData(aMimeType, &chars, nullptr);
   for (size_t n = 0; n < mPlugins.Length(); ++n) {
     Manifest *plugin = mPlugins[n];
     const char* const *codecs;
     if (!plugin->CanDecode(chars, len, &codecs)) {
       continue;
     }
     if (plugin->CreateDecoder(&sPluginHost, decoder, chars, len)) {
-      aResource->AddRef();
-      return decoder.forget();
+      return decoder;
     }
   }
 
   return nullptr;
 }
 
 void MediaPluginHost::DestroyDecoder(Decoder *aDecoder)
 {
   aDecoder->DestroyDecoder(aDecoder);
-  MediaResource* resource = GetResource(aDecoder);
-  if (resource) {
-    // resource *shouldn't* be null, but check anyway just in case the plugin
-    // decoder does something stupid.
-    resource->Release();
-  }
   delete aDecoder;
 }
 
 MediaPluginHost *sMediaPluginHost = nullptr;
 MediaPluginHost *GetMediaPluginHost()
 {
   if (!sMediaPluginHost) {
     sMediaPluginHost = new MediaPluginHost();