mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
Revert "Revert recent dom/media related changes. This should hopefully restore stability as 27 March 2021 build."
This reverts commit c5b776d07a.
This commit is contained in:
@@ -103,11 +103,10 @@ const int64_t NO_VIDEO_AMPLE_AUDIO_DIVISOR = 8;
|
||||
static const uint32_t LOW_VIDEO_FRAMES = 1;
|
||||
|
||||
// Threshold in usecs that used to check if we are low on decoded video.
|
||||
// If the last video frame's end time |mDecodedVideoEndTime| doesn't exceed
|
||||
// |clock time + LOW_VIDEO_THRESHOLD_USECS*mPlaybackRate| calculation in
|
||||
// Advanceframe(), we are low on decoded video frames and trying to skip to next
|
||||
// keyframe.
|
||||
static const int32_t LOW_VIDEO_THRESHOLD_USECS = 16000;
|
||||
// If the last video frame's end time |mDecodedVideoEndTime| is more than
|
||||
// |LOW_VIDEO_THRESHOLD_USECS*mPlaybackRate| after the current clock in
|
||||
// Advanceframe(), the video decode is lagging, and we skip to next keyframe.
|
||||
static const int32_t LOW_VIDEO_THRESHOLD_USECS = 60000;
|
||||
|
||||
// Arbitrary "frame duration" when playing only audio.
|
||||
static const int AUDIO_DURATION_USECS = 40000;
|
||||
@@ -181,18 +180,16 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
||||
bool aRealTime) :
|
||||
mDecoder(aDecoder),
|
||||
mTaskQueue(new MediaTaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
|
||||
/* aAssertTailDispatch = */ true)),
|
||||
/* aSupportsTailDispatch = */ true)),
|
||||
mWatchManager(this, mTaskQueue),
|
||||
mRealTime(aRealTime),
|
||||
mDispatchedStateMachine(false),
|
||||
mDelayedScheduler(this),
|
||||
mState(DECODER_STATE_DECODING_NONE, "MediaDecoderStateMachine::mState"),
|
||||
mPlayDuration(0),
|
||||
mStartTime(-1),
|
||||
mEndTime(-1),
|
||||
mDurationSet(false),
|
||||
mDuration(mTaskQueue, NullableTimeUnit(), "MediaDecoderStateMachine::mDuration (Canonical"),
|
||||
mEstimatedDuration(mTaskQueue, NullableTimeUnit(),
|
||||
"MediaDecoderStateMachine::EstimatedDuration (Mirror)"),
|
||||
"MediaDecoderStateMachine::mEstimatedDuration (Mirror)"),
|
||||
mExplicitDuration(mTaskQueue, Maybe<double>(),
|
||||
"MediaDecoderStateMachine::mExplicitDuration (Mirror)"),
|
||||
mObservedDuration(TimeUnit(), "MediaDecoderStateMachine::mObservedDuration"),
|
||||
@@ -207,7 +204,8 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
||||
mFragmentEndTime(-1),
|
||||
mReader(aReader),
|
||||
mCurrentPosition(mTaskQueue, 0, "MediaDecoderStateMachine::mCurrentPosition (Canonical)"),
|
||||
mAudioStartTime(-1),
|
||||
mStreamStartTime(0),
|
||||
mAudioStartTime(0),
|
||||
mAudioEndTime(-1),
|
||||
mDecodedAudioEndTime(-1),
|
||||
mVideoFrameEndTime(-1),
|
||||
@@ -216,7 +214,6 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
||||
mPlaybackRate(1.0),
|
||||
mLogicalPlaybackRate(mTaskQueue, 1.0, "MediaDecoderStateMachine::mLogicalPlaybackRate (Mirror)"),
|
||||
mPreservesPitch(mTaskQueue, true, "MediaDecoderStateMachine::mPreservesPitch (Mirror)"),
|
||||
mAmpleVideoFrames(MIN_VIDEO_QUEUE_SIZE),
|
||||
mLowAudioThresholdUsecs(detail::LOW_AUDIO_USECS),
|
||||
mAmpleAudioThresholdUsecs(detail::AMPLE_AUDIO_USECS),
|
||||
mQuickBufferingLowDataThresholdUsecs(detail::QUICK_BUFFERING_LOW_DATA_USECS),
|
||||
@@ -271,14 +268,20 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
||||
// timeEndPeriod() call.
|
||||
timeBeginPeriod(1);
|
||||
#endif
|
||||
|
||||
AudioQueue().AddPopListener(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::OnAudioPopped),
|
||||
mTaskQueue);
|
||||
|
||||
VideoQueue().AddPopListener(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::OnVideoPopped),
|
||||
mTaskQueue);
|
||||
}
|
||||
|
||||
MediaDecoderStateMachine::~MediaDecoderStateMachine()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread.");
|
||||
MOZ_COUNT_DTOR(MediaDecoderStateMachine);
|
||||
NS_ASSERTION(!mPendingWakeDecoder.get(),
|
||||
"WakeDecoder should have been revoked already");
|
||||
|
||||
mReader = nullptr;
|
||||
|
||||
@@ -317,7 +320,8 @@ MediaDecoderStateMachine::InitializationTask()
|
||||
mWatchManager.Watch(mLogicallySeeking, &MediaDecoderStateMachine::UpdateStreamBlockingForPlayState);
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::HasFutureAudio() {
|
||||
bool MediaDecoderStateMachine::HasFutureAudio()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
NS_ASSERTION(HasAudio(), "Should only call HasFutureAudio() when we have audio");
|
||||
@@ -332,14 +336,16 @@ bool MediaDecoderStateMachine::HasFutureAudio() {
|
||||
AudioQueue().IsFinished());
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::HaveNextFrameData() {
|
||||
bool MediaDecoderStateMachine::HaveNextFrameData()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
return (!HasAudio() || HasFutureAudio()) &&
|
||||
(!HasVideo() || VideoQueue().GetSize() > 0);
|
||||
}
|
||||
|
||||
int64_t MediaDecoderStateMachine::GetDecodedAudioDuration() {
|
||||
int64_t MediaDecoderStateMachine::GetDecodedAudioDuration()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
int64_t audioDecoded = AudioQueue().Duration();
|
||||
@@ -359,7 +365,7 @@ void MediaDecoderStateMachine::SendStreamAudio(AudioData* aAudio,
|
||||
// This logic has to mimic AudioSink closely to make sure we write
|
||||
// the exact same silences
|
||||
CheckedInt64 audioWrittenOffset = aStream->mAudioFramesWritten +
|
||||
UsecsToFrames(mInfo.mAudio.mRate, aStream->mInitialTime + mStartTime);
|
||||
UsecsToFrames(mInfo.mAudio.mRate, mStreamStartTime);
|
||||
CheckedInt64 frameOffset = UsecsToFrames(mInfo.mAudio.mRate, aAudio->mTime);
|
||||
|
||||
if (!audioWrittenOffset.isValid() ||
|
||||
@@ -434,15 +440,18 @@ void MediaDecoderStateMachine::SendStreamData()
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
MOZ_ASSERT(!mAudioSink, "Should've been stopped in RunStateMachine()");
|
||||
MOZ_ASSERT(mStreamStartTime != -1);
|
||||
|
||||
DecodedStreamData* stream = GetDecodedStream();
|
||||
|
||||
bool finished =
|
||||
(!mInfo.HasAudio() || AudioQueue().IsFinished()) &&
|
||||
(!mInfo.HasVideo() || VideoQueue().IsFinished());
|
||||
if (mDecoder->IsSameOriginMedia()) {
|
||||
|
||||
{
|
||||
SourceMediaStream* mediaStream = stream->mStream;
|
||||
StreamTime endPosition = 0;
|
||||
const bool isSameOrigin = mDecoder->IsSameOriginMedia();
|
||||
|
||||
if (!stream->mStreamInitialized) {
|
||||
if (mInfo.HasAudio()) {
|
||||
@@ -450,23 +459,14 @@ void MediaDecoderStateMachine::SendStreamData()
|
||||
AudioSegment* audio = new AudioSegment();
|
||||
mediaStream->AddAudioTrack(audioTrackId, mInfo.mAudio.mRate, 0, audio,
|
||||
SourceMediaStream::ADDTRACK_QUEUED);
|
||||
stream->mStream->DispatchWhenNotEnoughBuffered(audioTrackId,
|
||||
TaskQueue(), GetWakeDecoderRunnable());
|
||||
stream->mNextAudioTime = mStartTime + stream->mInitialTime;
|
||||
stream->mNextAudioTime = mStreamStartTime;
|
||||
}
|
||||
if (mInfo.HasVideo()) {
|
||||
TrackID videoTrackId = mInfo.mVideo.mTrackId;
|
||||
VideoSegment* video = new VideoSegment();
|
||||
mediaStream->AddTrack(videoTrackId, 0, video,
|
||||
SourceMediaStream::ADDTRACK_QUEUED);
|
||||
stream->mStream->DispatchWhenNotEnoughBuffered(videoTrackId,
|
||||
TaskQueue(), GetWakeDecoderRunnable());
|
||||
|
||||
// TODO: We can't initialize |mNextVideoTime| until |mStartTime|
|
||||
// is set. This is a good indication that DecodedStreamData is in
|
||||
// deep coupling with the state machine and we should move the class
|
||||
// into MediaDecoderStateMachine.
|
||||
stream->mNextVideoTime = mStartTime + stream->mInitialTime;
|
||||
stream->mNextVideoTime = mStreamStartTime;
|
||||
}
|
||||
mediaStream->FinishAddTracks();
|
||||
stream->mStreamInitialized = true;
|
||||
@@ -489,6 +489,9 @@ void MediaDecoderStateMachine::SendStreamData()
|
||||
for (uint32_t i = 0; i < audio.Length(); ++i) {
|
||||
SendStreamAudio(audio[i], stream, &output);
|
||||
}
|
||||
if (!isSameOrigin) {
|
||||
output.ReplaceWithDisabled();
|
||||
}
|
||||
// |mNextAudioTime| is updated as we process each audio sample in
|
||||
// SendStreamAudio(). This is consistent with how |mNextVideoTime|
|
||||
// is updated for video samples.
|
||||
@@ -502,6 +505,12 @@ void MediaDecoderStateMachine::SendStreamData()
|
||||
endPosition = std::max(endPosition,
|
||||
mediaStream->TicksToTimeRoundDown(mInfo.mAudio.mRate,
|
||||
stream->mAudioFramesWritten));
|
||||
|
||||
CheckedInt64 playedUsecs = mStreamStartTime +
|
||||
FramesToUsecs(stream->mAudioFramesWritten, mInfo.mAudio.mRate);
|
||||
if (playedUsecs.isValid()) {
|
||||
OnAudioEndTimeUpdate(playedUsecs.value());
|
||||
}
|
||||
}
|
||||
|
||||
if (mInfo.HasVideo()) {
|
||||
@@ -545,6 +554,9 @@ void MediaDecoderStateMachine::SendStreamData()
|
||||
v->mTime, v->GetEndTime());
|
||||
}
|
||||
}
|
||||
if (!isSameOrigin) {
|
||||
output.ReplaceWithDisabled();
|
||||
}
|
||||
if (output.GetDuration() > 0) {
|
||||
mediaStream->AppendToTrack(videoTrackId, &output);
|
||||
}
|
||||
@@ -554,7 +566,7 @@ void MediaDecoderStateMachine::SendStreamData()
|
||||
}
|
||||
endPosition = std::max(endPosition,
|
||||
mediaStream->MicrosecondsToStreamTimeRoundDown(
|
||||
stream->mNextVideoTime - stream->mInitialTime - mStartTime));
|
||||
stream->mNextVideoTime - mStreamStartTime));
|
||||
}
|
||||
|
||||
if (!stream->mHaveSentFinish) {
|
||||
@@ -575,8 +587,7 @@ void MediaDecoderStateMachine::SendStreamData()
|
||||
// Therefore we only discard those behind the stream clock to throttle
|
||||
// the decoding speed.
|
||||
if (a && a->mTime <= clockTime) {
|
||||
OnAudioEndTimeUpdate(std::max(mAudioEndTime, a->GetEndTime()));
|
||||
nsRefPtr<AudioData> releaseMe = PopAudio();
|
||||
nsRefPtr<AudioData> releaseMe = AudioQueue().PopFront();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@@ -589,18 +600,6 @@ void MediaDecoderStateMachine::SendStreamData()
|
||||
}
|
||||
}
|
||||
|
||||
MediaDecoderStateMachine::WakeDecoderRunnable*
|
||||
MediaDecoderStateMachine::GetWakeDecoderRunnable()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
||||
if (!mPendingWakeDecoder.get()) {
|
||||
mPendingWakeDecoder = new WakeDecoderRunnable(this);
|
||||
}
|
||||
return mPendingWakeDecoder.get();
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
@@ -622,8 +621,6 @@ bool MediaDecoderStateMachine::HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs)
|
||||
if (!stream->mStream->HaveEnoughBuffered(audioTrackId)) {
|
||||
return false;
|
||||
}
|
||||
stream->mStream->DispatchWhenNotEnoughBuffered(audioTrackId,
|
||||
TaskQueue(), GetWakeDecoderRunnable());
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -634,7 +631,7 @@ bool MediaDecoderStateMachine::HaveEnoughDecodedVideo()
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
||||
if (static_cast<uint32_t>(VideoQueue().GetSize()) < mAmpleVideoFrames * mPlaybackRate) {
|
||||
if (static_cast<uint32_t>(VideoQueue().GetSize()) < GetAmpleVideoFrames() * mPlaybackRate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -646,8 +643,6 @@ bool MediaDecoderStateMachine::HaveEnoughDecodedVideo()
|
||||
if (!stream->mStream->HaveEnoughBuffered(videoTrackId)) {
|
||||
return false;
|
||||
}
|
||||
stream->mStream->DispatchWhenNotEnoughBuffered(videoTrackId,
|
||||
TaskQueue(), GetWakeDecoderRunnable());
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -693,7 +688,7 @@ MediaDecoderStateMachine::NeedToSkipToNextKeyframe()
|
||||
return false;
|
||||
}
|
||||
|
||||
// We'll skip the video decode to the nearest keyframe if we're low on
|
||||
// We'll skip the video decode to the next keyframe if we're low on
|
||||
// audio, or if we're low on video, provided we're not running low on
|
||||
// data to decode. If we're running low on downloaded data to decode,
|
||||
// we won't start keyframe skipping, as we'll be pausing playback to buffer
|
||||
@@ -706,9 +701,10 @@ MediaDecoderStateMachine::NeedToSkipToNextKeyframe()
|
||||
(GetDecodedAudioDuration() <
|
||||
mLowAudioThresholdUsecs * mPlaybackRate);
|
||||
bool isLowOnDecodedVideo = !mIsVideoPrerolling &&
|
||||
(mDecodedVideoEndTime - GetClock() <
|
||||
LOW_VIDEO_THRESHOLD_USECS * mPlaybackRate);
|
||||
((GetClock() - mDecodedVideoEndTime) * mPlaybackRate >
|
||||
LOW_VIDEO_THRESHOLD_USECS);
|
||||
bool lowUndecoded = HasLowUndecodedData();
|
||||
|
||||
if ((isLowOnDecodedAudio || isLowOnDecodedVideo) && !lowUndecoded) {
|
||||
DECODER_LOG("Skipping video decode to the next keyframe lowAudio=%d lowVideo=%d lowUndecoded=%d async=%d",
|
||||
isLowOnDecodedAudio, isLowOnDecodedVideo, lowUndecoded, mReader->IsAsync());
|
||||
@@ -902,22 +898,25 @@ MediaDecoderStateMachine::PushFront(VideoData* aSample)
|
||||
UpdateNextFrameStatus();
|
||||
}
|
||||
|
||||
already_AddRefed<AudioData>
|
||||
MediaDecoderStateMachine::PopAudio()
|
||||
void
|
||||
MediaDecoderStateMachine::OnAudioPopped()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
nsRefPtr<AudioData> sample = AudioQueue().PopFront();
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
UpdateNextFrameStatus();
|
||||
return sample.forget();
|
||||
DispatchAudioDecodeTaskIfNeeded();
|
||||
}
|
||||
|
||||
already_AddRefed<VideoData>
|
||||
MediaDecoderStateMachine::PopVideo()
|
||||
void
|
||||
MediaDecoderStateMachine::OnVideoPopped()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
nsRefPtr<VideoData> sample = VideoQueue().PopFront();
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
UpdateNextFrameStatus();
|
||||
return sample.forget();
|
||||
DispatchVideoDecodeTaskIfNeeded();
|
||||
// Notify the decode thread that the video queue's buffers may have
|
||||
// free'd up space for more frames.
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1240,10 +1239,6 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoderStateMachine* aCloneDonor)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (NS_WARN_IF(!mReader->EnsureTaskQueue())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MediaDecoderReader* cloneReader = nullptr;
|
||||
if (aCloneDonor) {
|
||||
cloneReader = aCloneDonor->mReader;
|
||||
@@ -1265,7 +1260,7 @@ void MediaDecoderStateMachine::StopPlayback()
|
||||
mDecoder->NotifyPlaybackStopped();
|
||||
|
||||
if (IsPlaying()) {
|
||||
mPlayDuration = GetClock() - mStartTime;
|
||||
mPlayDuration = GetClock();
|
||||
SetPlayStartTime(TimeStamp());
|
||||
}
|
||||
// Notify the audio sink, so that it notices that we've stopped playing,
|
||||
@@ -1317,11 +1312,10 @@ void MediaDecoderStateMachine::MaybeStartPlayback()
|
||||
void MediaDecoderStateMachine::UpdatePlaybackPositionInternal(int64_t aTime)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
SAMPLE_LOG("UpdatePlaybackPositionInternal(%lld) (mStartTime=%lld)", aTime, mStartTime);
|
||||
SAMPLE_LOG("UpdatePlaybackPositionInternal(%lld)", aTime);
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
||||
NS_ASSERTION(mStartTime >= 0, "Should have positive mStartTime");
|
||||
mCurrentPosition = aTime - mStartTime;
|
||||
mCurrentPosition = aTime;
|
||||
NS_ASSERTION(mCurrentPosition >= 0, "CurrentTime should be positive!");
|
||||
mObservedDuration = std::max(mObservedDuration.Ref(),
|
||||
TimeUnit::FromMicroseconds(mCurrentPosition.Ref()));
|
||||
@@ -1388,37 +1382,11 @@ void MediaDecoderStateMachine::VolumeChanged()
|
||||
}
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::IsRealTime() const {
|
||||
return mRealTime;
|
||||
}
|
||||
|
||||
int64_t MediaDecoderStateMachine::GetDuration()
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
||||
if (mEndTime == -1 || mStartTime == -1)
|
||||
return -1;
|
||||
return mEndTime - mStartTime;
|
||||
}
|
||||
|
||||
int64_t MediaDecoderStateMachine::GetEndTime()
|
||||
{
|
||||
if (mEndTime == -1 && mDurationSet) {
|
||||
return INT64_MAX;
|
||||
}
|
||||
return mEndTime;
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::RecomputeDuration()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
|
||||
// We dispatch DurationChanged to the MediaDecoder when the duration changes
|
||||
// sometime after initialization, unless it has already been fired by the code
|
||||
// that set the new duration.
|
||||
bool fireDurationChanged = false;
|
||||
|
||||
TimeUnit duration;
|
||||
if (mExplicitDuration.Ref().isSome()) {
|
||||
double d = mExplicitDuration.Ref().ref();
|
||||
@@ -1432,7 +1400,6 @@ void MediaDecoderStateMachine::RecomputeDuration()
|
||||
duration = TimeUnit::FromSeconds(d);
|
||||
} else if (mEstimatedDuration.Ref().isSome()) {
|
||||
duration = mEstimatedDuration.Ref().ref();
|
||||
fireDurationChanged = true;
|
||||
} else if (mInfo.mMetadataDuration.isSome()) {
|
||||
duration = mInfo.mMetadataDuration.ref();
|
||||
} else {
|
||||
@@ -1441,42 +1408,10 @@ void MediaDecoderStateMachine::RecomputeDuration()
|
||||
|
||||
if (duration < mObservedDuration.Ref()) {
|
||||
duration = mObservedDuration;
|
||||
fireDurationChanged = true;
|
||||
}
|
||||
|
||||
fireDurationChanged = fireDurationChanged && duration.ToMicroseconds() != GetDuration();
|
||||
SetDuration(duration);
|
||||
|
||||
if (fireDurationChanged) {
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethodWithArg<TimeUnit>(mDecoder, &MediaDecoder::DurationChanged, duration);
|
||||
AbstractThread::MainThread()->Dispatch(event.forget());
|
||||
}
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::SetDuration(TimeUnit aDuration)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
MOZ_ASSERT(aDuration.ToMicroseconds() >= 0);
|
||||
if (mStartTime == -1) {
|
||||
SetStartTime(0);
|
||||
}
|
||||
mDurationSet = true;
|
||||
|
||||
if (aDuration.IsInfinite()) {
|
||||
mEndTime = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
mEndTime = mStartTime + aDuration.ToMicroseconds();
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::SetFragmentEndTime(int64_t aEndTime)
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
||||
mFragmentEndTime = aEndTime < 0 ? aEndTime : aEndTime + mStartTime;
|
||||
MOZ_ASSERT(duration.ToMicroseconds() >= 0);
|
||||
mDuration = Some(duration);
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::IsDormantNeeded()
|
||||
@@ -1537,8 +1472,6 @@ void MediaDecoderStateMachine::SetDormant(bool aDormant)
|
||||
// it here as well.
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(mReader, &MediaDecoderReader::ReleaseMediaResources);
|
||||
DecodeTaskQueue()->Dispatch(r.forget());
|
||||
// There's now no possibility of mPendingWakeDecoder being needed again. Revoke it.
|
||||
mPendingWakeDecoder = nullptr;
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
} else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) {
|
||||
mDecodingFrozenAtStateDecoding = true;
|
||||
@@ -1691,24 +1624,26 @@ void MediaDecoderStateMachine::NotifyDataArrived(const char* aBuffer,
|
||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||
mReader->NotifyDataArrived(aBuffer, aLength, aOffset);
|
||||
|
||||
// While playing an unseekable stream of unknown duration, mEndTime is
|
||||
// While playing an unseekable stream of unknown duration, mDuration is
|
||||
// updated (in AdvanceFrame()) as we play. But if data is being downloaded
|
||||
// faster than played, mEndTime won't reflect the end of playable data
|
||||
// faster than played, mDuration won't reflect the end of playable data
|
||||
// since we haven't played the frame at the end of buffered data. So update
|
||||
// mEndTime here as new data is downloaded to prevent such a lag.
|
||||
// mDuration here as new data is downloaded to prevent such a lag.
|
||||
//
|
||||
// Make sure to only do this if we have a start time, otherwise the reader
|
||||
// doesn't know how to compute GetBuffered.
|
||||
if (!mDecoder->IsInfinite() || mStartTime == -1) {
|
||||
if (!mDecoder->IsInfinite() || !HaveStartTime())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
media::TimeIntervals buffered{mDecoder->GetBuffered()};
|
||||
if (!buffered.IsInvalid()) {
|
||||
bool exists;
|
||||
media::TimeUnit end{buffered.GetEnd(&exists)};
|
||||
if (exists) {
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mEndTime = std::max<int64_t>(mEndTime, end.ToMicroseconds());
|
||||
mDuration = Some(std::max<TimeUnit>(Duration(), end));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1856,26 +1791,19 @@ MediaDecoderStateMachine::InitiateSeek()
|
||||
mCurrentSeek.Steal(mPendingSeek);
|
||||
|
||||
// Bound the seek time to be inside the media range.
|
||||
int64_t end = GetEndTime();
|
||||
NS_ASSERTION(mStartTime != -1, "Should know start time by now");
|
||||
int64_t end = Duration().ToMicroseconds();
|
||||
NS_ASSERTION(end != -1, "Should know end time by now");
|
||||
int64_t seekTime = mCurrentSeek.mTarget.mTime + mStartTime;
|
||||
int64_t seekTime = mCurrentSeek.mTarget.mTime;
|
||||
seekTime = std::min(seekTime, end);
|
||||
seekTime = std::max(mStartTime, seekTime);
|
||||
NS_ASSERTION(seekTime >= mStartTime && seekTime <= end,
|
||||
"Can only seek in range [0,duration]");
|
||||
seekTime = std::max(int64_t(0), seekTime);
|
||||
NS_ASSERTION(seekTime >= 0 && seekTime <= end,
|
||||
"Can only seek in range [0,duration]");
|
||||
mCurrentSeek.mTarget.mTime = seekTime;
|
||||
|
||||
if (mAudioCaptured) {
|
||||
// TODO: We should re-create the decoded stream after seek completed as we do
|
||||
// for audio thread since it is until then we know which position we seek to
|
||||
// as far as fast-seek is concerned. It also fix the problem where stream
|
||||
// clock seems to go backwards during seeking.
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethodWithArg<int64_t>(this,
|
||||
&MediaDecoderStateMachine::RecreateDecodedStream,
|
||||
seekTime - mStartTime);
|
||||
AbstractThread::MainThread()->Dispatch(event.forget());
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethodWithArgs<MediaStreamGraph*>(
|
||||
this, &MediaDecoderStateMachine::RecreateDecodedStream, nullptr);
|
||||
AbstractThread::MainThread()->Dispatch(r.forget());
|
||||
}
|
||||
|
||||
mDropAudioUntilNextDiscontinuity = HasAudio();
|
||||
@@ -1904,7 +1832,7 @@ MediaDecoderStateMachine::InitiateSeek()
|
||||
nsRefPtr<MediaDecoderStateMachine> self = this;
|
||||
mSeekRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
|
||||
&MediaDecoderReader::Seek, mCurrentSeek.mTarget.mTime,
|
||||
GetEndTime())
|
||||
Duration().ToMicroseconds())
|
||||
->Then(TaskQueue(), __func__,
|
||||
[self] (int64_t) -> void {
|
||||
ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
|
||||
@@ -2115,7 +2043,7 @@ bool MediaDecoderStateMachine::HasLowUndecodedData(int64_t aUsecs)
|
||||
// If we don't have a duration, GetBuffered is probably not going to produce
|
||||
// a useful buffered range. Return false here so that we don't get stuck in
|
||||
// buffering mode for live streams.
|
||||
if (GetDuration() < 0) {
|
||||
if (Duration().IsInfinite()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2136,13 +2064,12 @@ bool MediaDecoderStateMachine::HasLowUndecodedData(int64_t aUsecs)
|
||||
endOfDecodedAudioData = mDecodedAudioEndTime;
|
||||
}
|
||||
int64_t endOfDecodedData = std::min(endOfDecodedVideoData, endOfDecodedAudioData);
|
||||
|
||||
if (GetDuration() < endOfDecodedData) {
|
||||
if (Duration().ToMicroseconds() < endOfDecodedData) {
|
||||
// Our duration is not up to date. No point buffering.
|
||||
return false;
|
||||
}
|
||||
media::TimeInterval interval(media::TimeUnit::FromMicroseconds(endOfDecodedData),
|
||||
media::TimeUnit::FromMicroseconds(std::min(endOfDecodedData + aUsecs, GetDuration())));
|
||||
media::TimeUnit::FromMicroseconds(std::min(endOfDecodedData + aUsecs, Duration().ToMicroseconds())));
|
||||
return endOfDecodedData != INT64_MAX && !buffered.Contains(interval);
|
||||
}
|
||||
|
||||
@@ -2217,13 +2144,10 @@ MediaDecoderStateMachine::OnMetadataRead(MetadataHolder* aMetadata)
|
||||
}
|
||||
|
||||
if (HasVideo()) {
|
||||
mAmpleVideoFrames = (mReader->IsAsync() && mInfo.mVideo.mIsHardwareAccelerated)
|
||||
? std::max<uint32_t>(sVideoQueueHWAccelSize, MIN_VIDEO_QUEUE_SIZE)
|
||||
: std::max<uint32_t>(sVideoQueueDefaultSize, MIN_VIDEO_QUEUE_SIZE);
|
||||
DECODER_LOG("Video decode isAsync=%d HWAccel=%d videoQueueSize=%d",
|
||||
mReader->IsAsync(),
|
||||
mInfo.mVideo.mIsHardwareAccelerated,
|
||||
mAmpleVideoFrames);
|
||||
mReader->VideoIsHardwareAccelerated(),
|
||||
GetAmpleVideoFrames());
|
||||
}
|
||||
|
||||
mDecoder->StartProgressUpdates();
|
||||
@@ -2234,7 +2158,7 @@ MediaDecoderStateMachine::OnMetadataRead(MetadataHolder* aMetadata)
|
||||
// feeding in the CDM, which we need to decode the first frame (and
|
||||
// thus get the metadata). We could fix this if we could compute the start
|
||||
// time by demuxing without necessaring decoding.
|
||||
mNotifyMetadataBeforeFirstFrame = mDurationSet || mReader->IsWaitingOnCDMResource();
|
||||
mNotifyMetadataBeforeFirstFrame = mDuration.Ref().isSome() || mReader->IsWaitingOnCDMResource();
|
||||
if (mNotifyMetadataBeforeFirstFrame) {
|
||||
EnqueueLoadedMetadataEvent();
|
||||
}
|
||||
@@ -2320,26 +2244,13 @@ MediaDecoderStateMachine::DecodeFirstFrame()
|
||||
MOZ_ASSERT(mState == DECODER_STATE_DECODING_FIRSTFRAME);
|
||||
DECODER_LOG("DecodeFirstFrame started");
|
||||
|
||||
if (HasAudio()) {
|
||||
RefPtr<nsIRunnable> decodeTask(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchAudioDecodeTaskIfNeeded));
|
||||
AudioQueue().AddPopListener(decodeTask, TaskQueue());
|
||||
}
|
||||
if (HasVideo()) {
|
||||
RefPtr<nsIRunnable> decodeTask(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchVideoDecodeTaskIfNeeded));
|
||||
VideoQueue().AddPopListener(decodeTask, TaskQueue());
|
||||
}
|
||||
|
||||
if (IsRealTime()) {
|
||||
SetStartTime(0);
|
||||
nsresult res = FinishDecodeFirstFrame();
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
} else if (mSentFirstFrameLoadedEvent) {
|
||||
// We're resuming from dormant state, so we don't need to request
|
||||
// the first samples in order to determine the media start time,
|
||||
// we have the start time from last time we loaded.
|
||||
SetStartTime(mStartTime);
|
||||
nsresult res = FinishDecodeFirstFrame();
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
} else {
|
||||
@@ -2386,23 +2297,20 @@ MediaDecoderStateMachine::FinishDecodeFirstFrame()
|
||||
}
|
||||
|
||||
if (!IsRealTime() && !mSentFirstFrameLoadedEvent) {
|
||||
const VideoData* v = VideoQueue().PeekFront();
|
||||
const AudioData* a = AudioQueue().PeekFront();
|
||||
SetStartTime(mReader->ComputeStartTime(v, a));
|
||||
if (VideoQueue().GetSize()) {
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
RenderVideoFrame(VideoQueue().PeekFront(), TimeStamp::Now());
|
||||
}
|
||||
}
|
||||
|
||||
NS_ASSERTION(mStartTime != -1, "Must have start time");
|
||||
MOZ_ASSERT(!(mDecoder->IsMediaSeekable() && mDecoder->IsTransportSeekable()) ||
|
||||
(GetDuration() != -1) || mDurationSet,
|
||||
"Seekable media should have duration");
|
||||
DECODER_LOG("Media goes from %lld to %lld (duration %lld) "
|
||||
// If we don't know the duration by this point, we assume infinity, per spec.
|
||||
if (mDuration.Ref().isNothing()) {
|
||||
mDuration = Some(TimeUnit::FromInfinity());
|
||||
}
|
||||
|
||||
DECODER_LOG("Media duration %lld, "
|
||||
"transportSeekable=%d, mediaSeekable=%d",
|
||||
mStartTime, mEndTime, GetDuration(),
|
||||
mDecoder->IsTransportSeekable(), mDecoder->IsMediaSeekable());
|
||||
Duration().ToMicroseconds(), mDecoder->IsTransportSeekable(), mDecoder->IsMediaSeekable());
|
||||
|
||||
if (HasAudio() && !HasVideo()) {
|
||||
// We're playing audio only. We don't need to worry about slow video
|
||||
@@ -2435,7 +2343,6 @@ MediaDecoderStateMachine::FinishDecodeFirstFrame()
|
||||
// So we need to check if this has occurred, else our decode pipeline won't
|
||||
// run (since it doesn't need to) and we won't detect end of stream.
|
||||
CheckIfDecodeComplete();
|
||||
MaybeStartPlayback();
|
||||
|
||||
if (mQueuedSeek.Exists()) {
|
||||
mPendingSeek.Steal(mQueuedSeek);
|
||||
@@ -2458,7 +2365,7 @@ MediaDecoderStateMachine::SeekCompleted()
|
||||
|
||||
// Setup timestamp state.
|
||||
nsRefPtr<VideoData> video = VideoQueue().PeekFront();
|
||||
if (seekTime == mEndTime) {
|
||||
if (seekTime == Duration().ToMicroseconds()) {
|
||||
newCurrentTime = mAudioStartTime = seekTime;
|
||||
} else if (HasAudio()) {
|
||||
AudioData* audio = AudioQueue().PeekFront();
|
||||
@@ -2466,7 +2373,8 @@ MediaDecoderStateMachine::SeekCompleted()
|
||||
} else {
|
||||
newCurrentTime = video ? video->mTime : seekTime;
|
||||
}
|
||||
mPlayDuration = newCurrentTime - mStartTime;
|
||||
mStreamStartTime = newCurrentTime;
|
||||
mPlayDuration = newCurrentTime;
|
||||
|
||||
mDecoder->StartProgressUpdates();
|
||||
|
||||
@@ -2480,7 +2388,7 @@ MediaDecoderStateMachine::SeekCompleted()
|
||||
// for the seeking.
|
||||
DECODER_LOG("A new seek came along while we were finishing the old one - staying in SEEKING");
|
||||
SetState(DECODER_STATE_SEEKING);
|
||||
} else if (GetMediaTime() == mEndTime && !isLiveStream) {
|
||||
} else if (GetMediaTime() == Duration().ToMicroseconds() && !isLiveStream) {
|
||||
// Seeked to end of media, move to COMPLETED state. Note we don't do
|
||||
// this if we're playing a live stream, since the end of media will advance
|
||||
// once we download more data!
|
||||
@@ -2553,10 +2461,6 @@ MediaDecoderStateMachine::FinishShutdown()
|
||||
AudioQueue().ClearListeners();
|
||||
VideoQueue().ClearListeners();
|
||||
|
||||
// Now that those threads are stopped, there's no possibility of
|
||||
// mPendingWakeDecoder being needed again. Revoke it.
|
||||
mPendingWakeDecoder = nullptr;
|
||||
|
||||
// Disconnect canonicals and mirrors before shutting down our task queue.
|
||||
mEstimatedDuration.DisconnectIfConnected();
|
||||
mExplicitDuration.DisconnectIfConnected();
|
||||
@@ -2566,6 +2470,7 @@ MediaDecoderStateMachine::FinishShutdown()
|
||||
mVolume.DisconnectIfConnected();
|
||||
mLogicalPlaybackRate.DisconnectIfConnected();
|
||||
mPreservesPitch.DisconnectIfConnected();
|
||||
mDuration.DisconnectAll();
|
||||
mNextFrameStatus.DisconnectAll();
|
||||
mCurrentPosition.DisconnectAll();
|
||||
|
||||
@@ -2603,11 +2508,6 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
||||
mDelayedScheduler.Reset(); // Must happen on state machine task queue.
|
||||
mDispatchedStateMachine = false;
|
||||
|
||||
// If audio is being captured, stop the audio sink if it's running
|
||||
if (mAudioCaptured) {
|
||||
StopAudioThread();
|
||||
}
|
||||
|
||||
MediaResource* resource = mDecoder->GetResource();
|
||||
NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER);
|
||||
|
||||
@@ -2653,11 +2553,11 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
||||
// Start playback if necessary so that the clock can be properly queried.
|
||||
MaybeStartPlayback();
|
||||
|
||||
AdvanceFrame();
|
||||
UpdateRenderedVideoFrames();
|
||||
NS_ASSERTION(!IsPlaying() ||
|
||||
mLogicallySeeking ||
|
||||
IsStateMachineScheduled() ||
|
||||
mPlaybackRate == 0.0, "Must have timer scheduled");
|
||||
IsStateMachineScheduled(),
|
||||
"Must have timer scheduled");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -2727,10 +2627,10 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
||||
{
|
||||
// Start playback if necessary to play the remaining media.
|
||||
MaybeStartPlayback();
|
||||
AdvanceFrame();
|
||||
UpdateRenderedVideoFrames();
|
||||
NS_ASSERTION(!IsPlaying() ||
|
||||
mLogicallySeeking ||
|
||||
mPlaybackRate == 0 || IsStateMachineScheduled(),
|
||||
IsStateMachineScheduled(),
|
||||
"Must have timer scheduled");
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -2752,7 +2652,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
||||
!mSentPlaybackEndedEvent)
|
||||
{
|
||||
int64_t clockTime = std::max(mAudioEndTime, mVideoFrameEndTime);
|
||||
clockTime = std::max(int64_t(0), std::max(clockTime, mEndTime));
|
||||
clockTime = std::max(int64_t(0), std::max(clockTime, Duration().ToMicroseconds()));
|
||||
UpdatePlaybackPosition(clockTime);
|
||||
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
@@ -2791,7 +2691,8 @@ MediaDecoderStateMachine::Reset()
|
||||
|
||||
mVideoFrameEndTime = -1;
|
||||
mDecodedVideoEndTime = -1;
|
||||
mAudioStartTime = -1;
|
||||
mStreamStartTime = 0;
|
||||
mAudioStartTime = 0;
|
||||
mAudioEndTime = -1;
|
||||
mDecodedAudioEndTime = -1;
|
||||
mAudioCompleted = false;
|
||||
@@ -2855,7 +2756,7 @@ void MediaDecoderStateMachine::ResyncAudioClock()
|
||||
AssertCurrentThreadInMonitor();
|
||||
if (IsPlaying()) {
|
||||
SetPlayStartTime(TimeStamp::Now());
|
||||
mPlayDuration = GetAudioClock() - mStartTime;
|
||||
mPlayDuration = GetAudioClock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2872,19 +2773,28 @@ MediaDecoderStateMachine::GetAudioClock() const
|
||||
(mAudioSink ? mAudioSink->GetPosition() : 0);
|
||||
}
|
||||
|
||||
int64_t MediaDecoderStateMachine::GetStreamClock() const
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
MOZ_ASSERT(mStreamStartTime != -1);
|
||||
return mStreamStartTime + GetDecodedStream()->GetPosition();
|
||||
}
|
||||
|
||||
int64_t MediaDecoderStateMachine::GetVideoStreamPosition() const
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
||||
if (!IsPlaying()) {
|
||||
return mPlayDuration + mStartTime;
|
||||
return mPlayDuration;
|
||||
}
|
||||
|
||||
// Time elapsed since we started playing.
|
||||
int64_t delta = DurationToUsecs(TimeStamp::Now() - mPlayStartTime);
|
||||
// Take playback rate into account.
|
||||
delta *= mPlaybackRate;
|
||||
return mStartTime + mPlayDuration + delta;
|
||||
return mPlayDuration + delta;
|
||||
}
|
||||
|
||||
int64_t MediaDecoderStateMachine::GetClock() const
|
||||
@@ -2898,28 +2808,23 @@ int64_t MediaDecoderStateMachine::GetClock() const
|
||||
// fed to a MediaStream, use that stream as the source of the clock.
|
||||
int64_t clock_time = -1;
|
||||
if (!IsPlaying()) {
|
||||
clock_time = mPlayDuration + mStartTime;
|
||||
clock_time = mPlayDuration;
|
||||
} else {
|
||||
if (mAudioCaptured) {
|
||||
clock_time = mStartTime + GetDecodedStream()->GetClock();
|
||||
clock_time = GetStreamClock();
|
||||
} else if (HasAudio() && !mAudioCompleted) {
|
||||
clock_time = GetAudioClock();
|
||||
} else {
|
||||
// Audio is disabled on this system. Sync to the system clock.
|
||||
clock_time = GetVideoStreamPosition();
|
||||
}
|
||||
// Ensure the clock can never go backwards.
|
||||
// Note we allow clock going backwards in capture mode during seeking.
|
||||
NS_ASSERTION(GetMediaTime() <= clock_time ||
|
||||
mPlaybackRate <= 0 ||
|
||||
(mAudioCaptured && mState == DECODER_STATE_SEEKING),
|
||||
"Clock should go forwards.");
|
||||
NS_ASSERTION(GetMediaTime() <= clock_time, "Clock should go forwards.");
|
||||
}
|
||||
|
||||
return clock_time;
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::AdvanceFrame()
|
||||
void MediaDecoderStateMachine::UpdateRenderedVideoFrames()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
@@ -2930,12 +2835,6 @@ void MediaDecoderStateMachine::AdvanceFrame()
|
||||
return;
|
||||
}
|
||||
|
||||
// If playbackRate is 0.0, we should stop the progress, but not be in paused
|
||||
// state, per spec.
|
||||
if (mPlaybackRate == 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mAudioCaptured) {
|
||||
SendStreamData();
|
||||
}
|
||||
@@ -2945,7 +2844,7 @@ void MediaDecoderStateMachine::AdvanceFrame()
|
||||
// Skip frames up to the frame at the playback position, and figure out
|
||||
// the time remaining until it's time to display the next frame.
|
||||
int64_t remainingTime = AUDIO_DURATION_USECS;
|
||||
NS_ASSERTION(clock_time >= mStartTime, "Should have positive clock time.");
|
||||
NS_ASSERTION(clock_time >= 0, "Should have positive clock time.");
|
||||
nsRefPtr<VideoData> currentFrame;
|
||||
if (VideoQueue().GetSize() > 0) {
|
||||
VideoData* frame = VideoQueue().PeekFront();
|
||||
@@ -2958,10 +2857,7 @@ void MediaDecoderStateMachine::AdvanceFrame()
|
||||
currentFrame->mTime, clock_time, ++droppedFrames);
|
||||
}
|
||||
currentFrame = frame;
|
||||
nsRefPtr<VideoData> releaseMe = PopVideo();
|
||||
// Notify the decode thread that the video queue's buffers may have
|
||||
// free'd up space for more frames.
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
nsRefPtr<VideoData> releaseMe = VideoQueue().PopFront();
|
||||
OnPlaybackOffsetUpdate(frame->mOffset);
|
||||
if (VideoQueue().GetSize() == 0)
|
||||
break;
|
||||
@@ -3001,12 +2897,6 @@ void MediaDecoderStateMachine::AdvanceFrame()
|
||||
}
|
||||
}
|
||||
|
||||
// We've got enough data to keep playing until at least the next frame.
|
||||
// Start playing now if need be.
|
||||
if ((mFragmentEndTime >= 0 && clock_time < mFragmentEndTime) || mFragmentEndTime < 0) {
|
||||
MaybeStartPlayback();
|
||||
}
|
||||
|
||||
// Cap the current time to the larger of the audio and video end time.
|
||||
// This ensures that if we're running off the system clock, we don't
|
||||
// advance the clock to after the media end time.
|
||||
@@ -3026,12 +2916,8 @@ void MediaDecoderStateMachine::AdvanceFrame()
|
||||
// Decode one frame and display it.
|
||||
int64_t delta = currentFrame->mTime - clock_time;
|
||||
TimeStamp presTime = nowTime + TimeDuration::FromMicroseconds(delta / mPlaybackRate);
|
||||
NS_ASSERTION(currentFrame->mTime >= mStartTime, "Should have positive frame time");
|
||||
// Filter out invalid frames by checking the frame time. FrameTime could be
|
||||
// zero if it's a initial frame.
|
||||
int64_t frameTime = currentFrame->mTime - mStartTime;
|
||||
if (frameTime > 0 || (frameTime == 0 && mPlayDuration == 0) ||
|
||||
IsRealTime()) {
|
||||
NS_ASSERTION(currentFrame->mTime >= 0, "Should have positive frame time");
|
||||
{
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
// If we have video, we want to increment the clock in steps of the frame
|
||||
// duration.
|
||||
@@ -3179,31 +3065,6 @@ MediaDecoderStateMachine::DropAudioUpToSeekTarget(AudioData* aSample)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::SetStartTime(int64_t aStartTimeUsecs)
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
DECODER_LOG("SetStartTime(%lld)", aStartTimeUsecs);
|
||||
mStartTime = 0;
|
||||
if (aStartTimeUsecs != 0) {
|
||||
mStartTime = aStartTimeUsecs;
|
||||
// XXXbholley - this whole method goes away in the upcoming patches.
|
||||
if (mDurationSet && 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.
|
||||
// Adjust mEndTime so that mEndTime-mStartTime matches the specified
|
||||
// duration.
|
||||
mEndTime = mStartTime + mEndTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the audio start time to be start of media. If this lies before the
|
||||
// first actual audio frame we have, we'll inject silence during playback
|
||||
// to ensure the audio starts at the correct time.
|
||||
mAudioStartTime = mStartTime;
|
||||
DECODER_LOG("Set media start time to %lld", mStartTime);
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::UpdateNextFrameStatus()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
@@ -3281,6 +3142,7 @@ void MediaDecoderStateMachine::StartBuffering()
|
||||
|
||||
void MediaDecoderStateMachine::SetPlayStartTime(const TimeStamp& aTimeStamp)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
mPlayStartTime = aTimeStamp;
|
||||
if (!mAudioSink) {
|
||||
@@ -3302,7 +3164,8 @@ void MediaDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder()
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::ScheduleStateMachine() {
|
||||
MediaDecoderStateMachine::ScheduleStateMachine()
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
if (mDispatchedStateMachine) {
|
||||
return;
|
||||
@@ -3350,6 +3213,7 @@ bool MediaDecoderStateMachine::OnTaskQueue() const
|
||||
|
||||
bool MediaDecoderStateMachine::IsStateMachineScheduled() const
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
return mDispatchedStateMachine || mDelayedScheduler.IsScheduled();
|
||||
}
|
||||
|
||||
@@ -3370,7 +3234,7 @@ MediaDecoderStateMachine::LogicalPlaybackRateChanged()
|
||||
if (!HasAudio() && IsPlaying()) {
|
||||
// Remember how much time we've spent in playing the media
|
||||
// for playback rate will change from now on.
|
||||
mPlayDuration = GetVideoStreamPosition() - mStartTime;
|
||||
mPlayDuration = GetVideoStreamPosition();
|
||||
SetPlayStartTime(TimeStamp::Now());
|
||||
}
|
||||
|
||||
@@ -3473,6 +3337,15 @@ void MediaDecoderStateMachine::DispatchAudioCaptured()
|
||||
MOZ_ASSERT(self->OnTaskQueue());
|
||||
ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
|
||||
if (!self->mAudioCaptured) {
|
||||
// Stop the audio sink if it's running.
|
||||
self->StopAudioThread();
|
||||
// GetMediaTime() could return -1 because we haven't decoded
|
||||
// the 1st frame. But this is OK since we will update mStreamStartTime
|
||||
// again in SetStartTime().
|
||||
self->mStreamStartTime = self->GetMediaTime();
|
||||
// Reset mAudioEndTime which will be updated as we send audio data to
|
||||
// stream. Otherwise it will remain -1 if we don't have audio.
|
||||
self->mAudioEndTime = -1;
|
||||
self->mAudioCaptured = true;
|
||||
self->ScheduleStateMachine();
|
||||
}
|
||||
@@ -3488,7 +3361,7 @@ void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream,
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
if (!GetDecodedStream()) {
|
||||
RecreateDecodedStream(mCurrentPosition.ReadOnWrongThread());
|
||||
RecreateDecodedStream(aStream->Graph());
|
||||
}
|
||||
mDecodedStream.Connect(aStream, aFinishWhenEnded);
|
||||
DispatchAudioCaptured();
|
||||
@@ -3527,12 +3400,19 @@ void MediaDecoderStateMachine::UpdateStreamBlockingForStateMachinePlaying()
|
||||
}
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::RecreateDecodedStream(int64_t aInitialTime)
|
||||
void MediaDecoderStateMachine::RecreateDecodedStream(MediaStreamGraph* aGraph)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
DECODER_LOG("RecreateDecodedStream aInitialTime=%lld!", aInitialTime);
|
||||
mDecodedStream.RecreateData(aInitialTime, MediaStreamGraph::GetInstance());
|
||||
mDecodedStream.RecreateData(aGraph);
|
||||
}
|
||||
|
||||
uint32_t MediaDecoderStateMachine::GetAmpleVideoFrames() const
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
return (mReader->IsAsync() && mReader->VideoIsHardwareAccelerated())
|
||||
? std::max<uint32_t>(sVideoQueueHWAccelSize, MIN_VIDEO_QUEUE_SIZE)
|
||||
: std::max<uint32_t>(sVideoQueueDefaultSize, MIN_VIDEO_QUEUE_SIZE);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
Reference in New Issue
Block a user