Bug 1313632: P1. Remove unused OggReader. r=kaku
authorJean-Yves Avenard <jyavenard@mozilla.com>
Wed, 09 Nov 2016 11:54:41 +1100
changeset 351898 864ab5efde71487c27619d175978818b37c1ac74
parent 351897 8ffd0e45ac580a8d0a85d603e5395297b5f2d9d3
child 351899 87e4efe2210fcf79a4731cf7da59327b011147ef
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskaku
bugs1313632
milestone52.0a1
Bug 1313632: P1. Remove unused OggReader. r=kaku Also remove related preference. MozReview-Commit-ID: D5pkyPXAoG9
dom/media/DecoderTraits.cpp
dom/media/MediaPrefs.h
dom/media/ogg/OggDecoder.cpp
dom/media/ogg/OggReader.cpp
dom/media/ogg/OggReader.h
dom/media/ogg/moz.build
modules/libpref/init/all.js
--- a/dom/media/DecoderTraits.cpp
+++ b/dom/media/DecoderTraits.cpp
@@ -8,17 +8,16 @@
 #include "MediaContentType.h"
 #include "MediaDecoder.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsMimeTypes.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 
 #include "OggDecoder.h"
-#include "OggReader.h"
 #include "OggDemuxer.h"
 
 #include "WebMDecoder.h"
 #include "WebMDemuxer.h"
 
 #ifdef MOZ_ANDROID_OMX
 #include "AndroidMediaDecoder.h"
 #include "AndroidMediaReader.h"
@@ -497,21 +496,18 @@ MediaDecoderReader* DecoderTraits::Creat
   } else
   if (IsWAVSupportedType(aType)) {
     decoderReader = new MediaFormatReader(aDecoder, new WAVDemuxer(aDecoder->GetResource()));
   } else
   if (IsFlacSupportedType(aType)) {
     decoderReader = new MediaFormatReader(aDecoder, new FlacDemuxer(aDecoder->GetResource()));
   } else
   if (IsOggSupportedType(aType)) {
-    decoderReader = MediaPrefs::OggFormatReader() ?
-      static_cast<MediaDecoderReader*>(new MediaFormatReader(aDecoder, new OggDemuxer(aDecoder->GetResource()))) :
-      new OggReader(aDecoder);
-  } else
-  if (IsWaveType(aType)) {
+    decoderReader = new MediaFormatReader(aDecoder, new OggDemuxer(aDecoder->GetResource()));
+  } else if (IsWaveType(aType)) {
     decoderReader = new WaveReader(aDecoder);
   } else
 #ifdef MOZ_ANDROID_OMX
   if (MediaDecoder::IsAndroidMediaPluginEnabled() &&
       EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
     decoderReader = new AndroidMediaReader(aDecoder, aType);
   } else
 #endif
--- a/dom/media/MediaPrefs.h
+++ b/dom/media/MediaPrefs.h
@@ -147,17 +147,16 @@ private:
   DECL_MEDIA_PREF("media.webspeech.recognition.enable",       WebSpeechRecognitionEnabled, bool, false);
   DECL_MEDIA_PREF("media.webspeech.recognition.force_enable", WebSpeechRecognitionForceEnabled, bool, false);
 
   DECL_MEDIA_PREF("media.num-decode-threads",                 MediaThreadPoolDefaultCount, uint32_t, 4);
   DECL_MEDIA_PREF("media.decoder.limit",                      MediaDecoderLimit, int32_t, MediaDecoderLimitDefault());
 
   // Ogg
   DECL_MEDIA_PREF("media.ogg.enabled",                        OggEnabled, bool, true);
-  DECL_MEDIA_PREF("media.format-reader.ogg",                  OggFormatReader, bool, true);
   // Flac
   DECL_MEDIA_PREF("media.ogg.flac.enabled",                   FlacInOgg, bool, false);
   DECL_MEDIA_PREF("media.flac.enabled",                       FlacEnabled, bool, true);
 
 #if defined(MOZ_RUST_MP4PARSE) && !defined(RELEASE_OR_BETA)
   DECL_MEDIA_PREF("media.rust.test_mode",                     RustTestMode, bool, false);
 #endif
 
