Bug 846769 - Mark Ogg frames with MediaResource offset, instead of (incorrectly) trying to infer and then use the offset of pages. r=rillian

This commit is contained in:
Chris Pearce 2013-07-29 10:03:06 +12:00
Родитель 1fa65593c1
Коммит 3a531b30f9
2 изменённых файлов: 40 добавлений и 57 удалений

Просмотреть файл

@ -92,7 +92,6 @@ OggReader::OggReader(AbstractMediaDecoder* aDecoder)
mOpusSerial(0),
mTheoraSerial(0),
mOpusPreSkip(0),
mPageOffset(0),
mIsChained(false),
mDecodedAudioFrames(0)
{
@ -184,8 +183,7 @@ nsresult OggReader::ReadMetadata(VideoInfo* aInfo,
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;
}
@ -415,7 +413,7 @@ nsresult OggReader::DecodeVorbis(ogg_packet* aPacket) {
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,
@ -535,7 +533,7 @@ nsresult OggReader::DecodeOpus(ogg_packet* aPacket) {
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,
@ -675,8 +673,7 @@ bool OggReader::ReadOggChain()
}
ogg_page page;
int64_t pageOffset = ReadOggPage(&page);
if ((pageOffset == -1) || (!ogg_page_bos(&page))) {
if (!ReadOggPage(&page) || !ogg_page_bos(&page)) {
return false;
}
@ -784,7 +781,7 @@ nsresult OggReader::DecodeTheora(ogg_packet* aPacket, int64_t aTimeThreshold)
}
if (ret == TH_DUPFRAME) {
VideoData* v = VideoData::CreateDuplicate(mPageOffset,
VideoData* v = VideoData::CreateDuplicate(mDecoder->GetResource()->Tell(),
time,
endTime,
aPacket->granulepos);
@ -805,7 +802,7 @@ nsresult OggReader::DecodeTheora(ogg_packet* aPacket, int64_t aTimeThreshold)
VideoData *v = VideoData::Create(mInfo,
mDecoder->GetImageContainer(),
mPageOffset,
mDecoder->GetResource()->Tell(),
time,
endTime,
b,
@ -873,7 +870,7 @@ bool OggReader::DecodeVideoFrame(bool &aKeyframeSkip,
return true;
}
int64_t OggReader::ReadOggPage(ogg_page* aPage)
bool OggReader::ReadOggPage(ogg_page* aPage)
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
@ -881,7 +878,6 @@ int64_t OggReader::ReadOggPage(ogg_page* aPage)
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
@ -896,19 +892,17 @@ int64_t OggReader::ReadOggPage(ogg_page* aPage)
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)
@ -924,7 +918,7 @@ ogg_packet* OggReader::NextOggPacket(OggCodecState* aCodecState)
// 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;
}
@ -1231,7 +1225,6 @@ OggReader::IndexedSeekResult OggReader::SeekToKeyframeUsingIndex(int64_t aTarget
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();
@ -1244,7 +1237,7 @@ OggReader::IndexedSeekResult OggReader::SeekToKeyframeUsingIndex(int64_t aTarget
PageSyncResult syncres = PageSync(resource,
&mOggState,
false,
mPageOffset,
keyframe.mKeyPoint.mOffset,
resource->GetLength(),
&page,
skippedBytes);
@ -1269,7 +1262,6 @@ OggReader::IndexedSeekResult OggReader::SeekToKeyframeUsingIndex(int64_t aTarget
// is no longer active.
return RollbackIndexedSeek(tell);
}
mPageOffset = keyframe.mKeyPoint.mOffset + page.header_len + page.body_len;
return SEEK_OK;
}
@ -1386,7 +1378,6 @@ nsresult OggReader::Seek(int64_t aTarget,
res = resource->Seek(nsISeekableStream::NS_SEEK_SET, 0);
NS_ENSURE_SUCCESS(res,res);
mPageOffset = 0;
res = ResetDecode(true);
NS_ENSURE_SUCCESS(res,res);
@ -1513,7 +1504,6 @@ nsresult OggReader::SeekBisection(int64_t aTarget,
}
res = resource->Seek(nsISeekableStream::NS_SEEK_SET, 0);
NS_ENSURE_SUCCESS(res,res);
mPageOffset = 0;
return NS_OK;
}
@ -1627,12 +1617,6 @@ nsresult OggReader::SeekBisection(int64_t aTarget,
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
@ -1642,6 +1626,11 @@ nsresult OggReader::SeekBisection(int64_t aTarget,
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;
@ -1674,25 +1663,25 @@ nsresult OggReader::SeekBisection(int64_t aTarget,
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))
{
// 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
@ -1722,7 +1711,6 @@ nsresult OggReader::SeekBisection(int64_t aTarget,
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;
}
@ -1734,11 +1722,10 @@ nsresult OggReader::SeekBisection(int64_t aTarget,
// 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;
}

Просмотреть файл

@ -234,9 +234,9 @@ private:
// 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.
@ -295,10 +295,6 @@ private:
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;