Bug 1175768 - Dispatch NotifyDataArrived and remove the aBuffer argument. r=jya
☠☠ backed out by 85029878321b ☠ ☠
authorBobby Holley <bobbyholley@gmail.com>
Tue, 16 Jun 2015 15:37:48 -0700
changeset 249986 6aa5fa1d318e56114333dc842eaf3242c3d1f7a7
parent 249985 a8bd7a0d2aea2e69e07be3724954f46618ce9225
child 249987 6776ce74b9e5547bbf9a149d567b9baa2580c8ec
push id61401
push userjyavenard@mozilla.com
push dateTue, 23 Jun 2015 05:55:33 +0000
treeherdermozilla-inbound@a369cfb95b59 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjya
bugs1175768
milestone41.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 1175768 - Dispatch NotifyDataArrived and remove the aBuffer argument. r=jya It would be nice to remove the argument in a separate patch, but we can't perform MediaResource reads on the main thread, so the SilentReadAt stuff needs to happen at the same time as the off-main-thread stuff.
dom/media/AbstractMediaDecoder.h
dom/media/MP3FrameParser.cpp
dom/media/MP3FrameParser.h
dom/media/MediaDecoder.cpp
dom/media/MediaDecoder.h
dom/media/MediaDecoderReader.h
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
dom/media/MediaFormatReader.cpp
dom/media/MediaFormatReader.h
dom/media/MediaResource.cpp
dom/media/apple/AppleMP3Reader.cpp
dom/media/apple/AppleMP3Reader.h
dom/media/directshow/DirectShowReader.cpp
dom/media/directshow/DirectShowReader.h
dom/media/fmp4/MP4Reader.cpp
dom/media/fmp4/MP4Reader.h
dom/media/gstreamer/GStreamerReader.cpp
dom/media/gstreamer/GStreamerReader.h
dom/media/mediasource/SourceBuffer.cpp
dom/media/mediasource/SourceBufferDecoder.cpp
dom/media/mediasource/SourceBufferDecoder.h
dom/media/mediasource/TrackBuffer.cpp
dom/media/omx/MediaCodecReader.cpp
dom/media/omx/MediaCodecReader.h
dom/media/omx/MediaOmxReader.cpp
dom/media/omx/MediaOmxReader.h
dom/media/webaudio/BufferDecoder.cpp
dom/media/webaudio/BufferDecoder.h
dom/media/webm/WebMBufferedParser.cpp
dom/media/webm/WebMBufferedParser.h
dom/media/webm/WebMReader.cpp
dom/media/webm/WebMReader.h
--- a/dom/media/AbstractMediaDecoder.h
+++ b/dom/media/AbstractMediaDecoder.h
@@ -112,17 +112,17 @@ public:
   virtual MediaDecoderOwner* GetOwner() = 0;
 
   // May be called by the reader to notify the decoder that the resources
   // required to begin playback have been acquired. Can be called on any thread.
   virtual void NotifyWaitingForResourcesStatusChanged() = 0;
 
   // Called by the reader's MediaResource as data arrives over the network.
   // Must be called on the main thread.
-  virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) = 0;
+  virtual void NotifyDataArrived(uint32_t aLength, int64_t aOffset) = 0;
 
   // Set by Reader if the current audio track can be offloaded
   virtual void SetPlatformCanOffloadAudio(bool aCanOffloadAudio) {}
 
   // Called by Decoder/State machine to check audio offload condtions are met
   virtual bool CheckDecoderCanOffloadAudio() { return false; }
 
   // Called from HTMLMediaElement when owner document activity changes
--- a/dom/media/MP3FrameParser.cpp
+++ b/dom/media/MP3FrameParser.cpp
@@ -461,26 +461,26 @@ nsresult MP3FrameParser::ParseBuffer(con
     // We have our whole first frame. Try to find a VBR header.
     mNumFrames = FindNumVBRFrames(mFirstFrame);
     mFirstFrameEnd = -1;
   }
 
   return NS_OK;
 }
 
