Bug 1363283 - Reduce ref-counting overhead of MediaFormatReader::HandleDemuxedSamples(). draft
authorJW Wang <jwwang@mozilla.com>
Sat, 06 May 2017 22:28:49 +0800
changeset 574642 0ad3e668c7e1b15cf1d8f895f84c8703244bfec0
parent 574519 b21b974d60d3075ae24f6fb1bae75d0f122f28fc
child 627666 5b1acafd98a82c83ba12355a111315c29a0b1514
push id57782
push userjwwang@mozilla.com
push dateTue, 09 May 2017 07:14:22 +0000
bugs1363283
milestone55.0a1
Bug 1363283 - Reduce ref-counting overhead of MediaFormatReader::HandleDemuxedSamples(). http://searchfox.org/mozilla-central/rev/224cc663d54085994a4871ef464b7662e0721e83/dom/media/MediaFormatReader.cpp#2037 We can reduce one AddRef/Release pair by transferring the ownership of |sample| for it is no longer used and will be removed by |decoder.mQueuedSamples.RemoveElementAt(0)| soon. http://searchfox.org/mozilla-central/rev/224cc663d54085994a4871ef464b7662e0721e83/dom/media/platforms/PlatformDecoderModule.h#244 Note We will let Decode() take an already_AddRefed<MediaRawData> instead so it is possible to transfer the ownership all the way down to the underlying platform decoder across thread boundaries. MozReview-Commit-ID: GOxRChmHzHG
dom/media/Benchmark.cpp
dom/media/MediaFormatReader.cpp
dom/media/MediaFormatReader.h
dom/media/ipc/RemoteVideoDecoder.cpp
dom/media/ipc/RemoteVideoDecoder.h
dom/media/ipc/VideoDecoderParent.cpp
dom/media/platforms/PlatformDecoderModule.h
dom/media/platforms/agnostic/DummyMediaDataDecoder.cpp
dom/media/platforms/agnostic/DummyMediaDataDecoder.h
dom/media/platforms/agnostic/OpusDecoder.cpp
dom/media/platforms/agnostic/OpusDecoder.h
dom/media/platforms/agnostic/TheoraDecoder.cpp
dom/media/platforms/agnostic/TheoraDecoder.h
dom/media/platforms/agnostic/VPXDecoder.cpp
dom/media/platforms/agnostic/VPXDecoder.h
dom/media/platforms/agnostic/VorbisDecoder.cpp
dom/media/platforms/agnostic/VorbisDecoder.h
dom/media/platforms/agnostic/WAVDecoder.cpp
dom/media/platforms/agnostic/WAVDecoder.h
dom/media/platforms/agnostic/eme/ChromiumCDMVideoDecoder.cpp
dom/media/platforms/agnostic/eme/ChromiumCDMVideoDecoder.h
dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
dom/media/platforms/agnostic/eme/EMEDecoderModule.h
dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h
dom/media/platforms/android/RemoteDataDecoder.cpp
dom/media/platforms/android/RemoteDataDecoder.h
dom/media/platforms/apple/AppleATDecoder.cpp
dom/media/platforms/apple/AppleATDecoder.h
dom/media/platforms/apple/AppleVTDecoder.cpp
dom/media/platforms/apple/AppleVTDecoder.h
dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp
dom/media/platforms/ffmpeg/FFmpegDataDecoder.h
dom/media/platforms/omx/OmxDataDecoder.cpp
dom/media/platforms/omx/OmxDataDecoder.h
dom/media/platforms/wmf/WMFMediaDataDecoder.cpp
dom/media/platforms/wmf/WMFMediaDataDecoder.h
dom/media/platforms/wrappers/H264Converter.cpp
dom/media/platforms/wrappers/H264Converter.h
dom/media/platforms/wrappers/MediaDataDecoderProxy.cpp
dom/media/platforms/wrappers/MediaDataDecoderProxy.h
--- a/dom/media/Benchmark.cpp
+++ b/dom/media/Benchmark.cpp
@@ -300,17 +300,17 @@ BenchmarkPlayback::Output(const MediaDat
 void
 BenchmarkPlayback::InputExhausted()
 {
   MOZ_ASSERT(OnThread());
   if (mFinished || mSampleIndex >= mSamples.Length()) {
     return;
   }
   RefPtr<Benchmark> ref(mMainThreadState);
-  mDecoder->Decode(mSamples[mSampleIndex])
+  mDecoder->Decode(mSamples[mSampleIndex].forget())
     ->Then(Thread(), __func__,
            [ref, this](const MediaDataDecoder::DecodedData& aResults) {
              Output(aResults);
              InputExhausted();
            },
            [ref, this](const MediaResult& aError) { MainThreadShutdown(); });
   mSampleIndex++;
   if (mSampleIndex == mSamples.Length()) {
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -537,19 +537,19 @@ class MediaFormatReader::DecoderFactory:
   using Token = GlobalAllocPolicy::Token;
 
 public:
   Wrapper(already_AddRefed<MediaDataDecoder> aDecoder,
           already_AddRefed<Token> aToken)
     : mDecoder(aDecoder), mToken(aToken) {}
 
   RefPtr<InitPromise> Init() override { return mDecoder->Init(); }
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override
   {
-    return mDecoder->Decode(aSample);
+    return mDecoder->Decode(Move(aSample));
   }
   RefPtr<DecodePromise> Drain() override { return mDecoder->Drain(); }
   RefPtr<FlushPromise> Flush() override { return mDecoder->Flush(); }
   bool IsHardwareAccelerated(nsACString& aFailureReason) const override
   {
     return mDecoder->IsHardwareAccelerated(aFailureReason);
   }
   const char* GetDescriptionName() const override
@@ -1923,24 +1923,24 @@ MediaFormatReader::RequestDemuxSamples(T
   if (aTrack == TrackInfo::kVideoTrack) {
     DoDemuxVideo();
   } else {
     DoDemuxAudio();
   }
 }
 
 void
-MediaFormatReader::DecodeDemuxedSamples(TrackType aTrack,
-                                        MediaRawData* aSample)
+MediaFormatReader::DecodeDemuxedSamples(
+  TrackType aTrack, already_AddRefed<MediaRawData> aSample)
 {
   MOZ_ASSERT(OnTaskQueue());
   auto& decoder = GetDecoderData(aTrack);
   RefPtr<MediaFormatReader> self = this;
   decoder.mFlushed = false;
-  decoder.mDecoder->Decode(aSample)
+  decoder.mDecoder->Decode(Move(aSample))
     ->Then(mTaskQueue, __func__,
            [self, this, aTrack, &decoder]
            (const MediaDataDecoder::DecodedData& aResults) {
              decoder.mDecodeRequest.Complete();
              NotifyNewOutput(aTrack, aResults);
            },
            [self, this, aTrack, &decoder](const MediaResult& aError) {
              decoder.mDecodeRequest.Complete();
@@ -1970,17 +1970,17 @@ MediaFormatReader::HandleDemuxedSamples(
     mDecoderFactory->CreateDecoder(aTrack);
     return;
   }
 
   LOGV("Giving %s input to decoder", TrackTypeToStr(aTrack));
 
   // Decode all our demuxed frames.
   while (decoder.mQueuedSamples.Length()) {
-    RefPtr<MediaRawData> sample = decoder.mQueuedSamples[0];
+    MediaRawData* sample = decoder.mQueuedSamples[0];
     RefPtr<TrackInfoSharedPtr> info = sample->mTrackInfo;
 
     if (info && decoder.mLastStreamSourceID != info->GetID()) {
       bool recyclable = MediaPrefs::MediaDecoderCheckRecycling()
                         && decoder.mDecoder->SupportDecoderRecycling();
       if (!recyclable
           && (decoder.mNextStreamSourceID.isNothing()
               || decoder.mNextStreamSourceID.ref() != info->GetID())) {
@@ -1994,24 +1994,28 @@ MediaFormatReader::HandleDemuxedSamples(
       }
 
       LOG("%s stream id has changed from:%d to:%d.",
           TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
           info->GetID());
       decoder.mLastStreamSourceID = info->GetID();
       decoder.mNextStreamSourceID.reset();
 
+      // Note |sample| is guaranteed to be valid either by
+      // |decoder.mQueuedSamples| or |samples|.
+      nsTArray<RefPtr<MediaRawData>> samples;
+
       if (!recyclable) {
         LOG("Decoder does not support recycling, recreate decoder.");
         // If flushing is required, it will clear our array of queued samples.
         // So make a copy now.
-        nsTArray<RefPtr<MediaRawData>> samples{ Move(decoder.mQueuedSamples) };
+        samples.SwapElements(decoder.mQueuedSamples);
         ShutdownDecoder(aTrack);
         if (sample->mKeyframe) {
-          decoder.mQueuedSamples.AppendElements(Move(samples));
+          decoder.mQueuedSamples.SwapElements(samples);
         }
       }
 
       decoder.mInfo = info;
 
       if (sample->mKeyframe) {
         ScheduleUpdate(aTrack);
       } else {
@@ -2029,17 +2033,17 @@ MediaFormatReader::HandleDemuxedSamples(
          sample->mTime.ToMicroseconds(), sample->mTimecode.ToMicroseconds(),
          sample->mKeyframe);
     decoder.mNumSamplesInput++;
     decoder.mSizeOfQueue++;
     if (aTrack == TrackInfo::kVideoTrack) {
       aA.mStats.mParsedFrames++;
     }
 
-    DecodeDemuxedSamples(aTrack, sample);
+    DecodeDemuxedSamples(aTrack, decoder.mQueuedSamples[0].forget());
 
     decoder.mQueuedSamples.RemoveElementAt(0);
     break;
   }
 }
 
 void
 MediaFormatReader::InternalSeek(TrackType aTrack,
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -103,18 +103,18 @@ private:
   // Returns true if no more action is required.
   bool UpdateReceivedNewData(TrackType aTrack);
   // Called when new samples need to be demuxed.
   void RequestDemuxSamples(TrackType aTrack);
   // Handle demuxed samples by the input behavior.
   void HandleDemuxedSamples(TrackType aTrack,
                             AbstractMediaDecoder::AutoNotifyDecoded& aA);
   // Decode any pending already demuxed samples.
-  void DecodeDemuxedSamples(TrackType aTrack,
-                            MediaRawData* aSample);
+  void DecodeDemuxedSamples(
+    TrackType aTrack, already_AddRefed<MediaRawData> aSample);
 
   struct InternalSeekTarget
   {
     InternalSeekTarget(const media::TimeInterval& aTime, bool aDropTarget)
       : mTime(aTime)
       , mDropTarget(aDropTarget)
       , mWaiting(false)
       , mHasSeeked(false)
--- a/dom/media/ipc/RemoteVideoDecoder.cpp
+++ b/dom/media/ipc/RemoteVideoDecoder.cpp
@@ -51,17 +51,17 @@ RefPtr<MediaDataDecoder::InitPromise>
 RemoteVideoDecoder::Init()
 {
   RefPtr<RemoteVideoDecoder> self = this;
   return InvokeAsync(VideoDecoderManagerChild::GetManagerAbstractThread(),
                      __func__, [self, this]() { return mActor->Init(); });
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
-RemoteVideoDecoder::Decode(MediaRawData* aSample)
+RemoteVideoDecoder::Decode(already_AddRefed<MediaRawData> aSample)
 {
   RefPtr<RemoteVideoDecoder> self = this;
   RefPtr<MediaRawData> sample = aSample;
   return InvokeAsync(VideoDecoderManagerChild::GetManagerAbstractThread(),
                      __func__,
                      [self, this, sample]() { return mActor->Decode(sample); });
 }
 
--- a/dom/media/ipc/RemoteVideoDecoder.h
+++ b/dom/media/ipc/RemoteVideoDecoder.h
@@ -23,17 +23,17 @@ class RemoteDecoderModule;
 // operates solely on the VideoDecoderManagerChild thread.
 class RemoteVideoDecoder : public MediaDataDecoder
 {
 public:
   friend class RemoteDecoderModule;
 
   // MediaDataDecoder
   RefPtr<InitPromise> Init() override;
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override;
   RefPtr<DecodePromise> Drain() override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
   bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
   void SetSeekThreshold(const media::TimeUnit& aTime) override;
 
   const char* GetDescriptionName() const override { return "RemoteVideoDecoder"; }
   ConversionRequired NeedsConversion() const override;
--- a/dom/media/ipc/VideoDecoderParent.cpp
+++ b/dom/media/ipc/VideoDecoderParent.cpp
@@ -141,17 +141,17 @@ VideoDecoderParent::RecvInput(const Medi
   data->mTime = TimeUnit::FromMicroseconds(aData.base().time());
   data->mTimecode = TimeUnit::FromMicroseconds(aData.base().timecode());
   data->mDuration = TimeUnit::FromMicroseconds(aData.base().duration());
   data->mKeyframe = aData.base().keyframe();
 
   DeallocShmem(aData.buffer());
 
   RefPtr<VideoDecoderParent> self = this;
-  mDecoder->Decode(data)->Then(
+  mDecoder->Decode(data.forget())->Then(
     mManagerTaskQueue, __func__,
     [self, this](const MediaDataDecoder::DecodedData& aResults) {
       if (mDestroyed) {
         return;
       }
       ProcessDecodedData(aResults);
       Unused << SendInputExhausted();
     },
--- a/dom/media/platforms/PlatformDecoderModule.h
+++ b/dom/media/platforms/PlatformDecoderModule.h
@@ -236,17 +236,17 @@ public:
   // that requires blocking the calling thread in this function *must*
   // be done here so that it can be canceled by calling Shutdown()!
   virtual RefPtr<InitPromise> Init() = 0;
 
   // Inserts a sample into the decoder's decode pipeline. The DecodePromise will
   // be resolved with the decoded MediaData. In case the decoder needs more
   // input, the DecodePromise may be resolved with an empty array of samples to
   // indicate that Decode should be called again before a MediaData is returned.
-  virtual RefPtr<DecodePromise> Decode(MediaRawData* aSample) = 0;
+  virtual RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) = 0;
 
   // Causes all complete samples in the pipeline that can be decoded to be
   // output. If the decoder can't produce samples from the current output,
   // it drops the input samples. The decoder may be holding onto samples
   // that are required to decode samples that it expects to get in future.
   // This is called when the demuxer reaches end of stream.
   // This function is asynchronous.
   // The MediaDataDecoder shall resolve the pending DecodePromise with drained
--- a/dom/media/platforms/agnostic/DummyMediaDataDecoder.cpp
+++ b/dom/media/platforms/agnostic/DummyMediaDataDecoder.cpp
@@ -36,19 +36,20 @@ DummyMediaDataDecoder::Init()
 
 RefPtr<ShutdownPromise>
 DummyMediaDataDecoder::Shutdown()
 {
   return ShutdownPromise::CreateAndResolve(true, __func__);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
-DummyMediaDataDecoder::Decode(MediaRawData* aSample)
+DummyMediaDataDecoder::Decode(already_AddRefed<MediaRawData> aSample)
 {
-  RefPtr<MediaData> data = mCreator->Create(aSample);
+  RefPtr<MediaRawData> sample(aSample);
+  RefPtr<MediaData> data = mCreator->Create(sample);
 
   if (!data) {
     return DecodePromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY, __func__);
   }
 
   // Frames come out in DTS order but we need to output them in PTS order.
   mReorderQueue.Push(data);
 
--- a/dom/media/platforms/agnostic/DummyMediaDataDecoder.h
+++ b/dom/media/platforms/agnostic/DummyMediaDataDecoder.h
@@ -31,17 +31,17 @@ public:
   DummyMediaDataDecoder(UniquePtr<DummyDataCreator>&& aCreator,
                         const char* aDescription,
                         const CreateDecoderParams& aParams);
 
   RefPtr<InitPromise> Init() override;
 
   RefPtr<ShutdownPromise> Shutdown() override;
 
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override;
 
   RefPtr<DecodePromise> Drain() override;
 
   RefPtr<FlushPromise> Flush() override;
 
   const char* GetDescriptionName() const override;
 
   ConversionRequired NeedsConversion() const override;
--- a/dom/media/platforms/agnostic/OpusDecoder.cpp
+++ b/dom/media/platforms/agnostic/OpusDecoder.cpp
@@ -141,20 +141,20 @@ OpusDataDecoder::DecodeHeader(const unsi
     // default layout.
     PodCopy(mMappingTable, mOpusParser->mMappingTable, MAX_AUDIO_CHANNELS);
   }
 
   return NS_OK;
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
-OpusDataDecoder::Decode(MediaRawData* aSample)
+OpusDataDecoder::Decode(already_AddRefed<MediaRawData> aSample)
 {
-  return InvokeAsync<MediaRawData*>(mTaskQueue, this, __func__,
-                                    &OpusDataDecoder::ProcessDecode, aSample);
+  return InvokeAsync<RefPtr<MediaRawData>>(
+    mTaskQueue, this, __func__, &OpusDataDecoder::ProcessDecode, aSample);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
 OpusDataDecoder::ProcessDecode(MediaRawData* aSample)
 {
   uint32_t channels = mOpusParser->mChannels;
 
   if (mPaddingDiscarded) {
--- a/dom/media/platforms/agnostic/OpusDecoder.h
+++ b/dom/media/platforms/agnostic/OpusDecoder.h
@@ -19,17 +19,17 @@ class OpusParser;
 
 class OpusDataDecoder : public MediaDataDecoder
 {
 public:
   explicit OpusDataDecoder(const CreateDecoderParams& aParams);
   ~OpusDataDecoder();
 
   RefPtr<InitPromise> Init() override;
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override;
   RefPtr<DecodePromise> Drain() override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
   const char* GetDescriptionName() const override
   {
     return "opus audio decoder";
   }
 
--- a/dom/media/platforms/agnostic/TheoraDecoder.cpp
+++ b/dom/media/platforms/agnostic/TheoraDecoder.cpp
@@ -198,20 +198,20 @@ TheoraDecoder::ProcessDecode(MediaRawDat
   LOG("Theora Decode error: %d", ret);
   return DecodePromise::CreateAndReject(
     MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
                 RESULT_DETAIL("Theora decode error:%d", ret)),
     __func__);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
-TheoraDecoder::Decode(MediaRawData* aSample)
+TheoraDecoder::Decode(already_AddRefed<MediaRawData> aSample)
 {
-  return InvokeAsync<MediaRawData*>(mTaskQueue, this, __func__,
-                                    &TheoraDecoder::ProcessDecode, aSample);
+  return InvokeAsync<RefPtr<MediaRawData>>(
+    mTaskQueue, this, __func__, &TheoraDecoder::ProcessDecode, aSample);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
 TheoraDecoder::Drain()
 {
   return InvokeAsync(mTaskQueue, __func__, [] {
     return DecodePromise::CreateAndResolve(DecodedData(), __func__);
   });
--- a/dom/media/platforms/agnostic/TheoraDecoder.h
+++ b/dom/media/platforms/agnostic/TheoraDecoder.h
@@ -14,17 +14,17 @@
 namespace mozilla {
 
 class TheoraDecoder : public MediaDataDecoder
 {
 public:
   explicit TheoraDecoder(const CreateDecoderParams& aParams);
 
   RefPtr<InitPromise> Init() override;
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override;
   RefPtr<DecodePromise> Drain() override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
 
   // Return true if mimetype is a Theora codec
   static bool IsTheora(const nsACString& aMimeType);
 
   const char* GetDescriptionName() const override
--- a/dom/media/platforms/agnostic/VPXDecoder.cpp
+++ b/dom/media/platforms/agnostic/VPXDecoder.cpp
@@ -236,20 +236,20 @@ VPXDecoder::ProcessDecode(MediaRawData* 
         MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__), __func__);
     }
     results.AppendElement(Move(v));
   }
   return DecodePromise::CreateAndResolve(Move(results), __func__);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
-VPXDecoder::Decode(MediaRawData* aSample)
+VPXDecoder::Decode(already_AddRefed<MediaRawData> aSample)
 {
-  return InvokeAsync<MediaRawData*>(mTaskQueue, this, __func__,
-                                    &VPXDecoder::ProcessDecode, aSample);
+  return InvokeAsync<RefPtr<MediaRawData>>(
+    mTaskQueue, this, __func__, &VPXDecoder::ProcessDecode, aSample);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
 VPXDecoder::Drain()
 {
   return InvokeAsync(mTaskQueue, __func__, [] {
     return DecodePromise::CreateAndResolve(DecodedData(), __func__);
   });
--- a/dom/media/platforms/agnostic/VPXDecoder.h
+++ b/dom/media/platforms/agnostic/VPXDecoder.h
@@ -18,17 +18,17 @@
 namespace mozilla {
 
 class VPXDecoder : public MediaDataDecoder
 {
 public:
   explicit VPXDecoder(const CreateDecoderParams& aParams);
 
   RefPtr<InitPromise> Init() override;
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override;
   RefPtr<DecodePromise> Drain() override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
   const char* GetDescriptionName() const override
   {
     return "libvpx video decoder";
   }
 
--- a/dom/media/platforms/agnostic/VorbisDecoder.cpp
+++ b/dom/media/platforms/agnostic/VorbisDecoder.cpp
@@ -122,20 +122,20 @@ VorbisDataDecoder::DecodeHeader(const un
 
   int r = vorbis_synthesis_headerin(&mVorbisInfo,
                                     &mVorbisComment,
                                     &pkt);
   return r == 0 ? NS_OK : NS_ERROR_FAILURE;
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
-VorbisDataDecoder::Decode(MediaRawData* aSample)
+VorbisDataDecoder::Decode(already_AddRefed<MediaRawData> aSample)
 {
-  return InvokeAsync<MediaRawData*>(mTaskQueue, this, __func__,
-                                    &VorbisDataDecoder::ProcessDecode, aSample);
+  return InvokeAsync<RefPtr<MediaRawData>>(
+    mTaskQueue, this, __func__, &VorbisDataDecoder::ProcessDecode, aSample);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
 VorbisDataDecoder::ProcessDecode(MediaRawData* aSample)
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
 
   const unsigned char* aData = aSample->Data();
--- a/dom/media/platforms/agnostic/VorbisDecoder.h
+++ b/dom/media/platforms/agnostic/VorbisDecoder.h
@@ -20,17 +20,17 @@ namespace mozilla {
 
 class VorbisDataDecoder : public MediaDataDecoder
 {
 public:
   explicit VorbisDataDecoder(const CreateDecoderParams& aParams);
   ~VorbisDataDecoder();
 
   RefPtr<InitPromise> Init() override;
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override;
   RefPtr<DecodePromise> Drain() override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
   const char* GetDescriptionName() const override
   {
     return "vorbis audio decoder";
   }
 
--- a/dom/media/platforms/agnostic/WAVDecoder.cpp
+++ b/dom/media/platforms/agnostic/WAVDecoder.cpp
@@ -62,20 +62,20 @@ WaveDataDecoder::Shutdown()
 
 RefPtr<MediaDataDecoder::InitPromise>
 WaveDataDecoder::Init()
 {
   return InitPromise::CreateAndResolve(TrackInfo::kAudioTrack, __func__);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
-WaveDataDecoder::Decode(MediaRawData* aSample)
+WaveDataDecoder::Decode(already_AddRefed<MediaRawData> aSample)
 {
-  return InvokeAsync<MediaRawData*>(mTaskQueue, this, __func__,
-                                    &WaveDataDecoder::ProcessDecode, aSample);
+  return InvokeAsync<RefPtr<MediaRawData>>(
+    mTaskQueue, this, __func__, &WaveDataDecoder::ProcessDecode, aSample);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
 WaveDataDecoder::ProcessDecode(MediaRawData* aSample)
 {
   size_t aLength = aSample->Size();
   ByteReader aReader(aSample->Data(), aLength);
   int64_t aOffset = aSample->mOffset;
--- a/dom/media/platforms/agnostic/WAVDecoder.h
+++ b/dom/media/platforms/agnostic/WAVDecoder.h
@@ -16,17 +16,17 @@ class WaveDataDecoder : public MediaData
 {
 public:
   explicit WaveDataDecoder(const CreateDecoderParams& aParams);
 
   // Return true if mimetype is Wave
   static bool IsWave(const nsACString& aMimeType);
 
   RefPtr<InitPromise> Init() override;
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override;
   RefPtr<DecodePromise> Drain() override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
   const char* GetDescriptionName() const override
   {
     return "wave audio decoder";
   }
 
--- a/dom/media/platforms/agnostic/eme/ChromiumCDMVideoDecoder.cpp
+++ b/dom/media/platforms/agnostic/eme/ChromiumCDMVideoDecoder.cpp
@@ -100,17 +100,17 @@ ChromiumCDMVideoDecoder::GetDescriptionN
 MediaDataDecoder::ConversionRequired
 ChromiumCDMVideoDecoder::NeedsConversion() const
 {
   return mConvertToAnnexB ? ConversionRequired::kNeedAnnexB
                           : ConversionRequired::kNeedNone;
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
-ChromiumCDMVideoDecoder::Decode(MediaRawData* aSample)
+ChromiumCDMVideoDecoder::Decode(already_AddRefed<MediaRawData> aSample)
 {
   RefPtr<gmp::ChromiumCDMParent> cdm = mCDMParent;
   RefPtr<MediaRawData> sample = aSample;
   return InvokeAsync(mGMPThread, __func__, [cdm, sample]() {
     return cdm->DecryptAndDecodeFrame(sample);
   });
 }
 
--- a/dom/media/platforms/agnostic/eme/ChromiumCDMVideoDecoder.h
+++ b/dom/media/platforms/agnostic/eme/ChromiumCDMVideoDecoder.h
@@ -17,17 +17,17 @@ struct GMPVideoDecoderParams;
 
 class ChromiumCDMVideoDecoder : public MediaDataDecoder
 {
 public:
   ChromiumCDMVideoDecoder(const GMPVideoDecoderParams& aParams,
                           CDMProxy* aCDMProxy);
 
   RefPtr<InitPromise> Init() override;
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<DecodePromise> Drain() override;
   RefPtr<ShutdownPromise> Shutdown() override;
   const char* GetDescriptionName() const override;
   ConversionRequired NeedsConversion() const override;
 
 private:
   ~ChromiumCDMVideoDecoder();
--- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
@@ -44,25 +44,26 @@ public:
   }
 
   RefPtr<InitPromise> Init() override
   {
     MOZ_ASSERT(!mIsShutdown);
     return mDecoder->Init();
   }
 
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override
   {
     MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
     MOZ_RELEASE_ASSERT(mDecrypts.Count() == 0,
                        "Can only process one sample at a time");
+    RefPtr<MediaRawData> sample(aSample);
     RefPtr<DecodePromise> p = mDecodePromise.Ensure(__func__);
 
     RefPtr<EMEDecryptor> self = this;
-    mSamplesWaitingForKey->WaitIfKeyNotUsable(aSample)
+    mSamplesWaitingForKey->WaitIfKeyNotUsable(sample)
       ->Then(mTaskQueue, __func__,
              [self, this](MediaRawData* aSample) {
                mKeyRequest.Complete();
                ThrottleDecode(aSample);
              },
              [self, this]() {
                mKeyRequest.Complete();
              })
@@ -139,17 +140,17 @@ public:
           RESULT_DETAIL("decrypted.mStatus=%u", uint32_t(aDecrypted.mStatus))),
         __func__);
     } else {
       MOZ_ASSERT(!mIsShutdown);
       // The sample is no longer encrypted, so clear its crypto metadata.
       UniquePtr<MediaRawDataWriter> writer(aDecrypted.mSample->CreateWriter());
       writer->mCrypto = CryptoSample();
       RefPtr<EMEDecryptor> self = this;
-      mDecoder->Decode(aDecrypted.mSample)
+      mDecoder->Decode(do_AddRef(aDecrypted.mSample))
         ->Then(mTaskQueue, __func__,
                [self, this](const DecodedData& aResults) {
                  mDecodeRequest.Complete();
                  mDecodePromise.ResolveIfExists(aResults, __func__);
                },
                [self, this](const MediaResult& aError) {
                  mDecodeRequest.Complete();
                  mDecodePromise.RejectIfExists(aError, __func__);
@@ -254,30 +255,31 @@ EMEMediaDataDecoderProxy::EMEMediaDataDe
       new SamplesWaitingForKey(aProxy,
                                aParams.mType,
                                aParams.mOnWaitingForKeyEvent))
   , mProxy(aProxy)
 {
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
-EMEMediaDataDecoderProxy::Decode(MediaRawData* aSample)
+EMEMediaDataDecoderProxy::Decode(already_AddRefed<MediaRawData> aSample)
 {
+  RefPtr<MediaRawData> sample(aSample);
   RefPtr<DecodePromise> p = mDecodePromise.Ensure(__func__);
 
   RefPtr<EMEMediaDataDecoderProxy> self = this;
-  mSamplesWaitingForKey->WaitIfKeyNotUsable(aSample)
+  mSamplesWaitingForKey->WaitIfKeyNotUsable(sample)
     ->Then(mTaskQueue, __func__,
            [self, this](MediaRawData* aSample) {
              mKeyRequest.Complete();
 
              nsAutoPtr<MediaRawDataWriter> writer(aSample->CreateWriter());
              mProxy->GetSessionIdsForKeyId(aSample->mCrypto.mKeyId,
                                            writer->mCrypto.mSessionIds);
-             MediaDataDecoderProxy::Decode(aSample)
+             MediaDataDecoderProxy::Decode(do_AddRef(aSample))
                ->Then(mTaskQueue, __func__,
                       [self, this](const DecodedData& aResults) {
                         mDecodeRequest.Complete();
                         mDecodePromise.Resolve(aResults, __func__);
                       },
                       [self, this](const MediaResult& aError) {
                         mDecodeRequest.Complete();
                         mDecodePromise.Reject(aError, __func__);
--- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.h
+++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.h
@@ -47,17 +47,17 @@ class EMEMediaDataDecoderProxy : public 
 public:
   EMEMediaDataDecoderProxy(
     already_AddRefed<AbstractThread> aProxyThread, CDMProxy* aProxy,
     const CreateDecoderParams& aParams);
   EMEMediaDataDecoderProxy(const CreateDecoderParams& aParams,
                            already_AddRefed<MediaDataDecoder> aProxyDecoder,
                            CDMProxy* aProxy);
 
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
 
 private:
   RefPtr<TaskQueue> mTaskQueue;
   RefPtr<SamplesWaitingForKey> mSamplesWaitingForKey;
   MozPromiseRequestHolder<SamplesWaitingForKey::WaitForKeyPromise> mKeyRequest;
   MozPromiseHolder<DecodePromise> mDecodePromise;
--- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
@@ -306,17 +306,17 @@ GMPVideoDecoder::Init()
                                                    DecryptorId()))) {
     mInitPromise.Reject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
   }
 
   return promise;
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
-GMPVideoDecoder::Decode(MediaRawData* aSample)
+GMPVideoDecoder::Decode(already_AddRefed<MediaRawData> aSample)
 {
   MOZ_ASSERT(IsOnGMPThread());
 
   RefPtr<MediaRawData> sample(aSample);
   if (!mGMP) {
     return DecodePromise::CreateAndReject(
       MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
                   RESULT_DETAIL("mGMP not initialized")),
--- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h
+++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h
@@ -29,17 +29,17 @@ struct GMPVideoDecoderParams
 
 class GMPVideoDecoder : public MediaDataDecoder,
                         public GMPVideoDecoderCallbackProxy
 {
 public:
   explicit GMPVideoDecoder(const GMPVideoDecoderParams& aParams);
 
   RefPtr<InitPromise> Init() override;
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override;
   RefPtr<DecodePromise> Drain() override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
   const char* GetDescriptionName() const override
   {
     return "GMP video decoder";
   }
   ConversionRequired NeedsConversion() const override
--- a/dom/media/platforms/android/RemoteDataDecoder.cpp
+++ b/dom/media/platforms/android/RemoteDataDecoder.cpp
@@ -213,27 +213,29 @@ public:
   }
 
   RefPtr<MediaDataDecoder::FlushPromise> Flush() override
   {
     mInputInfos.Clear();
     return RemoteDataDecoder::Flush();
   }
 
-  RefPtr<MediaDataDecoder::DecodePromise> Decode(MediaRawData* aSample) override
+  RefPtr<MediaDataDecoder::DecodePromise>
+  Decode(already_AddRefed<MediaRawData> aSample) override
   {
-    const VideoInfo* config = aSample->mTrackInfo
-                              ? aSample->mTrackInfo->GetAsVideoInfo()
+    RefPtr<MediaRawData> sample(aSample);
+    const VideoInfo* config = sample->mTrackInfo
+                              ? sample->mTrackInfo->GetAsVideoInfo()
                               : &mConfig;
     MOZ_ASSERT(config);
 
     InputInfo info(
-      aSample->mDuration.ToMicroseconds(), config->mImage, config->mDisplay);
-    mInputInfos.Insert(aSample->mTime.ToMicroseconds(), info);
-    return RemoteDataDecoder::Decode(aSample);
+      sample->mDuration.ToMicroseconds(), config->mImage, config->mDisplay);
+    mInputInfos.Insert(sample->mTime.ToMicroseconds(), info);
+    return RemoteDataDecoder::Decode(sample.forget());
   }
 
   bool SupportDecoderRecycling() const override
   {
     return mIsCodecSupportAdaptivePlayback;
   }
 
 private:
@@ -517,22 +519,21 @@ RemoteDataDecoder::ProcessShutdown()
   }
 
   mFormat = nullptr;
 
   return ShutdownPromise::CreateAndResolve(true, __func__);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
-RemoteDataDecoder::Decode(MediaRawData* aSample)
+RemoteDataDecoder::Decode(already_AddRefed<MediaRawData> aSample)
 {
-  MOZ_ASSERT(aSample != nullptr);
-
   RefPtr<RemoteDataDecoder> self = this;
   RefPtr<MediaRawData> sample = aSample;
+  MOZ_ASSERT(sample);
   return InvokeAsync(mTaskQueue, __func__, [self, sample, this]() {
     jni::ByteBuffer::LocalRef bytes = jni::ByteBuffer::New(
       const_cast<uint8_t*>(sample->Data()), sample->Size());
 
     BufferInfo::LocalRef bufferInfo;
     nsresult rv = BufferInfo::New(&bufferInfo);
     if (NS_FAILED(rv)) {
       return DecodePromise::CreateAndReject(
--- a/dom/media/platforms/android/RemoteDataDecoder.h
+++ b/dom/media/platforms/android/RemoteDataDecoder.h
@@ -22,17 +22,17 @@ public:
                      const nsString& aDrmStubId,
                      CDMProxy* aProxy);
 
   static already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const CreateDecoderParams& aParams,
                      const nsString& aDrmStubId,
                      CDMProxy* aProxy);
 
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override;
   RefPtr<DecodePromise> Drain() override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
   const char* GetDescriptionName() const override
   {
     return "android remote decoder";
   }
 
--- a/dom/media/platforms/apple/AppleATDecoder.cpp
+++ b/dom/media/platforms/apple/AppleATDecoder.cpp
@@ -59,27 +59,26 @@ AppleATDecoder::Init()
     NS_ERROR("Non recognised format");
     return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
   }
 
   return InitPromise::CreateAndResolve(TrackType::kAudioTrack, __func__);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
-AppleATDecoder::Decode(MediaRawData* aSample)
+AppleATDecoder::Decode(already_AddRefed<MediaRawData> aSample)
 {
-  LOG("mp4 input sample %p %lld us %lld pts%s %llu bytes audio", aSample,
-      aSample->mDuration.ToMicroseconds(), aSample->mTime.ToMicroseconds(),
-      aSample->mKeyframe ? " keyframe" : "",
-      (unsigned long long)aSample->Size());
-  RefPtr<AppleATDecoder> self = this;
-  RefPtr<MediaRawData> sample = aSample;
-  return InvokeAsync(mTaskQueue, __func__, [self, this, sample] {
-    return ProcessDecode(sample);
-  });
+  RefPtr<MediaRawData> sample(aSample);
+  LOG("mp4 input sample %p %lld us %lld pts%s %llu bytes audio", sample.get(),
+      sample->mDuration.ToMicroseconds(), sample->mTime.ToMicroseconds(),
+      sample->mKeyframe ? " keyframe" : "",
+      (unsigned long long)sample->Size());
+
+  return InvokeAsync<RefPtr<MediaRawData>>(mTaskQueue, this,
+      __func__, &AppleATDecoder::ProcessDecode, sample.forget());
 }
 
 RefPtr<MediaDataDecoder::FlushPromise>
 AppleATDecoder::ProcessFlush()
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
   mQueuedSamples.Clear();
   mDecodedSamples.Clear();
--- a/dom/media/platforms/apple/AppleATDecoder.h
+++ b/dom/media/platforms/apple/AppleATDecoder.h
@@ -19,17 +19,17 @@ class TaskQueue;
 
 class AppleATDecoder : public MediaDataDecoder {
 public:
   AppleATDecoder(const AudioInfo& aConfig,
                  TaskQueue* aTaskQueue);
   ~AppleATDecoder();
 
   RefPtr<InitPromise> Init() override;
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override;
   RefPtr<DecodePromise> Drain() override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
 
   const char* GetDescriptionName() const override
   {
     return "apple CoreMedia decoder";
   }
--- a/dom/media/platforms/apple/AppleVTDecoder.cpp
+++ b/dom/media/platforms/apple/AppleVTDecoder.cpp
@@ -69,27 +69,27 @@ AppleVTDecoder::Init()
   if (NS_SUCCEEDED(rv)) {
     return InitPromise::CreateAndResolve(TrackType::kVideoTrack, __func__);
   }
 
   return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
-AppleVTDecoder::Decode(MediaRawData* aSample)
+AppleVTDecoder::Decode(already_AddRefed<MediaRawData> aSample)
 {
+  RefPtr<MediaRawData> sample(aSample);
   LOG("mp4 input sample %p pts %lld duration %lld us%s %" PRIuSIZE " bytes",
-      aSample,
-      aSample->mTime.ToMicroseconds(),
-      aSample->mDuration.ToMicroseconds(),
-      aSample->mKeyframe ? " keyframe" : "",
-      aSample->Size());
+      sample.get(),
+      sample->mTime.ToMicroseconds(),
+      sample->mDuration.ToMicroseconds(),
+      sample->mKeyframe ? " keyframe" : "",
+      sample->Size());
 
   RefPtr<AppleVTDecoder> self = this;
-  RefPtr<MediaRawData> sample = aSample;
   return InvokeAsync(mTaskQueue, __func__, [self, this, sample] {
     RefPtr<DecodePromise> p;
     {
       MonitorAutoLock mon(mMonitor);
       p = mPromise.Ensure(__func__);
     }
     ProcessDecode(sample);
     return p;
--- a/dom/media/platforms/apple/AppleVTDecoder.h
+++ b/dom/media/platforms/apple/AppleVTDecoder.h
@@ -37,17 +37,17 @@ public:
       , duration(aSample.mDuration)
       , byte_offset(aSample.mOffset)
       , is_sync_point(aSample.mKeyframe)
     {
     }
   };
 
   RefPtr<InitPromise> Init() override;
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override;
   RefPtr<DecodePromise> Drain() override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
   void SetSeekThreshold(const media::TimeUnit& aTime) override;
 
   bool IsHardwareAccelerated(nsACString& aFailureReason) const override
   {
     return mIsHardwareAccelerated;
--- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp
@@ -95,20 +95,20 @@ FFmpegDataDecoder<LIBAV_VER>::Shutdown()
       return ShutdownPromise::CreateAndResolve(true, __func__);
     });
   }
   ProcessShutdown();
   return ShutdownPromise::CreateAndResolve(true, __func__);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
-FFmpegDataDecoder<LIBAV_VER>::Decode(MediaRawData* aSample)
+FFmpegDataDecoder<LIBAV_VER>::Decode(already_AddRefed<MediaRawData> aSample)
 {
-  return InvokeAsync<MediaRawData*>(mTaskQueue, this, __func__,
-                                    &FFmpegDataDecoder::ProcessDecode, aSample);
+  return InvokeAsync<RefPtr<MediaRawData>>(
+    mTaskQueue, this, __func__, &FFmpegDataDecoder::ProcessDecode, aSample);
 }
 
 RefPtr<MediaDataDecoder::FlushPromise>
 FFmpegDataDecoder<LIBAV_VER>::Flush()
 {
   return InvokeAsync(mTaskQueue, this, __func__,
                      &FFmpegDataDecoder<LIBAV_VER>::ProcessFlush);
 }
--- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h
+++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h
@@ -25,17 +25,17 @@ class FFmpegDataDecoder<LIBAV_VER> : pub
 public:
   FFmpegDataDecoder(FFmpegLibWrapper* aLib, TaskQueue* aTaskQueue,
                     AVCodecID aCodecID);
   virtual ~FFmpegDataDecoder();
 
   static bool Link();
 
   RefPtr<InitPromise> Init() override = 0;
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override;
   RefPtr<DecodePromise> Drain() override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
 
   static AVCodec* FindAVCodec(FFmpegLibWrapper* aLib, AVCodecID aCodec);
 
 protected:
   // Flush and Drain operation, always run
--- a/dom/media/platforms/omx/OmxDataDecoder.cpp
+++ b/dom/media/platforms/omx/OmxDataDecoder.cpp
@@ -164,23 +164,23 @@ OmxDataDecoder::Init()
              [self, this]() {
                RejectInitPromise(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
              });
     return p;
   });
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
-OmxDataDecoder::Decode(MediaRawData* aSample)
+OmxDataDecoder::Decode(already_AddRefed<MediaRawData> aSample)
 {
-  LOG("sample %p", aSample);
+  RefPtr<MediaRawData> sample(aSample);
+  LOG("sample %p", sample.get());
   MOZ_ASSERT(mInitPromise.IsEmpty());
 
   RefPtr<OmxDataDecoder> self = this;
-  RefPtr<MediaRawData> sample = aSample;
   return InvokeAsync(mOmxTaskQueue, __func__, [self, this, sample]() {
     RefPtr<DecodePromise> p = mDecodePromise.Ensure(__func__);
     mMediaRawDatas.AppendElement(Move(sample));
 
     // Start to fill/empty buffers.
     if (mOmxState == OMX_StateIdle ||
         mOmxState == OMX_StateExecuting) {
       FillAndEmptyBuffers();
--- a/dom/media/platforms/omx/OmxDataDecoder.h
+++ b/dom/media/platforms/omx/OmxDataDecoder.h
@@ -59,17 +59,17 @@ class OmxDataDecoder : public MediaDataD
 protected:
   virtual ~OmxDataDecoder();
 
 public:
   OmxDataDecoder(const TrackInfo& aTrackInfo,
                  layers::ImageContainer* aImageContainer);
 
   RefPtr<InitPromise> Init() override;
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override;
   RefPtr<DecodePromise> Drain() override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
 
   const char* GetDescriptionName() const override
   {
     return "omx decoder";
   }
--- a/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp
+++ b/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp
@@ -95,23 +95,22 @@ WMFMediaDataDecoder::ProcessShutdown()
       SendTelemetry(S_OK);
     }
   }
   return ShutdownPromise::CreateAndResolve(true, __func__);
 }
 
 // Inserts data into the decoder's pipeline.
 RefPtr<MediaDataDecoder::DecodePromise>
-WMFMediaDataDecoder::Decode(MediaRawData* aSample)
+WMFMediaDataDecoder::Decode(already_AddRefed<MediaRawData> aSample)
 {
   MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown);
 
-  return InvokeAsync<MediaRawData*>(mTaskQueue, this, __func__,
-                                    &WMFMediaDataDecoder::ProcessDecode,
-                                    aSample);
+  return InvokeAsync<RefPtr<MediaRawData>>(
+    mTaskQueue, this, __func__, &WMFMediaDataDecoder::ProcessDecode, aSample);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
 WMFMediaDataDecoder::ProcessError(HRESULT aError, const char* aReason)
 {
   if (!mRecordedError) {
     SendTelemetry(aError);
     mRecordedError = true;
--- a/dom/media/platforms/wmf/WMFMediaDataDecoder.h
+++ b/dom/media/platforms/wmf/WMFMediaDataDecoder.h
@@ -87,17 +87,17 @@ protected:
 class WMFMediaDataDecoder : public MediaDataDecoder
 {
 public:
   WMFMediaDataDecoder(MFTManager* aOutputSource, TaskQueue* aTaskQueue);
   ~WMFMediaDataDecoder();
 
   RefPtr<MediaDataDecoder::InitPromise> Init() override;
 
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override;
 
   RefPtr<DecodePromise> Drain() override;
 
   RefPtr<FlushPromise> Flush() override;
 
   RefPtr<ShutdownPromise> Shutdown() override;
 
   bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
--- a/dom/media/platforms/wrappers/H264Converter.cpp
+++ b/dom/media/platforms/wrappers/H264Converter.cpp
@@ -48,80 +48,82 @@ H264Converter::Init()
   }
 
   // We haven't been able to initialize a decoder due to a missing SPS/PPS.
   return MediaDataDecoder::InitPromise::CreateAndResolve(
            TrackType::kVideoTrack, __func__);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
-H264Converter::Decode(MediaRawData* aSample)
+H264Converter::Decode(already_AddRefed<MediaRawData> aSample)
 {
   MOZ_RELEASE_ASSERT(!mDecodePromiseRequest.Exists()
                      && !mInitPromiseRequest.Exists(),
                      "Can't request a new decode until previous one completed");
 
-  if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) {
+  RefPtr<MediaRawData> sample(aSample);
+
+  if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(sample)) {
     // We need AVCC content to be able to later parse the SPS.
     // This is a no-op if the data is already AVCC.
     return DecodePromise::CreateAndReject(
       MediaResult(NS_ERROR_OUT_OF_MEMORY, RESULT_DETAIL("ConvertSampleToAVCC")),
       __func__);
   }
 
   nsresult rv;
   if (!mDecoder) {
     // It is not possible to create an AVCC H264 decoder without SPS.
     // As such, creation will fail if the extra_data just extracted doesn't
     // contain a SPS.
-    rv = CreateDecoderAndInit(aSample);
+    rv = CreateDecoderAndInit(sample);
     if (rv == NS_ERROR_NOT_INITIALIZED) {
       // We are missing the required SPS to create the decoder.
       // Ignore for the time being, the MediaRawData will be dropped.
       return DecodePromise::CreateAndResolve(DecodedData(), __func__);
     }
   } else {
-    rv = CheckForSPSChange(aSample);
+    rv = CheckForSPSChange(sample);
   }
 
   if (rv == NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER) {
     // The decoder is pending initialization.
     RefPtr<DecodePromise> p = mDecodePromise.Ensure(__func__);
     return p;
   }
 
   if (NS_FAILED(rv)) {
     return DecodePromise::CreateAndReject(
       MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
                   RESULT_DETAIL("Unable to create H264 decoder")),
       __func__);
   }
 
-  if (mNeedKeyframe && !aSample->mKeyframe) {
+  if (mNeedKeyframe && !sample->mKeyframe) {
     return DecodePromise::CreateAndResolve(DecodedData(), __func__);
   }
 
   if (!mNeedAVCC) {
     mNeedAVCC =
       Some(mDecoder->NeedsConversion() == ConversionRequired::kNeedAVCC);
   }
 
   if (!*mNeedAVCC
-      && !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample, mNeedKeyframe)) {
+      && !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(sample, mNeedKeyframe)) {
     return DecodePromise::CreateAndReject(
       MediaResult(NS_ERROR_OUT_OF_MEMORY,
                   RESULT_DETAIL("ConvertSampleToAnnexB")),
       __func__);
   }
 
   mNeedKeyframe = false;
 
-  aSample->mExtraData = mCurrentConfig.mExtraData;
+  sample->mExtraData = mCurrentConfig.mExtraData;
 
-  return mDecoder->Decode(aSample);
+  return mDecoder->Decode(sample.forget());
 }
 
 RefPtr<MediaDataDecoder::FlushPromise>
 H264Converter::Flush()
 {
   mNeedKeyframe = true;
   if (mDecoder) {
     return mDecoder->Flush();
@@ -254,18 +256,17 @@ H264Converter::CreateDecoderAndInit(Medi
   }
   return rv;
 }
 
 void
 H264Converter::OnDecoderInitDone(const TrackType aTrackType)
 {
   mInitPromiseRequest.Complete();
-  RefPtr<MediaRawData> sample = mPendingSample.forget();
-  DecodeFirstSample(sample);
+  DecodeFirstSample(mPendingSample.forget());
 }
 
 void
 H264Converter::OnDecoderInitFailed(const MediaResult& aError)
 {
   mInitPromiseRequest.Complete();
   mDecodePromise.Reject(
     MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
@@ -277,39 +278,41 @@ bool
 H264Converter::CanRecycleDecoder() const
 {
   MOZ_ASSERT(mDecoder);
   return MediaPrefs::MediaDecoderCheckRecycling()
          && mDecoder->SupportDecoderRecycling();
 }
 
 void
-H264Converter::DecodeFirstSample(MediaRawData* aSample)
+H264Converter::DecodeFirstSample(already_AddRefed<MediaRawData> aSample)
 {
-  if (mNeedKeyframe && !aSample->mKeyframe) {
+  RefPtr<MediaRawData> sample(aSample);
+
+  if (mNeedKeyframe && !sample->mKeyframe) {
     mDecodePromise.Resolve(DecodedData(), __func__);
     return;
   }
 
   mNeedAVCC =
     Some(mDecoder->NeedsConversion() == ConversionRequired::kNeedAVCC);
 
   if (!*mNeedAVCC
-      && !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample, mNeedKeyframe)) {
+      && !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(sample, mNeedKeyframe)) {
     mDecodePromise.Reject(
       MediaResult(NS_ERROR_OUT_OF_MEMORY,
                   RESULT_DETAIL("ConvertSampleToAnnexB")),
       __func__);
     return;
   }
 
   mNeedKeyframe = false;
 
   RefPtr<H264Converter> self = this;
-  mDecoder->Decode(aSample)
+  mDecoder->Decode(sample.forget())
     ->Then(AbstractThread::GetCurrent()->AsTaskQueue(), __func__,
            [self, this](const MediaDataDecoder::DecodedData& aResults) {
              mDecodePromiseRequest.Complete();
              mDecodePromise.Resolve(aResults, __func__);
            },
            [self, this](const MediaResult& aError) {
              mDecodePromiseRequest.Complete();
              mDecodePromise.Reject(aError, __func__);
--- a/dom/media/platforms/wrappers/H264Converter.h
+++ b/dom/media/platforms/wrappers/H264Converter.h
@@ -25,17 +25,17 @@ class H264Converter : public MediaDataDe
 {
 public:
 
   H264Converter(PlatformDecoderModule* aPDM,
                 const CreateDecoderParams& aParams);
   virtual ~H264Converter();
 
   RefPtr<InitPromise> Init() override;
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override;
   RefPtr<DecodePromise> Drain() override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
   bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
   const char* GetDescriptionName() const override
   {
     if (mDecoder) {
       return mDecoder->GetDescriptionName();
@@ -71,17 +71,17 @@ private:
   nsresult CheckForSPSChange(MediaRawData* aSample);
   void UpdateConfigFromExtraData(MediaByteBuffer* aExtraData);
 
   void OnDecoderInitDone(const TrackType aTrackType);
   void OnDecoderInitFailed(const MediaResult& aError);
 
   bool CanRecycleDecoder() const;
 
-  void DecodeFirstSample(MediaRawData* aSample);
+  void DecodeFirstSample(already_AddRefed<MediaRawData> aSample);
 
   RefPtr<PlatformDecoderModule> mPDM;
   const VideoInfo mOriginalConfig;
   VideoInfo mCurrentConfig;
   RefPtr<layers::KnowsCompositor> mKnowsCompositor;
   RefPtr<layers::ImageContainer> mImageContainer;
   const RefPtr<TaskQueue> mTaskQueue;
   RefPtr<MediaRawData> mPendingSample;
--- a/dom/media/platforms/wrappers/MediaDataDecoderProxy.cpp
+++ b/dom/media/platforms/wrappers/MediaDataDecoderProxy.cpp
@@ -17,28 +17,25 @@ MediaDataDecoderProxy::Init()
     return mProxyDecoder->Init();
   }
   RefPtr<MediaDataDecoderProxy> self = this;
   return InvokeAsync(mProxyThread, __func__,
                      [self, this]() { return mProxyDecoder->Init(); });
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
-MediaDataDecoderProxy::Decode(MediaRawData* aSample)
+MediaDataDecoderProxy::Decode(already_AddRefed<MediaRawData> aSample)
 {
   MOZ_ASSERT(!mIsShutdown);
 
   if (!mProxyThread) {
-    return mProxyDecoder->Decode(aSample);
+    return mProxyDecoder->Decode(Move(aSample));
   }
-  RefPtr<MediaDataDecoderProxy> self = this;
-  RefPtr<MediaRawData> sample = aSample;
-  return InvokeAsync(mProxyThread, __func__, [self, this, sample]() {
-    return mProxyDecoder->Decode(sample);
-  });
+  return InvokeAsync(mProxyThread, mProxyDecoder.get(),
+    __func__, &MediaDataDecoder::Decode, Move(aSample));
 }
 
 RefPtr<MediaDataDecoder::FlushPromise>
 MediaDataDecoderProxy::Flush()
 {
   MOZ_ASSERT(!mIsShutdown);
 
   if (!mProxyThread) {
--- a/dom/media/platforms/wrappers/MediaDataDecoderProxy.h
+++ b/dom/media/platforms/wrappers/MediaDataDecoderProxy.h
@@ -37,17 +37,17 @@ public:
 
   void SetProxyTarget(MediaDataDecoder* aProxyDecoder)
   {
     MOZ_ASSERT(aProxyDecoder);
     mProxyDecoder = aProxyDecoder;
   }
 
   RefPtr<InitPromise> Init() override;
-  RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
+  RefPtr<DecodePromise> Decode(already_AddRefed<MediaRawData> aSample) override;
   RefPtr<DecodePromise> Drain() override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
   const char* GetDescriptionName() const override;
   bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
   void SetSeekThreshold(const media::TimeUnit& aTime) override;
   bool SupportDecoderRecycling() const override;
   ConversionRequired NeedsConversion() const override;