Bug 1119757: Allow seeking on media with infinite duration. r=cpearce

MSE defines content to have infinite duration when no duration is defined.
And MSE is always seekable within the buffered range, regardless of the duration
This commit is contained in:
Jean-Yves Avenard
2015-01-16 23:49:01 +11:00
parent ba43648dc4
commit d1d00bac1e
2 changed files with 38 additions and 11 deletions

View File

@@ -188,6 +188,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mPlayDuration(0),
mStartTime(-1),
mEndTime(-1),
mDurationSet(false),
mFragmentEndTime(-1),
mReader(aReader),
mCurrentFrameTime(0),
@@ -1408,6 +1409,14 @@ int64_t MediaDecoderStateMachine::GetDuration()
return mEndTime - mStartTime;
}
int64_t MediaDecoderStateMachine::GetEndTime()
{
if (mEndTime == -1 && mDurationSet) {
return INT64_MAX;
}
return mEndTime;
}
void MediaDecoderStateMachine::SetDuration(int64_t aDuration)
{
NS_ASSERTION(NS_IsMainThread() || OnDecodeThread(),
@@ -1415,13 +1424,21 @@ void MediaDecoderStateMachine::SetDuration(int64_t aDuration)
AssertCurrentThreadInMonitor();
if (aDuration == -1) {
mDurationSet = false;
return;
}
mDurationSet = true;
if (mStartTime == -1) {
SetStartTime(0);
}
if (aDuration == INT64_MAX) {
mEndTime = -1;
return;
}
mEndTime = mStartTime + aDuration;
}
@@ -1735,12 +1752,13 @@ MediaDecoderStateMachine::StartSeek(const SeekTarget& aTarget)
}
// Bound the seek time to be inside the media range.
int64_t end = GetEndTime();
NS_ASSERTION(mStartTime != -1, "Should know start time by now");
NS_ASSERTION(mEndTime != -1, "Should know end time by now");
NS_ASSERTION(end != -1, "Should know end time by now");
int64_t seekTime = aTarget.mTime + mStartTime;
seekTime = std::min(seekTime, mEndTime);
seekTime = std::min(seekTime, end);
seekTime = std::max(mStartTime, seekTime);
NS_ASSERTION(seekTime >= mStartTime && seekTime <= mEndTime,
NS_ASSERTION(seekTime >= mStartTime && seekTime <= end,
"Can only seek in range [0,duration]");
mSeekTarget = SeekTarget(seekTime, aTarget.mType);
@@ -2188,7 +2206,7 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
return NS_ERROR_FAILURE;
}
mDecoder->StartProgressUpdates();
mGotDurationFromMetaData = (GetDuration() != -1);
mGotDurationFromMetaData = (GetDuration() != -1) || mDurationSet;
if (mGotDurationFromMetaData) {
// We have all the information required: duration and size
@@ -2300,12 +2318,8 @@ MediaDecoderStateMachine::FinishDecodeFirstFrame()
}
NS_ASSERTION(mStartTime != -1, "Must have start time");
MOZ_ASSERT((!HasVideo() && !HasAudio()) ||
!(mDecoder->IsMediaSeekable() && mDecoder->IsTransportSeekable()) ||
mEndTime != -1,
"Active seekable media should have end time");
MOZ_ASSERT(!(mDecoder->IsMediaSeekable() && mDecoder->IsTransportSeekable()) ||
GetDuration() != -1,
(GetDuration() != -1) || mDurationSet,
"Seekable media should have duration");
DECODER_LOG("Media goes from %lld to %lld (duration %lld) "
"transportSeekable=%d, mediaSeekable=%d",
@@ -2429,7 +2443,7 @@ void MediaDecoderStateMachine::DecodeSeek()
// the reader, since it could do I/O or deadlock some other way.
res = mReader->ResetDecode();
if (NS_SUCCEEDED(res)) {
mReader->Seek(seekTime, mStartTime, mEndTime, mCurrentTimeBeforeSeek)
mReader->Seek(seekTime, mStartTime, GetEndTime(), mCurrentTimeBeforeSeek)
->Then(DecodeTaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnSeekCompleted,
&MediaDecoderStateMachine::OnSeekFailed);
@@ -3244,7 +3258,7 @@ void MediaDecoderStateMachine::SetStartTime(int64_t aStartTimeUsecs)
mStartTime = 0;
if (aStartTimeUsecs != 0) {
mStartTime = aStartTimeUsecs;
if (mGotDurationFromMetaData) {
if (mGotDurationFromMetaData && GetEndTime() != INT64_MAX) {
NS_ASSERTION(mEndTime != -1,
"We should have mEndTime as supplied duration here");
// We were specified a duration from a Content-Duration HTTP header.

View File

@@ -171,11 +171,18 @@ public:
// must be obtained before calling this. It is in units of microseconds.
int64_t GetDuration();
// Time of the last frame in the media, in microseconds or INT64_MAX if
// media has an infinite duration.
// Accessed on state machine, decode, and main threads.
// Access controlled by decoder monitor.
int64_t GetEndTime();
// Called from the main thread to set the duration of the media resource
// if it is able to be obtained via HTTP headers. Called from the
// state machine thread to set the duration if it is obtained from the
// media metadata. The decoder monitor must be obtained before calling this.
// aDuration is in microseconds.
// A value of INT64_MAX will be treated as infinity.
void SetDuration(int64_t aDuration);
// Called while decoding metadata to set the end time of the media
@@ -832,8 +839,14 @@ protected:
// Time of the last frame in the media, in microseconds. This is the
// end time of the last frame in the media. Accessed on state
// machine, decode, and main threads. Access controlled by decoder monitor.
// It will be set to -1 if the duration is infinite
int64_t mEndTime;
// Will be set when SetDuration has been called with a value != -1
// mDurationSet false doesn't indicate that we do not have a valid duration
// as mStartTime and mEndTime could have been set separately.
bool mDurationSet;
// Position to seek to in microseconds when the seek state transition occurs.
// The decoder monitor lock must be obtained before reading or writing
// this value. Accessed on main and decode thread.