-void MP3FrameParser::Parse(const char* aBuffer, uint32_t aLength, uint64_t aOffset)
+void MP3FrameParser::Parse(const uint8_t* aBuffer, uint32_t aLength, uint64_t aOffset)
 {
   MutexAutoLock mon(mLock);
 
   if (HasExactDuration()) {
     // We know the duration; nothing to do here.
     return;
   }
 
-  const uint8_t* buffer = reinterpret_cast<const uint8_t*>(aBuffer);
+  const uint8_t* buffer = aBuffer;
   int32_t length = aLength;
   uint64_t offset = aOffset;
 
   // Got some data we have seen already. Skip forward to what we need.
   if (aOffset < mOffset) {
     buffer += mOffset - aOffset;
     length -= mOffset - aOffset;
     offset = mOffset;
--- a/dom/media/MP3FrameParser.h
+++ b/dom/media/MP3FrameParser.h
@@ -107,17 +107,17 @@ class MP3FrameParser
 public:
   explicit MP3FrameParser(int64_t aLength=-1);
 
   bool IsMP3() {
     MutexAutoLock mon(mLock);
     return mIsMP3 != NOT_MP3;
   }
 
-  void Parse(const char* aBuffer, uint32_t aLength, uint64_t aStreamOffset);
+  void Parse(const uint8_t* aBuffer, uint32_t aLength, uint64_t aStreamOffset);
 
   // Returns the duration, in microseconds. If the entire stream has not
   // been parsed yet, this is an estimate based on the bitrate of the
   // frames parsed so far.
   int64_t GetDuration();
 
   // Returns the offset of the first MP3 frame in the stream, or -1 of
   // no MP3 frame has been detected yet.
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -1312,19 +1312,19 @@ size_t MediaDecoder::SizeOfVideoQueue() 
 
 size_t MediaDecoder::SizeOfAudioQueue() {
   if (mDecoderStateMachine) {
     return mDecoderStateMachine->SizeOfAudioQueue();
   }
   return 0;
 }
 
-void MediaDecoder::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) {
+void MediaDecoder::NotifyDataArrived(uint32_t aLength, int64_t aOffset) {
   if (mDecoderStateMachine) {
-    mDecoderStateMachine->NotifyDataArrived(aBuffer, aLength, aOffset);
+    mDecoderStateMachine->DispatchNotifyDataArrived(aLength, aOffset);
   }
 
   // ReadyState computation depends on MediaDecoder::CanPlayThrough, which
   // depends on the download rate.
   UpdateReadyState();
 }
 
 // Provide access to the state machine object
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -429,17 +429,17 @@ public:
 
   // Called by nsChannelToPipeListener or MediaResource when the
   // download has ended. Called on the main thread only. aStatus is
   // the result from OnStopRequest.
   virtual void NotifyDownloadEnded(nsresult aStatus);
 
   // Called as data arrives on the stream and is read into the cache.  Called
   // on the main thread only.
-  virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) override;
+  virtual void NotifyDataArrived(uint32_t aLength, int64_t aOffset) override;
 
   // Called by MediaResource when the principal of the resource has
   // changed. Called on main thread only.
   virtual void NotifyPrincipalChanged();
 
   // Called by the MediaResource to keep track of the number of bytes read
   // from the resource. Called on the main by an event runner dispatched
   // by the MediaResource read functions.
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -234,19 +234,33 @@ public:
 
   // Returns the number of bytes of memory allocated by structures/frames in
   // the audio queue.
   size_t SizeOfAudioQueueInBytes() const;
 
   virtual size_t SizeOfVideoQueueInFrames();
   virtual size_t SizeOfAudioQueueInFrames();
 
-  // Only used by WebMReader and MediaOmxReader for now, so stub here rather
-  // than in every reader than inherits from MediaDecoderReader.
-  virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) {}
+protected:
+  virtual void NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset) { }
+  void NotifyDataArrived(uint32_t aLength, int64_t aOffset)
+  {
+    MOZ_ASSERT(OnTaskQueue());
+    NS_ENSURE_TRUE_VOID(!mShutdown);
+    NotifyDataArrivedInternal(aLength, aOffset);
+  }
+
+public:
+  void DispatchNotifyDataArrived(uint32_t aLength, int64_t aOffset)
+  {
+    RefPtr<nsRunnable> r =
+      NS_NewRunnableMethodWithArgs<uint32_t, int64_t>(this, &MediaDecoderReader::NotifyDataArrived, aLength, aOffset);
+    TaskQueue()->Dispatch(r.forget(), AbstractThread::DontAssertDispatchSuccess);
+  }
+
   // Notify the reader that data from the resource was evicted (MediaSource only)
   virtual void NotifyDataRemoved() {}
   virtual int64_t GetEvictionOffset(double aTime) { return -1; }
 
   virtual MediaQueue<AudioData>& AudioQueue() { return mAudioQueue; }
   virtual MediaQueue<VideoData>& VideoQueue() { return mVideoQueue; }
 
   // Returns a pointer to the decoder.
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1634,22 +1634,20 @@ void MediaDecoderStateMachine::PlayState
 
 void MediaDecoderStateMachine::LogicallySeekingChanged()
 {
   MOZ_ASSERT(OnTaskQueue());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   ScheduleStateMachine();
 }
 
-void MediaDecoderStateMachine::NotifyDataArrived(const char* aBuffer,
-                                                     uint32_t aLength,
-                                                     int64_t aOffset)
+void MediaDecoderStateMachine::NotifyDataArrived(uint32_t aLength,
+                                                 int64_t aOffset)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
-  mReader->NotifyDataArrived(aBuffer, aLength, aOffset);
+  MOZ_ASSERT(OnTaskQueue());
 
   // While playing an unseekable stream of unknown duration, mObservedDuration
   // is updated (in AdvanceFrame()) as we play. But if data is being downloaded
   // faster than played, mObserved won't reflect the end of playable data
   // since we haven't played the frame at the end of buffered data. So update
   // mObservedDuration here as new data is downloaded to prevent such a lag.
   media::TimeIntervals buffered{mDecoder->GetBuffered()};
   if (!buffered.IsInvalid()) {
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -266,17 +266,26 @@ public:
 
   size_t SizeOfAudioQueue() {
     if (mReader) {
       return mReader->SizeOfAudioQueueInBytes();
     }
     return 0;
   }
 
-  void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
+private:
+  void NotifyDataArrived(uint32_t aLength, int64_t aOffset);
+public:
+  void DispatchNotifyDataArrived(uint32_t aLength, int64_t aOffset)
+  {
+    RefPtr<nsRunnable> r =
+      NS_NewRunnableMethodWithArgs<uint32_t, int64_t>(this, &MediaDecoderStateMachine::NotifyDataArrived, aLength, aOffset);
+    TaskQueue()->Dispatch(r.forget());
+    mReader->DispatchNotifyDataArrived(aLength, aOffset);
+  }
 
   // Returns the state machine task queue.
   MediaTaskQueue* TaskQueue() const { return mTaskQueue; }
 
   // Calls ScheduleStateMachine() after taking the decoder lock. Also
   // notifies the decoder thread in case it's waiting on the decoder lock.
   void ScheduleStateMachineWithLockAndWakeDecoder();
 
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -1534,21 +1534,20 @@ MediaFormatReader::NotifyDemuxer(uint32_
   }
   if (HasAudio()) {
     mAudio.mReceivedNewData = true;
     ScheduleUpdate(TrackType::kAudioTrack);
   }
 }
 
 void
-MediaFormatReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
+MediaFormatReader::NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset)
 {
-  MOZ_ASSERT(NS_IsMainThread());
-
-  MOZ_ASSERT(aBuffer || aLength);
+  MOZ_ASSERT(OnTaskQueue());
+  MOZ_ASSERT(aLength);
   if (mDataRange.IsEmpty()) {
     mDataRange = ByteInterval(aOffset, aOffset + aLength);
   } else {
     mDataRange = mDataRange.Span(ByteInterval(aOffset, aOffset + aLength));
   }
   mCachedTimeRangesStale = true;
 
   if (!mInitDone) {
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -63,19 +63,19 @@ public:
   Seek(int64_t aTime, int64_t aUnused) override;
 
   bool IsMediaSeekable() override
   {
     return mSeekable;
   }
 
   int64_t GetEvictionOffset(double aTime) override;
-  void NotifyDataArrived(const char* aBuffer,
-                                 uint32_t aLength,
-                                 int64_t aOffset) override;
+protected:
+  void NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset) override;
+public:
   void NotifyDataRemoved() override;
 
   media::TimeIntervals GetBuffered() override;
 
   virtual bool ForceZeroStartTime() const override;
 
   // For Media Resource Management
   void SetIdle() override;
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -458,17 +458,17 @@ ChannelMediaResource::CopySegmentToCache
                                          void *aClosure,
                                          const char *aFromSegment,
                                          uint32_t aToOffset,
                                          uint32_t aCount,
                                          uint32_t *aWriteCount)
 {
   CopySegmentClosure* closure = static_cast<CopySegmentClosure*>(aClosure);
 
-  closure->mResource->mDecoder->NotifyDataArrived(aFromSegment, aCount, closure->mResource->mOffset);
+  closure->mResource->mDecoder->NotifyDataArrived(aCount, closure->mResource->mOffset);
 
   // Keep track of where we're up to.
   RESOURCE_LOG("%p [ChannelMediaResource]: CopySegmentToCache at mOffset [%lld] add "
                "[%d] bytes for decoder[%p]",
                closure->mResource, closure->mResource->mOffset, aCount,
                closure->mResource->mDecoder);
   closure->mResource->mOffset += aCount;
 
--- a/dom/media/apple/AppleMP3Reader.cpp
+++ b/dom/media/apple/AppleMP3Reader.cpp
@@ -382,17 +382,17 @@ AppleMP3Reader::ReadMetadata(MediaInfo* 
     uint32_t numBytes = AUDIO_READ_BYTES;
     readrv = Read(&numBytes, bytes);
 
     rv = AudioFileStreamParseBytes(mAudioFileStream,
                                    numBytes,
                                    bytes,
                                    0 /* flags */);
 
-    mMP3FrameParser.Parse(bytes, numBytes, offset);
+    mMP3FrameParser.Parse(reinterpret_cast<uint8_t*>(bytes), numBytes, offset);
 
     offset += numBytes;
 
     // We have to do our decoder setup from the callback. When it's done it will
     // set mStreamReady.
   } while (!mStreamReady && !rv && NS_SUCCEEDED(readrv));
 
   if (rv) {
@@ -520,26 +520,26 @@ AppleMP3Reader::Seek(int64_t aTime, int6
   mDecoder->GetResource()->Seek(nsISeekableStream::NS_SEEK_SET, byteOffset);
 
   ResetDecode();
 
   return SeekPromise::CreateAndResolve(aTime, __func__);
 }
 
 void
-AppleMP3Reader::NotifyDataArrived(const char* aBuffer,
-                                  uint32_t aLength,
-                                  int64_t aOffset)
+AppleMP3Reader::NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset)
 {
-  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(OnTaskQueue());
   if (!mMP3FrameParser.NeedsData()) {
     return;
   }
 
-  mMP3FrameParser.Parse(aBuffer, aLength, aOffset);
+  nsRefPtr<MediaByteBuffer> bytes = mDecoder->GetResource()->SilentReadAt(aOffset, aLength);
+  NS_ENSURE_TRUE_VOID(bytes);
+  mMP3FrameParser.Parse(bytes->Elements(), aLength, aOffset);
   if (!mMP3FrameParser.IsMP3()) {
     return;
   }
 
   uint64_t duration = mMP3FrameParser.GetDuration();
   if (duration != mDuration) {
     LOGD("Updating media duration to %lluus\n", duration);
     MOZ_ASSERT(mDecoder);
--- a/dom/media/apple/AppleMP3Reader.h
+++ b/dom/media/apple/AppleMP3Reader.h
@@ -40,19 +40,20 @@ public:
                            UInt32 aNumPackets,
                            const void *aData,
                            AudioStreamPacketDescription *aPackets);
 
   void AudioMetadataCallback(AudioFileStreamID aFileStream,
                              AudioFileStreamPropertyID aPropertyID,
                              UInt32 *aFlags);
 
-  virtual void NotifyDataArrived(const char* aBuffer,
-                                 uint32_t aLength,
-                                 int64_t aOffset) override;
+protected:
+  virtual void NotifyDataArrivedInternal(uint32_t aLength,
+                                         int64_t aOffset) override;
+public:
 
   virtual bool IsMediaSeekable() override;
 
 private:
   void SetupDecoder();
   nsresult Read(uint32_t *aNumBytes, char *aData);
 
   static OSStatus PassthroughInputDataCallback(AudioConverterRef aAudioConverter,
--- a/dom/media/directshow/DirectShowReader.cpp
+++ b/dom/media/directshow/DirectShowReader.cpp
@@ -79,17 +79,17 @@ ParseMP3Headers(MP3FrameParser *aParser,
                                     MAX_READ_SIZE, &bytesRead);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (!bytesRead) {
       // End of stream.
       return NS_ERROR_FAILURE;
     }
 
-    aParser->Parse(buffer, bytesRead, offset);
+    aParser->Parse(reinterpret_cast<uint8_t*>(buffer), bytesRead, offset);
     offset += bytesRead;
   }
 
   return aParser->IsMP3() ? NS_OK : NS_ERROR_FAILURE;
 }
 
 // Windows XP's MP3 decoder filter. This is available on XP only, on Vista
 // and later we can use the DMO Wrapper filter and MP3 decoder DMO.
@@ -396,24 +396,26 @@ DirectShowReader::SeekInternal(int64_t a
 
   hr = mControl->Run();
   NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
 
   return NS_OK;
 }
 
 void
-DirectShowReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
+DirectShowReader::NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset)
 {
-  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(OnTaskQueue());
   if (!mMP3FrameParser.NeedsData()) {
     return;
   }
 
-  mMP3FrameParser.Parse(aBuffer, aLength, aOffset);
+  nsRefPtr<MediaByteBuffer> bytes = mDecoder->GetResource()->SilentReadAt(aOffset, aLength);
+  NS_ENSURE_TRUE_VOID(bytes);
+  mMP3FrameParser.Parse(bytes->Elements(), aLength, aOffset);
   if (!mMP3FrameParser.IsMP3()) {
     return;
   }
 
   int64_t duration = mMP3FrameParser.GetDuration();
   if (duration != mDuration) {
     MOZ_ASSERT(mDecoder);
     mDuration = duration;
--- a/dom/media/directshow/DirectShowReader.h
+++ b/dom/media/directshow/DirectShowReader.h
@@ -53,19 +53,20 @@ public:
   bool HasVideo() override;
 
   nsresult ReadMetadata(MediaInfo* aInfo,
                         MetadataTags** aTags) override;
 
   nsRefPtr<SeekPromise>
   Seek(int64_t aTime, int64_t aEndTime) override;
 
-  void NotifyDataArrived(const char* aBuffer,
-                         uint32_t aLength,
-                         int64_t aOffset) override;
+protected:
+  void NotifyDataArrivedInternal(uint32_t aLength,
+                                 int64_t aOffset) override;
+public:
 
   bool IsMediaSeekable() override;
 
 private:
 
   // Notifies the filter graph that playback is complete. aStatus is
   // the code to send to the filter graph. Always returns false, so
   // that we can just "return Finish()" from DecodeAudioData().
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -1141,24 +1141,19 @@ MP4Reader::SetSharedDecoderManager(Share
 
 bool
 MP4Reader::VideoIsHardwareAccelerated() const
 {
   return mVideo.mDecoder && mVideo.mDecoder->IsHardwareAccelerated();
 }
 
 void
-MP4Reader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
+MP4Reader::NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset)
 {
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (mShutdown) {
-    return;
-  }
-
+  MOZ_ASSERT(OnTaskQueue());
   if (mLastSeenEnd < 0) {
     MonitorAutoLock mon(mDemuxerMonitor);
     mLastSeenEnd = mDecoder->GetResource()->GetLength();
     if (mLastSeenEnd < 0) {
       // We dont have a length. Demuxer would have been blocking already.
       return;
     }
   }
--- a/dom/media/fmp4/MP4Reader.h
+++ b/dom/media/fmp4/MP4Reader.h
@@ -57,17 +57,20 @@ public:
   virtual void ReadUpdatedMetadata(MediaInfo* aInfo) override;
 
   virtual nsRefPtr<SeekPromise>
   Seek(int64_t aTime, int64_t aEndTime) override;
 
   virtual bool IsMediaSeekable() override;
 
   virtual int64_t GetEvictionOffset(double aTime) override;
-  virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) override;
+
+protected:
+  virtual void NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset) override;
+public:
 
   virtual media::TimeIntervals GetBuffered() override;
 
   // For Media Resource Management
   virtual void SetIdle() override;
   virtual bool IsDormantNeeded() override;
   virtual void ReleaseMediaResources() override;
   virtual void SetSharedDecoderManager(SharedDecoderManager* aManager)
--- a/dom/media/gstreamer/GStreamerReader.cpp
+++ b/dom/media/gstreamer/GStreamerReader.cpp
@@ -330,17 +330,17 @@ nsresult GStreamerReader::ParseMP3Header
   uint64_t offset = 0;
   char bytes[MAX_READ_BYTES];
   uint32_t bytesRead;
   do {
     nsresult rv = resource->ReadAt(offset, bytes, MAX_READ_BYTES, &bytesRead);
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ENSURE_TRUE(bytesRead, NS_ERROR_FAILURE);
 
-    mMP3FrameParser.Parse(bytes, bytesRead, offset);
+    mMP3FrameParser.Parse(reinterpret_cast<uint8_t*>(bytes), bytesRead, offset);
     offset += bytesRead;
   } while (!mMP3FrameParser.ParsedHeaders());
 
   if (mMP3FrameParser.IsMP3()) {
     mLastParserDuration = mMP3FrameParser.GetDuration();
     mDataOffset = mMP3FrameParser.GetMP3Offset();
 
     // Update GStreamer's stream length in case we found any ID3 headers to
@@ -1267,29 +1267,30 @@ GStreamerReader::AutoplugSortCb(GstEleme
    */
   return nullptr;
 }
 
 /**
  * If this is an MP3 stream, pass any new data we get to the MP3 frame parser
  * for duration estimation.
  */
-void GStreamerReader::NotifyDataArrived(const char *aBuffer,
-                                        uint32_t aLength,
-                                        int64_t aOffset)
+void GStreamerReader::NotifyDataArrivedInternal(uint32_t aLength,
+                                                int64_t aOffset)
 {
-  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(OnTaskQueue());
   if (HasVideo()) {
     return;
   }
   if (!mMP3FrameParser.NeedsData()) {
     return;
   }
 
-  mMP3FrameParser.Parse(aBuffer, aLength, aOffset);
+  nsRefPtr<MediaByteBuffer> bytes = mDecoder->GetResource()->SilentReadAt(aOffset, aLength);
+  NS_ENSURE_TRUE_VOID(bytes);
+  mMP3FrameParser.Parse(bytes->Elements(), aLength, aOffset);
   if (!mMP3FrameParser.IsMP3()) {
     return;
   }
 
   int64_t duration = mMP3FrameParser.GetDuration();
   if (duration != mLastParserDuration && mUseParserDuration) {
     MOZ_ASSERT(mDecoder);
     mLastParserDuration = duration;
--- a/dom/media/gstreamer/GStreamerReader.h
+++ b/dom/media/gstreamer/GStreamerReader.h
@@ -46,19 +46,20 @@ public:
   virtual bool DecodeVideoFrame(bool &aKeyframeSkip,
                                 int64_t aTimeThreshold) override;
   virtual nsresult ReadMetadata(MediaInfo* aInfo,
                                 MetadataTags** aTags) override;
   virtual nsRefPtr<SeekPromise>
   Seek(int64_t aTime, int64_t aEndTime) override;
   virtual media::TimeIntervals GetBuffered() override;
 
-  virtual void NotifyDataArrived(const char *aBuffer,
-                                 uint32_t aLength,
-                                 int64_t aOffset) override;
+protected:
+  virtual void NotifyDataArrivedInternal(uint32_t aLength,
+                                         int64_t aOffset) override;
+public:
 
   virtual bool HasAudio() override {
     return mInfo.HasAudio();
   }
 
   virtual bool HasVideo() override {
     return mInfo.HasVideo();
   }
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -292,17 +292,17 @@ void
 SourceBuffer::Ended()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(IsAttached());
   MSE_DEBUG("Ended");
   mContentManager->Ended();
   // We want the MediaSourceReader to refresh its buffered range as it may
   // have been modified (end lined up).
-  mMediaSource->GetDecoder()->NotifyDataArrived(nullptr, 1, mReportedOffset++);
+  mMediaSource->GetDecoder()->NotifyDataArrived(1, mReportedOffset++);
 }
 
 SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
   : DOMEventTargetHelper(aMediaSource->GetParentObject())
   , mMediaSource(aMediaSource)
   , mAppendWindowStart(0)
   , mAppendWindowEnd(PositiveInfinity<double>())
   , mApparentTimestampOffset(0)
@@ -487,17 +487,17 @@ SourceBuffer::AppendDataCompletedWithSuc
         mMediaSource->GetDecoder()->NotifyWaitingForResourcesStatusChanged();
       }
     }
   }
   if (mActive && mIsUsingFormatReader) {
     // Tell our parent decoder that we have received new data.
     // The information provided do not matter much so long as it is monotonically
     // increasing.
-    mMediaSource->GetDecoder()->NotifyDataArrived(nullptr, 1, mReportedOffset++);
+    mMediaSource->GetDecoder()->NotifyDataArrived(1, mReportedOffset++);
     // Send progress event.
     mMediaSource->GetDecoder()->NotifyBytesDownloaded();
   }
 
   CheckEndTime();
 
   StopUpdating();
 }