--- a/dom/media/ogg/OggDecoder.cpp
+++ b/dom/media/ogg/OggDecoder.cpp
@@ -3,34 +3,28 @@
 /* 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 "MediaPrefs.h"
 #include "MediaDecoderStateMachine.h"
 #include "MediaFormatReader.h"
 #include "OggDemuxer.h"
-#include "OggReader.h"
 #include "OggDecoder.h"
 #include "nsContentTypeParser.h"
 
 namespace mozilla {
 
 MediaDecoderStateMachine* OggDecoder::CreateStateMachine()
 {
-  bool useFormatDecoder = MediaPrefs::OggFormatReader();
-  RefPtr<OggDemuxer> demuxer =
-    useFormatDecoder ? new OggDemuxer(GetResource()) : nullptr;
-  RefPtr<MediaDecoderReader> reader = useFormatDecoder
-    ? static_cast<MediaDecoderReader*>(new MediaFormatReader(this, demuxer, GetVideoFrameContainer()))
-    : new OggReader(this);
-  if (useFormatDecoder) {
-    demuxer->SetChainingEvents(&reader->TimedMetadataProducer(),
-                               &reader->MediaNotSeekableProducer());
-  }
+  RefPtr<OggDemuxer> demuxer = new OggDemuxer(GetResource());
+  RefPtr<MediaFormatReader> reader =
+    new MediaFormatReader(this, demuxer, GetVideoFrameContainer());
+  demuxer->SetChainingEvents(&reader->TimedMetadataProducer(),
+                             &reader->MediaNotSeekableProducer());
   return new MediaDecoderStateMachine(this, reader);
 }
 
 /* static */
 bool
 OggDecoder::IsEnabled()
 {
   return MediaPrefs::OggEnabled();
deleted file mode 100644
--- a/dom/media/ogg/OggReader.cpp
+++ /dev/null
@@ -1,2028 +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 "mozilla/DebugOnly.h"
-
-#include "nsError.h"
-#include "MediaDecoderStateMachine.h"
-#include "MediaDecoder.h"
-#include "OggReader.h"
-#include "VideoUtils.h"
-#include "theora/theoradec.h"
-#include <algorithm>
-#include "opus/opus.h"
-extern "C" {
-#include "opus/opus_multistream.h"
-}
-#include "mozilla/TimeStamp.h"
-#include "VorbisUtils.h"
-#include "MediaMetadataManager.h"
-#include "nsAutoPtr.h"
-#include "nsISeekableStream.h"
-#include "gfx2DGlue.h"
-#include "mozilla/Telemetry.h"
-#include "nsPrintfCString.h"
-#include "VideoFrameContainer.h"
-
-using namespace mozilla::gfx;
-using namespace mozilla::media;
-
-namespace mozilla {
-
-// On B2G estimate the buffered ranges rather than calculating them explicitly.
-// This prevents us doing I/O on the main thread, which is prohibited in B2G.
-#ifdef MOZ_WIDGET_GONK
-#define OGG_ESTIMATE_BUFFERED 1
-#endif
-
-// Un-comment to enable logging of seek bisections.
-//#define SEEK_LOGGING
-
-extern LazyLogModule gMediaDecoderLog;
-#define LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg)
-#ifdef SEEK_LOGGING
-#define SEEK_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg)
-#else
-#define SEEK_LOG(type, msg)
-#endif
-
-// The number of microseconds of "fuzz" we use in a bisection search over
-// HTTP. When we're seeking with fuzz, we'll stop the search if a bisection
-// lands between the seek target and SEEK_FUZZ_USECS microseconds before the
-// seek target.  This is becaue it's usually quicker to just keep downloading
-// from an exisiting connection than to do another bisection inside that
-// small range, which would open a new HTTP connetion.
-static const uint32_t SEEK_FUZZ_USECS = 500000;
-
-// The number of microseconds of "pre-roll" we use for Opus streams.
-// The specification recommends 80 ms.
-static const int64_t SEEK_OPUS_PREROLL = 80 * USECS_PER_MS;
-
-enum PageSyncResult {
-  PAGE_SYNC_ERROR = 1,
-  PAGE_SYNC_END_OF_RANGE= 2,
-  PAGE_SYNC_OK = 3
-};
-
-// Reads a page from the media resource.
-static PageSyncResult
-PageSync(MediaResourceIndex* aResource,
-         ogg_sync_state* aState,
-         bool aCachedDataOnly,
-         int64_t aOffset,
-         int64_t aEndOffset,
-         ogg_page* aPage,
-         int& aSkippedBytes);
-
-// Chunk size to read when reading Ogg files. Average Ogg page length
-// is about 4300 bytes, so we read the file in chunks larger than that.
-static const int PAGE_STEP = 8192;
-
-// Return the corresponding category in aKind based on the following specs.
-// (https://www.whatwg.org/specs/web-apps/current-
-// work/multipage/embedded-content.html#dom-audiotrack-kind) &
-// (http://wiki.xiph.org/SkeletonHeaders)
-static const nsString GetKind(const nsCString& aRole)
-{
-  if (aRole.Find("audio/main") != -1 || aRole.Find("video/main") != -1) {
-    return NS_LITERAL_STRING("main");
-  } else if (aRole.Find("audio/alternate") != -1 ||
-             aRole.Find("video/alternate") != -1) {
-    return NS_LITERAL_STRING("alternative");
-  } else if (aRole.Find("audio/audiodesc") != -1) {
-    return NS_LITERAL_STRING("descriptions");
-  } else if (aRole.Find("audio/described") != -1) {
-    return NS_LITERAL_STRING("main-desc");
-  } else if (aRole.Find("audio/dub") != -1) {
-    return NS_LITERAL_STRING("translation");
-  } else if (aRole.Find("audio/commentary") != -1) {
-    return NS_LITERAL_STRING("commentary");
-  } else if (aRole.Find("video/sign") != -1) {
-    return NS_LITERAL_STRING("sign");
-  } else if (aRole.Find("video/captioned") != -1) {
-    return NS_LITERAL_STRING("captions");
-  } else if (aRole.Find("video/subtitled") != -1) {
-    return NS_LITERAL_STRING("subtitles");
-  }
-  return EmptyString();
-}
-
-static void InitTrack(MessageField* aMsgInfo,
-                      TrackInfo* aInfo,
-                      bool aEnable)
-{
-  MOZ_ASSERT(aMsgInfo);
-  MOZ_ASSERT(aInfo);
-
-  nsCString* sName = aMsgInfo->mValuesStore.Get(eName);
-  nsCString* sRole = aMsgInfo->mValuesStore.Get(eRole);
-  nsCString* sTitle = aMsgInfo->mValuesStore.Get(eTitle);
-  nsCString* sLanguage = aMsgInfo->mValuesStore.Get(eLanguage);
-  aInfo->Init(sName? NS_ConvertUTF8toUTF16(*sName):EmptyString(),
-              sRole? GetKind(*sRole):EmptyString(),
-              sTitle? NS_ConvertUTF8toUTF16(*sTitle):EmptyString(),
-              sLanguage? NS_ConvertUTF8toUTF16(*sLanguage):EmptyString(),
-              aEnable);
-}
-
-OggReader::OggReader(AbstractMediaDecoder* aDecoder)
-  : MediaDecoderReader(aDecoder),
-    mMonitor("OggReader"),
-    mTheoraState(nullptr),
-    mVorbisState(nullptr),
-    mOpusState(nullptr),
-    mOpusEnabled(MediaDecoder::IsOpusEnabled()),
-    mSkeletonState(nullptr),
-    mVorbisSerial(0),
-    mOpusSerial(0),
-    mTheoraSerial(0),
-    mOpusPreSkip(0),
-    mIsChained(false),
-    mDecodedAudioFrames(0),
-    mResource(aDecoder->GetResource())
-{
-  MOZ_COUNT_CTOR(OggReader);
-  memset(&mTheoraInfo, 0, sizeof(mTheoraInfo));
-}
-
-OggReader::~OggReader()
-{
-  ogg_sync_clear(&mOggState);
-  MOZ_COUNT_DTOR(OggReader);
-  if (HasAudio() || HasVideo()) {
-    // If we were able to initialize our decoders, report whether we encountered
-    // a chained stream or not.
-    ReentrantMonitorAutoEnter mon(mMonitor);
-    bool isChained = mIsChained;
-    nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction([=]() -> void {
-      LOG(LogLevel::Debug, (nsPrintfCString("Reporting telemetry MEDIA_OGG_LOADED_IS_CHAINED=%d", isChained).get()));
-      Telemetry::Accumulate(Telemetry::ID::MEDIA_OGG_LOADED_IS_CHAINED, isChained);
-    });
-    AbstractThread::MainThread()->Dispatch(task.forget());
-  }
-}
-
-nsresult OggReader::Init() {
-  int ret = ogg_sync_init(&mOggState);
-  NS_ENSURE_TRUE(ret == 0, NS_ERROR_FAILURE);
-  return NS_OK;
-}
-
-nsresult OggReader::ResetDecode(TrackSet aTracks)
-{
-  return ResetDecode(false, aTracks);
-}
-
-nsresult OggReader::ResetDecode(bool start, TrackSet aTracks)
-{
-  MOZ_ASSERT(OnTaskQueue());
-  nsresult res = NS_OK;
-
-  if (NS_FAILED(MediaDecoderReader::ResetDecode(aTracks))) {
-    res = NS_ERROR_FAILURE;
-  }
-
-  // Discard any previously buffered packets/pages.
-  ogg_sync_reset(&mOggState);
-  if (mVorbisState && NS_FAILED(mVorbisState->Reset())) {
-    res = NS_ERROR_FAILURE;
-  }
-  if (mOpusState && NS_FAILED(mOpusState->Reset(start))) {
-    res = NS_ERROR_FAILURE;
-  }
-  if (mTheoraState && NS_FAILED(mTheoraState->Reset())) {
-    res = NS_ERROR_FAILURE;
-  }
-
-  return res;
-}
-
-bool OggReader::ReadHeaders(OggCodecState* aState)
-{
-  while (!aState->DoneReadingHeaders()) {
-    ogg_packet* packet = NextOggPacket(aState);
-    // DecodeHeader is responsible for releasing packet.
-    if (!packet || !aState->DecodeHeader(packet)) {
-      aState->Deactivate();
-      return false;
-    }
-  }
-  return aState->Init();
-}
-
-void OggReader::BuildSerialList(nsTArray<uint32_t>& aTracks)
-{
-  // Obtaining seek index information for currently active bitstreams.
-  if (HasVideo()) {
-    aTracks.AppendElement(mTheoraState->mSerial);
-  }
-  if (HasAudio()) {
-    if (mVorbisState) {
-      aTracks.AppendElement(mVorbisState->mSerial);
-    } else if (mOpusState) {
-      aTracks.AppendElement(mOpusState->mSerial);
-    }
-  }
-}
-
-void OggReader::SetupTargetTheora(TheoraState* aTheoraState)
-{
-  if (mTheoraState) {
-    mTheoraState->Reset();
-  }
-  nsIntRect picture = nsIntRect(aTheoraState->mInfo.pic_x,
-                                aTheoraState->mInfo.pic_y,
-                                aTheoraState->mInfo.pic_width,
-                                aTheoraState->mInfo.pic_height);
-
-  nsIntSize displaySize = nsIntSize(aTheoraState->mInfo.pic_width,
-                                    aTheoraState->mInfo.pic_height);
-
-  // Apply the aspect ratio to produce the intrinsic display size we report
-  // to the element.
-  ScaleDisplayByAspectRatio(displaySize, aTheoraState->mPixelAspectRatio);
-
-  nsIntSize frameSize(aTheoraState->mInfo.frame_width,
-                      aTheoraState->mInfo.frame_height);
-  if (IsValidVideoRegion(frameSize, picture, displaySize)) {
-    // Video track's frame sizes will not overflow. Activate the video track.
-    mPicture = picture;
-
-    VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
-    if (container) {
-      container->ClearCurrentFrame(IntSize(displaySize.width, displaySize.height));
-    }
-
-    // Copy Theora info data for time computations on other threads.
-    memcpy(&mTheoraInfo, &aTheoraState->mInfo, sizeof(mTheoraInfo));
-
-    mTheoraState = aTheoraState;
-    mTheoraSerial = aTheoraState->mSerial;
-  }
-}
-
-void OggReader::SetupTargetVorbis(VorbisState* aVorbisState)
-{
-  if (mVorbisState) {
-    mVorbisState->Reset();
-  }
-  // Copy Vorbis info data for time computations on other threads.
-  memcpy(&mVorbisInfo, &aVorbisState->mInfo, sizeof(mVorbisInfo));
-  mVorbisInfo.codec_setup = nullptr;
-  mVorbisState = aVorbisState;
-  mVorbisSerial = aVorbisState->mSerial;
-}
-
-void OggReader::SetupTargetOpus(OpusState* aOpusState)
-{
-  if (mOpusState) {
-    mOpusState->Reset();
-  }
-  mOpusState = aOpusState;
-  mOpusSerial = aOpusState->mSerial;
-  mOpusPreSkip = aOpusState->mPreSkip;
-}
-
-void OggReader::SetupTargetSkeleton(SkeletonState* aSkeletonState)
-{
-  // Setup skeleton related information after mVorbisState & mTheroState
-  // being set (if they exist).
-  if (aSkeletonState) {
-    if (!HasAudio() && !HasVideo()) {
-      // We have a skeleton track, but no audio or video, may as well disable
-      // the skeleton, we can't do anything useful with this media.
-      aSkeletonState->Deactivate();
-    } else if (ReadHeaders(aSkeletonState) && aSkeletonState->HasIndex()) {
-      // Extract the duration info out of the index, so we don't need to seek to
-      // the end of resource to get it.
-      AutoTArray<uint32_t, 2> tracks;
-      BuildSerialList(tracks);
-      int64_t duration = 0;
-      if (NS_SUCCEEDED(aSkeletonState->GetDuration(tracks, duration))) {
-        LOG(LogLevel::Debug, ("Got duration from Skeleton index %lld", duration));
-        mInfo.mMetadataDuration.emplace(TimeUnit::FromMicroseconds(duration));
-      }
-    }
-  }
-}
-
-void OggReader::SetupMediaTracksInfo(const nsTArray<uint32_t>& aSerials)
-{
-  // For each serial number
-  // 1. Retrieve a codecState from mCodecStore by this serial number.
-  // 2. Retrieve a message field from mMsgFieldStore by this serial number.
-  // 3. For now, skip if the serial number refers to a non-primary bitstream.
-  // 4. Setup track and other audio/video related information per different types.
-  for (size_t i = 0; i < aSerials.Length(); i++) {
-    uint32_t serial = aSerials[i];
-    OggCodecState* codecState = mCodecStore.Get(serial);
-
-    MessageField* msgInfo = nullptr;
-    if (mSkeletonState && mSkeletonState->mMsgFieldStore.Contains(serial)) {
-      mSkeletonState->mMsgFieldStore.Get(serial, &msgInfo);
-    }
-
-    if (codecState->GetType() == OggCodecState::TYPE_THEORA) {
-      TheoraState* theoraState = static_cast<TheoraState*>(codecState);
-      if (!(mTheoraState && mTheoraState->mSerial == theoraState->mSerial)) {
-        continue;
-      }
-
-      if (msgInfo) {
-        InitTrack(msgInfo,
-                  &mInfo.mVideo,
-                  mTheoraState == theoraState);
-      }
-      mInfo.mVideo.mMimeType = NS_LITERAL_CSTRING("video/ogg; codecs=theora");
-
-      nsIntRect picture = nsIntRect(theoraState->mInfo.pic_x,
-                                    theoraState->mInfo.pic_y,
-                                    theoraState->mInfo.pic_width,
-                                    theoraState->mInfo.pic_height);
-      nsIntSize displaySize = nsIntSize(theoraState->mInfo.pic_width,
-                                        theoraState->mInfo.pic_height);
-      nsIntSize frameSize(theoraState->mInfo.frame_width,
-                          theoraState->mInfo.frame_height);
-      ScaleDisplayByAspectRatio(displaySize, theoraState->mPixelAspectRatio);
-      if (IsValidVideoRegion(frameSize, picture, displaySize)) {
-        mInfo.mVideo.mDisplay = displaySize;
-      }
-    } else if (codecState->GetType() == OggCodecState::TYPE_VORBIS) {
-      VorbisState* vorbisState = static_cast<VorbisState*>(codecState);
-      if (!(mVorbisState && mVorbisState->mSerial == vorbisState->mSerial)) {
-        continue;
-      }
-
-      if (msgInfo) {
-        InitTrack(msgInfo,
-                  &mInfo.mAudio,
-                  mVorbisState == vorbisState);
-      }
-      mInfo.mAudio.mMimeType = NS_LITERAL_CSTRING("audio/ogg; codecs=vorbis");
-
-      mInfo.mAudio.mRate = vorbisState->mInfo.rate;
-      mInfo.mAudio.mChannels = vorbisState->mInfo.channels;
-    } else if (codecState->GetType() == OggCodecState::TYPE_OPUS) {
-      OpusState* opusState = static_cast<OpusState*>(codecState);
-      if (!(mOpusState && mOpusState->mSerial == opusState->mSerial)) {
-        continue;
-      }
-
-      if (msgInfo) {
-        InitTrack(msgInfo,
-                  &mInfo.mAudio,
-                  mOpusState == opusState);
-      }
-      mInfo.mAudio.mMimeType = NS_LITERAL_CSTRING("audio/ogg; codecs=opus");
-
-      mInfo.mAudio.mRate = opusState->mRate;
-      mInfo.mAudio.mChannels = opusState->mChannels;
-    }
-  }
-}
-
-nsresult OggReader::ReadMetadata(MediaInfo* aInfo,
-                                 MetadataTags** aTags)
-{
-  MOZ_ASSERT(OnTaskQueue());
-
-  // We read packets until all bitstreams have read all their header packets.
-  // We record the offset of the first non-header page so that we know
-  // what page to seek to when seeking to the media start.
-
-  NS_ASSERTION(aTags, "Called with null MetadataTags**.");
-  *aTags = nullptr;
-
-  ogg_page page;
-  AutoTArray<OggCodecState*,4> bitstreams;
-  nsTArray<uint32_t> serials;
-  bool readAllBOS = false;
-  while (!readAllBOS) {
-    if (!ReadOggPage(&page)) {
-      // Some kind of error...
-      break;
-    }
-
-    int serial = ogg_page_serialno(&page);
-    OggCodecState* codecState = 0;
-
-    if (!ogg_page_bos(&page)) {
-      // We've encountered a non Beginning Of Stream page. No more BOS pages
-      // can follow in this Ogg segment, so there will be no other bitstreams
-      // in the Ogg (unless it's invalid).
-      readAllBOS = true;
-    } else if (!mCodecStore.Contains(serial)) {
-      // We've not encountered a stream with this serial number before. Create
-      // an OggCodecState to demux it, and map that to the OggCodecState
-      // in mCodecStates.
-      codecState = OggCodecState::Create(&page);
-      mCodecStore.Add(serial, codecState);
-      bitstreams.AppendElement(codecState);
-      serials.AppendElement(serial);
-    }
-
-    codecState = mCodecStore.Get(serial);
-    NS_ENSURE_TRUE(codecState != nullptr, NS_ERROR_FAILURE);
-
-    if (NS_FAILED(codecState->PageIn(&page))) {
-      return NS_ERROR_FAILURE;
-    }
-  }
-
-  // We've read all BOS pages, so we know the streams contained in the media.
-  // 1. Process all available header packets in the Theora, Vorbis/Opus bitstreams.
-  // 2. Find the first encountered Theora/Vorbis/Opus bitstream, and configure
-  //    it as the target A/V bitstream.
-  // 3. Deactivate the rest of bitstreams for now, until we have MediaInfo
-  //    support multiple track infos.
-  for (uint32_t i = 0; i < bitstreams.Length(); ++i) {
-    OggCodecState* s = bitstreams[i];
-    if (s) {
-      if (s->GetType() == OggCodecState::TYPE_THEORA && ReadHeaders(s)) {
-        if (!mTheoraState) {
-          TheoraState* theoraState = static_cast<TheoraState*>(s);
-          SetupTargetTheora(theoraState);
-        } else {
-          s->Deactivate();
-        }
-      } else if (s->GetType() == OggCodecState::TYPE_VORBIS && ReadHeaders(s)) {
-        if (!mVorbisState) {
-          VorbisState* vorbisState = static_cast<VorbisState*>(s);
-          SetupTargetVorbis(vorbisState);
-          *aTags = vorbisState->GetTags();
-        } else {
-          s->Deactivate();
-        }
-      } else if (s->GetType() == OggCodecState::TYPE_OPUS && ReadHeaders(s)) {
-        if (mOpusEnabled) {
-          if (!mOpusState) {
-            OpusState* opusState = static_cast<OpusState*>(s);
-            SetupTargetOpus(opusState);
-            *aTags = opusState->GetTags();
-          } else {
-            s->Deactivate();
-          }
-        } else {
-          NS_WARNING("Opus decoding disabled."
-                     " See media.opus.enabled in about:config");
-        }
-      } else if (s->GetType() == OggCodecState::TYPE_SKELETON && !mSkeletonState) {
-        mSkeletonState = static_cast<SkeletonState*>(s);
-      } else {
-        // Deactivate any non-primary bitstreams.
-        s->Deactivate();
-      }
-
-    }
-  }
-
-  SetupTargetSkeleton(mSkeletonState);
-  SetupMediaTracksInfo(serials);
-
-  if (HasAudio() || HasVideo()) {
-    if (mInfo.mMetadataDuration.isNothing() &&
-        !mDecoder->IsOggDecoderShutdown() &&
-        mResource.GetLength() >= 0) {
-      // 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.
-      int64_t length = mResource.GetLength();
-
-      NS_ASSERTION(length > 0, "Must have a content length to get end time");
-
-      int64_t endTime = RangeEndTime(length);
-      if (endTime != -1) {
-        mInfo.mUnadjustedMetadataEndTime.emplace(TimeUnit::FromMicroseconds(endTime));
-        LOG(LogLevel::Debug, ("Got Ogg duration from seeking to end %lld", endTime));
-      }
-    }
-  } else {
-    return NS_ERROR_FAILURE;
-  }
-
-  {
-    ReentrantMonitorAutoEnter mon(mMonitor);
-    mInfo.mMediaSeekable = !mIsChained;
-  }
-
-  *aInfo = mInfo;
-
-  return NS_OK;
-}
-
-nsresult OggReader::DecodeVorbis(ogg_packet* aPacket) {
-  NS_ASSERTION(aPacket->granulepos != -1, "Must know vorbis granulepos!");
-
-  if (vorbis_synthesis(&mVorbisState->mBlock, aPacket) != 0) {
-    return NS_ERROR_FAILURE;
-  }
-  if (vorbis_synthesis_blockin(&mVorbisState->mDsp,
-                               &mVorbisState->mBlock) != 0)
-  {
-    return NS_ERROR_FAILURE;
-  }
-
-  VorbisPCMValue** pcm = 0;
-  int32_t frames = 0;
-  uint32_t channels = mVorbisState->mInfo.channels;
-  ogg_int64_t endFrame = aPacket->granulepos;
-  while ((frames = vorbis_synthesis_pcmout(&mVorbisState->mDsp, &pcm)) > 0) {
-    mVorbisState->ValidateVorbisPacketSamples(aPacket, frames);
-    AlignedAudioBuffer buffer(frames * channels);
-    if (!buffer) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-    for (uint32_t j = 0; j < channels; ++j) {
-      VorbisPCMValue* channel = pcm[j];
-      for (uint32_t i = 0; i < uint32_t(frames); ++i) {
-        buffer[i*channels + j] = MOZ_CONVERT_VORBIS_SAMPLE(channel[i]);
-      }
-    }
-
-    // No channel mapping for more than 8 channels.
-    if (channels > 8) {
-      return NS_ERROR_FAILURE;
-    }
-
-    int64_t duration = mVorbisState->Time((int64_t)frames);
-    int64_t startTime = mVorbisState->Time(endFrame - frames);
-    mAudioQueue.Push(new AudioData(mResource.Tell(),
-                                   startTime,
-                                   duration,
-                                   frames,
-                                   Move(buffer),
-                                   channels,
-                                   mVorbisState->mInfo.rate));
-
-    mDecodedAudioFrames += frames;
-
-    endFrame -= frames;
-    if (vorbis_synthesis_read(&mVorbisState->mDsp, frames) != 0) {
-      return NS_ERROR_FAILURE;
-    }
-  }
-  return NS_OK;
-}
-
-nsresult OggReader::DecodeOpus(ogg_packet* aPacket) {
-  NS_ASSERTION(aPacket->granulepos != -1, "Must know opus granulepos!");
-
-  // Maximum value is 63*2880, so there's no chance of overflow.
-  int32_t frames_number = opus_packet_get_nb_frames(aPacket->packet,
-                                                    aPacket->bytes);
-  if (frames_number <= 0)
-    return NS_ERROR_FAILURE; // Invalid packet header.
-  int32_t samplesPerFrame =
-      opus_packet_get_samples_per_frame(aPacket->packet,
-                                        (opus_int32) mOpusState->mRate);
-  int32_t frames = frames_number * samplesPerFrame;
-
-  // A valid Opus packet must be between 2.5 and 120 ms long.
-  if (frames < 120 || frames > 5760)
-    return NS_ERROR_FAILURE;
-  uint32_t channels = mOpusState->mChannels;
-  AlignedAudioBuffer buffer(frames * channels);
-  if (!buffer) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  // Decode to the appropriate sample type.
-#ifdef MOZ_SAMPLE_TYPE_FLOAT32
-  int ret = opus_multistream_decode_float(mOpusState->mDecoder,
-                                          aPacket->packet, aPacket->bytes,
-                                          buffer.get(), frames, false);
-#else
-  int ret = opus_multistream_decode(mOpusState->mDecoder,
-                                    aPacket->packet, aPacket->bytes,
-                                    buffer.get(), frames, false);
-#endif
-  if (ret < 0)
-    return NS_ERROR_FAILURE;
-  NS_ASSERTION(ret == frames, "Opus decoded too few audio samples");
-
-  int64_t endFrame = aPacket->granulepos;
-  int64_t startFrame;
-  // If this is the last packet, perform end trimming.
-  if (aPacket->e_o_s && mOpusState->mPrevPacketGranulepos != -1) {
-    startFrame = mOpusState->mPrevPacketGranulepos;
-    frames = static_cast<int32_t>(std::max(static_cast<int64_t>(0),
-                                         std::min(endFrame - startFrame,
-                                                static_cast<int64_t>(frames))));
-  } else {
-    startFrame = endFrame - frames;
-  }
-
-  // Trim the initial frames while the decoder is settling.
-  if (mOpusState->mSkip > 0) {
-    int32_t skipFrames = std::min(mOpusState->mSkip, frames);
-    if (skipFrames == frames) {
-      // discard the whole packet
-      mOpusState->mSkip -= frames;
-      LOG(LogLevel::Debug, ("Opus decoder skipping %d frames"
-                         " (whole packet)", frames));
-      return NS_OK;
-    }
-    int32_t keepFrames = frames - skipFrames;
-    int keepSamples = keepFrames * channels;
-    AlignedAudioBuffer trimBuffer(keepSamples);
-    if (!trimBuffer) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-    for (int i = 0; i < keepSamples; i++)
-      trimBuffer[i] = buffer[skipFrames*channels + i];
-
-    startFrame = endFrame - keepFrames;
-    frames = keepFrames;
-    buffer = Move(trimBuffer);
-
-    mOpusState->mSkip -= skipFrames;
-    LOG(LogLevel::Debug, ("Opus decoder skipping %d frames", skipFrames));
-  }
-  // Save this packet's granule position in case we need to perform end
-  // trimming on the next packet.
-  mOpusState->mPrevPacketGranulepos = endFrame;
-
-  // Apply the header gain if one was specified.
-#ifdef MOZ_SAMPLE_TYPE_FLOAT32
-  if (mOpusState->mGain != 1.0f) {
-    float gain = mOpusState->mGain;
-    int gainSamples = frames * channels;
-    for (int i = 0; i < gainSamples; i++) {
-      buffer[i] *= gain;
-    }
-  }
-#else
-  if (mOpusState->mGain_Q16 != 65536) {
-    int64_t gain_Q16 = mOpusState->mGain_Q16;
-    int gainSamples = frames * channels;
-    for (int i = 0; i < gainSamples; i++) {
-      int32_t val = static_cast<int32_t>((gain_Q16*buffer[i] + 32768)>>16);
-      buffer[i] = static_cast<AudioDataValue>(MOZ_CLIP_TO_15(val));
-    }
-  }
-#endif
-
-  // No channel mapping for more than 8 channels.
-  if (channels > 8) {
-    return NS_ERROR_FAILURE;
-  }
-
-  LOG(LogLevel::Debug, ("Opus decoder pushing %d frames", frames));
-  int64_t startTime = mOpusState->Time(startFrame);
-  int64_t endTime = mOpusState->Time(endFrame);
-  mAudioQueue.Push(new AudioData(mResource.Tell(),
-                                 startTime,
-                                 endTime - startTime,
-                                 frames,
-                                 Move(buffer),
-                                 channels,
-                                 mOpusState->mRate));
-
-  mDecodedAudioFrames += frames;
-
-  return NS_OK;
-}
-
-bool OggReader::DecodeAudioData()
-{
-  MOZ_ASSERT(OnTaskQueue());
-  DebugOnly<bool> haveCodecState = mVorbisState != nullptr ||
-                                   mOpusState != nullptr;
-  NS_ASSERTION(haveCodecState, "Need audio codec state to decode audio");
-
-  // Read the next data packet. Skip any non-data packets we encounter.
-  ogg_packet* packet = 0;
-  OggCodecState* codecState;
-  if (mVorbisState)
-    codecState = static_cast<OggCodecState*>(mVorbisState);
-  else
-    codecState = static_cast<OggCodecState*>(mOpusState);
-  do {
-    if (packet) {
-      OggCodecState::ReleasePacket(packet);
-    }
-    packet = NextOggPacket(codecState);
-  } while (packet && codecState->IsHeader(packet));
-
-  if (!packet) {
-    return false;
-  }
-
-  NS_ASSERTION(packet && packet->granulepos != -1,
-    "Must have packet with known granulepos");
-  nsAutoRef<ogg_packet> autoRelease(packet);
-  if (mVorbisState) {
-    DecodeVorbis(packet);
-  } else if (mOpusState) {
-    DecodeOpus(packet);
-  }
-
-  if ((packet->e_o_s) && (!ReadOggChain())) {
-    // We've encountered an end of bitstream packet, or we've hit the end of
-    // file while trying to decode, so inform the audio queue that there'll
-    // be no more samples.
-    return false;
-  }
-
-  return true;
-}
-
-void OggReader::SetChained() {
-  {
-    ReentrantMonitorAutoEnter mon(mMonitor);
-    if (mIsChained) {
-      return;
-    }
-    mIsChained = true;
-  }
-  mOnMediaNotSeekable.Notify();
-}
-
-bool OggReader::ReadOggChain()
-{
-  bool chained = false;
-  OpusState* newOpusState = nullptr;
-  VorbisState* newVorbisState = nullptr;
-  nsAutoPtr<MetadataTags> tags;
-
-  if (HasVideo() || HasSkeleton() || !HasAudio()) {
-    return false;
-  }
-
-  ogg_page page;
-  if (!ReadOggPage(&page) || !ogg_page_bos(&page)) {
-    return false;
-  }
-
-  int serial = ogg_page_serialno(&page);
-  if (mCodecStore.Contains(serial)) {
-    return false;
-  }
-
-  nsAutoPtr<OggCodecState> codecState;
-  codecState = OggCodecState::Create(&page);
-  if (!codecState) {
-    return false;
-  }
-
-  if (mVorbisState && (codecState->GetType() == OggCodecState::TYPE_VORBIS)) {
-    newVorbisState = static_cast<VorbisState*>(codecState.get());
-  }
-  else if (mOpusState && (codecState->GetType() == OggCodecState::TYPE_OPUS)) {
-    newOpusState = static_cast<OpusState*>(codecState.get());
-  }
-  else {
-    return false;
-  }
-  OggCodecState* state;
-
-  mCodecStore.Add(serial, codecState.forget());
-  state = mCodecStore.Get(serial);
-
-  NS_ENSURE_TRUE(state != nullptr, false);
-
-  if (NS_FAILED(state->PageIn(&page))) {
-    return false;
-  }
-
-  MessageField* msgInfo = nullptr;
-  if (mSkeletonState && mSkeletonState->mMsgFieldStore.Contains(serial)) {
-    mSkeletonState->mMsgFieldStore.Get(serial, &msgInfo);
-  }
-
-  if ((newVorbisState && ReadHeaders(newVorbisState)) &&
-      (mVorbisState->mInfo.rate == newVorbisState->mInfo.rate) &&
-      (mVorbisState->mInfo.channels == newVorbisState->mInfo.channels)) {
-
-    SetupTargetVorbis(newVorbisState);
-    LOG(LogLevel::Debug, ("New vorbis ogg link, serial=%d\n", mVorbisSerial));
-
-    if (msgInfo) {
-      InitTrack(msgInfo, &mInfo.mAudio, true);
-    }
-    mInfo.mAudio.mMimeType = NS_LITERAL_CSTRING("audio/ogg; codec=vorbis");
-    mInfo.mAudio.mRate = newVorbisState->mInfo.rate;
-    mInfo.mAudio.mChannels = newVorbisState->mInfo.channels;
-
-    chained = true;
-    tags = newVorbisState->GetTags();
-  }
-
-  if ((newOpusState && ReadHeaders(newOpusState)) &&
-      (mOpusState->mRate == newOpusState->mRate) &&
-      (mOpusState->mChannels == newOpusState->mChannels)) {
-
-    SetupTargetOpus(newOpusState);
-
-    if (msgInfo) {
-      InitTrack(msgInfo, &mInfo.mAudio, true);
-    }
-    mInfo.mAudio.mMimeType = NS_LITERAL_CSTRING("audio/ogg; codec=opus");
-    mInfo.mAudio.mRate = newOpusState->mRate;
-    mInfo.mAudio.mChannels = newOpusState->mChannels;
-
-    chained = true;
-    tags = newOpusState->GetTags();
-  }
-
-  if (chained) {
-    SetChained();
-    {
-      auto t = mDecodedAudioFrames * USECS_PER_S / mInfo.mAudio.mRate;
-      mTimedMetadataEvent.Notify(
-        TimedMetadata(media::TimeUnit::FromMicroseconds(t),
-                      Move(tags),
-                      nsAutoPtr<MediaInfo>(new MediaInfo(mInfo))));
-    }
-    return true;
-  }
-
-  return false;
-}
-
-nsresult OggReader::DecodeTheora(ogg_packet* aPacket, int64_t aTimeThreshold)
-{
-  NS_ASSERTION(aPacket->granulepos >= TheoraVersion(&mTheoraState->mInfo,3,2,1),
-    "Packets must have valid granulepos and packetno");
-
-  int ret = th_decode_packetin(mTheoraState->mCtx, aPacket, 0);
-  if (ret != 0 && ret != TH_DUPFRAME) {
-    return NS_ERROR_FAILURE;
-  }
-  int64_t time = mTheoraState->StartTime(aPacket->granulepos);
-
-  // Don't use the frame if it's outside the bounds of the presentation
-  // start time in the skeleton track. Note we still must submit the frame
-  // to the decoder (via th_decode_packetin), as the frames which are
-  // presentable may depend on this frame's data.
-  if (mSkeletonState && !mSkeletonState->IsPresentable(time)) {
-    return NS_OK;
-  }
-
-  int64_t endTime = mTheoraState->Time(aPacket->granulepos);
-  if (endTime < aTimeThreshold) {
-    // The end time of this frame is already before the current playback
-    // position. It will never be displayed, don't bother enqueing it.
-    return NS_OK;
-  }
-
-  th_ycbcr_buffer buffer;
-  ret = th_decode_ycbcr_out(mTheoraState->mCtx, buffer);
-  NS_ASSERTION(ret == 0, "th_decode_ycbcr_out failed");
-  bool isKeyframe = th_packet_iskeyframe(aPacket) == 1;
-  VideoData::YCbCrBuffer b;
-  for (uint32_t i=0; i < 3; ++i) {
-    b.mPlanes[i].mData = buffer[i].data;
-    b.mPlanes[i].mHeight = buffer[i].height;
-    b.mPlanes[i].mWidth = buffer[i].width;
-    b.mPlanes[i].mStride = buffer[i].stride;
-    b.mPlanes[i].mOffset = b.mPlanes[i].mSkip = 0;
-  }
-
-  RefPtr<VideoData> v =
-    VideoData::CreateAndCopyData(mInfo.mVideo,
-                                 mDecoder->GetImageContainer(),
-                                 mResource.Tell(),
-                                 time,
-                                 endTime - time,
-                                 b,
-                                 isKeyframe,
-                                 aPacket->granulepos,
-                                 mPicture);
-  if (!v) {
-    // There may be other reasons for this error, but for
-    // simplicity just assume the worst case: out of memory.
-    NS_WARNING("Failed to allocate memory for video frame");
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  mVideoQueue.Push(v);
-  return NS_OK;
-}
-
-bool OggReader::DecodeVideoFrame(bool &aKeyframeSkip,
-                                 int64_t aTimeThreshold)
-{
-  MOZ_ASSERT(OnTaskQueue());
-
-  // Record number of frames decoded and parsed. Automatically update the
-  // stats counters using the AutoNotifyDecoded stack-based class.
-  AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
-
-  // Read the next data packet. Skip any non-data packets we encounter.
-  ogg_packet* packet = 0;
-  do {
-    if (packet) {
-      OggCodecState::ReleasePacket(packet);
-    }
-    packet = NextOggPacket(mTheoraState);
-  } while (packet && mTheoraState->IsHeader(packet));
-  if (!packet) {
-    return false;
-  }
-  nsAutoRef<ogg_packet> autoRelease(packet);
-
-  a.mStats.mParsedFrames++;
-  NS_ASSERTION(packet && packet->granulepos != -1,
-                "Must know first packet's granulepos");
-  bool eos = packet->e_o_s;
-  int64_t frameEndTime = mTheoraState->Time(packet->granulepos);
-  if (!aKeyframeSkip ||
-     (th_packet_iskeyframe(packet) && frameEndTime >= aTimeThreshold))
-  {
-    aKeyframeSkip = false;
-    nsresult res = DecodeTheora(packet, aTimeThreshold);
-    a.mStats.mDecodedFrames++;
-    if (NS_FAILED(res)) {
-      return false;
-    }
-  }
-
-  if (eos) {
-    // We've encountered an end of bitstream packet. Inform the queue that
-    // there will be no more frames.
-    return false;
-  }
-
-  return true;
-}
-
-bool OggReader::ReadOggPage(ogg_page* aPage)
-{
-  MOZ_ASSERT(OnTaskQueue());
-
-  int ret = 0;
-  while((ret = ogg_sync_pageseek(&mOggState, aPage)) <= 0) {
-    if (ret < 0) {
-      // Lost page sync, have to skip up to next page.
-      continue;
-    }
-    // Returns a buffer that can be written too
-    // with the given size. This buffer is stored
-    // in the ogg synchronisation structure.
-    char* buffer = ogg_sync_buffer(&mOggState, 4096);
-    NS_ASSERTION(buffer, "ogg_sync_buffer failed");
-
-    // Read from the resource into the buffer
-    uint32_t bytesRead = 0;
-
-    nsresult rv = mResource.Read(buffer, 4096, &bytesRead);
-    if (NS_FAILED(rv) || !bytesRead) {
-      // End of file or error.
-      return false;
-    }
-
-    // Update the synchronisation layer with the number
-    // of bytes written to the buffer
-    ret = ogg_sync_wrote(&mOggState, bytesRead);
-    NS_ENSURE_TRUE(ret == 0, false);
-  }
-
-  return true;
-}
-
-ogg_packet* OggReader::NextOggPacket(OggCodecState* aCodecState)
-{
-  MOZ_ASSERT(OnTaskQueue());
-
-  if (!aCodecState || !aCodecState->mActive) {
-    return nullptr;
-  }
-
-  ogg_packet* packet;
-  while ((packet = aCodecState->PacketOut()) == nullptr) {
-    // The codec state does not have any buffered pages, so try to read another
-    // page from the channel.
-    ogg_page page;
-    if (!ReadOggPage(&page)) {
-      return nullptr;
-    }
-
-    uint32_t serial = ogg_page_serialno(&page);
-    OggCodecState* codecState = nullptr;
-    codecState = mCodecStore.Get(serial);
-    if (codecState && NS_FAILED(codecState->PageIn(&page))) {
-      return nullptr;
-    }
-  }
-
-  return packet;
-}
-
-// Returns an ogg page's checksum.
-static ogg_uint32_t
-GetChecksum(ogg_page* page)
-{
-  if (page == 0 || page->header == 0 || page->header_len < 25) {
-    return 0;
-  }
-  const unsigned char* p = page->header + 22;
-  uint32_t c =  p[0] +
-               (p[1] << 8) +
-               (p[2] << 16) +
-               (p[3] << 24);
-  return c;
-}
-
-int64_t OggReader::RangeStartTime(int64_t aOffset)
-{
-  MOZ_ASSERT(OnTaskQueue());
-  nsresult res = mResource.Seek(nsISeekableStream::NS_SEEK_SET, aOffset);
-  NS_ENSURE_SUCCESS(res, 0);
-  int64_t startTime = 0;
-  FindStartTime(startTime);
-  return startTime;
-}
-
-struct nsAutoOggSyncState {
-  nsAutoOggSyncState() {
-    ogg_sync_init(&mState);
-  }
-  ~nsAutoOggSyncState() {
-    ogg_sync_clear(&mState);
-  }
-  ogg_sync_state mState;
-};
-
-int64_t OggReader::RangeEndTime(int64_t aEndOffset)
-{
-  MOZ_ASSERT(OnTaskQueue());
-
-  int64_t position = mResource.Tell();
-  int64_t endTime = RangeEndTime(0, aEndOffset, false);
-  nsresult res = mResource.Seek(nsISeekableStream::NS_SEEK_SET, position);
-  NS_ENSURE_SUCCESS(res, -1);
-  return endTime;
-}
-
-int64_t OggReader::RangeEndTime(int64_t aStartOffset,
-                                  int64_t aEndOffset,
-                                  bool aCachedDataOnly)
-{
-  nsAutoOggSyncState sync;
-
-  // We need to find the last page which ends before aEndOffset that
-  // has a granulepos that we can convert to a timestamp. We do this by
-  // backing off from aEndOffset until we encounter a page on which we can
-  // interpret the granulepos. If while backing off we encounter a page which
-  // we've previously encountered before, we'll either backoff again if we
-  // haven't found an end time yet, or return the last end time found.
-  const int step = 5000;
-  const int maxOggPageSize = 65306;
-  int64_t readStartOffset = aEndOffset;
-  int64_t readLimitOffset = aEndOffset;
-  int64_t readHead = aEndOffset;
-  int64_t endTime = -1;
-  uint32_t checksumAfterSeek = 0;
-  uint32_t prevChecksumAfterSeek = 0;
-  bool mustBackOff = false;
-  while (true) {
-    ogg_page page;
-    int ret = ogg_sync_pageseek(&sync.mState, &page);
-    if (ret == 0) {
-      // We need more data if we've not encountered a page we've seen before,
-      // or we've read to the end of file.
-      if (mustBackOff || readHead == aEndOffset || readHead == aStartOffset) {
-        if (endTime != -1 || readStartOffset == 0) {
-          // We have encountered a page before, or we're at the end of file.
-          break;
-        }
-        mustBackOff = false;
-        prevChecksumAfterSeek = checksumAfterSeek;
-        checksumAfterSeek = 0;
-        ogg_sync_reset(&sync.mState);
-        readStartOffset = std::max(static_cast<int64_t>(0), readStartOffset - step);
-        // There's no point reading more than the maximum size of
-        // an Ogg page into data we've previously scanned. Any data
-        // between readLimitOffset and aEndOffset must be garbage
-        // and we can ignore it thereafter.
-        readLimitOffset = std::min(readLimitOffset,
-                                 readStartOffset + maxOggPageSize);
-        readHead = std::max(aStartOffset, readStartOffset);
-      }
-
-      int64_t limit = std::min(static_cast<int64_t>(UINT32_MAX),
-                             aEndOffset - readHead);
-      limit = std::max(static_cast<int64_t>(0), limit);
-      limit = std::min(limit, static_cast<int64_t>(step));
-      uint32_t bytesToRead = static_cast<uint32_t>(limit);
-      uint32_t bytesRead = 0;
-      char* buffer = ogg_sync_buffer(&sync.mState, bytesToRead);
-      NS_ASSERTION(buffer, "Must have buffer");
-      nsresult res;
-      if (aCachedDataOnly) {
-        res = mResource.GetResource()->ReadFromCache(buffer, readHead, bytesToRead);
-        NS_ENSURE_SUCCESS(res, -1);
-        bytesRead = bytesToRead;
-      } else {
-        NS_ASSERTION(readHead < aEndOffset,
-                     "resource pos must be before range end");
-        res = mResource.Seek(nsISeekableStream::NS_SEEK_SET, readHead);
-        NS_ENSURE_SUCCESS(res, -1);
-        res = mResource.Read(buffer, bytesToRead, &bytesRead);
-        NS_ENSURE_SUCCESS(res, -1);
-      }
-      readHead += bytesRead;
-      if (readHead > readLimitOffset) {
-        mustBackOff = true;
-      }
-
-      // Update the synchronisation layer with the number
-      // of bytes written to the buffer
-      ret = ogg_sync_wrote(&sync.mState, bytesRead);
-      if (ret != 0) {
-        endTime = -1;
-        break;
-      }
-      continue;
-    }
-
-    if (ret < 0 || ogg_page_granulepos(&page) < 0) {
-      continue;
-    }
-
-    uint32_t checksum = GetChecksum(&page);
-    if (checksumAfterSeek == 0) {
-      // This is the first page we've decoded after a backoff/seek. Remember
-      // the page checksum. If we backoff further and encounter this page
-      // again, we'll know that we won't find a page with an end time after
-      // this one, so we'll know to back off again.
-      checksumAfterSeek = checksum;
-    }
-    if (checksum == prevChecksumAfterSeek) {
-      // This page has the same checksum as the first page we encountered
-      // after the last backoff/seek. Since we've already scanned after this
-      // page and failed to find an end time, we may as well backoff again and
-      // try to find an end time from an earlier page.
-      mustBackOff = true;
-      continue;
-    }
-
-    int64_t granulepos = ogg_page_granulepos(&page);
-    int serial = ogg_page_serialno(&page);
-
-    OggCodecState* codecState = nullptr;
-    codecState = mCodecStore.Get(serial);
-    if (!codecState) {
-      // This page is from a bitstream which we haven't encountered yet.
-      // It's probably from a new "link" in a "chained" ogg. Don't
-      // bother even trying to find a duration...
-      SetChained();
-      endTime = -1;
-      break;
-    }
-
-    int64_t t = codecState->Time(granulepos);
-    if (t != -1) {
-      endTime = t;
-    }
-  }
-
-  return endTime;
-}
-
-nsresult OggReader::GetSeekRanges(nsTArray<SeekRange>& aRanges)
-{
-  MOZ_ASSERT(OnTaskQueue());
-  AutoPinned<MediaResource> resource(mDecoder->GetResource());
-  MediaByteRangeSet cached;
-  nsresult res = resource->GetCachedRanges(cached);
-  NS_ENSURE_SUCCESS(res, res);
-
-  for (uint32_t index = 0; index < cached.Length(); index++) {
-    auto& range = cached[index];
-    int64_t startTime = -1;
-    int64_t endTime = -1;
-    if (NS_FAILED(ResetDecode())) {
-      return NS_ERROR_FAILURE;
-    }
-    int64_t startOffset = range.mStart;
-    int64_t endOffset = range.mEnd;
-    startTime = RangeStartTime(startOffset);
-    if (startTime != -1 &&
-        ((endTime = RangeEndTime(endOffset)) != -1))
-    {
-      NS_WARNING_ASSERTION(startTime < endTime,
-                           "Start time must be before end time");
-      aRanges.AppendElement(SeekRange(startOffset,
-                                      endOffset,
-                                      startTime,
-                                      endTime));
-     }
-  }
-  if (NS_FAILED(ResetDecode())) {
-    return NS_ERROR_FAILURE;
-  }
-  return NS_OK;
-}
-
-OggReader::SeekRange
-OggReader::SelectSeekRange(const nsTArray<SeekRange>& ranges,
-                             int64_t aTarget,
-                             int64_t aStartTime,
-                             int64_t aEndTime,
-                             bool aExact)
-{
-  MOZ_ASSERT(OnTaskQueue());
-  int64_t so = 0;
-  int64_t eo = mResource.GetLength();
-  int64_t st = aStartTime;
-  int64_t et = aEndTime;
-  for (uint32_t i = 0; i < ranges.Length(); i++) {
-    const SeekRange &r = ranges[i];
-    if (r.mTimeStart < aTarget) {
-      so = r.mOffsetStart;
-      st = r.mTimeStart;
-    }
-    if (r.mTimeEnd >= aTarget && r.mTimeEnd < et) {
-      eo = r.mOffsetEnd;
-      et = r.mTimeEnd;
-    }
-
-    if (r.mTimeStart < aTarget && aTarget <= r.mTimeEnd) {
-      // Target lies exactly in this range.
-      return ranges[i];
-    }
-  }
-  if (aExact || eo == -1) {
-    return SeekRange();
-  }
-  return SeekRange(so, eo, st, et);
-}
-
-OggReader::IndexedSeekResult OggReader::RollbackIndexedSeek(int64_t aOffset)
-{
-  if (mSkeletonState) {
-    mSkeletonState->Deactivate();
-  }
-  nsresult res = mResource.Seek(nsISeekableStream::NS_SEEK_SET, aOffset);
-  NS_ENSURE_SUCCESS(res, SEEK_FATAL_ERROR);
-  return SEEK_INDEX_FAIL;
-}
-
-OggReader::IndexedSeekResult OggReader::SeekToKeyframeUsingIndex(int64_t aTarget)
-{
-  if (!HasSkeleton() || !mSkeletonState->HasIndex()) {
-    return SEEK_INDEX_FAIL;
-  }
-  // We have an index from the Skeleton track, try to use it to seek.
-  AutoTArray<uint32_t, 2> tracks;
-  BuildSerialList(tracks);
-  SkeletonState::nsSeekTarget keyframe;
-  if (NS_FAILED(mSkeletonState->IndexedSeekTarget(aTarget,
-                                                  tracks,
-                                                  keyframe)))
-  {
-    // Could not locate a keypoint for the target in the index.
-    return SEEK_INDEX_FAIL;
-  }
-
-  // Remember original resource read cursor position so we can rollback on failure.
-  int64_t tell = mResource.Tell();
-
-  // Seek to the keypoint returned by the index.
-  if (keyframe.mKeyPoint.mOffset > mResource.GetLength() ||
-      keyframe.mKeyPoint.mOffset < 0)
-  {
-    // Index must be invalid.
-    return RollbackIndexedSeek(tell);
-  }
-  LOG(LogLevel::Debug, ("Seeking using index to keyframe at offset %lld\n",
-                     keyframe.mKeyPoint.mOffset));
-  nsresult res = mResource.Seek(nsISeekableStream::NS_SEEK_SET,
-                                keyframe.mKeyPoint.mOffset);
-  NS_ENSURE_SUCCESS(res, SEEK_FATAL_ERROR);
-
-  // We've moved the read set, so reset decode.
-  res = ResetDecode();
-  NS_ENSURE_SUCCESS(res, SEEK_FATAL_ERROR);
-
-  // Check that the page the index thinks is exactly here is actually exactly
-  // here. If not, the index is invalid.
-  ogg_page page;
-  int skippedBytes = 0;
-  PageSyncResult syncres = PageSync(&mResource,
-                                    &mOggState,
-                                    false,
-                                    keyframe.mKeyPoint.mOffset,
-                                    mResource.GetLength(),
-                                    &page,
-                                    skippedBytes);
-  NS_ENSURE_TRUE(syncres != PAGE_SYNC_ERROR, SEEK_FATAL_ERROR);
-  if (syncres != PAGE_SYNC_OK || skippedBytes != 0) {
-    LOG(LogLevel::Debug, ("Indexed-seek failure: Ogg Skeleton Index is invalid "
-                       "or sync error after seek"));
-    return RollbackIndexedSeek(tell);
-  }
-  uint32_t serial = ogg_page_serialno(&page);
-  if (serial != keyframe.mSerial) {
-    // Serialno of page at offset isn't what the index told us to expect.
-    // Assume the index is invalid.
-    return RollbackIndexedSeek(tell);
-  }
-  OggCodecState* codecState = mCodecStore.Get(serial);
-  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);
-  }
-  return SEEK_OK;
-}
-
-nsresult OggReader::SeekInBufferedRange(int64_t aTarget,
-                                          int64_t aAdjustedTarget,
-                                          int64_t aStartTime,
-                                          int64_t aEndTime,
-                                          const nsTArray<SeekRange>& aRanges,
-                                          const SeekRange& aRange)
-{
-  LOG(LogLevel::Debug, ("%p Seeking in buffered data to %lld using bisection search", mDecoder, aTarget));
-  if (HasVideo() || aAdjustedTarget >= aTarget) {
-    // We know the exact byte range in which the target must lie. It must
-    // be buffered in the media cache. Seek there.
-    nsresult res = SeekBisection(aTarget, aRange, 0);
-    if (NS_FAILED(res) || !HasVideo()) {
-      return res;
-    }
-
-    // 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);
-      if (mDecoder->IsOggDecoderShutdown()) {
-        return NS_ERROR_FAILURE;
-      }
-    } while (!eof &&
-             mVideoQueue.GetSize() == 0);
-
-    RefPtr<VideoData> video = mVideoQueue.PeekFront();
-    if (video && !video->mKeyframe) {
-      // First decoded frame isn't a keyframe, seek back to previous keyframe,
-      // otherwise we'll get visual artifacts.
-      NS_ASSERTION(video->mTimecode != -1, "Must have a granulepos");
-      int shift = mTheoraState->mInfo.keyframe_granule_shift;
-      int64_t keyframeGranulepos = (video->mTimecode >> shift) << shift;
-      int64_t keyframeTime = mTheoraState->StartTime(keyframeGranulepos);
-      SEEK_LOG(LogLevel::Debug, ("Keyframe for %lld is at %lld, seeking back to it",
-                              video->mTime, keyframeTime));
-      aAdjustedTarget = std::min(aAdjustedTarget, keyframeTime);
-    }
-  }
-
-  nsresult res = NS_OK;
-  if (aAdjustedTarget < aTarget) {
-    SeekRange k = SelectSeekRange(aRanges,
-                                  aAdjustedTarget,
-                                  aStartTime,
-                                  aEndTime,
-                                  false);
-    res = SeekBisection(aAdjustedTarget, k, SEEK_FUZZ_USECS);
-  }
-  return res;
-}
-
-nsresult OggReader::SeekInUnbuffered(int64_t aTarget,
-                                       int64_t aStartTime,
-                                       int64_t aEndTime,
-                                       const nsTArray<SeekRange>& aRanges)
-{
-  LOG(LogLevel::Debug, ("%p Seeking in unbuffered data to %lld using bisection search", mDecoder, aTarget));
-
-  // If we've got an active Theora bitstream, determine the maximum possible
-  // time in usecs which a keyframe could be before a given interframe. We
-  // subtract this from our seek target, seek to the new target, and then
-  // will decode forward to the original seek target. We should encounter a
-  // keyframe in that interval. This prevents us from needing to run two
-  // bisections; one for the seek target frame, and another to find its
-  // keyframe. It's usually faster to just download this extra data, rather
-  // tham perform two bisections to find the seek target's keyframe. We
-  // don't do this offsetting when seeking in a buffered range,
-  // as the extra decoding causes a noticeable speed hit when all the data
-  // is buffered (compared to just doing a bisection to exactly find the
-  // keyframe).
-  int64_t keyframeOffsetMs = 0;
-  if (HasVideo() && mTheoraState) {
-    keyframeOffsetMs = mTheoraState->MaxKeyframeOffset();
-  }
-  // Add in the Opus pre-roll if necessary, as well.
-  if (HasAudio() && mOpusState) {
-    keyframeOffsetMs = std::max(keyframeOffsetMs, SEEK_OPUS_PREROLL);
-  }
-  int64_t seekTarget = std::max(aStartTime, aTarget - keyframeOffsetMs);
-  // Minimize the bisection search space using the known timestamps from the
-  // buffered ranges.
-  SeekRange k = SelectSeekRange(aRanges, seekTarget, aStartTime, aEndTime, false);
-  return SeekBisection(seekTarget, k, SEEK_FUZZ_USECS);
-}
-
-RefPtr<MediaDecoderReader::SeekPromise>
-OggReader::Seek(SeekTarget aTarget, int64_t aEndTime)
-{
-  nsresult res = SeekInternal(aTarget.GetTime().ToMicroseconds(), aEndTime);
-  if (NS_FAILED(res)) {
-    return SeekPromise::CreateAndReject(res, __func__);
-  } else {
-    return SeekPromise::CreateAndResolve(aTarget.GetTime(), __func__);
-  }
-}
-
-nsresult OggReader::SeekInternal(int64_t aTarget, int64_t aEndTime)
-{
-  MOZ_ASSERT(OnTaskQueue());
-  NS_ENSURE_TRUE(HaveStartTime(), NS_ERROR_FAILURE);
-  if (mIsChained)
-    return NS_ERROR_FAILURE;
-  LOG(LogLevel::Debug, ("%p About to seek to %lld", mDecoder, aTarget));
-  nsresult res;
-  int64_t adjustedTarget = aTarget;
-  if (HasAudio() && mOpusState){
-    adjustedTarget = std::max(StartTime(), aTarget - SEEK_OPUS_PREROLL);
-  }
-
-  if (adjustedTarget == StartTime()) {
-    // We've seeked to the media start. Just seek to the offset of the first
-    // content page.
-    res = mResource.Seek(nsISeekableStream::NS_SEEK_SET, 0);
-    NS_ENSURE_SUCCESS(res,res);
-
-    res = ResetDecode(true);
-    NS_ENSURE_SUCCESS(res,res);
-  } else {
-    // TODO: This may seek back unnecessarily far in the video, but we don't
-    // have a way of asking Skeleton to seek to a different target for each
-    // stream yet. Using adjustedTarget here is at least correct, if slow.
-    IndexedSeekResult sres = SeekToKeyframeUsingIndex(adjustedTarget);
-    NS_ENSURE_TRUE(sres != SEEK_FATAL_ERROR, NS_ERROR_FAILURE);
-    if (sres == SEEK_INDEX_FAIL) {
-      // No index or other non-fatal index-related failure. Try to seek
-      // using a bisection search. Determine the already downloaded data
-      // in the media cache, so we can try to seek in the cached data first.
-      AutoTArray<SeekRange, 16> ranges;
-      res = GetSeekRanges(ranges);
-      NS_ENSURE_SUCCESS(res,res);
-
-      // Figure out if the seek target lies in a buffered range.
-      SeekRange r = SelectSeekRange(ranges, aTarget, StartTime(), aEndTime, true);
-
-      if (!r.IsNull()) {
-        // We know the buffered range in which the seek target lies, do a
-        // bisection search in that buffered range.
-        res = SeekInBufferedRange(aTarget, adjustedTarget, StartTime(), aEndTime, ranges, r);
-        NS_ENSURE_SUCCESS(res,res);
-      } else {
-        // The target doesn't lie in a buffered range. Perform a bisection
-        // search over the whole media, using the known buffered ranges to
-        // reduce the search space.
-        res = SeekInUnbuffered(aTarget, StartTime(), aEndTime, ranges);
-        NS_ENSURE_SUCCESS(res,res);
-      }
-    }
-  }
-
-  if (HasVideo()) {
-    // Decode forwards until we find the next keyframe. This is required,
-    // as although the seek should finish on a page containing a keyframe,
-    // there may be non-keyframes in the page before the keyframe.
-    // When doing fastSeek we display the first frame after the seek, so
-    // we need to advance the decode to the keyframe otherwise we'll get
-    // visual artifacts in the first frame output after the seek.
-    // First, we must check to see if there's already a keyframe in the frames
-    // that we may have already decoded, and discard frames up to the
-    // keyframe.
-    RefPtr<VideoData> v;
-    while ((v = mVideoQueue.PeekFront()) && !v->mKeyframe) {
-      RefPtr<VideoData> releaseMe = mVideoQueue.PopFront();
-    }
-    if (mVideoQueue.GetSize() == 0) {
-      // We didn't find a keyframe in the frames already here, so decode
-      // forwards until we find a keyframe.
-      bool skip = true;
-      while (DecodeVideoFrame(skip, 0) && skip) {
-        if (mDecoder->IsOggDecoderShutdown()) {
-          return NS_ERROR_FAILURE;
-        }
-      }
-    }
-#ifdef DEBUG
-    v = mVideoQueue.PeekFront();
-    if (!v || !v->mKeyframe) {
-      NS_WARNING("Ogg seek didn't end up before a key frame!");
-    }
-#endif
-  }
-  return NS_OK;
-}
-
-// Reads a page from the media resource.
-static PageSyncResult
-PageSync(MediaResourceIndex* aResource,
-         ogg_sync_state* aState,
-         bool aCachedDataOnly,
-         int64_t aOffset,
-         int64_t aEndOffset,
-         ogg_page* aPage,
-         int& aSkippedBytes)
-{
-  aSkippedBytes = 0;
-  // Sync to the next page.
-  int ret = 0;
-  uint32_t bytesRead = 0;
-  int64_t readHead = aOffset;
-  while (ret <= 0) {
-    ret = ogg_sync_pageseek(aState, aPage);
-    if (ret == 0) {
-      char* buffer = ogg_sync_buffer(aState, PAGE_STEP);
-      NS_ASSERTION(buffer, "Must have a buffer");
-
-      // Read from the file into the buffer
-      int64_t bytesToRead = std::min(static_cast<int64_t>(PAGE_STEP),
-                                   aEndOffset - readHead);
-      NS_ASSERTION(bytesToRead <= UINT32_MAX, "bytesToRead range check");
-      if (bytesToRead <= 0) {
-        return PAGE_SYNC_END_OF_RANGE;
-      }
-      nsresult rv = NS_OK;
-      if (aCachedDataOnly) {
-        rv = aResource->GetResource()->ReadFromCache(buffer, readHead,
-                                                     static_cast<uint32_t>(bytesToRead));
-        NS_ENSURE_SUCCESS(rv,PAGE_SYNC_ERROR);
-        bytesRead = static_cast<uint32_t>(bytesToRead);
-      } else {
-        rv = aResource->Seek(nsISeekableStream::NS_SEEK_SET, readHead);
-        NS_ENSURE_SUCCESS(rv,PAGE_SYNC_ERROR);
-        rv = aResource->Read(buffer,
-                             static_cast<uint32_t>(bytesToRead),
-                             &bytesRead);
-        NS_ENSURE_SUCCESS(rv,PAGE_SYNC_ERROR);
-      }
-      if (bytesRead == 0 && NS_SUCCEEDED(rv)) {
-        // End of file.
-        return PAGE_SYNC_END_OF_RANGE;
-      }
-      readHead += bytesRead;
-
-      // Update the synchronisation layer with the number
-      // of bytes written to the buffer
-      ret = ogg_sync_wrote(aState, bytesRead);
-      NS_ENSURE_TRUE(ret == 0, PAGE_SYNC_ERROR);
-      continue;
-    }
-
-    if (ret < 0) {
-      NS_ASSERTION(aSkippedBytes >= 0, "Offset >= 0");
-      aSkippedBytes += -ret;
-      NS_ASSERTION(aSkippedBytes >= 0, "Offset >= 0");
-      continue;
-    }
-  }
-
-  return PAGE_SYNC_OK;
-}
-
-nsresult OggReader::SeekBisection(int64_t aTarget,
-                                    const SeekRange& aRange,
-                                    uint32_t aFuzz)
-{
-  MOZ_ASSERT(OnTaskQueue());
-  nsresult res;
-
-  if (aTarget <= aRange.mTimeStart) {
-    if (NS_FAILED(ResetDecode())) {
-      return NS_ERROR_FAILURE;
-    }
-    res = mResource.Seek(nsISeekableStream::NS_SEEK_SET, 0);
-    NS_ENSURE_SUCCESS(res,res);
-    return NS_OK;
-  }
-
-  // Bisection search, find start offset of last page with end time less than
-  // the seek target.
-  ogg_int64_t startOffset = aRange.mOffsetStart;
-  ogg_int64_t startTime = aRange.mTimeStart;
-  ogg_int64_t startLength = 0; // Length of the page at startOffset.
-  ogg_int64_t endOffset = aRange.mOffsetEnd;
-  ogg_int64_t endTime = aRange.mTimeEnd;
-
-  ogg_int64_t seekTarget = aTarget;
-  int64_t seekLowerBound = std::max(static_cast<int64_t>(0), aTarget - aFuzz);
-  int hops = 0;
-  DebugOnly<ogg_int64_t> previousGuess = -1;
-  int backsteps = 0;
-  const int maxBackStep = 10;
-  NS_ASSERTION(static_cast<uint64_t>(PAGE_STEP) * pow(2.0, maxBackStep) < INT32_MAX,
-               "Backstep calculation must not overflow");
-
-  // Seek via bisection search. Loop until we find the offset where the page
-  // before the offset is before the seek target, and the page after the offset
-  // is after the seek target.
-  while (true) {
-    ogg_int64_t duration = 0;
-    double target = 0;
-    ogg_int64_t interval = 0;
-    ogg_int64_t guess = 0;
-    ogg_page page;
-    int skippedBytes = 0;
-    ogg_int64_t pageOffset = 0;
-    ogg_int64_t pageLength = 0;
-    ogg_int64_t granuleTime = -1;
-    bool mustBackoff = false;
-
-    // Guess where we should bisect to, based on the bit rate and the time
-    // remaining in the interval. Loop until we can determine the time at
-    // the guess offset.
-    while (true) {
-
-      // Discard any previously buffered packets/pages.
-      if (NS_FAILED(ResetDecode())) {
-        return NS_ERROR_FAILURE;
-      }
-
-      interval = endOffset - startOffset - startLength;
-      if (interval == 0) {
-        // Our interval is empty, we've found the optimal seek point, as the
-        // page at the start offset is before the seek target, and the page
-        // at the end offset is after the seek target.
-        SEEK_LOG(LogLevel::Debug, ("Interval narrowed, terminating bisection."));
-        break;
-      }
-
-      // Guess bisection point.
-      duration = endTime - startTime;
-      target = (double)(seekTarget - startTime) / (double)duration;
-      guess = startOffset + startLength +
-              static_cast<ogg_int64_t>((double)interval * target);
-      guess = std::min(guess, endOffset - PAGE_STEP);
-      if (mustBackoff) {
-        // We previously failed to determine the time at the guess offset,
-        // probably because we ran out of data to decode. This usually happens
-        // when we guess very close to the end offset. So reduce the guess
-        // offset using an exponential backoff until we determine the time.
-        SEEK_LOG(LogLevel::Debug, ("Backing off %d bytes, backsteps=%d",
-          static_cast<int32_t>(PAGE_STEP * pow(2.0, backsteps)), backsteps));
-        guess -= PAGE_STEP * static_cast<ogg_int64_t>(pow(2.0, backsteps));
-
-        if (guess <= startOffset) {
-          // We've tried to backoff to before the start offset of our seek
-          // range. This means we couldn't find a seek termination position
-          // near the end of the seek range, so just set the seek termination
-          // condition, and break out of the bisection loop. We'll begin
-          // decoding from the start of the seek range.
-          interval = 0;
-          break;
-        }
-
-        backsteps = std::min(backsteps + 1, maxBackStep);
-        // We reset mustBackoff. If we still need to backoff further, it will
-        // be set to true again.
-        mustBackoff = false;
-      } else {
-        backsteps = 0;
-      }
-      guess = std::max(guess, startOffset + startLength);
-
-      SEEK_LOG(LogLevel::Debug, ("Seek loop start[o=%lld..%lld t=%lld] "
-                              "end[o=%lld t=%lld] "
-                              "interval=%lld target=%lf guess=%lld",
-                              startOffset, (startOffset+startLength), startTime,
-                              endOffset, endTime, interval, target, guess));
-
-      NS_ASSERTION(guess >= startOffset + startLength, "Guess must be after range start");
-      NS_ASSERTION(guess < endOffset, "Guess must be before range end");
-      NS_ASSERTION(guess != previousGuess, "Guess should be different to previous");
-      previousGuess = guess;
-
-      hops++;
-
-      // Locate the next page after our seek guess, and then figure out the
-      // granule time of the audio and video bitstreams there. We can then
-      // make a bisection decision based on our location in the media.
-      PageSyncResult pageSyncResult = PageSync(&mResource,
-                                               &mOggState,
-                                               false,
-                                               guess,
-                                               endOffset,
-                                               &page,
-                                               skippedBytes);
-      NS_ENSURE_TRUE(pageSyncResult != PAGE_SYNC_ERROR, NS_ERROR_FAILURE);
-
-      if (pageSyncResult == PAGE_SYNC_END_OF_RANGE) {
-        // Our guess was too close to the end, we've ended up reading the end
-        // page. Backoff exponentially from the end point, in case the last
-        // page/frame/sample is huge.
-        mustBackoff = true;
-        SEEK_LOG(LogLevel::Debug, ("Hit the end of range, backing off"));
-        continue;
-      }
-
-      // We've located a page of length |ret| at |guess + skippedBytes|.
-      // Remember where the page is located.
-      pageOffset = guess + skippedBytes;
-      pageLength = page.header_len + page.body_len;
-
-      // Read pages until we can determine the granule time of the audio and
-      // video bitstream.
-      ogg_int64_t audioTime = -1;
-      ogg_int64_t videoTime = -1;
-      do {
-        // Add the page to its codec state, determine its granule time.
-        uint32_t serial = ogg_page_serialno(&page);
-        OggCodecState* codecState = mCodecStore.Get(serial);
-        if (codecState && codecState->mActive) {
-          int ret = ogg_stream_pagein(&codecState->mState, &page);
-          NS_ENSURE_TRUE(ret == 0, NS_ERROR_FAILURE);
-        }
-
-        ogg_int64_t granulepos = ogg_page_granulepos(&page);
-
-        if (HasAudio() && granulepos > 0 && audioTime == -1) {
-          if (mVorbisState && serial == mVorbisState->mSerial) {
-            audioTime = mVorbisState->Time(granulepos);
-          } else if (mOpusState && serial == mOpusState->mSerial) {
-            audioTime = mOpusState->Time(granulepos);
-          }
-        }
-
-        if (HasVideo() &&
-            granulepos > 0 &&
-            serial == mTheoraState->mSerial &&
-            videoTime == -1) {
-          videoTime = mTheoraState->Time(granulepos);
-        }
-
-        if (pageOffset + pageLength >= endOffset) {
-          // Hit end of readable data.
-          break;
-        }
-
-        if (!ReadOggPage(&page)) {
-          break;
-        }
-
-      } while ((HasAudio() && audioTime == -1) ||
-               (HasVideo() && videoTime == -1));
-
-
-      if ((HasAudio() && audioTime == -1) ||
-          (HasVideo() && videoTime == -1))
-      {
-        // We don't have timestamps for all active tracks...
-        if (pageOffset == startOffset + startLength &&
-            pageOffset + pageLength >= endOffset) {
-          // We read the entire interval without finding timestamps for all
-          // active tracks. We know the interval start offset is before the seek
-          // target, and the interval end is after the seek target, and we can't
-          // terminate inside the interval, so we terminate the seek at the
-          // start of the interval.
-          interval = 0;
-          break;
-        }
-
-        // We should backoff; cause the guess to back off from the end, so
-        // that we've got more room to capture.
-        mustBackoff = true;
-        continue;
-      }
-
-      // We've found appropriate time stamps here. Proceed to bisect
-      // the search space.
-      granuleTime = std::max(audioTime, videoTime);
-      NS_ASSERTION(granuleTime > 0, "Must get a granuletime");
-      break;
-    } // End of "until we determine time at guess offset" loop.
-
-    if (interval == 0) {
-      // Seek termination condition; we've found the page boundary of the
-      // last page before the target, and the first page after the target.
-      SEEK_LOG(LogLevel::Debug, ("Terminating seek at offset=%lld", startOffset));
-      NS_ASSERTION(startTime < aTarget, "Start time must always be less than target");
-      res = mResource.Seek(nsISeekableStream::NS_SEEK_SET, startOffset);
-      NS_ENSURE_SUCCESS(res,res);
-      if (NS_FAILED(ResetDecode())) {
-        return NS_ERROR_FAILURE;
-      }
-      break;
-    }
-
-    SEEK_LOG(LogLevel::Debug, ("Time at offset %lld is %lld", guess, granuleTime));
-    if (granuleTime < seekTarget && granuleTime > seekLowerBound) {
-      // We're within the fuzzy region in which we want to terminate the search.
-      res = mResource.Seek(nsISeekableStream::NS_SEEK_SET, pageOffset);
-      NS_ENSURE_SUCCESS(res,res);
-      if (NS_FAILED(ResetDecode())) {
-        return NS_ERROR_FAILURE;
-      }
-      SEEK_LOG(LogLevel::Debug, ("Terminating seek at offset=%lld", pageOffset));
-      break;
-    }
-
-    if (granuleTime >= seekTarget) {
-      // We've landed after the seek target.
-      NS_ASSERTION(pageOffset < endOffset, "offset_end must decrease");
-      endOffset = pageOffset;
-      endTime = granuleTime;
-    } else if (granuleTime < seekTarget) {
-      // Landed before seek target.
-      NS_ASSERTION(pageOffset >= startOffset + startLength,
-        "Bisection point should be at or after end of first page in interval");
-      startOffset = pageOffset;
-      startLength = pageLength;
-      startTime = granuleTime;
-    }
-    NS_ASSERTION(startTime < seekTarget, "Must be before seek target");
-    NS_ASSERTION(endTime >= seekTarget, "End must be after seek target");
-  }
-
-  SEEK_LOG(LogLevel::Debug, ("Seek complete in %d bisections.", hops));
-
-  return NS_OK;
-}
-
-media::TimeIntervals OggReader::GetBuffered()
-{
-  MOZ_ASSERT(OnTaskQueue());
-  if (!HaveStartTime()) {
-    return media::TimeIntervals();
-  }
-  {
-    mozilla::ReentrantMonitorAutoEnter mon(mMonitor);
-    if (mIsChained) {
-      return media::TimeIntervals::Invalid();
-    }
-  }
-#ifdef OGG_ESTIMATE_BUFFERED
-  return MediaDecoderReader::GetBuffered();
-#else
-  media::TimeIntervals buffered;
-  // HasAudio and HasVideo are not used here as they take a lock and cause
-  // a deadlock. Accessing mInfo doesn't require a lock - it doesn't change
-  // after metadata is read.
-  if (!mInfo.HasValidMedia()) {
-    // No need to search through the file if there are no audio or video tracks
-    return buffered;
-  }
-
-  AutoPinned<MediaResource> resource(mDecoder->GetResource());
-  MediaByteRangeSet ranges;
-  nsresult res = resource->GetCachedRanges(ranges);
-  NS_ENSURE_SUCCESS(res, media::TimeIntervals::Invalid());
-
-  // Traverse across the buffered byte ranges, determining the time ranges
-  // they contain. MediaResource::GetNextCachedData(offset) returns -1 when
-  // offset is after the end of the media resource, or there's no more cached
-  // data after the offset. This loop will run until we've checked every
-  // buffered range in the media, in increasing order of offset.
-  nsAutoOggSyncState sync;
-  for (uint32_t index = 0; index < ranges.Length(); index++) {
-    // Ensure the offsets are after the header pages.
-    int64_t startOffset = ranges[index].mStart;
-    int64_t endOffset = ranges[index].mEnd;
-
-    // Because the granulepos time is actually the end time of the page,
-    // we special-case (startOffset == 0) so that the first
-    // buffered range always appears to be buffered from the media start
-    // time, rather than from the end-time of the first page.
-    int64_t startTime = (startOffset == 0) ? StartTime() : -1;
-
-    // Find the start time of the range. Read pages until we find one with a
-    // granulepos which we can convert into a timestamp to use as the time of
-    // the start of the buffered range.
-    ogg_sync_reset(&sync.mState);
-    while (startTime == -1) {
-      ogg_page page;
-      int32_t discard;
-      PageSyncResult pageSyncResult = PageSync(&mResource,
-                                               &sync.mState,
-                                               true,
-                                               startOffset,
-                                               endOffset,
-                                               &page,
-                                               discard);
-      if (pageSyncResult == PAGE_SYNC_ERROR) {
-        return media::TimeIntervals::Invalid();
-      } else if (pageSyncResult == PAGE_SYNC_END_OF_RANGE) {
-        // Hit the end of range without reading a page, give up trying to
-        // find a start time for this buffered range, skip onto the next one.
-        break;
-      }
-
-      int64_t granulepos = ogg_page_granulepos(&page);
-      if (granulepos == -1) {
-        // Page doesn't have an end time, advance to the next page
-        // until we find one.
-        startOffset += page.header_len + page.body_len;
-        continue;
-      }
-
-      uint32_t serial = ogg_page_serialno(&page);
-      if (mVorbisState && serial == mVorbisSerial) {
-        startTime = VorbisState::Time(&mVorbisInfo, granulepos);
-        NS_ASSERTION(startTime > 0, "Must have positive start time");
-      }
-      else if (mOpusState && serial == mOpusSerial) {
-        startTime = OpusState::Time(mOpusPreSkip, granulepos);
-        NS_ASSERTION(startTime > 0, "Must have positive start time");
-      }
-      else if (mTheoraState && serial == mTheoraSerial) {
-        startTime = TheoraState::Time(&mTheoraInfo, granulepos);
-        NS_ASSERTION(startTime > 0, "Must have positive start time");
-      }
-      else if (mCodecStore.Contains(serial)) {
-        // Stream is not the theora or vorbis stream we're playing,
-        // but is one that we have header data for.
-        startOffset += page.header_len + page.body_len;
-        continue;
-      }
-      else {
-        // Page is for a stream we don't know about (possibly a chained
-        // ogg), return OK to abort the finding any further ranges. This
-        // prevents us searching through the rest of the media when we
-        // may not be able to extract timestamps from it.
-        SetChained();
-        return buffered;
-      }
-    }
-
-    if (startTime != -1) {
-      // We were able to find a start time for that range, see if we can
-      // find an end time.
-      int64_t endTime = RangeEndTime(startOffset, endOffset, true);
-      if (endTime > startTime) {
-        buffered += media::TimeInterval(
-           media::TimeUnit::FromMicroseconds(startTime - StartTime()),
-           media::TimeUnit::FromMicroseconds(endTime - StartTime()));
-      }
-    }
-  }
-
-  return buffered;
-#endif
-}
-
-void OggReader::FindStartTime(int64_t& aOutStartTime)
-{
-  MOZ_ASSERT(OnTaskQueue());
-
-  // Extract the start times of the bitstreams in order to calculate
-  // the duration.
-  int64_t videoStartTime = INT64_MAX;
-  int64_t audioStartTime = INT64_MAX;
-
-  if (HasVideo()) {
-    RefPtr<VideoData> videoData = SyncDecodeToFirstVideoData();
-    if (videoData) {
-      videoStartTime = videoData->mTime;
-      LOG(LogLevel::Debug, ("OggReader::FindStartTime() video=%lld", videoStartTime));
-    }
-  }
-  if (HasAudio()) {
-    RefPtr<AudioData> audioData = SyncDecodeToFirstAudioData();
-    if (audioData) {
-      audioStartTime = audioData->mTime;
-      LOG(LogLevel::Debug, ("OggReader::FindStartTime() audio=%lld", audioStartTime));
-    }
-  }
-
-  int64_t startTime = std::min(videoStartTime, audioStartTime);
-  if (startTime != INT64_MAX) {
-    aOutStartTime = startTime;
-  }
-}
-
-RefPtr<AudioData> OggReader::SyncDecodeToFirstAudioData()
-{
-  bool eof = false;
-  while (!eof && AudioQueue().GetSize() == 0) {
-    if (mDecoder->IsOggDecoderShutdown()) {
-      return nullptr;
-    }
-    eof = !DecodeAudioData();
-  }
-  if (eof) {
-    AudioQueue().Finish();
-  }
-  return AudioQueue().PeekFront();
-}
-
-RefPtr<VideoData> OggReader::SyncDecodeToFirstVideoData()
-{
-  bool eof = false;
-  while (!eof && VideoQueue().GetSize() == 0) {
-    if (mDecoder->IsOggDecoderShutdown()) {
-      return nullptr;
-    }
-    bool keyframeSkip = false;
-    eof = !DecodeVideoFrame(keyframeSkip, 0);
-  }
-  if (eof) {
-    VideoQueue().Finish();
-  }
-  return VideoQueue().PeekFront();
-}
-
-} // namespace mozilla
deleted file mode 100644
--- a/dom/media/ogg/OggReader.h
+++ /dev/null
@@ -1,306 +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/. */
-#if !defined(OggReader_h_)
-#define OggReader_h_
-
-#include <ogg/ogg.h>
-#include <theora/theoradec.h>
-#ifdef MOZ_TREMOR
-#include <tremor/ivorbiscodec.h>
-#else
-#include <vorbis/codec.h>
-#endif
-#include "MediaDecoderReader.h"
-#include "MediaResource.h"
-#include "OggCodecState.h"
-#include "VideoUtils.h"
-#include "mozilla/Monitor.h"
-#include "OggDecoder.h"
-#include "OggCodecStore.h"
-
-namespace mozilla {
-
-class OggReader final : public MediaDecoderReader
-{
-public:
-  explicit OggReader(AbstractMediaDecoder* aDecoder);
-
-protected:
-  ~OggReader();
-
-public:
-  nsresult Init() override;
-  nsresult ResetDecode(TrackSet aTracks = TrackSet(TrackInfo::kAudioTrack,
-                                                   TrackInfo::kVideoTrack)) override;
-  bool DecodeAudioData() override;
-
-  // If the Theora granulepos has not been captured, it may read several packets
-  // until one with a granulepos has been captured, to ensure that all packets
-  // read have valid time info.
-  bool DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) override;
-
-  nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) override;
-  RefPtr<SeekPromise> Seek(SeekTarget aTarget, int64_t aEndTime) override;
-  media::TimeIntervals GetBuffered() override;
-
-private:
-  bool HasAudio() {
-    return (mVorbisState != 0 && mVorbisState->mActive) ||
-           (mOpusState != 0 && mOpusState->mActive);
-  }
-
-  bool HasVideo() {
-    return mTheoraState != 0 && mTheoraState->mActive;
-  }
-
-  // TODO: DEPRECATED. This uses synchronous decoding.
-  // Stores the presentation time of the first frame we'd be able to play if
-  // we started playback at the current position. Returns the first video
-  // frame, if we have video.
-  void FindStartTime(int64_t& aOutStartTime);
-  RefPtr<AudioData> SyncDecodeToFirstAudioData();
-  RefPtr<VideoData> SyncDecodeToFirstVideoData();
-
-  // This monitor should be taken when reading or writing to mIsChained.
-  ReentrantMonitor mMonitor;
-
-  // Specialized Reset() method to signal if the seek is
-  // to the start of the stream.
-  nsresult ResetDecode(bool start,
-                       TrackSet aTracks = TrackSet(TrackInfo::kAudioTrack,
-                                                   TrackInfo::kVideoTrack));
-
-  nsresult SeekInternal(int64_t aTime, int64_t aEndTime);
-
-  bool HasSkeleton() {
-    return mSkeletonState != 0 && mSkeletonState->mActive;
-  }
-
-  // Seeks to the keyframe preceding the target time using available
-  // keyframe indexes.
-  enum IndexedSeekResult {
-    SEEK_OK,          // Success.
-    SEEK_INDEX_FAIL,  // Failure due to no index, or invalid index.
-    SEEK_FATAL_ERROR  // Error returned by a stream operation.
-  };
-  IndexedSeekResult SeekToKeyframeUsingIndex(int64_t aTarget);
-
-  // Rolls back a seek-using-index attempt, returning a failure error code.
-  IndexedSeekResult RollbackIndexedSeek(int64_t aOffset);
-
-  // Represents a section of contiguous media, with a start and end offset,
-  // and the timestamps of the start and end of that range, that is cached.
-  // Used to denote the extremities of a range in which we can seek quickly
-  // (because it's cached).
-  class SeekRange {
-  public:
-    SeekRange()
-      : mOffsetStart(0),
-        mOffsetEnd(0),
-        mTimeStart(0),
-        mTimeEnd(0)
-    {}
-
-    SeekRange(int64_t aOffsetStart,
-              int64_t aOffsetEnd,
-              int64_t aTimeStart,
-              int64_t aTimeEnd)
-      : mOffsetStart(aOffsetStart),
-        mOffsetEnd(aOffsetEnd),
-        mTimeStart(aTimeStart),
-        mTimeEnd(aTimeEnd)
-    {}
-
-    bool IsNull() const {
-      return mOffsetStart == 0 &&
-             mOffsetEnd == 0 &&
-             mTimeStart == 0 &&
-             mTimeEnd == 0;
-    }
-
-    int64_t mOffsetStart, mOffsetEnd; // in bytes.
-    int64_t mTimeStart, mTimeEnd; // in usecs.
-  };
-
-  // Seeks to aTarget usecs in the buffered range aRange using bisection search,
-  // or to the keyframe prior to aTarget if we have video. aAdjustedTarget is
-  // an adjusted version of the target used to account for Opus pre-roll, if
-  // necessary. aStartTime must be the presentation time at the start of media,
-  // and aEndTime the time at end of media. aRanges must be the time/byte ranges
-  // buffered in the media cache as per GetSeekRanges().
-  nsresult SeekInBufferedRange(int64_t aTarget,
-                               int64_t aAdjustedTarget,
-                               int64_t aStartTime,
-                               int64_t aEndTime,
-                               const nsTArray<SeekRange>& aRanges,
-                               const SeekRange& aRange);
-
-  // Seeks to before aTarget usecs in media using bisection search. If the media
-  // has video, this will seek to before the keyframe required to render the
-  // media at aTarget. Will use aRanges in order to narrow the bisection
-  // search space. aStartTime must be the presentation time at the start of
-  // media, and aEndTime the time at end of media. aRanges must be the time/byte
-  // ranges buffered in the media cache as per GetSeekRanges().
-  nsresult SeekInUnbuffered(int64_t aTarget,
-                            int64_t aStartTime,
-                            int64_t aEndTime,
-                            const nsTArray<SeekRange>& aRanges);
-
-  // Get the end time of aEndOffset. This is the playback position we'd reach
-  // after playback finished at aEndOffset.
-  int64_t RangeEndTime(int64_t aEndOffset);
-
-  // Get the end time of aEndOffset, without reading before aStartOffset.
-  // This is the playback position we'd reach after playback finished at
-  // aEndOffset. If bool aCachedDataOnly is true, then we'll only read
-  // from data which is cached in the media cached, otherwise we'll do
-  // regular blocking reads from the media stream. If bool aCachedDataOnly
-  // is true, this can safely be called on the main thread, otherwise it
-  // must be called on the state machine thread.
-  int64_t RangeEndTime(int64_t aStartOffset,
-                       int64_t aEndOffset,
-                       bool aCachedDataOnly);
-
-  // Get the start time of the range beginning at aOffset. This is the start
-  // time of the first frame and or audio sample we'd be able to play if we
-  // started playback at aOffset.
-  int64_t RangeStartTime(int64_t aOffset);
-
-  // Performs a seek bisection to move the media stream's read cursor to the
-  // last ogg page boundary which has end time before aTarget usecs on both the
-  // Theora and Vorbis bitstreams. Limits its search to data inside aRange;
-  // i.e. it will only read inside of the aRange's start and end offsets.
-  // aFuzz is the number of usecs of leniency we'll allow; we'll terminate the
-  // seek when we land in the range (aTime - aFuzz, aTime) usecs.
-  nsresult SeekBisection(int64_t aTarget,
-                         const SeekRange& aRange,
-                         uint32_t aFuzz);
-
-  // Returns true if the serial number is for a stream we encountered
-  // while reading metadata. Call on the main thread only.
-  bool IsKnownStream(uint32_t aSerial);
-
-  // Fills aRanges with SeekRanges denoting the sections of the media which
-  // have been downloaded and are stored in the media cache. The reader
-  // monitor must must be held with exactly one lock count. The MediaResource
-  // must be pinned while calling this.
-  nsresult GetSeekRanges(nsTArray<SeekRange>& aRanges);
-
-  // Returns the range in which you should perform a seek bisection if
-  // you wish to seek to aTarget usecs, given the known (buffered) byte ranges
-  // in aRanges. If aExact is true, we only return an exact copy of a
-  // range in which aTarget lies, or a null range if aTarget isn't contained
-  // in any of the (buffered) ranges. Otherwise, when aExact is false,
-  // we'll construct the smallest possible range we can, based on the times
-  // and byte offsets known in aRanges. We can then use this to minimize our
-  // bisection's search space when the target isn't in a known buffered range.
-  SeekRange SelectSeekRange(const nsTArray<SeekRange>& aRanges,
-                            int64_t aTarget,
-                            int64_t aStartTime,
-                            int64_t aEndTime,
-                            bool aExact);
-private:
-
-  // Decodes a packet of Vorbis data, and inserts its samples into the
-  // audio queue.
-  nsresult DecodeVorbis(ogg_packet* aPacket);
-
-  // Decodes a packet of Opus data, and inserts its samples into the
-  // audio queue.
-  nsresult DecodeOpus(ogg_packet* aPacket);
-
-  // Decodes a packet of Theora data, and inserts its frame into the
-  // video queue. May return NS_ERROR_OUT_OF_MEMORY. Caller must have obtained
-  // the reader's monitor. aTimeThreshold is the current playback position
-  // in media time in microseconds. Frames with an end time before this will
-  // not be enqueued.
-  nsresult DecodeTheora(ogg_packet* aPacket, int64_t aTimeThreshold);
-
-  // Read a page of data from the Ogg file. Returns true if a page has been
-  // read, false if the page read failed or end of file reached.
-  bool ReadOggPage(ogg_page* aPage);
-
-  // Reads and decodes header packets for aState, until either header decode
-  // fails, or is complete. Initializes the codec state before returning.
-  // Returns true if reading headers and initializtion of the stream
-  // succeeds.
-  bool ReadHeaders(OggCodecState* aState);
-
-  // Reads the next link in the chain.
-  bool ReadOggChain();
-
-  // Set this media as being a chain and notifies the state machine that the
-  // media is no longer seekable.
-  void SetChained();
-
-  // Returns the next Ogg packet for an bitstream/codec state. Returns a
-  // pointer to an ogg_packet on success, or nullptr if the read failed.
-  // The caller is responsible for deleting the packet and its |packet| field.
-  ogg_packet* NextOggPacket(OggCodecState* aCodecState);
-
-  // Fills aTracks with the serial numbers of each active stream, for use by
-  // various SkeletonState functions.
-  void BuildSerialList(nsTArray<uint32_t>& aTracks);
-
-  // Setup target bitstreams for decoding.
-  void SetupTargetTheora(TheoraState* aTheoraState);
-  void SetupTargetVorbis(VorbisState* aVorbisState);
-  void SetupTargetOpus(OpusState* aOpusState);
-  void SetupTargetSkeleton(SkeletonState* aSkeletonState);
-  void SetupMediaTracksInfo(const nsTArray<uint32_t>& aSerials);
-
-  OggCodecStore mCodecStore;
-
-  // Decode state of the Theora bitstream we're decoding, if we have video.
-  TheoraState* mTheoraState;
-
-  // Decode state of the Vorbis bitstream we're decoding, if we have audio.
-  VorbisState* mVorbisState;
-
-  // Decode state of the Opus bitstream we're decoding, if we have one.
-  OpusState *mOpusState;
-
-  // Represents the user pref media.opus.enabled at the time our
-  // contructor was called. We can't check it dynamically because
-  // we're not on the main thread;
-  bool mOpusEnabled;
-
-  // Decode state of the Skeleton bitstream.
-  SkeletonState* mSkeletonState;
-
-  // Ogg decoding state.
-  ogg_sync_state mOggState;
-
-  // Vorbis/Opus/Theora data used to compute timestamps. This is written on the
-  // decoder thread and read on the main thread. All reading on the main
-  // thread must be done after metadataloaded. We can't use the existing
-  // data in the codec states due to threading issues. You must check the
-  // associated mTheoraState or mVorbisState pointer is non-null before
-  // using this codec data.
-  uint32_t mVorbisSerial;
-  uint32_t mOpusSerial;
-  uint32_t mTheoraSerial;
-  vorbis_info mVorbisInfo;
-  int mOpusPreSkip;
-  th_info mTheoraInfo;
-
-  // The picture region inside Theora frame to be displayed, if we have
-  // a Theora video track.
-  nsIntRect mPicture;
-
-  // True if we are decoding a chained ogg. Reading or writing to this member
-  // should be done with |mMonitor| acquired.
-  bool mIsChained;
-
-  // Number of audio frames decoded so far.
-  int64_t mDecodedAudioFrames;
-
-  MediaResourceIndex mResource;
-};
-
-} // namespace mozilla
-
-#endif
--- a/dom/media/ogg/moz.build
+++ b/dom/media/ogg/moz.build
@@ -4,24 +4,22 @@
 # 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 += [
     'OggCodecState.h',
     'OggCodecStore.h',
     'OggDecoder.h',
     'OggDemuxer.h',
-    'OggReader.h',
     'OggWriter.h',
     'OpusParser.h',
 ]
 
 UNIFIED_SOURCES += [
     'OggCodecState.cpp',
     'OggCodecStore.cpp',
     'OggDecoder.cpp',
     'OggDemuxer.cpp',
-    'OggReader.cpp',
     'OggWriter.cpp',
     'OpusParser.cpp',
 ]
 
 FINAL_LIBRARY = 'xul'
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -573,17 +573,16 @@ pref("media.mediasource.mp4.enabled", tr
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID)
 pref("media.mediasource.webm.enabled", false);
 #else
 pref("media.mediasource.webm.enabled", true);
 #endif
 pref("media.mediasource.webm.audio.enabled", true);
 
 // Use new MediaFormatReader architecture for plain ogg.
-pref("media.format-reader.ogg", true);
 pref("media.flac.enabled", true);
 pref("media.ogg.flac.enabled", true);
 
 pref("media.benchmark.vp9.threshold", 150);
 pref("media.benchmark.frames", 300);
 pref("media.benchmark.timeout", 1000);
 
 #ifdef MOZ_WEBSPEECH