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;
}
@ -948,7 +942,7 @@ GetChecksum(ogg_page* page)
}
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;
@ -1013,7 +1007,7 @@ int64_t OggReader::RangeEndTime(int64_t aStartOffset,
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,
@ -1196,7 +1190,7 @@ OggReader::IndexedSeekResult OggReader::RollbackIndexedSeek(int64_t aOffset)
NS_ENSURE_SUCCESS(res, SEEK_FATAL_ERROR);
return SEEK_INDEX_FAIL;
}
OggReader::IndexedSeekResult OggReader::SeekToKeyframeUsingIndex(int64_t aTarget)
{
MediaResource* resource = mDecoder->GetResource();
@ -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;
}
@ -1335,7 +1327,7 @@ nsresult OggReader::SeekInUnbuffered(int64_t aTarget,
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
@ -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);
@ -1484,7 +1475,7 @@ PageSync(MediaResource* aResource,
// 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;
}
@ -1495,7 +1486,7 @@ PageSync(MediaResource* aResource,
continue;
}
}
return PAGE_SYNC_OK;
}
@ -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;
}
@ -1553,7 +1543,7 @@ nsresult OggReader::SeekBisection(int64_t aTarget,
// 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;
@ -1614,7 +1604,7 @@ nsresult OggReader::SeekBisection(int64_t aTarget,
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.
@ -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,7 +1626,12 @@ nsresult OggReader::SeekBisection(int64_t aTarget,
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;
@ -1666,7 +1655,7 @@ nsresult OggReader::SeekBisection(int64_t aTarget,
#endif
}
}
if (HasVideo() &&
granulepos > 0 &&
serial == mTheoraState->mSerial &&
@ -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))
(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;
}
@ -1779,7 +1766,7 @@ nsresult OggReader::GetBuffered(TimeRanges* aBuffered, int64_t aStartTime)
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

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

@ -212,7 +212,7 @@ private:
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);
@ -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;