Bug 1100776 - Reference-count MediaData. r=cpearce
authorBobby Holley <bobbyholley@gmail.com>
Wed, 19 Nov 2014 13:01:10 -0800
changeset 242947 b49cba7d3b2843593c31cf46ecc0b591cdf037d4
parent 242946 d757834c073bab6ed5140bf20a730422901d5050
child 242948 dd71e7d2b3452a5363c1ae3908e6ade849d26a00
child 242982 7c4360f398ffaf8455f179c56f5103cd9f1fd39e
push id660
push userraliiev@mozilla.com
push dateWed, 18 Feb 2015 20:30:48 +0000
treeherdermozilla-release@49e493494178 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1100776
milestone36.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 1100776 - Reference-count MediaData. r=cpearce
dom/media/AudioSink.cpp
dom/media/MediaData.cpp
dom/media/MediaData.h
dom/media/MediaDataDecodedListener.h
dom/media/MediaDecoderReader.cpp
dom/media/MediaDecoderReader.h
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
dom/media/MediaQueue.h
dom/media/android/AndroidMediaReader.cpp
dom/media/android/AndroidMediaReader.h
dom/media/fmp4/BlankDecoderModule.cpp
dom/media/fmp4/MP4Reader.cpp
dom/media/fmp4/PlatformDecoderModule.h
dom/media/fmp4/android/AndroidDecoderModule.cpp
dom/media/fmp4/apple/AppleVDADecoder.cpp
dom/media/fmp4/apple/ReorderQueue.h
dom/media/fmp4/eme/EMEAudioDecoder.cpp
dom/media/fmp4/eme/EMEH264Decoder.cpp
dom/media/fmp4/ffmpeg/FFmpegH264Decoder.cpp
dom/media/fmp4/gonk/GonkAudioDecoderManager.cpp
dom/media/fmp4/gonk/GonkAudioDecoderManager.h
dom/media/fmp4/gonk/GonkMediaDataDecoder.cpp
dom/media/fmp4/gonk/GonkMediaDataDecoder.h
dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
dom/media/fmp4/gonk/GonkVideoDecoderManager.h
dom/media/fmp4/wmf/WMFAudioMFTManager.cpp
dom/media/fmp4/wmf/WMFAudioMFTManager.h
dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp
dom/media/fmp4/wmf/WMFMediaDataDecoder.h
dom/media/fmp4/wmf/WMFVideoMFTManager.cpp
dom/media/fmp4/wmf/WMFVideoMFTManager.h
dom/media/gstreamer/GStreamerReader.cpp
dom/media/mediasource/MediaSourceReader.cpp
dom/media/ogg/OggReader.cpp
dom/media/omx/MediaCodecReader.cpp
dom/media/omx/MediaOmxReader.cpp
dom/media/raw/RawReader.cpp
dom/media/webaudio/MediaBufferDecoder.cpp
dom/media/webm/WebMReader.cpp
dom/media/wmf/WMFReader.cpp
--- a/dom/media/AudioSink.cpp
+++ b/dom/media/AudioSink.cpp
@@ -311,17 +311,17 @@ AudioSink::PlaySilence(uint32_t aFrames)
   return frames;
 }
 
 uint32_t
 AudioSink::PlayFromAudioQueue()
 {
   AssertOnAudioThread();
   NS_ASSERTION(!mAudioStream->IsPaused(), "Don't play when paused");
-  nsAutoPtr<AudioData> audio(AudioQueue().PopFront());
+  nsRefPtr<AudioData> audio(AudioQueue().PopFront());
 
   SINK_LOG_V("playing %u frames of audio at time %lld",
              audio->mFrames, audio->mTime);
   mAudioStream->Write(audio->mAudioData, audio->mFrames);
 
   StartAudioStreamPlaybackIfNeeded();
 
   if (audio->mOffset != -1) {
--- a/dom/media/MediaData.cpp
+++ b/dom/media/MediaData.cpp
@@ -83,39 +83,36 @@ IsInEmulator()
 #endif
 
 VideoData::VideoData(int64_t aOffset, int64_t aTime, int64_t aDuration, int64_t aTimecode)
   : MediaData(VIDEO_DATA, aOffset, aTime, aDuration),
     mTimecode(aTimecode),
     mDuplicate(true),
     mKeyframe(false)
 {
-  MOZ_COUNT_CTOR(VideoData);
   NS_ASSERTION(mDuration >= 0, "Frame must have non-negative duration.");
 }
 
 VideoData::VideoData(int64_t aOffset,
                      int64_t aTime,
                      int64_t aDuration,
                      bool aKeyframe,
                      int64_t aTimecode,
                      IntSize aDisplay)
   : MediaData(VIDEO_DATA, aOffset, aTime, aDuration),
     mDisplay(aDisplay),
     mTimecode(aTimecode),
     mDuplicate(false),
     mKeyframe(aKeyframe)
 {
-  MOZ_COUNT_CTOR(VideoData);
   NS_ASSERTION(mDuration >= 0, "Frame must have non-negative duration.");
 }
 
 VideoData::~VideoData()
 {
-  MOZ_COUNT_DTOR(VideoData);
 }
 
 size_t
 VideoData::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
 {
   size_t size = aMallocSizeOf(this);
 
   // Currently only PLANAR_YCBCR has a well defined function for determining
@@ -125,58 +122,61 @@ VideoData::SizeOfIncludingThis(MallocSiz
         static_cast<const mozilla::layers::PlanarYCbCrImage*>(mImage.get());
     size += img->SizeOfIncludingThis(aMallocSizeOf);
   }
 
   return size;
 }
 
 /* static */
-VideoData* VideoData::ShallowCopyUpdateDuration(VideoData* aOther,
-                                                int64_t aDuration)
+already_AddRefed<VideoData>
+VideoData::ShallowCopyUpdateDuration(VideoData* aOther,
+                                     int64_t aDuration)
 {
-  VideoData* v = new VideoData(aOther->mOffset,
-                               aOther->mTime,
-                               aDuration,
-                               aOther->mKeyframe,
-                               aOther->mTimecode,
-                               aOther->mDisplay);
+  nsRefPtr<VideoData> v = new VideoData(aOther->mOffset,
+                                        aOther->mTime,
+                                        aDuration,
+                                        aOther->mKeyframe,
+                                        aOther->mTimecode,
+                                        aOther->mDisplay);
   v->mImage = aOther->mImage;
-  return v;
+  return v.forget();
 }
 
 /* static */
-VideoData* VideoData::ShallowCopyUpdateTimestamp(VideoData* aOther,
-                                                 int64_t aTimestamp)
+already_AddRefed<VideoData>
+VideoData::ShallowCopyUpdateTimestamp(VideoData* aOther,
+                                      int64_t aTimestamp)
 {
   NS_ENSURE_TRUE(aOther, nullptr);
-  VideoData* v = new VideoData(aOther->mOffset,
-                               aTimestamp,
-                               aOther->GetEndTime() - aTimestamp,
-                               aOther->mKeyframe,
-                               aOther->mTimecode,
-                               aOther->mDisplay);
+  nsRefPtr<VideoData> v = new VideoData(aOther->mOffset,
+                                        aTimestamp,
+                                        aOther->GetEndTime() - aTimestamp,
+                                        aOther->mKeyframe,
+                                        aOther->mTimecode,
+                                        aOther->mDisplay);
   v->mImage = aOther->mImage;
-  return v;
+  return v.forget();
 }
 
 /* static */
-VideoData* VideoData::ShallowCopyUpdateTimestampAndDuration(VideoData* aOther,
-                                                            int64_t aTimestamp,
-                                                            int64_t aDuration)
+already_AddRefed<VideoData>
+VideoData::ShallowCopyUpdateTimestampAndDuration(VideoData* aOther,
+                                                 int64_t aTimestamp,
+                                                 int64_t aDuration)
 {
   NS_ENSURE_TRUE(aOther, nullptr);
-  VideoData* v = new VideoData(aOther->mOffset,
-                               aTimestamp,
-                               aDuration,
-                               aOther->mKeyframe,
-                               aOther->mTimecode,
-                               aOther->mDisplay);
+  nsRefPtr<VideoData> v = new VideoData(aOther->mOffset,
+                                        aTimestamp,
+                                        aDuration,
+                                        aOther->mKeyframe,
+                                        aOther->mTimecode,
+                                        aOther->mDisplay);
   v->mImage = aOther->mImage;
-  return v;
+  return v.forget();
 }
 
 /* static */
 void VideoData::SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
                                     VideoInfo& aInfo,
                                     const YCbCrBuffer &aBuffer,
                                     const IntRect& aPicture,
                                     bool aCopyData)
@@ -208,36 +208,37 @@ void VideoData::SetVideoDataToImage(Plan
   if (aCopyData) {
     aVideoImage->SetData(data);
   } else {
     aVideoImage->SetDataNoCopy(data);
   }
 }
 
 /* static */
-VideoData* VideoData::Create(VideoInfo& aInfo,
-                             ImageContainer* aContainer,
-                             Image* aImage,
-                             int64_t aOffset,
-                             int64_t aTime,
-                             int64_t aDuration,
-                             const YCbCrBuffer& aBuffer,
-                             bool aKeyframe,
-                             int64_t aTimecode,
-                             const IntRect& aPicture)
+already_AddRefed<VideoData>
+VideoData::Create(VideoInfo& aInfo,
+                  ImageContainer* aContainer,
+                  Image* aImage,
+                  int64_t aOffset,
+                  int64_t aTime,
+                  int64_t aDuration,
+                  const YCbCrBuffer& aBuffer,
+                  bool aKeyframe,
+                  int64_t aTimecode,
+                  const IntRect& aPicture)
 {
   if (!aImage && !aContainer) {
     // Create a dummy VideoData with no image. This gives us something to
     // send to media streams if necessary.
-    nsAutoPtr<VideoData> v(new VideoData(aOffset,
-                                         aTime,
-                                         aDuration,
-                                         aKeyframe,
-                                         aTimecode,
-                                         aInfo.mDisplay.ToIntSize()));
+    nsRefPtr<VideoData> v(new VideoData(aOffset,
+                                        aTime,
+                                        aDuration,
+                                        aKeyframe,
+                                        aTimecode,
+                                        aInfo.mDisplay.ToIntSize()));
     return v.forget();
   }
 
   // The following situation should never happen unless there is a bug
   // in the decoder
   if (aBuffer.mPlanes[1].mWidth != aBuffer.mPlanes[2].mWidth ||
       aBuffer.mPlanes[1].mHeight != aBuffer.mPlanes[2].mHeight) {
     NS_ERROR("C planes with different sizes");
@@ -264,22 +265,22 @@ VideoData* VideoData::Create(VideoInfo& 
       !yLimit.isValid() || yLimit.value() > aBuffer.mPlanes[0].mHeight)
   {
     // The specified picture dimensions can't be contained inside the video
     // frame, we'll stomp memory if we try to copy it. Fail.
     NS_WARNING("Overflowing picture rect");
     return nullptr;
   }
 
-  nsAutoPtr<VideoData> v(new VideoData(aOffset,
-                                       aTime,
-                                       aDuration,
-                                       aKeyframe,
-                                       aTimecode,
-                                       aInfo.mDisplay.ToIntSize()));
+  nsRefPtr<VideoData> v(new VideoData(aOffset,
+                                      aTime,
+                                      aDuration,
+                                      aKeyframe,
+                                      aTimecode,
+                                      aInfo.mDisplay.ToIntSize()));
 #ifdef MOZ_WIDGET_GONK
   const YCbCrBuffer::Plane &Y = aBuffer.mPlanes[0];
   const YCbCrBuffer::Plane &Cb = aBuffer.mPlanes[1];
   const YCbCrBuffer::Plane &Cr = aBuffer.mPlanes[2];
 #endif
 
   if (!aImage) {
     // Currently our decoder only knows how to output to ImageFormat::PLANAR_YCBCR
@@ -323,87 +324,91 @@ VideoData* VideoData::Create(VideoInfo& 
     VideoData::SetVideoDataToImage(videoImage, aInfo, aBuffer, aPicture,
                                    true /* aCopyData */);
   }
 #endif
   return v.forget();
 }
 
 /* static */
-VideoData* VideoData::Create(VideoInfo& aInfo,
-                             ImageContainer* aContainer,
-                             int64_t aOffset,
-                             int64_t aTime,
-                             int64_t aDuration,
-                             const YCbCrBuffer& aBuffer,
-                             bool aKeyframe,
-                             int64_t aTimecode,
-                             const IntRect& aPicture)
+already_AddRefed<VideoData>
+VideoData::Create(VideoInfo& aInfo,
+                  ImageContainer* aContainer,
+                  int64_t aOffset,
+                  int64_t aTime,
+                  int64_t aDuration,
+                  const YCbCrBuffer& aBuffer,
+                  bool aKeyframe,
+                  int64_t aTimecode,
+                  const IntRect& aPicture)
 {
   return Create(aInfo, aContainer, nullptr, aOffset, aTime, aDuration, aBuffer,
                 aKeyframe, aTimecode, aPicture);
 }
 
 /* static */
-VideoData* VideoData::Create(VideoInfo& aInfo,
-                             Image* aImage,
-                             int64_t aOffset,
-                             int64_t aTime,
-                             int64_t aDuration,
-                             const YCbCrBuffer& aBuffer,
-                             bool aKeyframe,
-                             int64_t aTimecode,
-                             const IntRect& aPicture)
+already_AddRefed<VideoData>
+VideoData::Create(VideoInfo& aInfo,
+                  Image* aImage,
+                  int64_t aOffset,
+                  int64_t aTime,
+                  int64_t aDuration,
+                  const YCbCrBuffer& aBuffer,
+                  bool aKeyframe,
+                  int64_t aTimecode,
+                  const IntRect& aPicture)
 {
   return Create(aInfo, nullptr, aImage, aOffset, aTime, aDuration, aBuffer,
                 aKeyframe, aTimecode, aPicture);
 }
 
 /* static */
-VideoData* VideoData::CreateFromImage(VideoInfo& aInfo,
-                                      ImageContainer* aContainer,
-                                      int64_t aOffset,
-                                      int64_t aTime,
-                                      int64_t aDuration,
-                                      const nsRefPtr<Image>& aImage,
-                                      bool aKeyframe,
-                                      int64_t aTimecode,
-                                      const IntRect& aPicture)
+already_AddRefed<VideoData>
+VideoData::CreateFromImage(VideoInfo& aInfo,
+                           ImageContainer* aContainer,
+                           int64_t aOffset,
+                           int64_t aTime,
+                           int64_t aDuration,
+                           const nsRefPtr<Image>& aImage,
+                           bool aKeyframe,
+                           int64_t aTimecode,
+                           const IntRect& aPicture)
 {
-  nsAutoPtr<VideoData> v(new VideoData(aOffset,
-                                       aTime,
-                                       aDuration,
-                                       aKeyframe,
-                                       aTimecode,
-                                       aInfo.mDisplay.ToIntSize()));
+  nsRefPtr<VideoData> v(new VideoData(aOffset,
+                                      aTime,
+                                      aDuration,
+                                      aKeyframe,
+                                      aTimecode,
+                                      aInfo.mDisplay.ToIntSize()));
   v->mImage = aImage;
   return v.forget();
 }
 
 #ifdef MOZ_OMX_DECODER
 /* static */
-VideoData* VideoData::Create(VideoInfo& aInfo,
-                             ImageContainer* aContainer,
-                             int64_t aOffset,
-                             int64_t aTime,
-                             int64_t aDuration,
-                             mozilla::layers::TextureClient* aBuffer,
-                             bool aKeyframe,
-                             int64_t aTimecode,
-                             const IntRect& aPicture)
+already_AddRefed<VideoData>
+VideoData::Create(VideoInfo& aInfo,
+                  ImageContainer* aContainer,
+                  int64_t aOffset,
+                  int64_t aTime,
+                  int64_t aDuration,
+                  mozilla::layers::TextureClient* aBuffer,
+                  bool aKeyframe,
+                  int64_t aTimecode,
+                  const IntRect& aPicture)
 {
   if (!aContainer) {
     // Create a dummy VideoData with no image. This gives us something to
     // send to media streams if necessary.
-    nsAutoPtr<VideoData> v(new VideoData(aOffset,
-                                         aTime,
-                                         aDuration,
-                                         aKeyframe,
-                                         aTimecode,
-                                         aInfo.mDisplay.ToIntSize()));
+    nsRefPtr<VideoData> v(new VideoData(aOffset,
+                                        aTime,
+                                        aDuration,
+                                        aKeyframe,
+                                        aTimecode,
+                                        aInfo.mDisplay.ToIntSize()));
     return v.forget();
   }
 
   // The following situations could be triggered by invalid input
   if (aPicture.width <= 0 || aPicture.height <= 0) {
     NS_WARNING("Empty picture rect");
     return nullptr;
   }
@@ -415,22 +420,22 @@ VideoData* VideoData::Create(VideoInfo& 
   if (!xLimit.isValid() || !yLimit.isValid())
   {
     // The specified picture dimensions can't be contained inside the video
     // frame, we'll stomp memory if we try to copy it. Fail.
     NS_WARNING("Overflowing picture rect");
     return nullptr;
   }
 
-  nsAutoPtr<VideoData> v(new VideoData(aOffset,
-                                       aTime,
-                                       aDuration,
-                                       aKeyframe,
-                                       aTimecode,
-                                       aInfo.mDisplay.ToIntSize()));
+  nsRefPtr<VideoData> v(new VideoData(aOffset,
+                                      aTime,
+                                      aDuration,
+                                      aKeyframe,
+                                      aTimecode,
+                                      aInfo.mDisplay.ToIntSize()));
 
   v->mImage = aContainer->CreateImage(ImageFormat::GRALLOC_PLANAR_YCBCR);
   if (!v->mImage) {
     return nullptr;
   }
   NS_ASSERTION(v->mImage->GetFormat() == ImageFormat::GRALLOC_PLANAR_YCBCR,
                "Wrong format?");
   typedef mozilla::layers::GrallocImage GrallocImage;
--- a/dom/media/MediaData.h
+++ b/dom/media/MediaData.h
@@ -19,34 +19,34 @@ namespace layers {
 class Image;
 class ImageContainer;
 }
 
 // Container that holds media samples.
 class MediaData {
 public:
 
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaData)
+
   enum Type {
     AUDIO_DATA = 0,
     VIDEO_DATA
   };
 
   MediaData(Type aType,
             int64_t aOffset,
             int64_t aTimestamp,
             int64_t aDuration)
     : mType(aType)
     , mOffset(aOffset)
     , mTime(aTimestamp)
     , mDuration(aDuration)
     , mDiscontinuity(false)
   {}
 
-  virtual ~MediaData() {}
-
   // Type of contained data.
   const Type mType;
 
   // Approximate byte offset where this data was demuxed from its media.
   const int64_t mOffset;
 
   // Start time of sample, in microseconds.
   const int64_t mTime;
@@ -55,16 +55,19 @@ public:
   const int64_t mDuration;
 
   // True if this is the first sample after a gap or discontinuity in
   // the stream. This is true for the first sample in a stream after a seek.
   bool mDiscontinuity;
 
   int64_t GetEndTime() const { return mTime + mDuration; }
 
+protected:
+  virtual ~MediaData() {}
+
 };
 
 // Holds chunk a decoded audio frames.
 class AudioData : public MediaData {
 public:
 
   AudioData(int64_t aOffset,
             int64_t aTime,
@@ -72,39 +75,34 @@ public:
             uint32_t aFrames,
             AudioDataValue* aData,
             uint32_t aChannels,
             uint32_t aRate)
     : MediaData(AUDIO_DATA, aOffset, aTime, aDuration)
     , mFrames(aFrames)
     , mChannels(aChannels)
     , mRate(aRate)
-    , mAudioData(aData)
-  {
-    MOZ_COUNT_CTOR(AudioData);
-  }
-
-  ~AudioData()
-  {
-    MOZ_COUNT_DTOR(AudioData);
-  }
+    , mAudioData(aData) {}
 
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
 
   // If mAudioBuffer is null, creates it from mAudioData.
   void EnsureAudioBuffer();
 
   const uint32_t mFrames;
   const uint32_t mChannels;
   const uint32_t mRate;
   // At least one of mAudioBuffer/mAudioData must be non-null.
   // mChannels channels, each with mFrames frames
   nsRefPtr<SharedBuffer> mAudioBuffer;
   // mFrames frames, each with mChannels values
   nsAutoArrayPtr<AudioDataValue> mAudioData;
+
+protected:
+  ~AudioData() {}
 };
 
 namespace layers {
 class TextureClient;
 class PlanarYCbCrImage;
 }
 
 class VideoInfo;
@@ -138,113 +136,112 @@ public:
   // Constructs a VideoData object. If aImage is nullptr, creates a new Image
   // holding a copy of the YCbCr data passed in aBuffer. If aImage is not
   // nullptr, it's stored as the underlying video image and aBuffer is assumed
   // to point to memory within aImage so no copy is made. aTimecode is a codec
   // specific number representing the timestamp of the frame of video data.
   // Returns nsnull if an error occurs. This may indicate that memory couldn't
   // be allocated to create the VideoData object, or it may indicate some
   // problem with the input data (e.g. negative stride).
-  static VideoData* Create(VideoInfo& aInfo,
-                           ImageContainer* aContainer,
-                           Image* aImage,
-                           int64_t aOffset,
-                           int64_t aTime,
-                           int64_t aDuration,
-                           const YCbCrBuffer &aBuffer,
-                           bool aKeyframe,
-                           int64_t aTimecode,
-                           const IntRect& aPicture);
+  static already_AddRefed<VideoData> Create(VideoInfo& aInfo,
+                                            ImageContainer* aContainer,
+                                            Image* aImage,
+                                            int64_t aOffset,
+                                            int64_t aTime,
+                                            int64_t aDuration,
+                                            const YCbCrBuffer &aBuffer,
+                                            bool aKeyframe,
+                                            int64_t aTimecode,
+                                            const IntRect& aPicture);
 
   // Variant that always makes a copy of aBuffer
-  static VideoData* Create(VideoInfo& aInfo,
-                           ImageContainer* aContainer,
-                           int64_t aOffset,
-                           int64_t aTime,
-                           int64_t aDuration,
-                           const YCbCrBuffer &aBuffer,
-                           bool aKeyframe,
-                           int64_t aTimecode,
-                           const IntRect& aPicture);
+  static already_AddRefed<VideoData> Create(VideoInfo& aInfo,
+                                            ImageContainer* aContainer,
+                                            int64_t aOffset,
+                                            int64_t aTime,
+                                            int64_t aDuration,
+                                            const YCbCrBuffer &aBuffer,
+                                            bool aKeyframe,
+                                            int64_t aTimecode,
+                                            const IntRect& aPicture);
 
   // Variant to create a VideoData instance given an existing aImage
-  static VideoData* Create(VideoInfo& aInfo,
-                           Image* aImage,
-                           int64_t aOffset,
-                           int64_t aTime,
-                           int64_t aDuration,
-                           const YCbCrBuffer &aBuffer,
-                           bool aKeyframe,
-                           int64_t aTimecode,
-                           const IntRect& aPicture);
+  static already_AddRefed<VideoData> Create(VideoInfo& aInfo,
+                                            Image* aImage,
+                                            int64_t aOffset,
+                                            int64_t aTime,
+                                            int64_t aDuration,
+                                            const YCbCrBuffer &aBuffer,
+                                            bool aKeyframe,
+                                            int64_t aTimecode,
+                                            const IntRect& aPicture);
 
-  static VideoData* Create(VideoInfo& aInfo,
-                           ImageContainer* aContainer,
-                           int64_t aOffset,
-                           int64_t aTime,
-                           int64_t aDuration,
-                           layers::TextureClient* aBuffer,
-                           bool aKeyframe,
-                           int64_t aTimecode,
-                           const IntRect& aPicture);
+  static already_AddRefed<VideoData> Create(VideoInfo& aInfo,
+                                             ImageContainer* aContainer,
+                                             int64_t aOffset,
+                                             int64_t aTime,
+                                             int64_t aDuration,
+                                             layers::TextureClient* aBuffer,
+                                             bool aKeyframe,
+                                             int64_t aTimecode,
+                                             const IntRect& aPicture);
 
-  static VideoData* CreateFromImage(VideoInfo& aInfo,
-                                    ImageContainer* aContainer,
-                                    int64_t aOffset,
-                                    int64_t aTime,
-                                    int64_t aDuration,
-                                    const nsRefPtr<Image>& aImage,
-                                    bool aKeyframe,
-                                    int64_t aTimecode,
-                                    const IntRect& aPicture);
+  static already_AddRefed<VideoData> CreateFromImage(VideoInfo& aInfo,
+                                                     ImageContainer* aContainer,
+                                                     int64_t aOffset,
+                                                     int64_t aTime,
+                                                     int64_t aDuration,
+                                                     const nsRefPtr<Image>& aImage,
+                                                     bool aKeyframe,
+                                                     int64_t aTimecode,
+                                                     const IntRect& aPicture);
 
   // Creates a new VideoData identical to aOther, but with a different
   // specified duration. All data from aOther is copied into the new
   // VideoData. The new VideoData's mImage field holds a reference to
   // aOther's mImage, i.e. the Image is not copied. This function is useful
   // in reader backends that can't determine the duration of a VideoData
   // until the next frame is decoded, i.e. it's a way to change the const
   // duration field on a VideoData.
-  static VideoData* ShallowCopyUpdateDuration(VideoData* aOther,
-                                              int64_t aDuration);
+  static already_AddRefed<VideoData> ShallowCopyUpdateDuration(VideoData* aOther,
+                                                               int64_t aDuration);
 
   // Creates a new VideoData identical to aOther, but with a different
   // specified timestamp. All data from aOther is copied into the new
   // VideoData, as ShallowCopyUpdateDuration() does.
-  static VideoData* ShallowCopyUpdateTimestamp(VideoData* aOther,
-                                               int64_t aTimestamp);
+  static already_AddRefed<VideoData> ShallowCopyUpdateTimestamp(VideoData* aOther,
+                                                                int64_t aTimestamp);
 
   // Creates a new VideoData identical to aOther, but with a different
   // specified timestamp and duration. All data from aOther is copied
   // into the new VideoData, as ShallowCopyUpdateDuration() does.
-  static VideoData* ShallowCopyUpdateTimestampAndDuration(VideoData* aOther,
-                                                          int64_t aTimestamp,
-                                                          int64_t aDuration);
+  static already_AddRefed<VideoData>
+  ShallowCopyUpdateTimestampAndDuration(VideoData* aOther, int64_t aTimestamp,
+                                        int64_t aDuration);
 
   // Initialize PlanarYCbCrImage. Only When aCopyData is true,
   // video data is copied to PlanarYCbCrImage.
   static void SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
                                   VideoInfo& aInfo,
                                   const YCbCrBuffer &aBuffer,
                                   const IntRect& aPicture,
                                   bool aCopyData);
 
   // Constructs a duplicate VideoData object. This intrinsically tells the
   // player that it does not need to update the displayed frame when this
   // frame is played; this frame is identical to the previous.
-  static VideoData* CreateDuplicate(int64_t aOffset,
-                                    int64_t aTime,
-                                    int64_t aDuration,
-                                    int64_t aTimecode)
+  static already_AddRefed<VideoData> CreateDuplicate(int64_t aOffset,
+                                                     int64_t aTime,
+                                                     int64_t aDuration,
+                                                     int64_t aTimecode)
   {
-    return new VideoData(aOffset, aTime, aDuration, aTimecode);
+    nsRefPtr<VideoData> rv = new VideoData(aOffset, aTime, aDuration, aTimecode);
+    return rv.forget();
   }
 
-  ~VideoData();
-
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
 
   // Dimensions at which to display the video frame. The picture region
   // will be scaled to this size. This is should be the picture region's
   // dimensions scaled with respect to its aspect ratio.
   const IntSize mDisplay;
 
   // Codec specific internal time code. For Ogg based codecs this is the
@@ -254,26 +251,27 @@ public:
   // This frame's image.
   nsRefPtr<Image> mImage;
 
   // When true, denotes that this frame is identical to the frame that
   // came before; it's a duplicate. mBuffer will be empty.
   const bool mDuplicate;
   const bool mKeyframe;
 
-public:
   VideoData(int64_t aOffset,
             int64_t aTime,
             int64_t aDuration,
             int64_t aTimecode);
 
   VideoData(int64_t aOffset,
             int64_t aTime,
             int64_t aDuration,
             bool aKeyframe,
             int64_t aTimecode,
             IntSize aDisplay);
 
+protected:
+  ~VideoData();
 };
 
 } // namespace mozilla
 
 #endif // MediaData_h
--- a/dom/media/MediaDataDecodedListener.h
+++ b/dom/media/MediaDataDecodedListener.h
@@ -29,33 +29,31 @@ public:
     , mTarget(aTarget)
   {
     MOZ_ASSERT(aTarget);
     MOZ_ASSERT(aTaskQueue);
   }
 
   virtual void OnAudioDecoded(AudioData* aSample) MOZ_OVERRIDE {
     MonitorAutoLock lock(mMonitor);
-    nsAutoPtr<AudioData> sample(aSample);
     if (!mTarget || !mTaskQueue) {
       // We've been shutdown, abort.
       return;
     }
-    RefPtr<nsIRunnable> task(new DeliverAudioTask(sample.forget(), mTarget));
+    RefPtr<nsIRunnable> task(new DeliverAudioTask(aSample, mTarget));
     mTaskQueue->Dispatch(task);
   }
 
   virtual void OnVideoDecoded(VideoData* aSample) MOZ_OVERRIDE {
     MonitorAutoLock lock(mMonitor);
-    nsAutoPtr<VideoData> sample(aSample);
     if (!mTarget || !mTaskQueue) {
       // We've been shutdown, abort.
       return;
     }
-    RefPtr<nsIRunnable> task(new DeliverVideoTask(sample.forget(), mTarget));
+    RefPtr<nsIRunnable> task(new DeliverVideoTask(aSample, mTarget));
     mTaskQueue->Dispatch(task);
   }
 
   virtual void OnNotDecoded(MediaData::Type aType, NotDecodedReason aReason) MOZ_OVERRIDE {
     MonitorAutoLock lock(mMonitor);
     if (!mTarget || !mTaskQueue) {
       // We've been shutdown, abort.
       return;
@@ -96,21 +94,21 @@ private:
     }
   protected:
     ~DeliverAudioTask()
     {
       MOZ_COUNT_DTOR(DeliverAudioTask);
     }
   public:
     NS_METHOD Run() {
-      mTarget->OnAudioDecoded(mSample.forget());
+      mTarget->OnAudioDecoded(mSample);
       return NS_OK;
     }
   private:
-    nsAutoPtr<AudioData> mSample;
+    nsRefPtr<AudioData> mSample;
     RefPtr<Target> mTarget;
   };
 
   class DeliverVideoTask : public nsRunnable {
   public:
     DeliverVideoTask(VideoData* aSample, Target* aTarget)
       : mSample(aSample)
       , mTarget(aTarget)
@@ -119,21 +117,21 @@ private:
     }
   protected:
     ~DeliverVideoTask()
     {
       MOZ_COUNT_DTOR(DeliverVideoTask);
     }
   public:
     NS_METHOD Run() {
-      mTarget->OnVideoDecoded(mSample.forget());
+      mTarget->OnVideoDecoded(mSample);
       return NS_OK;
     }
   private:
-    nsAutoPtr<VideoData> mSample;
+    nsRefPtr<VideoData> mSample;
     RefPtr<Target> mTarget;
   };
 
   class DeliverNotDecodedTask : public nsRunnable {
   public:
     DeliverNotDecodedTask(MediaData::Type aType,
                           RequestSampleCallback::NotDecodedReason aReason,
                           Target* aTarget)
--- a/dom/media/MediaDecoderReader.cpp
+++ b/dom/media/MediaDecoderReader.cpp
@@ -189,17 +189,17 @@ MediaDecoderReader::RequestVideoData(boo
       // again. We don't just decode straight in a loop here, as that
       // would hog the decode task queue.
       RefPtr<nsIRunnable> task(new RequestVideoWithSkipTask(this, aTimeThreshold));
       mTaskQueue->Dispatch(task);
       return;
     }
   }
   if (VideoQueue().GetSize() > 0) {
-    VideoData* v = VideoQueue().PopFront();
+    nsRefPtr<VideoData> v = VideoQueue().PopFront();
     if (v && mVideoDiscontinuity) {
       v->mDiscontinuity = true;
       mVideoDiscontinuity = false;
     }
     GetCallback()->OnVideoDecoded(v);
   } else if (VideoQueue().IsFinished()) {
     GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA, RequestSampleCallback::END_OF_STREAM);
   }
