Bug 1250054. Part 2 - implement MediaDecoderReaderWrapper. r=jya.

This commit is contained in:
JW Wang 2016-03-02 21:16:00 +08:00
Родитель 635996582d
Коммит cd4fad046a
2 изменённых файлов: 180 добавлений и 0 удалений

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

@ -145,4 +145,141 @@ private:
Maybe<int64_t> mVideoStartTime;
};
MediaDecoderReaderWrapper::MediaDecoderReaderWrapper(bool aIsRealTime,
AbstractThread* aOwnerThread,
MediaDecoderReader* aReader)
: mForceZeroStartTime(aIsRealTime || aReader->ForceZeroStartTime())
, mOwnerThread(aOwnerThread)
, mReader(aReader)
{}
MediaDecoderReaderWrapper::~MediaDecoderReaderWrapper()
{}
media::TimeUnit
MediaDecoderReaderWrapper::StartTime() const
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
return media::TimeUnit::FromMicroseconds(mStartTimeRendezvous->StartTime());
}
RefPtr<MediaDecoderReaderWrapper::MetadataPromise>
MediaDecoderReaderWrapper::ReadMetadata()
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
&MediaDecoderReader::AsyncReadMetadata)
->Then(mOwnerThread, __func__, this,
&MediaDecoderReaderWrapper::OnMetadataRead,
&MediaDecoderReaderWrapper::OnMetadataNotRead)
->CompletionPromise();
}
RefPtr<HaveStartTimePromise>
MediaDecoderReaderWrapper::AwaitStartTime()
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
return mStartTimeRendezvous->AwaitStartTime();
}
RefPtr<MediaDecoderReaderWrapper::AudioDataPromise>
MediaDecoderReaderWrapper::RequestAudioData()
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
auto p = InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
&MediaDecoderReader::RequestAudioData);
if (!mStartTimeRendezvous->HaveStartTime()) {
p = p->Then(mOwnerThread, __func__, mStartTimeRendezvous.get(),
&StartTimeRendezvous::ProcessFirstSample<AudioDataPromise, MediaData::AUDIO_DATA>,
&StartTimeRendezvous::FirstSampleRejected<MediaData::AUDIO_DATA>)
->CompletionPromise();
}
return p->Then(mOwnerThread, __func__, this,
&MediaDecoderReaderWrapper::OnSampleDecoded,
&MediaDecoderReaderWrapper::OnNotDecoded)
->CompletionPromise();
}
RefPtr<MediaDecoderReaderWrapper::VideoDataPromise>
MediaDecoderReaderWrapper::RequestVideoData(bool aSkipToNextKeyframe,
media::TimeUnit aTimeThreshold)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
if (aTimeThreshold.ToMicroseconds() > 0 &&
mStartTimeRendezvous->HaveStartTime()) {
aTimeThreshold += StartTime();
}
auto p = InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
&MediaDecoderReader::RequestVideoData,
aSkipToNextKeyframe, aTimeThreshold.ToMicroseconds());
if (!mStartTimeRendezvous->HaveStartTime()) {
p = p->Then(mOwnerThread, __func__, mStartTimeRendezvous.get(),
&StartTimeRendezvous::ProcessFirstSample<VideoDataPromise, MediaData::VIDEO_DATA>,
&StartTimeRendezvous::FirstSampleRejected<MediaData::VIDEO_DATA>)
->CompletionPromise();
}
return p->Then(mOwnerThread, __func__, this,
&MediaDecoderReaderWrapper::OnSampleDecoded,
&MediaDecoderReaderWrapper::OnNotDecoded)
->CompletionPromise();
}
RefPtr<MediaDecoderReader::SeekPromise>
MediaDecoderReaderWrapper::Seek(SeekTarget aTarget, media::TimeUnit aEndTime)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
aTarget.SetTime(aTarget.GetTime() + StartTime());
return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
&MediaDecoderReader::Seek, aTarget,
aEndTime.ToMicroseconds());
}
void
MediaDecoderReaderWrapper::Shutdown()
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
mShutdown = true;
if (mStartTimeRendezvous) {
mStartTimeRendezvous->Destroy();
}
}
void
MediaDecoderReaderWrapper::OnMetadataRead(MetadataHolder* aMetadata)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
// 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(
mOwnerThread, aMetadata->mInfo.HasAudio(),
aMetadata->mInfo.HasVideo(), mForceZeroStartTime);
RefPtr<MediaDecoderReaderWrapper> self = this;
mStartTimeRendezvous->AwaitStartTime()->Then(
mOwnerThread, __func__,
[self] () {
NS_ENSURE_TRUE_VOID(!self->mShutdown);
self->mReader->DispatchSetStartTime(self->StartTime().ToMicroseconds());
},
[] () {
NS_WARNING("Setting start time on reader failed");
});
}
}
void
MediaDecoderReaderWrapper::OnSampleDecoded(MediaData* aSample)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
aSample->AdjustForStartTime(StartTime().ToMicroseconds());
}
} // namespace mozilla

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

@ -19,6 +19,49 @@ class StartTimeRendezvous;
typedef MozPromise<bool, bool, /* isExclusive = */ false> HaveStartTimePromise;
/**
* A wrapper around MediaDecoderReader to offset the timestamps of Audio/Video
* samples by the start time to ensure MDSM can always assume zero start time.
* It also adjusts the seek target passed to Seek() to ensure correct seek time
* is passed to the underlying reader.
*/
class MediaDecoderReaderWrapper {
typedef MediaDecoderReader::MetadataPromise MetadataPromise;
typedef MediaDecoderReader::AudioDataPromise AudioDataPromise;
typedef MediaDecoderReader::VideoDataPromise VideoDataPromise;
typedef MediaDecoderReader::SeekPromise SeekPromise;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReaderWrapper);
public:
MediaDecoderReaderWrapper(bool aIsRealTime,
AbstractThread* aOwnerThread,
MediaDecoderReader* aReader);
media::TimeUnit StartTime() const;
RefPtr<MetadataPromise> ReadMetadata();
RefPtr<HaveStartTimePromise> AwaitStartTime();
RefPtr<AudioDataPromise> RequestAudioData();
RefPtr<VideoDataPromise> RequestVideoData(bool aSkipToNextKeyframe,
media::TimeUnit aTimeThreshold);
RefPtr<SeekPromise> Seek(SeekTarget aTarget, media::TimeUnit aEndTime);
void Shutdown();
private:
~MediaDecoderReaderWrapper();
void OnMetadataRead(MetadataHolder* aMetadata);
void OnMetadataNotRead() {}
void OnSampleDecoded(MediaData* aSample);
void OnNotDecoded() {}
const bool mForceZeroStartTime;
const RefPtr<AbstractThread> mOwnerThread;
const RefPtr<MediaDecoderReader> mReader;
bool mShutdown = false;
RefPtr<StartTimeRendezvous> mStartTimeRendezvous;
};
} // namespace mozilla
#endif // MediaDecoderReaderWrapper_h_