Bug 1250054. Part 2 - employ MediaDecoderReaderWrapper for MDSM and remove code about adjusting start time. r=jya.

MozReview-Commit-ID: CvEnGuvr6gt
This commit is contained in:
JW Wang 2016-03-31 16:35:47 +08:00
Родитель 13a1e758be
Коммит 11cf428801
2 изменённых файлов: 28 добавлений и 210 удалений

Просмотреть файл

@ -42,6 +42,7 @@
#include "ImageContainer.h"
#include "MediaDecoder.h"
#include "MediaDecoderReader.h"
#include "MediaDecoderReaderWrapper.h"
#include "MediaDecoderStateMachine.h"
#include "MediaShutdownManager.h"
#include "MediaTimer.h"
@ -219,6 +220,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mObservedDuration(TimeUnit(), "MediaDecoderStateMachine::mObservedDuration"),
mFragmentEndTime(-1),
mReader(aReader),
mReaderWrapper(new MediaDecoderReaderWrapper(aRealTime, mTaskQueue, aReader)),
mDecodedAudioEndTime(0),
mDecodedVideoEndTime(0),
mPlaybackRate(1.0),
@ -604,7 +606,6 @@ MediaDecoderStateMachine::OnAudioDecoded(MediaData* aAudioSample)
RefPtr<MediaData> audio(aAudioSample);
MOZ_ASSERT(audio);
mAudioDataRequest.Complete();
aAudioSample->AdjustForStartTime(StartTime());
// audio->GetEndTime() is not always mono-increasing in chained ogg.
mDecodedAudioEndTime = std::max(audio->GetEndTime(), mDecodedAudioEndTime);
@ -887,7 +888,6 @@ MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample,
RefPtr<MediaData> video(aVideoSample);
MOZ_ASSERT(video);
mVideoDataRequest.Complete();
aVideoSample->AdjustForStartTime(StartTime());
// Handle abnormal or negative timestamps.
mDecodedVideoEndTime = std::max(mDecodedVideoEndTime, video->GetEndTime());
@ -1342,11 +1342,7 @@ MediaDecoderStateMachine::Shutdown()
Reset();
mMediaSink->Shutdown();
// Shut down our start time rendezvous.
if (mStartTimeRendezvous) {
mStartTimeRendezvous->Destroy();
}
mReaderWrapper->Shutdown();
DECODER_LOG("Shutdown started");
@ -1483,8 +1479,7 @@ MediaDecoderStateMachine::ReadMetadata()
DECODER_LOG("Dispatching AsyncReadMetadata");
// Set mode to METADATA since we are about to read metadata.
mResource->SetReadMode(MediaCacheStream::MODE_METADATA);
mMetadataRequest.Begin(InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::AsyncReadMetadata)
mMetadataRequest.Begin(mReaderWrapper->ReadMetadata()
->Then(OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnMetadataRead,
&MediaDecoderStateMachine::OnMetadataNotRead));
@ -1637,11 +1632,8 @@ MediaDecoderStateMachine::InitiateSeek(SeekJob aSeekJob)
// Do the seek.
RefPtr<MediaDecoderStateMachine> self = this;
SeekTarget seekTarget = mCurrentSeek.mTarget;
seekTarget.SetTime(seekTarget.GetTime() + media::TimeUnit::FromMicroseconds(StartTime()));
mSeekRequest.Begin(InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::Seek, seekTarget,
Duration().ToMicroseconds())
mSeekRequest.Begin(
mReaderWrapper->Seek(mCurrentSeek.mTarget, Duration())
->Then(OwnerThread(), __func__,
[self] (media::TimeUnit) -> void {
self->mSeekRequest.Complete();
@ -1703,25 +1695,11 @@ MediaDecoderStateMachine::RequestAudioData()
SAMPLE_LOG("Queueing audio task - queued=%i, decoder-queued=%o",
AudioQueue().GetSize(), mReader->SizeOfAudioQueueInFrames());
if (mSentFirstFrameLoadedEvent) {
mAudioDataRequest.Begin(InvokeAsync(DecodeTaskQueue(), mReader.get(),
__func__, &MediaDecoderReader::RequestAudioData)
->Then(OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnAudioDecoded,
&MediaDecoderStateMachine::OnAudioNotDecoded));
} else {
mAudioDataRequest.Begin(
InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestAudioData)
->Then(OwnerThread(), __func__, mStartTimeRendezvous.get(),
&StartTimeRendezvous::ProcessFirstSample<AudioDataPromise, MediaData::AUDIO_DATA>,
&StartTimeRendezvous::FirstSampleRejected<MediaData::AUDIO_DATA>)
->CompletionPromise()
->Then(OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnAudioDecoded,
&MediaDecoderStateMachine::OnAudioNotDecoded)
);
}
mAudioDataRequest.Begin(
mReaderWrapper->RequestAudioData()
->Then(OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnAudioDecoded,
&MediaDecoderStateMachine::OnAudioNotDecoded));
}
nsresult
@ -1776,44 +1754,23 @@ MediaDecoderStateMachine::RequestVideoData()
bool skipToNextKeyFrame = mSentFirstFrameLoadedEvent &&
NeedToSkipToNextKeyframe();
int64_t currentTime =
mState == DECODER_STATE_SEEKING || !mSentFirstFrameLoadedEvent
? 0 : GetMediaTime() + StartTime();
media::TimeUnit currentTime = media::TimeUnit::FromMicroseconds(
mState == DECODER_STATE_SEEKING ? 0 : GetMediaTime());
SAMPLE_LOG("Queueing video task - queued=%i, decoder-queued=%o, skip=%i, time=%lld",
VideoQueue().GetSize(), mReader->SizeOfVideoQueueInFrames(), skipToNextKeyFrame,
currentTime);
currentTime.ToMicroseconds());
RefPtr<MediaDecoderStateMachine> self = this;
if (mSentFirstFrameLoadedEvent) {
mVideoDataRequest.Begin(
InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestVideoData,
skipToNextKeyFrame, currentTime)
->Then(OwnerThread(), __func__,
[self, videoDecodeStartTime] (MediaData* aVideoSample) {
self->OnVideoDecoded(aVideoSample, videoDecodeStartTime);
},
[self] (MediaDecoderReader::NotDecodedReason aReason) {
self->OnVideoNotDecoded(aReason);
}));
} else {
mVideoDataRequest.Begin(
InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestVideoData,
skipToNextKeyFrame, currentTime)
->Then(OwnerThread(), __func__, mStartTimeRendezvous.get(),
&StartTimeRendezvous::ProcessFirstSample<VideoDataPromise, MediaData::VIDEO_DATA>,
&StartTimeRendezvous::FirstSampleRejected<MediaData::VIDEO_DATA>)
->CompletionPromise()
->Then(OwnerThread(), __func__,
[self, videoDecodeStartTime] (MediaData* aVideoSample) {
self->OnVideoDecoded(aVideoSample, videoDecodeStartTime);
},
[self] (MediaDecoderReader::NotDecodedReason aReason) {
self->OnVideoNotDecoded(aReason);
}));
}
mVideoDataRequest.Begin(
mReaderWrapper->RequestVideoData(skipToNextKeyFrame, currentTime)
->Then(OwnerThread(), __func__,
[self, videoDecodeStartTime] (MediaData* aVideoSample) {
self->OnVideoDecoded(aVideoSample, videoDecodeStartTime);
},
[self] (MediaDecoderReader::NotDecodedReason aReason) {
self->OnVideoNotDecoded(aReason);
}));
}
void
@ -1946,29 +1903,14 @@ MediaDecoderStateMachine::OnMetadataRead(MetadataHolder* aMetadata)
mMetadataTags = aMetadata->mTags.forget();
RefPtr<MediaDecoderStateMachine> self = this;
// Set up the start time rendezvous if it doesn't already exist (which is
// generally the case, unless we're coming out of dormant mode).
if (!mStartTimeRendezvous) {
mStartTimeRendezvous = new StartTimeRendezvous(OwnerThread(), HasAudio(), HasVideo(),
mReader->ForceZeroStartTime() || IsRealTime());
mStartTimeRendezvous->AwaitStartTime()->Then(OwnerThread(), __func__,
[self] () -> void {
NS_ENSURE_TRUE_VOID(!self->IsShutdown());
self->mReader->DispatchSetStartTime(self->StartTime());
},
[] () -> void { NS_WARNING("Setting start time on reader failed"); }
);
}
if (mInfo.mMetadataDuration.isSome()) {
RecomputeDuration();
} else if (mInfo.mUnadjustedMetadataEndTime.isSome()) {
mStartTimeRendezvous->AwaitStartTime()->Then(OwnerThread(), __func__,
mReaderWrapper->AwaitStartTime()->Then(OwnerThread(), __func__,
[self] () -> void {
NS_ENSURE_TRUE_VOID(!self->IsShutdown());
TimeUnit unadjusted = self->mInfo.mUnadjustedMetadataEndTime.ref();
TimeUnit adjustment = TimeUnit::FromMicroseconds(self->StartTime());
TimeUnit adjustment = self->mReaderWrapper->StartTime();
self->mInfo.mMetadataDuration.emplace(unadjusted - adjustment);
self->RecomputeDuration();
}, [] () -> void { NS_WARNING("Adjusting metadata end time failed"); }

Просмотреть файл

@ -104,6 +104,7 @@ class MediaSink;
class AudioSegment;
class DecodedStream;
class MediaDecoderReaderWrapper;
class OutputStreamManager;
class TaskQueue;
@ -694,133 +695,6 @@ private:
// Used to dispatch another round schedule with specific target time.
DelayedScheduler mDelayedScheduler;
// StartTimeRendezvous is a helper class that quarantines the first sample
// until it gets a sample from both channels, such that we can be guaranteed
// to know the start time by the time On{Audio,Video}Decoded is called.
class StartTimeRendezvous {
public:
typedef MediaDecoderReader::AudioDataPromise AudioDataPromise;
typedef MediaDecoderReader::VideoDataPromise VideoDataPromise;
typedef MozPromise<bool, bool, /* isExclusive = */ false> HaveStartTimePromise;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StartTimeRendezvous);
StartTimeRendezvous(AbstractThread* aOwnerThread, bool aHasAudio, bool aHasVideo,
bool aForceZeroStartTime)
: mOwnerThread(aOwnerThread)
{
if (aForceZeroStartTime) {
mAudioStartTime.emplace(0);
mVideoStartTime.emplace(0);
return;
}
if (!aHasAudio) {
mAudioStartTime.emplace(INT64_MAX);
}
if (!aHasVideo) {
mVideoStartTime.emplace(INT64_MAX);
}
}
void Destroy()
{
mAudioStartTime = Some(mAudioStartTime.refOr(INT64_MAX));
mVideoStartTime = Some(mVideoStartTime.refOr(INT64_MAX));
mHaveStartTimePromise.RejectIfExists(false, __func__);
}
RefPtr<HaveStartTimePromise> AwaitStartTime()
{
if (HaveStartTime()) {
return HaveStartTimePromise::CreateAndResolve(true, __func__);
}
return mHaveStartTimePromise.Ensure(__func__);
}
template<typename PromiseType>
struct PromiseSampleType {
typedef typename PromiseType::ResolveValueType::element_type Type;
};
template<typename PromiseType, MediaData::Type SampleType>
RefPtr<PromiseType> ProcessFirstSample(typename PromiseSampleType<PromiseType>::Type* aData)
{
typedef typename PromiseSampleType<PromiseType>::Type DataType;
typedef typename PromiseType::Private PromisePrivate;
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
MaybeSetChannelStartTime<SampleType>(aData->mTime);
RefPtr<PromisePrivate> p = new PromisePrivate(__func__);
RefPtr<DataType> data = aData;
RefPtr<StartTimeRendezvous> self = this;
AwaitStartTime()->Then(mOwnerThread, __func__,
[p, data, self] () -> void {
MOZ_ASSERT(self->mOwnerThread->IsCurrentThreadIn());
p->Resolve(data, __func__);
},
[p] () -> void { p->Reject(MediaDecoderReader::CANCELED, __func__); });
return p.forget();
}
template<MediaData::Type SampleType>
void FirstSampleRejected(MediaDecoderReader::NotDecodedReason aReason)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
if (aReason == MediaDecoderReader::DECODE_ERROR) {
mHaveStartTimePromise.RejectIfExists(false, __func__);
} else if (aReason == MediaDecoderReader::END_OF_STREAM) {
MOZ_LOG(gMediaDecoderLog, LogLevel::Debug,
("StartTimeRendezvous=%p SampleType(%d) Has no samples.", this, SampleType));
MaybeSetChannelStartTime<SampleType>(INT64_MAX);
}
}
bool HaveStartTime() { return mAudioStartTime.isSome() && mVideoStartTime.isSome(); }
int64_t StartTime()
{
int64_t time = std::min(mAudioStartTime.ref(), mVideoStartTime.ref());
return time == INT64_MAX ? 0 : time;
}
private:
virtual ~StartTimeRendezvous() {}
template<MediaData::Type SampleType>
void MaybeSetChannelStartTime(int64_t aStartTime)
{
if (ChannelStartTime(SampleType).isSome()) {
// If we're initialized with aForceZeroStartTime=true, the channel start
// times are already set.
return;
}
MOZ_LOG(gMediaDecoderLog, LogLevel::Debug,
("StartTimeRendezvous=%p Setting SampleType(%d) start time to %lld",
this, SampleType, aStartTime));
ChannelStartTime(SampleType).emplace(aStartTime);
if (HaveStartTime()) {
mHaveStartTimePromise.ResolveIfExists(true, __func__);
}
}
Maybe<int64_t>& ChannelStartTime(MediaData::Type aType)
{
return aType == MediaData::AUDIO_DATA ? mAudioStartTime : mVideoStartTime;
}
MozPromiseHolder<HaveStartTimePromise> mHaveStartTimePromise;
RefPtr<AbstractThread> mOwnerThread;
Maybe<int64_t> mAudioStartTime;
Maybe<int64_t> mVideoStartTime;
};
RefPtr<StartTimeRendezvous> mStartTimeRendezvous;
bool HaveStartTime() { return mStartTimeRendezvous && mStartTimeRendezvous->HaveStartTime(); }
int64_t StartTime() { return mStartTimeRendezvous->StartTime(); }
// Queue of audio frames. This queue is threadsafe, and is accessed from
// the audio, decoder, state machine, and main threads.
MediaQueue<MediaData> mAudioQueue;
@ -883,6 +757,8 @@ private:
// This is created in the state machine's constructor.
const RefPtr<MediaDecoderReader> mReader;
const RefPtr<MediaDecoderReaderWrapper> mReaderWrapper;
// The end time of the last audio frame that's been pushed onto the media sink
// in microseconds. This will approximately be the end time
// of the audio stream, unless another frame is pushed to the hardware.