Bug 566779 - Clean up media start and end time calculation. r=doublec

This commit is contained in:
Chris Pearce 2011-05-09 09:10:28 +12:00
Родитель f70d867b0e
Коммит 61d1102801
10 изменённых файлов: 112 добавлений и 149 удалений

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

@ -260,6 +260,11 @@ public:
// aDuration is in microseconds. // aDuration is in microseconds.
virtual void SetDuration(PRInt64 aDuration) = 0; virtual void SetDuration(PRInt64 aDuration) = 0;
// Called while decoding metadata to set the end time of the media
// resource. The decoder monitor must be obtained before calling this.
// aEndTime is in microseconds.
virtual void SetEndTime(PRInt64 aEndTime) = 0;
// Functions used by assertions to ensure we're calling things // Functions used by assertions to ensure we're calling things
// on the appropriate threads. // on the appropriate threads.
virtual PRBool OnDecodeThread() const = 0; virtual PRBool OnDecodeThread() const = 0;
@ -285,9 +290,15 @@ public:
virtual void ClearPositionChangeFlag() = 0; virtual void ClearPositionChangeFlag() = 0;
// Called from the main thread to set whether the media resource can // Called from the main thread to set whether the media resource can
// be seeked. The decoder monitor must be obtained before calling this. // seek into unbuffered ranges. The decoder monitor must be obtained
// before calling this.
virtual void SetSeekable(PRBool aSeekable) = 0; virtual void SetSeekable(PRBool aSeekable) = 0;
// Returns PR_TRUE if the media resource can seek into unbuffered ranges,
// as set by SetSeekable(). The decoder monitor must be obtained before
// calling this.
virtual PRBool GetSeekable() = 0;
// Update the playback position. This can result in a timeupdate event // Update the playback position. This can result in a timeupdate event
// and an invalidate of the frame being dispatched asynchronously if // and an invalidate of the frame being dispatched asynchronously if
// there is no such event currently queued. // there is no such event currently queued.

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

@ -229,15 +229,10 @@ nsresult nsBuiltinDecoderReader::ResetDecode()
return res; return res;
} }
VideoData* nsBuiltinDecoderReader::FindStartTime(PRInt64 aOffset, VideoData* nsBuiltinDecoderReader::FindStartTime(PRInt64& aOutStartTime)
PRInt64& aOutStartTime)
{ {
NS_ASSERTION(mDecoder->OnStateMachineThread(), "Should be on state machine thread."); NS_ASSERTION(mDecoder->OnStateMachineThread(), "Should be on state machine thread.");
if (NS_FAILED(ResetDecode())) {
return nsnull;
}
// Extract the start times of the bitstreams in order to calculate // Extract the start times of the bitstreams in order to calculate
// the duration. // the duration.
PRInt64 videoStartTime = PR_INT64_MAX; PRInt64 videoStartTime = PR_INT64_MAX;
@ -267,11 +262,6 @@ VideoData* nsBuiltinDecoderReader::FindStartTime(PRInt64 aOffset,
return videoData; return videoData;
} }
PRInt64 nsBuiltinDecoderReader::FindEndTime(PRInt64 aEndOffset)
{
return -1;
}
template<class Data> template<class Data>
Data* nsBuiltinDecoderReader::DecodeToFirstData(DecodeFn aDecodeFn, Data* nsBuiltinDecoderReader::DecodeToFirstData(DecodeFn aDecodeFn,
MediaQueue<Data>& aQueue) MediaQueue<Data>& aQueue)

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

@ -444,14 +444,9 @@ public:
virtual nsresult ReadMetadata(nsVideoInfo* aInfo) = 0; virtual nsresult ReadMetadata(nsVideoInfo* aInfo) = 0;
// Stores the presentation time of the first frame/sample we'd be // Stores the presentation time of the first frame/sample we'd be
// able to play if we started playback at aOffset, and returns the // able to play if we started playback at the current position. Returns
// first video sample, if we have video. // the first video sample, if we have video.
virtual VideoData* FindStartTime(PRInt64 aOffset, VideoData* FindStartTime(PRInt64& aOutStartTime);
PRInt64& aOutStartTime);
// Returns the end time of the last page which occurs before aEndOffset.
// This will not read past aEndOffset. Returns -1 on failure.
virtual PRInt64 FindEndTime(PRInt64 aEndOffset);
// Moves the decode head to aTime microseconds. aStartTime and aEndTime // Moves the decode head to aTime microseconds. aStartTime and aEndTime
// denote the start and end times of the media in usecs, and aCurrentTime // denote the start and end times of the media in usecs, and aCurrentTime

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

@ -817,6 +817,10 @@ void nsBuiltinDecoderStateMachine::SetDuration(PRInt64 aDuration)
"Should be on main or state machine thread."); "Should be on main or state machine thread.");
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn(); mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
if (aDuration == -1) {
return;
}
if (mStartTime != -1) { if (mStartTime != -1) {
mEndTime = mStartTime + aDuration; mEndTime = mStartTime + aDuration;
} else { } else {
@ -825,6 +829,14 @@ void nsBuiltinDecoderStateMachine::SetDuration(PRInt64 aDuration)
} }
} }
void nsBuiltinDecoderStateMachine::SetEndTime(PRInt64 aEndTime)
{
NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread");
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
mEndTime = aEndTime;
}
void nsBuiltinDecoderStateMachine::SetSeekable(PRBool aSeekable) void nsBuiltinDecoderStateMachine::SetSeekable(PRBool aSeekable)
{ {
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
@ -1559,7 +1571,7 @@ VideoData* nsBuiltinDecoderStateMachine::FindStartTime()
VideoData* v = nsnull; VideoData* v = nsnull;
{ {
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
v = mReader->FindStartTime(0, startTime); v = mReader->FindStartTime(startTime);
} }
if (startTime != 0) { if (startTime != 0) {
mStartTime = startTime; mStartTime = startTime;
@ -1580,30 +1592,6 @@ VideoData* nsBuiltinDecoderStateMachine::FindStartTime()
return v; return v;
} }
void nsBuiltinDecoderStateMachine::FindEndTime()
{
NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
nsMediaStream* stream = mDecoder->GetCurrentStream();
// Seek to the end of file to find the length and duration.
PRInt64 length = stream->GetLength();
NS_ASSERTION(length > 0, "Must have a content length to get end time");
mEndTime = 0;
PRInt64 endTime = 0;
{
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
endTime = mReader->FindEndTime(length);
}
if (endTime != -1) {
mEndTime = endTime;
}
LOG(PR_LOG_DEBUG, ("%p Media end time is %lld", mDecoder, mEndTime));
}
void nsBuiltinDecoderStateMachine::UpdateReadyState() { void nsBuiltinDecoderStateMachine::UpdateReadyState() {
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn(); mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();

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

@ -158,6 +158,7 @@ public:
virtual void Shutdown(); virtual void Shutdown();
virtual PRInt64 GetDuration(); virtual PRInt64 GetDuration();
virtual void SetDuration(PRInt64 aDuration); virtual void SetDuration(PRInt64 aDuration);
void SetEndTime(PRInt64 aEndTime);
virtual PRBool OnDecodeThread() const { virtual PRBool OnDecodeThread() const {
return IsCurrentThread(mDecodeThread); return IsCurrentThread(mDecodeThread);
} }
@ -247,6 +248,11 @@ public:
return mEndTime; return mEndTime;
} }
PRBool GetSeekable() {
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
return mSeekable;
}
// Sets the current frame buffer length for the MozAudioAvailable event. // Sets the current frame buffer length for the MozAudioAvailable event.
// Accessed on the main and state machine threads. // Accessed on the main and state machine threads.
virtual void SetFrameBufferLength(PRUint32 aLength); virtual void SetFrameBufferLength(PRUint32 aLength);
@ -303,11 +309,6 @@ protected:
// machine thread. // machine thread.
VideoData* FindStartTime(); VideoData* FindStartTime();
// Finds the end time of the last frame of data in the file, storing the value
// in mEndTime if successful. The decoder must be held with exactly one lock
// count. Called on the state machine thread.
void FindEndTime();
// Update only the state machine's current playback position (and duration, // Update only the state machine's current playback position (and duration,
// if unknown). Does not update the playback position on the decoder or // if unknown). Does not update the playback position on the decoder or
// media element -- use UpdatePlaybackPosition for that. Called on the state // media element -- use UpdatePlaybackPosition for that. Called on the state

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

@ -45,24 +45,3 @@ nsOggDecoderStateMachine::nsOggDecoderStateMachine(nsBuiltinDecoder* aDecoder) :
nsBuiltinDecoderStateMachine(aDecoder, new nsOggReader(aDecoder)) nsBuiltinDecoderStateMachine(aDecoder, new nsOggReader(aDecoder))
{ {
} }
void nsOggDecoderStateMachine::LoadMetadata()
{
nsBuiltinDecoderStateMachine::LoadMetadata();
// Get the duration from the media file. We only do this if the
// content length of the resource is known as we need to seek
// to the end of the file to get the last time field. We also
// only do this if the resource is seekable and if we haven't
// already obtained the duration via an HTTP header.
if (mState != DECODER_STATE_SHUTDOWN &&
mDecoder->GetCurrentStream()->GetLength() >= 0 &&
mSeekable &&
mEndTime == -1)
{
mDecoder->StopProgressUpdates();
FindEndTime();
mDecoder->StartProgressUpdates();
}
}

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

@ -45,10 +45,6 @@ class nsOggDecoderStateMachine : public nsBuiltinDecoderStateMachine
{ {
public: public:
nsOggDecoderStateMachine(nsBuiltinDecoder* aDecoder); nsOggDecoderStateMachine(nsBuiltinDecoder* aDecoder);
// Overload LoadMetadata to seek to the end of the file and get the
// duration.
virtual void LoadMetadata();
}; };
#endif #endif

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

@ -261,13 +261,13 @@ nsresult nsOggReader::ReadMetadata(nsVideoInfo* aInfo)
mInfo.mHasVideo = PR_TRUE; mInfo.mHasVideo = PR_TRUE;
mInfo.mPixelAspectRatio = mTheoraState->mPixelAspectRatio; mInfo.mPixelAspectRatio = mTheoraState->mPixelAspectRatio;
mInfo.mPicture = nsIntRect(mTheoraState->mInfo.pic_x, mInfo.mPicture = nsIntRect(mTheoraState->mInfo.pic_x,
mTheoraState->mInfo.pic_y, mTheoraState->mInfo.pic_y,
mTheoraState->mInfo.pic_width, mTheoraState->mInfo.pic_width,
mTheoraState->mInfo.pic_height); mTheoraState->mInfo.pic_height);
mInfo.mFrame = nsIntSize(mTheoraState->mInfo.frame_width, mInfo.mFrame = nsIntSize(mTheoraState->mInfo.frame_width,
mTheoraState->mInfo.frame_height); mTheoraState->mInfo.frame_height);
mInfo.mDisplay = nsIntSize(mInfo.mPicture.width, mInfo.mDisplay = nsIntSize(mInfo.mPicture.width,
mInfo.mPicture.height); mInfo.mPicture.height);
gfxIntSize sz(mTheoraState->mInfo.pic_width, gfxIntSize sz(mTheoraState->mInfo.pic_width,
mTheoraState->mInfo.pic_height); mTheoraState->mInfo.pic_height);
mDecoder->SetVideoData(sz, mDecoder->SetVideoData(sz,
@ -318,6 +318,32 @@ nsresult nsOggReader::ReadMetadata(nsVideoInfo* aInfo)
} }
} }
{
ReentrantMonitorAutoExit exitReaderMon(mReentrantMonitor);
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
nsMediaStream* stream = mDecoder->GetCurrentStream();
if (mDecoder->GetStateMachine()->GetDuration() == -1 &&
mDecoder->GetStateMachine()->GetState() != nsDecoderStateMachine::DECODER_STATE_SHUTDOWN &&
stream->GetLength() >= 0 &&
mDecoder->GetStateMachine()->GetSeekable())
{
// 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.
PRInt64 length = stream->GetLength();
NS_ASSERTION(length > 0, "Must have a content length to get end time");
PRInt64 endTime = 0;
{
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
endTime = RangeEndTime(length);
}
if (endTime != -1) {
mDecoder->GetStateMachine()->SetEndTime(endTime);
LOG(PR_LOG_DEBUG, ("Got Ogg duration from seeking to end %lld", endTime));
}
}
}
*aInfo = mInfo; *aInfo = mInfo;
return NS_OK; return NS_OK;
@ -401,27 +427,6 @@ PRBool nsOggReader::DecodeAudioData()
return PR_TRUE; return PR_TRUE;
} }
#ifdef DEBUG
// Ensures that all the VideoData in aFrames array are stored in increasing
// order by timestamp. Used in assertions in debug builds.
static PRBool
AllFrameTimesIncrease(nsTArray<nsAutoPtr<VideoData> >& aFrames)
{
PRInt64 prevTime = -1;
PRInt64 prevGranulepos = -1;
for (PRUint32 i = 0; i < aFrames.Length(); i++) {
VideoData* f = aFrames[i];
if (f->mTime < prevTime) {
return PR_FALSE;
}
prevTime = f->mTime;
prevGranulepos = f->mTimecode;
}
return PR_TRUE;
}
#endif
nsresult nsOggReader::DecodeTheora(ogg_packet* aPacket) nsresult nsOggReader::DecodeTheora(ogg_packet* aPacket)
{ {
NS_ASSERTION(aPacket->granulepos >= TheoraVersion(&mTheoraState->mInfo,3,2,1), NS_ASSERTION(aPacket->granulepos >= TheoraVersion(&mTheoraState->mInfo,3,2,1),
@ -620,8 +625,7 @@ GetChecksum(ogg_page* page)
return c; return c;
} }
VideoData* nsOggReader::FindStartTime(PRInt64 aOffset, PRInt64 nsOggReader::RangeStartTime(PRInt64 aOffset)
PRInt64& aOutStartTime)
{ {
NS_ASSERTION(mDecoder->OnStateMachineThread(), NS_ASSERTION(mDecoder->OnStateMachineThread(),
"Should be on state machine thread."); "Should be on state machine thread.");
@ -629,30 +633,42 @@ VideoData* nsOggReader::FindStartTime(PRInt64 aOffset,
NS_ENSURE_TRUE(stream != nsnull, nsnull); NS_ENSURE_TRUE(stream != nsnull, nsnull);
nsresult res = stream->Seek(nsISeekableStream::NS_SEEK_SET, aOffset); nsresult res = stream->Seek(nsISeekableStream::NS_SEEK_SET, aOffset);
NS_ENSURE_SUCCESS(res, nsnull); NS_ENSURE_SUCCESS(res, nsnull);
return nsBuiltinDecoderReader::FindStartTime(aOffset, aOutStartTime); PRInt64 startTime = 0;
nsBuiltinDecoderReader::FindStartTime(startTime);
return startTime;
} }
PRInt64 nsOggReader::FindEndTime(PRInt64 aEndOffset) struct nsAutoOggSyncState {
nsAutoOggSyncState() {
ogg_sync_init(&mState);
}
~nsAutoOggSyncState() {
ogg_sync_clear(&mState);
}
ogg_sync_state mState;
};
PRInt64 nsOggReader::RangeEndTime(PRInt64 aEndOffset)
{ {
ReentrantMonitorAutoEnter mon(mReentrantMonitor); ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mDecoder->OnStateMachineThread(), NS_ASSERTION(mDecoder->OnStateMachineThread(),
"Should be on state machine thread."); "Should be on state machine thread.");
PRInt64 endTime = FindEndTime(0, aEndOffset, PR_FALSE, &mOggState);
// Reset read head to start of media data.
nsMediaStream* stream = mDecoder->GetCurrentStream(); nsMediaStream* stream = mDecoder->GetCurrentStream();
NS_ENSURE_TRUE(stream != nsnull, -1); NS_ENSURE_TRUE(stream != nsnull, -1);
nsresult res = stream->Seek(nsISeekableStream::NS_SEEK_SET, 0); PRInt64 position = stream->Tell();
PRInt64 endTime = RangeEndTime(0, aEndOffset, PR_FALSE);
nsresult res = stream->Seek(nsISeekableStream::NS_SEEK_SET, position);
NS_ENSURE_SUCCESS(res, -1); NS_ENSURE_SUCCESS(res, -1);
return endTime; return endTime;
} }
PRInt64 nsOggReader::FindEndTime(PRInt64 aStartOffset, PRInt64 nsOggReader::RangeEndTime(PRInt64 aStartOffset,
PRInt64 aEndOffset, PRInt64 aEndOffset,
PRBool aCachedDataOnly, PRBool aCachedDataOnly)
ogg_sync_state* aState)
{ {
nsMediaStream* stream = mDecoder->GetCurrentStream(); nsMediaStream* stream = mDecoder->GetCurrentStream();
ogg_sync_reset(aState); nsAutoOggSyncState sync;
// We need to find the last page which ends before aEndOffset that // 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 // has a granulepos that we can convert to a timestamp. We do this by
@ -669,7 +685,7 @@ PRInt64 nsOggReader::FindEndTime(PRInt64 aStartOffset,
PRBool mustBackOff = PR_FALSE; PRBool mustBackOff = PR_FALSE;
while (PR_TRUE) { while (PR_TRUE) {
ogg_page page; ogg_page page;
int ret = ogg_sync_pageseek(aState, &page); int ret = ogg_sync_pageseek(&sync.mState, &page);
if (ret == 0) { if (ret == 0) {
// We need more data if we've not encountered a page we've seen before, // We need more data if we've not encountered a page we've seen before,
// or we've read to the end of file. // or we've read to the end of file.
@ -681,7 +697,7 @@ PRInt64 nsOggReader::FindEndTime(PRInt64 aStartOffset,
mustBackOff = PR_FALSE; mustBackOff = PR_FALSE;
prevChecksumAfterSeek = checksumAfterSeek; prevChecksumAfterSeek = checksumAfterSeek;
checksumAfterSeek = 0; checksumAfterSeek = 0;
ogg_sync_reset(aState); ogg_sync_reset(&sync.mState);
readStartOffset = NS_MAX(static_cast<PRInt64>(0), readStartOffset - step); readStartOffset = NS_MAX(static_cast<PRInt64>(0), readStartOffset - step);
readHead = NS_MAX(aStartOffset, readStartOffset); readHead = NS_MAX(aStartOffset, readStartOffset);
} }
@ -692,7 +708,7 @@ PRInt64 nsOggReader::FindEndTime(PRInt64 aStartOffset,
limit = NS_MIN(limit, static_cast<PRInt64>(step)); limit = NS_MIN(limit, static_cast<PRInt64>(step));
PRUint32 bytesToRead = static_cast<PRUint32>(limit); PRUint32 bytesToRead = static_cast<PRUint32>(limit);
PRUint32 bytesRead = 0; PRUint32 bytesRead = 0;
char* buffer = ogg_sync_buffer(aState, bytesToRead); char* buffer = ogg_sync_buffer(&sync.mState, bytesToRead);
NS_ASSERTION(buffer, "Must have buffer"); NS_ASSERTION(buffer, "Must have buffer");
nsresult res; nsresult res;
if (aCachedDataOnly) { if (aCachedDataOnly) {
@ -711,7 +727,7 @@ PRInt64 nsOggReader::FindEndTime(PRInt64 aStartOffset,
// Update the synchronisation layer with the number // Update the synchronisation layer with the number
// of bytes written to the buffer // of bytes written to the buffer
ret = ogg_sync_wrote(aState, bytesRead); ret = ogg_sync_wrote(&sync.mState, bytesRead);
if (ret != 0) { if (ret != 0) {
endTime = -1; endTime = -1;
break; break;
@ -761,8 +777,6 @@ PRInt64 nsOggReader::FindEndTime(PRInt64 aStartOffset,
} }
} }
ogg_sync_reset(aState);
return endTime; return endTime;
} }
@ -784,9 +798,9 @@ nsresult nsOggReader::GetSeekRanges(nsTArray<SeekRange>& aRanges)
} }
PRInt64 startOffset = range.mStart; PRInt64 startOffset = range.mStart;
PRInt64 endOffset = range.mEnd; PRInt64 endOffset = range.mEnd;
FindStartTime(startOffset, startTime); startTime = RangeStartTime(startOffset);
if (startTime != -1 && if (startTime != -1 &&
((endTime = FindEndTime(endOffset)) != -1)) ((endTime = RangeEndTime(endOffset)) != -1))
{ {
NS_ASSERTION(startTime < endTime, NS_ASSERTION(startTime < endTime,
"Start time must be before end time"); "Start time must be before end time");
@ -1423,8 +1437,7 @@ nsresult nsOggReader::GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime)
// offset is after the end of the media stream, or there's no more cached // offset is after the end of the media stream, or there's no more cached
// data after the offset. This loop will run until we've checked every // data after the offset. This loop will run until we've checked every
// buffered range in the media, in increasing order of offset. // buffered range in the media, in increasing order of offset.
ogg_sync_state state; nsAutoOggSyncState sync;
ogg_sync_init(&state);
for (PRUint32 index = 0; index < ranges.Length(); index++) { for (PRUint32 index = 0; index < ranges.Length(); index++) {
// Ensure the offsets are after the header pages. // Ensure the offsets are after the header pages.
PRInt64 startOffset = ranges[index].mStart; PRInt64 startOffset = ranges[index].mStart;
@ -1439,20 +1452,18 @@ nsresult nsOggReader::GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime)
// Find the start time of the range. Read pages until we find one with a // 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 // granulepos which we can convert into a timestamp to use as the time of
// the start of the buffered range. // the start of the buffered range.
ogg_sync_reset(&state); ogg_sync_reset(&sync.mState);
while (startTime == -1) { while (startTime == -1) {
ogg_page page; ogg_page page;
PRInt32 discard; PRInt32 discard;
PageSyncResult res = PageSync(stream, PageSyncResult res = PageSync(stream,
&state, &sync.mState,
PR_TRUE, PR_TRUE,
startOffset, startOffset,
endOffset, endOffset,
&page, &page,
discard); discard);
if (res == PAGE_SYNC_ERROR) { if (res == PAGE_SYNC_ERROR) {
// If we don't clear the sync state before exit we'll leak.
ogg_sync_clear(&state);
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} else if (res == PAGE_SYNC_END_OF_RANGE) { } else if (res == PAGE_SYNC_END_OF_RANGE) {
// Hit the end of range without reading a page, give up trying to // Hit the end of range without reading a page, give up trying to
@ -1486,7 +1497,6 @@ nsresult nsOggReader::GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime)
else { else {
// Page is for a stream we don't know about (possibly a chained // Page is for a stream we don't know about (possibly a chained
// ogg), return an error. // ogg), return an error.
ogg_sync_clear(&state);
return PAGE_SYNC_ERROR; return PAGE_SYNC_ERROR;
} }
} }
@ -1494,7 +1504,7 @@ nsresult nsOggReader::GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime)
if (startTime != -1) { if (startTime != -1) {
// We were able to find a start time for that range, see if we can // We were able to find a start time for that range, see if we can
// find an end time. // find an end time.
PRInt64 endTime = FindEndTime(startOffset, endOffset, PR_TRUE, &state); PRInt64 endTime = RangeEndTime(startOffset, endOffset, PR_TRUE);
if (endTime != -1) { if (endTime != -1) {
aBuffered->Add(startTime / static_cast<double>(USECS_PER_S), aBuffered->Add(startTime / static_cast<double>(USECS_PER_S),
(endTime - aStartTime) / static_cast<double>(USECS_PER_S)); (endTime - aStartTime) / static_cast<double>(USECS_PER_S));
@ -1502,9 +1512,6 @@ nsresult nsOggReader::GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime)
} }
} }
// If we don't clear the sync state before exit we'll leak.
ogg_sync_clear(&state);
return NS_OK; return NS_OK;
} }

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

@ -71,13 +71,6 @@ public:
virtual PRBool DecodeVideoFrame(PRBool &aKeyframeSkip, virtual PRBool DecodeVideoFrame(PRBool &aKeyframeSkip,
PRInt64 aTimeThreshold); PRInt64 aTimeThreshold);
virtual VideoData* FindStartTime(PRInt64 aOffset,
PRInt64& aOutStartTime);
// Get the end time of aEndOffset. This is the playback position we'd reach
// after playback finished at aEndOffset.
virtual PRInt64 FindEndTime(PRInt64 aEndOffset);
virtual PRBool HasAudio() virtual PRBool HasAudio()
{ {
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor); mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
@ -177,17 +170,25 @@ private:
PRInt64 aEndTime, PRInt64 aEndTime,
const nsTArray<SeekRange>& aRanges); const nsTArray<SeekRange>& aRanges);
// Get the end time of aEndOffset. This is the playback position we'd reach
// after playback finished at aEndOffset.
PRInt64 RangeEndTime(PRInt64 aEndOffset);
// Get the end time of aEndOffset, without reading before aStartOffset. // Get the end time of aEndOffset, without reading before aStartOffset.
// This is the playback position we'd reach after playback finished at // This is the playback position we'd reach after playback finished at
// aEndOffset. If PRBool aCachedDataOnly is PR_TRUE, then we'll only read // aEndOffset. If PRBool aCachedDataOnly is PR_TRUE, then we'll only read
// from data which is cached in the media cached, otherwise we'll do // from data which is cached in the media cached, otherwise we'll do
// regular blocking reads from the media stream. If PRBool aCachedDataOnly // regular blocking reads from the media stream. If PRBool aCachedDataOnly
// is PR_TRUE, and aState is not mOggState, this can safely be called on // is PR_TRUE, this can safely be called on the main thread, otherwise it
// the main thread, otherwise it must be called on the state machine thread. // must be called on the state machine thread.
PRInt64 FindEndTime(PRInt64 aStartOffset, PRInt64 RangeEndTime(PRInt64 aStartOffset,
PRInt64 aEndOffset, PRInt64 aEndOffset,
PRBool aCachedDataOnly, PRBool aCachedDataOnly);
ogg_sync_state* aState);
// 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.
PRInt64 RangeStartTime(PRInt64 aOffset);
// Performs a seek bisection to move the media stream's read cursor to the // 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 // last ogg page boundary which has end time before aTarget usecs on both the

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

@ -305,11 +305,6 @@ nsresult nsRawReader::Seek(PRInt64 aTime, PRInt64 aStartTime, PRInt64 aEndTime,
return NS_OK; return NS_OK;
} }
PRInt64 nsRawReader::FindEndTime(PRInt64 aEndTime)
{
return -1;
}
nsresult nsRawReader::GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime) nsresult nsRawReader::GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime)
{ {
return NS_OK; return NS_OK;