зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
13a1e758be
Коммит
11cf428801
|
@ -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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче