Bug 862182. r=roc,doublec
authorChris Pearce <cpearce@mozilla.com>
Fri, 03 May 2013 10:59:18 +1200
changeset 130694 11cf235a84d68d2c0bb0aca8996ee73caf5d38e3
parent 130693 f47c18bd70e37cb9504e63252382d41fa925552a
child 130695 14929e61959deb59b713d9710fa855f5665b0959
push id1579
push userphilringnalda@gmail.com
push dateSat, 04 May 2013 04:38:04 +0000
treeherderfx-team@a56432a42a41 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, doublec
bugs862182
milestone23.0a1
Bug 862182. r=roc,doublec
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
@@ -2384,17 +2384,17 @@ nsresult HTMLMediaElement::InitializeDec
 
   double duration = aOriginal->GetDuration();
   if (duration >= 0) {
     decoder->SetDuration(duration);
     decoder->SetTransportSeekable(aOriginal->IsTransportSeekable());
     decoder->SetMediaSeekable(aOriginal->IsMediaSeekable());
   }
 
-  MediaResource* resource = originalResource->CloneData(decoder);
+  nsRefPtr<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);
 }
 
@@ -2416,17 +2416,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()));
 
-  MediaResource* resource = MediaResource::Create(decoder, aChannel);
+  nsRefPtr<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 MediaResource* CloneData(MediaDecoder* aDecoder)
+  virtual already_AddRefed<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(MediaResource** aActiveResource) { return false; }
+  virtual bool IsSuspendedByCache() { 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,42 +1825,36 @@ MediaCacheStream::SetTransportSeekable(b
 bool
 MediaCacheStream::IsTransportSeekable()
 {
   ReentrantMonitorAutoEnter mon(gMediaCache->GetReentrantMonitor());
   return mIsTransportSeekable;
 }
 
 bool
-MediaCacheStream::AreAllStreamsForResourceSuspended(MediaResource** aActiveStream)
+MediaCacheStream::AreAllStreamsForResourceSuspended()
 {
   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,19 +326,17 @@ 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.
-  // 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);
+  bool AreAllStreamsForResourceSuspended();
 
   // 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,33 +404,32 @@ 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;
 }
 
@@ -943,19 +942,17 @@ void MediaDecoder::UpdatePlaybackRate()
   mResource->SetPlaybackRate(rate);
 }
 
 void MediaDecoder::NotifySuspendedStatusChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!mResource)
     return;
-  MediaResource* activeStream;
-  bool suspended = mResource->IsSuspendedByCache(&activeStream);
-
+  bool suspended = mResource->IsSuspendedByCache();
   if (mOwner) {
     mOwner->NotifySuspendedByCache(suspended);
     UpdateReadyStateForData();
   }
 }
 
 void MediaDecoder::NotifyBytesDownloaded()
 {
--- a/content/media/MediaDecoder.h
+++ b/content/media/MediaDecoder.h
@@ -291,16 +291,22 @@ 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,38 +708,39 @@ already_AddRefed<nsIPrincipal> ChannelMe
   return principal.forget();
 }
 
 bool ChannelMediaResource::CanClone()
 {
   return mCacheStream.IsAvailableForSharing();
 }
 
-MediaResource* ChannelMediaResource::CloneData(MediaDecoder* aDecoder)
+already_AddRefed<MediaResource> ChannelMediaResource::CloneData(MediaDecoder* aDecoder)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
   NS_ASSERTION(mCacheStream.IsAvailableForSharing(), "Stream can't be cloned");
 
-  ChannelMediaResource* resource = new ChannelMediaResource(aDecoder,
-                                                            nullptr,
-                                                            mURI,
-                                                            GetContentType());
+  nsRefPtr<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;
+  return resource.forget();
 }
 
 void ChannelMediaResource::CloseChannel()
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   {
     MutexAutoLock lock(mLock);
@@ -1182,19 +1183,19 @@ ChannelMediaResource::IsDataCachedToEndO
 
 void
 ChannelMediaResource::EnsureCacheUpToDate()
 {
   mCacheStream.EnsureCacheUpdate();
 }
 
 bool
-ChannelMediaResource::IsSuspendedByCache(MediaResource** aActiveResource)
+ChannelMediaResource::IsSuspendedByCache()
 {
-  return mCacheStream.AreAllStreamsForResourceSuspended(aActiveResource);
+  return mCacheStream.AreAllStreamsForResourceSuspended();
 }
 
 bool
 ChannelMediaResource::IsSuspended()
 {
   MutexAutoLock lock(mLock);
   return mSuspendCount > 0;
 }
@@ -1278,17 +1279,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 MediaResource* CloneData(MediaDecoder* aDecoder);
+  virtual already_AddRefed<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);
@@ -1321,23 +1322,17 @@ 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(MediaResource** aActiveResource)
-  {
-    if (aActiveResource) {
-      *aActiveResource = nullptr;
-    }
-    return false;
-  }
+  virtual bool    IsSuspendedByCache() { 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.
@@ -1499,17 +1494,17 @@ already_AddRefed<nsIPrincipal> FileMedia
   return principal.forget();
 }
 
 bool FileMediaResource::CanClone()
 {
   return true;
 }
 
-MediaResource* FileMediaResource::CloneData(MediaDecoder* aDecoder)
+already_AddRefed<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;
   }
