merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 06 Jul 2015 11:31:27 +0200
changeset 251448 cef11c3e86c3ab51adcb2a6c341d4a9864e63aff
parent 251427 0bc555946d99ef74b99cffd0a3aa47064b2a3df1 (current diff)
parent 251447 f9aaae416bbb2443bc0cca174a76619b0c60e7ae (diff)
child 251457 c6288350c268d2b00dce44d7bc22c5edd1fe894d
child 251480 8a02b5e8f72caf95e0ec5be5da59fa4de1893bba
child 251504 0d861d613927ac8b6b95dcf79b10917d80a96a0f
push id28999
push usercbook@mozilla.com
push dateMon, 06 Jul 2015 09:37:03 +0000
treeherdermozilla-central@cef11c3e86c3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone42.0a1
first release with
nightly linux32
cef11c3e86c3 / 42.0a1 / 20150706030206 / files
nightly linux64
cef11c3e86c3 / 42.0a1 / 20150706030206 / files
nightly mac
cef11c3e86c3 / 42.0a1 / 20150706030206 / files
nightly win32
cef11c3e86c3 / 42.0a1 / 20150706030206 / files
nightly win64
cef11c3e86c3 / 42.0a1 / 20150706030206 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
dom/media/omx/mediaresourcemanager/IMediaResourceManagerClient.cpp
dom/media/omx/mediaresourcemanager/IMediaResourceManagerClient.h
dom/media/omx/mediaresourcemanager/IMediaResourceManagerDeathNotifier.cpp
dom/media/omx/mediaresourcemanager/IMediaResourceManagerDeathNotifier.h
dom/media/omx/mediaresourcemanager/IMediaResourceManagerService.cpp
dom/media/omx/mediaresourcemanager/IMediaResourceManagerService.h
dom/media/omx/mediaresourcemanager/MediaResourceHandler.cpp
dom/media/omx/mediaresourcemanager/MediaResourceHandler.h
dom/media/omx/mediaresourcemanager/MediaResourceManagerClient.cpp
dom/media/omx/mediaresourcemanager/MediaResourceManagerClient.h
dom/media/omx/mediaresourcemanager/MediaResourceManagerService.cpp
dom/media/omx/mediaresourcemanager/MediaResourceManagerService.h
dom/media/omx/mediaresourcemanager/moz.build
--- a/dom/media/DecodedStream.cpp
+++ b/dom/media/DecodedStream.cpp
@@ -1,17 +1,23 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DecodedStream.h"
 #include "MediaStreamGraph.h"
-#include "mozilla/ReentrantMonitor.h"
+#include "AudioSegment.h"
+#include "VideoSegment.h"
+#include "MediaQueue.h"
+#include "MediaData.h"
+#include "MediaInfo.h"
+#include "SharedBuffer.h"
+#include "VideoUtils.h"
 
 namespace mozilla {
 
 class DecodedStreamGraphListener : public MediaStreamListener {
   typedef MediaStreamListener::MediaStreamGraphEvent MediaStreamGraphEvent;
 public:
   explicit DecodedStreamGraphListener(MediaStream* aStream)
     : mMutex("DecodedStreamGraphListener::mMutex")
@@ -77,32 +83,35 @@ UpdateStreamBlocking(MediaStream* aStrea
     aStream->ChangeExplicitBlockerCount(delta);
   } else {
     nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethodWithArg<int32_t>(
       aStream, &MediaStream::ChangeExplicitBlockerCount, delta);
     AbstractThread::MainThread()->Dispatch(r.forget());
   }
 }
 
-DecodedStreamData::DecodedStreamData(SourceMediaStream* aStream)
+DecodedStreamData::DecodedStreamData(SourceMediaStream* aStream, bool aPlaying)
   : mAudioFramesWritten(0)
   , mNextVideoTime(-1)
   , mNextAudioTime(-1)
   , mStreamInitialized(false)
   , mHaveSentFinish(false)
   , mHaveSentFinishAudio(false)
   , mHaveSentFinishVideo(false)
   , mStream(aStream)
-  , mPlaying(false)
+  , mPlaying(aPlaying)
   , mEOSVideoCompensation(false)
 {
   mListener = new DecodedStreamGraphListener(mStream);
   mStream->AddListener(mListener);
-  // Block the stream as mPlaying is initially false.
-  UpdateStreamBlocking(mStream, true);
+
+  // Block the stream if we are not playing.
+  if (!aPlaying) {
+    UpdateStreamBlocking(mStream, true);
+  }
 }
 
 DecodedStreamData::~DecodedStreamData()
 {
   mListener->Forget();
   mStream->Destroy();
 }
 
@@ -147,36 +156,19 @@ public:
     MOZ_ASSERT(NS_IsMainThread());
     mDecodedStream = nullptr;
   }
 
 private:
   void DoNotifyFinished()
   {
     MOZ_ASSERT(NS_IsMainThread());
-    if (!mDecodedStream) {
-      return;
-    }
-
-    // Remove the finished stream so it won't block the decoded stream.
-    ReentrantMonitorAutoEnter mon(mDecodedStream->GetReentrantMonitor());
-    auto& streams = mDecodedStream->OutputStreams();
-    // Don't read |mDecodedStream| in the loop since removing the element will lead
-    // to ~OutputStreamData() which will call Forget() to reset |mDecodedStream|.
-    for (int32_t i = streams.Length() - 1; i >= 0; --i) {
-      auto& os = streams[i];
-      MediaStream* p = os.mStream.get();
-      if (p == mStream.get()) {
-        if (os.mPort) {
-          os.mPort->Destroy();
-          os.mPort = nullptr;
-        }
-        streams.RemoveElementAt(i);
-        break;
-      }
+    if (mDecodedStream) {
+      // Remove the finished stream so it won't block the decoded stream.
+      mDecodedStream->Remove(mStream);
     }
   }
 
   // Main thread only
   DecodedStream* mDecodedStream;
   nsRefPtr<MediaStream> mStream;
 };
 
@@ -190,27 +182,21 @@ OutputStreamData::Init(DecodedStream* aD
 {
   mStream = aStream;
   mListener = new OutputStreamListener(aDecodedStream, aStream);
   aStream->AddListener(mListener);
 }
 
 DecodedStream::DecodedStream()
   : mMonitor("DecodedStream::mMonitor")
+  , mPlaying(false)
 {
   //
 }
 
-DecodedStreamData*
-DecodedStream::GetData() const
-{
-  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
-  return mData.get();
-}
-
 void
 DecodedStream::DestroyData()
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
 
   // Avoid the redundant blocking to output stream.
   if (!mData) {
@@ -237,44 +223,55 @@ DecodedStream::DestroyData()
       os.mStream->ChangeExplicitBlockerCount(1);
     }
   }
 
   mData = nullptr;
 }
 
 void
+DecodedStream::RecreateData()
+{
+  nsRefPtr<DecodedStream> self = this;
+  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self] () -> void {
+    self->RecreateData(nullptr);
+  });
+  AbstractThread::MainThread()->Dispatch(r.forget());
+}
+
+void
 DecodedStream::RecreateData(MediaStreamGraph* aGraph)
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   MOZ_ASSERT((aGraph && !mData && OutputStreams().IsEmpty()) || // first time
              (!aGraph && mData)); // 2nd time and later
 
   if (!aGraph) {
     aGraph = mData->mStream->Graph();
   }
   auto source = aGraph->CreateSourceStream(nullptr);
   DestroyData();
-  mData.reset(new DecodedStreamData(source));
+  mData.reset(new DecodedStreamData(source, mPlaying));
 
   // Note that the delay between removing ports in DestroyDecodedStream
   // and adding new ones won't cause a glitch since all graph operations
   // between main-thread stable states take effect atomically.
   auto& outputStreams = OutputStreams();
   for (int32_t i = outputStreams.Length() - 1; i >= 0; --i) {
     OutputStreamData& os = outputStreams[i];
     MOZ_ASSERT(!os.mStream->IsDestroyed(), "Should've been removed in DestroyData()");
     Connect(&os);
   }
 }
 
 nsTArray<OutputStreamData>&
 DecodedStream::OutputStreams()
 {
+  MOZ_ASSERT(NS_IsMainThread());
   GetReentrantMonitor().AssertCurrentThreadIn();
   return mOutputStreams;
 }
 
 ReentrantMonitor&
 DecodedStream::GetReentrantMonitor() const
 {
   return mMonitor;
@@ -297,26 +294,380 @@ DecodedStream::Connect(OutputStreamData*
 }
 
 void
 DecodedStream::Connect(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
 
+  if (!mData) {
+    RecreateData(aStream->Graph());
+  }
+
   OutputStreamData* os = OutputStreams().AppendElement();
   os->Init(this, aStream);
   Connect(os);
   if (aFinishWhenEnded) {
     // Ensure that aStream finishes the moment mDecodedStream does.
     aStream->SetAutofinish(true);
   }
 }
 
 void
+DecodedStream::Remove(MediaStream* aStream)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+
+  auto& streams = OutputStreams();
+  for (int32_t i = streams.Length() - 1; i >= 0; --i) {
+    auto& os = streams[i];
+    MediaStream* p = os.mStream.get();
+    if (p == aStream) {
+      if (os.mPort) {
+        os.mPort->Destroy();
+        os.mPort = nullptr;
+      }
+      streams.RemoveElementAt(i);
+      break;
+    }
+  }
+}
+
+void
 DecodedStream::SetPlaying(bool aPlaying)
 {
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
-  MOZ_ASSERT(mData);
-  mData->SetPlaying(aPlaying);
+  mPlaying = aPlaying;
+  if (mData) {
+    mData->SetPlaying(aPlaying);
+  }
+}
+
+bool
+DecodedStream::HaveEnoughAudio(const MediaInfo& aInfo) const
+{
+  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+
+  if (mData->mStreamInitialized && !mData->mHaveSentFinishAudio) {
+    MOZ_ASSERT(aInfo.HasAudio());
+    TrackID audioTrackId = aInfo.mAudio.mTrackId;
+    if (!mData->mStream->HaveEnoughBuffered(audioTrackId)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool
+DecodedStream::HaveEnoughVideo(const MediaInfo& aInfo) const
+{
+  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+
+  if (mData->mStreamInitialized && !mData->mHaveSentFinishVideo) {
+    MOZ_ASSERT(aInfo.HasVideo());
+    TrackID videoTrackId = aInfo.mVideo.mTrackId;
+    if (!mData->mStream->HaveEnoughBuffered(videoTrackId)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+void
+DecodedStream::InitTracks(int64_t aStartTime, const MediaInfo& aInfo)
+{
+  GetReentrantMonitor().AssertCurrentThreadIn();
+
+  if (mData->mStreamInitialized) {
+    return;
+  }
+
+  SourceMediaStream* sourceStream = mData->mStream;
+
+  if (aInfo.HasAudio()) {
+    TrackID audioTrackId = aInfo.mAudio.mTrackId;
+    AudioSegment* audio = new AudioSegment();
+    sourceStream->AddAudioTrack(audioTrackId, aInfo.mAudio.mRate, 0, audio,
+                                SourceMediaStream::ADDTRACK_QUEUED);
+    mData->mNextAudioTime = aStartTime;
+  }
+
+  if (aInfo.HasVideo()) {
+    TrackID videoTrackId = aInfo.mVideo.mTrackId;
+    VideoSegment* video = new VideoSegment();
+    sourceStream->AddTrack(videoTrackId, 0, video,
+                           SourceMediaStream::ADDTRACK_QUEUED);
+    mData->mNextVideoTime = aStartTime;
+  }
+
+  sourceStream->FinishAddTracks();
+  mData->mStreamInitialized = true;
+}
+
+static void
+SendStreamAudio(DecodedStreamData* aStream, int64_t aStartTime,
+                AudioData* aAudio, AudioSegment* aOutput,
+                uint32_t aRate, double aVolume)
+{
+  // This logic has to mimic AudioSink closely to make sure we write
+  // the exact same silences
+  CheckedInt64 audioWrittenOffset = aStream->mAudioFramesWritten +
+                                    UsecsToFrames(aStartTime, aRate);
+  CheckedInt64 frameOffset = UsecsToFrames(aAudio->mTime, aRate);
+
+  if (!audioWrittenOffset.isValid() ||
+      !frameOffset.isValid() ||
+      // ignore packet that we've already processed
+      frameOffset.value() + aAudio->mFrames <= audioWrittenOffset.value()) {
+    return;
+  }
+
+  if (audioWrittenOffset.value() < frameOffset.value()) {
+    int64_t silentFrames = frameOffset.value() - audioWrittenOffset.value();
+    // Write silence to catch up
+    AudioSegment silence;
+    silence.InsertNullDataAtStart(silentFrames);
+    aStream->mAudioFramesWritten += silentFrames;
+    audioWrittenOffset += silentFrames;
+    aOutput->AppendFrom(&silence);
+  }
+
+  MOZ_ASSERT(audioWrittenOffset.value() >= frameOffset.value());
+
+  int64_t offset = audioWrittenOffset.value() - frameOffset.value();
+  size_t framesToWrite = aAudio->mFrames - offset;
+
+  aAudio->EnsureAudioBuffer();
+  nsRefPtr<SharedBuffer> buffer = aAudio->mAudioBuffer;
+  AudioDataValue* bufferData = static_cast<AudioDataValue*>(buffer->Data());
+  nsAutoTArray<const AudioDataValue*, 2> channels;
+  for (uint32_t i = 0; i < aAudio->mChannels; ++i) {
+    channels.AppendElement(bufferData + i * aAudio->mFrames + offset);
+  }
+  aOutput->AppendFrames(buffer.forget(), channels, framesToWrite);
+  aStream->mAudioFramesWritten += framesToWrite;
+  aOutput->ApplyVolume(aVolume);
+
+  aStream->mNextAudioTime = aAudio->GetEndTime();
+}
+
+void
+DecodedStream::SendAudio(int64_t aStartTime,
+                         const MediaInfo& aInfo,
+                         MediaQueue<AudioData>& aQueue,
+                         double aVolume, bool aIsSameOrigin)
+{
+  GetReentrantMonitor().AssertCurrentThreadIn();
+
+  if (!aInfo.HasAudio()) {
+    return;
+  }
+
+  AudioSegment output;
+  uint32_t rate = aInfo.mAudio.mRate;
+  nsAutoTArray<nsRefPtr<AudioData>,10> audio;
+  TrackID audioTrackId = aInfo.mAudio.mTrackId;
+  SourceMediaStream* sourceStream = mData->mStream;
+
+  // It's OK to hold references to the AudioData because AudioData
+  // is ref-counted.
+  aQueue.GetElementsAfter(mData->mNextAudioTime, &audio);
+  for (uint32_t i = 0; i < audio.Length(); ++i) {
+    SendStreamAudio(mData.get(), aStartTime, audio[i], &output, rate, aVolume);
+  }
+
+  if (!aIsSameOrigin) {
+    output.ReplaceWithDisabled();
+  }
+
+  // |mNextAudioTime| is updated as we process each audio sample in
+  // SendStreamAudio(). This is consistent with how |mNextVideoTime|
+  // is updated for video samples.
+  if (output.GetDuration() > 0) {
+    sourceStream->AppendToTrack(audioTrackId, &output);
+  }
+
+  if (aQueue.IsFinished() && !mData->mHaveSentFinishAudio) {
+    sourceStream->EndTrack(audioTrackId);
+    mData->mHaveSentFinishAudio = true;
+  }
+}
+
+static void
+WriteVideoToMediaStream(MediaStream* aStream,
+                        layers::Image* aImage,
+                        int64_t aEndMicroseconds,
+                        int64_t aStartMicroseconds,
+                        const mozilla::gfx::IntSize& aIntrinsicSize,
+                        VideoSegment* aOutput)
+{
+  nsRefPtr<layers::Image> image = aImage;
+  StreamTime duration =
+      aStream->MicrosecondsToStreamTimeRoundDown(aEndMicroseconds) -
+      aStream->MicrosecondsToStreamTimeRoundDown(aStartMicroseconds);
+  aOutput->AppendFrame(image.forget(), duration, aIntrinsicSize);
+}
+
+static bool
+ZeroDurationAtLastChunk(VideoSegment& aInput)
+{
+  // Get the last video frame's start time in VideoSegment aInput.
+  // If the start time is equal to the duration of aInput, means the last video
+  // frame's duration is zero.
+  StreamTime lastVideoStratTime;
+  aInput.GetLastFrame(&lastVideoStratTime);
+  return lastVideoStratTime == aInput.GetDuration();
+}
+
+void
+DecodedStream::SendVideo(int64_t aStartTime,
+                         const MediaInfo& aInfo,
+                         MediaQueue<VideoData>& aQueue,
+                         bool aIsSameOrigin)
+{
+  GetReentrantMonitor().AssertCurrentThreadIn();
+
+  if (!aInfo.HasVideo()) {
+    return;
+  }
+
+  VideoSegment output;
+  TrackID videoTrackId = aInfo.mVideo.mTrackId;
+  nsAutoTArray<nsRefPtr<VideoData>, 10> video;
+  SourceMediaStream* sourceStream = mData->mStream;
+
+  // It's OK to hold references to the VideoData because VideoData
+  // is ref-counted.
+  aQueue.GetElementsAfter(mData->mNextVideoTime, &video);
+
+  for (uint32_t i = 0; i < video.Length(); ++i) {
+    VideoData* v = video[i];
+
+    if (mData->mNextVideoTime < v->mTime) {
+      // Write last video frame to catch up. mLastVideoImage can be null here
+      // which is fine, it just means there's no video.
+
+      // TODO: |mLastVideoImage| should come from the last image rendered
+      // by the state machine. This will avoid the black frame when capture
+      // happens in the middle of playback (especially in th middle of a
+      // video frame). E.g. if we have a video frame that is 30 sec long
+      // and capture happens at 15 sec, we'll have to append a black frame
+      // that is 15 sec long.
+      WriteVideoToMediaStream(sourceStream, mData->mLastVideoImage, v->mTime,
+          mData->mNextVideoTime, mData->mLastVideoImageDisplaySize, &output);
+      mData->mNextVideoTime = v->mTime;
+    }
+
+    if (mData->mNextVideoTime < v->GetEndTime()) {
+      WriteVideoToMediaStream(sourceStream, v->mImage,
+          v->GetEndTime(), mData->mNextVideoTime, v->mDisplay, &output);
+      mData->mNextVideoTime = v->GetEndTime();
+      mData->mLastVideoImage = v->mImage;
+      mData->mLastVideoImageDisplaySize = v->mDisplay;
+    }
+  }
+
+  // Check the output is not empty.
+  if (output.GetLastFrame()) {
+    mData->mEOSVideoCompensation = ZeroDurationAtLastChunk(output);
+  }
+
+  if (!aIsSameOrigin) {
+    output.ReplaceWithDisabled();
+  }
+
+  if (output.GetDuration() > 0) {
+    sourceStream->AppendToTrack(videoTrackId, &output);
+  }
+
+  if (aQueue.IsFinished() && !mData->mHaveSentFinishVideo) {
+    if (mData->mEOSVideoCompensation) {
+      VideoSegment endSegment;
+      // Calculate the deviation clock time from DecodedStream.
+      int64_t deviation_usec = sourceStream->StreamTimeToMicroseconds(1);
+      WriteVideoToMediaStream(sourceStream, mData->mLastVideoImage,
+          mData->mNextVideoTime + deviation_usec, mData->mNextVideoTime,
+          mData->mLastVideoImageDisplaySize, &endSegment);
+      mData->mNextVideoTime += deviation_usec;
+      MOZ_ASSERT(endSegment.GetDuration() > 0);
+      if (!aIsSameOrigin) {
+        endSegment.ReplaceWithDisabled();
+      }
+      sourceStream->AppendToTrack(videoTrackId, &endSegment);
+    }
+    sourceStream->EndTrack(videoTrackId);
+    mData->mHaveSentFinishVideo = true;
+  }
+}
+
+void
+DecodedStream::AdvanceTracks(int64_t aStartTime, const MediaInfo& aInfo)
+{
+  GetReentrantMonitor().AssertCurrentThreadIn();
+
+  StreamTime endPosition = 0;
+
+  if (aInfo.HasAudio()) {
+    StreamTime audioEnd = mData->mStream->TicksToTimeRoundDown(
+        aInfo.mAudio.mRate, mData->mAudioFramesWritten);
+    endPosition = std::max(endPosition, audioEnd);
+  }
+
+  if (aInfo.HasVideo()) {
+    StreamTime videoEnd = mData->mStream->MicrosecondsToStreamTimeRoundDown(
+        mData->mNextVideoTime - aStartTime);
+    endPosition = std::max(endPosition, videoEnd);
+  }
+
+  if (!mData->mHaveSentFinish) {
+    mData->mStream->AdvanceKnownTracksTime(endPosition);
+  }
+}
+
+bool
+DecodedStream::SendData(int64_t aStartTime,
+                        const MediaInfo& aInfo,
+                        MediaQueue<AudioData>& aAudioQueue,
+                        MediaQueue<VideoData>& aVideoQueue,
+                        double aVolume, bool aIsSameOrigin)
+{
+  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+
+  InitTracks(aStartTime, aInfo);
+  SendAudio(aStartTime, aInfo, aAudioQueue, aVolume, aIsSameOrigin);
+  SendVideo(aStartTime, aInfo, aVideoQueue, aIsSameOrigin);
+  AdvanceTracks(aStartTime, aInfo);
+
+  bool finished = (!aInfo.HasAudio() || aAudioQueue.IsFinished()) &&
+                  (!aInfo.HasVideo() || aVideoQueue.IsFinished());
+
+  if (finished && !mData->mHaveSentFinish) {
+    mData->mHaveSentFinish = true;
+    mData->mStream->Finish();
+  }
+
+  return finished;
+}
+
+CheckedInt64
+DecodedStream::AudioEndTime(int64_t aStartTime, uint32_t aRate) const
+{
+  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+  return aStartTime + FramesToUsecs(mData->mAudioFramesWritten, aRate);
+}
+
+int64_t
+DecodedStream::GetPosition() const
+{
+  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+  return mData->GetPosition();
+}
+
+bool
+DecodedStream::IsFinished() const
+{
+  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+  return mData->IsFinished();
 }
 
 } // namespace mozilla
--- a/dom/media/DecodedStream.h
+++ b/dom/media/DecodedStream.h
@@ -4,45 +4,55 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef DecodedStream_h_
 #define DecodedStream_h_
 
 #include "nsRefPtr.h"
 #include "nsTArray.h"
+
 #include "mozilla/UniquePtr.h"
 #include "mozilla/gfx/Point.h"
+#include "mozilla/CheckedInt.h"
+#include "mozilla/ReentrantMonitor.h"
 
 namespace mozilla {
 
+class AudioData;
+class VideoData;
+class MediaInfo;
+class AudioSegment;
+class MediaStream;
 class MediaInputPort;
 class SourceMediaStream;
 class ProcessedMediaStream;
 class DecodedStream;
 class DecodedStreamGraphListener;
 class OutputStreamListener;
 class ReentrantMonitor;
 class MediaStreamGraph;
 
+template <class T> class MediaQueue;
+
 namespace layers {
 class Image;
 }
 
 /*
  * All MediaStream-related data is protected by the decoder's monitor.
  * We have at most one DecodedStreamDaata per MediaDecoder. Its stream
  * is used as the input for each ProcessedMediaStream created by calls to
  * captureStream(UntilEnded). Seeking creates a new source stream, as does
  * replaying after the input as ended. In the latter case, the new source is
  * not connected to streams created by captureStreamUntilEnded.
  */
 class DecodedStreamData {
 public:
-  explicit DecodedStreamData(SourceMediaStream* aStream);
+  DecodedStreamData(SourceMediaStream* aStream, bool aPlaying);
   ~DecodedStreamData();
   bool IsFinished() const;
   int64_t GetPosition() const;
   void SetPlaying(bool aPlaying);
 
   /* The following group of fields are protected by the decoder's monitor
    * and can be read or written on any thread.
    */
@@ -79,38 +89,69 @@ public:
   void Init(DecodedStream* aDecodedStream, ProcessedMediaStream* aStream);
   nsRefPtr<ProcessedMediaStream> mStream;
   // mPort connects DecodedStreamData::mStream to our mStream.
   nsRefPtr<MediaInputPort> mPort;
   nsRefPtr<OutputStreamListener> mListener;
 };
 
 class DecodedStream {
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecodedStream);
 public:
   DecodedStream();
-  DecodedStreamData* GetData() const;
   void DestroyData();
-  void RecreateData(MediaStreamGraph* aGraph);
-  nsTArray<OutputStreamData>& OutputStreams();
-  ReentrantMonitor& GetReentrantMonitor() const;
+  void RecreateData();
   void Connect(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
+  void Remove(MediaStream* aStream);
   void SetPlaying(bool aPlaying);
+  bool HaveEnoughAudio(const MediaInfo& aInfo) const;
+  bool HaveEnoughVideo(const MediaInfo& aInfo) const;
+  CheckedInt64 AudioEndTime(int64_t aStartTime, uint32_t aRate) const;
+  int64_t GetPosition() const;
+  bool IsFinished() const;
+
+  // Return true if stream is finished.
+  bool SendData(int64_t aStartTime,
+                const MediaInfo& aInfo,
+                MediaQueue<AudioData>& aAudioQueue,
+                MediaQueue<VideoData>& aVideoQueue,
+                double aVolume, bool aIsSameOrigin);
+
+protected:
+  virtual ~DecodedStream() {}
 
 private:
+  ReentrantMonitor& GetReentrantMonitor() const;
+  void RecreateData(MediaStreamGraph* aGraph);
   void Connect(OutputStreamData* aStream);
+  nsTArray<OutputStreamData>& OutputStreams();
+  void InitTracks(int64_t aStartTime, const MediaInfo& aInfo);
+  void AdvanceTracks(int64_t aStartTime, const MediaInfo& aInfo);
+
+  void SendAudio(int64_t aStartTime,
+                 const MediaInfo& aInfo,
+                 MediaQueue<AudioData>& aQueue,
+                 double aVolume, bool aIsSameOrigin);
+
+  void SendVideo(int64_t aStartTime,
+                 const MediaInfo& aInfo,
+                 MediaQueue<VideoData>& aQueue,
+                 bool aIsSameOrigin);
 
   UniquePtr<DecodedStreamData> mData;
   // Data about MediaStreams that are being fed by the decoder.
   nsTArray<OutputStreamData> mOutputStreams;
 
   // TODO: This is a temp solution to get rid of decoder monitor on the main
   // thread in MDSM::AddOutputStream and MDSM::RecreateDecodedStream as
   // required by bug 1146482. DecodedStream needs to release monitor before
   // calling back into MDSM functions in order to prevent deadlocks.
   //
   // Please move all capture-stream related code from MDSM into DecodedStream
   // and apply "dispatch + mirroring" to get rid of this monitor in the future.
   mutable ReentrantMonitor mMonitor;
+
+  bool mPlaying;
 };
 
 } // namespace mozilla
 
 #endif // DecodedStream_h_
--- a/dom/media/MediaDecoderReader.cpp
+++ b/dom/media/MediaDecoderReader.cpp
@@ -291,17 +291,18 @@ public:
   }
 
   NS_METHOD Run()
   {
     MOZ_ASSERT(mReader->OnTaskQueue());
 
     // Make sure ResetDecode hasn't been called in the mean time.
     if (!mReader->mBaseVideoPromise.IsEmpty()) {
-      mReader->RequestVideoData(/* aSkip = */ true, mTimeThreshold);
+      mReader->RequestVideoData(/* aSkip = */ true, mTimeThreshold,
+                                /* aForceDecodeAhead = */ false);
     }
 
     return NS_OK;
   }
 
 private:
   nsRefPtr<MediaDecoderReader> mReader;
   const int64_t mTimeThreshold;
@@ -328,17 +329,18 @@ public:
   }
 
 private:
   nsRefPtr<MediaDecoderReader> mReader;
 };
 
 nsRefPtr<MediaDecoderReader::VideoDataPromise>
 MediaDecoderReader::RequestVideoData(bool aSkipToNextKeyframe,
-                                     int64_t aTimeThreshold)
+                                     int64_t aTimeThreshold,
+                                     bool aForceDecodeAhead)
 {
   nsRefPtr<VideoDataPromise> p = mBaseVideoPromise.Ensure(__func__);
   bool skip = aSkipToNextKeyframe;
   while (VideoQueue().GetSize() == 0 &&
          !VideoQueue().IsFinished()) {
     if (!DecodeVideoFrame(skip, aTimeThreshold)) {
       VideoQueue().Finish();
     } else if (skip) {
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -142,17 +142,17 @@ public:
 
   // Requests one video sample from the reader.
   //
   // Don't hold the decoder monitor while calling this, as the implementation
   // may try to wait on something that needs the monitor and deadlock.
   // If aSkipToKeyframe is true, the decode should skip ahead to the
   // the next keyframe at or after aTimeThreshold microseconds.
   virtual nsRefPtr<VideoDataPromise>
-  RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold);
+  RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold, bool aForceDecodeAhead);
 
   friend class ReRequestVideoWithSkipTask;
   friend class ReRequestAudioTask;
 
   // By default, the state machine polls the reader once per second when it's
   // in buffering mode. Some readers support a promise-based mechanism by which
   // they notify the state machine when the data arrives.
   virtual bool IsWaitForDataSupported() { return false; }
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -40,17 +40,16 @@
 #include "DOMMediaStream.h"
 #include "DecodedStream.h"
 
 #include <algorithm>
 
 namespace mozilla {
 
 using namespace mozilla::dom;
-using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using namespace mozilla::media;
 
 #define NS_DispatchToMainThread(...) CompileError_UseAbstractThreadDispatchInstead
 
 // avoid redefined macro in unified build
 #undef LOG
 #undef DECODER_LOG
@@ -166,16 +165,17 @@ static TimeDuration UsecsToDuration(int6
 }
 
 static int64_t DurationToUsecs(TimeDuration aDuration) {
   return static_cast<int64_t>(aDuration.ToSeconds() * USECS_PER_S);
 }
 
 static const uint32_t MIN_VIDEO_QUEUE_SIZE = 3;
 static const uint32_t MAX_VIDEO_QUEUE_SIZE = 10;
+static const uint32_t SCARCE_VIDEO_QUEUE_SIZE = 1;
 
 static uint32_t sVideoQueueDefaultSize = MAX_VIDEO_QUEUE_SIZE;
 static uint32_t sVideoQueueHWAccelSize = MIN_VIDEO_QUEUE_SIZE;
 
 MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
                                                    MediaDecoderReader* aReader,
                                                    bool aRealTime) :
   mDecoder(aDecoder),
@@ -234,17 +234,18 @@ MediaDecoderStateMachine::MediaDecoderSt
   mDropVideoUntilNextDiscontinuity(false),
   mDecodeToSeekTarget(false),
   mCurrentTimeBeforeSeek(0),
   mCorruptFrames(30),
   mDisabledHardwareAcceleration(false),
   mDecodingFrozenAtStateDecoding(false),
   mSentLoadedMetadataEvent(false),
   mSentFirstFrameLoadedEvent(false),
-  mSentPlaybackEndedEvent(false)
+  mSentPlaybackEndedEvent(false),
+  mDecodedStream(new DecodedStream())
 {
   MOZ_COUNT_CTOR(MediaDecoderStateMachine);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 
   // Dispatch initialization that needs to happen on that task queue.
   nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::InitializationTask);
   mTaskQueue->Dispatch(r.forget());
 
@@ -352,246 +353,31 @@ int64_t MediaDecoderStateMachine::GetDec
   AssertCurrentThreadInMonitor();
   int64_t audioDecoded = AudioQueue().Duration();
   if (mAudioEndTime != -1) {
     audioDecoded += mAudioEndTime - GetMediaTime();
   }
   return audioDecoded;
 }
 
-void MediaDecoderStateMachine::SendStreamAudio(AudioData* aAudio,
-                                               DecodedStreamData* aStream,
-                                               AudioSegment* aOutput)
-{
-  MOZ_ASSERT(OnTaskQueue());
-  AssertCurrentThreadInMonitor();
-
-  // This logic has to mimic AudioSink closely to make sure we write
-  // the exact same silences
-  CheckedInt64 audioWrittenOffset = aStream->mAudioFramesWritten +
-      UsecsToFrames(mStreamStartTime, mInfo.mAudio.mRate);
-  CheckedInt64 frameOffset = UsecsToFrames(aAudio->mTime, mInfo.mAudio.mRate);
-
-  if (!audioWrittenOffset.isValid() ||
-      !frameOffset.isValid() ||
-      // ignore packet that we've already processed
-      frameOffset.value() + aAudio->mFrames <= audioWrittenOffset.value()) {
-    return;
-  }
-
-  if (audioWrittenOffset.value() < frameOffset.value()) {
-    int64_t silentFrames = frameOffset.value() - audioWrittenOffset.value();
-    // Write silence to catch up
-    VERBOSE_LOG("writing %lld frames of silence to MediaStream", silentFrames);
-    AudioSegment silence;
-    silence.InsertNullDataAtStart(silentFrames);
-    aStream->mAudioFramesWritten += silentFrames;
-    audioWrittenOffset += silentFrames;
-    aOutput->AppendFrom(&silence);
-  }
-
-  MOZ_ASSERT(audioWrittenOffset.value() >= frameOffset.value());
-
-  int64_t offset = audioWrittenOffset.value() - frameOffset.value();
-  size_t framesToWrite = aAudio->mFrames - offset;
-
-  aAudio->EnsureAudioBuffer();
-  nsRefPtr<SharedBuffer> buffer = aAudio->mAudioBuffer;
-  AudioDataValue* bufferData = static_cast<AudioDataValue*>(buffer->Data());
-  nsAutoTArray<const AudioDataValue*,2> channels;
-  for (uint32_t i = 0; i < aAudio->mChannels; ++i) {
-    channels.AppendElement(bufferData + i*aAudio->mFrames + offset);
-  }
-  aOutput->AppendFrames(buffer.forget(), channels, framesToWrite);
-  VERBOSE_LOG("writing %u frames of data to MediaStream for AudioData at %lld",
-              static_cast<unsigned>(framesToWrite),
-              aAudio->mTime);
-  aStream->mAudioFramesWritten += framesToWrite;
-  aOutput->ApplyVolume(mVolume);
-
-  aStream->mNextAudioTime = aAudio->GetEndTime();
-}
-
-static void WriteVideoToMediaStream(MediaStream* aStream,
-                                    layers::Image* aImage,
-                                    int64_t aEndMicroseconds,
-                                    int64_t aStartMicroseconds,
-                                    const IntSize& aIntrinsicSize,
-                                    VideoSegment* aOutput)
-{
-  nsRefPtr<layers::Image> image = aImage;
-  StreamTime duration =
-      aStream->MicrosecondsToStreamTimeRoundDown(aEndMicroseconds) -
-      aStream->MicrosecondsToStreamTimeRoundDown(aStartMicroseconds);
-  aOutput->AppendFrame(image.forget(), duration, aIntrinsicSize);
-}
-
-static bool ZeroDurationAtLastChunk(VideoSegment& aInput)
-{
-  // Get the last video frame's start time in VideoSegment aInput.
-  // If the start time is equal to the duration of aInput, means the last video
-  // frame's duration is zero.
-  StreamTime lastVideoStratTime;
-  aInput.GetLastFrame(&lastVideoStratTime);
-  return lastVideoStratTime == aInput.GetDuration();
-}
-
 void MediaDecoderStateMachine::SendStreamData()
 {
   MOZ_ASSERT(OnTaskQueue());
   AssertCurrentThreadInMonitor();
   MOZ_ASSERT(!mAudioSink, "Should've been stopped in RunStateMachine()");
-  MOZ_ASSERT(mStreamStartTime != -1);
-
-  DecodedStreamData* stream = GetDecodedStream();
-
-  bool finished =
-      (!mInfo.HasAudio() || AudioQueue().IsFinished()) &&
-      (!mInfo.HasVideo() || VideoQueue().IsFinished());
-
-  {
-    SourceMediaStream* mediaStream = stream->mStream;
-    StreamTime endPosition = 0;
-    const bool isSameOrigin = mDecoder->IsSameOriginMedia();
-
-    if (!stream->mStreamInitialized) {
-      if (mInfo.HasAudio()) {
-        TrackID audioTrackId = mInfo.mAudio.mTrackId;
-        AudioSegment* audio = new AudioSegment();
-        mediaStream->AddAudioTrack(audioTrackId, mInfo.mAudio.mRate, 0, audio,
-                                   SourceMediaStream::ADDTRACK_QUEUED);
-        stream->mNextAudioTime = mStreamStartTime;
-      }
-      if (mInfo.HasVideo()) {
-        TrackID videoTrackId = mInfo.mVideo.mTrackId;
-        VideoSegment* video = new VideoSegment();
-        mediaStream->AddTrack(videoTrackId, 0, video,
-                              SourceMediaStream::ADDTRACK_QUEUED);
-        stream->mNextVideoTime = mStreamStartTime;
-      }
-      mediaStream->FinishAddTracks();
-      stream->mStreamInitialized = true;
-    }
-
-    if (mInfo.HasAudio()) {
-      MOZ_ASSERT(stream->mNextAudioTime != -1, "Should've been initialized");
-      TrackID audioTrackId = mInfo.mAudio.mTrackId;
-      nsAutoTArray<nsRefPtr<AudioData>,10> audio;
-      // It's OK to hold references to the AudioData because AudioData
-      // is ref-counted.
-      AudioQueue().GetElementsAfter(stream->mNextAudioTime, &audio);
-      AudioSegment output;
-      for (uint32_t i = 0; i < audio.Length(); ++i) {
-        SendStreamAudio(audio[i], stream, &output);
-      }
-      if (!isSameOrigin) {
-        output.ReplaceWithDisabled();
-      }
-      // |mNextAudioTime| is updated as we process each audio sample in
-      // SendStreamAudio(). This is consistent with how |mNextVideoTime|
-      // is updated for video samples.
-      if (output.GetDuration() > 0) {
-        mediaStream->AppendToTrack(audioTrackId, &output);
-      }
-      if (AudioQueue().IsFinished() && !stream->mHaveSentFinishAudio) {
-        mediaStream->EndTrack(audioTrackId);
-        stream->mHaveSentFinishAudio = true;
-      }
-      endPosition = std::max(endPosition,
-          mediaStream->TicksToTimeRoundDown(mInfo.mAudio.mRate,
-                                            stream->mAudioFramesWritten));
-
-      CheckedInt64 playedUsecs = mStreamStartTime +
-          FramesToUsecs(stream->mAudioFramesWritten, mInfo.mAudio.mRate);
-      if (playedUsecs.isValid()) {
-        OnAudioEndTimeUpdate(playedUsecs.value());
-      }
-    }
-
-    if (mInfo.HasVideo()) {
-      MOZ_ASSERT(stream->mNextVideoTime != -1, "Should've been initialized");
-      TrackID videoTrackId = mInfo.mVideo.mTrackId;
-      nsAutoTArray<nsRefPtr<VideoData>,10> video;
-      // It's OK to hold references to the VideoData because VideoData
-      // is ref-counted.
-      VideoQueue().GetElementsAfter(stream->mNextVideoTime, &video);
-      VideoSegment output;
-      for (uint32_t i = 0; i < video.Length(); ++i) {
-        VideoData* v = video[i];
-        if (stream->mNextVideoTime < v->mTime) {
-          VERBOSE_LOG("writing last video to MediaStream %p for %lldus",
-                      mediaStream, v->mTime - stream->mNextVideoTime);
-          // Write last video frame to catch up. mLastVideoImage can be null here
-          // which is fine, it just means there's no video.
-
-          // TODO: |mLastVideoImage| should come from the last image rendered
-          // by the state machine. This will avoid the black frame when capture
-          // happens in the middle of playback (especially in th middle of a
-          // video frame). E.g. if we have a video frame that is 30 sec long
-          // and capture happens at 15 sec, we'll have to append a black frame
-          // that is 15 sec long.
-          WriteVideoToMediaStream(mediaStream, stream->mLastVideoImage,
-            v->mTime, stream->mNextVideoTime, stream->mLastVideoImageDisplaySize,
-              &output);
-          stream->mNextVideoTime = v->mTime;
-        }
-        if (stream->mNextVideoTime < v->GetEndTime()) {
-          VERBOSE_LOG("writing video frame %lldus to MediaStream %p for %lldus",
-                      v->mTime, mediaStream, v->GetEndTime() - stream->mNextVideoTime);
-          WriteVideoToMediaStream(mediaStream, v->mImage,
-              v->GetEndTime(), stream->mNextVideoTime, v->mDisplay,
-              &output);
-          stream->mNextVideoTime = v->GetEndTime();
-          stream->mLastVideoImage = v->mImage;
-          stream->mLastVideoImageDisplaySize = v->mDisplay;
-        } else {
-          VERBOSE_LOG("skipping writing video frame %lldus (end %lldus) to MediaStream",
-                      v->mTime, v->GetEndTime());
-        }
-      }
-      // Check the output is not empty.
-      if (output.GetLastFrame()) {
-        stream->mEOSVideoCompensation = ZeroDurationAtLastChunk(output);
-      }
-      if (!isSameOrigin) {
-        output.ReplaceWithDisabled();
-      }
-      if (output.GetDuration() > 0) {
-        mediaStream->AppendToTrack(videoTrackId, &output);
-      }
-      if (VideoQueue().IsFinished() && !stream->mHaveSentFinishVideo) {
-        if (stream->mEOSVideoCompensation) {
-          VideoSegment endSegment;
-          // Calculate the deviation clock time from DecodedStream.
-          int64_t deviation_usec = mediaStream->StreamTimeToMicroseconds(1);
-          WriteVideoToMediaStream(mediaStream, stream->mLastVideoImage,
-            stream->mNextVideoTime + deviation_usec, stream->mNextVideoTime,
-            stream->mLastVideoImageDisplaySize, &endSegment);
-          stream->mNextVideoTime += deviation_usec;
-          MOZ_ASSERT(endSegment.GetDuration() > 0);
-          if (!isSameOrigin) {
-            endSegment.ReplaceWithDisabled();
-          }
-          mediaStream->AppendToTrack(videoTrackId, &endSegment);
-        }
-        mediaStream->EndTrack(videoTrackId);
-        stream->mHaveSentFinishVideo = true;
-      }
-      endPosition = std::max(endPosition,
-          mediaStream->MicrosecondsToStreamTimeRoundDown(
-              stream->mNextVideoTime - mStreamStartTime));
-    }
-
-    if (!stream->mHaveSentFinish) {
-      stream->mStream->AdvanceKnownTracksTime(endPosition);
-    }
-
-    if (finished && !stream->mHaveSentFinish) {
-      stream->mHaveSentFinish = true;
-      stream->mStream->Finish();
+
+  bool finished = mDecodedStream->SendData(
+      mStreamStartTime, mInfo, AudioQueue(), VideoQueue(),
+      mVolume, mDecoder->IsSameOriginMedia());
+
+  if (mInfo.HasAudio()) {
+    CheckedInt64 playedUsecs = mDecodedStream->AudioEndTime(
+        mStreamStartTime, mInfo.mAudio.mRate);
+    if (playedUsecs.isValid()) {
+      OnAudioEndTimeUpdate(playedUsecs.value());
     }
   }
 
   const auto clockTime = GetClock();
   while (true) {
     const AudioData* a = AudioQueue().PeekFront();
     // If we discard audio samples fed to the stream immediately, we will
     // keep decoding audio samples till the end and consume a lot of memory.
@@ -615,53 +401,30 @@ bool MediaDecoderStateMachine::HaveEnoug
 {
   MOZ_ASSERT(OnTaskQueue());
   AssertCurrentThreadInMonitor();
 
   if (AudioQueue().GetSize() == 0 ||
       GetDecodedAudioDuration() < aAmpleAudioUSecs) {
     return false;
   }
-  if (!mAudioCaptured) {
-    return true;
-  }
-
-  DecodedStreamData* stream = GetDecodedStream();
-
-  if (stream && stream->mStreamInitialized && !stream->mHaveSentFinishAudio) {
-    MOZ_ASSERT(mInfo.HasAudio());
-    TrackID audioTrackId = mInfo.mAudio.mTrackId;
-    if (!stream->mStream->HaveEnoughBuffered(audioTrackId)) {
-      return false;
-    }
-  }
-
-  return true;
+
+  return !mAudioCaptured || mDecodedStream->HaveEnoughAudio(mInfo);
 }
 
 bool MediaDecoderStateMachine::HaveEnoughDecodedVideo()
 {
   MOZ_ASSERT(OnTaskQueue());
   AssertCurrentThreadInMonitor();
 
   if (static_cast<uint32_t>(VideoQueue().GetSize()) < GetAmpleVideoFrames() * mPlaybackRate) {
     return false;
   }
 
-  DecodedStreamData* stream = GetDecodedStream();
-
-  if (stream && stream->mStreamInitialized && !stream->mHaveSentFinishVideo) {
-    MOZ_ASSERT(mInfo.HasVideo());
-    TrackID videoTrackId = mInfo.mVideo.mTrackId;
-    if (!stream->mStream->HaveEnoughBuffered(videoTrackId)) {
-      return false;
-    }
-  }
-
-  return true;
+  return !mAudioCaptured || mDecodedStream->HaveEnoughVideo(mInfo);
 }
 
 bool
 MediaDecoderStateMachine::NeedToDecodeVideo()
 {
   MOZ_ASSERT(OnTaskQueue());
   AssertCurrentThreadInMonitor();
   return IsVideoDecoding() &&
@@ -1796,19 +1559,17 @@ MediaDecoderStateMachine::InitiateSeek()
   int64_t seekTime = mCurrentSeek.mTarget.mTime;
   seekTime = std::min(seekTime, end);
   seekTime = std::max(int64_t(0), seekTime);
   NS_ASSERTION(seekTime >= 0 && seekTime <= end,
                "Can only seek in range [0,duration]");
   mCurrentSeek.mTarget.mTime = seekTime;
 
   if (mAudioCaptured) {
-    nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethodWithArgs<MediaStreamGraph*>(
-      this, &MediaDecoderStateMachine::RecreateDecodedStream, nullptr);
-    AbstractThread::MainThread()->Dispatch(r.forget());
+    mDecodedStream->RecreateData();
   }
 
   mDropAudioUntilNextDiscontinuity = HasAudio();
   mDropVideoUntilNextDiscontinuity = HasVideo();
 
   mDecoder->StopProgressUpdates();
   mCurrentTimeBeforeSeek = GetMediaTime();
 
@@ -1934,29 +1695,30 @@ MediaDecoderStateMachine::EnsureVideoDec
 
   if (!IsVideoDecoding() || mVideoDataRequest.Exists() ||
       mVideoWaitRequest.Exists() || mSeekRequest.Exists()) {
     return NS_OK;
   }
 
   bool skipToNextKeyFrame = NeedToSkipToNextKeyframe();
   int64_t currentTime = mState == DECODER_STATE_SEEKING ? 0 : GetMediaTime();
+  bool forceDecodeAhead = static_cast<uint32_t>(VideoQueue().GetSize()) <= SCARCE_VIDEO_QUEUE_SIZE;
 
   // Time the video decode, so that if it's slow, we can increase our low
   // audio threshold to reduce the chance of an audio underrun while we're
   // waiting for a video decode to complete.
   mVideoDecodeStartTime = TimeStamp::Now();
 
   SAMPLE_LOG("Queueing video task - queued=%i, decoder-queued=%o, skip=%i, time=%lld",
              VideoQueue().GetSize(), mReader->SizeOfVideoQueueInFrames(), skipToNextKeyFrame,
              currentTime);
 
   mVideoDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
                                          &MediaDecoderReader::RequestVideoData,
-                                         skipToNextKeyFrame, currentTime)
+                                         skipToNextKeyFrame, currentTime, forceDecodeAhead)
     ->Then(TaskQueue(), __func__, this,
            &MediaDecoderStateMachine::OnVideoDecoded,
            &MediaDecoderStateMachine::OnVideoNotDecoded));
   return NS_OK;
 }
 
 nsresult
 MediaDecoderStateMachine::StartAudioThread()
@@ -2264,17 +2026,17 @@ MediaDecoderStateMachine::DecodeFirstFra
                &MediaDecoderStateMachine::OnAudioDecoded,
                &MediaDecoderStateMachine::OnAudioNotDecoded)
       );
     }
     if (HasVideo()) {
       mVideoDecodeStartTime = TimeStamp::Now();
       mVideoDataRequest.Begin(
         ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
-                       &MediaDecoderReader::RequestVideoData, false, int64_t(0))
+                       &MediaDecoderReader::RequestVideoData, false, int64_t(0), false)
         ->Then(TaskQueue(), __func__, mStartTimeRendezvous.get(),
                &StartTimeRendezvous::ProcessFirstSample<VideoDataPromise>,
                &StartTimeRendezvous::FirstSampleRejected<VideoData>)
         ->CompletionPromise()
         ->Then(TaskQueue(), __func__, this,
                &MediaDecoderStateMachine::OnVideoDecoded,
                &MediaDecoderStateMachine::OnVideoNotDecoded));
     }
@@ -2618,17 +2380,17 @@ nsresult MediaDecoderStateMachine::RunSt
       if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING && IsPlaying()) {
         StopPlayback();
       }
       // Play the remaining media. We want to run AdvanceFrame() at least
       // once to ensure the current playback position is advanced to the
       // end of the media, and so that we update the readyState.
       if (VideoQueue().GetSize() > 0 ||
           (HasAudio() && !mAudioCompleted) ||
-          (mAudioCaptured && !GetDecodedStream()->IsFinished()))
+          (mAudioCaptured && !mDecodedStream->IsFinished()))
       {
         // Start playback if necessary to play the remaining media.
         MaybeStartPlayback();
         AdvanceFrame();
         NS_ASSERTION(!IsPlaying() ||
                      mLogicallySeeking ||
                      IsStateMachineScheduled(),
                      "Must have timer scheduled");
@@ -2777,18 +2539,17 @@ MediaDecoderStateMachine::GetAudioClock(
   return mAudioStartTime +
          (mAudioSink ? mAudioSink->GetPosition() : 0);
 }
 
 int64_t MediaDecoderStateMachine::GetStreamClock() const
 {
   MOZ_ASSERT(OnTaskQueue());
   AssertCurrentThreadInMonitor();
-  MOZ_ASSERT(mStreamStartTime != -1);
-  return mStreamStartTime + GetDecodedStream()->GetPosition();
+  return mStreamStartTime + mDecodedStream->GetPosition();
 }
 
 int64_t MediaDecoderStateMachine::GetVideoStreamPosition() const
 {
   MOZ_ASSERT(OnTaskQueue());
   AssertCurrentThreadInMonitor();
 
   if (!IsPlaying()) {
@@ -3162,19 +2923,21 @@ void MediaDecoderStateMachine::StartBuff
 void MediaDecoderStateMachine::SetPlayStartTime(const TimeStamp& aTimeStamp)
 {
   MOZ_ASSERT(OnTaskQueue());
   AssertCurrentThreadInMonitor();
   mPlayStartTime = aTimeStamp;
 
   if (mAudioSink) {
     mAudioSink->SetPlaying(!mPlayStartTime.IsNull());
-  } else if (mAudioCaptured) {
-    mDecodedStream.SetPlaying(!mPlayStartTime.IsNull());
   }
+  // Have DecodedStream remember the playing state so it doesn't need to
+  // ask MDSM about IsPlaying(). Note we have to do this even before capture
+  // happens since capture could happen in the middle of playback.
+  mDecodedStream->SetPlaying(!mPlayStartTime.IsNull());
 }
 
 void MediaDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder()
 {
   MOZ_ASSERT(OnTaskQueue());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   DispatchAudioDecodeTaskIfNeeded();
   DispatchVideoDecodeTaskIfNeeded();
@@ -3345,72 +3108,46 @@ uint32_t MediaDecoderStateMachine::GetAm
 {
   MOZ_ASSERT(OnTaskQueue());
   AssertCurrentThreadInMonitor();
   return (mReader->IsAsync() && mReader->VideoIsHardwareAccelerated())
     ? std::max<uint32_t>(sVideoQueueHWAccelSize, MIN_VIDEO_QUEUE_SIZE)
     : std::max<uint32_t>(sVideoQueueDefaultSize, MIN_VIDEO_QUEUE_SIZE);
 }
 
-DecodedStreamData* MediaDecoderStateMachine::GetDecodedStream() const
-{
-  return mDecodedStream.GetData();
-}
-
 void MediaDecoderStateMachine::DispatchAudioCaptured()
 {
   nsRefPtr<MediaDecoderStateMachine> self = this;
   nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self] () -> void
   {
     MOZ_ASSERT(self->OnTaskQueue());
     ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
     if (!self->mAudioCaptured) {
       // Stop the audio sink if it's running.
       self->StopAudioThread();
-      // GetMediaTime() could return -1 because we haven't decoded
-      // the 1st frame. But this is OK since we will update mStreamStartTime
-      // again in SetStartTime().
       self->mStreamStartTime = self->GetMediaTime();
       // Reset mAudioEndTime which will be updated as we send audio data to
       // stream. Otherwise it will remain -1 if we don't have audio.
       self->mAudioEndTime = -1;
       self->mAudioCaptured = true;
       self->ScheduleStateMachine();
     }
   });
   TaskQueue()->Dispatch(r.forget());
 }
 
 void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream,
                                                bool aFinishWhenEnded)
 {
   MOZ_ASSERT(NS_IsMainThread());
   DECODER_LOG("AddOutputStream aStream=%p!", aStream);
-
-  if (!GetDecodedStream()) {
-    RecreateDecodedStream(aStream->Graph());
-  }
-  mDecodedStream.Connect(aStream, aFinishWhenEnded);
+  mDecodedStream->Connect(aStream, aFinishWhenEnded);
   DispatchAudioCaptured();
 }
 
-void MediaDecoderStateMachine::RecreateDecodedStream(MediaStreamGraph* aGraph)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  mDecodedStream.RecreateData(aGraph);
-
-  nsRefPtr<MediaDecoderStateMachine> self = this;
-  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self] () -> void
-  {
-    ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
-    self->mDecodedStream.SetPlaying(self->IsPlaying());
-  });
-  TaskQueue()->Dispatch(r.forget());
-}
-
 } // namespace mozilla
 
 // avoid redefined macro in unified build
 #undef LOG
 #undef DECODER_LOG
 #undef VERBOSE_LOG
 #undef DECODER_WARN
 #undef DECODER_WARN_HELPER
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -140,36 +140,29 @@ public:
     DECODER_STATE_DECODING,
     DECODER_STATE_SEEKING,
     DECODER_STATE_BUFFERING,
     DECODER_STATE_COMPLETED,
     DECODER_STATE_SHUTDOWN,
     DECODER_STATE_ERROR
   };
 
-  DecodedStreamData* GetDecodedStream() const;
-
   void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
 
   // Set/Unset dormant state.
   void SetDormant(bool aDormant);
 
 private:
   // Initialization that needs to happen on the task queue. This is the first
   // task that gets run on the task queue, and is dispatched from the MDSM
   // constructor immediately after the task queue is created.
   void InitializationTask();
 
   void DispatchAudioCaptured();
 
-  // Recreates mDecodedStream. Call this to create mDecodedStream at first,
-  // and when seeking, to ensure a new stream is set up with fresh buffers.
-  // Decoder monitor must be held.
-  void RecreateDecodedStream(MediaStreamGraph* aGraph);
-
   void Shutdown();
 public:
 
   void DispatchShutdown()
   {
     nsCOMPtr<nsIRunnable> runnable =
       NS_NewRunnableMethod(this, &MediaDecoderStateMachine::Shutdown);
     TaskQueue()->Dispatch(runnable.forget());
@@ -315,17 +308,17 @@ public:
   }
 
   // Drop reference to decoder.  Only called during shutdown dance.
   void BreakCycles() {
     MOZ_ASSERT(NS_IsMainThread());
     if (mReader) {
       mReader->BreakCycles();
     }
-    mDecodedStream.DestroyData();
+    mDecodedStream->DestroyData();
     mDecoder = nullptr;
   }
 
   // Copy queued audio/video data in the reader to any output MediaStreams that
   // need it.
   void SendStreamData();
   void FinishStreamData();
   bool HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs);
@@ -630,21 +623,16 @@ protected:
   void SeekCompleted();
 
   // Queries our state to see whether the decode has finished for all streams.
   // If so, we move into DECODER_STATE_COMPLETED and schedule the state machine
   // to run.
   // The decoder monitor must be held.
   void CheckIfDecodeComplete();
 
-  // Copy audio from an AudioData packet to aOutput. This may require
-  // inserting silence depending on the timing of the audio packet.
-  void SendStreamAudio(AudioData* aAudio, DecodedStreamData* aStream,
-                       AudioSegment* aOutput);
-
   // Performs one "cycle" of the state machine. Polls the state, and may send
   // a video frame to be displayed, and generally manages the decode. Called
   // periodically via timer to ensure the video stays in sync.
   nsresult RunStateMachine();
 
   bool IsStateMachineScheduled() const;
 
   // Returns true if we're not playing and the decode thread has filled its
@@ -1356,13 +1344,13 @@ protected:
 
   bool mSentPlaybackEndedEvent;
 
   // The SourceMediaStream we are using to feed the mOutputStreams. This stream
   // is never exposed outside the decoder.
   // Only written on the main thread while holding the monitor. Therefore it
   // can be read on any thread while holding the monitor, or on the main thread
   // without holding the monitor.