--- a/dom/media/mediasource/SourceBufferDecoder.cpp
+++ b/dom/media/mediasource/SourceBufferDecoder.cpp
@@ -192,25 +192,25 @@ SourceBufferDecoder::GetImageContainer()
 
 MediaDecoderOwner*
 SourceBufferDecoder::GetOwner()
 {
   return mParentDecoder->GetOwner();
 }
 
 void
-SourceBufferDecoder::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
+SourceBufferDecoder::NotifyDataArrived(uint32_t aLength, int64_t aOffset)
 {
-  mReader->NotifyDataArrived(aBuffer, aLength, aOffset);
+  mReader->DispatchNotifyDataArrived(aLength, aOffset);
 
   // XXX: Params make no sense to parent decoder as it relates to a
   // specific SourceBufferDecoder's data stream.  Pass bogus values here to
   // force parent decoder's state machine to recompute end time for
   // infinite length media.
-  mParentDecoder->NotifyDataArrived(nullptr, 0, 0);
+  mParentDecoder->NotifyDataArrived(0, 0);
 }
 
 media::TimeIntervals
 SourceBufferDecoder::GetBuffered()
 {
   media::TimeIntervals buffered = mReader->GetBuffered();
   if (buffered.IsInvalid()) {
     return buffered;
--- a/dom/media/mediasource/SourceBufferDecoder.h
+++ b/dom/media/mediasource/SourceBufferDecoder.h
@@ -42,17 +42,17 @@ public:
   virtual ReentrantMonitor& GetReentrantMonitor() final override;
   virtual VideoFrameContainer* GetVideoFrameContainer() final override;
   virtual void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo,
                               nsAutoPtr<MetadataTags> aTags,
                               MediaDecoderEventVisibility aEventVisibility) final override;
   virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
                                 MediaDecoderEventVisibility aEventVisibility) final override;
   virtual void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) final override;