@@ -1522,17 +1517,18 @@ MediaResource* FileMediaResource::CloneD
   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;
 
-  return new FileMediaResource(aDecoder, channel, mURI, GetContentType());
+  nsRefPtr<MediaResource> resource(new FileMediaResource(aDecoder, channel, mURI, GetContentType()));
+  return resource.forget();
 }
 
 nsresult FileMediaResource::ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount)
 {
   MutexAutoLock lock(mLock);
 
   EnsureSizeInitialized();
   int64_t offset = 0;
@@ -1587,37 +1583,40 @@ int64_t FileMediaResource::Tell()
     return 0;
   EnsureSizeInitialized();
 
   int64_t offset = 0;
   mSeekable->Tell(&offset);
   return offset;
 }
 
-MediaResource*
+already_AddRefed<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)) {
-    return new FileMediaResource(aDecoder, aChannel, uri, contentType);
+    resource = new FileMediaResource(aDecoder, aChannel, uri, contentType);
+  } else {
+    resource = new ChannelMediaResource(aDecoder, aChannel, uri, contentType);
   }
-  return new ChannelMediaResource(aDecoder, aChannel, uri, contentType);
+  return resource.forget();
 }
 
 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,18 +191,16 @@ 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.
@@ -219,17 +217,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 MediaResource* CloneData(MediaDecoder* aDecoder) = 0;
+  virtual already_AddRefed<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
@@ -308,19 +306,17 @@ 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.
-  // 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;
+  virtual bool IsSuspendedByCache() = 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,
@@ -330,17 +326,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 MediaResource* Create(MediaDecoder* aDecoder, nsIChannel* aChannel);
+  static already_AddRefed<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
@@ -369,16 +365,18 @@ 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:
@@ -491,17 +489,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 MediaResource* CloneData(MediaDecoder* aDecoder);
+  virtual already_AddRefed<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;
     }
@@ -521,17 +519,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(MediaResource** aActiveResource);
+  virtual bool    IsSuspendedByCache();
   virtual bool    IsSuspended();
   virtual bool    IsTransportSeekable() MOZ_OVERRIDE;
 
   class Listener MOZ_FINAL : public nsIStreamListener,
                              public nsIInterfaceRequestor,
                              public nsIChannelEventSink
   {
   public:
@@ -542,17 +540,17 @@ public:
     NS_DECL_NSIREQUESTOBSERVER
     NS_DECL_NSISTREAMLISTENER
     NS_DECL_NSICHANNELEVENTSINK
     NS_DECL_NSIINTERFACEREQUESTOR
 
     void Revoke() { mResource = nullptr; }
 
   private:
-    ChannelMediaResource* mResource;
+    nsRefPtr<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,17 +17,16 @@ 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()) {
-    nsresult result = mOmxDecoder->Play();
+    DebugOnly<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),
-    mOmxDecoder(aOmxDecoder),
-    mMediaBuffer(aBuffer)
+    mMediaBuffer(aBuffer),
+    mOmxDecoder(aOmxDecoder)
 {
   mMediaBuffer->add_ref();
 }
 
 VideoGraphicBuffer::~VideoGraphicBuffer()
 {
   if (mMediaBuffer) {
     mMediaBuffer->release();
@@ -69,17 +69,17 @@ VideoGraphicBuffer::Unlock()
 
 }
 }
 
 namespace android {
 
 MediaStreamSource::MediaStreamSource(MediaResource *aResource,
                                      AbstractMediaDecoder *aDecoder) :
-  mDecoder(aDecoder), mResource(aResource)
+  mResource(aResource), mDecoder(aDecoder)
 {
 }
 
 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) :
+  mDecoder(aDecoder),
   mResource(aResource),
-  mDecoder(aDecoder),
   mVideoWidth(0),
   mVideoHeight(0),
   mVideoColorFormat(0),
   mVideoStride(0),
   mVideoSliceHeight(0),
   mVideoRotation(0),
   mAudioChannels(-1),
   mAudioSampleRate(-1),
   mDurationUs(-1),
   mVideoBuffer(nullptr),
   mAudioBuffer(nullptr),
   mIsVideoSeeking(false),
-  mPaused(false),
-  mAudioMetadataRead(false)
+  mAudioMetadataRead(false),
+  mPaused(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;
-  status_t err = client.connect();
+  DebugOnly<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,17 +507,16 @@ 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;
     }
 
@@ -540,33 +539,30 @@ 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) {
@@ -691,8 +687,9 @@ 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;
 
-  MediaResource *mResource;
+  nsRefPtr<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;
-  MediaResource *mResource;
+  nsRefPtr<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,42 +268,50 @@ bool MediaPluginHost::FindDecoder(const 
       return true;
     }
   }
   return false;
 }
 
 MPAPI::Decoder *MediaPluginHost::CreateDecoder(MediaResource *aResource, const nsACString& aMimeType)
 {
-  const char *chars;
-  size_t len = NS_CStringGetData(aMimeType, &chars, nullptr);
+  NS_ENSURE_TRUE(aResource, nullptr);
 
-  Decoder *decoder = new Decoder();
+  nsAutoPtr<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)) {
-      return decoder;
+      aResource->AddRef();
+      return decoder.forget();
     }
   }
 
   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();