-  DecodedStream mDecodedStream;
+  nsRefPtr<DecodedStream> mDecodedStream;
 };
 
 } // namespace mozilla;
 #endif
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -516,17 +516,18 @@ MediaFormatReader::ShouldSkip(bool aSkip
   if (NS_FAILED(rv)) {
     return aSkipToNextKeyframe;
   }
   return nextKeyframe < aTimeThreshold && nextKeyframe.ToMicroseconds() >= 0;
 }
 
 nsRefPtr<MediaDecoderReader::VideoDataPromise>
 MediaFormatReader::RequestVideoData(bool aSkipToNextKeyframe,
-                                     int64_t aTimeThreshold)
+                                    int64_t aTimeThreshold,
+                                    bool aForceDecodeAhead)
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(), "No sample requests allowed while seeking");
   MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise(), "No duplicate sample requests");
   MOZ_DIAGNOSTIC_ASSERT(!mVideo.mSeekRequest.Exists());
   MOZ_DIAGNOSTIC_ASSERT(!mSkipRequest.Exists(), "called mid-skipping");
   MOZ_DIAGNOSTIC_ASSERT(!IsSeeking(), "called mid-seek");
   LOGV("RequestVideoData(%d, %lld)", aSkipToNextKeyframe, aTimeThreshold);
@@ -548,16 +549,17 @@ MediaFormatReader::RequestVideoData(bool
 
   if (!EnsureDecodersSetup()) {
     NS_WARNING("Error constructing decoders");
     return VideoDataPromise::CreateAndReject(DECODE_ERROR, __func__);
   }
 
   MOZ_ASSERT(HasVideo() && mPlatform && mVideo.mDecoder);
 
+  mVideo.mForceDecodeAhead = aForceDecodeAhead;
   media::TimeUnit timeThreshold{media::TimeUnit::FromMicroseconds(aTimeThreshold)};
   if (ShouldSkip(aSkipToNextKeyframe, timeThreshold)) {
     Flush(TrackInfo::kVideoTrack);
     nsRefPtr<VideoDataPromise> p = mVideo.mPromise.Ensure(__func__);
     SkipVideoDemuxToNextKeyFrame(timeThreshold);
     return p;
   }
 
@@ -746,21 +748,22 @@ MediaFormatReader::NeedInput(DecoderData
   MOZ_ASSERT(OnTaskQueue());
   // We try to keep a few more compressed samples input than decoded samples
   // have been output, provided the state machine has requested we send it a
   // decoded sample. To account for H.264 streams which may require a longer
   // run of input than we input, decoders fire an "input exhausted" callback,
   // which overrides our "few more samples" threshold.
   return
     !aDecoder.mError &&
-    aDecoder.HasPromise() &&
+    (aDecoder.HasPromise() || aDecoder.mForceDecodeAhead) &&
     !aDecoder.mDemuxRequest.Exists() &&
     aDecoder.mOutput.IsEmpty() &&
     (aDecoder.mInputExhausted || !aDecoder.mQueuedSamples.IsEmpty() ||
      aDecoder.mTimeThreshold.isSome() ||
+     aDecoder.mForceDecodeAhead ||
      aDecoder.mNumSamplesInput - aDecoder.mNumSamplesOutput < aDecoder.mDecodeAhead);
 }
 
 void
 MediaFormatReader::ScheduleUpdate(TrackType aTrack)
 {
   MOZ_ASSERT(OnTaskQueue());
   if (mShutdown) {
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -29,17 +29,17 @@ public:
   virtual ~MediaFormatReader();
 
   nsresult Init(MediaDecoderReader* aCloneDonor) override;
 
   size_t SizeOfVideoQueueInFrames() override;
   size_t SizeOfAudioQueueInFrames() override;
 
   nsRefPtr<VideoDataPromise>
-  RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold) override;
+  RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold, bool aForceDecodeAhead) override;
 
   nsRefPtr<AudioDataPromise> RequestAudioData() override;
 
   bool HasVideo() override
   {
     return mInfo.HasVideo();
   }
 
@@ -180,16 +180,17 @@ private:
 
   struct DecoderData {
     DecoderData(MediaFormatReader* aOwner,
                 MediaData::Type aType,
                 uint32_t aDecodeAhead)
       : mOwner(aOwner)
       , mType(aType)
       , mDecodeAhead(aDecodeAhead)
+      , mForceDecodeAhead(false)
       , mUpdateScheduled(false)
       , mDemuxEOS(false)
       , mDemuxEOSServiced(false)
       , mWaitingForData(false)
       , mReceivedNewData(false)
       , mDiscontinuity(true)
       , mOutputRequested(false)
       , mInputExhausted(false)
@@ -210,16 +211,17 @@ private:
     // TaskQueue on which decoder can choose to decode.
     // Only non-null up until the decoder is created.
     nsRefPtr<FlushableMediaTaskQueue> mTaskQueue;
     // Callback that receives output and error notifications from the decoder.
     nsAutoPtr<DecoderCallback> mCallback;
 
     // Only accessed from reader's task queue.
     uint32_t mDecodeAhead;
+    bool mForceDecodeAhead;
     bool mUpdateScheduled;
     bool mDemuxEOS;
     bool mDemuxEOSServiced;
     bool mWaitingForData;
     bool mReceivedNewData;
     bool mDiscontinuity;
 
     // Pending seek.
@@ -261,16 +263,17 @@ private:
       // Clear demuxer related data.
       mDemuxRequest.DisconnectIfExists();
       mTrackDemuxer->Reset();
     }
 
     void ResetState()
     {
       MOZ_ASSERT(mOwner->OnTaskQueue());
+      mForceDecodeAhead = false;
       mDemuxEOS = false;
       mDemuxEOSServiced = false;
       mWaitingForData = false;
       mReceivedNewData = false;
       mDiscontinuity = true;
       mQueuedSamples.Clear();
       mOutputRequested = false;
       mInputExhausted = false;
--- a/dom/media/MediaPromise.h
+++ b/dom/media/MediaPromise.h
@@ -905,16 +905,32 @@ public:
   nsRefPtr<PromiseType> Invoke() override { return ((*mThisVal).*mMethod)(mArg1, mArg2); }
 protected:
   nsRefPtr<ThisType> mThisVal;
   Type mMethod;
   Arg1Type mArg1;
   Arg2Type mArg2;
 };
 
+template<typename PromiseType, typename ThisType, typename Arg1Type, typename Arg2Type, typename Arg3Type>
+class MethodCallWithThreeArgs : public MethodCallBase<PromiseType>
+{
+public:
+  typedef nsRefPtr<PromiseType>(ThisType::*Type)(Arg1Type, Arg2Type, Arg3Type);
+  MethodCallWithThreeArgs(ThisType* aThisVal, Type aMethod, Arg1Type aArg1, Arg2Type aArg2, Arg3Type aArg3)
+    : mThisVal(aThisVal), mMethod(aMethod), mArg1(aArg1), mArg2(aArg2), mArg3(aArg3) {}
+  nsRefPtr<PromiseType> Invoke() override { return ((*mThisVal).*mMethod)(mArg1, mArg2, mArg3); }
+protected:
+  nsRefPtr<ThisType> mThisVal;
+  Type mMethod;
+  Arg1Type mArg1;
+  Arg2Type mArg2;
+  Arg3Type mArg3;
+};
+
 template<typename PromiseType>
 class ProxyRunnable : public nsRunnable
 {
 public:
   ProxyRunnable(typename PromiseType::Private* aProxyPromise, MethodCallBase<PromiseType>* aMethodCall)
     : mProxyPromise(aProxyPromise), mMethodCall(aMethodCall) {}
 
   NS_IMETHODIMP Run()
@@ -968,13 +984,23 @@ static nsRefPtr<PromiseType>
 ProxyMediaCall(AbstractThread* aTarget, ThisType* aThisVal, const char* aCallerName,
                nsRefPtr<PromiseType>(ThisType::*aMethod)(Arg1Type, Arg2Type), Arg1Type aArg1, Arg2Type aArg2)
 {
   typedef detail::MethodCallWithTwoArgs<PromiseType, ThisType, Arg1Type, Arg2Type> MethodCallType;
   MethodCallType* methodCall = new MethodCallType(aThisVal, aMethod, aArg1, aArg2);
   return detail::ProxyInternal(aTarget, methodCall, aCallerName);
 }
 
+template<typename PromiseType, typename ThisType, typename Arg1Type, typename Arg2Type, typename Arg3Type>
+static nsRefPtr<PromiseType>
+ProxyMediaCall(AbstractThread* aTarget, ThisType* aThisVal, const char* aCallerName,
+               nsRefPtr<PromiseType>(ThisType::*aMethod)(Arg1Type, Arg2Type, Arg3Type), Arg1Type aArg1, Arg2Type aArg2, Arg3Type aArg3)
+{
+  typedef detail::MethodCallWithThreeArgs<PromiseType, ThisType, Arg1Type, Arg2Type, Arg3Type> MethodCallType;
+  MethodCallType* methodCall = new MethodCallType(aThisVal, aMethod, aArg1, aArg2, aArg3);
+  return detail::ProxyInternal(aTarget, methodCall, aCallerName);
+}
+
 #undef PROMISE_LOG
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -601,17 +601,18 @@ MP4Reader::ShouldSkip(bool aSkipToNextKe
       (nextKeyframe = GetNextKeyframeTime()) == -1) {
     return aSkipToNextKeyframe;
   }
   return nextKeyframe < aTimeThreshold && nextKeyframe >= 0;
 }
 
 nsRefPtr<MediaDecoderReader::VideoDataPromise>
 MP4Reader::RequestVideoData(bool aSkipToNextKeyframe,
-                            int64_t aTimeThreshold)
+                            int64_t aTimeThreshold,
+                            bool aForceDecodeAhead)
 {
   MOZ_ASSERT(OnTaskQueue());
   VLOG("skip=%d time=%lld", aSkipToNextKeyframe, aTimeThreshold);
 
   if (!EnsureDecodersSetup()) {
     NS_WARNING("Error constructing MP4 decoders");
     return VideoDataPromise::CreateAndReject(DECODE_ERROR, __func__);
   }
@@ -619,16 +620,17 @@ MP4Reader::RequestVideoData(bool aSkipTo
   if (mShutdown) {
     NS_WARNING("RequestVideoData on shutdown MP4Reader!");
     return VideoDataPromise::CreateAndReject(CANCELED, __func__);
   }
 
   MOZ_ASSERT(HasVideo() && mPlatform && mVideo.mDecoder);
 
   bool eos = false;
+  mVideo.mForceDecodeAhead = aForceDecodeAhead;
   if (ShouldSkip(aSkipToNextKeyframe, aTimeThreshold)) {
     uint32_t parsed = 0;
     eos = !SkipVideoDemuxToNextKeyFrame(aTimeThreshold, parsed);
     if (!eos && NS_FAILED(mVideo.mDecoder->Flush())) {
       NS_WARNING("Failed to skip/flush video when skipping-to-next-keyframe.");
     }
     mDecoder->NotifyDecodedFrames(parsed, 0, parsed);
   }
@@ -690,19 +692,20 @@ MP4Reader::NeedInput(DecoderData& aDecod
   // We try to keep a few more compressed samples input than decoded samples
   // have been output, provided the state machine has requested we send it a
   // decoded sample. To account for H.264 streams which may require a longer
   // run of input than we input, decoders fire an "input exhausted" callback,
   // which overrides our "few more samples" threshold.
   return
     !aDecoder.mError &&
     !aDecoder.mDemuxEOS &&
-    aDecoder.HasPromise() &&
+    (aDecoder.HasPromise() || aDecoder.mForceDecodeAhead) &&
     aDecoder.mOutput.IsEmpty() &&
     (aDecoder.mInputExhausted ||
+     aDecoder.mForceDecodeAhead ||
      aDecoder.mNumSamplesInput - aDecoder.mNumSamplesOutput < aDecoder.mDecodeAhead);
 }
 
 void
 MP4Reader::Update(TrackType aTrack)
 {
   MOZ_ASSERT(OnTaskQueue());
 
@@ -964,16 +967,17 @@ MP4Reader::Flush(TrackType aTrack)
   {
     MonitorAutoLock mon(data.mMonitor);
     data.mIsFlushing = true;
     data.mDemuxEOS = false;
   }
   data.mDecoder->Flush();
   {
     MonitorAutoLock mon(data.mMonitor);
+    data.mForceDecodeAhead = false;
     data.mIsFlushing = false;
     data.mDrainComplete = false;
     data.mOutput.Clear();
     data.mNumSamplesInput = 0;
     data.mNumSamplesOutput = 0;
     data.mInputExhausted = false;
     if (data.HasPromise()) {
       data.RejectPromise(CANCELED, __func__);
--- a/dom/media/fmp4/MP4Reader.h
+++ b/dom/media/fmp4/MP4Reader.h
@@ -33,17 +33,17 @@ public:
   virtual ~MP4Reader();
 
   virtual nsresult Init(MediaDecoderReader* aCloneDonor) override;
 
   virtual size_t SizeOfVideoQueueInFrames() override;
   virtual size_t SizeOfAudioQueueInFrames() override;
 
   virtual nsRefPtr<VideoDataPromise>
-  RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold) override;
+  RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold, bool aForceDecodeAhead) override;
 
   virtual nsRefPtr<AudioDataPromise> RequestAudioData() override;
 
   virtual bool HasAudio() override;
   virtual bool HasVideo() override;
 
   virtual nsresult ReadMetadata(MediaInfo* aInfo,
                                 MetadataTags** aTags) override;
@@ -162,16 +162,17 @@ private:
     DecoderData(MediaData::Type aType,
                 uint32_t aDecodeAhead)
       : mType(aType)
       , mMonitor(aType == MediaData::AUDIO_DATA ? "MP4 audio decoder data"
                                                 : "MP4 video decoder data")
       , mNumSamplesInput(0)
       , mNumSamplesOutput(0)
       , mDecodeAhead(aDecodeAhead)
+      , mForceDecodeAhead(false)
       , mActive(false)
       , mInputExhausted(false)
       , mError(false)
       , mIsFlushing(false)
       , mUpdateScheduled(false)
       , mDemuxEOS(false)
       , mDrainComplete(false)
       , mDiscontinuity(false)
@@ -198,16 +199,17 @@ private:
                                const char* aMethodName) = 0;
 
     // Monitor that protects all non-threadsafe state; the primitives
     // that follow.
     Monitor mMonitor;
     uint64_t mNumSamplesInput;
     uint64_t mNumSamplesOutput;
     uint32_t mDecodeAhead;
+    bool mForceDecodeAhead;
     // Whether this stream exists in the media.
     bool mActive;
     bool mInputExhausted;
     bool mError;
     bool mIsFlushing;
     bool mUpdateScheduled;
     bool mDemuxEOS;
     bool mDrainComplete;
--- a/dom/media/mediasource/MediaSourceReader.cpp
+++ b/dom/media/mediasource/MediaSourceReader.cpp
@@ -40,16 +40,17 @@ extern PRLogModuleInfo* GetMediaSourceLo
 #define EOS_FUZZ_US 125000
 
 namespace mozilla {
 
 MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
   : MediaDecoderReader(aDecoder)
   , mLastAudioTime(0)
   , mLastVideoTime(0)
+  , mForceVideoDecodeAhead(false)
   , mOriginalSeekTime(-1)
   , mPendingSeekTime(-1)
   , mWaitingForSeekData(false)
   , mSeekToEnd(false)
   , mTimeThreshold(0)
   , mDropAudioBeforeThreshold(false)
   , mDropVideoBeforeThreshold(false)
   , mAudioDiscontinuity(false)
@@ -300,17 +301,19 @@ MediaSourceReader::OnAudioNotDecoded(Not
   if (mLastAudioTime - lastAudioTime >= EOS_FUZZ_US) {
     // No decoders are available to switch to. We will re-attempt from the last
     // failing position.
     mLastAudioTime = lastAudioTime;
   }
 }
 
 nsRefPtr<MediaDecoderReader::VideoDataPromise>
-MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold)
+MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe,
+                                    int64_t aTimeThreshold,
+                                    bool aForceDecodeAhead)
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(), "No sample requests allowed while seeking");
   MOZ_DIAGNOSTIC_ASSERT(mVideoPromise.IsEmpty(), "No duplicate sample requests");
   nsRefPtr<VideoDataPromise> p = mVideoPromise.Ensure(__func__);
   MSE_DEBUGV("RequestVideoData(%d, %lld), mLastVideoTime=%lld",
              aSkipToNextKeyframe, aTimeThreshold, mLastVideoTime);
   if (!mVideoTrack) {
@@ -324,16 +327,17 @@ MediaSourceReader::RequestVideoData(bool
     mDropVideoBeforeThreshold = true;
   }
   if (IsSeeking()) {
     MSE_DEBUG("called mid-seek. Rejecting.");
     mVideoPromise.Reject(CANCELED, __func__);
     return p;
   }
   MOZ_DIAGNOSTIC_ASSERT(!mVideoSeekRequest.Exists());
+  mForceVideoDecodeAhead = aForceDecodeAhead;
 
   SwitchSourceResult ret = SwitchVideoSource(&mLastVideoTime);
   switch (ret) {
     case SOURCE_NEW:
       GetVideoReader()->ResetDecode();
       mVideoSeekRequest.Begin(GetVideoReader()->Seek(GetReaderVideoTime(mLastVideoTime), 0)
                              ->Then(TaskQueue(), __func__, this,
                                     &MediaSourceReader::CompleteVideoSeekAndDoRequest,
@@ -356,17 +360,19 @@ MediaSourceReader::RequestVideoData(bool
   }
 
   return p;
 }
 
 void
 MediaSourceReader::DoVideoRequest()
 {
-  mVideoRequest.Begin(GetVideoReader()->RequestVideoData(mDropVideoBeforeThreshold, GetReaderVideoTime(mTimeThreshold))
+  mVideoRequest.Begin(GetVideoReader()->RequestVideoData(mDropVideoBeforeThreshold,
+                                                         GetReaderVideoTime(mTimeThreshold),
+                                                         mForceVideoDecodeAhead)
                       ->Then(TaskQueue(), __func__, this,
                              &MediaSourceReader::OnVideoDecoded,
                              &MediaSourceReader::OnVideoNotDecoded));
 }
 
 void
 MediaSourceReader::OnVideoDecoded(VideoData* aSample)
 {
@@ -880,16 +886,19 @@ MediaSourceReader::ResetDecode()
   // Do the same for any data wait promises.
   mAudioWaitPromise.RejectIfExists(WaitForDataRejectValue(MediaData::AUDIO_DATA, WaitForDataRejectValue::CANCELED), __func__);
   mVideoWaitPromise.RejectIfExists(WaitForDataRejectValue(MediaData::VIDEO_DATA, WaitForDataRejectValue::CANCELED), __func__);
 
   // Reset miscellaneous seeking state.
   mWaitingForSeekData = false;
   mPendingSeekTime = -1;
 
+  // Reset force video decode ahead.
+  mForceVideoDecodeAhead = false;
+
   // Reset all the readers.
   if (GetAudioReader()) {
     GetAudioReader()->ResetDecode();
   }
   if (GetVideoReader()) {
     GetVideoReader()->ResetDecode();
   }
 
--- a/dom/media/mediasource/MediaSourceReader.h
+++ b/dom/media/mediasource/MediaSourceReader.h
@@ -44,17 +44,17 @@ public:
   // registered TrackBuffers essential for initialization.
   void PrepareInitialization();
 
   bool IsWaitingMediaResources() override;
   bool IsWaitingOnCDMResource() override;
 
   nsRefPtr<AudioDataPromise> RequestAudioData() override;
   nsRefPtr<VideoDataPromise>
-  RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold) override;
+  RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold, bool aForceDecodeAhead) override;
 
   virtual size_t SizeOfVideoQueueInFrames() override;
   virtual size_t SizeOfAudioQueueInFrames() override;
 
   virtual void ReleaseMediaResources() override;
 
   void OnAudioDecoded(AudioData* aSample);
   void OnAudioNotDecoded(NotDecodedReason aReason);
@@ -250,16 +250,18 @@ private:
 #ifdef MOZ_EME
   nsRefPtr<CDMProxy> mCDMProxy;
 #endif
 
   // These are read and written on the decode task queue threads.
   int64_t mLastAudioTime;
   int64_t mLastVideoTime;
 
+  bool mForceVideoDecodeAhead;
+
   MediaPromiseRequestHolder<SeekPromise> mAudioSeekRequest;
   MediaPromiseRequestHolder<SeekPromise> mVideoSeekRequest;
   MediaPromiseHolder<SeekPromise> mSeekPromise;
 
   // Temporary seek information while we wait for the data
   // to be added to the track buffer.
   int64_t mOriginalSeekTime;
   int64_t mPendingSeekTime;
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -60,17 +60,16 @@ if CONFIG['MOZ_FMP4']:
 if CONFIG['MOZ_APPLEMEDIA']:
     DIRS += ['apple']
 
 if CONFIG['MOZ_WEBRTC']:
     DIRS += ['bridge']
 
 if CONFIG['MOZ_OMX_DECODER']:
     DIRS += ['omx']
-    DIRS += ['omx/mediaresourcemanager']
 
 if CONFIG['MOZ_EME']:
     DIRS += ['eme']
 
 TEST_DIRS += [
     'compiledtest',
     'gtest',
 ]
--- a/dom/media/omx/MediaCodecProxy.cpp
+++ b/dom/media/omx/MediaCodecProxy.cpp
@@ -94,84 +94,99 @@ MediaCodecProxy::MediaCodecProxy(sp<ALoo
   : mCodecLooper(aLooper)
   , mCodecMime(aMime)
   , mCodecEncoder(aEncoder)
   , mListener(aListener)
   , mMediaCodecLock("MediaCodecProxy::mMediaCodecLock")
   , mPendingRequestMediaResource(false)
 {
   MOZ_ASSERT(mCodecLooper != nullptr, "ALooper should not be nullptr.");
-  mResourceHandler = new MediaResourceHandler(this);
 }
 
 MediaCodecProxy::~MediaCodecProxy()
 {
-  releaseCodec();
-  SetMediaCodecFree();
+  ReleaseMediaCodec();
 }
 
 bool
 MediaCodecProxy::AskMediaCodecAndWait()
 {
-  if (mResourceHandler == nullptr) {
+  if (mResourceClient || mCodec.get()) {
     return false;
   }
 
   if (strncasecmp(mCodecMime.get(), "video/", 6) == 0) {
-    mResourceHandler->requestResource(mCodecEncoder
-        ? IMediaResourceManagerService::HW_VIDEO_ENCODER
-        : IMediaResourceManagerService::HW_VIDEO_DECODER);
+    mozilla::MediaSystemResourceType type =
+      mCodecEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
+                      mozilla::MediaSystemResourceType::VIDEO_DECODER;
+    mResourceClient = new mozilla::MediaSystemResourceClient(type);
+    mResourceClient->SetListener(this);
   } else if (strncasecmp(mCodecMime.get(), "audio/", 6) == 0) {
     if (allocateCodec()) {
       return true;
     }
-  } else {
+  }
+
+  if (!mResourceClient) {
     return false;
   }
 
   mozilla::MonitorAutoLock mon(mMediaCodecLock);
   mPendingRequestMediaResource = true;
+  // request video codec
+  mResourceClient->Acquire();
 
   while (mPendingRequestMediaResource) {
     mMediaCodecLock.Wait();
   }
   MCP_LOG("AskMediaCodecAndWait complete");
 
   return true;
 }
 
 bool
 MediaCodecProxy::AsyncAskMediaCodec()
 {
-  if ((strncasecmp(mCodecMime.get(), "video/", 6) != 0) ||
-      (mResourceHandler == nullptr)) {
+  if (mResourceClient || mCodec.get()) {
+    return false;
+  }
+
+  if (strncasecmp(mCodecMime.get(), "video/", 6) != 0) {
     return false;
   }
   // request video codec
-  mResourceHandler->requestResource(mCodecEncoder
-    ? IMediaResourceManagerService::HW_VIDEO_ENCODER
-    : IMediaResourceManagerService::HW_VIDEO_DECODER);
+  mozilla::MediaSystemResourceType type =
+    mCodecEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
+                    mozilla::MediaSystemResourceType::VIDEO_DECODER;
+  mResourceClient = new mozilla::MediaSystemResourceClient(type);
+  mResourceClient->SetListener(this);
+  mResourceClient->Acquire();
+
   return true;
 }
 
 void
-MediaCodecProxy::SetMediaCodecFree()
+MediaCodecProxy::ReleaseMediaCodec()
 {
-  if (mResourceHandler == nullptr) {
+  releaseCodec();
+
+  if (!mResourceClient) {
     return;
   }
 
   mozilla::MonitorAutoLock mon(mMediaCodecLock);
   if (mPendingRequestMediaResource) {
     mPendingRequestMediaResource = false;
     mon.NotifyAll();
   }
 
-  mResourceHandler->cancelResource();
-  mResourceHandler = nullptr;
+  if (mResourceClient) {
+    mResourceClient->ReleaseResource();
+    mResourceClient = nullptr;
+  }
 }
 
 bool
 MediaCodecProxy::allocateCodec()
 {
   if (mCodecLooper == nullptr) {
     return false;
   }
@@ -472,25 +487,24 @@ MediaCodecProxy::getCapability(uint32_t 
     capability |= kCanExposeGraphicBuffer;
   }
 
   *aCapability = capability;
 
   return OK;
 }
 
-// Called on a Binder thread
+// Called on ImageBridge thread
 void
-MediaCodecProxy::resourceReserved()
+MediaCodecProxy::ResourceReserved()
 {
   MCP_LOG("resourceReserved");
   // Create MediaCodec
-  releaseCodec();
   if (!allocateCodec()) {
-    SetMediaCodecFree();
+    ReleaseMediaCodec();
     // Notification
     sp<CodecResourceListener> listener = mListener.promote();
     if (listener != nullptr) {
       listener->codecCanceled();
     }
     return;
   }
 
@@ -501,20 +515,21 @@ MediaCodecProxy::resourceReserved()
 
   // Notification
   sp<CodecResourceListener> listener = mListener.promote();
   if (listener != nullptr) {
     listener->codecReserved();
   }
 }
 
+// Called on ImageBridge thread
 void
-MediaCodecProxy::resourceCanceled()
+MediaCodecProxy::ResourceReserveFailed()
 {
-  SetMediaCodecFree();
+  ReleaseMediaCodec();
   // Notification
   sp<CodecResourceListener> listener = mListener.promote();
   if (listener != nullptr) {
     listener->codecCanceled();
   }
 }
 
 bool MediaCodecProxy::Prepare()
@@ -635,18 +650,17 @@ status_t MediaCodecProxy::Output(MediaBu
   if (flags & MediaCodec::BUFFER_FLAG_EOS) {
     return ERROR_END_OF_STREAM;
   }
   return err;
 }
 
 void MediaCodecProxy::ReleaseMediaResources()
 {
-  releaseCodec();
-  SetMediaCodecFree();
+  ReleaseMediaCodec();
 }
 
 void MediaCodecProxy::ReleaseMediaBuffer(MediaBuffer* aBuffer) {
   if (aBuffer) {
     sp<MetaData> metaData = aBuffer->meta_data();
     int32_t index;
     metaData->findInt32(kKeyBufferIndex, &index);
     aBuffer->release();
--- a/dom/media/omx/MediaCodecProxy.h
+++ b/dom/media/omx/MediaCodecProxy.h
@@ -6,27 +6,30 @@
 
 #ifndef MEDIA_CODEC_PROXY_H
 #define MEDIA_CODEC_PROXY_H
 
 #include <nsString.h>
 #include <stagefright/MediaCodec.h>
 #include <stagefright/MediaBuffer.h>
 #include <utils/threads.h>
-#include "MediaResourceHandler.h"
+
+#include "mozilla/media/MediaSystemResourceClient.h"
 #include "mozilla/Monitor.h"
+#include "nsRefPtr.h"
 
 namespace android {
 // This class is intended to be a proxy for MediaCodec with codec resource
 // management. Basically user can use it like MediaCodec, but need to handle
 // the listener when Codec is reserved for Async case. A good example is
 // MediaCodecReader.cpp. Another useage is to use configure(), Prepare(),
 // Input(), and Output(). It is used in GonkVideoDecoderManager.cpp which
 // doesn't need to handle the buffers for codec.
-class MediaCodecProxy : public MediaResourceHandler::ResourceListener
+class MediaCodecProxy : public RefBase
+                      , public mozilla::MediaSystemResourceReservationListener
 {
 public:
   /* Codec resource notification listener.
    * All functions are called on the Binder thread.
    */
   struct CodecResourceListener : public virtual RefBase {
     /* The codec resource is reserved and can be granted.
      * The client can allocate the requested resource.
@@ -132,32 +135,32 @@ public:
   void ReleaseMediaResources();
   // This updates mOutputBuffer when receiving INFO_OUTPUT_BUFFERS_CHANGED event.
   bool UpdateOutputBuffers();
 
   void ReleaseMediaBuffer(MediaBuffer* abuffer);
 
   // It asks for the OMX codec and blocked until the resource is grant to be
   // allocated.
+  // Audio codec allocation should use this.
   bool AskMediaCodecAndWait();
 
   // It asks for the OMX codec asynchronously.
   // Only video codec is supported.
   bool AsyncAskMediaCodec();
 
   // Free the OMX codec so others can allocate it.
-  void SetMediaCodecFree();
+  void ReleaseMediaCodec();
 
 protected:
   virtual ~MediaCodecProxy();
 
-  // MediaResourceHandler::EventListener::resourceReserved()
-  virtual void resourceReserved();
-  // MediaResourceHandler::EventListener::resourceCanceled()
-  virtual void resourceCanceled();
+  // MediaResourceReservationListener
+  void ResourceReserved() override;
+  void ResourceReserveFailed() override;
 
 private:
   // Forbidden
   MediaCodecProxy() = delete;
   MediaCodecProxy(const MediaCodecProxy &) = delete;
   const MediaCodecProxy &operator=(const MediaCodecProxy &) = delete;
 
   // Constructor for MediaCodecProxy::CreateByType
@@ -175,17 +178,17 @@ private:
   sp<ALooper> mCodecLooper;
   nsCString mCodecMime;
   bool mCodecEncoder;
 
   // Codec Resource Notification Listener
   wp<CodecResourceListener> mListener;
 
   // Media Resource Management
-  sp<MediaResourceHandler> mResourceHandler;
+  nsRefPtr<mozilla::MediaSystemResourceClient> mResourceClient;
 
   // MediaCodec instance
   mutable RWLock mCodecLock;
   sp<MediaCodec> mCodec;
 
   //MediaCodec buffers to hold input/output data.
   Vector<sp<ABuffer> > mInputBuffers;
   Vector<sp<ABuffer> > mOutputBuffers;
--- a/dom/media/omx/MediaCodecReader.cpp
+++ b/dom/media/omx/MediaCodecReader.cpp
@@ -348,17 +348,18 @@ MediaCodecReader::RequestAudioData()
     DispatchAudioTask();
   }
   MOZ_ASSERT(mAudioTrack.mAudioPromise.IsEmpty());
   return mAudioTrack.mAudioPromise.Ensure(__func__);
 }
 
 nsRefPtr<MediaDecoderReader::VideoDataPromise>
 MediaCodecReader::RequestVideoData(bool aSkipToNextKeyframe,
-                                   int64_t aTimeThreshold)
+                                   int64_t aTimeThreshold,
+                                   bool aForceDecodeAhead)
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_ASSERT(HasVideo());
 
   int64_t threshold = sInvalidTimestampUs;
   if (aSkipToNextKeyframe && IsValidTimestampUs(aTimeThreshold)) {
     threshold = aTimeThreshold;
   }
--- a/dom/media/omx/MediaCodecReader.h
+++ b/dom/media/omx/MediaCodecReader.h
@@ -78,17 +78,18 @@ protected:
 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;
+                   int64_t aTimeThreshold,
+                   bool aForceDecodeAhead) override;
 
   // Disptach a DecodeAduioDataTask to decode video data.
   virtual nsRefPtr<AudioDataPromise> RequestAudioData() override;
 
   virtual bool HasAudio();
   virtual bool HasVideo();
 
   virtual nsRefPtr<MediaDecoderReader::MetadataPromise> AsyncReadMetadata() override;
--- a/dom/media/omx/MediaOmxCommonDecoder.cpp
+++ b/dom/media/omx/MediaOmxCommonDecoder.cpp
@@ -23,16 +23,17 @@ namespace mozilla {
 extern PRLogModuleInfo* gMediaDecoderLog;
 #define DECODER_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg)
 
 MediaOmxCommonDecoder::MediaOmxCommonDecoder()
   : MediaDecoder()
   , mReader(nullptr)
   , mCanOffloadAudio(false)
   , mFallbackToStateMachine(false)
+  , mIsCaptured(false)
 {
   mDormantSupported = true;
   if (!gMediaDecoderLog) {
     gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
   }
 }
 
 MediaOmxCommonDecoder::~MediaOmxCommonDecoder() {}
@@ -43,18 +44,17 @@ MediaOmxCommonDecoder::SetPlatformCanOff
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   mCanOffloadAudio = aCanOffloadAudio;
 }
 
 bool
 MediaOmxCommonDecoder::CheckDecoderCanOffloadAudio()
 {
   return (mCanOffloadAudio && !mFallbackToStateMachine &&
-          !(GetStateMachine() && GetStateMachine()->GetDecodedStream()) &&
-          mPlaybackRate == 1.0);
+          !mIsCaptured && mPlaybackRate == 1.0);
 }
 
 void
 MediaOmxCommonDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
                                         MediaDecoderEventVisibility aEventVisibility)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -178,16 +178,18 @@ MediaOmxCommonDecoder::AudioOffloadTearD
 }
 
 void
 MediaOmxCommonDecoder::AddOutputStream(ProcessedMediaStream* aStream,
                                        bool aFinishWhenEnded)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
+  mIsCaptured = true;
+
   if (mAudioOffloadPlayer) {
     ResumeStateMachine();
   }
 
   MediaDecoder::AddOutputStream(aStream, aFinishWhenEnded);
 }
 
 void
--- a/dom/media/omx/MediaOmxCommonDecoder.h
+++ b/dom/media/omx/MediaOmxCommonDecoder.h
@@ -59,13 +59,16 @@ protected:
   nsAutoPtr<AudioOffloadPlayerBase> mAudioOffloadPlayer;
 
   // Set by Media*Reader to denote current track can be offloaded
   bool mCanOffloadAudio;
 
   // Set when offload playback of current track fails in the middle and need to
   // fallback to state machine
   bool mFallbackToStateMachine;
+
+  // True if the media element is captured.
+  bool mIsCaptured;
 };
 
 } // namespace mozilla
 
 #endif // MEDIA_OMX_COMMON_DECODER_H
--- a/dom/media/omx/OMXCodecProxy.cpp
+++ b/dom/media/omx/OMXCodecProxy.cpp
@@ -11,18 +11,16 @@
 #include <cutils/properties.h>
 #include <stagefright/foundation/ADebug.h>
 #include <stagefright/MetaData.h>
 #include <stagefright/OMXCodec.h>
 #include <utils/Log.h>
 
 #include "nsDebug.h"
 
-#include "IMediaResourceManagerService.h"
-
 #include "OMXCodecProxy.h"
 
 namespace android {
 
 // static
 sp<OMXCodecProxy> OMXCodecProxy::Create(
         const sp<IOMX> &omx,
         const sp<MetaData> &meta, bool createEncoder,
@@ -55,50 +53,45 @@ OMXCodecProxy::OMXCodecProxy(
         const sp<ANativeWindow> &nativeWindow)
     : mOMX(omx),
       mSrcMeta(meta),
       mComponentName(nullptr),
       mIsEncoder(createEncoder),
       mFlags(flags),
       mNativeWindow(nativeWindow),
       mSource(source),
-      mState(MediaResourceManagerClient::CLIENT_STATE_WAIT_FOR_RESOURCE)
+      mState(ResourceState::START)
 {
 }
 
 OMXCodecProxy::~OMXCodecProxy()
 {
-  mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
+  mState = ResourceState::END;
 
   if (mOMXCodec.get()) {
     wp<MediaSource> tmp = mOMXCodec;
     mOMXCodec.clear();
     while (tmp.promote() != nullptr) {
         // this value come from stagefrigh's AwesomePlayer.
         usleep(1000);
     }
   }
   // Complete all pending Binder ipc transactions
   IPCThreadState::self()->flushCommands();
 
-  if (mManagerService.get() && mClient.get()) {
-    mManagerService->cancelClient(mClient, IMediaResourceManagerService::HW_VIDEO_DECODER);
+  if (mResourceClient) {
+    mResourceClient->ReleaseResource();
+    mResourceClient = nullptr;
   }
 
   mSource.clear();
   free(mComponentName);
   mComponentName = nullptr;
 }
 
-MediaResourceManagerClient::State OMXCodecProxy::getState()
-{
-  Mutex::Autolock autoLock(mLock);
-  return mState;
-}
-
 void OMXCodecProxy::setListener(const wp<CodecResourceListener>& listener)
 {
   Mutex::Autolock autoLock(mLock);
   mListener = listener;
 }
 
 void OMXCodecProxy::notifyResourceReserved()
 {
@@ -115,58 +108,50 @@ void OMXCodecProxy::notifyResourceCancel
     listener->codecCanceled();
   }
 }
 
 void OMXCodecProxy::requestResource()
 {
   Mutex::Autolock autoLock(mLock);
 
-  if (mClient.get()) {
+  if (mResourceClient) {
     return;
   }
-  sp<MediaResourceManagerClient::EventListener> listener = this;
-  mClient = new MediaResourceManagerClient(listener);
+  mState = ResourceState::WAITING;
 
-  mManagerService = mClient->getMediaResourceManagerService();
-  if (!mManagerService.get()) {
-    mClient = nullptr;
-    return;
-  }
-
-  mManagerService->requestMediaResource(mClient, IMediaResourceManagerService::HW_VIDEO_DECODER, true /* will wait */);
+  mozilla::MediaSystemResourceType type = mIsEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
+                                                 mozilla::MediaSystemResourceType::VIDEO_DECODER;
+  mResourceClient = new mozilla::MediaSystemResourceClient(type);
+  mResourceClient->SetListener(this);
+  mResourceClient->Acquire();
 }
 
-// called on Binder ipc thread
-void OMXCodecProxy::statusChanged(int event)
+// Called on ImageBridge thread
+void
+OMXCodecProxy::ResourceReserved()
 {
   Mutex::Autolock autoLock(mLock);
 
-  if (mState != MediaResourceManagerClient::CLIENT_STATE_WAIT_FOR_RESOURCE) {
-    return;
-  }
-
-  mState = (MediaResourceManagerClient::State) event;
-  if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
-    notifyResourceCanceled();
+  if (mState != ResourceState::WAITING) {
     return;
   }
 
   const char *mime;
   if (!mSrcMeta->findCString(kKeyMIMEType, &mime)) {
-    mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
+    mState = ResourceState::END;
     notifyResourceCanceled();
     return;
   }
 
   if (!strncasecmp(mime, "video/", 6)) {
     sp<MediaSource> codec;
     mOMXCodec = OMXCodec::Create(mOMX, mSrcMeta, mIsEncoder, mSource, mComponentName, mFlags, mNativeWindow);
     if (mOMXCodec == nullptr) {
-      mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
+      mState = ResourceState::END;
       notifyResourceCanceled();
       return;
     }
     // Check if this video is sized such that we're comfortable
     // possibly using an OMX decoder.
     int32_t maxWidth, maxHeight;
     char propValue[PROPERTY_VALUE_MAX];
     property_get("ro.moz.omx.hw.max_width", propValue, "-1");
@@ -177,81 +162,91 @@ void OMXCodecProxy::statusChanged(int ev
     int32_t width = -1, height = -1;
     if (maxWidth > 0 && maxHeight > 0 &&
         !(mOMXCodec->getFormat()->findInt32(kKeyWidth, &width) &&
           mOMXCodec->getFormat()->findInt32(kKeyHeight, &height) &&
           width * height <= maxWidth * maxHeight)) {
       printf_stderr("Failed to get video size, or it was too large for HW decoder (<w=%d, h=%d> but <maxW=%d, maxH=%d>)",
                     width, height, maxWidth, maxHeight);
       mOMXCodec.clear();
-      mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
+      mState = ResourceState::END;
       notifyResourceCanceled();
       return;
     }
 
     if (mOMXCodec->start() != OK) {
       NS_WARNING("Couldn't start OMX video source");
       mOMXCodec.clear();
-      mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
+      mState = ResourceState::END;
       notifyResourceCanceled();
       return;
     }
   }
+
+  mState = ResourceState::ACQUIRED;
   notifyResourceReserved();
 }
 
+// Called on ImageBridge thread
+void
+OMXCodecProxy::ResourceReserveFailed()
+{
+  Mutex::Autolock autoLock(mLock);
+  mState = ResourceState::NOT_ACQUIRED;
+}
+
 status_t OMXCodecProxy::start(MetaData *params)
 {
   Mutex::Autolock autoLock(mLock);
 
-  if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
+  if (mState != ResourceState::ACQUIRED) {
     return NO_INIT;
   }
   CHECK(mOMXCodec.get() != nullptr);
   return mOMXCodec->start();
 }
 
 status_t OMXCodecProxy::stop()
 {
   Mutex::Autolock autoLock(mLock);
 
-  if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
+  if (mState != ResourceState::ACQUIRED) {
     return NO_INIT;
   }
   CHECK(mOMXCodec.get() != nullptr);
   return mOMXCodec->stop();
 }
 
 sp<MetaData> OMXCodecProxy::getFormat()
 {
   Mutex::Autolock autoLock(mLock);
 
-  if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
+  if (mState != ResourceState::ACQUIRED) {
     sp<MetaData> meta = new MetaData;
     return meta;
   }
   CHECK(mOMXCodec.get() != nullptr);
   return mOMXCodec->getFormat();
 }
 
 status_t OMXCodecProxy::read(MediaBuffer **buffer, const ReadOptions *options)
 {
   Mutex::Autolock autoLock(mLock);
 
-  if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
+  if (mState != ResourceState::ACQUIRED) {
     return NO_INIT;
   }
   CHECK(mOMXCodec.get() != nullptr);
   return mOMXCodec->read(buffer, options);
 }
 
 status_t OMXCodecProxy::pause()
 {
   Mutex::Autolock autoLock(mLock);
 
-  if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
+  if (mState != ResourceState::ACQUIRED) {
     return NO_INIT;
   }
   CHECK(mOMXCodec.get() != nullptr);
   return mOMXCodec->pause();
 }
 
 }  // namespace android
--- a/dom/media/omx/OMXCodecProxy.h
+++ b/dom/media/omx/OMXCodecProxy.h
@@ -8,24 +8,25 @@
 
 
 #include <android/native_window.h>
 #include <media/IOMX.h>
 #include <stagefright/MediaBuffer.h>
 #include <stagefright/MediaSource.h>
 #include <utils/threads.h>
 
-#include "MediaResourceManagerClient.h"
+#include "mozilla/media/MediaSystemResourceClient.h"
+#include "nsRefPtr.h"
 
 namespace android {
 
 struct MetaData;
 
-class OMXCodecProxy : public MediaSource,
-                      public MediaResourceManagerClient::EventListener
+class OMXCodecProxy : public MediaSource
+                    , public mozilla::MediaSystemResourceReservationListener
 {
 public:
   /* Codec resource notification listener.
    * All functions are called on the Binder thread.
    */
   struct CodecResourceListener : public virtual RefBase {
     /* The codec resource is reserved and can be granted.
      * The client can allocate the requested resource.
@@ -33,32 +34,40 @@ public:
     virtual void codecReserved() = 0;
     /* The codec resource is not reserved any more.
      * The client should release the resource as soon as possible if the
      * resource is still being held.
      */
     virtual void codecCanceled() = 0;
   };
 
+  // Enumeration for the valid resource allcoation states
+  enum class ResourceState : int8_t {
+    START,
+    WAITING,
+    ACQUIRED,
+    NOT_ACQUIRED,
+    END
+  };
+
   static sp<OMXCodecProxy> Create(
           const sp<IOMX> &omx,
           const sp<MetaData> &meta, bool createEncoder,
           const sp<MediaSource> &source,
           const char *matchComponentName = nullptr,
           uint32_t flags = 0,
           const sp<ANativeWindow> &nativeWindow = nullptr);
 
-    MediaResourceManagerClient::State getState();
-
     void setListener(const wp<CodecResourceListener>& listener);
 
     void requestResource();
 
-    // MediaResourceManagerClient::EventListener
-    virtual void statusChanged(int event);
+    // MediaSystemResourceReservationListener
+    void ResourceReserved() override;
+    void ResourceReserveFailed() override;
 
     // MediaSource
     virtual status_t start(MetaData *params = nullptr);
     virtual status_t stop();
 
     virtual sp<MetaData> getFormat();
 
     virtual status_t read(
@@ -95,19 +104,19 @@ private:
     bool mIsEncoder;
     // Flags specified in the creation of the codec.
     uint32_t mFlags;
     sp<ANativeWindow> mNativeWindow;
 
     sp<MediaSource> mSource;
 
     sp<MediaSource> mOMXCodec;
-    sp<MediaResourceManagerClient> mClient;
-    MediaResourceManagerClient::State mState;
 
-    sp<IMediaResourceManagerService> mManagerService;
+    nsRefPtr<mozilla::MediaSystemResourceClient> mResourceClient;
+    ResourceState mState;
+
     // Codec Resource Notification Listener
     wp<CodecResourceListener> mListener;
 };
 
 }  // namespace android
 
 #endif  // OMX_CODEC_PROXY_DECODER_H_
--- a/dom/media/omx/OMXCodecWrapper.cpp
+++ b/dom/media/omx/OMXCodecWrapper.cpp
@@ -12,17 +12,17 @@
 #include <media/ICrypto.h>
 #include <media/IOMX.h>
 #include <OMX_Component.h>
 #include <stagefright/MediaDefs.h>
 #include <stagefright/MediaErrors.h>
 
 #include "AudioChannelFormat.h"
 #include "GrallocImages.h"
-#include <mozilla/Monitor.h>
+#include "mozilla/Monitor.h"
 #include "mozilla/layers/GrallocTextureClient.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 
 #define INPUT_BUFFER_TIMEOUT_US (5 * 1000ll)
 // AMR NB kbps
@@ -40,37 +40,31 @@ enum BufferState
   BUFFER_OK,
   BUFFER_FAIL,
   WAIT_FOR_NEW_BUFFER
 };
 
 bool
 OMXCodecReservation::ReserveOMXCodec()
 {
-  if (!mManagerService.get()) {
-    sp<MediaResourceManagerClient::EventListener> listener = this;
-    mClient = new MediaResourceManagerClient(listener);
-
-    mManagerService = mClient->getMediaResourceManagerService();
-    if (!mManagerService.get()) {
-      mClient = nullptr;
-      return true; // not really in use, but not usable
-    }
+  if (mClient) {
+    // Already tried reservation.
+    return false;
   }
-  return (mManagerService->requestMediaResource(mClient, mType, false) == OK); // don't wait
+  mClient = new mozilla::MediaSystemResourceClient(mType);
+  return mClient->AcquireSyncNoWait(); // don't wait if resrouce is not available
 }
 
 void
 OMXCodecReservation::ReleaseOMXCodec()
 {
-  if (!mManagerService.get() || !mClient.get()) {
+  if (!mClient) {
     return;
   }
-
-  mManagerService->cancelClient(mClient, mType);
+  mClient->ReleaseResource();
 }
 
 OMXAudioEncoder*
 OMXCodecWrapper::CreateAACEncoder()
 {
   nsAutoPtr<OMXAudioEncoder> aac(new OMXAudioEncoder(CodecType::AAC_ENC));
   // Return the object only when media codec is valid.
   NS_ENSURE_TRUE(aac->IsValid(), nullptr);
--- a/dom/media/omx/OMXCodecWrapper.h
+++ b/dom/media/omx/OMXCodecWrapper.h
@@ -10,53 +10,48 @@
 #include <utils/RefBase.h>
 #include <stagefright/foundation/ABuffer.h>
 #include <stagefright/foundation/AMessage.h>
 #include <stagefright/MediaCodec.h>
 
 #include "AudioSegment.h"
 #include "GonkNativeWindow.h"
 #include "GonkNativeWindowClient.h"
-
-#include "IMediaResourceManagerService.h"
-#include "MediaResourceManagerClient.h"
+#include "mozilla/media/MediaSystemResourceClient.h"
+#include "nsRefPtr.h"
 
 #include <speex/speex_resampler.h>
 
 namespace android {
 
 // Wrapper class for managing HW codec reservations
-class OMXCodecReservation : public MediaResourceManagerClient::EventListener
+class OMXCodecReservation : public RefBase
 {
 public:
   OMXCodecReservation(bool aEncoder)
   {
-    mType = aEncoder ? IMediaResourceManagerService::HW_VIDEO_ENCODER :
-            IMediaResourceManagerService::HW_VIDEO_DECODER;
+    mType = aEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
+            mozilla::MediaSystemResourceType::VIDEO_DECODER;
   }
 
   virtual ~OMXCodecReservation()
   {
     ReleaseOMXCodec();
   }
 
   /** Reserve the Encode or Decode resource for this instance */
   virtual bool ReserveOMXCodec();
 
   /** Release the Encode or Decode resource for this instance */
   virtual void ReleaseOMXCodec();
 
-  // MediaResourceManagerClient::EventListener
-  virtual void statusChanged(int event) {}
+private:
+  mozilla::MediaSystemResourceType mType;
 
-private:
-  IMediaResourceManagerService::ResourceType mType;
-
-  sp<MediaResourceManagerClient> mClient;
-  sp<IMediaResourceManagerService> mManagerService;
+  nsRefPtr<mozilla::MediaSystemResourceClient> mClient;
 };
 
 
 class OMXAudioEncoder;
 class OMXVideoEncoder;
 
 /**
  * This class (and its subclasses) wraps the video and audio codec from
--- a/dom/media/omx/RtspMediaCodecReader.cpp
+++ b/dom/media/omx/RtspMediaCodecReader.cpp
@@ -77,20 +77,23 @@ nsRefPtr<MediaDecoderReader::AudioDataPr
 RtspMediaCodecReader::RequestAudioData()
 {
   EnsureActive();
   return MediaCodecReader::RequestAudioData();
 }
 
 nsRefPtr<MediaDecoderReader::VideoDataPromise>
 RtspMediaCodecReader::RequestVideoData(bool aSkipToNextKeyframe,
-                                       int64_t aTimeThreshold)
+                                       int64_t aTimeThreshold,
+                                       bool aForceDecodeAhead)
 {
   EnsureActive();
-  return MediaCodecReader::RequestVideoData(aSkipToNextKeyframe, aTimeThreshold);
+  return MediaCodecReader::RequestVideoData(aSkipToNextKeyframe,
+                                            aTimeThreshold,
+                                            aForceDecodeAhead);
 }
 
 nsRefPtr<MediaDecoderReader::MetadataPromise>
 RtspMediaCodecReader::AsyncReadMetadata()
 {
   mRtspResource->DisablePlayoutDelay();
   EnsureActive();
 
--- a/dom/media/omx/RtspMediaCodecReader.h
+++ b/dom/media/omx/RtspMediaCodecReader.h
@@ -48,17 +48,18 @@ public:
     return media::TimeIntervals::Invalid();
   }
 
   virtual void SetIdle() override;
 
   // Disptach a DecodeVideoFrameTask to decode video data.
   virtual nsRefPtr<VideoDataPromise>
   RequestVideoData(bool aSkipToNextKeyframe,
-                   int64_t aTimeThreshold) override;
+                   int64_t aTimeThreshold,
+                   bool aForceDecodeAhead) override;
 
   // Disptach a DecodeAudioDataTask to decode audio data.
   virtual nsRefPtr<AudioDataPromise> RequestAudioData() override;
 
   virtual nsRefPtr<MediaDecoderReader::MetadataPromise> AsyncReadMetadata()
     override;
 
   virtual void HandleResourceAllocated() override;
deleted file mode 100644
--- a/dom/media/omx/mediaresourcemanager/IMediaResourceManagerClient.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "IMediaResourceManagerClient"
-#include <utils/Log.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-
-#include "IMediaResourceManagerClient.h"
-
-namespace android {
-
-enum {
-    STATUS_CHANGED = IBinder::FIRST_CALL_TRANSACTION
-};
-
-class BpMediaResourceManagerClient : public BpInterface<IMediaResourceManagerClient>
-{
-public:
-    BpMediaResourceManagerClient(const sp<IBinder>& impl)
-        : BpInterface<IMediaResourceManagerClient>(impl)
-    {
-    }
-
-    void statusChanged(int event)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaResourceManagerClient::getInterfaceDescriptor());
-        data.writeInt32(event);
-        remote()->transact(STATUS_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
-    }
-};
-
-IMPLEMENT_META_INTERFACE(MediaResourceManagerClient, "android.media.IMediaResourceManagerClient");
-
-// ----------------------------------------------------------------------
-
-status_t BnMediaResourceManagerClient::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    switch(code) {
-    case STATUS_CHANGED: {
-            CHECK_INTERFACE(IMediaResourceManagerClient, data, reply);
-            int event = data.readInt32();
-            statusChanged(event);
-            return NO_ERROR;
-        } break;
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
deleted file mode 100644
--- a/dom/media/omx/mediaresourcemanager/IMediaResourceManagerClient.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef ANDROID_IMEDIARESOURCEMANAGERCLIENT_H
-#define ANDROID_IMEDIARESOURCEMANAGERCLIENT_H
-
-#include <utils/RefBase.h>
-#include <binder/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class IMediaResourceManagerClient : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(MediaResourceManagerClient);
-
-    // Notifies a change of media resource request status.
-    virtual void statusChanged(int event) = 0;
-
-};
-
-
-// ----------------------------------------------------------------------------
-
-class BnMediaResourceManagerClient : public BnInterface<IMediaResourceManagerClient>
-{
-public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IMEDIARESOURCEMANAGERCLIENT_H
deleted file mode 100644
--- a/dom/media/omx/mediaresourcemanager/IMediaResourceManagerDeathNotifier.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
-** Copyright 2010, The Android Open Source Project
-** Copyright 2013, Mozilla Foundation
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "IMediaResourceManagerDeathNotifier"
-#include <utils/Log.h>
-
-#include <binder/IServiceManager.h>
-#include <binder/IPCThreadState.h>
-
-#include "IMediaResourceManagerDeathNotifier.h"
-
-#define DN_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
-#define DN_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
-#define DN_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
-#define DN_LOGE_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-
-namespace android {
-
-// client singleton for binder interface to services
-Mutex IMediaResourceManagerDeathNotifier::sServiceLock;
-sp<IMediaResourceManagerService> IMediaResourceManagerDeathNotifier::sMediaResourceManagerService;
-sp<IMediaResourceManagerDeathNotifier::DeathNotifier> IMediaResourceManagerDeathNotifier::sDeathNotifier;
-SortedVector< wp<IMediaResourceManagerDeathNotifier> > IMediaResourceManagerDeathNotifier::sObitRecipients;
-
-// establish binder interface to MediaResourceManagerService
-/*static*/const sp<IMediaResourceManagerService>&
-IMediaResourceManagerDeathNotifier::getMediaResourceManagerService()
-{
-    DN_LOGV("getMediaResourceManagerService");
-    Mutex::Autolock _l(sServiceLock);
-    if (sMediaResourceManagerService.get() == 0) {
-        sp<IServiceManager> sm = defaultServiceManager();
-        sp<IBinder> binder;
-        do {
-            binder = sm->getService(String16("media.resource_manager"));
-            if (binder != 0) {
-                break;
-             }
-             DN_LOGW("Media resource manager service not published, waiting...");
-             usleep(500000); // 0.5 s
-        } while(true);
-
-        if (sDeathNotifier == NULL) {
-        sDeathNotifier = new DeathNotifier();
-    }
-    binder->linkToDeath(sDeathNotifier);
-    sMediaResourceManagerService = interface_cast<IMediaResourceManagerService>(binder);
-    }
-    DN_LOGE_IF(sMediaResourceManagerService == 0, "no media player service!?");
-    return sMediaResourceManagerService;
-}
-
-/*static*/ void
-IMediaResourceManagerDeathNotifier::addObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient)
-{
-    Mutex::Autolock _l(sServiceLock);
-    sObitRecipients.add(recipient);
-}
-
-/*static*/ void
-IMediaResourceManagerDeathNotifier::removeObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient)
-{
-    Mutex::Autolock _l(sServiceLock);
-    sObitRecipients.remove(recipient);
-}
-
-void
-IMediaResourceManagerDeathNotifier::DeathNotifier::binderDied(const wp<IBinder>& who)
-{
-    DN_LOGW("media resource manager service died");
-    // Need to do this with the lock held
-    SortedVector< wp<IMediaResourceManagerDeathNotifier> > list;
-    {
-        Mutex::Autolock _l(sServiceLock);
-        sMediaResourceManagerService.clear();
-        list = sObitRecipients;
-    }
-
-    // Notify application when media server dies.
-    // Don't hold the static lock during callback in case app
-    // makes a call that needs the lock.
-    size_t count = list.size();
-    for (size_t iter = 0; iter < count; ++iter) {
-        sp<IMediaResourceManagerDeathNotifier> notifier = list[iter].promote();
-        if (notifier != 0) {
-            notifier->died();
-        }
-    }
-}
-
-IMediaResourceManagerDeathNotifier::DeathNotifier::~DeathNotifier()
-{
-    Mutex::Autolock _l(sServiceLock);
-    sObitRecipients.clear();
-    if (sMediaResourceManagerService != 0) {
-        sMediaResourceManagerService->asBinder()->unlinkToDeath(this);
-    }
-}
-
-}; // namespace android
deleted file mode 100644
--- a/dom/media/omx/mediaresourcemanager/IMediaResourceManagerDeathNotifier.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
-** Copyright 2010, The Android Open Source Project
-** Copyright 2013, Mozilla Foundation
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_IMEDIARESOURCEMANAGERDEATHNOTIFIER_H
-#define ANDROID_IMEDIARESOURCEMANAGERDEATHNOTIFIER_H
-
-#include <utils/threads.h>
-#include <utils/SortedVector.h>
-
-#include "IMediaResourceManagerService.h"
-
-namespace android {
-
-/**
- * Handle MediaResourceManagerService's death notification.
- * Made from android's IMediaDeathNotifier class.
- */
-class IMediaResourceManagerDeathNotifier: virtual public RefBase
-{
-public:
-    IMediaResourceManagerDeathNotifier() { addObitRecipient(this); }
-    virtual ~IMediaResourceManagerDeathNotifier() { removeObitRecipient(this); }
-
-    virtual void died() = 0;
-    static const sp<IMediaResourceManagerService>& getMediaResourceManagerService();
-
-private:
-    IMediaResourceManagerDeathNotifier &operator=(const IMediaResourceManagerDeathNotifier &);
-    IMediaResourceManagerDeathNotifier(const IMediaResourceManagerDeathNotifier &);
-
-    static void addObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient);
-    static void removeObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient);
-
-    class DeathNotifier: public IBinder::DeathRecipient
-    {
-    public:
-                DeathNotifier() {}
-        virtual ~DeathNotifier();
-
-        virtual void binderDied(const wp<IBinder>& who);
-    };
-
-    friend class DeathNotifier;
-
-    static  Mutex                                   sServiceLock;
-    static  sp<IMediaResourceManagerService>        sMediaResourceManagerService;
-    static  sp<DeathNotifier>                       sDeathNotifier;
-    static  SortedVector< wp<IMediaResourceManagerDeathNotifier> > sObitRecipients;
-};
-
-}; // namespace android
-
-#endif // ANDROID_IMEDIARESOURCEMANAGERDEATHNOTIFIER_H
deleted file mode 100644
--- a/dom/media/omx/mediaresourcemanager/IMediaResourceManagerService.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "IMediaResourceManagerService"
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-#include <utils/Log.h>
-
-#include "IMediaResourceManagerService.h"
-
-namespace android {
-
-/**
- * Function ID used between BpMediaResourceManagerService and 
- *  BnMediaResourceManagerService by using Binder ipc.
- */
-enum {
-    REQUEST_MEDIA_RESOURCE = IBinder::FIRST_CALL_TRANSACTION,
-    DEREGISTER_CLIENT
-};
-
-class BpMediaResourceManagerService : public BpInterface<IMediaResourceManagerService>
-{
-public:
-    BpMediaResourceManagerService(const sp<IBinder>& impl)
-        : BpInterface<IMediaResourceManagerService>(impl)
-    {
-    }
-
-    virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType, bool willWait)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaResourceManagerService::getInterfaceDescriptor());
-        data.writeStrongBinder(client->asBinder());
-        data.writeInt32(resourceType);
-        data.writeInt32(willWait ? 1 : 0);
-        remote()->transact(REQUEST_MEDIA_RESOURCE, data, &reply);
-        return reply.readInt32();
-    }
-
-    virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client, int resourceType)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaResourceManagerService::getInterfaceDescriptor());
-        data.writeStrongBinder(client->asBinder());
-        data.writeInt32(resourceType);
-        remote()->transact(DEREGISTER_CLIENT, data, &reply);
-        return reply.readInt32();
-    }
-};
-
-IMPLEMENT_META_INTERFACE(MediaResourceManagerService, "android.media.IMediaResourceManagerService");
-
-// ----------------------------------------------------------------------
-
-status_t BnMediaResourceManagerService::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    switch(code) {
-
-        case REQUEST_MEDIA_RESOURCE: {
-            CHECK_INTERFACE(IMediaResourceManagerService, data, reply);
-            sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(data.readStrongBinder());
-            int resourceType = data.readInt32();
-            bool willWait = (data.readInt32() == 1);
-            status_t result = requestMediaResource(client, resourceType, willWait);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        } break;
-        case DEREGISTER_CLIENT: {
-            CHECK_INTERFACE(IMediaResourceManagerService, data, reply);
-            sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(data.readStrongBinder());
-            int resourceType = data.readInt32();
-            status_t result = cancelClient(client, resourceType);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        } break;
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
deleted file mode 100644
--- a/dom/media/omx/mediaresourcemanager/IMediaResourceManagerService.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef ANDROID_IMEDIARESOURCEMANAGERSERVICE_H
-#define ANDROID_IMEDIARESOURCEMANAGERSERVICE_H
-
-#include <utils/RefBase.h>
-#include <binder/IInterface.h>
-
-#include "IMediaResourceManagerClient.h"
-
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class IMediaResourceManagerService : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(MediaResourceManagerService);
-
-    // Enumeration for the resource types
-    enum ResourceType {
-      HW_VIDEO_DECODER = 0,
-      HW_AUDIO_DECODER,  // Not supported currently.
-      HW_VIDEO_ENCODER,
-      HW_AUDIO_ENCODER,  // Not supported currently.
-      HW_CAMERA,          // Not supported currently.
-      NUM_OF_RESOURCE_TYPES,
-      INVALID_RESOURCE_TYPE = -1
-    };
-
-    enum ErrorCode {
-        RESOURCE_NOT_AVAILABLE = -EAGAIN
-    };
-
-    // Request a media resource for IMediaResourceManagerClient.
-    // client is the binder that service will notify (through
-    // IMediaResourceManagerClient::statusChanged()) when request status changed.
-    // resourceType is type of resource that client would like to request.
-    // willWait indicates that, when the resource is not currently available
-    // (i.e., already in use by another client), if the client wants to wait. If
-    // true, client will be put into a (FIFO) waiting list and be notified when
-    // resource is available.
-    // For unsupported types, this function returns BAD_TYPE. For supported
-    // types, it always returns OK when willWait is true; otherwise it will
-    // return true when resouce is available, or RESOURCE_NOT_AVAILABLE when
-    // resouce is in use.
-    virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType, bool willWait) = 0;
-    // Cancel a media resource request and a resource allocated to IMediaResourceManagerClient.
-    // Client must call this function after it's done with the media resource requested.
-    virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client, int resourceType) = 0;
-};
-
-
-// ----------------------------------------------------------------------------
-
-class BnMediaResourceManagerService : public BnInterface<IMediaResourceManagerService>
-{
-public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IMEDIARESOURCEMANAGERSERVICE_H
deleted file mode 100644
--- a/dom/media/omx/mediaresourcemanager/MediaResourceHandler.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "MediaResourceHandler.h"
-
-namespace android {
-
-MediaResourceHandler::MediaResourceHandler(const wp<ResourceListener> &aListener)
-  : mListener(aListener)
-  , mType(IMediaResourceManagerService::INVALID_RESOURCE_TYPE)
-  , mWaitingResource(false)
-{
-}
-
-MediaResourceHandler::~MediaResourceHandler()
-{
-  cancelResource();
-}
-
-bool
-MediaResourceHandler::IsWaitingResource()
-{
-  Mutex::Autolock al(mLock);
-  return mWaitingResource;
-}
-
-bool
-MediaResourceHandler::requestResource(IMediaResourceManagerService::ResourceType aType)
-{
-  Mutex::Autolock al(mLock);
-
-  if (mClient != nullptr && mService != nullptr) {
-    return false;
-  }
-
-  sp<MediaResourceManagerClient> client = new MediaResourceManagerClient(this);
-  sp<IMediaResourceManagerService> service = client->getMediaResourceManagerService();
-
-  if (service == nullptr) {
-    return false;
-  }
-
-  if (service->requestMediaResource(client, (int)aType, true) != OK) {
-    return false;
-  }
-
-  mClient = client;
-  mService = service;
-  mType = aType;
-  mWaitingResource = true;
-
-  return true;
-}
-
-void
-MediaResourceHandler::cancelResource()
-{
-  Mutex::Autolock al(mLock);
-
-  if (mClient != nullptr && mService != nullptr) {
-    mService->cancelClient(mClient, (int)mType);
-  }
-
-  mWaitingResource = false;
-  mClient = nullptr;
-  mService = nullptr;
-}
-
-// Called on a Binder thread
-void
-MediaResourceHandler::statusChanged(int aEvent)
-{
-  sp<ResourceListener> listener;
-
-  Mutex::Autolock autoLock(mLock);
-
-  listener = mListener.promote();
-  if (listener == nullptr) {
-    return;
-  }
-
-  mWaitingResource = false;
-
-  MediaResourceManagerClient::State state = (MediaResourceManagerClient::State)aEvent;
-  if (state == MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
-    listener->resourceReserved();
-  } else {
-    listener->resourceCanceled();
-  }
-}
-
-} // namespace android
deleted file mode 100644
--- a/dom/media/omx/mediaresourcemanager/MediaResourceHandler.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef MEDIA_RESOURCE_HANDLER_H
-#define MEDIA_RESOURCE_HANDLER_H
-
-#include <utils/threads.h>
-
-#include <mozilla/Attributes.h>
-
-#include "MediaResourceManagerClient.h"
-
-namespace android {
-
-class MediaResourceHandler : public MediaResourceManagerClient::EventListener
-{
-public:
-  /* Resource notification listener.
-   * All functions are called on the Binder thread.
-   */
-  struct ResourceListener : public virtual RefBase {
-    /* The resource is reserved and can be granted.
-     * The client can allocate the requested resource.
-     */
-    virtual void resourceReserved() = 0;
-    /* The resource is not reserved any more.
-     * The client should release the resource as soon as possible if the
-     * resource is still being held.
-     */
-    virtual void resourceCanceled() = 0;
-  };
-
-  MediaResourceHandler(const wp<ResourceListener> &aListener);
-
-  virtual ~MediaResourceHandler();
-
-  // Request Resource
-  bool requestResource(IMediaResourceManagerService::ResourceType aType);
-  // Cancel Resource
-  void cancelResource();
-
-  bool IsWaitingResource();
-
-protected:
-  // MediaResourceManagerClient::EventListener::statusChanged()
-  virtual void statusChanged(int event);
-
-private:
-  // Forbidden
-  MediaResourceHandler() = delete;
-  MediaResourceHandler(const MediaResourceHandler &) = delete;
-  const MediaResourceHandler &operator=(const MediaResourceHandler &) = delete;
-
-  // Resource Notification Listener
-  wp<ResourceListener> mListener;
-
-  // Resource Management
-  Mutex mLock;
-  sp<IMediaResourceManagerClient> mClient;
-  sp<IMediaResourceManagerService> mService;
-  IMediaResourceManagerService::ResourceType mType;
-
-  bool mWaitingResource;
-};
-
-} // namespace android
-
-#endif // MEDIA_RESOURCE_HANDLER_H
deleted file mode 100644
--- a/dom/media/omx/mediaresourcemanager/MediaResourceManagerClient.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaResourceManagerClient"
-
-#include <utils/Log.h>
-
-#include "MediaResourceManagerClient.h"
-
-namespace android {
-
-MediaResourceManagerClient::MediaResourceManagerClient(const wp<EventListener>& listener)
-  : mEventListener(listener)
-{
-}
-
-void MediaResourceManagerClient::statusChanged(int event)
-{
-  if (mEventListener != NULL) {
-    sp<EventListener> listener = mEventListener.promote();
-    if (listener != NULL) {
-      listener->statusChanged(event);
-    }
-  }
-}
-
-void MediaResourceManagerClient::died()
-{
-  sp<EventListener> listener = mEventListener.promote();
-  if (listener != NULL) {
-    listener->statusChanged(CLIENT_STATE_SHUTDOWN);
-  }
-}
-
-}; // namespace android
-
deleted file mode 100644
--- a/dom/media/omx/mediaresourcemanager/MediaResourceManagerClient.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef ANDROID_MEDIARESOURCEMANAGERCLIENT_H
-#define ANDROID_MEDIARESOURCEMANAGERCLIENT_H
-
-#include "IMediaResourceManagerClient.h"
-#include "IMediaResourceManagerDeathNotifier.h"
-
-namespace android {
-
-class MediaResourceManagerClient: public BnMediaResourceManagerClient,
-                                  public virtual IMediaResourceManagerDeathNotifier
-{
-public:
-  // Enumeration for the valid decoding states
-  enum State {
-    CLIENT_STATE_WAIT_FOR_RESOURCE,
-    CLIENT_STATE_RESOURCE_ASSIGNED,
-    CLIENT_STATE_SHUTDOWN
-  };
-
-  struct EventListener : public virtual RefBase {
-    // Notifies a change of media resource request status.
-    virtual void statusChanged(int event) = 0;
-  };
-
-  MediaResourceManagerClient(const wp<EventListener>& listener);
-
-  // DeathRecipient
-  void            died();
-
-  // IMediaResourceManagerClient
-  virtual void statusChanged(int event);
-
-private:
-  wp<EventListener> mEventListener;
-};
-
-}; // namespace android
-
-#endif // ANDROID_IMEDIARESOURCEMANAGERCLIENT_H
deleted file mode 100644
--- a/dom/media/omx/mediaresourcemanager/MediaResourceManagerService.cpp
+++ /dev/null
@@ -1,371 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaResourceManagerService"
-
-#include <mozilla/Assertions.h>
-
-#include <binder/IServiceManager.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <utils/Log.h>
-
-#include "MediaResourceManagerClient.h"
-#include "MediaResourceManagerService.h"
-
-namespace android {
-
-const char* MediaResourceManagerService::kMsgKeyResourceType = "res-type";
-
-/* static */
-void MediaResourceManagerService::instantiate() {
-  defaultServiceManager()->addService(
-            String16("media.resource_manager"),
-            new MediaResourceManagerService());
-}
-
-MediaResourceManagerService::MediaResourceManagerService()
-{
-  mLooper = new ALooper;
-  mLooper->setName("MediaResourceManagerService");
-
-  mReflector = new AHandlerReflector<MediaResourceManagerService>(this);
-  // Register AMessage handler to ALooper.
-  mLooper->registerHandler(mReflector);
-  // Start ALooper thread.
-  mLooper->start();
-}
-
-MediaResourceManagerService::~MediaResourceManagerService()
-{
-  // Unregister AMessage handler from ALooper.
-  mLooper->unregisterHandler(mReflector->id());
-  // Stop ALooper thread.
-  mLooper->stop();
-}
-
-void MediaResourceManagerService::binderDied(const wp<IBinder>& who)
-{
-  if (who != NULL) {
-    Mutex::Autolock autoLock(mLock);
-    sp<IBinder> binder = who.promote();
-    if (binder != NULL) {
-      mResources.forgetClient(binder);
-    }
-  }
-}
-
-status_t MediaResourceManagerService::requestMediaResource(const sp<IMediaResourceManagerClient>& client,
-                                                           int resourceType, bool willWait)
-{
-  ResourceType type = static_cast<ResourceType>(resourceType);
-  // Support only HW_VIDEO_DECODER and HW_VIDEO_ENCODER.
-  switch (type) {
-    case HW_VIDEO_DECODER:
-    case HW_VIDEO_ENCODER:
-      break;
-    default:
-      // Type not supported.
-      return BAD_TYPE;
-  }
-
-  Mutex::Autolock autoLock(mLock);
-
-  // Must know if it will be granted or not - if there are enough unfufilled requests to
-  // use up the resource, fail.  Otherwise we know that enqueuing under lock will succeed.
-  if (!willWait &&
-      (mResources.findAvailableResource(type, mResources.countRequests(type) + 1) ==
-       NAME_NOT_FOUND)) {
-    return RESOURCE_NOT_AVAILABLE;
-  }
-  // We could early-return here without enqueuing IF we can do the rest of
-  // the allocation safely here.  However, enqueuing ensures there's only
-  // one copy of that code, and that any callbacks are made from the same
-  // context.
-
-  sp<IBinder> binder = client->asBinder();
-  mResources.enqueueRequest(binder, type);
-  binder->linkToDeath(this);
-
-  sp<AMessage> notify = new AMessage(kNotifyRequest, mReflector->id());
-  notify->setInt32(kMsgKeyResourceType, resourceType);
-  // Post AMessage to MediaResourceManagerService via ALooper.
-  notify->post();
-
-  return OK;
-}
-
-status_t MediaResourceManagerService::cancelClient(const sp<IMediaResourceManagerClient>& client,
-                                                   int resourceType)
-{
-  Mutex::Autolock autoLock(mLock);
-
-  sp<IBinder> binder = client->asBinder();
-  cancelClientLocked(binder, static_cast<ResourceType>(resourceType));
-
-  sp<AMessage> notify = new AMessage(kNotifyRequest, mReflector->id());
-  notify->setInt32(kMsgKeyResourceType, resourceType);
-  // Next!
-  // Note: since we held the lock while releasing and then posting, if there is
-  // a queue, no willWait==false entries can jump into the queue thinking they'll
-  // get the resource.
-  notify->post();
-
-  return NO_ERROR;
-}
-
-// Extract resource type from message.
-static int32_t getResourceType(const sp<AMessage>& message)
-{
-  int32_t resourceType = MediaResourceManagerService::INVALID_RESOURCE_TYPE;
-  return message->findInt32(MediaResourceManagerService::kMsgKeyResourceType, &resourceType) ?
-          resourceType : MediaResourceManagerService::INVALID_RESOURCE_TYPE;
-}
-
-// Called on ALooper thread.
-void MediaResourceManagerService::onMessageReceived(const sp<AMessage> &msg)
-{
-  Mutex::Autolock autoLock(mLock);
-  ResourceType type = static_cast<ResourceType>(getResourceType(msg));
-
-  // Note: a message is sent both for "I added an entry to the queue"
-  // (which may succeed, typically if the queue is empty), and for "I gave
-  // up the resource", in which case it's "give to the next waiting client,
-  // or no one".
-
-  // Exit if no resource is available, but leave the client in the waiting
-  // list.
-  int found = mResources.findAvailableResource(type);
-  if (found == NAME_NOT_FOUND) {
-    return;
-  }
-
-  // Exit if no request.
-  if (!mResources.hasRequest(type)) {
-    return;
-  }
-
-  sp<IBinder> req = mResources.nextRequest(type);
-  mResources.aquireResource(req, type, found);
-  // Notify resource assignment to the client.
-  sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(req);
-  client->statusChanged(MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED);
-  mResources.dequeueRequest(type);
-}
-
-void MediaResourceManagerService::cancelClientLocked(const sp<IBinder>& binder,
-                                                     ResourceType resourceType)
-{
-  mResources.forgetClient(binder, resourceType);
-  binder->unlinkToDeath(this);
-}
-
-MediaResourceManagerService::ResourceTable::ResourceTable()
-{
-  // Populate types of resources.
-  for (int type = 0; type < NUM_OF_RESOURCE_TYPES; type++) {
-    ssize_t index = mMap.add(static_cast<ResourceType>(type), Resources());
-    Resources& resources = mMap.editValueAt(index);
-    int available;
-    switch (type) {
-      case HW_VIDEO_DECODER:
-        available = VIDEO_DECODER_COUNT;
-        break;
-      case HW_VIDEO_ENCODER:
-        available = VIDEO_ENCODER_COUNT;
-        break;
-      default:
-        available = 0;
-        break;
-    }
-    resources.mSlots.insertAt(0, available);
-  }
-}
-
-MediaResourceManagerService::ResourceTable::~ResourceTable() {
-  // Remove resouces.
-  mMap.clear();
-}
-
-bool MediaResourceManagerService::ResourceTable::supportsType(ResourceType type)
-{
-  return mMap.indexOfKey(type) != NAME_NOT_FOUND;
-}
-
-ssize_t MediaResourceManagerService::ResourceTable::findAvailableResource(ResourceType type,
-                                                                          size_t numberNeeded)
-{
-  MOZ_ASSERT(numberNeeded > 0);
-  ssize_t found = mMap.indexOfKey(type);
-  if (found == NAME_NOT_FOUND) {
-    // Unsupported type.
-    return found;
-  }
-  const Slots& slots = mMap.valueAt(found).mSlots;
-
-  found = NAME_NOT_FOUND;
-  for (size_t i = 0; i < slots.size(); i++) {
-    if (slots[i].mClient != nullptr) {
-      // Already in use.
-      continue;
-    }
-    if (--numberNeeded == 0) {
-      found = i;
-      break;
-    }
-  }
-
-  return found;
-}
-
-bool MediaResourceManagerService::ResourceTable::isOwnedByClient(const sp<IBinder>& client,
-                                                                 ResourceType type,
-                                                                 size_t index)
-{
-  ResourceSlot* slot = resourceOfTypeAt(type, index);
-  return slot && slot->mClient == client;
-}
-
-status_t MediaResourceManagerService::ResourceTable::aquireResource(const sp<IBinder>& client,
-                                                                    ResourceType type,
-                                                                    size_t index)
-{
-  ResourceSlot* slot = resourceOfTypeAt(type, index);
-  // Resouce should not be in use.
-  MOZ_ASSERT(slot && slot->mClient == nullptr);
-  if (!slot) {
-    return NAME_NOT_FOUND;
-  } else if (slot->mClient != nullptr) {
-    // Resource already in use by other client.
-    return PERMISSION_DENIED;
-  }
-
-  slot->mClient = client;
-
-
-  return OK;
-}
-
-MediaResourceManagerService::ResourceSlot*
-MediaResourceManagerService::ResourceTable::resourceOfTypeAt(ResourceType type,
-                                                             size_t index)
-{
-  ssize_t found = mMap.indexOfKey(type);
-  if (found == NAME_NOT_FOUND) {
-    // Unsupported type.
-    return nullptr;
-  }
-
-  Slots& slots = mMap.editValueAt(found).mSlots;
-  MOZ_ASSERT(index < slots.size());
-  if (index >= slots.size()) {
-    // Index out of range.
-    return nullptr;
-  }
-  return &(slots.editItemAt(index));
-}
-
-bool MediaResourceManagerService::ResourceTable::hasRequest(ResourceType type)
-{
-  ssize_t found = mMap.indexOfKey(type);
-  if (found == NAME_NOT_FOUND) {
-    // Unsupported type.
-    return nullptr;
-  }
-
-  const Fifo& queue = mMap.valueAt(found).mRequestQueue;
-  return !queue.empty();
-}
-
-uint32_t MediaResourceManagerService::ResourceTable::countRequests(ResourceType type)
-{
-  ssize_t found = mMap.indexOfKey(type);
-  if (found == NAME_NOT_FOUND) {
-    // Unsupported type.
-    return 0;
-  }
-
-  const Fifo& queue = mMap.valueAt(found).mRequestQueue;
-  return queue.size();
-}
-
-sp<IBinder> MediaResourceManagerService::ResourceTable::nextRequest(ResourceType type)
-{
-  ssize_t found = mMap.indexOfKey(type);
-  if (found == NAME_NOT_FOUND) {
-    // Unsupported type.
-    return nullptr;
-  }
-
-  const Fifo& queue = mMap.valueAt(found).mRequestQueue;
-  return *(queue.begin());
-}
-
-status_t MediaResourceManagerService::ResourceTable::enqueueRequest(const sp<IBinder>& client,
-                                                                    ResourceType type)
-{
-  ssize_t found = mMap.indexOfKey(type);
-  if (found == NAME_NOT_FOUND) {
-    // Unsupported type.
-    return found;
-  }
-
-  mMap.editValueAt(found).mRequestQueue.push_back(client);
-  return OK;
-}
-
-status_t MediaResourceManagerService::ResourceTable::dequeueRequest(ResourceType type)
-{
-  ssize_t found = mMap.indexOfKey(type);
-  if (found == NAME_NOT_FOUND) {
-    // Unsupported type.
-    return found;
-  }
-
-  Fifo& queue = mMap.editValueAt(found).mRequestQueue;
-  queue.erase(queue.begin());
-  return OK;
-}
-
-status_t MediaResourceManagerService::ResourceTable::forgetClient(const sp<IBinder>& client)
-{
-  // Traverse all resources.
-  for (size_t i = 0; i < mMap.size(); i++) {
-    forgetClient(client, mMap.keyAt(i));
-  }
-  return OK;
-}
-
-status_t MediaResourceManagerService::ResourceTable::forgetClient(const sp<IBinder>& client, ResourceType type)
-{
-  MOZ_ASSERT(supportsType(type));
-
-  Resources& resources = mMap.editValueFor(type);
-
-  // Remove pending requests for given client.
-  Fifo& queue = resources.mRequestQueue;
-  Fifo::iterator it(queue.begin());
-  while (it != queue.end()) {
-    if ((*it).get() == client.get()) {
-      queue.erase(it);
-      break;
-    }
-    it++;
-  }
-
-  // Revoke ownership for given client.
-  Slots& slots = resources.mSlots;
-  for (size_t i = 0; i < slots.size(); i++) {
-    ResourceSlot& slot = slots.editItemAt(i);
-    if (client.get() == slot.mClient.get()) {
-      slot.mClient = nullptr;
-    }
-  }
-
-  return OK;
-}
-
-}; // namespace android
deleted file mode 100644
--- a/dom/media/omx/mediaresourcemanager/MediaResourceManagerService.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef ANDROID_MEDIARESOURCEMANAGERSERVICE_H
-#define ANDROID_MEDIARESOURCEMANAGERSERVICE_H
-
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AHandlerReflector.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <utils/KeyedVector.h>
-#include <utils/List.h>
-#include <utils/RefBase.h>
-#include <utils/Vector.h>
-
-#include "IMediaResourceManagerClient.h"
-#include "IMediaResourceManagerService.h"
-
-namespace android {
-
-/**
- * Manage permissions of using media resources(hw decoder, hw encoder, camera)
- * XXX Current implementation supports only one hw video codec.
- *     Need to extend to support multiple instance and other resources.
- */
-class MediaResourceManagerService: public BnMediaResourceManagerService,
-                                   public IBinder::DeathRecipient
-{
-public:
-  // The maximum number of hardware resoureces available.
-  enum
-  {
-    VIDEO_DECODER_COUNT = 1,
-    VIDEO_ENCODER_COUNT = 1
-  };
-
-  enum
-  {
-    kNotifyRequest = 'noti',
-  };
-
-  static const char* kMsgKeyResourceType;
-
-  // Instantiate MediaResourceManagerService and register to service manager.
-  // If service manager is not present, wait until service manager becomes present.
-  static  void instantiate();
-
-  // DeathRecipient
-  virtual void binderDied(const wp<IBinder>& who);
-
-  // derived from IMediaResourceManagerService
-  virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client,
-                                        int resourceType, bool willWait);
-  virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client,
-                                int resourceType);
-
-  // Receive a message from AHandlerReflector.
-  // Called on ALooper thread.
-  void onMessageReceived(const sp<AMessage> &msg);
-
-protected:
-  MediaResourceManagerService();
-  virtual ~MediaResourceManagerService();
-
-private:
-  // Represent a media resouce.
-  // Hold a IMediaResourceManagerClient that got a media resource as IBinder.
-  struct ResourceSlot
-  {
-    sp<IBinder> mClient;
-  };
-  typedef Vector<ResourceSlot> Slots;
-
-  typedef List<sp<IBinder> > Fifo;
-  struct Resources
-  {
-    // Queue of media resource requests. Hold IMediaResourceManagerClient that
-    // requesting a media resource as IBinder.
-    Fifo mRequestQueue;
-    // All resources that can be requested. Hold |ResourceSlot|s that track
-    // their usage.
-    Slots mSlots;
-  };
-
-  typedef KeyedVector<ResourceType, Resources> ResourcesMap;
-  // Manages requests from clients and availability of resources.
-  class ResourceTable
-  {
-    ResourceTable();
-    ~ResourceTable();
-    // Resource operations.
-    bool supportsType(ResourceType type);
-    ssize_t findAvailableResource(ResourceType type, size_t number_needed = 1);
-    bool isOwnedByClient(const sp<IBinder>& client, ResourceType type, size_t index);
-    status_t aquireResource(const sp<IBinder>& client, ResourceType type, size_t index);
-    ResourceSlot* resourceOfTypeAt(ResourceType type, size_t index);
-    // Request operations.
-    bool hasRequest(ResourceType type);
-    uint32_t countRequests(ResourceType type);
-    sp<IBinder> nextRequest(ResourceType type);
-    status_t enqueueRequest(const sp<IBinder>& client, ResourceType type);
-    status_t dequeueRequest(ResourceType type);
-    status_t forgetClient(const sp<IBinder>& client, ResourceType type);
-    status_t forgetClient(const sp<IBinder>& client);
-
-    friend class MediaResourceManagerService;
-
-    // A map for all types of supported resources.
-    ResourcesMap mMap;
-  };
-
-  void cancelClientLocked(const sp<IBinder>& binder, ResourceType resourceType);
-
-  // ALooper is a message loop used in stagefright.
-  // It creates a thread for messages and handles messages in the thread.
-  // ALooper is a clone of Looper in android Java.
-  // http://developer.android.com/reference/android/os/Looper.html
-  sp<ALooper> mLooper;
-  // deliver a message to a wrapped object(OmxDecoder).
-  // AHandlerReflector is similar to Handler in android Java.
-  // http://developer.android.com/reference/android/os/Handler.html
-  sp<AHandlerReflector<MediaResourceManagerService> > mReflector;
-
-  // The lock protects manager operations called from multiple threads.
-  Mutex mLock;
-
-  // Keeps all the records.
-  ResourceTable mResources;
-};
-
-}; // namespace android
-
-#endif // ANDROID_MEDIARESOURCEMANAGERSERVICE_H
deleted file mode 100644
--- a/dom/media/omx/mediaresourcemanager/moz.build
+++ /dev/null
@@ -1,47 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-EXPORTS += [
-    'IMediaResourceManagerClient.h',
-    'IMediaResourceManagerDeathNotifier.h',
-    'IMediaResourceManagerService.h',
-    'MediaResourceHandler.h',
-    'MediaResourceManagerClient.h',
-    'MediaResourceManagerService.h',
-]
-
-SOURCES += [
-    'IMediaResourceManagerClient.cpp',
-    'IMediaResourceManagerDeathNotifier.cpp',
-    'IMediaResourceManagerService.cpp',
-    'MediaResourceHandler.cpp',
-    'MediaResourceManagerClient.cpp',
-    'MediaResourceManagerService.cpp',
-]
-
-include('/ipc/chromium/chromium-config.mozbuild')
-
-# Suppress some GCC/clang warnings being treated as errors:
-#  - about multi-character constants which are used in codec-related code
-if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
-  CXXFLAGS += [
-    '-Wno-error=multichar'
-  ]
-
-CXXFLAGS += [
-    '-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [
-        'frameworks/base/include',
-        'frameworks/base/include/binder',
-        'frameworks/base/include/utils',
-        'frameworks/base/include/media/',
-        'frameworks/base/include/media/stagefright/openmax',
-        'frameworks/base/media/libstagefright/include',
-    ]
-]
-
-FINAL_LIBRARY = 'xul'
-
-FAIL_ON_WARNINGS = True
--- a/dom/media/omx/moz.build
+++ b/dom/media/omx/moz.build
@@ -89,17 +89,16 @@ if CONFIG['GNU_CC'] or CONFIG['CLANG_CL'
     '-Wno-error=multichar'
   ]
 
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '/dom/base',
     '/dom/html',
     '/ipc/chromium/src',
-    'mediaresourcemanager',
 ]
 
 CXXFLAGS += [
     '-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [
         'dalvik/libnativehelper/include/nativehelper',
         'frameworks/av/include/media',
         'frameworks/base/include',
         'frameworks/base/include/binder',
--- a/dom/media/platforms/gonk/moz.build
+++ b/dom/media/platforms/gonk/moz.build
@@ -13,17 +13,16 @@ EXPORTS += [
 UNIFIED_SOURCES += [
     'GonkAudioDecoderManager.cpp',
     'GonkDecoderModule.cpp',
     'GonkMediaDataDecoder.cpp',
     'GonkVideoDecoderManager.cpp',
 ]
 LOCAL_INCLUDES += [
     '/dom/media/omx/',
-    '/dom/media/omx/mediaresourcemanager',
 ]
 include('/ipc/chromium/chromium-config.mozbuild')
 
 # Suppress some GCC/clang warnings being treated as errors:
 #  - about attributes on forward declarations for types that are already
 #    defined, which complains about an important MOZ_EXPORT for android::AString
 #  - about multi-character constants which are used in codec-related code
 if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
new file mode 100644
--- /dev/null
+++ b/dom/media/systemservices/MediaSystemResourceClient.cpp
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/Monitor.h"
+#include "mozilla/ReentrantMonitor.h"
+
+#include "MediaSystemResourceClient.h"
+
+namespace mozilla {
+
+Atomic<uint32_t> MediaSystemResourceClient::sSerialCounter(0);
+
+MediaSystemResourceClient::MediaSystemResourceClient(MediaSystemResourceType aReourceType)
+  : mResourceType(aReourceType)
+  , mId(++sSerialCounter)
+  , mListener(nullptr)
+  , mResourceState(RESOURCE_STATE_START)
+  , mIsSync(false)
+  , mAcquireSyncWaitMonitor(nullptr)
+  , mAcquireSyncWaitDone(nullptr)
+{
+  mManager = MediaSystemResourceManager::Get();
+  if (mManager) {
+    mManager->Register(this);
+  }
+}
+
+MediaSystemResourceClient::~MediaSystemResourceClient()
+{
+  ReleaseResource();
+  if (mManager) {
+    mManager->Unregister(this);
+  }
+}
+
+bool
+MediaSystemResourceClient::SetListener(MediaSystemResourceReservationListener* aListener)
+{
+  if (!mManager) {
+    return false;
+  }
+  return mManager->SetListener(this, aListener);
+}
+
+void
+MediaSystemResourceClient::Acquire()
+{
+  if (!mManager) {
+    return;
+  }
+  mManager->Acquire(this);
+}
+
+bool
+MediaSystemResourceClient::AcquireSyncNoWait()
+{
+  if (!mManager) {
+    return false;
+  }
+  return mManager->AcquireSyncNoWait(this);
+}
+
+void
+MediaSystemResourceClient::ReleaseResource()
+{
+  if (!mManager) {
+    return;
+  }
+  mManager->ReleaseResource(this);
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/systemservices/MediaSystemResourceClient.h
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#if !defined(MediaSystemResourceClient_h_)
+#define MediaSystemResourceClient_h_
+
+#include "MediaSystemResourceManager.h"
+#include "MediaSystemResourceTypes.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/media/MediaSystemResourceTypes.h"
+#include "mozilla/Monitor.h"
+#include "nsRefPtr.h"
+
+namespace mozilla {
+
+class MediaSystemResourceManager;
+
+
+/**
+ * This is a base class for listener callbacks.
+ * This callback is invoked when the media system resource reservation state
+ * is changed.
+ */
+class MediaSystemResourceReservationListener {
+public:
+  virtual void ResourceReserved() = 0;
+  virtual void ResourceReserveFailed() = 0;
+};
+
+/**
+ * MediaSystemResourceClient is used to reserve a media system resource
+ * like hw decoder. When system has a limitation of a media resource,
+ * use this class to mediate use rights of the resource.
+ */
+class MediaSystemResourceClient
+{
+public:
+
+  // Enumeration for the valid decoding states
+  enum ResourceState {
+    RESOURCE_STATE_START,
+    RESOURCE_STATE_WAITING,
+    RESOURCE_STATE_ACQUIRED,
+    RESOURCE_STATE_NOT_ACQUIRED,
+    RESOURCE_STATE_END
+  };
+
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaSystemResourceClient)
+
+  explicit MediaSystemResourceClient(MediaSystemResourceType aReourceType);
+
+  bool SetListener(MediaSystemResourceReservationListener* aListener);
+
+  // Try to acquire media resource asynchronously.
+  // If the resource is used by others, wait until acquired.
+  void Acquire();
+
+  // Try to acquire media resource synchronously. If the resource is not immediately
+  // available, fail to acquire it.
+  // return false if resource is not acquired.
+  // return true if resource is acquired.
+  //
+  // This function should not be called on ImageBridge thread.
+  // It should be used only for compatibility with legacy code.
+  bool AcquireSyncNoWait();
+
+  void ReleaseResource();
+
+private:
+  ~MediaSystemResourceClient();
+
+  nsRefPtr<MediaSystemResourceManager> mManager;
+  const MediaSystemResourceType mResourceType;
+  const uint32_t mId;
+
+  // Modified only by MediaSystemResourceManager.
+  // Accessed and modified with MediaSystemResourceManager::mReentrantMonitor held.
+  MediaSystemResourceReservationListener* mListener;
+  ResourceState mResourceState;
+  bool mIsSync;
+  ReentrantMonitor* mAcquireSyncWaitMonitor;
+  bool* mAcquireSyncWaitDone;
+
+  static mozilla::Atomic<uint32_t> sSerialCounter;
+
+  friend class MediaSystemResourceManager;
+};
+
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/media/systemservices/MediaSystemResourceManager.cpp
@@ -0,0 +1,425 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gfxPrefs.h"
+#include "MediaSystemResourceManagerChild.h"
+#include "MediaTaskQueue.h"
+#include "mozilla/layers/ImageBridgeChild.h"
+
+#include "MediaSystemResourceManager.h"
+
+namespace mozilla {
+
+using namespace mozilla::ipc;
+using namespace mozilla::layers;
+
+/* static */ StaticRefPtr<MediaSystemResourceManager> MediaSystemResourceManager::sSingleton;
+
+/* static */ MediaSystemResourceManager*
+MediaSystemResourceManager::Get()
+{
+  if (sSingleton) {
+    return sSingleton;
+  }
+  MediaSystemResourceManager::Init();
+  return sSingleton;
+}
+
+/* static */ void
+MediaSystemResourceManager::Shutdown()
+{
+  MOZ_ASSERT(InImageBridgeChildThread());
+  if (sSingleton) {
+    sSingleton->CloseIPC();
+    sSingleton = nullptr;
+  }
+}
+
+/* static */ bool
+MediaSystemResourceManager::IsMediaSystemResourceManagerEnabled()
+{
+#ifdef MOZ_WIDGET_GONK
+  return true;
+#else
+  // XXX MediaSystemResourceManager is enabled only when ImageBridge is enabled.
+  // MediaSystemResourceManager uses ImageBridge's thread.
+  if (gfxPrefs::AsyncVideoOOPEnabled() &&
+      gfxPrefs::AsyncVideoEnabled()) {
+    return true;
+  } else  {
+    return false;
+  }
+#endif
+}
+
+class RunnableCallTask : public Task
+{
+public:
+  explicit RunnableCallTask(nsIRunnable* aRunnable)
+    : mRunnable(aRunnable) {}
+
+  void Run() override
+  {
+    mRunnable->Run();
+  }
+protected:
+  nsCOMPtr<nsIRunnable> mRunnable;
+};
+
+/* static */ void
+MediaSystemResourceManager::Init()
+{
+  MOZ_ASSERT(IsMediaSystemResourceManagerEnabled());
+  if (!ImageBridgeChild::IsCreated()) {
+    NS_WARNING("ImageBridge does not exist");
+    return;
+  }
+
+  if (InImageBridgeChildThread()) {
+    if (!sSingleton) {
+#ifdef DEBUG
+      static int timesCreated = 0;
+      timesCreated++;
+      MOZ_ASSERT(timesCreated == 1);
+#endif
+      sSingleton = new MediaSystemResourceManager();
+    }
+    return;
+  }
+
+  ReentrantMonitor barrier("MediaSystemResourceManager::Init");
+  ReentrantMonitorAutoEnter autoMon(barrier);
+  bool done = false;
+
+  nsCOMPtr<nsIRunnable> runnable =
+    NS_NewRunnableFunction([&]() {
+      if (!sSingleton) {
+        sSingleton = new MediaSystemResourceManager();
+      }
+      ReentrantMonitorAutoEnter autoMon(barrier);
+      done = true;
+      barrier.NotifyAll();
+    });
+
+  ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
+    FROM_HERE, new RunnableCallTask(runnable));
+
+  // should stop the thread until done.
+  while (!done) {
+    barrier.Wait();
+  }
+
+}
+
+MediaSystemResourceManager::MediaSystemResourceManager()
+  : mReentrantMonitor("MediaSystemResourceManager.mReentrantMonitor")
+  , mShutDown(false)
+  , mChild(nullptr)
+{
+  MOZ_ASSERT(InImageBridgeChildThread());
+  OpenIPC();
+}
+
+MediaSystemResourceManager::~MediaSystemResourceManager()
+{
+  MOZ_ASSERT(IsIpcClosed());
+}
+
+void
+MediaSystemResourceManager::OpenIPC()
+{
+  MOZ_ASSERT(InImageBridgeChildThread());
+  MOZ_ASSERT(!mChild);
+
+  media::PMediaSystemResourceManagerChild* child =
+    ImageBridgeChild::GetSingleton()->SendPMediaSystemResourceManagerConstructor();
+  mChild = static_cast<media::MediaSystemResourceManagerChild*>(child);
+  mChild->SetManager(this);
+}
+
+void
+MediaSystemResourceManager::CloseIPC()
+{
+  MOZ_ASSERT(InImageBridgeChildThread());
+
+  if (!mChild) {
+    return;
+  }
+  mChild->Destroy();
+  mChild = nullptr;
+  mShutDown = true;
+}
+
+void
+MediaSystemResourceManager::OnIpcClosed()
+{
+  mChild = nullptr;
+}
+
+bool
+MediaSystemResourceManager::IsIpcClosed()
+{
+  return mChild ? true : false;
+}
+
+void
+MediaSystemResourceManager::Register(MediaSystemResourceClient* aClient)
+{
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  MOZ_ASSERT(aClient);
+  MOZ_ASSERT(!mResourceClients.Get(aClient->mId));
+
+  mResourceClients.Put(aClient->mId, aClient);
+}
+
+void
+MediaSystemResourceManager::Unregister(MediaSystemResourceClient* aClient)
+{
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  MOZ_ASSERT(aClient);
+  MOZ_ASSERT(mResourceClients.Get(aClient->mId));
+  MOZ_ASSERT(mResourceClients.Get(aClient->mId) == aClient);
+
+  mResourceClients.Remove(aClient->mId);
+}
+
+bool
+MediaSystemResourceManager::SetListener(MediaSystemResourceClient* aClient,
+                                  MediaSystemResourceReservationListener* aListener)
+{
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  MOZ_ASSERT(aClient);
+
+  MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
+  MOZ_ASSERT(client);
+
+  if (!client) {
+    return false;
+  }
+  // State Check
+  if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_START) {
+    return false;
+  }
+  aClient->mListener = aListener;
+  return true;
+}
+
+void
+MediaSystemResourceManager::Acquire(MediaSystemResourceClient* aClient)
+{
+  MOZ_ASSERT(aClient);
+  MOZ_ASSERT(!InImageBridgeChildThread());
+
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
+  MOZ_ASSERT(client);
+  MOZ_ASSERT(client == aClient);
+
+  aClient->mIsSync = false; // async request
+
+  if (!client) {
+    HandleAcquireResult(aClient->mId, false);
+    return;
+  }
+  // State Check
+  if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_START) {
+    HandleAcquireResult(aClient->mId, false);
+    return;
+  }
+  aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_WAITING;
+  ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
+    FROM_HERE,
+    NewRunnableMethod(
+      this,
+      &MediaSystemResourceManager::DoAcquire,
+      aClient->mId));
+}
+
+bool
+MediaSystemResourceManager::AcquireSyncNoWait(MediaSystemResourceClient* aClient)
+{
+  MOZ_ASSERT(aClient);
+  MOZ_ASSERT(!InImageBridgeChildThread());
+
+  ReentrantMonitor barrier("MediaSystemResourceManager::AcquireSyncNoWait");
+  ReentrantMonitorAutoEnter autoMon(barrier);
+  bool done = false;
+  {
+    ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+    MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
+    MOZ_ASSERT(client);
+    MOZ_ASSERT(client == aClient);
+
+    aClient->mIsSync = true; // sync request
+
+    if (InImageBridgeChildThread()) {
+      HandleAcquireResult(aClient->mId, false);
+      return false;
+    }
+    if (!aClient ||
+        !client ||
+        client != aClient) {
+      HandleAcquireResult(aClient->mId, false);
+      return false;
+    }
+    // State Check
+    if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_START) {
+      HandleAcquireResult(aClient->mId, false);
+      return false;
+    }
+    // Hold barrier Monitor until acquire task end.
+    aClient->mAcquireSyncWaitMonitor = &barrier;
+    aClient->mAcquireSyncWaitDone = &done;
+    aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_WAITING;
+  }
+
+  ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
+    FROM_HERE,
+    NewRunnableMethod(
+      this,
+      &MediaSystemResourceManager::DoAcquire,
+      aClient->mId));
+
+  // should stop the thread until done.
+  while (!done) {
+    barrier.Wait();
+  }
+
+  {
+    ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+    if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_ACQUIRED) {
+      return false;
+    }
+    return true;
+  }
+}
+
+void
+MediaSystemResourceManager::DoAcquire(uint32_t aId)
+{
+  MOZ_ASSERT(InImageBridgeChildThread());
+  if (mShutDown || !mChild) {
+    HandleAcquireResult(aId, false);
+    return;
+  }
+  {
+    ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+    MediaSystemResourceClient* client = mResourceClients.Get(aId);
+    MOZ_ASSERT(client);
+
+    if (!client ||
+        client->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_WAITING) {
+      HandleAcquireResult(aId, false);
+      return;
+    }
+    MOZ_ASSERT(aId == client->mId);
+    bool willWait = !client->mAcquireSyncWaitMonitor ? true : false;
+    mChild->SendAcquire(client->mId,
+                        client->mResourceType,
+                        willWait);
+  }
+}
+
+void
+MediaSystemResourceManager::ReleaseResource(MediaSystemResourceClient* aClient)
+{
+  MOZ_ASSERT(aClient);
+  {
+    ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+    MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
+    MOZ_ASSERT(client);
+    MOZ_ASSERT(client == aClient);
+
+    if (!client ||
+        client != aClient ||
+        aClient->mResourceState == MediaSystemResourceClient::RESOURCE_STATE_START ||
+        aClient->mResourceState == MediaSystemResourceClient::RESOURCE_STATE_END) {
+
+      aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_END;
+      return;
+    }
+
+    aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_END;
+
+    ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
+      FROM_HERE,
+      NewRunnableMethod(
+        this,
+        &MediaSystemResourceManager::DoRelease,
+        aClient->mId));
+  }
+}
+
+void
+MediaSystemResourceManager::DoRelease(uint32_t aId)
+{
+  MOZ_ASSERT(InImageBridgeChildThread());
+  if (mShutDown || !mChild) {
+    return;
+  }
+  mChild->SendRelease(aId);
+}
+
+void
+MediaSystemResourceManager::RecvResponse(uint32_t aId, bool aSuccess)
+{
+  HandleAcquireResult(aId, aSuccess);
+}
+
+void
+MediaSystemResourceManager::HandleAcquireResult(uint32_t aId, bool aSuccess)
+{
+  if (!InImageBridgeChildThread()) {
+    ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
+      FROM_HERE,
+      NewRunnableMethod(
+        this,
+        &MediaSystemResourceManager::HandleAcquireResult,
+        aId,
+        aSuccess));
+    return;
+  }
+
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  MediaSystemResourceClient* client = mResourceClients.Get(aId);
+  if (!client) {
+    // Client was already unregistered.
+    return;
+  }
+  if (client->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_WAITING) {
+    return;
+  }
+
+  // Update state
+  if (aSuccess) {
+    client->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_ACQUIRED;
+  } else {
+    client->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_NOT_ACQUIRED;
+  }
+
+  if (client->mIsSync) {
+    if (client->mAcquireSyncWaitMonitor) {
+      // Notify AcquireSync() complete
+      MOZ_ASSERT(client->mAcquireSyncWaitDone);
+      ReentrantMonitorAutoEnter autoMon(*client->mAcquireSyncWaitMonitor);
+      *client->mAcquireSyncWaitDone = true;
+      client->mAcquireSyncWaitMonitor->NotifyAll();
+      client->mAcquireSyncWaitMonitor = nullptr;
+      client->mAcquireSyncWaitDone = nullptr;
+    }
+  } else {
+    // Notify Acquire() result
+    if (client->mListener) {
+      if (aSuccess) {
+        client->mListener->ResourceReserved();
+      } else {
+       client->mListener->ResourceReserveFailed();
+      }
+    }
+  }
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/systemservices/MediaSystemResourceManager.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#if !defined(MediaSystemResourceManager_h_)
+#define MediaSystemResourceManager_h_
+
+#include <queue>
+
+#include "MediaSystemResourceTypes.h"
+#include "mozilla/ReentrantMonitor.h"
+#include "mozilla/StaticPtr.h"
+#include "nsAutoPtr.h"
+#include "nsDataHashtable.h"
+#include "nsISupportsImpl.h"
+
+namespace mozilla {
+
+namespace media {
+class MediaSystemResourceManagerChild;
+}
+
+class MediaSystemResourceClient;
+class MediaSystemResourceReservationListener;
+class MediaTaskQueue;
+class ReentrantMonitor;
+
+/**
+ * Manage media system resource allocation requests within a process.
+ */
+class MediaSystemResourceManager
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaSystemResourceManager)
+
+  static MediaSystemResourceManager* Get();
+  static void Init();
+  static void Shutdown();
+
+  void OnIpcClosed();
+
+  void Register(MediaSystemResourceClient* aClient);
+  void Unregister(MediaSystemResourceClient* aClient);
+
+  bool SetListener(MediaSystemResourceClient* aClient,
+                   MediaSystemResourceReservationListener* aListener);
+
+  void Acquire(MediaSystemResourceClient* aClient);
+  bool AcquireSyncNoWait(MediaSystemResourceClient* aClient);
+  void ReleaseResource(MediaSystemResourceClient* aClient);
+
+  void RecvResponse(uint32_t aId, bool aSuccess);
+
+private:
+  MediaSystemResourceManager();
+  virtual ~MediaSystemResourceManager();
+
+  static bool IsMediaSystemResourceManagerEnabled();
+
+  void OpenIPC();
+  void CloseIPC();
+  bool IsIpcClosed();
+
+  void DoAcquire(uint32_t aId);
+
+  void DoRelease(uint32_t aId);
+
+  void HandleAcquireResult(uint32_t aId, bool aSuccess);
+
+  ReentrantMonitor mReentrantMonitor;
+
+  bool mShutDown;
+
+  media::MediaSystemResourceManagerChild* mChild;
+
+  nsDataHashtable<nsUint32HashKey, MediaSystemResourceClient*> mResourceClients;
+
+  static StaticRefPtr<MediaSystemResourceManager> sSingleton;
+};
+
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/media/systemservices/MediaSystemResourceManagerChild.cpp
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "MediaSystemResourceManager.h"
+
+#include "MediaSystemResourceManagerChild.h"
+
+namespace mozilla {
+namespace media {
+
+MediaSystemResourceManagerChild::MediaSystemResourceManagerChild()
+  : mDestroyed(false)
+{
+}
+
+MediaSystemResourceManagerChild::~MediaSystemResourceManagerChild()
+{
+}
+
+bool
+MediaSystemResourceManagerChild::RecvResponse(const uint32_t& aId,
+                                              const bool& aSuccess)
+{
+  if (mManager) {
+    mManager->RecvResponse(aId, aSuccess);
+  }
+  return true;
+}
+
+void
+MediaSystemResourceManagerChild::ActorDestroy(ActorDestroyReason aActorDestroyReason)
+{
+  MOZ_ASSERT(!mDestroyed);
+  if (mManager) {
+    mManager->OnIpcClosed();
+  }
+  mDestroyed = true;
+}
+
+void
+MediaSystemResourceManagerChild::Destroy()
+{
+  if (mDestroyed) {
+    return;
+  }
+  SendRemoveResourceManager();
+  // WARNING: |this| is dead, hands off
+}
+
+} // namespace media
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/systemservices/MediaSystemResourceManagerChild.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#if !defined(MediaSystemResourceManagerChild_h_)
+#define MediaSystemResourceManagerChild_h_
+
+#include "mozilla/media/PMediaSystemResourceManagerChild.h"
+#include "nsISupportsImpl.h"
+
+namespace mozilla {
+
+class MediaSystemResourceManager;
+
+namespace ipc {
+class BackgroundChildImpl;
+}
+
+namespace media {
+
+/**
+ * Handle MediaSystemResourceManager's IPC
+ */
+class MediaSystemResourceManagerChild final : public PMediaSystemResourceManagerChild
+{
+public:
+  struct ResourceListener {
+    /* The resource is reserved and can be granted.
+     * The client can allocate the requested resource.
+     */
+    virtual void resourceReserved() = 0;
+    /* The resource is not reserved any more.
+     * The client should release the resource as soon as possible if the
+     * resource is still being held.
+     */
+    virtual void resourceCanceled() = 0;
+  };
+
+  MediaSystemResourceManagerChild();
+  virtual ~MediaSystemResourceManagerChild();
+
+  void Destroy();
+
+  void SetManager(MediaSystemResourceManager* aManager)
+  {
+    mManager = aManager;
+  }
+
+protected:
+  bool RecvResponse(const uint32_t& aId,
+                    const bool& aSuccess) override;
+
+private:
+  void ActorDestroy(ActorDestroyReason aActorDestroyReason) override;
+
+  bool mDestroyed;
+  MediaSystemResourceManager* mManager;
+
+  friend class mozilla::ipc::BackgroundChildImpl;
+};
+
+} // namespatce media
+} // namespatce mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/media/systemservices/MediaSystemResourceManagerParent.cpp
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/unused.h"
+
+#include "MediaSystemResourceManagerParent.h"
+
+namespace mozilla {
+namespace media {
+
+using namespace ipc;
+
+MediaSystemResourceManagerParent::MediaSystemResourceManagerParent()
+  : mDestroyed(false)
+{
+  mMediaSystemResourceService = MediaSystemResourceService::Get();
+}
+
+MediaSystemResourceManagerParent::~MediaSystemResourceManagerParent()
+{
+  MOZ_ASSERT(mDestroyed);
+}
+
+bool
+MediaSystemResourceManagerParent::RecvAcquire(const uint32_t& aId,
+                                              const MediaSystemResourceType& aResourceType,
+                                              const bool& aWillWait)
+{
+  MediaSystemResourceRequest* request = mResourceRequests.Get(aId);
+  MOZ_ASSERT(!request);
+  if (request) {
+    // Send fail response
+    mozilla::unused << SendResponse(aId, false /* fail */);
+    return true;
+  }
+
+  request = new MediaSystemResourceRequest(aId, aResourceType);
+  mResourceRequests.Put(aId, request);
+  mMediaSystemResourceService->Acquire(this, aId, aResourceType, aWillWait);
+  return true;
+}
+
+bool
+MediaSystemResourceManagerParent::RecvRelease(const uint32_t& aId)
+{
+  MediaSystemResourceRequest* request = mResourceRequests.Get(aId);
+  if (!request) {
+    return true;
+  }
+
+  mMediaSystemResourceService->ReleaseResource(this, aId, request->mResourceType);
+  mResourceRequests.Remove(aId);
+  return true;
+}
+
+bool
+MediaSystemResourceManagerParent::RecvRemoveResourceManager()
+{
+  return PMediaSystemResourceManagerParent::Send__delete__(this);
+}
+
+void
+MediaSystemResourceManagerParent::ActorDestroy(ActorDestroyReason aReason)
+{
+  MOZ_ASSERT(!mDestroyed);
+
+  // Release all resource requests of the MediaSystemResourceManagerParent.
+  // Clears all remaining pointers to this object. 
+  mMediaSystemResourceService->ReleaseResource(this);
+
+  mDestroyed = true;
+}
+
+} // namespace media
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/systemservices/MediaSystemResourceManagerParent.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#if !defined(MediaSystemResourceManagerParent_h_)
+#define MediaSystemResourceManagerParent_h_
+
+#include "MediaSystemResourceManager.h"
+#include "MediaSystemResourceService.h"
+#include "MediaSystemResourceTypes.h"
+#include "mozilla/media/PMediaSystemResourceManagerParent.h"
+
+namespace mozilla {
+namespace media {
+
+/**
+ * Handle MediaSystemResourceManager's IPC
+ */
+class MediaSystemResourceManagerParent final : public PMediaSystemResourceManagerParent
+{
+public:
+  MediaSystemResourceManagerParent();
+  virtual ~MediaSystemResourceManagerParent();
+
+protected:
+  bool RecvAcquire(const uint32_t& aId,
+                   const MediaSystemResourceType& aResourceType,
+                   const bool& aWillWait) override;
+
+  bool RecvRelease(const uint32_t& aId) override;
+
+  bool RecvRemoveResourceManager() override;
+
+private:
+  void ActorDestroy(ActorDestroyReason aActorDestroyReason) override;
+
+  struct MediaSystemResourceRequest {
+    MediaSystemResourceRequest()
+      : mId(-1), mResourceType(MediaSystemResourceType::INVALID_RESOURCE) {}
+    MediaSystemResourceRequest(uint32_t aId, MediaSystemResourceType aResourceType)
+      : mId(aId), mResourceType(aResourceType) {}
+    int32_t mId;
+    MediaSystemResourceType mResourceType;
+  };
+
+  bool mDestroyed;
+
+  nsRefPtr<MediaSystemResourceService> mMediaSystemResourceService;
+
+  nsClassHashtable<nsUint32HashKey, MediaSystemResourceRequest> mResourceRequests;
+};
+
+} // namespatce media
+} // namespatce mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/media/systemservices/MediaSystemResourceMessageUtils.h
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#if !defined(MediaSystemResourceMessageUtils_h_)
+#define MediaSystemResourceMessageUtils_h_
+
+#include "ipc/IPCMessageUtils.h"
+#include "MediaSystemResourceTypes.h"
+
+namespace IPC {
+
+template <>
+struct ParamTraits<mozilla::MediaSystemResourceType>
+  : public ContiguousEnumSerializer<
+             mozilla::MediaSystemResourceType,
+             mozilla::MediaSystemResourceType::VIDEO_DECODER,
+             mozilla::MediaSystemResourceType::INVALID_RESOURCE>
+{};
+
+} // namespace IPC
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/media/systemservices/MediaSystemResourceService.cpp
@@ -0,0 +1,273 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "MediaSystemResourceManagerParent.h"
+#include "mozilla/layers/CompositorParent.h"
+#include "mozilla/unused.h"
+
+#include "MediaSystemResourceService.h"
+
+using namespace mozilla::layers;
+
+namespace mozilla {
+
+/* static */ StaticRefPtr<MediaSystemResourceService> MediaSystemResourceService::sSingleton;
+
+/* static */ MediaSystemResourceService*
+MediaSystemResourceService::Get()
+{
+  if (sSingleton) {
+    return sSingleton;
+  }
+  Init();
+  return sSingleton;
+}
+
+/* static */ void
+MediaSystemResourceService::Init()
+{
+  if (!sSingleton) {
+    sSingleton = new MediaSystemResourceService();
+  }
+}
+
+/* static */ void
+MediaSystemResourceService::Shutdown()
+{
+  if (sSingleton) {
+    sSingleton->Destroy();
+    sSingleton = nullptr;
+  }
+}
+
+MediaSystemResourceService::MediaSystemResourceService()
+  : mDestroyed(false)
+{
+  MOZ_ASSERT(CompositorParent::IsInCompositorThread());
+#ifdef MOZ_WIDGET_GONK
+  // The maximum number of hardware resoureces available.
+  // XXX need to hange to a dynamic way.
+  enum
+  {
+    VIDEO_DECODER_COUNT = 1,
+    VIDEO_ENCODER_COUNT = 1
+  };
+
+  MediaSystemResource* resource;
+
+  resource = new MediaSystemResource(VIDEO_DECODER_COUNT);
+  mResources.Put(static_cast<uint32_t>(MediaSystemResourceType::VIDEO_DECODER), resource);
+
+  resource = new MediaSystemResource(VIDEO_ENCODER_COUNT);
+  mResources.Put(static_cast<uint32_t>(MediaSystemResourceType::VIDEO_ENCODER), resource);
+#endif
+}
+
+MediaSystemResourceService::~MediaSystemResourceService()
+{
+}
+
+void
+MediaSystemResourceService::Destroy()
+{
+  mDestroyed = true;
+}
+
+void
+MediaSystemResourceService::Acquire(media::MediaSystemResourceManagerParent* aParent,
+                                    uint32_t aId,
+                                    MediaSystemResourceType aResourceType,
+                                    bool aWillWait)
+{
+  MOZ_ASSERT(CompositorParent::IsInCompositorThread());
+  MOZ_ASSERT(aParent);
+
+  if (mDestroyed) {
+    return;
+  }
+
+  MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
+
+  if (!resource ||
+      resource->mResourceCount == 0) {
+    // Resource does not exit
+    // Send fail response
+    mozilla::unused << aParent->SendResponse(aId, false /* fail */);
+    return;
+  }
+
+  // Try to acquire a resource
+  if (resource->mAcquiredRequests.size() < resource->mResourceCount) {
+    // Resource is available
+    resource->mAcquiredRequests.push_back(
+      MediaSystemResourceRequest(aParent, aId));
+    // Send success response
+    mozilla::unused << aParent->SendResponse(aId, true /* success */);
+    return;
+  } else if (!aWillWait) {
+    // Resource is not available and do not wait.
+    // Send fail response
+    mozilla::unused << aParent->SendResponse(aId, false /* fail */);
+    return;
+  }
+  // Wait until acquire.
+  resource->mWaitingRequests.push_back(
+    MediaSystemResourceRequest(aParent, aId));
+}
+
+void
+MediaSystemResourceService::ReleaseResource(media::MediaSystemResourceManagerParent* aParent,
+                                            uint32_t aId,
+                                            MediaSystemResourceType aResourceType)
+{
+  MOZ_ASSERT(CompositorParent::IsInCompositorThread());
+  MOZ_ASSERT(aParent);
+
+  if (mDestroyed) {
+    return;
+  }
+
+  MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
+
+  if (!resource ||
+      resource->mResourceCount == 0) {
+    // Resource does not exit
+    return;
+  }
+  RemoveRequest(aParent, aId, aResourceType);
+  UpdateRequests(aResourceType);
+}
+
+struct ReleaseResourceData
+{
+  MediaSystemResourceService* mSelf;
+  media::MediaSystemResourceManagerParent* mParent;
+};
+
+/*static*/PLDHashOperator
+MediaSystemResourceService::ReleaseResourceForKey(const uint32_t& aKey,
+                                                  nsAutoPtr<MediaSystemResource>& aData,
+                                                  void* aClosure)
+{
+  ReleaseResourceData* closure = static_cast<ReleaseResourceData*>(aClosure);
+
+  closure->mSelf->RemoveRequests(closure->mParent, static_cast<MediaSystemResourceType>(aKey));
+  closure->mSelf->UpdateRequests(static_cast<MediaSystemResourceType>(aKey));
+
+  return PLDHashOperator::PL_DHASH_NEXT;
+}
+
+void
+MediaSystemResourceService::ReleaseResource(media::MediaSystemResourceManagerParent* aParent)
+{
+  MOZ_ASSERT(aParent);
+
+  if (mDestroyed) {
+    return;
+  }
+
+  ReleaseResourceData data = { this, aParent };
+  mResources.Enumerate(ReleaseResourceForKey, &data);
+}
+
+void
+MediaSystemResourceService::RemoveRequest(media::MediaSystemResourceManagerParent* aParent,
+                                          uint32_t aId,
+                                          MediaSystemResourceType aResourceType)
+{
+  MOZ_ASSERT(aParent);
+
+  MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
+  if (!resource) {
+    return;
+  }
+
+  std::deque<MediaSystemResourceRequest>::iterator it;
+  std::deque<MediaSystemResourceRequest>& acquiredRequests =
+    resource->mAcquiredRequests;
+  for (it = acquiredRequests.begin(); it != acquiredRequests.end(); it++) {
+    if (((*it).mParent == aParent) && ((*it).mId == aId)) {
+      acquiredRequests.erase(it);
+      return;
+    }
+  }
+
+  std::deque<MediaSystemResourceRequest>& waitingRequests =
+    resource->mWaitingRequests;
+  for (it = waitingRequests.begin(); it != waitingRequests.end(); it++) {
+    if (((*it).mParent == aParent) && ((*it).mId == aId)) {
+      waitingRequests.erase(it);
+      return;
+    }
+  }
+}
+
+void
+MediaSystemResourceService::RemoveRequests(media::MediaSystemResourceManagerParent* aParent,
+                                           MediaSystemResourceType aResourceType)
+{
+  MOZ_ASSERT(aParent);
+
+  MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
+
+  if (!resource ||
+      resource->mResourceCount == 0) {
+    // Resource does not exit
+    return;
+  }
+
+  std::deque<MediaSystemResourceRequest>::iterator it;
+  std::deque<MediaSystemResourceRequest>& acquiredRequests =
+    resource->mAcquiredRequests;
+  for (it = acquiredRequests.begin(); it != acquiredRequests.end();) {
+    if ((*it).mParent == aParent) {
+      it = acquiredRequests.erase(it);
+    } else {
+      it++;
+    }
+  }
+
+  std::deque<MediaSystemResourceRequest>& waitingRequests =
+    resource->mWaitingRequests;
+  for (it = waitingRequests.begin(); it != waitingRequests.end();) {
+    if ((*it).mParent == aParent) {
+      it = waitingRequests.erase(it);
+      return;
+    } else {
+      it++;
+    }
+  }
+}
+
+void
+MediaSystemResourceService::UpdateRequests(MediaSystemResourceType aResourceType)
+{
+  MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
+
+  if (!resource ||
+      resource->mResourceCount == 0) {
+    // Resource does not exit
+    return;
+  }
+
+  std::deque<MediaSystemResourceRequest>& acquiredRequests =
+    resource->mAcquiredRequests;
+  std::deque<MediaSystemResourceRequest>& waitingRequests =
+    resource->mWaitingRequests;
+
+  while ((acquiredRequests.size() < resource->mResourceCount) &&
+         (waitingRequests.size() > 0)) {
+    MediaSystemResourceRequest& request = waitingRequests.front();
+    MOZ_ASSERT(request.mParent);
+    // Send response
+    mozilla::unused << request.mParent->SendResponse(request.mId, true /* success */);
+    // Move request to mAcquiredRequests
+    acquiredRequests.push_back(waitingRequests.front());
+    waitingRequests.pop_front();
+  }
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/systemservices/MediaSystemResourceService.h
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#if !defined(MediaSystemResourceService_h_)
+#define MediaSystemResourceService_h_
+
+#include <deque>
+
+#include "MediaSystemResourceTypes.h"
+#include "mozilla/StaticPtr.h"
+#include "nsClassHashtable.h"
+
+namespace mozilla {
+
+namespace media {
+class MediaSystemResourceManagerParent;
+}
+
+/**
+ * Manage media system resource allocation requests within system.
+ */
+class MediaSystemResourceService
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaSystemResourceService)
+
+  static MediaSystemResourceService* Get();
+  static void Init();
+  static void Shutdown();
+
+  void Acquire(media::MediaSystemResourceManagerParent* aParent,
+               uint32_t aId,
+               MediaSystemResourceType aResourceType,
+               bool aWillWait);
+
+  void ReleaseResource(media::MediaSystemResourceManagerParent* aParent,
+                       uint32_t aId,
+                       MediaSystemResourceType aResourceType);
+
+  void ReleaseResource(media::MediaSystemResourceManagerParent* aParent);
+
+private:
+  MediaSystemResourceService();
+  ~MediaSystemResourceService();
+
+  struct MediaSystemResourceRequest {
+    MediaSystemResourceRequest()
+      : mParent(nullptr), mId(-1) {}
+    MediaSystemResourceRequest(media::MediaSystemResourceManagerParent* aParent, uint32_t aId)
+      : mParent(aParent), mId(aId) {}
+    media::MediaSystemResourceManagerParent* mParent;
+    uint32_t mId;
+  };
+
+  struct MediaSystemResource {
+    MediaSystemResource()
+      : mResourceCount(0) {}
+    explicit MediaSystemResource(uint32_t aResourceCount)
+      : mResourceCount(aResourceCount) {}
+
+    std::deque<MediaSystemResourceRequest> mWaitingRequests;
+    std::deque<MediaSystemResourceRequest> mAcquiredRequests;
+    uint32_t mResourceCount;
+  };
+
+  void Destroy();
+
+  void RemoveRequest(media::MediaSystemResourceManagerParent* aParent,
+                     uint32_t aId,
+                     MediaSystemResourceType aResourceType);
+
+  void RemoveRequests(media::MediaSystemResourceManagerParent* aParent,
+                      MediaSystemResourceType aResourceType);
+
+  void UpdateRequests(MediaSystemResourceType aResourceType);
+
+  static PLDHashOperator ReleaseResourceForKey(const uint32_t& aKey,
+                                               nsAutoPtr<MediaSystemResource>& aData,
+                                               void* aClosure);
+
+  bool mDestroyed;
+
+  nsClassHashtable<nsUint32HashKey, MediaSystemResource> mResources;
+
+  static StaticRefPtr<MediaSystemResourceService> sSingleton;
+};
+
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/media/systemservices/MediaSystemResourceTypes.h
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#if !defined(MediaSystemResourceTypes_h_)
+#define MediaSystemResourceTypes_h_
+
+namespace mozilla {
+
+enum class MediaSystemResourceType : uint32_t {
+  VIDEO_DECODER = 0,
+  AUDIO_DECODER,  // Not supported currently.
+  VIDEO_ENCODER,
+  AUDIO_ENCODER,  // Not supported currently.
+  CAMERA,          // Not supported currently.
+  INVALID_RESOURCE,
+};
+
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/media/systemservices/PMediaSystemResourceManager.ipdl
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PImageBridge;
+include "mozilla/media/MediaSystemResourceMessageUtils.h";
+
+using mozilla::MediaSystemResourceType from "mozilla/media/MediaSystemResourceTypes.h";
+
+namespace mozilla {
+namespace media {
+
+/*
+ * The PMediaSystemResourceManager is a sub-protocol in PImageBridge
+ */
+sync protocol PMediaSystemResourceManager
+{
+  manager PImageBridge;
+
+child:
+  async Response(uint32_t aId, bool aSuccess);
+  async __delete__();
+
+parent:
+  async Acquire(uint32_t aId, MediaSystemResourceType aResourceType, bool aWillWait);
+  async Release(uint32_t aId);
+
+  /**
+   * Asynchronously tell the parent side to remove the PMediaSystemResourceManager.
+   */
+  async RemoveResourceManager();
+};
+
+} // namespace media
+} // namespace mozilla
+
--- a/dom/media/systemservices/moz.build
+++ b/dom/media/systemservices/moz.build
@@ -33,25 +33,38 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk
     CXXFLAGS += [
         '-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [
             'frameworks/wilhelm/include',
             'system/media/wilhelm/include',
         ]
     ]
 
 EXPORTS.mozilla.media += ['MediaChild.h',
-            'MediaParent.h',
-            'MediaUtils.h'
+                          'MediaParent.h',
+                          'MediaSystemResourceClient.h',
+                          'MediaSystemResourceManager.h',
+                          'MediaSystemResourceManagerChild.h',
+                          'MediaSystemResourceManagerParent.h',
+                          'MediaSystemResourceMessageUtils.h',
+                          'MediaSystemResourceService.h',
+                          'MediaSystemResourceTypes.h',
+                          'MediaUtils.h'
 ]
 UNIFIED_SOURCES += ['MediaChild.cpp',
                     'MediaParent.cpp',
-                    'MediaUtils.cpp'
+                    'MediaSystemResourceClient.cpp',
+                    'MediaSystemResourceManager.cpp',
+                    'MediaSystemResourceManagerChild.cpp',
+                    'MediaSystemResourceManagerParent.cpp',
+                    'MediaSystemResourceService.cpp',
+                    'MediaUtils.cpp',
 ]
 IPDL_SOURCES += [
     'PMedia.ipdl',
+    'PMediaSystemResourceManager.ipdl',
 ]
 # /dom/base needed for nsGlobalWindow.h in MediaChild.cpp
 LOCAL_INCLUDES += [
     '/dom/base',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -100,16 +100,21 @@ AudioContext::AudioContext(nsPIDOMWindow
   , mCloseCalled(false)
 {
   aWindow->AddAudioContext(this);
 
   // Note: AudioDestinationNode needs an AudioContext that must already be
   // bound to the window.
   mDestination = new AudioDestinationNode(this, aIsOffline, aChannel,
                                           aNumberOfChannels, aLength, aSampleRate);
+}
+
+void
+AudioContext::Init()
+{
   // We skip calling SetIsOnlyNodeForContext and the creation of the
   // audioChannelAgent during mDestination's constructor, because we can only
   // call them after mDestination has been set up.
   mDestination->CreateAudioChannelAgent();
   mDestination->SetIsOnlyNodeForContext(true);
 }
 
 AudioContext::~AudioContext()
@@ -140,16 +145,17 @@ AudioContext::Constructor(const GlobalOb
   if (!window) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<AudioContext> object =
     new AudioContext(window, false,
                      AudioChannelService::GetDefaultAudioChannel());
+  object->Init();
 
   RegisterWeakMemoryReporter(object);
 
   return object.forget();
 }
 
 /* static */ already_AddRefed<AudioContext>
 AudioContext::Constructor(const GlobalObject& aGlobal,
@@ -158,16 +164,17 @@ AudioContext::Constructor(const GlobalOb
 {
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<AudioContext> object = new AudioContext(window, false, aChannel);
+  object->Init();
 
   RegisterWeakMemoryReporter(object);
 
   return object.forget();
 }
 
 /* static */ already_AddRefed<AudioContext>
 AudioContext::Constructor(const GlobalObject& aGlobal,
--- a/dom/media/webaudio/AudioContext.h
+++ b/dom/media/webaudio/AudioContext.h
@@ -96,16 +96,18 @@ class AudioContext final : public DOMEve
   AudioContext(nsPIDOMWindow* aParentWindow,
                bool aIsOffline,
                AudioChannel aChannel,
                uint32_t aNumberOfChannels = 0,
                uint32_t aLength = 0,
                float aSampleRate = 0.0f);
   ~AudioContext();
 
+  void Init();
+
 public:
   typedef uint64_t AudioContextId;
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioContext,
                                            DOMEventTargetHelper)
   MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
 
--- a/dom/media/webaudio/AudioDestinationNode.cpp
+++ b/dom/media/webaudio/AudioDestinationNode.cpp
@@ -593,17 +593,17 @@ AudioDestinationNode::SetMozAudioChannel
       CreateAudioChannelAgent();
     }
   }
 }
 
 bool
 AudioDestinationNode::CheckAudioChannelPermissions(AudioChannel aValue)
 {
-  if (!Preferences::GetBool("media.useAudioChannelService")) {
+  if (!UseAudioChannelService()) {
     return true;
   }
 
   // Only normal channel doesn't need permission.
   if (aValue == AudioChannel::Normal) {
     return true;
   }
 
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -37,16 +37,17 @@
 #include "mozilla/layers/CompositorLRU.h"  // for CompositorLRU
 #include "mozilla/layers/CompositorOGL.h"  // for CompositorOGL
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/FrameUniformityData.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/layers/PLayerTransactionParent.h"
 #include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager
+#include "mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "mozilla/Telemetry.h"
 #ifdef MOZ_WIDGET_GTK
 #include "basic/X11BasicCompositor.h" // for X11BasicCompositor
 #endif
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION, etc
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
@@ -588,16 +589,17 @@ void CompositorParent::StartUp()
 }
 
 void CompositorParent::ShutDown()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
   MOZ_ASSERT(sCompositorThreadHolder, "The compositor thread has already been shut down!");
 
   ReleaseImageBridgeParentSingleton();
+  MediaSystemResourceService::Shutdown();
 
   sCompositorThreadHolder = nullptr;
 
   // No locking is needed around sFinishedCompositorShutDown because it is only
   // ever accessed on the main thread.
   while (!sFinishedCompositorShutDown) {
     NS_ProcessNextEvent(nullptr, true);
   }
@@ -1244,16 +1246,24 @@ CompositorParent::ShadowLayersUpdated(La
   mLayerManager->SetRoot(root);
 
   if (mApzcTreeManager && !aIsRepeatTransaction) {
     AutoResolveRefLayers resolve(mCompositionManager);
     mApzcTreeManager->UpdateHitTestingTree(this, root, aIsFirstPaint,
         mRootLayerTreeID, aPaintSequenceNumber);
   }
 
+#ifdef DEBUG
+  if (aTransactionId <= mPendingTransaction) {
+    // Logging added to help diagnose why we're triggering the assert below.
+    // See bug 1145295
+    printf_stderr("CRASH: aTransactionId %" PRIu64 " <= mPendingTransaction %" PRIu64 "\n",
+      aTransactionId, mPendingTransaction);
+  }
+#endif
   MOZ_ASSERT(aTransactionId > mPendingTransaction);
   mPendingTransaction = aTransactionId;
 
   if (root) {
     SetShadowProperties(root);
   }
   if (aScheduleComposite) {
     ScheduleComposition();
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -16,16 +16,18 @@
 #include "base/thread.h"                // for Thread
 #include "base/tracked.h"               // for FROM_HERE
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/Monitor.h"            // for Monitor, MonitorAutoLock
 #include "mozilla/ReentrantMonitor.h"   // for ReentrantMonitor, etc
 #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
 #include "mozilla/ipc/Transport.h"      // for Transport
 #include "mozilla/gfx/Point.h"          // for IntSize
+#include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager
+#include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild
 #include "mozilla/layers/CompositableClient.h"  // for CompositableChild, etc
 #include "mozilla/layers/CompositorParent.h" // for CompositorParent
 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
 #include "mozilla/layers/ImageClient.h"  // for ImageClient
 #include "mozilla/layers/LayersMessages.h"  // for CompositableOperation
 #include "mozilla/layers/PCompositableChild.h"  // for PCompositableChild
 #include "mozilla/layers/TextureClient.h"  // for TextureClient
 #include "mozilla/mozalloc.h"           // for operator new, etc
@@ -44,16 +46,17 @@ class Shmem;
 }
 
 namespace layers {
 
 using base::Thread;
 using base::ProcessId;
 using namespace mozilla::ipc;
 using namespace mozilla::gfx;
+using namespace mozilla::media;
 
 typedef std::vector<CompositableOperation> OpVector;
 
 struct CompositableTransaction
 {
   CompositableTransaction()
   : mSwapRequired(false)
   , mFinished(true)
@@ -166,16 +169,19 @@ void ReleaseImageBridgeParentSingleton()
 
 // dispatched function
 static void ImageBridgeShutdownStep1(ReentrantMonitor *aBarrier, bool *aDone)
 {
   ReentrantMonitorAutoEnter autoMon(*aBarrier);
 
   MOZ_ASSERT(InImageBridgeChildThread(),
              "Should be in ImageBridgeChild thread.");
+
+  MediaSystemResourceManager::Shutdown();
+
   if (sImageBridgeChildSingleton) {
     // Force all managed protocols to shut themselves down cleanly
     InfallibleTArray<PCompositableChild*> compositables;
     sImageBridgeChildSingleton->ManagedPCompositableChild(compositables);
     for (int i = compositables.Length() - 1; i >= 0; --i) {
       CompositableClient::FromIPDLActor(compositables[i])->Destroy();
     }
     InfallibleTArray<PTextureChild*> textures;
@@ -183,16 +189,17 @@ static void ImageBridgeShutdownStep1(Ree
     for (int i = textures.Length() - 1; i >= 0; --i) {
       TextureClient::AsTextureClient(textures[i])->ForceRemove();
     }
     sImageBridgeChildSingleton->SendWillStop();
     sImageBridgeChildSingleton->MarkShutDown();
     // From now on, no message can be sent through the image bridge from the
     // client side except the final Stop message.
   }
+
   *aDone = true;
   aBarrier->NotifyAll();
 }
 
 // dispatched function
 static void ImageBridgeShutdownStep2(ReentrantMonitor *aBarrier, bool *aDone)
 {
   ReentrantMonitorAutoEnter autoMon(*aBarrier);
@@ -816,16 +823,31 @@ ImageBridgeChild::AllocPTextureChild(con
 }
 
 bool
 ImageBridgeChild::DeallocPTextureChild(PTextureChild* actor)
 {
   return TextureClient::DestroyIPDLActor(actor);
 }
 
+PMediaSystemResourceManagerChild*
+ImageBridgeChild::AllocPMediaSystemResourceManagerChild()
+{
+  MOZ_ASSERT(!mShuttingDown);
+  return new mozilla::media::MediaSystemResourceManagerChild();
+}
+
+bool
+ImageBridgeChild::DeallocPMediaSystemResourceManagerChild(PMediaSystemResourceManagerChild* aActor)
+{
+  MOZ_ASSERT(aActor);
+  delete static_cast<mozilla::media::MediaSystemResourceManagerChild*>(aActor);
+  return true;
+}
+
 bool
 ImageBridgeChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages)
 {
   for (AsyncParentMessageArray::index_type i = 0; i < aMessages.Length(); ++i) {
     const AsyncParentMessageData& message = aMessages[i];
 
     switch (message.type()) {
       case AsyncParentMessageData::TOpDeliverFence: {
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -184,16 +184,22 @@ public:
   ~ImageBridgeChild();
 
   virtual PTextureChild*
   AllocPTextureChild(const SurfaceDescriptor& aSharedData, const TextureFlags& aFlags) override;
 
   virtual bool
   DeallocPTextureChild(PTextureChild* actor) override;
 
+  PMediaSystemResourceManagerChild*
+  AllocPMediaSystemResourceManagerChild() override;
+
+  bool
+  DeallocPMediaSystemResourceManagerChild(PMediaSystemResourceManagerChild* aActor) override;
+
   virtual bool
   RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages) override;
 
   already_AddRefed<ImageClient> CreateImageClient(CompositableType aType);
   already_AddRefed<ImageClient> CreateImageClientNow(CompositableType aType);
 
   static void DispatchReleaseImageClient(ImageClient* aClient);
   static void DispatchReleaseTextureClient(TextureClient* aClient);
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -12,16 +12,17 @@
 #include "base/task.h"                  // for CancelableTask, DeleteTask, etc
 #include "base/tracked.h"               // for FROM_HERE
 #include "mozilla/gfx/Point.h"                   // for IntSize
 #include "mozilla/Hal.h"                // for hal::SetCurrentThreadPriority()
 #include "mozilla/HalTypes.h"           // for hal::THREAD_PRIORITY_COMPOSITOR
 #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/ipc/Transport.h"      // for Transport
+#include "mozilla/media/MediaSystemResourceManagerParent.h" // for MediaSystemResourceManagerParent
 #include "mozilla/layers/CompositableTransactionParent.h"
 #include "mozilla/layers/CompositorParent.h"  // for CompositorParent
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayersMessages.h"  // for EditReply
 #include "mozilla/layers/LayersSurfaces.h"  // for PGrallocBufferParent
 #include "mozilla/layers/PCompositableParent.h"
 #include "mozilla/layers/PImageBridgeParent.h"
 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
@@ -37,16 +38,17 @@
 #include "mozilla/layers/TextureHost.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::ipc;
 using namespace mozilla::gfx;
+using namespace mozilla::media;
 
 std::map<base::ProcessId, ImageBridgeParent*> ImageBridgeParent::sImageBridges;
 
 MessageLoop* ImageBridgeParent::sMainLoop = nullptr;
 
 // defined in CompositorParent.cpp
 CompositorThreadHolder* GetCompositorThreadHolder();
 
@@ -254,16 +256,30 @@ ImageBridgeParent::AllocPTextureParent(c
 }
 
 bool
 ImageBridgeParent::DeallocPTextureParent(PTextureParent* actor)
 {
   return TextureHost::DestroyIPDLActor(actor);
 }
 
+PMediaSystemResourceManagerParent*
+ImageBridgeParent::AllocPMediaSystemResourceManagerParent()
+{
+  return new mozilla::media::MediaSystemResourceManagerParent();
+}
+
+bool
+ImageBridgeParent::DeallocPMediaSystemResourceManagerParent(PMediaSystemResourceManagerParent* aActor)
+{
+  MOZ_ASSERT(aActor);
+  delete static_cast<mozilla::media::MediaSystemResourceManagerParent*>(aActor);
+  return true;
+}
+
 void
 ImageBridgeParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage)
 {
   mozilla::unused << SendParentAsyncMessages(aMessage);
 }
 
 bool
 ImageBridgeParent::RecvChildAsyncMessages(InfallibleTArray<AsyncChildMessageData>&& aMessages)
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -76,16 +76,19 @@ public:
   PCompositableParent* AllocPCompositableParent(const TextureInfo& aInfo,
                                                 uint64_t*) override;
   bool DeallocPCompositableParent(PCompositableParent* aActor) override;
 
   virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
                                               const TextureFlags& aFlags) override;
   virtual bool DeallocPTextureParent(PTextureParent* actor) override;
 
+  PMediaSystemResourceManagerParent* AllocPMediaSystemResourceManagerParent() override;
+  bool DeallocPMediaSystemResourceManagerParent(PMediaSystemResourceManagerParent* aActor) override;
+
   virtual bool
   RecvChildAsyncMessages(InfallibleTArray<AsyncChildMessageData>&& aMessages) override;
 
   // Shutdown step 1
   virtual bool RecvWillStop() override;
   // Shutdown step 2
   virtual bool RecvStop() override;
 
--- a/gfx/layers/ipc/PImageBridge.ipdl
+++ b/gfx/layers/ipc/PImageBridge.ipdl
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include LayersSurfaces;
 include LayersMessages;
 include protocol PCompositable;
 include protocol PLayer;
 include protocol PTexture;
 include ProtocolTypes;
+include protocol PMediaSystemResourceManager;
 
 include "mozilla/GfxMessageUtils.h";
 
 using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
 using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h";
 
 using PlatformThreadId from "base/platform_thread.h";
 
@@ -24,16 +25,17 @@ namespace layers {
  * The PImageBridge protocol is used to allow isolated threads or processes to push
  * frames directly to the compositor thread/process without relying on the main thread
  * which might be too busy dealing with content script.
  */
 sync protocol PImageBridge
 {
   manages PCompositable;
   manages PTexture;
+  manages PMediaSystemResourceManager;
 
 child:
   async ParentAsyncMessages(AsyncParentMessageData[] aMessages);
 
 parent:
 
   async ImageBridgeThreadId(PlatformThreadId aTreahdId);
 
@@ -49,16 +51,17 @@ parent:
   // before sending Stop, and that after Stop returns, there is no message in
   // flight on any side and we can safely destroy the channel and threads.
   sync WillStop();
   // Second step
   sync Stop();
 
   sync PCompositable(TextureInfo aInfo) returns (uint64_t id);
   async PTexture(SurfaceDescriptor aSharedData, TextureFlags aTextureFlags);
+  async PMediaSystemResourceManager();
 
   async ChildAsyncMessages(AsyncChildMessageData[] aMessages);
 };
 
 
 } // namespace
 } // namespace
 
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1385,68 +1385,16 @@ gfxPlatform::MakePlatformFont(const nsAS
     // using the data to instantiate the font, and taking responsibility
     // for freeing it when no longer required.
     if (aFontData) {
         free((void*)aFontData);
     }
     return nullptr;
 }
 
-static void
-AppendGenericFontFromPref(nsString& aFonts, nsIAtom *aLangGroup, const char *aGenericName)
-{
-    NS_ENSURE_TRUE_VOID(Preferences::GetRootBranch());
-
-    nsAutoCString prefName, langGroupString;
-
-    aLangGroup->ToUTF8String(langGroupString);
-
-    nsAutoCString genericDotLang;
-    if (aGenericName) {
-        genericDotLang.Assign(aGenericName);
-    } else {
-        prefName.AssignLiteral("font.default.");
-        prefName.Append(langGroupString);
-        genericDotLang = Preferences::GetCString(prefName.get());
-    }
-
-    genericDotLang.Append('.');
-    genericDotLang.Append(langGroupString);
-
-    // fetch font.name.xxx value
-    prefName.AssignLiteral("font.name.");
-    prefName.Append(genericDotLang);
-    nsAdoptingString nameValue = Preferences::GetString(prefName.get());
-    if (nameValue) {
-        if (!aFonts.IsEmpty())
-            aFonts.AppendLiteral(", ");
-        aFonts += nameValue;
-    }
-
-    // fetch font.name-list.xxx value
-    prefName.AssignLiteral("font.name-list.");
-    prefName.Append(genericDotLang);
-    nsAdoptingString nameListValue = Preferences::GetString(prefName.get());
-    if (nameListValue && !nameListValue.Equals(nameValue)) {
-        if (!aFonts.IsEmpty())
-            aFonts.AppendLiteral(", ");
-        aFonts += nameListValue;
-    }
-}
-
-void
-gfxPlatform::GetPrefFonts(nsIAtom *aLanguage, nsString& aFonts, bool aAppendUnicode)
-{
-    aFonts.Truncate();
-
-    AppendGenericFontFromPref(aFonts, aLanguage, nullptr);
-    if (aAppendUnicode)
-        AppendGenericFontFromPref(aFonts, nsGkAtoms::Unicode, nullptr);
-}
-
 bool gfxPlatform::ForEachPrefFont(eFontPrefLang aLangArray[], uint32_t aLangArrayLen, PrefFontCallback aCallback,
                                     void *aClosure)
 {
     NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
 
     uint32_t    i;
     for (i = 0; i < aLangArrayLen; i++) {
         eFontPrefLang prefLang = aLangArray[i];
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -449,18 +449,16 @@ public:
      */
     bool UseGraphiteShaping();
 
     // check whether format is supported on a platform or not (if unclear, returns true)
     virtual bool IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) { return false; }
 
     virtual bool DidRenderingDeviceReset(DeviceResetReason* aResetReason = nullptr) { return false; }
 
-    void GetPrefFonts(nsIAtom *aLanguage, nsString& array, bool aAppendUnicode = true);
-
     // in some situations, need to make decisions about ambiguous characters, may need to look at multiple pref langs
     void GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang);
     
     /**
      * Iterate over pref fonts given a list of lang groups.  For a single lang
      * group, multiple pref fonts are possible.  If error occurs, returns false,
      * true otherwise.  Callback returns false to abort process.
      */
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -2978,26 +2978,50 @@ void gfxFontGroup::ComputeRanges(nsTArra
                     prevFont = font;
                 }
             }
         }
     }
 
     aRanges[lastRangeIndex].end = aLength;
 
-#if 0
-    // dump out font matching info
-    if (mStyle.systemFont) return;
-    for (size_t i = 0, i_end = aRanges.Length(); i < i_end; i++) {
-        const gfxTextRange& r = aRanges[i];
-        printf("fontmatch %zd:%zd font: %s (%d)\n",
-               r.start, r.end,
-               (r.font.get() ?
-                    NS_ConvertUTF16toUTF8(r.font->GetName()).get() : "<null>"),
-               r.matchType);
+#ifndef RELEASE_BUILD
+    PRLogModuleInfo *log = (mStyle.systemFont ?
+                            gfxPlatform::GetLog(eGfxLog_textrunui) :
+                            gfxPlatform::GetLog(eGfxLog_textrun));
+
+    if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) {
+        nsAutoCString lang;
+        mStyle.language->ToUTF8String(lang);
+        nsAutoString families;
+        mFamilyList.ToString(families);
+
+        // collect the font matched for each range
+        nsAutoCString fontMatches;
+        for (size_t i = 0, i_end = aRanges.Length(); i < i_end; i++) {
+            const gfxTextRange& r = aRanges[i];
+            fontMatches.AppendPrintf(" [%u:%u] %.200s (%s)", r.start, r.end,
+                (r.font.get() ?
+                 NS_ConvertUTF16toUTF8(r.font->GetName()).get() : "<null>"),
+                (r.matchType == gfxTextRange::kFontGroup ?
+                 "list" :
+                 (r.matchType == gfxTextRange::kPrefsFallback) ?
+                  "prefs" : "sys"));
+        }
+        MOZ_LOG(log, LogLevel::Debug,\
+               ("(%s-fontmatching) fontgroup: [%s] default: %s lang: %s script: %d"
+                "%s\n",
+                (mStyle.systemFont ? "textrunui" : "textrun"),
+                NS_ConvertUTF16toUTF8(families).get(),
+                (mFamilyList.GetDefaultFontType() == eFamily_serif ?
+                 "serif" :
+                 (mFamilyList.GetDefaultFontType() == eFamily_sans_serif ?
+                  "sans-serif" : "none")),
+                lang.get(), aRunScript,
+                fontMatches.get()));
     }
 #endif
 }
 
 gfxUserFontSet*
 gfxFontGroup::GetUserFontSet()
 {
     return mUserFontSet;
--- a/gfx/thebes/gfxTextRun.h
+++ b/gfx/thebes/gfxTextRun.h
@@ -826,28 +826,16 @@ public:
     enum { UNDERLINE_OFFSET_NOT_SET = INT16_MAX };
     virtual gfxFloat GetUnderlineOffset();
 
     virtual already_AddRefed<gfxFont>
         FindFontForChar(uint32_t ch, uint32_t prevCh, uint32_t aNextCh,
                         int32_t aRunScript, gfxFont *aPrevMatchedFont,
                         uint8_t *aMatchType);
 
-    // search through pref fonts for a character, return nullptr if no matching pref font
-    virtual already_AddRefed<gfxFont> WhichPrefFontSupportsChar(uint32_t aCh);
-
-    already_AddRefed<gfxFont>
-        WhichSystemFontSupportsChar(uint32_t aCh, uint32_t aNextCh,
-                                    int32_t aRunScript);
-
-    template<typename T>
-    void ComputeRanges(nsTArray<gfxTextRange>& mRanges,
-                       const T *aString, uint32_t aLength,
-                       int32_t aRunScript, uint16_t aOrientation);
-
     gfxUserFontSet* GetUserFontSet();
 
     // With downloadable fonts, the composition of the font group can change as fonts are downloaded
     // for each change in state of the user font set, the generation value is bumped to avoid picking up
     // previously created text runs in the text run word cache.  For font groups based on stylesheets
     // with no @font-face rule, this always returns 0.
     uint64_t GetGeneration();
 
@@ -886,16 +874,28 @@ public:
 
     // helper method for resolving generic font families
     static void
     ResolveGenericFontNames(mozilla::FontFamilyType aGenericType,
                             nsIAtom *aLanguage,
                             nsTArray<nsString>& aGenericFamilies);
 
 protected:
+    // search through pref fonts for a character, return nullptr if no matching pref font
+    already_AddRefed<gfxFont> WhichPrefFontSupportsChar(uint32_t aCh);
+
+    already_AddRefed<gfxFont>
+        WhichSystemFontSupportsChar(uint32_t aCh, uint32_t aNextCh,
+                                    int32_t aRunScript);
+
+    template<typename T>
+    void ComputeRanges(nsTArray<gfxTextRange>& mRanges,
+                       const T *aString, uint32_t aLength,
+                       int32_t aRunScript, uint16_t aOrientation);
+
     class FamilyFace {
     public:
         FamilyFace() : mFamily(nullptr), mFontEntry(nullptr),
                        mNeedsBold(false), mFontCreated(false),
                        mLoading(false), mInvalid(false)
         { }
 
         FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont)
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -2304,16 +2304,20 @@ ReportCompartmentStats(const JS::Compart
     ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("cross-compartment-wrapper-table"),
         cStats.crossCompartmentWrappersTable,
         "The cross-compartment wrapper table.");
 
     ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("regexp-compartment"),
         cStats.regexpCompartment,
         "The regexp compartment and regexp data.");
 
+    ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("saved-stacks-set"),
+        cStats.savedStacksSet,
+        "The saved stacks set.");
+
     if (sundriesGCHeap > 0) {
         // We deliberately don't use ZCREPORT_GC_BYTES here.
         REPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("sundries/gc-heap"),
             sundriesGCHeap,
             "The sum of all 'gc-heap' measurements that are too small to be "
             "worth showing individually.");
     }
 
@@ -2496,19 +2500,18 @@ ReportJSRuntimeExplicitTreeStats(const J
         KIND_HEAP, rtStats.runtime.gc.marker,
         "The GC mark stack and gray roots.");
 
     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/nursery-committed"),
         KIND_NONHEAP, rtStats.runtime.gc.nurseryCommitted,
         "Memory being used by the GC's nursery.");
 
     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/nursery-malloced-buffers"),
-        KIND_NONHEAP, rtStats.runtime.gc.nurseryMallocedBuffers,
-        "Out-of-line slots and elements belonging to objects in the "
-        "nursery.");
+        KIND_HEAP, rtStats.runtime.gc.nurseryMallocedBuffers,
+        "Out-of-line slots and elements belonging to objects in the nursery.");
 
     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/store-buffer/vals"),
         KIND_HEAP, rtStats.runtime.gc.storeBufferVals,
         "Values in the store buffer.");
 
     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/store-buffer/cells"),
         KIND_HEAP, rtStats.runtime.gc.storeBufferCells,
         "Cells in the store buffer.");
@@ -2544,17 +2547,17 @@ ReportJSRuntimeExplicitTreeStats(const J
     rtPath2.Replace(0, strlen("explicit"), NS_LITERAL_CSTRING("decommitted"));
     REPORT_GC_BYTES(rtPath2 + NS_LITERAL_CSTRING("gc-heap/decommitted-arenas"),
         rtStats.gcHeapDecommittedArenas,
         "GC arenas in non-empty chunks that is decommitted, i.e. it takes up "
         "address space but no physical memory or swap space.");
 
     REPORT_BYTES(rtPath2 + NS_LITERAL_CSTRING("runtime/gc/nursery-decommitted"),
         KIND_NONHEAP, rtStats.runtime.gc.nurseryDecommitted,
-        "Memory allocated to the GC's nursery this is decommitted, i.e. it takes up "
+        "Memory allocated to the GC's nursery that is decommitted, i.e. it takes up "
         "address space but no physical memory or swap space.");
 
     REPORT_GC_BYTES(rtPath + NS_LITERAL_CSTRING("gc-heap/unused-chunks"),
         rtStats.gcHeapUnusedChunks,
         "Empty GC chunks which will soon be released unless claimed for new "
         "allocations.");
 
     REPORT_GC_BYTES(rtPath + NS_LITERAL_CSTRING("gc-heap/unused-arenas"),
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -839,17 +839,17 @@ public:
   }
   virtual mozilla::Maybe<mozilla::FrameMetricsAndClip> ComputeFrameMetrics(
     Layer* aLayer, nsIFrame* aContainerReferenceFrame,
     const ContainerLayerParameters& aParameters,
     bool aIsForCaret) const override
   {
     return mHelper.ComputeFrameMetrics(aLayer, aContainerReferenceFrame, aParameters, aIsForCaret);
   }
-  virtual const mozilla::DisplayItemClip* ComputeScrollClip(bool aIsForCaret) const
+  virtual const mozilla::DisplayItemClip* ComputeScrollClip(bool aIsForCaret) const override
   {
     return mHelper.ComputeScrollClip(aIsForCaret);
   }
   virtual bool IsIgnoringViewportClipping() const override {
     return mHelper.IsIgnoringViewportClipping();
   }
   virtual void MarkScrollbarsDirtyForReflow() const override {
     mHelper.MarkScrollbarsDirtyForReflow();
@@ -1239,17 +1239,17 @@ public:
   }
   virtual mozilla::Maybe<mozilla::FrameMetricsAndClip> ComputeFrameMetrics(
     Layer* aLayer, nsIFrame* aContainerReferenceFrame,
     const ContainerLayerParameters& aParameters,
     bool aIsForCaret) const override
   {
     return mHelper.ComputeFrameMetrics(aLayer, aContainerReferenceFrame, aParameters, aIsForCaret);
   }
-  virtual const mozilla::DisplayItemClip* ComputeScrollClip(bool aIsForCaret) const
+  virtual const mozilla::DisplayItemClip* ComputeScrollClip(bool aIsForCaret) const override
   {
     return mHelper.ComputeScrollClip(aIsForCaret);
   }
   virtual bool IsIgnoringViewportClipping() const override {
     return mHelper.IsIgnoringViewportClipping();
   }
   virtual void MarkScrollbarsDirtyForReflow() const override {
     mHelper.MarkScrollbarsDirtyForReflow();
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -5715,17 +5715,17 @@ nsTableFrame::CalcBCBorders()
 
   // calculate an expanded damage area
   TableArea damageArea(propData->mDamageArea);
   ExpandBCDamageArea(damageArea);
 
   // segments that are on the table border edges need
   // to be initialized only once
   bool tableBorderReset[4];
-  for (uint32_t sideX = eLogicalSideBStart; sideX <= eLogicalSideIStart; sideX++) {
+  for (uint32_t sideX = 0; sideX < ArrayLength(tableBorderReset); sideX++) {
     tableBorderReset[sideX] = false;
   }
 
   // block-dir borders indexed in inline-direction (cols)
   BCCellBorders lastBlockDirBorders(damageArea.ColCount() + 1,
                                     damageArea.StartCol());
   if (!lastBlockDirBorders.borders) ABORT0();
   BCCellBorder  lastBStartBorder, lastBEndBorder;
--- a/widget/gonk/moz.build
+++ b/widget/gonk/moz.build
@@ -74,17 +74,16 @@ SOURCES += [
     'WidgetTraceEvent.cpp'
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
-    '/dom/media/omx/mediaresourcemanager',
     '/dom/system/android',
     '/gfx/skia/trunk/include/config',
     '/gfx/skia/trunk/include/core',
     '/widget',
 ]
 
 DEFINES['HAVE_OFF64_T'] = True
 DEFINES['SK_BUILD_FOR_ANDROID_NDK'] = True
--- a/widget/gonk/nativewindow/FakeSurfaceComposer.h
+++ b/widget/gonk/nativewindow/FakeSurfaceComposer.h
@@ -37,17 +37,17 @@ class IGraphicBufferAlloc;
 class FakeSurfaceComposer : public BinderService<FakeSurfaceComposer>,
                             public BnSurfaceComposer
 {
 public:
     static char const* getServiceName() {
         return "FakeSurfaceComposer";
     }
 
-    // Instantiate MediaResourceManagerService and register to service manager.
+    // Instantiate FakeSurfaceComposer and register to service manager.
     // If service manager is not present, wait until service manager becomes present.
     static  void instantiate();
 
 #if ANDROID_VERSION >= 19
     virtual void destroyDisplay(const sp<android::IBinder>& display);
 #endif
 
 #if ANDROID_VERSION >= 21
--- a/widget/gonk/nsAppShell.cpp
+++ b/widget/gonk/nsAppShell.cpp
@@ -31,19 +31,16 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include <utils/BitSet.h>
 
 #include "base/basictypes.h"
 #include "GonkPermission.h"
 #include "libdisplay/BootAnimation.h"
 #include "nscore.h"
-#ifdef MOZ_OMX_DECODER
-#include "MediaResourceManagerService.h"
-#endif
 #include "mozilla/TouchEvents.h"
 #include "mozilla/FileUtils.h"
 #include "mozilla/Hal.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/Services.h"
 #include "mozilla/TextEvents.h"
 #if ANDROID_VERSION >= 18
@@ -885,19 +882,16 @@ nsAppShell::Init()
     InitGonkMemoryPressureMonitoring();
 
     if (XRE_IsParentProcess()) {
         printf("*****************************************************************\n");
         printf("***\n");
         printf("*** This is stdout. Most of the useful output will be in logcat.\n");
         printf("***\n");
         printf("*****************************************************************\n");
-#ifdef MOZ_OMX_DECODER
-        android::MediaResourceManagerService::instantiate();
-#endif
 #if ANDROID_VERSION >= 18 && (defined(MOZ_OMX_DECODER) || defined(MOZ_B2G_CAMERA))
         android::FakeSurfaceComposer::instantiate();
 #endif
         GonkPermissionService::instantiate();
 
         // Causes the kernel timezone to be set, which in turn causes the
         // timestamps on SD cards to have the local time rather than UTC time.
         hal::SetTimezone(hal::GetTimezone());
--- a/widget/gtk/compat/gtk/gtkwindow.h
+++ b/widget/gtk/compat/gtk/gtkwindow.h
@@ -1,20 +1,30 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GTKWINDOW_WRAPPER_H
 #define GTKWINDOW_WRAPPER_H
 
 #define gtk_window_group_get_current_grab gtk_window_group_get_current_grab_
+#define gtk_window_get_window_type gtk_window_get_window_type_
 #include_next <gtk/gtkwindow.h>
 #undef gtk_window_group_get_current_grab
+#undef gtk_window_get_window_type
 
 static inline GtkWidget *
 gtk_window_group_get_current_grab(GtkWindowGroup *window_group)
 {
   if (!window_group->grabs)
     return NULL;
 
   return GTK_WIDGET(window_group->grabs->data);
 }
+
+static inline GtkWindowType
+gtk_window_get_window_type(GtkWindow *window)
+{
+  gint type;
+  g_object_get(window, "type", &type, (void*)NULL);
+  return (GtkWindowType)type;
+}
 #endif /* GTKWINDOW_WRAPPER_H */
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -1515,30 +1515,29 @@ nsWindow::GetClientBounds(nsIntRect &aRe
     return NS_OK;
 }
 
 nsIntPoint
 nsWindow::GetClientOffset()
 {
     PROFILER_LABEL("nsWindow", "GetClientOffset", js::ProfileEntry::Category::GRAPHICS);
 
-    if (!mIsTopLevel) {
+    if (!mIsTopLevel || !mShell || !mGdkWindow ||
+        gtk_window_get_window_type(GTK_WINDOW(mShell)) == GTK_WINDOW_POPUP) {
         return nsIntPoint(0, 0);
     }
 
     GdkAtom cardinal_atom = gdk_x11_xatom_to_atom(XA_CARDINAL);
 
     GdkAtom type_returned;
     int format_returned;
     int length_returned;
     long *frame_extents;
-    GdkWindow* window;
-
-    if (!mShell || !(window = gtk_widget_get_window(mShell)) ||
-        !gdk_property_get(window,
+
+    if (!gdk_property_get(mGdkWindow,
                           gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE),
                           cardinal_atom,
                           0, // offset
                           4*4, // length
                           FALSE, // delete
                           &type_returned,
                           &format_returned,
                           &length_returned,
@@ -2355,23 +2354,19 @@ nsWindow::OnConfigureEvent(GtkWidget *aW
             mBounds.y != screenBounds.y) {
             CheckForRollup(0, 0, false, true);
         }
     }
 
     // This event indicates that the window position may have changed.
     // mBounds.Size() is updated in OnSizeAllocate().
 
-    // (The gtk_window_get_window_type() function is only available from
-    // version 2.20.)
     NS_ASSERTION(GTK_IS_WINDOW(aWidget),
                  "Configure event on widget that is not a GtkWindow");
-    gint type;
-    g_object_get(aWidget, "type", &type, nullptr);
-    if (type == GTK_WINDOW_POPUP) {
+    if (gtk_window_get_window_type(GTK_WINDOW(aWidget)) == GTK_WINDOW_POPUP) {
         // Override-redirect window
         //
         // These windows should not be moved by the window manager, and so any
         // change in position is a result of our direction.  mBounds has
         // already been set in Move() or Resize(), and that is more
         // up-to-date than the position in the ConfigureNotify event if the
         // event is from an earlier window move.
         //
@@ -3622,17 +3617,17 @@ nsWindow::Create(nsIWidget        *aPare
                                     // cursor, even though our internal state
                                     // indicates that we already have the
                                     // standard cursor.
             SetCursor(eCursor_standard);
 
             if (aInitData->mNoAutoHide) {
                 gint wmd = ConvertBorderStyles(mBorderStyle);
                 if (wmd != -1)
-                  gdk_window_set_decorations(gtk_widget_get_window(mShell), (GdkWMDecoration) wmd);
+                  gdk_window_set_decorations(mGdkWindow, (GdkWMDecoration) wmd);
             }
 
             // If the popup ignores mouse events, set an empty input shape.
             if (aInitData->mMouseTransparent) {
 #if (MOZ_WIDGET_GTK == 2)
               GdkRectangle rect = { 0, 0, 0, 0 };
               GdkRegion *region = gdk_region_rectangle(&rect);
 
@@ -3845,34 +3840,33 @@ nsWindow::SetWindowClass(const nsAString
       role = c + 1;
     }
     else if (!isascii(*c) || (!isalnum(*c) && ('_' != *c) && ('-' != *c)))
       *c = '_';
   }
   res_name[0] = toupper(res_name[0]);
   if (!role) role = res_name;
 
-  GdkWindow *shellWindow = gtk_widget_get_window(GTK_WIDGET(mShell));
-  gdk_window_set_role(shellWindow, role);
+  gdk_window_set_role(mGdkWindow, role);
 
 #ifdef MOZ_X11
   GdkDisplay *display = gdk_display_get_default();
   if (GDK_IS_X11_DISPLAY(display)) {
       XClassHint *class_hint = XAllocClassHint();
       if (!class_hint) {
         free(res_name);
         return NS_ERROR_OUT_OF_MEMORY;
       }
       class_hint->res_name = res_name;
       class_hint->res_class = const_cast<char*>(res_class);
 
       // Can't use gtk_window_set_wmclass() for this; it prints
       // a warning & refuses to make the change.
       XSetClassHint(GDK_DISPLAY_XDISPLAY(display),
-                    gdk_x11_window_get_xid(shellWindow),
+                    gdk_x11_window_get_xid(mGdkWindow),
                     class_hint);
       XFree(class_hint);
   }
 #endif /* MOZ_X11 */
 
   free(res_name);
 
   return NS_OK;
@@ -4295,32 +4289,31 @@ void UpdateMaskBits(gchar* aMaskBits, in
 
 void
 nsWindow::ApplyTransparencyBitmap()
 {
 #ifdef MOZ_X11
     // We use X11 calls where possible, because GDK handles expose events
     // for shaped windows in a way that's incompatible with us (Bug 635903).
     // It doesn't occur when the shapes are set through X.
-    GdkWindow *shellWindow = gtk_widget_get_window(mShell);
-    Display* xDisplay = GDK_WINDOW_XDISPLAY(shellWindow);
-    Window xDrawable = GDK_WINDOW_XID(shellWindow);
+    Display* xDisplay = GDK_WINDOW_XDISPLAY(mGdkWindow);
+    Window xDrawable = GDK_WINDOW_XID(mGdkWindow);
     Pixmap maskPixmap = XCreateBitmapFromData(xDisplay,
                                               xDrawable,
                                               mTransparencyBitmap,
                                               mTransparencyBitmapWidth,
                                               mTransparencyBitmapHeight);
     XShapeCombineMask(xDisplay, xDrawable,
                       ShapeBounding, 0, 0,
                       maskPixmap, ShapeSet);
     XFreePixmap(xDisplay, maskPixmap);
 #else
 #if (MOZ_WIDGET_GTK == 2)
     gtk_widget_reset_shapes(mShell);
-    GdkBitmap* maskBitmap = gdk_bitmap_create_from_data(gtk_widget_get_window(mShell),
+    GdkBitmap* maskBitmap = gdk_bitmap_create_from_data(mGdkWindow,
             mTransparencyBitmap,
             mTransparencyBitmapWidth, mTransparencyBitmapHeight);
     if (!maskBitmap)
         return;
 
     gtk_widget_shape_combine_mask(mShell, maskBitmap, 0, 0);
     g_object_unref(maskBitmap);
 #else
@@ -4351,22 +4344,21 @@ nsWindow::ClearTransparencyBitmap()
     mTransparencyBitmap = nullptr;
     mTransparencyBitmapWidth = 0;
     mTransparencyBitmapHeight = 0;
 
     if (!mShell)
         return;
 
 #ifdef MOZ_X11
-    GdkWindow *window = gtk_widget_get_window(mShell);
-    if (!window)
+    if (!mGdkWindow)
         return;
 
-    Display* xDisplay = GDK_WINDOW_XDISPLAY(window);
-    Window xWindow = gdk_x11_window_get_xid(window);
+    Display* xDisplay = GDK_WINDOW_XDISPLAY(mGdkWindow);
+    Window xWindow = gdk_x11_window_get_xid(mGdkWindow);
 
     XShapeCombineMask(xDisplay, xWindow, ShapeBounding, 0, 0, None, ShapeSet);
 #endif
 }
 
 nsresult
 nsWindow::UpdateTranslucentWindowAlphaInternal(const nsIntRect& aRect,
                                                uint8_t* aAlphas, int32_t aStride)
@@ -4730,33 +4722,32 @@ nsWindow::HideWindowChrome(bool aShouldH
 
         return topWindow->HideWindowChrome(aShouldHide);
     }
 
     // Sawfish, metacity, and presumably other window managers get
     // confused if we change the window decorations while the window
     // is visible.
     bool wasVisible = false;
-    GdkWindow *shellWindow = gtk_widget_get_window(mShell);
-    if (gdk_window_is_visible(shellWindow)) {
-        gdk_window_hide(shellWindow);
+    if (gdk_window_is_visible(mGdkWindow)) {
+        gdk_window_hide(mGdkWindow);
         wasVisible = true;
     }
 
     gint wmd;
     if (aShouldHide)
         wmd = 0;
     else
         wmd = ConvertBorderStyles(mBorderStyle);
 
     if (wmd != -1)
-      gdk_window_set_decorations(shellWindow, (GdkWMDecoration) wmd);
+      gdk_window_set_decorations(mGdkWindow, (GdkWMDecoration) wmd);
 
     if (wasVisible)
-        gdk_window_show(shellWindow);
+        gdk_window_show(mGdkWindow);
 
     // For some window managers, adding or removing window decorations
     // requires unmapping and remapping our toplevel window.  Go ahead
     // and flush the queue here so that we don't end up with a BadWindow
     // error later when this happens (when the persistence timer fires
     // and GetWindowPos is called)
 #ifdef MOZ_X11
     XSync(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()) , False);