зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1182737
. Part 3 - make start/stop playback of DecodedStream more consistent with that of AudioSink.
This commit is contained in:
Родитель
5d896370ea
Коммит
0058bf1bad
|
@ -10,7 +10,6 @@
|
|||
#include "VideoSegment.h"
|
||||
#include "MediaQueue.h"
|
||||
#include "MediaData.h"
|
||||
#include "MediaInfo.h"
|
||||
#include "SharedBuffer.h"
|
||||
#include "VideoUtils.h"
|
||||
|
||||
|
@ -195,6 +194,22 @@ DecodedStream::DecodedStream(MediaQueue<AudioData>& aAudioQueue,
|
|||
//
|
||||
}
|
||||
|
||||
void
|
||||
DecodedStream::StartPlayback(int64_t aStartTime, const MediaInfo& aInfo)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
if (mStartTime.isNothing()) {
|
||||
mStartTime.emplace(aStartTime);
|
||||
mInfo = aInfo;
|
||||
}
|
||||
}
|
||||
|
||||
void DecodedStream::StopPlayback()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
mStartTime.reset();
|
||||
}
|
||||
|
||||
void
|
||||
DecodedStream::DestroyData()
|
||||
{
|
||||
|
@ -347,7 +362,7 @@ DecodedStream::SetPlaying(bool aPlaying)
|
|||
}
|
||||
|
||||
void
|
||||
DecodedStream::InitTracks(int64_t aStartTime, const MediaInfo& aInfo)
|
||||
DecodedStream::InitTracks()
|
||||
{
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
|
||||
|
@ -357,20 +372,20 @@ DecodedStream::InitTracks(int64_t aStartTime, const MediaInfo& aInfo)
|
|||
|
||||
SourceMediaStream* sourceStream = mData->mStream;
|
||||
|
||||
if (aInfo.HasAudio()) {
|
||||
TrackID audioTrackId = aInfo.mAudio.mTrackId;
|
||||
if (mInfo.HasAudio()) {
|
||||
TrackID audioTrackId = mInfo.mAudio.mTrackId;
|
||||
AudioSegment* audio = new AudioSegment();
|
||||
sourceStream->AddAudioTrack(audioTrackId, aInfo.mAudio.mRate, 0, audio,
|
||||
sourceStream->AddAudioTrack(audioTrackId, mInfo.mAudio.mRate, 0, audio,
|
||||
SourceMediaStream::ADDTRACK_QUEUED);
|
||||
mData->mNextAudioTime = aStartTime;
|
||||
mData->mNextAudioTime = mStartTime.ref();
|
||||
}
|
||||
|
||||
if (aInfo.HasVideo()) {
|
||||
TrackID videoTrackId = aInfo.mVideo.mTrackId;
|
||||
if (mInfo.HasVideo()) {
|
||||
TrackID videoTrackId = mInfo.mVideo.mTrackId;
|
||||
VideoSegment* video = new VideoSegment();
|
||||
sourceStream->AddTrack(videoTrackId, 0, video,
|
||||
SourceMediaStream::ADDTRACK_QUEUED);
|
||||
mData->mNextVideoTime = aStartTime;
|
||||
mData->mNextVideoTime = mStartTime.ref();
|
||||
}
|
||||
|
||||
sourceStream->FinishAddTracks();
|
||||
|
@ -425,27 +440,25 @@ SendStreamAudio(DecodedStreamData* aStream, int64_t aStartTime,
|
|||
}
|
||||
|
||||
void
|
||||
DecodedStream::SendAudio(int64_t aStartTime,
|
||||
const MediaInfo& aInfo,
|
||||
double aVolume, bool aIsSameOrigin)
|
||||
DecodedStream::SendAudio(double aVolume, bool aIsSameOrigin)
|
||||
{
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
|
||||
if (!aInfo.HasAudio()) {
|
||||
if (!mInfo.HasAudio()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AudioSegment output;
|
||||
uint32_t rate = aInfo.mAudio.mRate;
|
||||
uint32_t rate = mInfo.mAudio.mRate;
|
||||
nsAutoTArray<nsRefPtr<AudioData>,10> audio;
|
||||
TrackID audioTrackId = aInfo.mAudio.mTrackId;
|
||||
TrackID audioTrackId = mInfo.mAudio.mTrackId;
|
||||
SourceMediaStream* sourceStream = mData->mStream;
|
||||
|
||||
// It's OK to hold references to the AudioData because AudioData
|
||||
// is ref-counted.
|
||||
mAudioQueue.GetElementsAfter(mData->mNextAudioTime, &audio);
|
||||
for (uint32_t i = 0; i < audio.Length(); ++i) {
|
||||
SendStreamAudio(mData.get(), aStartTime, audio[i], &output, rate, aVolume);
|
||||
SendStreamAudio(mData.get(), mStartTime.ref(), audio[i], &output, rate, aVolume);
|
||||
}
|
||||
|
||||
if (!aIsSameOrigin) {
|
||||
|
@ -492,18 +505,16 @@ ZeroDurationAtLastChunk(VideoSegment& aInput)
|
|||
}
|
||||
|
||||
void
|
||||
DecodedStream::SendVideo(int64_t aStartTime,
|
||||
const MediaInfo& aInfo,
|
||||
bool aIsSameOrigin)
|
||||
DecodedStream::SendVideo(bool aIsSameOrigin)
|
||||
{
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
|
||||
if (!aInfo.HasVideo()) {
|
||||
if (!mInfo.HasVideo()) {
|
||||
return;
|
||||
}
|
||||
|
||||
VideoSegment output;
|
||||
TrackID videoTrackId = aInfo.mVideo.mTrackId;
|
||||
TrackID videoTrackId = mInfo.mVideo.mTrackId;
|
||||
nsAutoTArray<nsRefPtr<VideoData>, 10> video;
|
||||
SourceMediaStream* sourceStream = mData->mStream;
|
||||
|
||||
|
@ -572,21 +583,21 @@ DecodedStream::SendVideo(int64_t aStartTime,
|
|||
}
|
||||
|
||||
void
|
||||
DecodedStream::AdvanceTracks(int64_t aStartTime, const MediaInfo& aInfo)
|
||||
DecodedStream::AdvanceTracks()
|
||||
{
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
|
||||
StreamTime endPosition = 0;
|
||||
|
||||
if (aInfo.HasAudio()) {
|
||||
if (mInfo.HasAudio()) {
|
||||
StreamTime audioEnd = mData->mStream->TicksToTimeRoundDown(
|
||||
aInfo.mAudio.mRate, mData->mAudioFramesWritten);
|
||||
mInfo.mAudio.mRate, mData->mAudioFramesWritten);
|
||||
endPosition = std::max(endPosition, audioEnd);
|
||||
}
|
||||
|
||||
if (aInfo.HasVideo()) {
|
||||
if (mInfo.HasVideo()) {
|
||||
StreamTime videoEnd = mData->mStream->MicrosecondsToStreamTimeRoundDown(
|
||||
mData->mNextVideoTime - aStartTime);
|
||||
mData->mNextVideoTime - mStartTime.ref());
|
||||
endPosition = std::max(endPosition, videoEnd);
|
||||
}
|
||||
|
||||
|
@ -596,19 +607,18 @@ DecodedStream::AdvanceTracks(int64_t aStartTime, const MediaInfo& aInfo)
|
|||
}
|
||||
|
||||
bool
|
||||
DecodedStream::SendData(int64_t aStartTime,
|
||||
const MediaInfo& aInfo,
|
||||
double aVolume, bool aIsSameOrigin)
|
||||
DecodedStream::SendData(double aVolume, bool aIsSameOrigin)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
MOZ_ASSERT(mStartTime.isSome(), "Must be called after StartPlayback()");
|
||||
|
||||
InitTracks(aStartTime, aInfo);
|
||||
SendAudio(aStartTime, aInfo, aVolume, aIsSameOrigin);
|
||||
SendVideo(aStartTime, aInfo, aIsSameOrigin);
|
||||
AdvanceTracks(aStartTime, aInfo);
|
||||
InitTracks();
|
||||
SendAudio(aVolume, aIsSameOrigin);
|
||||
SendVideo(aIsSameOrigin);
|
||||
AdvanceTracks();
|
||||
|
||||
bool finished = (!aInfo.HasAudio() || mAudioQueue.IsFinished()) &&
|
||||
(!aInfo.HasVideo() || mVideoQueue.IsFinished());
|
||||
bool finished = (!mInfo.HasAudio() || mAudioQueue.IsFinished()) &&
|
||||
(!mInfo.HasVideo() || mVideoQueue.IsFinished());
|
||||
|
||||
if (finished && !mData->mHaveSentFinish) {
|
||||
mData->mHaveSentFinish = true;
|
||||
|
@ -619,10 +629,12 @@ DecodedStream::SendData(int64_t aStartTime,
|
|||
}
|
||||
|
||||
CheckedInt64
|
||||
DecodedStream::AudioEndTime(int64_t aStartTime, uint32_t aRate) const
|
||||
DecodedStream::AudioEndTime() const
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
return aStartTime + FramesToUsecs(mData->mAudioFramesWritten, aRate);
|
||||
MOZ_ASSERT(mStartTime.isSome(), "Must be called after StartPlayback()");
|
||||
return mStartTime.ref() +
|
||||
FramesToUsecs(mData->mAudioFramesWritten, mInfo.mAudio.mRate);
|
||||
}
|
||||
|
||||
int64_t
|
||||
|
|
|
@ -9,17 +9,18 @@
|
|||
|
||||
#include "nsRefPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "MediaInfo.h"
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class AudioData;
|
||||
class VideoData;
|
||||
class MediaInfo;
|
||||
class AudioSegment;
|
||||
class MediaStream;
|
||||
class MediaInputPort;
|
||||
|
@ -98,19 +99,24 @@ class DecodedStream {
|
|||
public:
|
||||
DecodedStream(MediaQueue<AudioData>& aAudioQueue,
|
||||
MediaQueue<VideoData>& aVideoQueue);
|
||||
|
||||
// Mimic MDSM::StartAudioThread.
|
||||
// Must be called before any calls to SendData().
|
||||
void StartPlayback(int64_t aStartTime, const MediaInfo& aInfo);
|
||||
// Mimic MDSM::StopAudioThread.
|
||||
void StopPlayback();
|
||||
|
||||
void DestroyData();
|
||||
void RecreateData();
|
||||
void Connect(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
|
||||
void Remove(MediaStream* aStream);
|
||||
void SetPlaying(bool aPlaying);
|
||||
CheckedInt64 AudioEndTime(int64_t aStartTime, uint32_t aRate) const;
|
||||
CheckedInt64 AudioEndTime() const;
|
||||
int64_t GetPosition() const;
|
||||
bool IsFinished() const;
|
||||
|
||||
// Return true if stream is finished.
|
||||
bool SendData(int64_t aStartTime,
|
||||
const MediaInfo& aInfo,
|
||||
double aVolume, bool aIsSameOrigin);
|
||||
bool SendData(double aVolume, bool aIsSameOrigin);
|
||||
|
||||
protected:
|
||||
virtual ~DecodedStream() {}
|
||||
|
@ -120,16 +126,10 @@ private:
|
|||
void RecreateData(MediaStreamGraph* aGraph);
|
||||
void Connect(OutputStreamData* aStream);
|
||||
nsTArray<OutputStreamData>& OutputStreams();
|
||||
void InitTracks(int64_t aStartTime, const MediaInfo& aInfo);
|
||||
void AdvanceTracks(int64_t aStartTime, const MediaInfo& aInfo);
|
||||
|
||||
void SendAudio(int64_t aStartTime,
|
||||
const MediaInfo& aInfo,
|
||||
double aVolume, bool aIsSameOrigin);
|
||||
|
||||
void SendVideo(int64_t aStartTime,
|
||||
const MediaInfo& aInfo,
|
||||
bool aIsSameOrigin);
|
||||
void InitTracks();
|
||||
void AdvanceTracks();
|
||||
void SendAudio(double aVolume, bool aIsSameOrigin);
|
||||
void SendVideo(bool aIsSameOrigin);
|
||||
|
||||
UniquePtr<DecodedStreamData> mData;
|
||||
// Data about MediaStreams that are being fed by the decoder.
|
||||
|
@ -145,6 +145,9 @@ private:
|
|||
mutable ReentrantMonitor mMonitor;
|
||||
|
||||
bool mPlaying;
|
||||
Maybe<int64_t> mStartTime;
|
||||
MediaInfo mInfo;
|
||||
|
||||
MediaQueue<AudioData>& mAudioQueue;
|
||||
MediaQueue<VideoData>& mVideoQueue;
|
||||
};
|
||||
|
|
|
@ -371,12 +371,10 @@ void MediaDecoderStateMachine::SendStreamData()
|
|||
AssertCurrentThreadInMonitor();
|
||||
MOZ_ASSERT(!mAudioSink, "Should've been stopped in RunStateMachine()");
|
||||
|
||||
bool finished = mDecodedStream->SendData(
|
||||
mStreamStartTime, mInfo, mVolume, mDecoder->IsSameOriginMedia());
|
||||
bool finished = mDecodedStream->SendData(mVolume, mDecoder->IsSameOriginMedia());
|
||||
|
||||
if (mInfo.HasAudio()) {
|
||||
CheckedInt64 playedUsecs = mDecodedStream->AudioEndTime(
|
||||
mStreamStartTime, mInfo.mAudio.mRate);
|
||||
CheckedInt64 playedUsecs = mDecodedStream->AudioEndTime();
|
||||
if (playedUsecs.isValid()) {
|
||||
OnAudioEndTimeUpdate(playedUsecs.value());
|
||||
}
|
||||
|
@ -1094,6 +1092,12 @@ void MediaDecoderStateMachine::MaybeStartPlayback()
|
|||
nsresult rv = StartAudioThread();
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
// Tell DecodedStream to start playback with specified start time and media
|
||||
// info. This is consistent with how we create AudioSink in StartAudioThread().
|
||||
if (mAudioCaptured) {
|
||||
mDecodedStream->StartPlayback(GetMediaTime(), mInfo);
|
||||
}
|
||||
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
}
|
||||
|
@ -2421,6 +2425,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
|||
}
|
||||
|
||||
StopAudioThread();
|
||||
mDecodedStream->StopPlayback();
|
||||
|
||||
if (mPlayState == MediaDecoder::PLAY_STATE_PLAYING &&
|
||||
!mSentPlaybackEndedEvent)
|
||||
|
@ -2462,6 +2467,7 @@ MediaDecoderStateMachine::Reset()
|
|||
// outside of the decoder monitor while we are clearing the queue and causes
|
||||
// crash for no samples to be popped.
|
||||
StopAudioThread();
|
||||
mDecodedStream->StopPlayback();
|
||||
|
||||
mVideoFrameEndTime = -1;
|
||||
mDecodedVideoEndTime = -1;
|
||||
|
@ -3141,6 +3147,11 @@ void MediaDecoderStateMachine::DispatchAudioCaptured()
|
|||
// stream. Otherwise it will remain -1 if we don't have audio.
|
||||
self->mAudioEndTime = -1;
|
||||
self->mAudioCaptured = true;
|
||||
// Start DecodedStream if we are already playing. Otherwise it will be
|
||||
// handled in MaybeStartPlayback().
|
||||
if (self->IsPlaying()) {
|
||||
self->mDecodedStream->StartPlayback(self->GetMediaTime(), self->mInfo);
|
||||
}
|
||||
self->ScheduleStateMachine();
|
||||
}
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче