Bug 1250054. Part 1 - add new files and move StartTimeRendezvous from MediaDecoderStateMachine.h to MediaDecoderReaderWrapper.cpp. r=jya.

This commit is contained in:
JW Wang 2016-03-29 14:48:11 +08:00
Родитель b9147b76ff
Коммит 635996582d
4 изменённых файлов: 173 добавлений и 127 удалений

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

@ -0,0 +1,148 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/MozPromise.h"
#include "MediaDecoderReaderWrapper.h"
namespace mozilla {
extern LazyLogModule gMediaDecoderLog;
#undef LOG
#define LOG(...) \
MOZ_LOG(gMediaDecoderLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
// 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 on MDSM.
class StartTimeRendezvous {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StartTimeRendezvous);
typedef MediaDecoderReader::AudioDataPromise AudioDataPromise;
typedef MediaDecoderReader::VideoDataPromise VideoDataPromise;
public:
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] () {
MOZ_ASSERT(self->mOwnerThread->IsCurrentThreadIn());
p->Resolve(data, __func__);
},
[p] () {
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) {
LOG("StartTimeRendezvous=%p SampleType(%d) Has no samples.",
this, SampleType);
MaybeSetChannelStartTime<SampleType>(INT64_MAX);
}
}
bool HaveStartTime() const
{
return mAudioStartTime.isSome() && mVideoStartTime.isSome();
}
int64_t StartTime() const
{
int64_t time = std::min(mAudioStartTime.ref(), mVideoStartTime.ref());
return time == INT64_MAX ? 0 : time;
}
private:
~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;
}
LOG("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;
};
} // namespace mozilla

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

@ -0,0 +1,24 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MediaDecoderReaderWrapper_h_
#define MediaDecoderReaderWrapper_h_
#include "mozilla/AbstractThread.h"
#include "mozilla/RefPtr.h"
#include "nsISupportsImpl.h"
#include "MediaDecoderReader.h"
namespace mozilla {
class StartTimeRendezvous;
typedef MozPromise<bool, bool, /* isExclusive = */ false> HaveStartTimePromise;
} // namespace mozilla
#endif // MediaDecoderReaderWrapper_h_

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

@ -694,133 +694,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;

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

@ -214,6 +214,7 @@ UNIFIED_SOURCES += [
'MediaData.cpp',
'MediaDecoder.cpp',
'MediaDecoderReader.cpp',
'MediaDecoderReaderWrapper.cpp',
'MediaDecoderStateMachine.cpp',
'MediaDeviceInfo.cpp',
'MediaDevices.cpp',