зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1536766 - End a track only after the graph has reported reaching its end time in DecodedStream. r=jya,padenot
This gives us a guarantee that the first frame of a media file can be rendered with a second media element and mozCaptureStream(), even if the file is very very short. With longer video-only files there were also cases where nothing ended up being rendered. Probably because the MediaStreamGraph ended up switching from an AudioCallbackDriver to a SystemClockDriver and this took enough time to put the SourceMediaStream::EndTrack and the SourceMediaStream::AddTrackListener calls for this video track to be processed in the same iteration. The listener would then always lose to the ending track and update main thread state too late, leading to its media element not rendering any frames and nasty intermittent failures. Differential Revision: https://phabricator.services.mozilla.com/D27270 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
8734620d4d
Коммит
2cab1f445f
|
@ -92,6 +92,17 @@ class DecodedStreamGraphListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifyOutput(TrackID aTrackID, StreamTime aCurrentTrackTime) {
|
void NotifyOutput(TrackID aTrackID, StreamTime aCurrentTrackTime) {
|
||||||
|
if (aTrackID == mAudioTrackID) {
|
||||||
|
if (aCurrentTrackTime >= mAudioEnd) {
|
||||||
|
mStream->EndTrack(mAudioTrackID);
|
||||||
|
}
|
||||||
|
} else if (aTrackID == mVideoTrackID) {
|
||||||
|
if (aCurrentTrackTime >= mVideoEnd) {
|
||||||
|
mStream->EndTrack(mVideoTrackID);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MOZ_CRASH("Unexpected TrackID");
|
||||||
|
}
|
||||||
if (aTrackID != mAudioTrackID && mAudioTrackID != TRACK_NONE &&
|
if (aTrackID != mAudioTrackID && mAudioTrackID != TRACK_NONE &&
|
||||||
!mAudioEnded) {
|
!mAudioEnded) {
|
||||||
// Only audio playout drives the clock forward, if present and live.
|
// Only audio playout drives the clock forward, if present and live.
|
||||||
|
@ -120,6 +131,36 @@ class DecodedStreamGraphListener {
|
||||||
|
|
||||||
TrackID VideoTrackID() const { return mVideoTrackID; }
|
TrackID VideoTrackID() const { return mVideoTrackID; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell the graph listener to end the given track after it has seen at least
|
||||||
|
* aEnd worth of output reported as processed by the graph.
|
||||||
|
*
|
||||||
|
* A StreamTime of STREAM_TIME_MAX indicates that the track has no end and is
|
||||||
|
* the default.
|
||||||
|
*
|
||||||
|
* This method of ending tracks is needed because the MediaStreamGraph
|
||||||
|
* processes ended tracks (through SourceMediaStream::EndTrack) at the
|
||||||
|
* beginning of an iteration, but waits until the end of the iteration to
|
||||||
|
* process any ControlMessages. When such a ControlMessage is a listener that
|
||||||
|
* is to be added to a track that has ended in its very first iteration, the
|
||||||
|
* track ends before the listener tracking this ending is added. This can lead
|
||||||
|
* to a MediaStreamTrack ending on main thread (it uses another listener)
|
||||||
|
* before the listeners to render the track get added, potentially meaning a
|
||||||
|
* media element doesn't progress before reaching the end although data was
|
||||||
|
* available.
|
||||||
|
*
|
||||||
|
* Callable from any thread.
|
||||||
|
*/
|
||||||
|
void EndTrackAt(TrackID aTrackID, StreamTime aEnd) {
|
||||||
|
if (aTrackID == mAudioTrackID) {
|
||||||
|
mAudioEnd = aEnd;
|
||||||
|
} else if (aTrackID == mVideoTrackID) {
|
||||||
|
mVideoEnd = aEnd;
|
||||||
|
} else {
|
||||||
|
MOZ_CRASH("Unexpected TrackID");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DoNotifyTrackEnded(TrackID aTrackID) {
|
void DoNotifyTrackEnded(TrackID aTrackID) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
if (aTrackID == mAudioTrackID) {
|
if (aTrackID == mAudioTrackID) {
|
||||||
|
@ -172,7 +213,9 @@ class DecodedStreamGraphListener {
|
||||||
// Any thread.
|
// Any thread.
|
||||||
const RefPtr<SourceMediaStream> mStream;
|
const RefPtr<SourceMediaStream> mStream;
|
||||||
const TrackID mAudioTrackID;
|
const TrackID mAudioTrackID;
|
||||||
|
Atomic<StreamTime> mAudioEnd{STREAM_TIME_MAX};
|
||||||
const TrackID mVideoTrackID;
|
const TrackID mVideoTrackID;
|
||||||
|
Atomic<StreamTime> mVideoEnd{STREAM_TIME_MAX};
|
||||||
const RefPtr<AbstractThread> mAbstractMainThread;
|
const RefPtr<AbstractThread> mAbstractMainThread;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -617,7 +660,7 @@ void DecodedStream::SendAudio(double aVolume, bool aIsSameOrigin,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mAudioQueue.IsFinished() && !mData->mHaveSentFinishAudio) {
|
if (mAudioQueue.IsFinished() && !mData->mHaveSentFinishAudio) {
|
||||||
sourceStream->EndTrack(audioTrackId);
|
mData->mListener->EndTrackAt(audioTrackId, mData->mStreamAudioWritten);
|
||||||
mData->mHaveSentFinishAudio = true;
|
mData->mHaveSentFinishAudio = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -810,7 +853,7 @@ void DecodedStream::SendVideo(bool aIsSameOrigin,
|
||||||
mData->mStreamVideoWritten +=
|
mData->mStreamVideoWritten +=
|
||||||
sourceStream->AppendToTrack(videoTrackId, &endSegment);
|
sourceStream->AppendToTrack(videoTrackId, &endSegment);
|
||||||
}
|
}
|
||||||
sourceStream->EndTrack(videoTrackId);
|
mData->mListener->EndTrackAt(videoTrackId, mData->mStreamVideoWritten);
|
||||||
mData->mHaveSentFinishVideo = true;
|
mData->mHaveSentFinishVideo = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче