зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1250054. Part 2 - implement MediaDecoderReaderWrapper. r=jya.
This commit is contained in:
Родитель
635996582d
Коммит
cd4fad046a
|
@ -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_
|
||||
|
|
Загрузка…
Ссылка в новой задаче