-  virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) final override;
+  virtual void NotifyDataArrived(uint32_t aLength, int64_t aOffset) final override;
   virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded, uint32_t aDropped) final override;
   virtual void NotifyWaitingForResourcesStatusChanged() final override;
   virtual void OnReadMetadataCompleted() final override;
   virtual void QueueMetadata(int64_t aTime, nsAutoPtr<MediaInfo> aInfo, nsAutoPtr<MetadataTags> aTags) final override;
   virtual void RemoveMediaTracks() final override;
   virtual void SetMediaSeekable(bool aMediaSeekable) final override;
   virtual bool HasInitializationData() final override;
 
--- a/dom/media/mediasource/TrackBuffer.cpp
+++ b/dom/media/mediasource/TrackBuffer.cpp
@@ -268,19 +268,17 @@ TrackBuffer::AppendDataToCurrentResource
   if (!mCurrentDecoder) {
     return false;
   }
 
   SourceBufferResource* resource = mCurrentDecoder->GetResource();
   int64_t appendOffset = resource->GetLength();
   resource->AppendData(aData);
   mCurrentDecoder->SetRealMediaDuration(mCurrentDecoder->GetRealMediaDuration() + aDuration);
-  // XXX: For future reference: NDA call must run on the main thread.
-  mCurrentDecoder->NotifyDataArrived(reinterpret_cast<const char*>(aData->Elements()),
-                                     aData->Length(), appendOffset);
+  mCurrentDecoder->NotifyDataArrived(aData->Length(), appendOffset);
   mParentDecoder->NotifyBytesDownloaded();
   NotifyTimeRangesChanged();
 
   return true;
 }
 
 void
 TrackBuffer::NotifyTimeRangesChanged()
--- a/dom/media/omx/MediaCodecReader.cpp
+++ b/dom/media/omx/MediaCodecReader.cpp
@@ -517,28 +517,30 @@ MediaCodecReader::HasAudio()
 
 bool
 MediaCodecReader::HasVideo()
 {
   return mInfo.HasVideo();
 }
 
 void
-MediaCodecReader::NotifyDataArrived(const char* aBuffer,
-                                    uint32_t aLength,
-                                    int64_t aOffset)
+MediaCodecReader::NotifyDataArrivedInternal(uint32_t aLength,
+                                            int64_t aOffset)
 {
+  nsRefPtr<MediaByteBuffer> bytes = mDecoder->GetResource()->SilentReadAt(aOffset, aLength);
+  NS_ENSURE_TRUE_VOID(bytes);
+
   MonitorAutoLock monLock(mParserMonitor);
   if (mNextParserPosition == mParsedDataLength &&
       mNextParserPosition >= aOffset &&
       mNextParserPosition <= aOffset + aLength) {
     // No pending parsing runnable currently. And available data are adjacent to
     // parsed data.
     int64_t shift = mNextParserPosition - aOffset;
-    const char* buffer = aBuffer + shift;
+    const char* buffer = reinterpret_cast<const char*>(bytes->Elements()) + shift;
     uint32_t length = aLength - shift;
     int64_t offset = mNextParserPosition;
     if (length > 0) {
       MonitorAutoUnlock monUnlock(mParserMonitor);
       ParseDataSegment(buffer, length, offset);
     }
     mParseDataFromCache = false;
     mParsedDataLength = offset + length;
@@ -625,17 +627,17 @@ MediaCodecReader::ParseDataSegment(const
     if (mMP3FrameParser == nullptr) {
       return false;
     }
 
     if (!mMP3FrameParser->IsMP3()) {
       return true; // NO-OP
     }
 
-    mMP3FrameParser->Parse(aBuffer, aLength, aOffset);
+    mMP3FrameParser->Parse(reinterpret_cast<const uint8_t*>(aBuffer), aLength, aOffset);
 
     duration = mMP3FrameParser->GetDuration();
   }
 
   bool durationUpdateRequired = false;
 
   {
     MonitorAutoLock al(mAudioTrack.mTrackMonitor);
--- a/dom/media/omx/MediaCodecReader.h
+++ b/dom/media/omx/MediaCodecReader.h
@@ -68,20 +68,22 @@ public:
   // Release media resources they should be released in dormant state
   virtual void ReleaseMediaResources();
 
   // Destroys the decoding state. The reader cannot be made usable again.
   // This is different from ReleaseMediaResources() as Shutdown() is
   // irreversible, whereas ReleaseMediaResources() is reversible.
   virtual nsRefPtr<ShutdownPromise> Shutdown();
 
+protected:
   // Used to retrieve some special information that can only be retrieved after
   // all contents have been continuously parsed. (ex. total duration of some
   // variable-bit-rate MP3 files.)
-  virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
+  virtual void NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset) override;
+public:
 
   // Flush the MediaTaskQueue, flush MediaCodec and raise the mDiscontinuity.
   virtual nsresult ResetDecode() override;
 
   // Disptach a DecodeVideoFrameTask to decode video data.
   virtual nsRefPtr<VideoDataPromise>
   RequestVideoData(bool aSkipToNextKeyframe,
                    int64_t aTimeThreshold) override;
--- a/dom/media/omx/MediaOmxReader.cpp
+++ b/dom/media/omx/MediaOmxReader.cpp
@@ -38,17 +38,17 @@ public:
   : mOmxReader(aOmxReader),
     mOffset(aOffset)
   { }
 
   void Run()
   {
     MOZ_ASSERT(!NS_IsMainThread());
     MOZ_ASSERT(mOmxReader.get());
-    mOmxReader->ProcessCachedData(mOffset, false);
+    mOmxReader->ProcessCachedData(mOffset);
   }
 
 private:
   nsRefPtr<MediaOmxReader> mOmxReader;
   int64_t                  mOffset;
 };
 
 // When loading an MP3 stream from a file, we need to parse the file's
@@ -65,65 +65,57 @@ private:
 // a task to the IO thread for retrieving the next chunk of data, and
 // the IO task dispatches a runnable to the main thread for parsing the
 // data. This goes on until all of the MP3 file has been parsed.
 
 class MediaOmxReader::NotifyDataArrivedRunnable : public nsRunnable
 {
 public:
   NotifyDataArrivedRunnable(MediaOmxReader* aOmxReader,
-                                     const char* aBuffer, uint64_t aLength,
-                                     int64_t aOffset, uint64_t aFullLength)
+                            uint64_t aLength,
+                            int64_t aOffset, uint64_t aFullLength)
   : mOmxReader(aOmxReader),
-    mBuffer(aBuffer),
     mLength(aLength),
     mOffset(aOffset),
     mFullLength(aFullLength)
   {
     MOZ_ASSERT(mOmxReader.get());
-    MOZ_ASSERT(mBuffer.get() || !mLength);
   }
 
   NS_IMETHOD Run()
   {
-    NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
-
+    MOZ_ASSERT(mOmxReader->OnTaskQueue());
     NotifyDataArrived();
-
     return NS_OK;
   }
 
 private:
   void NotifyDataArrived()
   {
     if (mOmxReader->IsShutdown()) {
       return;
     }
-    const char* buffer = mBuffer.get();
 
     while (mLength) {
       uint32_t length = std::min<uint64_t>(mLength, UINT32_MAX);
-      mOmxReader->NotifyDataArrived(buffer, length,
-                                    mOffset);
-      buffer  += length;
+      mOmxReader->NotifyDataArrived(length, mOffset);
       mLength -= length;
       mOffset += length;
     }
 
     if (static_cast<uint64_t>(mOffset) < mFullLength) {
       // We cannot read data in the main thread because it
       // might block for too long. Instead we post an IO task
       // to the IO thread if there is more data available.
       XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
           new ProcessCachedDataTask(mOmxReader.get(), mOffset));
     }
   }
 
   nsRefPtr<MediaOmxReader>         mOmxReader;
-  nsAutoArrayPtr<const char>       mBuffer;
   uint64_t                         mLength;
   int64_t                          mOffset;
   uint64_t                         mFullLength;
 };
 
 MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder)
   : MediaOmxCommonReader(aDecoder)
   , mShutdownMutex("MediaOmxReader.Shutdown")
