diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index f486cd76e126..ef7d4bbb8239 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -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. diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h index a2f995a07577..280b067a0ab4 100644 --- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -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.