Bug 1182737. Part 3 - make start/stop playback of DecodedStream more consistent with that of AudioSink.

This commit is contained in:
JW Wang 2015-07-11 16:41:39 +08:00
parent d4aa45790c
commit 3139a49c50
3 changed files with 82 additions and 56 deletions

View File

@ -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

View File

@ -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;
};

View File

@ -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();
}
});