Bug 846769 - Mark Ogg frames with MediaResource offset, instead of (incorrectly) trying to infer and then use the offset of pages. r=rillian
authorChris Pearce <cpearce@mozilla.com>
Mon, 29 Jul 2013 10:03:06 +1200
changeset 140280 6558e79080bdbea49766afb22196592f2c4bfab4
parent 140279 c28a758324262fcda6df5b459ef50045803f203f
child 140281 2d7d821c792dc4f3e1bd40a0809af934c59e19a1
push id25023
push useremorley@mozilla.com
push dateMon, 29 Jul 2013 14:13:44 +0000
treeherdermozilla-central@8c89fe2a5c92 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrillian
bugs846769
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 846769 - Mark Ogg frames with MediaResource offset, instead of (incorrectly) trying to infer and then use the offset of pages. r=rillian
content/media/ogg/OggReader.cpp
content/media/ogg/OggReader.h
--- a/content/media/ogg/OggReader.cpp
+++ b/content/media/ogg/OggReader.cpp
@@ -87,17 +87,16 @@ OggReader::OggReader(AbstractMediaDecode
     mVorbisState(nullptr),
     mOpusState(nullptr),
     mOpusEnabled(MediaDecoder::IsOpusEnabled()),
     mSkeletonState(nullptr),
     mVorbisSerial(0),
     mOpusSerial(0),
     mTheoraSerial(0),
     mOpusPreSkip(0),
-    mPageOffset(0),
     mIsChained(false),
     mDecodedAudioFrames(0)
 {
   MOZ_COUNT_CTOR(OggReader);
   memset(&mTheoraInfo, 0, sizeof(mTheoraInfo));
 }
 
 OggReader::~OggReader()
@@ -179,18 +178,17 @@ nsresult OggReader::ReadMetadata(VideoIn
 
   NS_ASSERTION(aTags, "Called with null MetadataTags**.");
   *aTags = nullptr;
 
   ogg_page page;
   nsAutoTArray<OggCodecState*,4> bitstreams;
   bool readAllBOS = false;
   while (!readAllBOS) {
-    int64_t pageOffset = ReadOggPage(&page);
-    if (pageOffset == -1) {
+    if (!ReadOggPage(&page)) {
       // Some kind of error...
       break;
     }
 
     int serial = ogg_page_serialno(&page);
     OggCodecState* codecState = 0;
 
     if (!ogg_page_bos(&page)) {
@@ -410,17 +408,17 @@ nsresult OggReader::DecodeVorbis(ogg_pac
         // No channel mapping for more than 8 channels.
         return NS_ERROR_FAILURE;
       }
       DownmixToStereo(buffer, channels, frames);
     }
 
     int64_t duration = mVorbisState->Time((int64_t)frames);
     int64_t startTime = mVorbisState->Time(endFrame - frames);
-    mAudioQueue.Push(new AudioData(mPageOffset,
+    mAudioQueue.Push(new AudioData(mDecoder->GetResource()->Tell(),
                                    startTime,
                                    duration,
                                    frames,
                                    buffer.forget(),
                                    channels));
 
     mDecodedAudioFrames += frames;
 
@@ -530,17 +528,17 @@ nsresult OggReader::DecodeOpus(ogg_packe
     if (channels > 8)
       return NS_ERROR_FAILURE;
     DownmixToStereo(buffer, channels, frames);
   }
 
   LOG(PR_LOG_DEBUG, ("Opus decoder pushing %d frames", frames));
   int64_t startTime = mOpusState->Time(startFrame);
   int64_t endTime = mOpusState->Time(endFrame);
-  mAudioQueue.Push(new AudioData(mPageOffset,
+  mAudioQueue.Push(new AudioData(mDecoder->GetResource()->Tell(),
                                  startTime,
                                  endTime - startTime,
                                  frames,
                                  buffer.forget(),
                                  channels));
 
   mDecodedAudioFrames += frames;
 
@@ -670,18 +668,17 @@ bool OggReader::ReadOggChain()
   long rate = 0;
   MetadataTags* tags = nullptr;
 
   if (HasVideo() || HasSkeleton() || !HasAudio()) {
     return false;
   }
 
   ogg_page page;
-  int64_t pageOffset = ReadOggPage(&page);
-  if ((pageOffset == -1) || (!ogg_page_bos(&page))) {
+  if (!ReadOggPage(&page) || !ogg_page_bos(&page)) {
     return false;
   }
 
   int serial = ogg_page_serialno(&page);
   if (mCodecStore.Contains(serial)) {
     return false;
   }
 
@@ -779,17 +776,17 @@ nsresult OggReader::DecodeTheora(ogg_pac
   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;
   }
 
   if (ret == TH_DUPFRAME) {
-    VideoData* v = VideoData::CreateDuplicate(mPageOffset,
+    VideoData* v = VideoData::CreateDuplicate(mDecoder->GetResource()->Tell(),
                                               time,
                                               endTime,
                                               aPacket->granulepos);
     mVideoQueue.Push(v);
   } else if (ret == 0) {
     th_ycbcr_buffer buffer;
     ret = th_decode_ycbcr_out(mTheoraState->mCtx, buffer);
     NS_ASSERTION(ret == 0, "th_decode_ycbcr_out failed");
@@ -800,17 +797,17 @@ nsresult OggReader::DecodeTheora(ogg_pac
       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;
     }
 
     VideoData *v = VideoData::Create(mInfo,
                                      mDecoder->GetImageContainer(),
-                                     mPageOffset,
+                                     mDecoder->GetResource()->Tell(),
                                      time,
                                      endTime,
                                      b,
                                      isKeyframe,
                                      aPacket->granulepos,
                                      mPicture);
     if (!v) {
       // There may be other reasons for this error, but for
@@ -868,68 +865,65 @@ bool OggReader::DecodeVideoFrame(bool &a
     // there will be no more frames.
     mVideoQueue.Finish();
     return false;
   }
 
   return true;
 }
 
-int64_t OggReader::ReadOggPage(ogg_page* aPage)
+bool OggReader::ReadOggPage(ogg_page* aPage)
 {
   NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
 
   int ret = 0;
   while((ret = ogg_sync_pageseek(&mOggState, aPage)) <= 0) {
     if (ret < 0) {
       // Lost page sync, have to skip up to next page.
-      mPageOffset += -ret;
       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 = mDecoder->GetResource()->Read(buffer, 4096, &bytesRead);
     if (NS_FAILED(rv) || (bytesRead == 0 && ret == 0)) {
       // End of file.
-      return -1;
+      return false;
     }
 
     mDecoder->NotifyBytesConsumed(bytesRead);
     // Update the synchronisation layer with the number
     // of bytes written to the buffer
     ret = ogg_sync_wrote(&mOggState, bytesRead);
-    NS_ENSURE_TRUE(ret == 0, -1);    
+    NS_ENSURE_TRUE(ret == 0, false);
   }
-  int64_t offset = mPageOffset;
-  mPageOffset += aPage->header_len + aPage->body_len;
-  
-  return offset;
+
+  return true;
 }
 
 ogg_packet* OggReader::NextOggPacket(OggCodecState* aCodecState)
 {
   NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
 
   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) == -1) {
+    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;
@@ -943,17 +937,17 @@ ogg_packet* OggReader::NextOggPacket(Ogg
 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[1] << 8) +
                (p[2] << 16) +
                (p[3] << 24);
   return c;
 }
 
 int64_t OggReader::RangeStartTime(int64_t aOffset)
 {
   NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
@@ -1008,17 +1002,17 @@ int64_t OggReader::RangeEndTime(int64_t 
   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;    
+    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;
@@ -1191,17 +1185,17 @@ OggReader::IndexedSeekResult OggReader::
 {
   mSkeletonState->Deactivate();
   MediaResource* resource = mDecoder->GetResource();
   NS_ENSURE_TRUE(resource != nullptr, SEEK_FATAL_ERROR);
   nsresult res = resource->Seek(nsISeekableStream::NS_SEEK_SET, aOffset);
   NS_ENSURE_SUCCESS(res, SEEK_FATAL_ERROR);
   return SEEK_INDEX_FAIL;
 }
- 
+
 OggReader::IndexedSeekResult OggReader::SeekToKeyframeUsingIndex(int64_t aTarget)
 {
   MediaResource* resource = mDecoder->GetResource();
   NS_ENSURE_TRUE(resource != nullptr, SEEK_FATAL_ERROR);
   if (!HasSkeleton() || !mSkeletonState->HasIndex()) {
     return SEEK_INDEX_FAIL;
   }
   // We have an index from the Skeleton track, try to use it to seek.
@@ -1226,30 +1220,29 @@ OggReader::IndexedSeekResult OggReader::
     // Index must be invalid.
     return RollbackIndexedSeek(tell);
   }
   LOG(PR_LOG_DEBUG, ("Seeking using index to keyframe at offset %lld\n",
                      keyframe.mKeyPoint.mOffset));
   nsresult res = resource->Seek(nsISeekableStream::NS_SEEK_SET,
                               keyframe.mKeyPoint.mOffset);
   NS_ENSURE_SUCCESS(res, SEEK_FATAL_ERROR);
-  mPageOffset = keyframe.mKeyPoint.mOffset;
 
   // 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(resource,
                                     &mOggState,
                                     false,
-                                    mPageOffset,
+                                    keyframe.mKeyPoint.mOffset,
                                     resource->GetLength(),
                                     &page,
                                     skippedBytes);
   NS_ENSURE_TRUE(syncres != PAGE_SYNC_ERROR, SEEK_FATAL_ERROR);
   if (syncres != PAGE_SYNC_OK || skippedBytes != 0) {
     LOG(PR_LOG_DEBUG, ("Indexed-seek failure: Ogg Skeleton Index is invalid "
                        "or sync error after seek"));
     return RollbackIndexedSeek(tell);
@@ -1264,17 +1257,16 @@ OggReader::IndexedSeekResult OggReader::
   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 OggReader::SeekInBufferedRange(int64_t aTarget,
                                           int64_t aAdjustedTarget,
                                           int64_t aStartTime,
                                           int64_t aEndTime,
                                           const nsTArray<SeekRange>& aRanges,
@@ -1330,17 +1322,17 @@ nsresult OggReader::SeekInBufferedRange(
 }
 
 nsresult OggReader::SeekInUnbuffered(int64_t aTarget,
                                        int64_t aStartTime,
                                        int64_t aEndTime,
                                        const nsTArray<SeekRange>& aRanges)
 {
   LOG(PR_LOG_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
@@ -1381,17 +1373,16 @@ nsresult OggReader::Seek(int64_t aTarget
   }
 
   if (adjustedTarget == aStartTime) {
     // We've seeked to the media start. Just seek to the offset of the first
     // content page.
     res = resource->Seek(nsISeekableStream::NS_SEEK_SET, 0);
     NS_ENSURE_SUCCESS(res,res);
 
-    mPageOffset = 0;
     res = ResetDecode(true);
     NS_ENSURE_SUCCESS(res,res);
 
     NS_ASSERTION(aStartTime != -1, "mStartTime should be known");
     {
       ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
       mDecoder->UpdatePlaybackPosition(aStartTime);
     }
@@ -1479,28 +1470,28 @@ PageSync(MediaResource* aResource,
         // 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);    
+      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)
 {
   NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
@@ -1508,17 +1499,16 @@ nsresult OggReader::SeekBisection(int64_
   MediaResource* resource = mDecoder->GetResource();
 
   if (aTarget == aRange.mTimeStart) {
     if (NS_FAILED(ResetDecode())) {
       return NS_ERROR_FAILURE;
     }
     res = resource->Seek(nsISeekableStream::NS_SEEK_SET, 0);
     NS_ENSURE_SUCCESS(res,res);
-    mPageOffset = 0;
     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.
@@ -1548,17 +1538,17 @@ nsresult OggReader::SeekBisection(int64_
     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
@@ -1609,45 +1599,44 @@ nsresult OggReader::SeekBisection(int64_
                               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 res = PageSync(resource,
                                     &mOggState,
                                     false,
                                     guess,
                                     endOffset,
                                     &page,
                                     skippedBytes);
       NS_ENSURE_TRUE(res != PAGE_SYNC_ERROR, NS_ERROR_FAILURE);
 
-      // 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;
-      mPageOffset = pageOffset + pageLength;
-
       if (res == 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(PR_LOG_DEBUG, ("Hit the end of range, backing off"));
         continue;
       }
 
-      // Read pages until we can determine the granule time of the audio and 
+      // 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) {
@@ -1661,43 +1650,43 @@ nsresult OggReader::SeekBisection(int64_
           if (mVorbisState && serial == mVorbisState->mSerial) {
             audioTime = mVorbisState->Time(granulepos);
 #ifdef MOZ_OPUS
           } else if (mOpusState && serial == mOpusState->mSerial) {
             audioTime = mOpusState->Time(granulepos);
 #endif
           }
         }
-        
+
         if (HasVideo() &&
             granulepos > 0 &&
             serial == mTheoraState->mSerial &&
             videoTime == -1) {
           videoTime = mTheoraState->StartTime(granulepos);
         }
 
-        if (mPageOffset == endOffset) {
+        if (pageOffset + pageLength >= endOffset) {
           // Hit end of readable data.
           break;
         }
 
-        if (ReadOggPage(&page) == -1) {
+        if (!ReadOggPage(&page)) {
           break;
         }
-        
+
       } while ((HasAudio() && audioTime == -1) ||
                (HasVideo() && videoTime == -1));
 
-      NS_ASSERTION(mPageOffset <= endOffset, "Page read cursor should be inside range");
 
       if ((HasAudio() && audioTime == -1) ||
-          (HasVideo() && videoTime == -1)) 
+          (HasVideo() && videoTime == -1))
       {
         // We don't have timestamps for all active tracks...
-        if (pageOffset == startOffset + startLength && mPageOffset == endOffset) {
+        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;
         }
@@ -1717,33 +1706,31 @@ nsresult OggReader::SeekBisection(int64_
 
     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(PR_LOG_DEBUG, ("Terminating seek at offset=%lld", startOffset));
       NS_ASSERTION(startTime < aTarget, "Start time must always be less than target");
       res = resource->Seek(nsISeekableStream::NS_SEEK_SET, startOffset);
       NS_ENSURE_SUCCESS(res,res);
-      mPageOffset = startOffset;
       if (NS_FAILED(ResetDecode())) {
         return NS_ERROR_FAILURE;
       }
       break;
     }
 
     SEEK_LOG(PR_LOG_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 = resource->Seek(nsISeekableStream::NS_SEEK_SET, pageOffset);
       NS_ENSURE_SUCCESS(res,res);
-      mPageOffset = pageOffset;
       if (NS_FAILED(ResetDecode())) {
         return NS_ERROR_FAILURE;
       }
-      SEEK_LOG(PR_LOG_DEBUG, ("Terminating seek at offset=%lld", mPageOffset));
+      SEEK_LOG(PR_LOG_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;
@@ -1774,17 +1761,17 @@ nsresult OggReader::GetBuffered(TimeRang
 #ifdef OGG_ESTIMATE_BUFFERED
   MediaResource* stream = mDecoder->GetResource();
   int64_t durationUs = 0;
   {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
     durationUs = mDecoder->GetMediaDuration();
   }
   GetEstimatedBufferedTimeRanges(stream, durationUs, aBuffered);
-  
+
   return NS_OK;
 #else
   // 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.mHasVideo && !mInfo.mHasAudio) {
     // No need to search through the file if there are no audio or video tracks
     return NS_OK;
--- a/content/media/ogg/OggReader.h
+++ b/content/media/ogg/OggReader.h
@@ -207,17 +207,17 @@ private:
   // 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 
+  // 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);
 
   // Downmix multichannel Audio samples to Stereo.
@@ -229,19 +229,19 @@ private:
 
   // 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 the offset of the start
-  // of the page, or -1 if the page read failed.
-  int64_t ReadOggPage(ogg_page* aPage);
+  // 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.
@@ -290,20 +290,16 @@ private:
   // using this codec data.
   uint32_t mVorbisSerial;
   uint32_t mOpusSerial;
   uint32_t mTheoraSerial;
   vorbis_info mVorbisInfo;
   int mOpusPreSkip;
   th_info mTheoraInfo;
 
-  // The offset of the end of the last page we've read, or the start of
-  // the page we're about to read.
-  int64_t mPageOffset;
-
   // 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;