@@ -221,17 +221,17 @@ MediaDecoderReader::RequestAudioData()
     if (AudioQueue().GetSize() == 0 && mTaskQueue) {
       RefPtr<nsIRunnable> task(NS_NewRunnableMethod(
           this, &MediaDecoderReader::RequestAudioData));
       mTaskQueue->Dispatch(task.forget());
       return;
     }
   }
   if (AudioQueue().GetSize() > 0) {
-    AudioData* a = AudioQueue().PopFront();
+    nsRefPtr<AudioData> a = AudioQueue().PopFront();
     if (mAudioDiscontinuity) {
       a->mDiscontinuity = true;
       mAudioDiscontinuity = false;
     }
     GetCallback()->OnAudioDecoded(a);
     return;
   } else if (AudioQueue().IsFinished()) {
     GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, RequestSampleCallback::END_OF_STREAM);
@@ -303,17 +303,17 @@ AudioDecodeRendezvous::Reset()
 {
   MonitorAutoLock mon(mMonitor);
   mHaveResult = false;
   mStatus = NS_OK;
   mSample = nullptr;
 }
 
 nsresult
-AudioDecodeRendezvous::Await(nsAutoPtr<AudioData>& aSample)
+AudioDecodeRendezvous::Await(nsRefPtr<AudioData>& aSample)
 {
   MonitorAutoLock mon(mMonitor);
   while (!mHaveResult) {
     mon.Wait();
   }
   mHaveResult = false;
   aSample = mSample;
   return mStatus;
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -317,23 +317,23 @@ public:
   virtual void OnVideoDecoded(VideoData* aSample) MOZ_OVERRIDE {}
   virtual void OnNotDecoded(MediaData::Type aType, NotDecodedReason aReason) MOZ_OVERRIDE;
   virtual void OnSeekCompleted(nsresult aResult) MOZ_OVERRIDE {};
   virtual void BreakCycles() MOZ_OVERRIDE {};
   void Reset();
 
   // Returns failure on error, or NS_OK.
   // If *aSample is null, EOS has been reached.
-  nsresult Await(nsAutoPtr<AudioData>& aSample);
+  nsresult Await(nsRefPtr<AudioData>& aSample);
 
   // Interrupts a call to Wait().
   void Cancel();
 
 private:
   Monitor mMonitor;
   nsresult mStatus;
-  nsAutoPtr<AudioData> mSample;
+  nsRefPtr<AudioData> mSample;
   bool mHaveResult;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -398,17 +398,17 @@ void MediaDecoderStateMachine::SendStrea
         mediaStream->AddTrack(TRACK_VIDEO, RATE_VIDEO, 0, video);
         stream->mStream->DispatchWhenNotEnoughBuffered(TRACK_VIDEO,
             GetStateMachineThread(), GetWakeDecoderRunnable());
       }
       stream->mStreamInitialized = true;
     }
 
     if (mInfo.HasAudio()) {
-      nsAutoTArray<AudioData*,10> audio;
+      nsAutoTArray<nsRefPtr<AudioData>,10> audio;
       // It's OK to hold references to the AudioData because while audio
       // is captured, only the decoder thread pops from the queue (see below).
       AudioQueue().GetElementsAfter(stream->mLastAudioPacketTime, &audio);
       AudioSegment output;
       for (uint32_t i = 0; i < audio.Length(); ++i) {
         SendStreamAudio(audio[i], stream, &output);
       }
       if (output.GetDuration() > 0) {
@@ -420,17 +420,17 @@ void MediaDecoderStateMachine::SendStrea
       }
       minLastAudioPacketTime = std::min(minLastAudioPacketTime, stream->mLastAudioPacketTime);
       endPosition = std::max(endPosition,
           mediaStream->TicksToTimeRoundDown(mInfo.mAudio.mRate,
                                             stream->mAudioFramesWritten));
     }
 
     if (mInfo.HasVideo()) {
-      nsAutoTArray<VideoData*,10> video;
+      nsAutoTArray<nsRefPtr<VideoData>,10> video;
       // It's OK to hold references to the VideoData only the decoder thread
       // pops from the queue.
       VideoQueue().GetElementsAfter(stream->mNextVideoTime, &video);
       VideoSegment output;
       for (uint32_t i = 0; i < video.Length(); ++i) {
         VideoData* v = video[i];
         if (stream->mNextVideoTime < v->mTime) {
           VERBOSE_LOG("writing last video to MediaStream %p for %lldus",
@@ -485,17 +485,17 @@ void MediaDecoderStateMachine::SendStrea
       // actually contain data for mCurrentFrameTime. This means if someone might
       // create a new output stream and we actually don't have the audio for the
       // very start. That's OK, we'll play silence instead for a brief moment.
       // That's OK. Seeking to this time would have a similar issue for such
       // badly muxed resources.
       if (!a || a->GetEndTime() >= minLastAudioPacketTime)
         break;
       OnAudioEndTimeUpdate(std::max(mAudioEndTime, a->GetEndTime()));
-      delete AudioQueue().PopFront();
+      nsRefPtr<AudioData> releaseMe = AudioQueue().PopFront();
     }
 
     if (finished) {
       mAudioCompleted = true;
       UpdateReadyState();
     }
   }
 }
@@ -686,36 +686,36 @@ MediaDecoderStateMachine::IsVideoSeekCom
      !mDropVideoUntilNextDiscontinuity &&
      (VideoQueue().IsFinished() || VideoQueue().GetSize() > 0));
 }
 
 void
 MediaDecoderStateMachine::OnAudioDecoded(AudioData* aAudioSample)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  nsAutoPtr<AudioData> audio(aAudioSample);
+  nsRefPtr<AudioData> audio(aAudioSample);
   MOZ_ASSERT(audio);
   mAudioRequestPending = false;
 
   SAMPLE_LOG("OnAudioDecoded [%lld,%lld] disc=%d",
              (audio ? audio->mTime : -1),
              (audio ? audio->GetEndTime() : -1),
              (audio ? audio->mDiscontinuity : 0));
 
   switch (mState) {
     case DECODER_STATE_DECODING_FIRSTFRAME: {
-      Push(audio.forget());
+      Push(audio);
       MaybeFinishDecodeFirstFrame();
       return;
     }
 
     case DECODER_STATE_BUFFERING:
     case DECODER_STATE_DECODING: {
       // In buffering and decoding state, we simply enqueue samples.
-      Push(audio.forget());
+      Push(audio);
       return;
     }
 
     case DECODER_STATE_SEEKING: {
       if (!mCurrentSeekTarget.IsValid()) {
         // We've received a sample from a previous decode. Discard it.
         return;
       }
@@ -733,21 +733,21 @@ MediaDecoderStateMachine::OnAudioDecoded
           // seek and decode to the seek target. This is not conformant to the
           // spec, fastSeek should always be fast, but until we get the time to
           // change all Readers to seek to the keyframe after the currentTime
           // in this case, we'll just decode forward. Bug 1026330.
           mCurrentSeekTarget.mType = SeekTarget::Accurate;
         }
         if (mCurrentSeekTarget.mType == SeekTarget::PrevSyncPoint) {
           // Non-precise seek; we can stop the seek at the first sample.
-          AudioQueue().Push(audio.forget());
+          AudioQueue().Push(audio);
         } else {
           // We're doing an accurate seek. We must discard
           // MediaData up to the one containing exact seek target.
-          if (NS_FAILED(DropAudioUpToSeekTarget(audio.forget()))) {
+          if (NS_FAILED(DropAudioUpToSeekTarget(audio))) {
             DecodeError();
             return;
           }
         }
       }
       CheckIfSeekComplete();
       return;
     }
@@ -832,17 +832,18 @@ MediaDecoderStateMachine::OnNotDecoded(M
   // state.
   MOZ_ASSERT(aReason == RequestSampleCallback::END_OF_STREAM);
   if (!isAudio && mState == DECODER_STATE_SEEKING &&
       mCurrentSeekTarget.IsValid() && mFirstVideoFrameAfterSeek) {
     // Null sample. Hit end of stream. If we have decoded a frame,
     // insert it into the queue so that we have something to display.
     // We make sure to do this before invoking VideoQueue().Finish()
     // below.
-    VideoQueue().Push(mFirstVideoFrameAfterSeek.forget());
+    VideoQueue().Push(mFirstVideoFrameAfterSeek);
+    mFirstVideoFrameAfterSeek = nullptr;
   }
   isAudio ? AudioQueue().Finish() : VideoQueue().Finish();
   switch (mState) {
     case DECODER_STATE_DECODING_FIRSTFRAME: {
       MaybeFinishDecodeFirstFrame();
       return;
     }
 
@@ -896,34 +897,34 @@ MediaDecoderStateMachine::MaybeFinishDec
     DecodeError();
   }
 }
 
 void
 MediaDecoderStateMachine::OnVideoDecoded(VideoData* aVideoSample)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  nsAutoPtr<VideoData> video(aVideoSample);
