Backout 3f0e69962962, 84a1afc5b15e, c62f225d0dbb, 24870ebc9665, and dd7663e68657 (bug 799344) for mochitest-1 orange.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 06 Nov 2012 19:36:49 -0500
changeset 112486 bd15d6741bffda17af97d17fa9b1f41698068640
parent 112485 e3bec8c880a77dbd84e01eba49a289fd54468b80
child 112487 70f7e6ce95b8f6de7a42da57f13c1cb1040e935a
push id17607
push userryanvm@gmail.com
push dateWed, 07 Nov 2012 00:37:03 +0000
treeherdermozilla-inbound@bd15d6741bff [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs799344
milestone19.0a1
backs out3f0e699629623280fc46d25f749be343299c9ad0
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backout 3f0e69962962, 84a1afc5b15e, c62f225d0dbb, 24870ebc9665, and dd7663e68657 (bug 799344) for mochitest-1 orange.
content/media/dash/nsDASHDecoder.cpp
content/media/dash/nsDASHDecoder.h
content/media/dash/nsDASHReader.cpp
content/media/dash/nsDASHRepDecoder.cpp
content/media/dash/nsDASHRepDecoder.h
content/media/gstreamer/nsGStreamerDecoder.cpp
content/media/gstreamer/nsGStreamerDecoder.h
content/media/nsBuiltinDecoder.cpp
content/media/nsBuiltinDecoder.h
content/media/nsBuiltinDecoderReader.cpp
content/media/nsBuiltinDecoderReader.h
content/media/nsBuiltinDecoderStateMachine.cpp
content/media/nsBuiltinDecoderStateMachine.h
content/media/ogg/nsOggDecoder.cpp
content/media/ogg/nsOggDecoder.h
content/media/ogg/nsOggReader.cpp
content/media/omx/nsMediaOmxDecoder.cpp
content/media/omx/nsMediaOmxDecoder.h
content/media/omx/nsMediaOmxReader.cpp
content/media/plugins/nsMediaPluginDecoder.cpp
content/media/plugins/nsMediaPluginDecoder.h
content/media/plugins/nsMediaPluginReader.cpp
content/media/raw/nsRawDecoder.cpp
content/media/raw/nsRawDecoder.h
content/media/raw/nsRawReader.cpp
content/media/wave/nsWaveDecoder.cpp
content/media/wave/nsWaveDecoder.h
content/media/wave/nsWaveReader.cpp
content/media/webm/nsWebMDecoder.cpp
content/media/webm/nsWebMDecoder.h
layout/build/nsLayoutStatics.cpp
--- a/content/media/dash/nsDASHDecoder.cpp
+++ b/content/media/dash/nsDASHDecoder.cpp
@@ -153,17 +153,17 @@ nsDASHDecoder::nsDASHDecoder() :
   MOZ_COUNT_CTOR(nsDASHDecoder);
 }
 
 nsDASHDecoder::~nsDASHDecoder()
 {
   MOZ_COUNT_DTOR(nsDASHDecoder);
 }
 
-nsBuiltinDecoderStateMachine*
+nsDecoderStateMachine*
 nsDASHDecoder::CreateStateMachine()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   return new nsBuiltinDecoderStateMachine(this, mDASHReader);
 }
 
 void
 nsDASHDecoder::ReleaseStateMachine()
--- a/content/media/dash/nsDASHDecoder.h
+++ b/content/media/dash/nsDASHDecoder.h
@@ -45,17 +45,17 @@ public:
   nsDASHDecoder();
   ~nsDASHDecoder();
 
   // Clone not supported; just return nullptr.
   nsMediaDecoder* Clone() { return nullptr; }
 
   // Creates a single state machine for all stream decoders.
   // Called from Load on the main thread only.
-  nsBuiltinDecoderStateMachine* CreateStateMachine();
+  nsDecoderStateMachine* CreateStateMachine();
 
   // Loads the MPD from the network and subsequently loads the media streams.
   // Called from the main thread only.
   nsresult Load(MediaResource* aResource,
                 nsIStreamListener** aListener,
                 nsMediaDecoder* aCloneDonor);
 
   // Notifies download of MPD file has ended.
--- a/content/media/dash/nsDASHReader.cpp
+++ b/content/media/dash/nsDASHReader.cpp
@@ -269,24 +269,28 @@ nsDASHReader::FindStartTime(int64_t& aOu
   int64_t videoStartTime = INT64_MAX;
   int64_t audioStartTime = INT64_MAX;
   VideoData* videoData = nullptr;
 
   ReentrantMonitorConditionallyEnter mon(!mDecoder->OnDecodeThread(),
                                          mDecoder->GetReentrantMonitor());
   if (HasVideo()) {
     // Forward to video reader.
-    videoData = mVideoReader->DecodeToFirstVideoData();
+    videoData
+       = mVideoReader->DecodeToFirstData(&nsBuiltinDecoderReader::DecodeVideoFrame,
+                                         VideoQueue());
     if (videoData) {
       videoStartTime = videoData->mTime;
     }
   }
   if (HasAudio()) {
     // Forward to audio reader.
-    AudioData* audioData = mAudioReader->DecodeToFirstAudioData();
+    AudioData* audioData
+        = mAudioReader->DecodeToFirstData(&nsBuiltinDecoderReader::DecodeAudioData,
+                                          AudioQueue());
     if (audioData) {
       audioStartTime = audioData->mTime;
     }
   }
 
   int64_t startTime = NS_MIN(videoStartTime, audioStartTime);
   if (startTime != INT64_MAX) {
     aOutStartTime = startTime;
--- a/content/media/dash/nsDASHRepDecoder.cpp
+++ b/content/media/dash/nsDASHRepDecoder.cpp
@@ -26,26 +26,26 @@ extern PRLogModuleInfo* gBuiltinDecoderL
                              ("%p [nsDASHRepDecoder] " msg, this, __VA_ARGS__))
 #define LOG1(msg) PR_LOG(gBuiltinDecoderLog, PR_LOG_DEBUG, \
                          ("%p [nsDASHRepDecoder] " msg, this))
 #else
 #define LOG(msg, ...)
 #define LOG1(msg)
 #endif
 
-nsBuiltinDecoderStateMachine*
+nsDecoderStateMachine*
 nsDASHRepDecoder::CreateStateMachine()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   // Do not create; just return current state machine.
   return mDecoderStateMachine;
 }
 
 nsresult
-nsDASHRepDecoder::SetStateMachine(nsBuiltinDecoderStateMachine* aSM)
+nsDASHRepDecoder::SetStateMachine(nsDecoderStateMachine* aSM)
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   mDecoderStateMachine = aSM;
   return NS_OK;
 }
 
 void
 nsDASHRepDecoder::SetResource(MediaResource* aResource)
@@ -341,16 +341,24 @@ nsDASHRepDecoder::OnDecodeThread() const
 }
 
 ReentrantMonitor&
 nsDASHRepDecoder::GetReentrantMonitor()
 {
   return mMainDecoder->GetReentrantMonitor();
 }
 
+nsDecoderStateMachine::State
+nsDASHRepDecoder::GetDecodeState()
+{
+  // XXX SHUTDOWN might not be an appropriate error.
+  return (mMainDecoder ? mMainDecoder->GetDecodeState()
+                       : nsDecoderStateMachine::DECODER_STATE_SHUTDOWN);
+}
+
 mozilla::layers::ImageContainer*
 nsDASHRepDecoder::GetImageContainer()
 {
   NS_ASSERTION(mMainDecoder && mMainDecoder->OnDecodeThread(),
                "Should be on decode thread.");
   return (mMainDecoder ? mMainDecoder->GetImageContainer() : nullptr);
 }
 
--- a/content/media/dash/nsDASHRepDecoder.h
+++ b/content/media/dash/nsDASHRepDecoder.h
@@ -48,22 +48,22 @@ public:
     MOZ_COUNT_DTOR(nsDASHRepDecoder);
   }
 
   // Clone not supported; just return nullptr.
   virtual nsMediaDecoder* Clone() { return nullptr; }
 
   // Called by the main decoder at creation time; points to the main state
   // machine managed by the main decoder. Called on the main thread only.
-  nsresult SetStateMachine(nsBuiltinDecoderStateMachine* aSM);
+  nsresult SetStateMachine(nsDecoderStateMachine* aSM);
 
 private:
   // Overridden to return the ptr set by SetStateMachine. Called on the main
   // thread only.
-  nsBuiltinDecoderStateMachine* CreateStateMachine();
+  nsDecoderStateMachine* CreateStateMachine();
 
 public:
   // Called by nsDASHDecoder at creation time; points to the media resource
   // for this decoder's |Representation|. Called on the main thread only.
   void SetResource(MediaResource* aResource);
 
   // Sets the |Representation| object for this decoder. Called on the main
   // thread.
@@ -130,16 +130,20 @@ public:
   bool OnStateMachineThread() const;
 
   // Returns true if the current thread is the decode thread.
   bool OnDecodeThread() const;
 
   // Returns main decoder's monitor for synchronised access.
   ReentrantMonitor& GetReentrantMonitor();
 
+  // Return the current decode state, according to the main decoder. The
+  // decoder monitor must be obtained before calling this.
+  nsDecoderStateMachine::State GetDecodeState();
+
   // Called on the decode thread from nsWebMReader.
   ImageContainer* GetImageContainer();
 
   // Called when Metadata has been read; notifies that index data is read.
   // Called on the decode thread only.
   void OnReadMetadataCompleted();
 
   // Overridden to cleanup ref to |nsDASHDecoder|. Called on main thread only.
--- a/content/media/gstreamer/nsGStreamerDecoder.cpp
+++ b/content/media/gstreamer/nsGStreamerDecoder.cpp
@@ -3,12 +3,12 @@
 /* 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 "nsBuiltinDecoderStateMachine.h"
 #include "nsGStreamerReader.h"
 #include "nsGStreamerDecoder.h"
 
-nsBuiltinDecoderStateMachine* nsGStreamerDecoder::CreateStateMachine()
+nsDecoderStateMachine* nsGStreamerDecoder::CreateStateMachine()
 {
   return new nsBuiltinDecoderStateMachine(this, new nsGStreamerReader(this));
 }
--- a/content/media/gstreamer/nsGStreamerDecoder.h
+++ b/content/media/gstreamer/nsGStreamerDecoder.h
@@ -8,12 +8,12 @@
 #define nsGStreamerDecoder_h_
 
 #include "nsBuiltinDecoder.h"
 
 class nsGStreamerDecoder : public nsBuiltinDecoder
 {
 public:
   virtual nsMediaDecoder* Clone() { return new nsGStreamerDecoder(); }
-  virtual nsBuiltinDecoderStateMachine* CreateStateMachine();
+  virtual nsDecoderStateMachine* CreateStateMachine();
 };
 
 #endif
--- a/content/media/nsBuiltinDecoder.cpp
+++ b/content/media/nsBuiltinDecoder.cpp
@@ -1,40 +1,40 @@
 /* -*- 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 "nsBuiltinDecoder.h"
 #include <limits>
 #include "nsNetUtil.h"
 #include "nsAudioStream.h"
 #include "nsHTMLVideoElement.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
 #include "nsTArray.h"
 #include "VideoUtils.h"
+#include "nsBuiltinDecoder.h"
 #include "nsBuiltinDecoderStateMachine.h"
 #include "nsTimeRanges.h"
 #include "nsContentUtils.h"
 #include "ImageContainer.h"
 
 using namespace mozilla;
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* gBuiltinDecoderLog;
 #define LOG(type, msg) PR_LOG(gBuiltinDecoderLog, type, msg)
 #else
 #define LOG(type, msg)
 #endif
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(nsBuiltinDecoder, nsIObserver)
 
-void nsBuiltinDecoder::Pause()
+void nsBuiltinDecoder::Pause() 
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   if (mPlayState == PLAY_STATE_SEEKING || mPlayState == PLAY_STATE_ENDED) {
     mNextState = PLAY_STATE_PAUSED;
     return;
   }
 
@@ -248,17 +248,17 @@ bool nsBuiltinDecoder::Init(nsHTMLMediaE
 
   nsContentUtils::RegisterShutdownObserver(this);
   return true;
 }
 
 void nsBuiltinDecoder::Shutdown()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
-
+  
   if (mShuttingDown)
     return;
 
   mShuttingDown = true;
 
   {
     ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
     DestroyDecodedStream();
@@ -345,17 +345,17 @@ nsresult nsBuiltinDecoder::InitializeSta
     return NS_ERROR_FAILURE;
   }
   {
     ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
     mDecoderStateMachine->SetSeekable(mSeekable);
     mDecoderStateMachine->SetDuration(mDuration);
     mDecoderStateMachine->SetVolume(mInitialVolume);
     mDecoderStateMachine->SetAudioCaptured(mInitialAudioCaptured);
-
+    
     if (mFrameBufferLength > 0) {
       // The valid mFrameBufferLength value was specified earlier
       mDecoderStateMachine->SetFrameBufferLength(mFrameBufferLength);
     }
   }
 
   ChangeState(PLAY_STATE_LOADING);
 
@@ -739,17 +739,17 @@ nsMediaDecoder::Statistics
 nsBuiltinDecoder::GetStatistics()
 {
   NS_ASSERTION(NS_IsMainThread() || OnStateMachineThread(),
                "Should be on main or state machine thread.");
   Statistics result;
 
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   if (mResource) {
-    result.mDownloadRate =
+    result.mDownloadRate = 
       mResource->GetDownloadRate(&result.mDownloadRateReliable);
     result.mDownloadPosition =
       mResource->GetCachedDataEnd(mDecoderPosition);
     result.mTotalBytes = mResource->GetLength();
     result.mPlaybackRate = ComputePlaybackRate(&result.mPlaybackRateReliable);
     result.mDecoderPosition = mDecoderPosition;
     result.mPlaybackPosition = mPlaybackPosition;
   }
@@ -804,26 +804,26 @@ void nsBuiltinDecoder::UpdatePlaybackRat
 
 void nsBuiltinDecoder::NotifySuspendedStatusChanged()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   if (!mResource)
     return;
   MediaResource* activeStream;
   bool suspended = mResource->IsSuspendedByCache(&activeStream);
-
+  
   if (mElement) {
     if (suspended) {
       // If this is an autoplay element, we need to kick off its autoplaying
       // now so we consume data and hopefully free up cache space.
       mElement->NotifyAutoplayDataReady();
     }
     mElement->NotifySuspendedByCache(suspended);
     UpdateReadyStateForData();
-  }
+  } 
 }
 
 void nsBuiltinDecoder::NotifyBytesDownloaded()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   UpdateReadyStateForData();
   Progress(false);
 }
@@ -984,17 +984,17 @@ void nsBuiltinDecoder::SeekingStarted()
   if (mElement) {
     UpdateReadyStateForData();
     mElement->SeekStarted();
   }
 }
 
 void nsBuiltinDecoder::ChangeState(PlayState aState)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
+  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");   
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
 
   if (mNextState == aState) {
     mNextState = PLAY_STATE_PAUSED;
   }
 
   if (mPlayState == PLAY_STATE_SHUTDOWN) {
     GetReentrantMonitor().NotifyAll();
@@ -1206,61 +1206,8 @@ bool nsBuiltinDecoder::OnStateMachineThr
 void nsBuiltinDecoder::NotifyAudioAvailableListener()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   if (mDecoderStateMachine) {
     ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
     mDecoderStateMachine->NotifyAudioAvailableListener();
   }
 }
-
-bool nsBuiltinDecoder::OnDecodeThread() const {
-  return mDecoderStateMachine->OnDecodeThread();
-}
-
-ReentrantMonitor& nsBuiltinDecoder::GetReentrantMonitor() {
-  return mReentrantMonitor.GetReentrantMonitor();
-}
-
-// Constructs the time ranges representing what segments of the media
-// are buffered and playable.
-nsresult nsBuiltinDecoder::GetBuffered(nsTimeRanges* aBuffered) {
-  if (mDecoderStateMachine) {
-    return mDecoderStateMachine->GetBuffered(aBuffered);
-  }
-  return NS_ERROR_FAILURE;
-}
-
-int64_t nsBuiltinDecoder::VideoQueueMemoryInUse() {
-  if (mDecoderStateMachine) {
-    return mDecoderStateMachine->VideoQueueMemoryInUse();
-  }
-  return 0;
-}
-
-int64_t nsBuiltinDecoder::AudioQueueMemoryInUse() {
-  if (mDecoderStateMachine) {
-    return mDecoderStateMachine->AudioQueueMemoryInUse();
-  }
-  return 0;
-}
-
-void nsBuiltinDecoder::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) {
-  if (mDecoderStateMachine) {
-    mDecoderStateMachine->NotifyDataArrived(aBuffer, aLength, aOffset);
-  }
-}
-
-void nsBuiltinDecoder::UpdatePlaybackPosition(int64_t aTime)
-{
-  mDecoderStateMachine->UpdatePlaybackPosition(aTime);
-}
-
-// Provide access to the state machine object
-nsBuiltinDecoderStateMachine* nsBuiltinDecoder::GetStateMachine() {
-  return mDecoderStateMachine;
-}
-
-// Drop reference to state machine.  Only called during shutdown dance.
-void nsBuiltinDecoder::ReleaseStateMachine() {
-  mDecoderStateMachine = nullptr;
-}
-
--- a/content/media/nsBuiltinDecoder.h
+++ b/content/media/nsBuiltinDecoder.h
@@ -8,19 +8,20 @@ Each video element based on nsBuiltinDec
 its play state and keep the current frame up to date. All state machines
 share time in a single shared thread. Each decoder also has one thread
 dedicated to decoding audio and video data. This thread is shutdown when
 playback is paused. Each decoder also has a thread to push decoded audio
 to the hardware. This thread is not created until playback starts, but
 currently is not destroyed when paused, only when playback ends.
 
 The decoder owns the resources for downloading the media file, and the
-high level state. It holds an owning reference to the state machine that
+high level state. It holds an owning reference to the state machine
+(a subclass of nsDecoderStateMachine; nsBuiltinDecoderStateMachine) that
 owns all the resources related to decoding data, and manages the low level
-decoding operations and A/V sync.
+decoding operations and A/V sync. 
 
 Each state machine runs on the shared state machine thread. Every time some
 action is required for a state machine, it is scheduled to run on the shared
 the state machine thread. The state machine runs one "cycle" on the state
 machine thread, and then returns. If necessary, it will schedule itself to
 run again in future. While running this cycle, it must not block the
 thread, as other state machines' events may need to run. State shared
 between a state machine's threads is synchronised via the monitor owned
@@ -29,17 +30,17 @@ by its nsBuiltinDecoder object.
 The Main thread controls the decode state machine by setting the value
 of a mPlayState variable and notifying on the monitor based on the
 high level player actions required (Seek, Pause, Play, etc).
 
 The player states are the states requested by the client through the
 DOM API.  They represent the desired state of the player, while the
 decoder's state represents the actual state of the decoder.
 
-The high level state of the player is maintained via a PlayState value.
+The high level state of the player is maintained via a PlayState value. 
 It can have the following states:
 
 START
   The decoder has been initialized but has no resource loaded.
 PAUSED
   A request via the API has been received to pause playback.
 LOADING
   A request via the API has been received to load a resource.
@@ -54,17 +55,17 @@ SHUTDOWN
 
 State transition occurs when the Media Element calls the Play, Seek,
 etc methods on the nsBuiltinDecoder object. When the transition
 occurs nsBuiltinDecoder then calls the methods on the decoder state
 machine object to cause it to behave as required by the play state.
 State transitions will likely schedule the state machine to run to
 affect the change.
 
-An implementation of the nsBuiltinDecoderStateMachine class is the event
+An implementation of the nsDecoderStateMachine class is the event
 that gets dispatched to the state machine thread. Each time the event is run,
 the state machine must cycle the state machine once, and then return.
 
 The state machine has the following states:
 
 DECODING_METADATA
   The media headers are being loaded, and things like framerate, etc are
   being determined, and the first frame of audio/video data is being decoded.
@@ -85,17 +86,17 @@ COMPLETED
 SHUTDOWN
   The decoder object and its state machine are about to be destroyed.
   Once the last state machine has been destroyed, the shared state machine
   thread will also be destroyed. It will be recreated later if needed.
 
 The following result in state transitions.
 
 Shutdown()
-  Clean up any resources the nsBuiltinDecoderStateMachine owns.
+  Clean up any resources the nsDecoderStateMachine owns.
 Play()
   Start decoding and playback of media data.
 Buffer
   This is not user initiated. It occurs when the
   available data in the stream drops below a certain point.
 Complete
   This is not user initiated. It occurs when the
   stream is completely decoded.
@@ -121,31 +122,31 @@ DECODING             |          |  |    
   |          Play()  |Seek(t)   |Buffer()         |
   -----------<--------<-------BUFFERING           |
                                 |                 ^
                                 v Shutdown()      |
                                 |                 |
                                 ------------>-----|
 
 The following represents the states that the nsBuiltinDecoder object
-can be in, and the valid states the nsBuiltinDecoderStateMachine can be in at that
+can be in, and the valid states the nsDecoderStateMachine can be in at that
 time:
 
 player LOADING   decoder DECODING_METADATA
 player PLAYING   decoder DECODING, BUFFERING, SEEKING, COMPLETED
 player PAUSED    decoder DECODING, BUFFERING, SEEKING, COMPLETED
 player SEEKING   decoder SEEKING
 player COMPLETED decoder SHUTDOWN
 player SHUTDOWN  decoder SHUTDOWN
 
 The general sequence of events is:
 
 1) The video element calls Load on nsMediaDecoder. This creates the
    state machine and starts the channel for downloading the
-   file. It instantiates and schedules the nsBuiltinDecoderStateMachine. The
+   file. It instantiates and schedules the nsDecoderStateMachine. The
    high level LOADING state is entered, which results in the decode
    thread being created and starting to decode metadata. These are
    the headers that give the video size, framerate, etc. Load() returns
    immediately to the calling video element.
 
 2) When the metadata has been loaded by the decode thread, the state machine
    will call a method on the video element object to inform it that this
    step is done, so it can do the things required by the video specification
@@ -199,22 +200,139 @@ namespace mozilla {
 namespace layers {
 class Image;
 } //namespace
 } //namespace
 
 typedef mozilla::layers::Image Image;
 
 class nsAudioStream;
-class nsBuiltinDecoderStateMachine;
 
 static inline bool IsCurrentThread(nsIThread* aThread) {
   return NS_GetCurrentThread() == aThread;
 }
 
+// Decoder backends must implement this class to perform the codec
+// specific parts of decoding the video/audio format.
+class nsDecoderStateMachine : public nsRunnable
+{
+public:
+  // Enumeration for the valid decoding states
+  enum State {
+    DECODER_STATE_DECODING_METADATA,
+    DECODER_STATE_DECODING,
+    DECODER_STATE_SEEKING,
+    DECODER_STATE_BUFFERING,
+    DECODER_STATE_COMPLETED,
+    DECODER_STATE_SHUTDOWN
+  };
+
+  // Initializes the state machine, returns NS_OK on success, or
+  // NS_ERROR_FAILURE on failure.
+  virtual nsresult Init(nsDecoderStateMachine* aCloneDonor) = 0;
+
+  // Return the current decode state. The decoder monitor must be
+  // obtained before calling this.
+  virtual State GetState() = 0;
+
+  // Set the audio volume. The decoder monitor must be obtained before
+  // calling this.
+  virtual void SetVolume(double aVolume) = 0;
+  virtual void SetAudioCaptured(bool aCapture) = 0;
+
+  virtual void Shutdown() = 0;
+
+  // Called from the main thread to get the duration. The decoder monitor
+  // must be obtained before calling this. It is in units of microseconds.
+  virtual int64_t GetDuration() = 0;
+
+  // Called from the main thread to set the duration of the media resource
+  // if it is able to be obtained via HTTP headers. Called from the 
+  // state machine thread to set the duration if it is obtained from the
+  // media metadata. The decoder monitor must be obtained before calling this.
+  // aDuration is in microseconds.
+  virtual void SetDuration(int64_t aDuration) = 0;
+
+  // Called while decoding metadata to set the end time of the media
+  // resource. The decoder monitor must be obtained before calling this.
+  // aEndTime is in microseconds.
+  virtual void SetEndTime(int64_t aEndTime) = 0;
+
+  // Set the media fragment end time. aEndTime is in microseconds.
+  virtual void SetFragmentEndTime(int64_t aEndTime) = 0;
+
+  // Functions used by assertions to ensure we're calling things
+  // on the appropriate threads.
+  virtual bool OnDecodeThread() const = 0;
+
+  // Returns true if the current thread is the state machine thread.
+  virtual bool OnStateMachineThread() const = 0;
+
+  virtual nsHTMLMediaElement::NextFrameStatus GetNextFrameStatus() = 0;
+
+  // Cause state transitions. These methods obtain the decoder monitor
+  // to synchronise the change of state, and to notify other threads
+  // that the state has changed.
+  virtual void Play() = 0;
+
+  // Seeks to aTime in seconds
+  virtual void Seek(double aTime) = 0;
+
+  // Returns the current playback position in seconds.
+  // Called from the main thread to get the current frame time. The decoder
+  // monitor must be obtained before calling this.
+  virtual double GetCurrentTime() const = 0;
+
+  // Clear the flag indicating that a playback position change event
+  // is currently queued. This is called from the main thread and must
+  // be called with the decode monitor held.
+  virtual void ClearPositionChangeFlag() = 0;
+
+  // Called from the main thread to set whether the media resource can
+  // seek into unbuffered ranges. The decoder monitor must be obtained
+  // before calling this.
+  virtual void SetSeekable(bool aSeekable) = 0;
+
+  // Returns true if the media resource can seek into unbuffered ranges,
+  // as set by SetSeekable(). The decoder monitor must be obtained before
+  // calling this.
+  virtual bool IsSeekable() = 0;
+
+  // Update the playback position. This can result in a timeupdate event
+  // and an invalidate of the frame being dispatched asynchronously if
+  // there is no such event currently queued.
+  // Only called on the decoder thread. Must be called with
+  // the decode monitor held.
+  virtual void UpdatePlaybackPosition(int64_t aTime) = 0;
+
+  virtual nsresult GetBuffered(nsTimeRanges* aBuffered) = 0;
+
+  // Return true if the media is seekable using only buffered ranges.
+  virtual bool IsSeekableInBufferedRanges() = 0;
+
+  virtual int64_t VideoQueueMemoryInUse() = 0;
+  virtual int64_t AudioQueueMemoryInUse() = 0;
+
+  virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) = 0;
+
+  // Causes the state machine to switch to buffering state, and to
+  // immediately stop playback and buffer downloaded data. Must be called
+  // with the decode monitor held. Called on the state machine thread and
+  // the main thread.
+  virtual void StartBuffering() = 0;
+
+  // Sets the current size of the framebuffer used in MozAudioAvailable events.
+  // Called on the state machine thread and the main thread.
+  virtual void SetFrameBufferLength(uint32_t aLength) = 0;
+
+  // Called when a "MozAudioAvailable" event listener is added to the media
+  // element. Called on the main thread.
+  virtual void NotifyAudioAvailableListener() = 0;
+};
+
 class nsBuiltinDecoder : public nsMediaDecoder
 {
 public:
   typedef mozilla::MediaChannelStatistics MediaChannelStatistics;
   class DecodedStreamMainThreadListener;
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
@@ -227,34 +345,34 @@ public:
     PLAY_STATE_PLAYING,
     PLAY_STATE_SEEKING,
     PLAY_STATE_ENDED,
     PLAY_STATE_SHUTDOWN
   };
 
   nsBuiltinDecoder();
   ~nsBuiltinDecoder();
-
+  
   virtual bool Init(nsHTMLMediaElement* aElement);
 
   // This method must be called by the owning object before that
   // object disposes of this decoder object.
   virtual void Shutdown();
-
+  
   virtual double GetCurrentTime();
 
   virtual nsresult Load(MediaResource* aResource,
                         nsIStreamListener** aListener,
                         nsMediaDecoder* aCloneDonor);
 
   // Called in |Load| to open the media resource.
   nsresult OpenResource(MediaResource* aResource,
                         nsIStreamListener** aStreamListener);
 
-  virtual nsBuiltinDecoderStateMachine* CreateStateMachine() = 0;
+  virtual nsDecoderStateMachine* CreateStateMachine() = 0;
 
   // Initialize state machine and schedule it.
   nsresult InitializeStateMachine(nsMediaDecoder* aCloneDonor);
 
   // Start playback of a video. 'Load' must have previously been
   // called.
   virtual nsresult Play();
 
@@ -275,17 +393,17 @@ public:
   // not connected to streams created by captureStreamUntilEnded.
 
   struct DecodedStreamData {
     DecodedStreamData(nsBuiltinDecoder* aDecoder,
                       int64_t aInitialTime, SourceMediaStream* aStream);
     ~DecodedStreamData();
 
     // The following group of fields are protected by the decoder's monitor
-    // and can be read or written on any thread.
+    // and can be read or written on any thread.    
     int64_t mLastAudioPacketTime; // microseconds
     int64_t mLastAudioPacketEndTime; // microseconds
     // Count of audio frames written to the stream
     int64_t mAudioFramesWritten;
     // Saved value of aInitialTime. Timestamp of the first audio and/or
     // video packet written.
     int64_t mInitialTime; // microseconds
     // mNextVideoTime is the end timestamp for the last packet sent to the stream.
@@ -435,31 +553,54 @@ public:
   void AudioAvailable(float* aFrameBuffer, uint32_t aFrameBufferLength, float aTime);
 
   // Called by the state machine to notify the decoder that the duration
   // has changed.
   void DurationChanged();
 
   virtual bool OnStateMachineThread() const;
 
-  virtual bool OnDecodeThread() const;
+  virtual bool OnDecodeThread() const {
+    return mDecoderStateMachine->OnDecodeThread();
+  }
 
   // Returns the monitor for other threads to synchronise access to
   // state.
-  virtual ReentrantMonitor& GetReentrantMonitor();
+  virtual ReentrantMonitor& GetReentrantMonitor() {
+    return mReentrantMonitor.GetReentrantMonitor();
+  }
 
   // Constructs the time ranges representing what segments of the media
   // are buffered and playable.
-  virtual nsresult GetBuffered(nsTimeRanges* aBuffered);
-
-  virtual int64_t VideoQueueMemoryInUse();
+  virtual nsresult GetBuffered(nsTimeRanges* aBuffered) {
+    if (mDecoderStateMachine) {
+      return mDecoderStateMachine->GetBuffered(aBuffered);
+    }
+    return NS_ERROR_FAILURE;
+  }
 
-  virtual int64_t AudioQueueMemoryInUse();
+  virtual int64_t VideoQueueMemoryInUse() {
+    if (mDecoderStateMachine) {
+      return mDecoderStateMachine->VideoQueueMemoryInUse();
+    }
+    return 0;
+  }
 
-  virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
+  virtual int64_t AudioQueueMemoryInUse() {
+    if (mDecoderStateMachine) {
+      return mDecoderStateMachine->AudioQueueMemoryInUse();
+    }
+    return 0;
+  }
+
+  virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) {
+    if (mDecoderStateMachine) {
+      mDecoderStateMachine->NotifyDataArrived(aBuffer, aLength, aOffset);
+    }
+  }
 
   // Sets the length of the framebuffer used in MozAudioAvailable events.
   // The new size must be between 512 and 16384.
   virtual nsresult RequestFrameBufferLength(uint32_t aLength);
 
   // Return the current state. Can be called on any thread. If called from
   // a non-main thread, the decoder monitor must be held.
   PlayState GetState() {
@@ -478,21 +619,25 @@ public:
   // Something has changed that could affect the computed playback rate,
   // so recompute it. The monitor must be held.
   void UpdatePlaybackRate();
 
   // The actual playback rate computation. The monitor must be held.
   double ComputePlaybackRate(bool* aReliable);
 
   // Make the decoder state machine update the playback position. Called by
-  // the reader on the decoder thread (Assertions for this checked by
+  // the reader on the decoder thread (Assertions for this checked by 
   // mDecoderStateMachine). This must be called with the decode monitor
   // held.
-  void UpdatePlaybackPosition(int64_t aTime);
-  /******
+  void UpdatePlaybackPosition(int64_t aTime)
+  {
+    mDecoderStateMachine->UpdatePlaybackPosition(aTime);
+  }
+
+  /****** 
    * The following methods must only be called on the main
    * thread.
    ******/
 
   // Change to a new play state. This updates the mState variable and
   // notifies any thread blocking on this object's monitor of the
   // change. Call on the main thread only.
   void ChangeState(PlayState aState);
@@ -547,20 +692,24 @@ public:
   // position.
   int64_t GetDownloadPosition();
 
   // Updates the approximate byte offset which playback has reached. This is
   // used to calculate the readyState transitions.
   void UpdatePlaybackOffset(int64_t aOffset);
 
   // Provide access to the state machine object
-  nsBuiltinDecoderStateMachine* GetStateMachine();
+  nsDecoderStateMachine* GetStateMachine() { return mDecoderStateMachine; }
+
+  // Return the current decode state. The decoder monitor must be
+  // obtained before calling this.
+  nsDecoderStateMachine::State GetDecodeState() { return mDecoderStateMachine->GetState(); }
 
   // Drop reference to state machine.  Only called during shutdown dance.
-  virtual void ReleaseStateMachine();
+  virtual void ReleaseStateMachine() { mDecoderStateMachine = nullptr; }
 
    // Called when a "MozAudioAvailable" event listener is added to the media
    // element. Called on the main thread.
    virtual void NotifyAudioAvailableListener();
 
   // Notifies the element that decoding has failed.
   virtual void DecodeError();
 
@@ -620,17 +769,17 @@ public:
    * The following member variables can be accessed from any thread.
    ******/
 
   // The state machine object for handling the decoding. It is safe to
   // call methods of this object from other threads. Its internal data
   // is synchronised on a monitor. The lifetime of this object is
   // after mPlayState is LOADING and before mPlayState is SHUTDOWN. It
   // is safe to access it during this period.
-  nsCOMPtr<nsBuiltinDecoderStateMachine> mDecoderStateMachine;
+  nsCOMPtr<nsDecoderStateMachine> mDecoderStateMachine;
 
   // Media data resource.
   nsAutoPtr<MediaResource> mResource;
 
   // |ReentrantMonitor| for detecting when the video play state changes. A call
   // to |Wait| on this monitor will block the thread until the next state
   // change.
   // Using a wrapper class to restrict direct access to the |ReentrantMonitor|
--- a/content/media/nsBuiltinDecoderReader.cpp
+++ b/content/media/nsBuiltinDecoderReader.cpp
@@ -1,17 +1,17 @@
 /* -*- 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 "GonkIOSurfaceImage.h"
+#include "nsBuiltinDecoder.h"
 #include "nsBuiltinDecoderReader.h"
-#include "nsBuiltinDecoder.h"
 #include "nsBuiltinDecoderStateMachine.h"
 #include "VideoUtils.h"
 #include "ImageContainer.h"
 
 #include "mozilla/mozalloc.h"
 #include "mozilla/StandardInteger.h"
 
 using namespace mozilla;
@@ -337,68 +337,37 @@ nsresult nsBuiltinDecoderReader::ResetDe
   nsresult res = NS_OK;
 
   mVideoQueue.Reset();
   mAudioQueue.Reset();
 
   return res;
 }
 
-VideoData* nsBuiltinDecoderReader::DecodeToFirstVideoData()
-{
-  bool eof = false;
-  while (!eof && mVideoQueue.GetSize() == 0) {
-    {
-      ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
-      if (mDecoder->GetStateMachine()->IsShutdown()) {
-        return nullptr;
-      }
-    }
-    bool unused;
-    eof = !DecodeVideoFrame(unused, 0);
-  }
-  VideoData* d = nullptr;
-  return (d = mVideoQueue.PeekFront()) ? d : nullptr;
-}
-
-AudioData* nsBuiltinDecoderReader::DecodeToFirstAudioData()
-{
-  bool eof = false;
-  while (!eof && mAudioQueue.GetSize() == 0) {
-    {
-      ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
-      if (mDecoder->GetStateMachine()->IsShutdown()) {
-        return nullptr;
-      }
-    }
-    eof = !DecodeAudioData();
-  }
-  AudioData* d = nullptr;
-  return (d = mAudioQueue.PeekFront()) ? d : nullptr;
-}
-
 VideoData* nsBuiltinDecoderReader::FindStartTime(int64_t& aOutStartTime)
 {
   NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
                "Should be on state machine or decode thread.");
 
   // Extract the start times of the bitstreams in order to calculate
   // the duration.
   int64_t videoStartTime = INT64_MAX;
   int64_t audioStartTime = INT64_MAX;
   VideoData* videoData = nullptr;
 
   if (HasVideo()) {
-    videoData = DecodeToFirstVideoData();
+    videoData = DecodeToFirstData(&nsBuiltinDecoderReader::DecodeVideoFrame,
+                                  mVideoQueue);
     if (videoData) {
       videoStartTime = videoData->mTime;
     }
   }
   if (HasAudio()) {
-    AudioData* audioData = DecodeToFirstAudioData();
+    AudioData* audioData = DecodeToFirstData(&nsBuiltinDecoderReader::DecodeAudioData,
+                                             mAudioQueue);
     if (audioData) {
       audioStartTime = audioData->mTime;
     }
   }
 
   int64_t startTime = NS_MIN(videoStartTime, audioStartTime);
   if (startTime != INT64_MAX) {
     aOutStartTime = startTime;
@@ -415,17 +384,17 @@ nsresult nsBuiltinDecoderReader::DecodeT
     int64_t startTime = -1;
     nsAutoPtr<VideoData> video;
     while (HasVideo() && !eof) {
       while (mVideoQueue.GetSize() == 0 && !eof) {
         bool skip = false;
         eof = !DecodeVideoFrame(skip, 0);
         {
           ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
-          if (mDecoder->GetStateMachine()->IsShutdown()) {
+          if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
             return NS_ERROR_FAILURE;
           }
         }
       }
       if (mVideoQueue.GetSize() == 0) {
         // Hit end of file, we want to display the last frame of the video.
         if (video) {
           mVideoQueue.PushFront(video.forget());
@@ -442,32 +411,32 @@ nsresult nsBuiltinDecoderReader::DecodeT
         mVideoQueue.PopFront();
       } else {
         video.forget();
         break;
       }
     }
     {
       ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
-      if (mDecoder->GetStateMachine()->IsShutdown()) {
+      if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
         return NS_ERROR_FAILURE;
       }
     }
     LOG(PR_LOG_DEBUG, ("First video frame after decode is %lld", startTime));
   }
 
   if (HasAudio()) {
     // Decode audio forward to the seek target.
     bool eof = false;
     while (HasAudio() && !eof) {
       while (!eof && mAudioQueue.GetSize() == 0) {
         eof = !DecodeAudioData();
         {
           ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
-          if (mDecoder->GetStateMachine()->IsShutdown()) {
+          if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
             return NS_ERROR_FAILURE;
           }
         }
       }
       const AudioData* audio = mAudioQueue.PeekFront();
       if (!audio)
         break;
       CheckedInt64 startFrame = UsecsToFrames(audio->mTime, mInfo.mAudioRate);
--- a/content/media/nsBuiltinDecoderReader.h
+++ b/content/media/nsBuiltinDecoderReader.h
@@ -8,20 +8,16 @@
 
 #include <nsDeque.h>
 #include "nsSize.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "MediaStreamGraph.h"
 #include "SharedBuffer.h"
 #include "ImageLayers.h"
 #include "AudioSampleFormat.h"
-#include "MediaResource.h"
-#include "nsHTMLMediaElement.h"
-
-class nsBuiltinDecoder;
 
 // Stores info relevant to presenting media frames.
 class nsVideoInfo {
 public:
   nsVideoInfo()
     : mAudioRate(44100),
       mAudioChannels(2),
       mDisplay(0,0),
@@ -30,18 +26,18 @@ public:
       mHasVideo(false)
   {}
 
   // Returns true if it's safe to use aPicture as the picture to be
   // extracted inside a frame of size aFrame, and scaled up to and displayed
   // at a size of aDisplay. You should validate the frame, picture, and
   // display regions before using them to display video frames.
   static bool ValidateVideoRegion(const nsIntSize& aFrame,
-                                  const nsIntRect& aPicture,
-                                  const nsIntSize& aDisplay);
+                                    const nsIntRect& aPicture,
+                                    const nsIntSize& aDisplay);
 
   // Sample rate.
   uint32_t mAudioRate;
 
   // Number of audio channels.
   uint32_t mAudioChannels;
 
   // Size in pixels at which the video is rendered. This is after it has
@@ -227,22 +223,22 @@ template <class T> class MediaQueue : pr
    typedef mozilla::ReentrantMonitorAutoEnter ReentrantMonitorAutoEnter;
    typedef mozilla::ReentrantMonitor ReentrantMonitor;
 
    MediaQueue()
      : nsDeque(new MediaQueueDeallocator<T>()),
        mReentrantMonitor("mediaqueue"),
        mEndOfStream(false)
    {}
-
+  
   ~MediaQueue() {
     Reset();
   }
 
-  inline int32_t GetSize() {
+  inline int32_t GetSize() { 
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     return nsDeque::GetSize();
   }
 
   inline void Push(T* aItem) {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     nsDeque::Push(aItem);
   }
@@ -256,22 +252,22 @@ template <class T> class MediaQueue : pr
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     return static_cast<T*>(nsDeque::Pop());
   }
 
   inline T* PopFront() {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     return static_cast<T*>(nsDeque::PopFront());
   }
-
+  
   inline T* Peek() {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     return static_cast<T*>(nsDeque::Peek());
   }
-
+  
   inline T* PeekFront() {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     return static_cast<T*>(nsDeque::PeekFront());
   }
 
   inline void Empty() {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     nsDeque::Empty();
@@ -471,18 +467,47 @@ public:
   virtual MediaQueue<AudioData>& AudioQueue() { return mAudioQueue; }
   virtual MediaQueue<VideoData>& VideoQueue() { return mVideoQueue; }
 
   // Returns a pointer to the decoder.
   nsBuiltinDecoder* GetDecoder() {
     return mDecoder;
   }
 
-  AudioData* DecodeToFirstAudioData();
-  VideoData* DecodeToFirstVideoData();
+  // Reader decode function. Matches DecodeVideoFrame() and
+  // DecodeAudioData().
+  typedef bool (nsBuiltinDecoderReader::*DecodeFn)();
+
+  // Calls aDecodeFn on *this until aQueue has an item, whereupon
+  // we return the first item. Note: Inline defn. for external accessibility.
+  template<class Data>
+  Data* DecodeToFirstData(DecodeFn aDecodeFn,
+                          MediaQueue<Data>& aQueue)
+  {
+    bool eof = false;
+    while (!eof && aQueue.GetSize() == 0) {
+      {
+        ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
+        if (mDecoder->GetDecodeState()
+            == nsDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
+          return nullptr;
+        }
+      }
+      eof = !(this->*aDecodeFn)();
+    }
+    Data* d = nullptr;
+    return (d = aQueue.PeekFront()) ? d : nullptr;
+  }
+
+  // Wrapper so that DecodeVideoFrame(bool&,int64_t) can be called from
+  // DecodeToFirstData().
+  bool DecodeVideoFrame() {
+    bool f = false;
+    return DecodeVideoFrame(f, 0);
+  }
 
   // Sets range for initialization bytes; used by DASH.
   virtual void SetInitByteRange(MediaByteRange &aByteRange) { }
 
   // Sets range for index frame bytes; used by DASH.
   virtual void SetIndexByteRange(MediaByteRange &aByteRange) { }
 
   // Returns list of ranges for index frame start/end offsets. Used by DASH.
--- a/content/media/nsBuiltinDecoderStateMachine.cpp
+++ b/content/media/nsBuiltinDecoderStateMachine.cpp
@@ -1,19 +1,19 @@
 /* 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 "nsBuiltinDecoderStateMachine.h"
 #include <limits>
 #include "nsAudioStream.h"
 #include "nsTArray.h"
 #include "nsBuiltinDecoder.h"
 #include "nsBuiltinDecoderReader.h"
+#include "nsBuiltinDecoderStateMachine.h"
 #include "mozilla/mozalloc.h"
 #include "VideoUtils.h"
 #include "nsTimeRanges.h"
 #include "nsDeque.h"
 #include "AudioSegment.h"
 #include "VideoSegment.h"
 #include "ImageContainer.h"
 
@@ -1210,17 +1210,17 @@ uint32_t nsBuiltinDecoderStateMachine::P
                                       audio->mFrames * aChannels,
                                       (aFrameOffset + frames) * aChannels);
   if (offset != -1) {
     mDecoder->UpdatePlaybackOffset(offset);
   }
   return frames;
 }
 
-nsresult nsBuiltinDecoderStateMachine::Init(nsBuiltinDecoderStateMachine* aCloneDonor)
+nsresult nsBuiltinDecoderStateMachine::Init(nsDecoderStateMachine* aCloneDonor)
 {
   nsBuiltinDecoderReader* cloneReader = nullptr;
   if (aCloneDonor) {
     cloneReader = static_cast<nsBuiltinDecoderStateMachine*>(aCloneDonor)->mReader;
   }
   return mReader->Init(cloneReader);
 }
 
@@ -2608,15 +2608,8 @@ nsIThread* nsBuiltinDecoderStateMachine:
   return StateMachineTracker::Instance().GetGlobalStateMachineThread();
 }
 
 void nsBuiltinDecoderStateMachine::NotifyAudioAvailableListener()
 {
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
   mEventManager.NotifyAudioAvailableListener();
 }
-
-bool nsBuiltinDecoderStateMachine::IsShutdown()
-{
-  mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
-  return GetState() == DECODER_STATE_SHUTDOWN;
-}
-
--- a/content/media/nsBuiltinDecoderStateMachine.h
+++ b/content/media/nsBuiltinDecoderStateMachine.h
@@ -73,140 +73,76 @@ audio data off the queue and plays it wi
 hardware (via nsAudioStream and libsydneyaudio).
 
 */
 #if !defined(nsBuiltinDecoderStateMachine_h__)
 #define nsBuiltinDecoderStateMachine_h__
 
 #include "nsThreadUtils.h"
 #include "nsBuiltinDecoder.h"
+#include "nsBuiltinDecoderReader.h"
 #include "nsAudioAvailableEventManager.h"
 #include "nsHTMLMediaElement.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "nsITimer.h"
 #include "AudioSegment.h"
 #include "VideoSegment.h"
 
-
-class nsBuiltinDecoderReader;
-
 /*
   The state machine class. This manages the decoding and seeking in the
   nsBuiltinDecoderReader on the decode thread, and A/V sync on the shared
   state machine thread, and controls the audio "push" thread.
 
   All internal state is synchronised via the decoder monitor. State changes
   are either propagated by NotifyAll on the monitor (typically when state
   changes need to be propagated to non-state machine threads) or by scheduling
   the state machine to run another cycle on the shared state machine thread.
 
   See nsBuiltinDecoder.h for more details.
 */
-class nsBuiltinDecoderStateMachine : public nsRunnable
+class nsBuiltinDecoderStateMachine : public nsDecoderStateMachine
 {
 public:
   typedef mozilla::ReentrantMonitor ReentrantMonitor;
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
   typedef mozilla::VideoFrameContainer VideoFrameContainer;
   typedef nsBuiltinDecoder::DecodedStreamData DecodedStreamData;
   typedef mozilla::SourceMediaStream SourceMediaStream;
   typedef mozilla::AudioSegment AudioSegment;
   typedef mozilla::VideoSegment VideoSegment;
 
   nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDecoder, nsBuiltinDecoderReader* aReader, bool aRealTime = false);
   ~nsBuiltinDecoderStateMachine();
 
   // nsDecoderStateMachine interface
-  nsresult Init(nsBuiltinDecoderStateMachine* aCloneDonor);
-
-  // Enumeration for the valid decoding states
-  enum State {
-    DECODER_STATE_DECODING_METADATA,
-    DECODER_STATE_DECODING,
-    DECODER_STATE_SEEKING,
-    DECODER_STATE_BUFFERING,
-    DECODER_STATE_COMPLETED,
-    DECODER_STATE_SHUTDOWN
-  };
-
-  State GetState() {
+  virtual nsresult Init(nsDecoderStateMachine* aCloneDonor);
+  State GetState()
+  { 
     mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
-    return mState;
+    return mState; 
+  }
+  virtual void SetVolume(double aVolume);
+  virtual void SetAudioCaptured(bool aCapture);
+  virtual void Shutdown();
+  virtual int64_t GetDuration();
+  virtual void SetDuration(int64_t aDuration);
+  void SetEndTime(int64_t aEndTime);
+  virtual bool OnDecodeThread() const {
+    return IsCurrentThread(mDecodeThread);
   }
 
-  // Set the audio volume. The decoder monitor must be obtained before
-  // calling this.
-  void SetVolume(double aVolume);
-  void SetAudioCaptured(bool aCapture);
-  void Shutdown();
-
-  // Called from the main thread to get the duration. The decoder monitor
-  // must be obtained before calling this. It is in units of microseconds.
-  int64_t GetDuration();
-
-  // Called from the main thread to set the duration of the media resource
-  // if it is able to be obtained via HTTP headers. Called from the
-  // state machine thread to set the duration if it is obtained from the
-  // media metadata. The decoder monitor must be obtained before calling this.
-  // aDuration is in microseconds.
-  void SetDuration(int64_t aDuration);
-
-  // Called while decoding metadata to set the end time of the media
-  // resource. The decoder monitor must be obtained before calling this.
-  // aEndTime is in microseconds.
-  void SetEndTime(int64_t aEndTime);
-
-  // Functions used by assertions to ensure we're calling things
-  // on the appropriate threads.
-  bool OnDecodeThread() const {
-    return IsCurrentThread(mDecodeThread);
-  }
-  bool OnStateMachineThread() const;
-  bool OnAudioThread() const {
-    return IsCurrentThread(mAudioThread);
-  }
-
-  nsHTMLMediaElement::NextFrameStatus GetNextFrameStatus();
-
-  // Cause state transitions. These methods obtain the decoder monitor
-  // to synchronise the change of state, and to notify other threads
-  // that the state has changed.
-  void Play();
-
-  // Seeks to aTime in seconds.
-  void Seek(double aTime);
-
-  // Returns the current playback position in seconds.
-  // Called from the main thread to get the current frame time. The decoder
-  // monitor must be obtained before calling this.
-  double GetCurrentTime() const;
-
-  // Clear the flag indicating that a playback position change event
-  // is currently queued. This is called from the main thread and must
-  // be called with the decode monitor held.
-  void ClearPositionChangeFlag();
-
-  // Called from the main thread to set whether the media resource can
-  // seek into unbuffered ranges. The decoder monitor must be obtained
-  // before calling this.
-  void SetSeekable(bool aSeekable);
-
-  // Update the playback position. This can result in a timeupdate event
-  // and an invalidate of the frame being dispatched asynchronously if
-  // there is no such event currently queued.
-  // Only called on the decoder thread. Must be called with
-  // the decode monitor held.
-  void UpdatePlaybackPosition(int64_t aTime);
-
-  // Causes the state machine to switch to buffering state, and to
-  // immediately stop playback and buffer downloaded data. Must be called
-  // with the decode monitor held. Called on the state machine thread and
-  // the main thread.
-  void StartBuffering();
+  virtual nsHTMLMediaElement::NextFrameStatus GetNextFrameStatus();
+  virtual void Play();
+  virtual void Seek(double aTime);
+  virtual double GetCurrentTime() const;
+  virtual void ClearPositionChangeFlag();
+  virtual void SetSeekable(bool aSeekable);
+  virtual void UpdatePlaybackPosition(int64_t aTime);
+  virtual void StartBuffering();
 
   // State machine thread run function. Defers to RunStateMachine().
   NS_IMETHOD Run();
 
   // This is called on the state machine thread and audio thread.
   // The decoder monitor must be obtained before calling this.
   bool HasAudio() const {
     mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
@@ -222,26 +158,34 @@ public:
 
   // Should be called by main thread.
   bool HaveNextFrameData() const;
 
   // Must be called with the decode monitor held.
   bool IsBuffering() const {
     mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
 
-    return mState == DECODER_STATE_BUFFERING;
+    return mState == nsBuiltinDecoderStateMachine::DECODER_STATE_BUFFERING;
   }
 
   // Must be called with the decode monitor held.
   bool IsSeeking() const {
     mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
 
-    return mState == DECODER_STATE_SEEKING;
+    return mState == nsBuiltinDecoderStateMachine::DECODER_STATE_SEEKING;
   }
 
+  // Functions used by assertions to ensure we're calling things
+  // on the appropriate threads.
+  bool OnAudioThread() const {
+    return IsCurrentThread(mAudioThread);
+  }
+
+  bool OnStateMachineThread() const;
+ 
   nsresult GetBuffered(nsTimeRanges* aBuffered);
 
   int64_t VideoQueueMemoryInUse() {
     if (mReader) {
       return mReader->VideoQueueMemoryInUse();
     }
     return 0;
   }
@@ -260,27 +204,26 @@ public:
     return mEndTime;
   }
 
   bool IsSeekable() {
     mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
     return mSeekable;
   }
 
-  // Return true if the media is seekable using only buffered ranges.
   bool IsSeekableInBufferedRanges() {
     if (mReader) {
       return mReader->IsSeekableInBufferedRanges();
     }
     return false;
   }
 
   // Sets the current frame buffer length for the MozAudioAvailable event.
   // Accessed on the main and state machine threads.
-  void SetFrameBufferLength(uint32_t aLength);
+  virtual void SetFrameBufferLength(uint32_t aLength);
 
   // Returns the shared state machine thread.
   static nsIThread* GetStateMachineThread();
 
   // Schedules the shared state machine thread to run the state machine.
   // If the state machine thread is the currently running the state machine,
   // we wait until that has completely finished before running the state
   // machine again.
@@ -316,21 +259,17 @@ public:
 
   // Copy queued audio/video data in the reader to any output MediaStreams that
   // need it.
   void SendStreamData();
   void FinishStreamData();
   bool HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs);
   bool HaveEnoughDecodedVideo();
 
-  // Returns true if the state machine has shutdown or is in the process of
-  // shutting down. The decoder monitor must be held while calling this.
-  bool IsShutdown();
-
-private:
+protected:
   class WakeDecoderRunnable : public nsRunnable {
   public:
     WakeDecoderRunnable(nsBuiltinDecoderStateMachine* aSM)
       : mMutex("WakeDecoderRunnable"), mStateMachine(aSM) {}
     NS_IMETHOD Run()
     {
       nsRefPtr<nsBuiltinDecoderStateMachine> stateMachine;
       {
@@ -416,17 +355,17 @@ private:
   // if unknown).  Does not update the playback position on the decoder or
   // media element -- use UpdatePlaybackPosition for that.  Called on the state
   // machine thread, caller must hold the decoder lock.
   void UpdatePlaybackPositionInternal(int64_t aTime);
 
   // Pushes the image down the rendering pipeline. Called on the shared state
   // machine thread. The decoder monitor must *not* be held when calling this.
   void RenderVideoFrame(VideoData* aData, TimeStamp aTarget);
-
+ 
   // If we have video, display a video frame if it's time for display has
   // arrived, otherwise sleep until it's time for the next frame. Update the
   // current frame time as appropriate, and trigger ready state update.  The
   // decoder monitor must be held with exactly one lock count. Called on the
   // state machine thread.
   void AdvanceFrame();
 
   // Write aFrames of audio frames of silence to the audio hardware. Returns
@@ -646,17 +585,17 @@ private:
   // The end time of the last audio frame that's been pushed onto the audio
   // hardware in microseconds. This will approximately be the end time of the
   // audio stream, unless another frame is pushed to the hardware.
   int64_t mAudioEndTime;
 
   // The presentation end time of the last video frame which has been displayed
   // in microseconds. Accessed from the state machine thread.
   int64_t mVideoFrameEndTime;
-
+  
   // Volume of playback. 0.0 = muted. 1.0 = full volume. Read/Written
   // from the state machine and main threads. Synchronised via decoder
   // monitor.
   double mVolume;
 
   // Time at which we started decoding. Synchronised via decoder monitor.
   TimeStamp mDecodeStartTime;
 
@@ -689,17 +628,17 @@ private:
   // playing, or we've moved into shutdown state, and the threads are to be
   // destroyed. Written by the audio playback thread and read and written by
   // the state machine thread. Synchronised via decoder monitor.
   bool mAudioCompleted;
 
   // True if mDuration has a value obtained from an HTTP header, or from
   // the media index/metadata. Accessed on the state machine thread.
   bool mGotDurationFromMetaData;
-
+    
   // False while decode thread should be running. Accessed state machine
   // and decode threads. Syncrhonised by decoder monitor.
   bool mStopDecodeThread;
 
   // True when the decode thread run function has finished, but the thread
   // has not necessarily been shut down yet. This can happen if we switch
   // from COMPLETED state to SEEKING before the state machine has a chance
   // to run in the COMPLETED state and shutdown the decode thread.
@@ -744,17 +683,18 @@ private:
   // previous iteration of DecodeLooop. When we transition from
   // throttled to not-throttled we need to pump decoding.
   bool mDidThrottleAudioDecoding;
   bool mDidThrottleVideoDecoding;
 
   // True if we've requested a new decode thread, but it has not yet been
   // created. Synchronized by the decoder monitor.
   bool mRequestedNewDecodeThread;
-
+  
+private:
   // Manager for queuing and dispatching MozAudioAvailable events.  The
   // event manager is accessed from the state machine and audio threads,
   // and takes care of synchronizing access to its internal queue.
   nsAudioAvailableEventManager mEventManager;
 
   // Stores presentation info required for playback. The decoder monitor
   // must be held when accessing this.
   nsVideoInfo mInfo;
--- a/content/media/ogg/nsOggDecoder.cpp
+++ b/content/media/ogg/nsOggDecoder.cpp
@@ -3,12 +3,12 @@
 /* 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 "nsBuiltinDecoderStateMachine.h"
 #include "nsOggReader.h"
 #include "nsOggDecoder.h"
 
-nsBuiltinDecoderStateMachine* nsOggDecoder::CreateStateMachine()
+nsDecoderStateMachine* nsOggDecoder::CreateStateMachine()
 {
   return new nsBuiltinDecoderStateMachine(this, new nsOggReader(this));
 }
--- a/content/media/ogg/nsOggDecoder.h
+++ b/content/media/ogg/nsOggDecoder.h
@@ -12,12 +12,12 @@ class nsOggDecoder : public nsBuiltinDec
 {
 public:
   virtual nsMediaDecoder* Clone() {
     if (!nsHTMLMediaElement::IsOggEnabled()) {
       return nullptr;
     }
     return new nsOggDecoder();
   }
-  virtual nsBuiltinDecoderStateMachine* CreateStateMachine();
+  virtual nsDecoderStateMachine* CreateStateMachine();
 };
 
 #endif
--- a/content/media/ogg/nsOggReader.cpp
+++ b/content/media/ogg/nsOggReader.cpp
@@ -331,17 +331,17 @@ nsresult nsOggReader::ReadMetadata(nsVid
     }
   }
 
   if (HasAudio() || HasVideo()) {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
 
     MediaResource* resource = mDecoder->GetResource();
     if (mDecoder->GetStateMachine()->GetDuration() == -1 &&
-        !mDecoder->GetStateMachine()->IsShutdown() &&
+        mDecoder->GetStateMachine()->GetState() != nsDecoderStateMachine::DECODER_STATE_SHUTDOWN &&
         resource->GetLength() >= 0 &&
         mDecoder->GetStateMachine()->IsSeekable())
     {
       // We didn't get a duration from the index or a Content-Duration header.
       // Seek to the end of file to find the end time.
       mDecoder->GetResource()->StartSeekingForMetadata();
       int64_t length = resource->GetLength();
 
@@ -1101,17 +1101,17 @@ nsOggReader::IndexedSeekResult nsOggRead
   mCodecStates.Get(serial, &codecState);
   if (codecState &&
       codecState->mActive &&
       ogg_stream_pagein(&codecState->mState, &page) != 0)
   {
     // Couldn't insert page into the ogg resource, or somehow the resource
     // is no longer active.
     return RollbackIndexedSeek(tell);
-  }
+  }      
   mPageOffset = keyframe.mKeyPoint.mOffset + page.header_len + page.body_len;
   return SEEK_OK;
 }
 
 nsresult nsOggReader::SeekInBufferedRange(int64_t aTarget,
                                           int64_t aAdjustedTarget,
                                           int64_t aStartTime,
                                           int64_t aEndTime,
@@ -1131,17 +1131,17 @@ nsresult nsOggReader::SeekInBufferedRang
     // We have an active Theora bitstream. Decode the next Theora frame, and
     // extract its keyframe's time.
     bool eof;
     do {
       bool skip = false;
       eof = !DecodeVideoFrame(skip, 0);
       {
         ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-        if (mDecoder->GetStateMachine()->IsShutdown()) {
+        if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
           return NS_ERROR_FAILURE;
         }
       }
     } while (!eof &&
              mVideoQueue.GetSize() == 0);
 
     VideoData* video = mVideoQueue.PeekFront();
     if (video && !video->mKeyframe) {
--- a/content/media/omx/nsMediaOmxDecoder.cpp
+++ b/content/media/omx/nsMediaOmxDecoder.cpp
@@ -13,16 +13,16 @@ nsMediaOmxDecoder::nsMediaOmxDecoder() :
 {
 }
 
 nsMediaDecoder* nsMediaOmxDecoder::Clone()
 {
   return new nsMediaOmxDecoder();
 }
 
-nsBuiltinDecoderStateMachine* nsMediaOmxDecoder::CreateStateMachine()
+nsDecoderStateMachine* nsMediaOmxDecoder::CreateStateMachine()
 {
   return new nsBuiltinDecoderStateMachine(this, new nsMediaOmxReader(this));
 }
 
 nsMediaOmxDecoder::~nsMediaOmxDecoder()
 {
 }
--- a/content/media/omx/nsMediaOmxDecoder.h
+++ b/content/media/omx/nsMediaOmxDecoder.h
@@ -11,12 +11,12 @@
 
 class nsMediaOmxDecoder : public nsBuiltinDecoder
 {
 public:
   nsMediaOmxDecoder();
   ~nsMediaOmxDecoder();
 
   virtual nsMediaDecoder* Clone();
-  virtual nsBuiltinDecoderStateMachine* CreateStateMachine();
+  virtual nsDecoderStateMachine* CreateStateMachine();
 };
 
 #endif
--- a/content/media/omx/nsMediaOmxReader.cpp
+++ b/content/media/omx/nsMediaOmxReader.cpp
@@ -1,17 +1,16 @@
 /* -*- 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 "nsMediaOmxReader.h"
 
-#include "nsBuiltinDecoderStateMachine.h"
 #include "mozilla/TimeStamp.h"
 #include "nsTimeRanges.h"
 #include "MediaResource.h"
 #include "VideoUtils.h"
 #include "nsMediaOmxDecoder.h"
 
 using namespace android;
 using namespace mozilla;
--- a/content/media/plugins/nsMediaPluginDecoder.cpp
+++ b/content/media/plugins/nsMediaPluginDecoder.cpp
@@ -7,12 +7,12 @@
 #include "nsBuiltinDecoderStateMachine.h"
 #include "nsMediaPluginDecoder.h"
 #include "nsMediaPluginReader.h"
 
 nsMediaPluginDecoder::nsMediaPluginDecoder(const nsACString& aType) : mType(aType)
 {
 }
 
-nsBuiltinDecoderStateMachine* nsMediaPluginDecoder::CreateStateMachine()
+nsDecoderStateMachine* nsMediaPluginDecoder::CreateStateMachine()
 {
   return new nsBuiltinDecoderStateMachine(this, new nsMediaPluginReader(this));
 }
--- a/content/media/plugins/nsMediaPluginDecoder.h
+++ b/content/media/plugins/nsMediaPluginDecoder.h
@@ -16,12 +16,12 @@ public:
   nsMediaPluginDecoder(const nsACString& aType);
 
   const nsresult GetContentType(nsACString& aType) const {
     aType = mType;
     return NS_OK;
   }
 
   virtual nsMediaDecoder* Clone() { return new nsMediaPluginDecoder(mType); }
-  virtual nsBuiltinDecoderStateMachine* CreateStateMachine();
+  virtual nsDecoderStateMachine* CreateStateMachine();
 };
 
 #endif
--- a/content/media/plugins/nsMediaPluginReader.cpp
+++ b/content/media/plugins/nsMediaPluginReader.cpp
@@ -1,21 +1,20 @@
 /* -*- 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 "nsMediaPluginReader.h"
 #include "mozilla/TimeStamp.h"
 #include "nsTimeRanges.h"
 #include "MediaResource.h"
 #include "VideoUtils.h"
+#include "nsMediaPluginReader.h"
 #include "nsMediaPluginDecoder.h"
 #include "nsMediaPluginHost.h"
-#include "nsBuiltinDecoderStateMachine.h"
 
 using namespace mozilla;
 
 nsMediaPluginReader::nsMediaPluginReader(nsBuiltinDecoder *aDecoder) :
   nsBuiltinDecoderReader(aDecoder),
   mPlugin(NULL),
   mHasAudio(false),
   mHasVideo(false),
--- a/content/media/raw/nsRawDecoder.cpp
+++ b/content/media/raw/nsRawDecoder.cpp
@@ -1,12 +1,12 @@
 /* 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 "nsBuiltinDecoderStateMachine.h"
 #include "nsRawReader.h"
 #include "nsRawDecoder.h"
 
-nsBuiltinDecoderStateMachine* nsRawDecoder::CreateStateMachine()
+nsDecoderStateMachine* nsRawDecoder::CreateStateMachine()
 {
   return new nsBuiltinDecoderStateMachine(this, new nsRawReader(this), true);
 }
--- a/content/media/raw/nsRawDecoder.h
+++ b/content/media/raw/nsRawDecoder.h
@@ -11,12 +11,12 @@ class nsRawDecoder : public nsBuiltinDec
 {
 public:
   virtual nsMediaDecoder* Clone() { 
     if (!nsHTMLMediaElement::IsRawEnabled()) {
       return nullptr;
     }    
     return new nsRawDecoder();
   }
-  virtual nsBuiltinDecoderStateMachine* CreateStateMachine();
+  virtual nsDecoderStateMachine* CreateStateMachine();
 };
 
 #endif
--- a/content/media/raw/nsRawReader.cpp
+++ b/content/media/raw/nsRawReader.cpp
@@ -253,17 +253,18 @@ nsresult nsRawReader::Seek(int64_t aTime
     bool keyframeSkip = false;
     if (!DecodeVideoFrame(keyframeSkip, 0)) {
       mCurrentFrame = frame;
       return NS_ERROR_FAILURE;
     }
 
     {
       mozilla::ReentrantMonitorAutoEnter autoMonitor(mDecoder->GetReentrantMonitor());
-      if (mDecoder->GetStateMachine()->IsShutdown()) {
+      if (mDecoder->GetDecodeState() ==
+          nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
         mCurrentFrame = frame;
         return NS_ERROR_FAILURE;
       }
     }
 
     nsAutoPtr<VideoData> video(mVideoQueue.PeekFront());
     if (video && video->mEndTime < aTime) {
       mVideoQueue.PopFront();
--- a/content/media/wave/nsWaveDecoder.cpp
+++ b/content/media/wave/nsWaveDecoder.cpp
@@ -2,12 +2,12 @@
 /* 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 "nsBuiltinDecoderStateMachine.h"
 #include "nsWaveReader.h"
 #include "nsWaveDecoder.h"
 
-nsBuiltinDecoderStateMachine* nsWaveDecoder::CreateStateMachine()
+nsDecoderStateMachine* nsWaveDecoder::CreateStateMachine()
 {
   return new nsBuiltinDecoderStateMachine(this, new nsWaveReader(this));
 }
--- a/content/media/wave/nsWaveDecoder.h
+++ b/content/media/wave/nsWaveDecoder.h
@@ -24,12 +24,12 @@ class nsWaveDecoder : public nsBuiltinDe
 {
 public:
   virtual nsMediaDecoder* Clone() {
     if (!nsHTMLMediaElement::IsWaveEnabled()) {
       return nullptr;
     }
     return new nsWaveDecoder();
   }
-  virtual nsBuiltinDecoderStateMachine* CreateStateMachine();
+  virtual nsDecoderStateMachine* CreateStateMachine();
 };
 
 #endif
--- a/content/media/wave/nsWaveReader.cpp
+++ b/content/media/wave/nsWaveReader.cpp
@@ -3,17 +3,16 @@
 /* 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 "nsError.h"
 #include "nsBuiltinDecoder.h"
 #include "MediaResource.h"
 #include "nsWaveReader.h"
 #include "nsTimeRanges.h"
-#include "nsBuiltinDecoderStateMachine.h"
 #include "VideoUtils.h"
 
 #include "mozilla/StandardInteger.h"
 
 using namespace mozilla;
 
 // Un-comment to enable logging of seek bisections.
 //#define SEEK_LOGGING
--- a/content/media/webm/nsWebMDecoder.cpp
+++ b/content/media/webm/nsWebMDecoder.cpp
@@ -3,12 +3,12 @@
 /* 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 "nsBuiltinDecoderStateMachine.h"
 #include "nsWebMReader.h"
 #include "nsWebMDecoder.h"
 
-nsBuiltinDecoderStateMachine* nsWebMDecoder::CreateStateMachine()
+nsDecoderStateMachine* nsWebMDecoder::CreateStateMachine()
 {
   return new nsBuiltinDecoderStateMachine(this, new nsWebMReader(this));
 }
--- a/content/media/webm/nsWebMDecoder.h
+++ b/content/media/webm/nsWebMDecoder.h
@@ -12,12 +12,12 @@ class nsWebMDecoder : public nsBuiltinDe
 {
 public:
   virtual nsMediaDecoder* Clone() {
     if (!nsHTMLMediaElement::IsWebMEnabled()) {
       return nullptr;
     }
     return new nsWebMDecoder();
   }
-  virtual nsBuiltinDecoderStateMachine* CreateStateMachine();
+  virtual nsDecoderStateMachine* CreateStateMachine();
 };
 
 #endif
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -68,16 +68,21 @@
 #include "nsXULTooltipListener.h"
 
 #include "inDOMView.h"
 #endif
 
 #include "nsHTMLEditor.h"
 #include "nsTextServicesDocument.h"
 
+#ifdef MOZ_MEDIA
+#include "nsMediaDecoder.h"
+#include "nsHTMLMediaElement.h"
+#endif
+
 #ifdef MOZ_MEDIA_PLUGINS
 #include "nsMediaPluginHost.h"
 #endif
 
 #ifdef MOZ_SYDNEYAUDIO
 #include "nsAudioStream.h"
 #endif