@@ -240,17 +232,17 @@ MediaOmxReader::AsyncReadMetadata()
   }
 
   bool isMP3 = mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3);
   if (isMP3) {
     // When read sdcard's file on b2g platform at constructor,
     // the mDecoder->GetResource()->GetLength() would return -1.
     // Delay set the total duration on this function.
     mMP3FrameParser.SetLength(mDecoder->GetResource()->GetLength());
-    ProcessCachedData(0, true);
+    ProcessCachedData(0);
   }
 
   nsRefPtr<MediaDecoderReader::MetadataPromise> p = mMetadataPromise.Ensure(__func__);
 
   nsRefPtr<MediaOmxReader> self = this;
   mMediaResourceRequest.Begin(mOmxDecoder->AllocateMediaResources()
     ->Then(TaskQueue(), __func__,
       [self] (bool) -> void {
@@ -463,31 +455,33 @@ bool MediaOmxReader::DecodeVideoFrame(bo
     mVideoQueue.Push(v);
 
     break;
   }
 
   return true;
 }
 
-void MediaOmxReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
+void MediaOmxReader::NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset)
 {
-  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(OnTaskQueue());
   nsRefPtr<AbstractMediaDecoder> decoder = SafeGetDecoder();
   if (!decoder) { // reader has shut down
     return;
   }
   if (HasVideo()) {
     return;
   }
   if (!mMP3FrameParser.NeedsData()) {
     return;
   }
 
-  mMP3FrameParser.Parse(aBuffer, aLength, aOffset);
+  nsRefPtr<MediaByteBuffer> bytes = mDecoder->GetResource()->SilentReadAt(aOffset, aLength);
+  NS_ENSURE_TRUE_VOID(bytes);
+  mMP3FrameParser.Parse(bytes->Elements(), aLength, aOffset);
   if (!mMP3FrameParser.IsMP3()) {
     return;
   }
 
   int64_t duration = mMP3FrameParser.GetDuration();
   if (duration != mLastParserDuration) {
     mLastParserDuration = duration;
     decoder->DispatchUpdateEstimatedMediaDuration(mLastParserDuration);
@@ -568,17 +562,17 @@ void MediaOmxReader::SetIdle() {
 void MediaOmxReader::EnsureActive() {
   if (!mOmxDecoder.get()) {
     return;
   }
   DebugOnly<nsresult> result = mOmxDecoder->Play();
   NS_ASSERTION(result == NS_OK, "OmxDecoder should be in play state to continue decoding");
 }
 
-int64_t MediaOmxReader::ProcessCachedData(int64_t aOffset, bool aWaitForCompletion)
+int64_t MediaOmxReader::ProcessCachedData(int64_t aOffset)
 {
   // Could run on decoder thread or IO thread.
   nsRefPtr<AbstractMediaDecoder> decoder = SafeGetDecoder();
   if (!decoder) { // reader has shut down
     return -1;
   }
   // We read data in chunks of 32 KiB. We can reduce this
   // value if media, such as sdcards, is too slow.
@@ -592,32 +586,24 @@ int64_t MediaOmxReader::ProcessCachedDat
   int64_t resourceLength = decoder->GetResource()->GetCachedDataEnd(0);
   NS_ENSURE_TRUE(resourceLength >= 0, -1);
 
   if (aOffset >= resourceLength) {
     return 0; // Cache is empty, nothing to do
   }
 
   int64_t bufferLength = std::min<int64_t>(resourceLength-aOffset, sReadSize);
-
-  nsAutoArrayPtr<char> buffer(new char[bufferLength]);
-
-  nsresult rv = decoder->GetResource()->ReadFromCache(buffer.get(),
-                                                       aOffset, bufferLength);
-  NS_ENSURE_SUCCESS(rv, -1);
+  nsRefPtr<NotifyDataArrivedRunnable> runnable(
+    new NotifyDataArrivedRunnable(this, bufferLength, aOffset, resourceLength));
 
-  nsRefPtr<NotifyDataArrivedRunnable> runnable(
-    new NotifyDataArrivedRunnable(this, buffer.forget(), bufferLength,
-                                  aOffset, resourceLength));
-  if (aWaitForCompletion) {
-    rv = NS_DispatchToMainThread(runnable.get(), NS_DISPATCH_SYNC);
+  if (OnTaskQueue()) {
+    runnable->Run();
   } else {
-    rv = NS_DispatchToMainThread(runnable.get());
+    TaskQueue()->Dispatch(runnable.forget());
   }
-  NS_ENSURE_SUCCESS(rv, -1);
 
   return resourceLength - aOffset - bufferLength;
 }
 
 android::sp<android::MediaSource> MediaOmxReader::GetAudioOffloadTrack()
 {
   if (!mOmxDecoder.get()) {
     return nullptr;
--- a/dom/media/omx/MediaOmxReader.h
+++ b/dom/media/omx/MediaOmxReader.h
@@ -64,17 +64,19 @@ protected:
   virtual void HandleResourceAllocated();
 
 public:
   MediaOmxReader(AbstractMediaDecoder* aDecoder);
   ~MediaOmxReader();
 
   virtual nsresult Init(MediaDecoderReader* aCloneDonor);
 
-  virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
+protected:
+  virtual void NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset) override;
+public:
 
   virtual bool DecodeAudioData();
   virtual bool DecodeVideoFrame(bool &aKeyframeSkip,
                                 int64_t aTimeThreshold);
 
   virtual bool HasAudio()
   {
     return mHasAudio;
@@ -109,16 +111,16 @@ private:
   class ProcessCachedDataTask;
   class NotifyDataArrivedRunnable;
 
   bool IsShutdown() {
     MutexAutoLock lock(mShutdownMutex);
     return mIsShutdown;
   }
 
-  int64_t ProcessCachedData(int64_t aOffset, bool aWaitForCompletion);
+  int64_t ProcessCachedData(int64_t aOffset);
 
   already_AddRefed<AbstractMediaDecoder> SafeGetDecoder();
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/webaudio/BufferDecoder.cpp
+++ b/dom/media/webaudio/BufferDecoder.cpp
@@ -149,17 +149,17 @@ BufferDecoder::OnReadMetadataCompleted()
 
 void
 BufferDecoder::NotifyWaitingForResourcesStatusChanged()
 {
   // ignore
 }
 
 void
-BufferDecoder::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
+BufferDecoder::NotifyDataArrived(uint32_t aLength, int64_t aOffset)
 {
   // ignore
 }
 
 MediaDecoderOwner*
 BufferDecoder::GetOwner()
 {
   // unknown
--- a/dom/media/webaudio/BufferDecoder.h
+++ b/dom/media/webaudio/BufferDecoder.h
@@ -64,17 +64,17 @@ public:
   virtual void RemoveMediaTracks() final override;
 
   virtual void OnReadMetadataCompleted() final override;
 
   virtual MediaDecoderOwner* GetOwner() final override;
 
   virtual void NotifyWaitingForResourcesStatusChanged() final override;
 
-  virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) final override;
+  virtual void NotifyDataArrived(uint32_t aLength, int64_t aOffset) final override;
 
 private:
   virtual ~BufferDecoder();
 
   // This monitor object is not really used to synchronize access to anything.
   // It's just there in order for us to be able to override
   // GetReentrantMonitor correctly.
   ReentrantMonitor mReentrantMonitor;
--- a/dom/media/webm/WebMBufferedParser.cpp
+++ b/dom/media/webm/WebMBufferedParser.cpp
@@ -295,19 +295,18 @@ bool WebMBufferedState::GetOffsetForTime
   if (idx == mTimeMapping.Length()) {
     return false;
   }
 
   *aOffset = mTimeMapping[idx].mSyncOffset;
   return true;
 }
 
-void WebMBufferedState::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
+void WebMBufferedState::NotifyDataArrived(const unsigned char* aBuffer, uint32_t aLength, int64_t aOffset)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   uint32_t idx = mRangeParsers.IndexOfFirstElementGt(aOffset - 1);
   if (idx == 0 || !(mRangeParsers[idx-1] == aOffset)) {
     // If the incoming data overlaps an already parsed range, adjust the
     // buffer so that we only reparse the new data.  It's also possible to
     // have an overlap where the end of the incoming data is within an
     // already parsed range, but we don't bother handling that other than by
     // avoiding storing duplicate timecodes when the parser runs.
     if (idx != mRangeParsers.Length() && mRangeParsers[idx].mStartOffset <= aOffset) {
@@ -324,17 +323,17 @@ void WebMBufferedState::NotifyDataArrive
     } else {
       mRangeParsers.InsertElementAt(idx, WebMBufferedParser(aOffset));
       if (idx != 0) {
         mRangeParsers[idx].SetTimecodeScale(mRangeParsers[0].GetTimecodeScale());
       }
     }
   }
 
-  mRangeParsers[idx].Append(reinterpret_cast<const unsigned char*>(aBuffer),
+  mRangeParsers[idx].Append(aBuffer,
                             aLength,
                             mTimeMapping,
                             mReentrantMonitor);
 
   // Merge parsers with overlapping regions and clean up the remnants.
   uint32_t i = 0;
   while (i + 1 < mRangeParsers.Length()) {
     if (mRangeParsers[i].mCurrentOffset >= mRangeParsers[i + 1].mStartOffset) {
--- a/dom/media/webm/WebMBufferedParser.h
+++ b/dom/media/webm/WebMBufferedParser.h
@@ -223,17 +223,17 @@ class WebMBufferedState final
 {
   NS_INLINE_DECL_REFCOUNTING(WebMBufferedState)
 
 public:
   WebMBufferedState() : mReentrantMonitor("WebMBufferedState") {
     MOZ_COUNT_CTOR(WebMBufferedState);
   }
 
-  void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
+  void NotifyDataArrived(const unsigned char* aBuffer, uint32_t aLength, int64_t aOffset);
   bool CalculateBufferedForRange(int64_t aStartOffset, int64_t aEndOffset,
                                  uint64_t* aStartTime, uint64_t* aEndTime);
 
   // Returns true if aTime is is present in mTimeMapping and sets aOffset to
   // the latest offset for which decoding can resume without data
   // dependencies to arrive at aTime.
   bool GetOffsetForTime(uint64_t aTime, int64_t* aOffset);
 
--- a/dom/media/webm/WebMReader.cpp
+++ b/dom/media/webm/WebMReader.cpp
@@ -1140,20 +1140,22 @@ media::TimeIntervals WebMReader::GetBuff
       buffered += media::TimeInterval(media::TimeUnit::FromSeconds(startTime),
                                       media::TimeUnit::FromSeconds(endTime));
     }
   }
 
   return buffered;
 }
 
-void WebMReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength,
-                                   int64_t aOffset)
+void WebMReader::NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset)
 {
-  mBufferedState->NotifyDataArrived(aBuffer, aLength, aOffset);
+  MOZ_ASSERT(OnTaskQueue());
+  nsRefPtr<MediaByteBuffer> bytes = mDecoder->GetResource()->SilentReadAt(aOffset, aLength);
+  NS_ENSURE_TRUE_VOID(bytes);
+  mBufferedState->NotifyDataArrived(bytes->Elements(), aLength, aOffset);
 }
 
 int64_t WebMReader::GetEvictionOffset(double aTime)
 {
   int64_t offset;
   if (!mBufferedState->GetOffsetForTime(aTime * NS_PER_S, &offset)) {
     return -1;
   }
--- a/dom/media/webm/WebMReader.h
+++ b/dom/media/webm/WebMReader.h
@@ -168,18 +168,16 @@ public:
   }
 
   virtual nsresult ReadMetadata(MediaInfo* aInfo,
                                 MetadataTags** aTags) override;
   virtual nsRefPtr<SeekPromise>
   Seek(int64_t aTime, int64_t aEndTime) override;
 
   virtual media::TimeIntervals GetBuffered() override;
-  virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength,
-                                 int64_t aOffset) override;
   virtual int64_t GetEvictionOffset(double aTime) override;
 
   virtual bool IsMediaSeekable() override;
 
   // Value passed to NextPacket to determine if we are reading a video or an
   // audio packet.
   enum TrackType {
     VIDEO = 0,
@@ -201,16 +199,18 @@ public:
   void SetLastVideoFrameTime(int64_t aFrameTime);
   layers::LayersBackend GetLayersBackendType() { return mLayersBackendType; }
   FlushableMediaTaskQueue* GetVideoTaskQueue() { return mVideoTaskQueue; }
 
 protected:
   // Setup opus decoder
   bool InitOpusDecoder();
 
+  virtual void NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset) override;
+
   // Decode a nestegg packet of audio data. Push the audio data on the
   // audio queue. Returns true when there's more audio to decode,
   // false if the audio is finished, end of file has been reached,
   // or an un-recoverable read error has occured. The reader's monitor
   // must be held during this call. The caller is responsible for freeing
   // aPacket.
   bool DecodeAudioPacket(NesteggPacketHolder* aHolder);
   bool DecodeVorbis(const unsigned char* aData, size_t aLength,