+  nsRefPtr<VideoData> video(aVideoSample);
   mVideoRequestPending = false;
 
   SAMPLE_LOG("OnVideoDecoded [%lld,%lld] disc=%d",
              (video ? video->mTime : -1),
              (video ? video->GetEndTime() : -1),
              (video ? video->mDiscontinuity : 0));
 
   switch (mState) {
     case DECODER_STATE_DECODING_FIRSTFRAME: {
-      Push(video.forget());
+      Push(video);
       MaybeFinishDecodeFirstFrame();
       return;
     }
 
     case DECODER_STATE_BUFFERING:
     case DECODER_STATE_DECODING: {
-      Push(video.forget());
+      Push(video);
       // If the requested video sample was slow to arrive, increase the
       // amount of audio we buffer to ensure that we don't run out of audio.
       // TODO: Detect when we're truly async, and don't do this if so, as
       // it's not necessary.
       TimeDuration decodeTime = TimeStamp::Now() - mVideoDecodeStartTime;
       if (THRESHOLD_FACTOR * DurationToUsecs(decodeTime) > mLowAudioThresholdUsecs &&
           !HasLowUndecodedData())
       {
@@ -957,21 +958,21 @@ MediaDecoderStateMachine::OnVideoDecoded
           // seek and decode to the seek target. This is not conformant to the
           // spec, fastSeek should always be fast, but until we get the time to
           // change all Readers to seek to the keyframe after the currentTime
           // in this case, we'll just decode forward. Bug 1026330.
           mCurrentSeekTarget.mType = SeekTarget::Accurate;
         }
         if (mCurrentSeekTarget.mType == SeekTarget::PrevSyncPoint) {
           // Non-precise seek; we can stop the seek at the first sample.
-          VideoQueue().Push(video.forget());
+          VideoQueue().Push(video);
         } else {
           // We're doing an accurate seek. We still need to discard
           // MediaData up to the one containing exact seek target.
-          if (NS_FAILED(DropVideoUpToSeekTarget(video.forget()))) {
+          if (NS_FAILED(DropVideoUpToSeekTarget(video))) {
             DecodeError();
             return;
           }
         }
       }
       CheckIfSeekComplete();
       return;
     }
@@ -2790,32 +2791,32 @@ void MediaDecoderStateMachine::AdvanceFr
   }
 
   const int64_t clock_time = GetClock();
   TimeStamp nowTime = TimeStamp::Now();
   // Skip frames up to the frame at the playback position, and figure out
   // the time remaining until it's time to display the next frame.
   int64_t remainingTime = AUDIO_DURATION_USECS;
   NS_ASSERTION(clock_time >= mStartTime, "Should have positive clock time.");
-  nsAutoPtr<VideoData> currentFrame;
+  nsRefPtr<VideoData> currentFrame;
   if (VideoQueue().GetSize() > 0) {
     VideoData* frame = VideoQueue().PeekFront();
 #ifdef PR_LOGGING
     int32_t droppedFrames = 0;
 #endif
     while (mScheduler->IsRealTime() || clock_time >= frame->mTime) {
       mVideoFrameEndTime = frame->GetEndTime();
 #ifdef PR_LOGGING
       if (currentFrame) {
         VERBOSE_LOG("discarding video frame mTime=%lld clock_time=%lld (%d so far)",
                     currentFrame->mTime, clock_time, ++droppedFrames);
       }
 #endif
       currentFrame = frame;
-      VideoQueue().PopFront();
+      nsRefPtr<VideoData> releaseMe = VideoQueue().PopFront();
       // Notify the decode thread that the video queue's buffers may have
       // free'd up space for more frames.
       mDecoder->GetReentrantMonitor().NotifyAll();
       OnPlaybackOffsetUpdate(frame->mOffset);
       if (VideoQueue().GetSize() == 0)
         break;
       frame = VideoQueue().PeekFront();
     }
@@ -2831,17 +2832,17 @@ void MediaDecoderStateMachine::AdvanceFr
   // Check to see if we don't have enough data to play up to the next frame.
   // If we don't, switch to buffering mode.
   if (mState == DECODER_STATE_DECODING &&
       mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING &&
       HasLowDecodedData(remainingTime + EXHAUSTED_DATA_MARGIN_USECS) &&
       mDecoder->IsExpectingMoreData()) {
     if (JustExitedQuickBuffering() || HasLowUndecodedData()) {
       if (currentFrame) {
-        VideoQueue().PushFront(currentFrame.forget());
+        VideoQueue().PushFront(currentFrame);
       }
       StartBuffering();
       // Don't go straight back to the state machine loop since that might
       // cause us to start decoding again and we could flip-flop between
       // decoding and quick-buffering.
       ScheduleStateMachine(USECS_PER_S);
       return;
     }
@@ -2901,32 +2902,32 @@ void MediaDecoderStateMachine::AdvanceFr
   UpdateReadyState();
 
   ScheduleStateMachine(remainingTime / mPlaybackRate);
 }
 
 nsresult
 MediaDecoderStateMachine::DropVideoUpToSeekTarget(VideoData* aSample)
 {
-  nsAutoPtr<VideoData> video(aSample);
+  nsRefPtr<VideoData> video(aSample);
   MOZ_ASSERT(video);
   DECODER_LOG("DropVideoUpToSeekTarget() frame [%lld, %lld] dup=%d",
               video->mTime, video->GetEndTime(), video->mDuplicate);
   const int64_t target = mCurrentSeekTarget.mTime;
 
   // Duplicate handling: if we're dropping frames up the seek target, we must
   // be wary of Theora duplicate frames. They don't have an image, so if the
   // target frame is in a run of duplicates, we won't have an image to draw
   // after the seek. So store the last frame encountered while dropping, and
   // copy its Image forward onto duplicate frames, so that every frame has
   // an Image.
   if (video->mDuplicate &&
       mFirstVideoFrameAfterSeek &&
       !mFirstVideoFrameAfterSeek->mDuplicate) {
-    VideoData* temp =
+    nsRefPtr<VideoData> temp =
       VideoData::ShallowCopyUpdateTimestampAndDuration(mFirstVideoFrameAfterSeek,
                                                        video->mTime,
                                                        video->mDuration);
     video = temp;
   }
 
   // If the frame end time is less than the seek target, we won't want
   // to display this frame after the seek, so discard it.
@@ -2934,34 +2935,34 @@ MediaDecoderStateMachine::DropVideoUpToS
     DECODER_LOG("DropVideoUpToSeekTarget() pop video frame [%lld, %lld] target=%lld",
                 video->mTime, video->GetEndTime(), target);
     mFirstVideoFrameAfterSeek = video;
   } else {
     if (target >= video->mTime && video->GetEndTime() >= target) {
       // The seek target lies inside this frame's time slice. Adjust the frame's
       // start time to match the seek target. We do this by replacing the
       // first frame with a shallow copy which has the new timestamp.
-      VideoData* temp = VideoData::ShallowCopyUpdateTimestamp(video, target);
+      nsRefPtr<VideoData> temp = VideoData::ShallowCopyUpdateTimestamp(video, target);
       video = temp;
     }
     mFirstVideoFrameAfterSeek = nullptr;
 
     DECODER_LOG("DropVideoUpToSeekTarget() found video frame [%lld, %lld] containing target=%lld",
                 video->mTime, video->GetEndTime(), target);
 
-    VideoQueue().PushFront(video.forget());
-
+    VideoQueue().PushFront(video);
   }
+
   return NS_OK;
 }
 
 nsresult
 MediaDecoderStateMachine::DropAudioUpToSeekTarget(AudioData* aSample)
 {
-  nsAutoPtr<AudioData> audio(aSample);
+  nsRefPtr<AudioData> audio(aSample);
   MOZ_ASSERT(audio &&
              mCurrentSeekTarget.IsValid() &&
              mCurrentSeekTarget.mType == SeekTarget::Accurate);
 
   CheckedInt64 startFrame = UsecsToFrames(audio->mTime,
                                           mInfo.mAudio.mRate);
   CheckedInt64 targetFrame = UsecsToFrames(mCurrentSeekTarget.mTime,
                                            mInfo.mAudio.mRate);
@@ -2977,17 +2978,17 @@ MediaDecoderStateMachine::DropAudioUpToS
     // The seek target doesn't lie in the audio block just after the last
     // audio frames we've seen which were before the seek target. This
     // could have been the first audio data we've seen after seek, i.e. the
     // seek terminated after the seek target in the audio stream. Just
     // abort the audio decode-to-target, the state machine will play
     // silence to cover the gap. Typically this happens in poorly muxed
     // files.
     DECODER_WARN("Audio not synced after seek, maybe a poorly muxed file?");
-    AudioQueue().Push(audio.forget());
+    AudioQueue().Push(audio);
     return NS_OK;
   }
 
   // The seek target lies somewhere in this AudioData's frames, strip off
   // any frames which lie before the seek target, so we'll begin playback
   // exactly at the seek target.
   NS_ASSERTION(targetFrame.value() >= startFrame.value(),
                "Target must at or be after data start.");
@@ -3006,24 +3007,24 @@ MediaDecoderStateMachine::DropAudioUpToS
   nsAutoArrayPtr<AudioDataValue> audioData(new AudioDataValue[frames * channels]);
   memcpy(audioData.get(),
          audio->mAudioData.get() + (framesToPrune * channels),
          frames * channels * sizeof(AudioDataValue));
   CheckedInt64 duration = FramesToUsecs(frames, mInfo.mAudio.mRate);
   if (!duration.isValid()) {
     return NS_ERROR_FAILURE;
   }
-  nsAutoPtr<AudioData> data(new AudioData(audio->mOffset,
-                                          mCurrentSeekTarget.mTime,
-                                          duration.value(),
-                                          frames,
-                                          audioData.forget(),
-                                          channels,
-                                          audio->mRate));
-  AudioQueue().PushFront(data.forget());
+  nsRefPtr<AudioData> data(new AudioData(audio->mOffset,
+                                         mCurrentSeekTarget.mTime,
+                                         duration.value(),
+                                         frames,
+                                         audioData.forget(),
+                                         channels,
+                                         audio->mRate));
+  AudioQueue().PushFront(data);
 
   return NS_OK;
 }
 
 void MediaDecoderStateMachine::SetStartTime(int64_t aStartTimeUsecs)
 {
   AssertCurrentThreadInMonitor();
   DECODER_LOG("SetStartTime(%lld)", aStartTimeUsecs);
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -872,17 +872,17 @@ protected:
   // samples we must consume before are considered to be finished prerolling.
   uint32_t mAudioPrerollUsecs;
   uint32_t mVideoPrerollFrames;
 
   // This temporarily stores the first frame we decode after we seek.
   // This is so that if we hit end of stream while we're decoding to reach
   // the seek target, we will still have a frame that we can display as the
   // last frame in the media.
-  nsAutoPtr<VideoData> mFirstVideoFrameAfterSeek;
+  nsRefPtr<VideoData> mFirstVideoFrameAfterSeek;
 
   // When we start decoding (either for the first time, or after a pause)
   // we may be low on decoded data. We don't want our "low data" logic to
   // kick in and decide that we're low on decoded data because the download
   // can't keep up with the decode, and cause us to pause playback. So we
   // have a "preroll" stage, where we ignore the results of our "low data"
   // logic during the first few frames of our decode. This occurs during
   // playback. The flags below are true when the corresponding stream is
--- a/dom/media/MediaQueue.h
+++ b/dom/media/MediaQueue.h
@@ -13,17 +13,17 @@
 #include "MediaTaskQueue.h"
 
 namespace mozilla {
 
 // Thread and type safe wrapper around nsDeque.
 template <class T>
 class MediaQueueDeallocator : public nsDequeFunctor {
   virtual void* operator() (void* aObject) {
-    delete static_cast<T*>(aObject);
+    nsRefPtr<T> releaseMe = dont_AddRef(static_cast<T*>(aObject));
     return nullptr;
   }
 };
 
 template <class T> class MediaQueue : private nsDeque {
  public:
 
    MediaQueue()
@@ -39,32 +39,34 @@ template <class T> class MediaQueue : pr
   inline int32_t GetSize() {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     return nsDeque::GetSize();
   }
 
   inline void Push(T* aItem) {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     MOZ_ASSERT(aItem);
+    NS_ADDREF(aItem);
     nsDeque::Push(aItem);
   }
 
   inline void PushFront(T* aItem) {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     MOZ_ASSERT(aItem);
+    NS_ADDREF(aItem);
     nsDeque::PushFront(aItem);
   }
 
-  inline T* PopFront() {
+  inline already_AddRefed<T> PopFront() {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-    T* rv = static_cast<T*>(nsDeque::PopFront());
+    nsRefPtr<T> rv = dont_AddRef(static_cast<T*>(nsDeque::PopFront()));
     if (rv) {
       NotifyPopListeners();
     }
-    return rv;
+    return rv.forget();
   }
 
   inline T* Peek() {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     return static_cast<T*>(nsDeque::Peek());
   }
 
   inline T* PeekFront() {
@@ -75,18 +77,17 @@ template <class T> class MediaQueue : pr
   inline void Empty() {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     nsDeque::Empty();
   }
 
   void Reset() {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     while (GetSize() > 0) {
-      T* x = PopFront();
-      delete x;
+      nsRefPtr<T> x = PopFront();
     }
     mEndOfStream = false;
   }
 
   bool AtEndOfStream() {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     return GetSize() == 0 && mEndOfStream;
   }
@@ -118,30 +119,31 @@ template <class T> class MediaQueue : pr
 
   void LockedForEach(nsDequeFunctor& aFunctor) const {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     ForEach(aFunctor);
   }
 
   // Extracts elements from the queue into aResult, in order.
   // Elements whose start time is before aTime are ignored.
-  void GetElementsAfter(int64_t aTime, nsTArray<T*>* aResult) {
+  void GetElementsAfter(int64_t aTime, nsTArray<nsRefPtr<T>>* aResult) {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     if (!GetSize())
       return;
     int32_t i;
     for (i = GetSize() - 1; i > 0; --i) {
       T* v = static_cast<T*>(ObjectAt(i));
       if (v->GetEndTime() < aTime)
         break;
     }
     // Elements less than i have a end time before aTime. It's also possible
     // that the element at i has a end time before aTime, but that's OK.
     for (; i < GetSize(); ++i) {
-      aResult->AppendElement(static_cast<T*>(ObjectAt(i)));
+      nsRefPtr<T> elem = static_cast<T*>(ObjectAt(i));
+      aResult->AppendElement(elem);
     }
   }
 
   uint32_t FrameCount() {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     uint32_t frames = 0;
     for (int32_t i = 0; i < GetSize(); ++i) {
       T* v = static_cast<T*>(ObjectAt(i));
--- a/dom/media/android/AndroidMediaReader.cpp
+++ b/dom/media/android/AndroidMediaReader.cpp
@@ -139,18 +139,19 @@ bool AndroidMediaReader::DecodeVideoFram
     if (!mPlugin->ReadVideo(mPlugin, &frame, mVideoSeekTimeUs, &bufferCallback)) {
       // We reached the end of the video stream. If we have a buffered
       // video frame, push it the video queue using the total duration
       // of the video as the end time.
       if (mLastVideoFrame) {
         int64_t durationUs;
         mPlugin->GetDuration(mPlugin, &durationUs);
         durationUs = std::max<int64_t>(durationUs - mLastVideoFrame->mTime, 0);
-        mVideoQueue.Push(VideoData::ShallowCopyUpdateDuration(mLastVideoFrame,
-                                                              durationUs));
+        nsRefPtr<VideoData> data = VideoData::ShallowCopyUpdateDuration(mLastVideoFrame,
+                                                                        durationUs);
+        mVideoQueue.Push(data);
         mLastVideoFrame = nullptr;
       }
       return false;
     }
     mVideoSeekTimeUs = -1;
 
     if (aKeyframeSkip) {
       // Disable keyframe skipping for now as
@@ -167,17 +168,17 @@ bool AndroidMediaReader::DecodeVideoFram
 
     if (frame.mSize == 0)
       return true;
 
     currentImage = bufferCallback.GetImage();
     int64_t pos = mDecoder->GetResource()->Tell();
     IntRect picture = ToIntRect(mPicture);
 
-    nsAutoPtr<VideoData> v;
+    nsRefPtr<VideoData> v;
     if (currentImage) {
       gfx::IntSize frameSize = currentImage->GetSize();
       if (frameSize.width != mInitialFrame.width ||
           frameSize.height != mInitialFrame.height) {
         // Frame size is different from what the container reports. This is legal,
         // and we will preserve the ratio of the crop rectangle as it
         // was reported relative to the picture size reported by the container.
         picture.x = (mPicture.x * frameSize.width) / mInitialFrame.width;
@@ -268,19 +269,18 @@ bool AndroidMediaReader::DecodeVideoFram
     // We have the start time of the next frame, so we can push the previous
     // frame into the queue, except if the end time is below the threshold,
     // in which case it wouldn't be displayed anyway.
     if (mLastVideoFrame->GetEndTime() < aTimeThreshold) {
       mLastVideoFrame = nullptr;
       continue;
     }
 
-    mVideoQueue.Push(mLastVideoFrame.forget());
-
     // Buffer the current frame we just decoded.
+    mVideoQueue.Push(mLastVideoFrame);
     mLastVideoFrame = v;
 
     break;
   }
 
   return true;
 }
 
--- a/dom/media/android/AndroidMediaReader.h
+++ b/dom/media/android/AndroidMediaReader.h
@@ -34,17 +34,17 @@ class AndroidMediaReader : public MediaD
   nsCString mType;
   MPAPI::Decoder *mPlugin;
   bool mHasAudio;
   bool mHasVideo;
   nsIntRect mPicture;
   nsIntSize mInitialFrame;
   int64_t mVideoSeekTimeUs;
   int64_t mAudioSeekTimeUs;
-  nsAutoPtr<VideoData> mLastVideoFrame;
+  nsRefPtr<VideoData> mLastVideoFrame;
 public:
   AndroidMediaReader(AbstractMediaDecoder* aDecoder,
                      const nsACString& aContentType);
 
   virtual nsresult Init(MediaDecoderReader* aCloneDonor);
   virtual nsresult ResetDecode();
 
   virtual bool DecodeAudioData();
--- a/dom/media/fmp4/BlankDecoderModule.cpp
+++ b/dom/media/fmp4/BlankDecoderModule.cpp
@@ -46,19 +46,20 @@ public:
                 BlankMediaDataCreator* aCreator)
       : mSample(aSample)
       , mCreator(aCreator)
       , mCallback(aCallback)
     {
     }
     NS_IMETHOD Run() MOZ_OVERRIDE
     {
-      mCallback->Output(mCreator->Create(mSample->composition_timestamp,
-                                         mSample->duration,
-                                         mSample->byte_offset));
+      nsRefPtr<MediaData> data = mCreator->Create(mSample->composition_timestamp,
+                                                  mSample->duration,
+                                                  mSample->byte_offset);
+      mCallback->Output(data);
       return NS_OK;
     }
   private:
     nsAutoPtr<mp4_demuxer::MP4Sample> mSample;
     BlankMediaDataCreator* mCreator;
     MediaDataDecoderCallback* mCallback;
   };
 
@@ -79,17 +80,16 @@ public:
 
   virtual nsresult Drain() MOZ_OVERRIDE {
     mCallback->DrainComplete();
     return NS_OK;
   }
 
 private:
   nsAutoPtr<BlankMediaDataCreator> mCreator;
-  nsAutoPtr<MediaData> mOutput;
   RefPtr<MediaTaskQueue> mTaskQueue;
   MediaDataDecoderCallback* mCallback;
 };
 
 class BlankVideoDataCreator {
 public:
   BlankVideoDataCreator(uint32_t aFrameWidth,
                         uint32_t aFrameHeight,
@@ -97,19 +97,18 @@ public:
     : mFrameWidth(aFrameWidth)
     , mFrameHeight(aFrameHeight)
     , mImageContainer(aImageContainer)
   {
     mInfo.mDisplay = nsIntSize(mFrameWidth, mFrameHeight);
     mPicture = gfx::IntRect(0, 0, mFrameWidth, mFrameHeight);
   }
 
-  MediaData* Create(Microseconds aDTS,
-                    Microseconds aDuration,
-                    int64_t aOffsetInStream)
+  already_AddRefed<MediaData>
+  Create(Microseconds aDTS, Microseconds aDuration, int64_t aOffsetInStream)
   {
     // Create a fake YUV buffer in a 420 format. That is, an 8bpp Y plane,
     // with a U and V plane that are half the size of the Y plane, i.e 8 bit,
     // 2x2 subsampled. Have the data pointers of each frame point to the
     // first plane, they'll always be zero'd memory anyway.
     nsAutoArrayPtr<uint8_t> frame(new uint8_t[mFrameWidth * mFrameHeight]);
     memset(frame, 0, mFrameWidth * mFrameHeight);
     VideoData::YCbCrBuffer buffer;
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -619,17 +619,16 @@ MP4Reader::Output(TrackType aTrack, Medi
     Error(aTrack);
     return;
   }
 
   DecoderData& data = GetDecoderData(aTrack);
   // Don't accept output while we're flushing.
   MonitorAutoLock mon(data.mMonitor);
   if (data.mIsFlushing) {
-    delete aSample;
     LOG("MP4Reader produced output while flushing, discarding.");
     mon.NotifyAll();
     return;
   }
 
   switch (aTrack) {
     case kAudio: {
       MOZ_ASSERT(aSample->mType == MediaData::AUDIO_DATA);
--- a/dom/media/fmp4/PlatformDecoderModule.h
+++ b/dom/media/fmp4/PlatformDecoderModule.h
@@ -136,18 +136,17 @@ protected:
 };
 
 // A callback used by MediaDataDecoder to return output/errors to the
 // MP4Reader. Implementation is threadsafe, and can be called on any thread.
 class MediaDataDecoderCallback {
 public:
   virtual ~MediaDataDecoderCallback() {}
 
-  // Called by MediaDataDecoder when a sample has been decoded. Callee is
-  // responsibile for deleting aData.
+  // Called by MediaDataDecoder when a sample has been decoded.
   virtual void Output(MediaData* aData) = 0;
 
   // Denotes an error in the decoding process. The reader will stop calling
   // the decoder.
   virtual void Error() = 0;
 
   // Denotes that the last input sample has been inserted into the decoder,
   // and no more output can be produced unless more input is sent.
--- a/dom/media/fmp4/android/AndroidDecoderModule.cpp
+++ b/dom/media/fmp4/android/AndroidDecoderModule.cpp
@@ -74,24 +74,25 @@ public:
     layers::SurfaceTextureImage::Data data;
     data.mSurfTex = mSurfaceTexture.get();
     data.mSize = gfx::IntSize(mConfig.display_width, mConfig.display_height);
     data.mInverted = true;
 
     layers::SurfaceTextureImage* typedImg = static_cast<layers::SurfaceTextureImage*>(img.get());
     typedImg->SetData(data);
 
-    mCallback->Output(VideoData::CreateFromImage(videoInfo, mImageContainer, aInfo->getOffset(),
-                                                 aInfo->getPresentationTimeUs(),
-                                                 aDuration,
-                                                 img, isSync,
-                                                 aInfo->getPresentationTimeUs(),
-                                                 gfx::IntRect(0, 0,
-                                                   mConfig.display_width,
-                                                   mConfig.display_height)));
+    nsRefPtr<VideoData> v = VideoData::CreateFromImage(videoInfo, mImageContainer, aInfo->getOffset(),
+                                                       aInfo->getPresentationTimeUs(),
+                                                       aDuration,
+                                                       img, isSync,
+                                                       aInfo->getPresentationTimeUs(),
+                                                       gfx::IntRect(0, 0,
+                                                         mConfig.display_width,
+                                                         mConfig.display_height));
+    mCallback->Output(v);
     return NS_OK;
   }
 
 protected:
   layers::ImageContainer* mImageContainer;
   const mp4_demuxer::VideoDecoderConfig& mConfig;
   RefPtr<AndroidSurfaceTexture> mSurfaceTexture;
 };
--- a/dom/media/fmp4/apple/AppleVDADecoder.cpp
+++ b/dom/media/fmp4/apple/AppleVDADecoder.cpp
@@ -209,17 +209,17 @@ AppleVDADecoder::DrainReorderedFrames()
     mCallback->Output(mReorderQueue.Pop());
   }
 }
 
 void
 AppleVDADecoder::ClearReorderedFrames()
 {
   while (!mReorderQueue.IsEmpty()) {
-    delete mReorderQueue.Pop();
+    mReorderQueue.Pop();
   }
 }
 
 // Copy and return a decoded frame.
 nsresult
 AppleVDADecoder::OutputFrame(CVPixelBufferRef aImage,
                              nsAutoPtr<AppleVDADecoder::AppleFrameRef> aFrameRef)
 {
@@ -245,17 +245,17 @@ AppleVDADecoder::OutputFrame(CVPixelBuff
                                       mConfig.display_height);
 
   nsRefPtr<layers::Image> image =
     mImageContainer->CreateImage(ImageFormat::MAC_IOSURFACE);
   layers::MacIOSurfaceImage* videoImage =
     static_cast<layers::MacIOSurfaceImage*>(image.get());
   videoImage->SetSurface(macSurface);
 
-  nsAutoPtr<VideoData> data;
+  nsRefPtr<VideoData> data;
   data = VideoData::CreateFromImage(info,
                                     mImageContainer,
                                     aFrameRef->byte_offset,
                                     aFrameRef->composition_timestamp,
                                     aFrameRef->duration, image.forget(),
                                     aFrameRef->is_sync_point,
                                     aFrameRef->decode_timestamp,
                                     visible);
@@ -263,20 +263,20 @@ AppleVDADecoder::OutputFrame(CVPixelBuff
   if (!data) {
     NS_ERROR("Couldn't create VideoData for frame");
     mCallback->Error();
     return NS_ERROR_FAILURE;
   }
 
   // Frames come out in DTS order but we need to output them
   // in composition order.
-  mReorderQueue.Push(data.forget());
+  mReorderQueue.Push(data);
   // Assume a frame with a PTS <= current DTS is ready.
   while (mReorderQueue.Length() > 0) {
-    VideoData* readyData = mReorderQueue.Pop();
+    nsRefPtr<VideoData> readyData = mReorderQueue.Pop();
     if (readyData->mTime <= aFrameRef->decode_timestamp) {
       LOG("returning queued frame with pts %lld", readyData->mTime);
       mCallback->Output(readyData);
     } else {
       LOG("requeued frame with pts %lld > %lld",
           readyData->mTime, aFrameRef->decode_timestamp);
       mReorderQueue.Push(readyData);
       break;
--- a/dom/media/fmp4/apple/ReorderQueue.h
+++ b/dom/media/fmp4/apple/ReorderQueue.h
@@ -17,13 +17,13 @@ namespace mozilla {
 struct ReorderQueueComparator
 {
   bool LessThan(VideoData* const& a, VideoData* const& b) const
   {
     return a->mTime < b->mTime;
   }
 };
 
-typedef nsTPriorityQueue<VideoData*, ReorderQueueComparator> ReorderQueue;
+typedef nsTPriorityQueue<nsRefPtr<VideoData>, ReorderQueueComparator> ReorderQueue;
 
 } // namespace mozilla
 
 #endif // mozilla_ReorderQueue_h
--- a/dom/media/fmp4/eme/EMEAudioDecoder.cpp
+++ b/dom/media/fmp4/eme/EMEAudioDecoder.cpp
@@ -170,30 +170,30 @@ EMEAudioDecoder::Decoded(const nsTArray<
 
   auto duration = FramesToUsecs(numFrames, aRate);
   if (!duration.isValid()) {
     NS_WARNING("Invalid duration on audio samples");
     mCallback->Error();
     return;
   }
 
-  nsAutoPtr<AudioData> audio(new AudioData(mStreamOffset,
-                                           timestamp.value(),
-                                           duration.value(),
-                                           numFrames,
-                                           audioData.forget(),
-                                           aChannels,
-                                           aRate));
+  nsRefPtr<AudioData> audio(new AudioData(mStreamOffset,
+                                          timestamp.value(),
+                                          duration.value(),
+                                          numFrames,
+                                          audioData.forget(),
+                                          aChannels,
+                                          aRate));
 
   #ifdef LOG_SAMPLE_DECODE
   LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u",
       timestamp, duration, currentLength);
   #endif
 
-  mCallback->Output(audio.forget());
+  mCallback->Output(audio);
 }
 
 void
 EMEAudioDecoder::InputDataExhausted()
 {
   MOZ_ASSERT(IsOnGMPThread());
   mCallback->InputExhausted();
 }
--- a/dom/media/fmp4/eme/EMEH264Decoder.cpp
+++ b/dom/media/fmp4/eme/EMEH264Decoder.cpp
@@ -152,25 +152,25 @@ EMEH264Decoder::Decoded(GMPVideoi420Fram
   b.mPlanes[2].mData = aDecodedFrame->Buffer(kGMPVPlane);
   b.mPlanes[2].mStride = aDecodedFrame->Stride(kGMPVPlane);
   b.mPlanes[2].mHeight = height / 2;
   b.mPlanes[2].mWidth = width / 2;
   b.mPlanes[2].mOffset = 0;
   b.mPlanes[2].mSkip = 0;
 
   gfx::IntRect pictureRegion(0, 0, width, height);
-  VideoData *v = VideoData::Create(mVideoInfo,
-                                   mImageContainer,
-                                   mLastStreamOffset,
-                                   aDecodedFrame->Timestamp(),
-                                   aDecodedFrame->Duration(),
-                                   b,
-                                   false,
-                                   -1,
-                                   pictureRegion);
+  nsRefPtr<VideoData> v = VideoData::Create(mVideoInfo,
+                                            mImageContainer,
+                                            mLastStreamOffset,
+                                            aDecodedFrame->Timestamp(),
+                                            aDecodedFrame->Duration(),
+                                            b,
+                                            false,
+                                            -1,
+                                            pictureRegion);
   aDecodedFrame->Destroy();
   mCallback->Output(v);
 }
 
 void
 EMEH264Decoder::ReceivedDecodedReferenceFrame(const uint64_t aPictureId)
 {
   // Ignore.
--- a/dom/media/fmp4/ffmpeg/FFmpegH264Decoder.cpp
+++ b/dom/media/fmp4/ffmpeg/FFmpegH264Decoder.cpp
@@ -98,25 +98,25 @@ FFmpegH264Decoder<LIBAV_VER>::DoDecodeFr
     b.mPlanes[1].mOffset = b.mPlanes[1].mSkip = 0;
 
     b.mPlanes[2].mData = mFrame->data[2];
     b.mPlanes[2].mStride = mFrame->linesize[2];
     b.mPlanes[2].mHeight = (mFrame->height + 1) >> 1;
     b.mPlanes[2].mWidth = (mFrame->width + 1) >> 1;
     b.mPlanes[2].mOffset = b.mPlanes[2].mSkip = 0;
 
-    VideoData *v = VideoData::Create(info,
-                                     mImageContainer,
-                                     aSample->byte_offset,
-                                     mFrame->pkt_pts,
-                                     aSample->duration,
-                                     b,
-                                     aSample->is_sync_point,
-                                     -1,
-                                     gfx::IntRect(0, 0, mCodecContext->width, mCodecContext->height));
+    nsRefPtr<VideoData> v = VideoData::Create(info,
+                                              mImageContainer,
+                                              aSample->byte_offset,
+                                              mFrame->pkt_pts,
+                                              aSample->duration,
+                                              b,
+                                              aSample->is_sync_point,
+                                              -1,
+                                              gfx::IntRect(0, 0, mCodecContext->width, mCodecContext->height));
     if (!v) {
       NS_WARNING("image allocation error.");
       mCallback->Error();
       return DecodeResult::DECODE_ERROR;
     }
     mCallback->Output(v);
     return DecodeResult::DECODE_FRAME;
   }
--- a/dom/media/fmp4/gonk/GonkAudioDecoderManager.cpp
+++ b/dom/media/fmp4/gonk/GonkAudioDecoderManager.cpp
@@ -124,40 +124,41 @@ GonkAudioDecoderManager::CreateAudioData
   nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[size/2]);
   memcpy(buffer.get(), data+dataOffset, size);
   uint32_t frames = size / (2 * mAudioChannels);
 
   CheckedInt64 duration = FramesToUsecs(frames, mAudioRate);
   if (!duration.isValid()) {
     return NS_ERROR_UNEXPECTED;
   }
-  *v = new AudioData(aStreamOffset,
-                     timeUs,
-                     duration.value(),
-                     frames,
-                     buffer.forget(),
-                     mAudioChannels,
-                     mAudioRate);
+  nsRefPtr<AudioData> audioData = new AudioData(aStreamOffset,
+                                                timeUs,
+                                                duration.value(),
+                                                frames,
+                                                buffer.forget(),
+                                                mAudioChannels,
+                                                mAudioRate);
   ReleaseAudioBuffer();
+  audioData.forget(v);
   return NS_OK;
 }
 
 nsresult
 GonkAudioDecoderManager::Output(int64_t aStreamOffset,
-                                nsAutoPtr<MediaData>& aOutData)
+                                nsRefPtr<MediaData>& aOutData)
 {
   aOutData = nullptr;
   status_t err;
   err = mDecoder->Output(&mAudioBuffer, READ_OUTPUT_BUFFER_TIMEOUT_US);
 
   switch (err) {
     case OK:
     {
-      AudioData* data = nullptr;
-      nsresult rv = CreateAudioData(aStreamOffset, &data);
+      nsRefPtr<AudioData> data;
+      nsresult rv = CreateAudioData(aStreamOffset, getter_AddRefs(data));
       if (rv == NS_ERROR_NOT_AVAILABLE) {
         // Decoder outputs an empty video buffer, try again
         return NS_ERROR_NOT_AVAILABLE;
       } else if (rv != NS_OK || data == nullptr) {
         return NS_ERROR_UNEXPECTED;
       }
       aOutData = data;
       return NS_OK;
@@ -171,18 +172,18 @@ GonkAudioDecoderManager::Output(int64_t 
     }
     case -EAGAIN:
     {
       return NS_ERROR_NOT_AVAILABLE;
     }
     case android::ERROR_END_OF_STREAM:
     {
       ALOG("Got EOS frame!");
-      AudioData* data = nullptr;
-      nsresult rv = CreateAudioData(aStreamOffset, &data);
+      nsRefPtr<AudioData> data;
+      nsresult rv = CreateAudioData(aStreamOffset, getter_AddRefs(data));
       if (rv == NS_ERROR_NOT_AVAILABLE) {
         // For EOS, no need to do any thing.
         return NS_ERROR_ABORT;
       } else if (rv != NS_OK || data == nullptr) {
         ALOG("Failed to create audio data!");
         return NS_ERROR_UNEXPECTED;
       }
       aOutData = data;
--- a/dom/media/fmp4/gonk/GonkAudioDecoderManager.h
+++ b/dom/media/fmp4/gonk/GonkAudioDecoderManager.h
@@ -26,17 +26,17 @@ public:
   GonkAudioDecoderManager(const mp4_demuxer::AudioDecoderConfig& aConfig);
   ~GonkAudioDecoderManager();
 
   virtual android::sp<MediaCodecProxy> Init(MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
 
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
 
   virtual nsresult Output(int64_t aStreamOffset,
-                          nsAutoPtr<MediaData>& aOutput) MOZ_OVERRIDE;
+                          nsRefPtr<MediaData>& aOutput) MOZ_OVERRIDE;
 private:
 
   nsresult CreateAudioData(int64_t aStreamOffset,
                               AudioData** aOutData);
 
   void ReleaseAudioBuffer();
   // MediaCodedc's wrapper that performs the decoding.
   android::sp<MediaCodecProxy> mDecoder;
--- a/dom/media/fmp4/gonk/GonkMediaDataDecoder.cpp
+++ b/dom/media/fmp4/gonk/GonkMediaDataDecoder.cpp
@@ -84,22 +84,22 @@ GonkMediaDataDecoder::ProcessDecode(mp4_
     mLastStreamOffset = aSample->byte_offset;
   }
   ProcessOutput();
 }
 
 void
 GonkMediaDataDecoder::ProcessOutput()
 {
-  nsAutoPtr<MediaData> output;
+  nsRefPtr<MediaData> output;
   nsresult rv;
   while (true && !mDrainComplete) {
     rv = mManager->Output(mLastStreamOffset, output);
     if (rv == NS_OK) {
-      mCallback->Output(output.forget());
+      mCallback->Output(output);
       continue;
     } else if (rv == NS_ERROR_NOT_AVAILABLE && mSignaledEOS) {
       // Try to get more frames before getting EOS frame
       continue;
     }
     else {
       break;
     }
@@ -109,18 +109,18 @@ GonkMediaDataDecoder::ProcessOutput()
     mCallback->InputExhausted();
     return;
   }
   if (rv != NS_OK) {
     NS_WARNING("GonkMediaDataDecoder failed to output data");
     ALOG("Failed to output data");
     // GonkDecoderManangers report NS_ERROR_ABORT when EOS is reached.
     if (rv == NS_ERROR_ABORT) {
-      if (output.get() != nullptr) {
-        mCallback->Output(output.forget());
+      if (output) {
+        mCallback->Output(output);
       }
       mCallback->DrainComplete();
       mSignaledEOS = false;
       mDrainComplete = true;
       return;
     }
     mCallback->Error();
   }
--- a/dom/media/fmp4/gonk/GonkMediaDataDecoder.h
+++ b/dom/media/fmp4/gonk/GonkMediaDataDecoder.h
@@ -27,17 +27,17 @@ public:
 
   // Produces decoded output, it blocks until output can be produced or a timeout
   // is expired or until EOS. Returns NS_OK on success, or NS_ERROR_NOT_AVAILABLE
   // if there's not enough data to produce more output. If this returns a failure
   // code other than NS_ERROR_NOT_AVAILABLE, an error will be reported to the
   // MP4Reader.
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) = 0;
   virtual nsresult Output(int64_t aStreamOffset,
-                          nsAutoPtr<MediaData>& aOutput) = 0;
+                          nsRefPtr<MediaData>& aOutput) = 0;
 
 };
 
 // Samples are decoded using the GonkDecoder (MediaCodec)
 // created by the GonkDecoderManager. This class implements
 // the higher-level logic that drives mapping the Gonk to the async
 // MediaDataDecoder interface. The specifics of decoding the exact stream
 // type are handled by GonkDecoderManager and the GonkDecoder it creates.
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
+++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
@@ -120,16 +120,17 @@ GonkVideoDecoderManager::Init(MediaDataD
 
   return mDecoder;
 }
 
 nsresult
 GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v)
 {
   *v = nullptr;
+  nsRefPtr<VideoData> data;
   int64_t timeUs;
   int32_t keyFrame;
 
   if (mVideoBuffer == nullptr) {
     ALOG("Video Buffer is not valid!");
     return NS_ERROR_UNEXPECTED;
   }
 
@@ -168,26 +169,25 @@ GonkVideoDecoderManager::CreateVideoData
     textureClient = mNativeWindow->getTextureClientFromBuffer(mVideoBuffer->graphicBuffer().get());
   }
 
   if (textureClient) {
     GrallocTextureClientOGL* grallocClient = static_cast<GrallocTextureClientOGL*>(textureClient.get());
     grallocClient->SetMediaBuffer(mVideoBuffer);
     textureClient->SetRecycleCallback(GonkVideoDecoderManager::RecycleCallback, this);
 
-    *v = VideoData::Create(mInfo.mVideo,
-                          mImageContainer,
-                          aStreamOffset,
-                          timeUs,
-                          1, // We don't know the duration.
-                          textureClient,
-                          keyFrame,
-                          -1,
-                          picture);
-
+    data = VideoData::Create(mInfo.mVideo,
+                             mImageContainer,
+                             aStreamOffset,
+                             timeUs,
+                             1, // We don't know the duration.
+                             textureClient,
+                             keyFrame,
+                             -1,
+                             picture);
   } else {
     if (!mVideoBuffer->data()) {
       ALOG("No data in Video Buffer!");
       return NS_ERROR_UNEXPECTED;
     }
     uint8_t *yuv420p_buffer = (uint8_t *)mVideoBuffer->data();
     int32_t stride = mFrameInfo.mStride;
     int32_t slice_height = mFrameInfo.mSliceHeight;
@@ -236,28 +236,30 @@ GonkVideoDecoderManager::CreateVideoData
 
     b.mPlanes[2].mData = yuv420p_v;
     b.mPlanes[2].mWidth =(mFrameInfo.mWidth + 1) / 2;
     b.mPlanes[2].mHeight = (mFrameInfo.mHeight + 1) / 2;
     b.mPlanes[2].mStride = (stride + 1) / 2;
     b.mPlanes[2].mOffset = 0;
     b.mPlanes[2].mSkip = 0;
 
-    *v = VideoData::Create(
+    data = VideoData::Create(
         mInfo.mVideo,
         mImageContainer,
         pos,
         timeUs,
         1, // We don't know the duration.
         b,
         keyFrame,
         -1,
         picture);
     ReleaseVideoBuffer();
   }
+
+  data.forget(v);
   return NS_OK;
 }
 
 bool
 GonkVideoDecoderManager::SetVideoFormat()
 {
   // read video metadata from MediaCodec
   sp<AMessage> codecFormat;
@@ -297,31 +299,31 @@ GonkVideoDecoderManager::SetVideoFormat(
   }
   ALOG("Fail to get output format");
   return false;
 }
 
 // Blocks until decoded sample is produced by the deoder.
 nsresult
 GonkVideoDecoderManager::Output(int64_t aStreamOffset,
-                                nsAutoPtr<MediaData>& aOutData)
+                                nsRefPtr<MediaData>& aOutData)
 {
   aOutData = nullptr;
   status_t err;
   if (mDecoder == nullptr) {
     ALOG("Decoder is not inited");
     return NS_ERROR_UNEXPECTED;
   }
   err = mDecoder->Output(&mVideoBuffer, READ_OUTPUT_BUFFER_TIMEOUT_US);
 
   switch (err) {
     case OK:
     {
-      VideoData* data = nullptr;
-      nsresult rv = CreateVideoData(aStreamOffset, &data);
+      nsRefPtr<VideoData> data;
+      nsresult rv = CreateVideoData(aStreamOffset, getter_AddRefs(data));
       if (rv == NS_ERROR_NOT_AVAILABLE) {
 	// Decoder outputs a empty video buffer, try again
         return NS_ERROR_NOT_AVAILABLE;
       } else if (rv != NS_OK || data == nullptr) {
         ALOG("Failed to create VideoData");
         return NS_ERROR_UNEXPECTED;
       }
       aOutData = data;
@@ -345,18 +347,18 @@ GonkVideoDecoderManager::Output(int64_t 
     }
     case -EAGAIN:
     {
       return NS_ERROR_NOT_AVAILABLE;
     }
     case android::ERROR_END_OF_STREAM:
     {
       ALOG("Got the EOS frame!");
-      VideoData* data = nullptr;
-      nsresult rv = CreateVideoData(aStreamOffset, &data);
+      nsRefPtr<VideoData> data;
+      nsresult rv = CreateVideoData(aStreamOffset, getter_AddRefs(data));
       if (rv == NS_ERROR_NOT_AVAILABLE) {
 	// For EOS, no need to do any thing.
         return NS_ERROR_ABORT;
       }
       if (rv != NS_OK || data == nullptr) {
         ALOG("Failed to create video data");
         return NS_ERROR_UNEXPECTED;
       }
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.h
+++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.h
@@ -43,17 +43,17 @@ public:
 
   ~GonkVideoDecoderManager();
 
   virtual android::sp<MediaCodecProxy> Init(MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
 
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
 
   virtual nsresult Output(int64_t aStreamOffset,
-                          nsAutoPtr<MediaData>& aOutput) MOZ_OVERRIDE;
+                          nsRefPtr<MediaData>& aOutput) MOZ_OVERRIDE;
 
   static void RecycleCallback(TextureClient* aClient, void* aClosure);
 private:
   struct FrameInfo
   {
     int32_t mWidth = 0;
     int32_t mHeight = 0;
     int32_t mStride = 0;
--- a/dom/media/fmp4/wmf/WMFAudioMFTManager.cpp
+++ b/dom/media/fmp4/wmf/WMFAudioMFTManager.cpp
@@ -187,17 +187,17 @@ WMFAudioMFTManager::UpdateOutputType()
   hr = type->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &mAudioChannels);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   return S_OK;
 }
 
 HRESULT
 WMFAudioMFTManager::Output(int64_t aStreamOffset,
-                           nsAutoPtr<MediaData>& aOutData)
+                           nsRefPtr<MediaData>& aOutData)
 {
   aOutData = nullptr;
   RefPtr<IMFSample> sample;
   HRESULT hr;
   while (true) {
     hr = mDecoder->Output(&sample);
     if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
       return hr;
--- a/dom/media/fmp4/wmf/WMFAudioMFTManager.h
+++ b/dom/media/fmp4/wmf/WMFAudioMFTManager.h
@@ -23,17 +23,17 @@ public:
   virtual TemporaryRef<MFTDecoder> Init() MOZ_OVERRIDE;
 
   virtual HRESULT Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
 
   // Note WMF's AAC decoder sometimes output negatively timestamped samples,
   // presumably they're the preroll samples, and we strip them. We may return
   // a null aOutput in this case.
   virtual HRESULT Output(int64_t aStreamOffset,
-                         nsAutoPtr<MediaData>& aOutput) MOZ_OVERRIDE;
+                         nsRefPtr<MediaData>& aOutput) MOZ_OVERRIDE;
 
   virtual void Shutdown() MOZ_OVERRIDE;
 
 private:
 
   HRESULT UpdateOutputType();
 
   // IMFTransform wrapper that performs the decoding.
--- a/dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp
+++ b/dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp
@@ -85,21 +85,21 @@ WMFMediaDataDecoder::ProcessDecode(mp4_d
   mLastStreamOffset = aSample->byte_offset;
 
   ProcessOutput();
 }
 
 void
 WMFMediaDataDecoder::ProcessOutput()
 {
-  nsAutoPtr<MediaData> output;
+  nsRefPtr<MediaData> output;
   HRESULT hr = S_OK;
   while (SUCCEEDED(hr = mMFTManager->Output(mLastStreamOffset, output)) &&
          output) {
-    mCallback->Output(output.forget());
+    mCallback->Output(output);
   }
   if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
     if (mTaskQueue->IsEmpty()) {
       mCallback->InputExhausted();
     }
   } else if (FAILED(hr)) {
     NS_WARNING("WMFMediaDataDecoder failed to output data");
     mCallback->Error();
--- a/dom/media/fmp4/wmf/WMFMediaDataDecoder.h
+++ b/dom/media/fmp4/wmf/WMFMediaDataDecoder.h
@@ -37,17 +37,17 @@ public:
 
   // Produces decoded output, if possible. Blocks until output can be produced,
   // or until no more is able to be produced.
   // Returns S_OK on success, or MF_E_TRANSFORM_NEED_MORE_INPUT if there's not
   // enough data to produce more output. If this returns a failure code other
   // than MF_E_TRANSFORM_NEED_MORE_INPUT, an error will be reported to the
   // MP4Reader.
   virtual HRESULT Output(int64_t aStreamOffset,
-                         nsAutoPtr<MediaData>& aOutput) = 0;
+                         nsRefPtr<MediaData>& aOutput) = 0;
 
   // Destroys all resources.
   virtual void Shutdown() = 0;
 };
 
 // Decodes audio and video using Windows Media Foundation. Samples are decoded
 // using the MFTDecoder created by the MFTManager. This class implements
 // the higher-level logic that drives mapping the MFT to the async
--- a/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp
@@ -284,33 +284,32 @@ WMFVideoMFTManager::CreateBasicVideoFram
   b.mPlanes[2].mStride = halfStride;
   b.mPlanes[2].mHeight = halfHeight;
   b.mPlanes[2].mWidth = halfWidth;
   b.mPlanes[2].mOffset = 0;
   b.mPlanes[2].mSkip = 0;
 
   Microseconds pts = GetSampleTime(aSample);
   Microseconds duration = GetSampleDuration(aSample);
-  VideoData *v = VideoData::Create(mVideoInfo,
-                                   mImageContainer,
-                                   aStreamOffset,
-                                   pts,
-                                   duration,
-                                   b,
-                                   false,
-                                   -1,
-                                   ToIntRect(mPictureRegion));
+  nsRefPtr<VideoData> v = VideoData::Create(mVideoInfo,
+                                            mImageContainer,
+                                            aStreamOffset,
+                                            pts,
+                                            duration,
+                                            b,
+                                            false,
+                                            -1,
+                                            ToIntRect(mPictureRegion));
   if (twoDBuffer) {
     twoDBuffer->Unlock2D();
   } else {
     buffer->Unlock();
   }
 
-  *aOutVideoData = v;
-
+  v.forget(aOutVideoData);
   return S_OK;
 }
 
 HRESULT
 WMFVideoMFTManager::CreateD3DVideoFrame(IMFSample* aSample,
                                         int64_t aStreamOffset,
                                         VideoData** aOutVideoData)
 {
@@ -327,36 +326,36 @@ WMFVideoMFTManager::CreateD3DVideoFrame(
                                   mPictureRegion,
                                   mImageContainer,
                                   getter_AddRefs(image));
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   NS_ENSURE_TRUE(image, E_FAIL);
 
   Microseconds pts = GetSampleTime(aSample);
   Microseconds duration = GetSampleDuration(aSample);
-  VideoData *v = VideoData::CreateFromImage(mVideoInfo,
-                                            mImageContainer,
-                                            aStreamOffset,
-                                            pts,
-                                            duration,
-                                            image.forget(),
-                                            false,
-                                            -1,
-                                            ToIntRect(mPictureRegion));
+  nsRefPtr<VideoData> v = VideoData::CreateFromImage(mVideoInfo,
+                                                     mImageContainer,
+                                                     aStreamOffset,
+                                                     pts,
+                                                     duration,
+                                                     image.forget(),
+                                                     false,
+                                                     -1,
+                                                     ToIntRect(mPictureRegion));
 
   NS_ENSURE_TRUE(v, E_FAIL);
-  *aOutVideoData = v;
+  v.forget(aOutVideoData);
 
   return S_OK;
 }
 
 // Blocks until decoded sample is produced by the deoder.
 HRESULT
 WMFVideoMFTManager::Output(int64_t aStreamOffset,
-                           nsAutoPtr<MediaData>& aOutData)
+                           nsRefPtr<MediaData>& aOutData)
 {
   RefPtr<IMFSample> sample;
   HRESULT hr;
   aOutData = nullptr;
 
   // Loop until we decode a sample, or an unexpected error that we can't
   // handle occurs.
   while (true) {
@@ -377,21 +376,21 @@ WMFVideoMFTManager::Output(int64_t aStre
     if (SUCCEEDED(hr)) {
       break;
     }
     // Else unexpected error, assert, and bail.
     NS_WARNING("WMFVideoMFTManager::Output() unexpected error");
     return E_FAIL;
   }
 
-  VideoData* frame = nullptr;
+  nsRefPtr<VideoData> frame;
   if (mUseHwAccel) {
-    hr = CreateD3DVideoFrame(sample, aStreamOffset, &frame);
+    hr = CreateD3DVideoFrame(sample, aStreamOffset, getter_AddRefs(frame));
   } else {
-    hr = CreateBasicVideoFrame(sample, aStreamOffset, &frame);
+    hr = CreateBasicVideoFrame(sample, aStreamOffset, getter_AddRefs(frame));
   }
   // Frame should be non null only when we succeeded.
   MOZ_ASSERT((frame != nullptr) == SUCCEEDED(hr));
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   NS_ENSURE_TRUE(frame, E_FAIL);
 
   aOutData = frame;
 
--- a/dom/media/fmp4/wmf/WMFVideoMFTManager.h
+++ b/dom/media/fmp4/wmf/WMFVideoMFTManager.h
@@ -26,17 +26,17 @@ public:
                      bool aDXVAEnabled);
   ~WMFVideoMFTManager();
 
   virtual TemporaryRef<MFTDecoder> Init() MOZ_OVERRIDE;
 
   virtual HRESULT Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
 
   virtual HRESULT Output(int64_t aStreamOffset,
-                         nsAutoPtr<MediaData>& aOutput) MOZ_OVERRIDE;
+                         nsRefPtr<MediaData>& aOutput) MOZ_OVERRIDE;
 
   virtual void Shutdown() MOZ_OVERRIDE;
 
 private:
 
   bool InitializeDXVA();
 
   HRESULT ConfigureVideoFrameGeometry();
--- a/dom/media/gstreamer/GStreamerReader.cpp
+++ b/dom/media/gstreamer/GStreamerReader.cpp
@@ -770,21 +770,21 @@ bool GStreamerReader::DecodeVideoFrame(b
      */
     GstBuffer* tmp = nullptr;
     CopyIntoImageBuffer(buffer, &tmp, image);
     gst_buffer_unref(buffer);
     buffer = tmp;
   }
 
   int64_t offset = mDecoder->GetResource()->Tell(); // Estimate location in media.
-  VideoData* video = VideoData::CreateFromImage(mInfo.mVideo,
-                                                mDecoder->GetImageContainer(),
-                                                offset, timestamp, duration,
-                                                static_cast<Image*>(image.get()),
-                                                isKeyframe, -1, mPicture);
+  nsRefPtr<VideoData> video = VideoData::CreateFromImage(mInfo.mVideo,
+                                                         mDecoder->GetImageContainer(),
+                                                         offset, timestamp, duration,
+                                                         static_cast<Image*>(image.get()),
+                                                         isKeyframe, -1, mPicture);
   mVideoQueue.Push(video);
 
   gst_buffer_unref(buffer);
 
   return true;
 }
 
 void GStreamerReader::Seek(int64_t aTarget,
--- a/dom/media/mediasource/MediaSourceReader.cpp
+++ b/dom/media/mediasource/MediaSourceReader.cpp
@@ -110,17 +110,16 @@ void
 MediaSourceReader::OnAudioDecoded(AudioData* aSample)
 {
   MSE_DEBUGV("MediaSourceReader(%p)::OnAudioDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
              this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
   if (mDropAudioBeforeThreshold) {
     if (aSample->mTime < mTimeThreshold) {
       MSE_DEBUG("MediaSourceReader(%p)::OnAudioDecoded mTime=%lld < mTimeThreshold=%lld",
                 this, aSample->mTime, mTimeThreshold);
-      delete aSample;
       mAudioReader->RequestAudioData();
       return;
     }
     mDropAudioBeforeThreshold = false;
   }
 
   // Any OnAudioDecoded callbacks received while mAudioIsSeeking must be not
   // update our last used timestamp, as these are emitted by the reader we're
@@ -155,17 +154,16 @@ void
 MediaSourceReader::OnVideoDecoded(VideoData* aSample)
 {
   MSE_DEBUGV("MediaSourceReader(%p)::OnVideoDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
              this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
   if (mDropVideoBeforeThreshold) {
     if (aSample->mTime < mTimeThreshold) {
       MSE_DEBUG("MediaSourceReader(%p)::OnVideoDecoded mTime=%lld < mTimeThreshold=%lld",
                 this, aSample->mTime, mTimeThreshold);
-      delete aSample;
       mVideoReader->RequestVideoData(false, 0);
       return;
     }
     mDropVideoBeforeThreshold = false;
   }
 
   // Any OnVideoDecoded callbacks received while mVideoIsSeeking must be not
   // update our last used timestamp, as these are emitted by the reader we're
--- a/dom/media/ogg/OggReader.cpp
+++ b/dom/media/ogg/OggReader.cpp
@@ -876,44 +876,44 @@ nsresult OggReader::DecodeTheora(ogg_pac
   int64_t endTime = mTheoraState->Time(aPacket->granulepos);
   if (endTime < aTimeThreshold) {
     // The end time of this frame is already before the current playback
     // position. It will never be displayed, don't bother enqueing it.
     return NS_OK;
   }
 
   if (ret == TH_DUPFRAME) {
-    VideoData* v = VideoData::CreateDuplicate(mDecoder->GetResource()->Tell(),
-                                              time,
-                                              endTime - time,
-                                              aPacket->granulepos);
+    nsRefPtr<VideoData> v = VideoData::CreateDuplicate(mDecoder->GetResource()->Tell(),
+                                                       time,
+                                                       endTime - time,
+                                                       aPacket->granulepos);
     mVideoQueue.Push(v);
   } else if (ret == 0) {
     th_ycbcr_buffer buffer;
     ret = th_decode_ycbcr_out(mTheoraState->mCtx, buffer);
     NS_ASSERTION(ret == 0, "th_decode_ycbcr_out failed");
     bool isKeyframe = th_packet_iskeyframe(aPacket) == 1;
     VideoData::YCbCrBuffer b;
     for (uint32_t i=0; i < 3; ++i) {
       b.mPlanes[i].mData = buffer[i].data;
       b.mPlanes[i].mHeight = buffer[i].height;
       b.mPlanes[i].mWidth = buffer[i].width;
       b.mPlanes[i].mStride = buffer[i].stride;
       b.mPlanes[i].mOffset = b.mPlanes[i].mSkip = 0;
     }
 
-    VideoData *v = VideoData::Create(mInfo.mVideo,
-                                     mDecoder->GetImageContainer(),
-                                     mDecoder->GetResource()->Tell(),
-                                     time,
-                                     endTime - time,
-                                     b,
-                                     isKeyframe,
-                                     aPacket->granulepos,
-                                     ToIntRect(mPicture));
+    nsRefPtr<VideoData> v = VideoData::Create(mInfo.mVideo,
+                                              mDecoder->GetImageContainer(),
+                                              mDecoder->GetResource()->Tell(),
+                                              time,
+                                              endTime - time,
+                                              b,
+                                              isKeyframe,
+                                              aPacket->granulepos,
+                                              ToIntRect(mPicture));
     if (!v) {
       // There may be other reasons for this error, but for
       // simplicity just assume the worst case: out of memory.
       NS_WARNING("Failed to allocate memory for video frame");
       return NS_ERROR_OUT_OF_MEMORY;
     }
     mVideoQueue.Push(v);
   }
@@ -1535,17 +1535,17 @@ nsresult OggReader::SeekInternal(int64_t
     // When doing fastSeek we display the first frame after the seek, so
     // we need to advance the decode to the keyframe otherwise we'll get
     // visual artifacts in the first frame output after the seek.
     // First, we must check to see if there's already a keyframe in the frames
     // that we may have already decoded, and discard frames up to the
     // keyframe.
     VideoData* v;
     while ((v = mVideoQueue.PeekFront()) && !v->mKeyframe) {
-      delete mVideoQueue.PopFront();
+      nsRefPtr<VideoData> releaseMe = mVideoQueue.PopFront();
     }
     if (mVideoQueue.GetSize() == 0) {
       // We didn't find a keyframe in the frames already here, so decode
       // forwards until we find a keyframe.
       bool skip = true;
       while (DecodeVideoFrame(skip, 0) && skip) {
         ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
         if (mDecoder->IsShutdown()) {
--- a/dom/media/omx/MediaCodecReader.cpp
+++ b/dom/media/omx/MediaCodecReader.cpp
@@ -472,17 +472,17 @@ MediaCodecReader::DecodeAudioDataSync()
   return result;
 }
 
 bool
 MediaCodecReader::DecodeAudioDataTask()
 {
   bool result = DecodeAudioDataSync();
   if (AudioQueue().GetSize() > 0) {
-    AudioData* a = AudioQueue().PopFront();
+    nsRefPtr<AudioData> a = AudioQueue().PopFront();
     if (a) {
       if (mAudioTrack.mDiscontinuity) {
         a->mDiscontinuity = true;
         mAudioTrack.mDiscontinuity = false;
       }
       GetCallback()->OnAudioDecoded(a);
     }
   }
@@ -492,17 +492,17 @@ MediaCodecReader::DecodeAudioDataTask()
   return result;
 }
 
 bool
 MediaCodecReader::DecodeVideoFrameTask(int64_t aTimeThreshold)
 {
   bool result = DecodeVideoFrameSync(aTimeThreshold);
   if (VideoQueue().GetSize() > 0) {
-    VideoData* v = VideoQueue().PopFront();
+    nsRefPtr<VideoData> v = VideoQueue().PopFront();
     if (v) {
       if (mVideoTrack.mDiscontinuity) {
         v->mDiscontinuity = true;
         mVideoTrack.mDiscontinuity = false;
       }
       GetCallback()->OnVideoDecoded(v);
     }
   }
@@ -873,17 +873,17 @@ MediaCodecReader::DecodeVideoFrameSync(i
         return false;
       }
     } else {
       return false;
     }
   }
 
   bool result = false;
-  VideoData *v = nullptr;
+  nsRefPtr<VideoData> v;
   RefPtr<TextureClient> textureClient;
   sp<GraphicBuffer> graphicBuffer;
   if (bufferInfo.mBuffer != nullptr) {
     // This is the approximate byte position in the stream.
     int64_t pos = mDecoder->GetResource()->Tell();
 
     if (mVideoTrack.mNativeWindow != nullptr &&
         mVideoTrack.mCodec->getOutputGraphicBufferFromIndex(bufferInfo.mIndex, &graphicBuffer) == OK &&
--- a/dom/media/omx/MediaOmxReader.cpp
+++ b/dom/media/omx/MediaOmxReader.cpp
@@ -415,17 +415,17 @@ bool MediaOmxReader::DecodeVideoFrame(bo
       picture.y = (mPicture.y * frame.Y.mHeight) / mInitialFrame.height;
       picture.width = (frame.Y.mWidth * mPicture.width) / mInitialFrame.width;
       picture.height = (frame.Y.mHeight * mPicture.height) / mInitialFrame.height;
     }
 
     // This is the approximate byte position in the stream.
     int64_t pos = mDecoder->GetResource()->Tell();
 
-    VideoData *v;
+    nsRefPtr<VideoData> v;
     if (!frame.mGraphicBuffer) {
 
       VideoData::YCbCrBuffer b;
       b.mPlanes[0].mData = static_cast<uint8_t *>(frame.Y.mData);
       b.mPlanes[0].mStride = frame.Y.mStride;
       b.mPlanes[0].mHeight = frame.Y.mHeight;
       b.mPlanes[0].mWidth = frame.Y.mWidth;
       b.mPlanes[0].mOffset = frame.Y.mOffset;
--- a/dom/media/raw/RawReader.cpp
+++ b/dom/media/raw/RawReader.cpp
@@ -210,25 +210,25 @@ bool RawReader::DecodeVideoFrame(bool &a
   b.mPlanes[1].mOffset = b.mPlanes[1].mSkip = 0;
 
   b.mPlanes[2].mData = b.mPlanes[1].mData + mMetadata.frameHeight * cbcrStride / 2;
   b.mPlanes[2].mStride = cbcrStride;
   b.mPlanes[2].mHeight = mMetadata.frameHeight / 2;
   b.mPlanes[2].mWidth = mMetadata.frameWidth / 2;
   b.mPlanes[2].mOffset = b.mPlanes[2].mSkip = 0;
 
-  VideoData *v = VideoData::Create(mInfo.mVideo,
-                                   mDecoder->GetImageContainer(),
-                                   -1,
-                                   currentFrameTime,
-                                   (USECS_PER_S / mFrameRate),
-                                   b,
-                                   1, // In raw video every frame is a keyframe
-                                   -1,
-                                   ToIntRect(mPicture));
+  nsRefPtr<VideoData> v = VideoData::Create(mInfo.mVideo,
+                                            mDecoder->GetImageContainer(),
+                                            -1,
+                                            currentFrameTime,
+                                            (USECS_PER_S / mFrameRate),
+                                            b,
+                                            1, // In raw video every frame is a keyframe
+                                            -1,
+                                            ToIntRect(mPicture));
   if (!v)
     return false;
 
   mVideoQueue.Push(v);
   mCurrentFrame++;
   decoded++;
   currentFrameTime += USECS_PER_S / mFrameRate;
 
@@ -273,22 +273,18 @@ nsresult RawReader::SeekInternal(int64_t
     {
       ReentrantMonitorAutoEnter autoMonitor(mDecoder->GetReentrantMonitor());
       if (mDecoder->IsShutdown()) {
         mCurrentFrame = frame;
         return NS_ERROR_FAILURE;
       }
     }
 
-    nsAutoPtr<VideoData> video(mVideoQueue.PeekFront());
-    if (video && video->GetEndTime() < aTime) {
-      mVideoQueue.PopFront();
-      video = nullptr;
-    } else {
-      video.forget();
+    if (mVideoQueue.PeekFront() && mVideoQueue.PeekFront()->GetEndTime() < aTime) {
+      nsRefPtr<VideoData> releaseMe = mVideoQueue.PopFront();
     }
   }
 
   return NS_OK;
 }
 
 nsresult RawReader::GetBuffered(dom::TimeRanges* aBuffered)
 {
--- a/dom/media/webaudio/MediaBufferDecoder.cpp
+++ b/dom/media/webaudio/MediaBufferDecoder.cpp
@@ -257,26 +257,26 @@ MediaDecodeTask::Decode()
     return;
   }
 
   MediaQueue<AudioData> audioQueue;
   nsRefPtr<AudioDecodeRendezvous> barrier(new AudioDecodeRendezvous());
   mDecoderReader->SetCallback(barrier);
   while (1) {
     mDecoderReader->RequestAudioData();
-    nsAutoPtr<AudioData> audio;
+    nsRefPtr<AudioData> audio;
     if (NS_FAILED(barrier->Await(audio))) {
       ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
       return;
     }
     if (!audio) {
       // End of stream.
       break;
     }
-    audioQueue.Push(audio.forget());
+    audioQueue.Push(audio);
   }
   mDecoderReader->Shutdown();
   mDecoderReader->BreakCycles();
 
   uint32_t frameCount = audioQueue.FrameCount();
   uint32_t channelCount = mediaInfo.mAudio.mChannels;
   uint32_t sampleRate = mediaInfo.mAudio.mRate;
 
@@ -320,17 +320,17 @@ MediaDecodeTask::Decode()
       }
     }
   }
   if (!memoryAllocationSuccess) {
     ReportFailureOnMainThread(WebAudioDecodeJob::UnknownError);
     return;
   }
 
-  nsAutoPtr<AudioData> audioData;
+  nsRefPtr<AudioData> audioData;
   while ((audioData = audioQueue.PopFront())) {
     audioData->EnsureAudioBuffer(); // could lead to a copy :(
     AudioDataValue* bufferData = static_cast<AudioDataValue*>
       (audioData->mAudioBuffer->Data());
 
     if (sampleRate != destSampleRate) {
       const uint32_t maxOutSamples = resampledFrames - mDecodeJob.mWriteIndex;
 
--- a/dom/media/webm/WebMReader.cpp
+++ b/dom/media/webm/WebMReader.cpp
@@ -1013,25 +1013,25 @@ bool WebMReader::DecodeVideoFrame(bool &
         // as it was reported relative to the picture size reported by the
         // container.
         picture.x = (mPicture.x * img->d_w) / mInitialFrame.width;
         picture.y = (mPicture.y * img->d_h) / mInitialFrame.height;
         picture.width = (img->d_w * mPicture.width) / mInitialFrame.width;
         picture.height = (img->d_h * mPicture.height) / mInitialFrame.height;
       }
 
-      VideoData *v = VideoData::Create(mInfo.mVideo,
-                                       mDecoder->GetImageContainer(),
-                                       holder->mOffset,
-                                       tstamp_usecs,
-                                       (next_tstamp / NS_PER_USEC)-tstamp_usecs,
-                                       b,
-                                       si.is_kf,
-                                       -1,
-                                       picture);
+      nsRefPtr<VideoData> v = VideoData::Create(mInfo.mVideo,
+                                                mDecoder->GetImageContainer(),
+                                                holder->mOffset,
+                                                tstamp_usecs,
+                                                (next_tstamp / NS_PER_USEC)-tstamp_usecs,
+                                                b,
+                                                si.is_kf,
+                                                -1,
+                                                picture);
       if (!v) {
         return false;
       }
       parsed++;
       decoded++;
       NS_ASSERTION(decoded <= parsed,
         "Expect only 1 frame per chunk per packet in WebM...");
       VideoQueue().Push(v);
--- a/dom/media/wmf/WMFReader.cpp
+++ b/dom/media/wmf/WMFReader.cpp
@@ -731,33 +731,32 @@ WMFReader::CreateBasicVideoFrame(IMFSamp
   // V plane (Cr)
   b.mPlanes[2].mData = data + y_size;
   b.mPlanes[2].mStride = halfStride;
   b.mPlanes[2].mHeight = halfHeight;
   b.mPlanes[2].mWidth = halfWidth;
   b.mPlanes[2].mOffset = 0;
   b.mPlanes[2].mSkip = 0;
 
-  VideoData *v = VideoData::Create(mInfo.mVideo,
-                                   mDecoder->GetImageContainer(),
-                                   aOffsetBytes,
-                                   aTimestampUsecs,
-                                   aDurationUsecs,
-                                   b,
-                                   false,
-                                   -1,
-                                   ToIntRect(mPictureRegion));
+  nsRefPtr<VideoData> v = VideoData::Create(mInfo.mVideo,
+                                            mDecoder->GetImageContainer(),
+                                            aOffsetBytes,
+                                            aTimestampUsecs,
+                                            aDurationUsecs,
+                                            b,
+                                            false,
+                                            -1,
+                                            ToIntRect(mPictureRegion));
   if (twoDBuffer) {
     twoDBuffer->Unlock2D();
   } else {
     buffer->Unlock();
   }
 
-  *aOutVideoData = v;
-
+  v.forget(aOutVideoData);
   return S_OK;
 }
 
 HRESULT
 WMFReader::CreateD3DVideoFrame(IMFSample* aSample,
                                int64_t aTimestampUsecs,
                                int64_t aDurationUsecs,
                                int64_t aOffsetBytes,
@@ -774,28 +773,28 @@ WMFReader::CreateD3DVideoFrame(IMFSample
   nsRefPtr<Image> image;
   hr = mDXVA2Manager->CopyToImage(aSample,
                                   mPictureRegion,
                                   mDecoder->GetImageContainer(),
                                   getter_AddRefs(image));
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   NS_ENSURE_TRUE(image, E_FAIL);
 
-  VideoData *v = VideoData::CreateFromImage(mInfo.mVideo,
-                                            mDecoder->GetImageContainer(),
-                                            aOffsetBytes,
-                                            aTimestampUsecs,
-                                            aDurationUsecs,
-                                            image.forget(),
-                                            false,
-                                            -1,
-                                            ToIntRect(mPictureRegion));
+  nsRefPtr<VideoData> v = VideoData::CreateFromImage(mInfo.mVideo,
+                                                     mDecoder->GetImageContainer(),
+                                                     aOffsetBytes,
+                                                     aTimestampUsecs,
+                                                     aDurationUsecs,
+                                                     image.forget(),
+                                                     false,
+                                                     -1,
+                                                     ToIntRect(mPictureRegion));
 
   NS_ENSURE_TRUE(v, E_FAIL);
-  *aOutVideoData = v;
+  v.forget(aOutVideoData);
 
   return S_OK;
 }
 
 bool
 WMFReader::DecodeVideoFrame(bool &aKeyframeSkip,
                             int64_t aTimeThreshold)
 {