зеркало из https://github.com/mozilla/gecko-dev.git
200 строки
7.5 KiB
C++
200 строки
7.5 KiB
C++
/* -*- 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 "MediaFormatReader.h"
|
|
#include "ReaderProxy.h"
|
|
#include "TimeUnits.h"
|
|
|
|
namespace mozilla {
|
|
|
|
ReaderProxy::ReaderProxy(AbstractThread* aOwnerThread,
|
|
MediaFormatReader* aReader)
|
|
: mOwnerThread(aOwnerThread),
|
|
mReader(aReader),
|
|
mWatchManager(this, aReader->OwnerThread()),
|
|
mDuration(aReader->OwnerThread(), media::NullableTimeUnit(),
|
|
"ReaderProxy::mDuration (Mirror)") {
|
|
// Must support either heuristic buffering or WaitForData().
|
|
MOZ_ASSERT(mReader->UseBufferingHeuristics() ||
|
|
mReader->IsWaitForDataSupported());
|
|
}
|
|
|
|
ReaderProxy::~ReaderProxy() = default;
|
|
|
|
media::TimeUnit ReaderProxy::StartTime() const {
|
|
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
|
return mStartTime.ref();
|
|
}
|
|
|
|
RefPtr<ReaderProxy::MetadataPromise> ReaderProxy::ReadMetadata() {
|
|
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
|
MOZ_ASSERT(!mShutdown);
|
|
return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
|
|
&MediaFormatReader::AsyncReadMetadata)
|
|
->Then(mOwnerThread, __func__, this, &ReaderProxy::OnMetadataRead,
|
|
&ReaderProxy::OnMetadataNotRead);
|
|
}
|
|
|
|
RefPtr<ReaderProxy::AudioDataPromise> ReaderProxy::OnAudioDataRequestCompleted(
|
|
RefPtr<AudioData> aAudio) {
|
|
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
|
|
|
if (aAudio->AdjustForStartTime(StartTime())) {
|
|
return AudioDataPromise::CreateAndResolve(aAudio.forget(), __func__);
|
|
}
|
|
return AudioDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
|
|
__func__);
|
|
}
|
|
|
|
RefPtr<ReaderProxy::AudioDataPromise> ReaderProxy::OnAudioDataRequestFailed(
|
|
const MediaResult& aError) {
|
|
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
|
return AudioDataPromise::CreateAndReject(aError, __func__);
|
|
}
|
|
|
|
RefPtr<ReaderProxy::AudioDataPromise> ReaderProxy::RequestAudioData() {
|
|
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
|
MOZ_ASSERT(!mShutdown);
|
|
|
|
return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
|
|
&MediaFormatReader::RequestAudioData)
|
|
->Then(mOwnerThread, __func__, this,
|
|
&ReaderProxy::OnAudioDataRequestCompleted,
|
|
&ReaderProxy::OnAudioDataRequestFailed);
|
|
}
|
|
|
|
RefPtr<ReaderProxy::VideoDataPromise> ReaderProxy::RequestVideoData(
|
|
const media::TimeUnit& aTimeThreshold, bool aRequestNextVideoKeyFrame) {
|
|
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
|
MOZ_ASSERT(!mShutdown);
|
|
|
|
const auto threshold = aTimeThreshold > media::TimeUnit::Zero()
|
|
? aTimeThreshold + StartTime()
|
|
: aTimeThreshold;
|
|
|
|
auto startTime = StartTime();
|
|
return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
|
|
&MediaFormatReader::RequestVideoData, threshold,
|
|
aRequestNextVideoKeyFrame)
|
|
->Then(
|
|
mOwnerThread, __func__,
|
|
[startTime](RefPtr<VideoData> aVideo) {
|
|
return aVideo->AdjustForStartTime(startTime)
|
|
? VideoDataPromise::CreateAndResolve(aVideo.forget(),
|
|
__func__)
|
|
: VideoDataPromise::CreateAndReject(
|
|
NS_ERROR_DOM_MEDIA_OVERFLOW_ERR, __func__);
|
|
},
|
|
[](const MediaResult& aError) {
|
|
return VideoDataPromise::CreateAndReject(aError, __func__);
|
|
});
|
|
}
|
|
|
|
RefPtr<ReaderProxy::SeekPromise> ReaderProxy::Seek(const SeekTarget& aTarget) {
|
|
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
|
return SeekInternal(aTarget);
|
|
}
|
|
|
|
RefPtr<ReaderProxy::SeekPromise> ReaderProxy::SeekInternal(
|
|
const SeekTarget& aTarget) {
|
|
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
|
SeekTarget adjustedTarget = aTarget;
|
|
adjustedTarget.SetTime(adjustedTarget.GetTime() + StartTime());
|
|
return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
|
|
&MediaFormatReader::Seek, std::move(adjustedTarget));
|
|
}
|
|
|
|
RefPtr<ReaderProxy::WaitForDataPromise> ReaderProxy::WaitForData(
|
|
MediaData::Type aType) {
|
|
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
|
MOZ_ASSERT(mReader->IsWaitForDataSupported());
|
|
return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
|
|
&MediaFormatReader::WaitForData, aType);
|
|
}
|
|
|
|
void ReaderProxy::ReleaseResources() {
|
|
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
|
nsCOMPtr<nsIRunnable> r =
|
|
NewRunnableMethod("MediaFormatReader::ReleaseResources", mReader,
|
|
&MediaFormatReader::ReleaseResources);
|
|
nsresult rv = mReader->OwnerThread()->Dispatch(r.forget());
|
|
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
|
Unused << rv;
|
|
}
|
|
|
|
void ReaderProxy::ResetDecode(TrackSet aTracks) {
|
|
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
|
nsCOMPtr<nsIRunnable> r =
|
|
NewRunnableMethod<TrackSet>("MediaFormatReader::ResetDecode", mReader,
|
|
&MediaFormatReader::ResetDecode, aTracks);
|
|
nsresult rv = mReader->OwnerThread()->Dispatch(r.forget());
|
|
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
|
Unused << rv;
|
|
}
|
|
|
|
RefPtr<ShutdownPromise> ReaderProxy::Shutdown() {
|
|
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
|
mShutdown = true;
|
|
RefPtr<ReaderProxy> self = this;
|
|
return InvokeAsync(mReader->OwnerThread(), __func__, [self]() {
|
|
self->mDuration.DisconnectIfConnected();
|
|
self->mWatchManager.Shutdown();
|
|
return self->mReader->Shutdown();
|
|
});
|
|
}
|
|
|
|
RefPtr<ReaderProxy::MetadataPromise> ReaderProxy::OnMetadataRead(
|
|
MetadataHolder&& aMetadata) {
|
|
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
|
if (mShutdown) {
|
|
return MetadataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_ABORT_ERR,
|
|
__func__);
|
|
}
|
|
|
|
if (mStartTime.isNothing()) {
|
|
mStartTime.emplace(aMetadata.mInfo->mStartTime);
|
|
}
|
|
return MetadataPromise::CreateAndResolve(std::move(aMetadata), __func__);
|
|
}
|
|
|
|
RefPtr<ReaderProxy::MetadataPromise> ReaderProxy::OnMetadataNotRead(
|
|
const MediaResult& aError) {
|
|
return MetadataPromise::CreateAndReject(aError, __func__);
|
|
}
|
|
|
|
void ReaderProxy::SetVideoBlankDecode(bool aIsBlankDecode) {
|
|
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
|
nsCOMPtr<nsIRunnable> r = NewRunnableMethod<bool>(
|
|
"MediaFormatReader::SetVideoNullDecode", mReader,
|
|
&MediaFormatReader::SetVideoNullDecode, aIsBlankDecode);
|
|
nsresult rv = mReader->OwnerThread()->Dispatch(r.forget());
|
|
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
|
Unused << rv;
|
|
}
|
|
|
|
void ReaderProxy::UpdateDuration() {
|
|
MOZ_ASSERT(mReader->OwnerThread()->IsCurrentThreadIn());
|
|
mReader->UpdateDuration(mDuration.Ref().ref());
|
|
}
|
|
|
|
void ReaderProxy::SetCanonicalDuration(
|
|
AbstractCanonical<media::NullableTimeUnit>* aCanonical) {
|
|
using DurationT = AbstractCanonical<media::NullableTimeUnit>;
|
|
RefPtr<ReaderProxy> self = this;
|
|
RefPtr<DurationT> canonical = aCanonical;
|
|
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
|
|
"ReaderProxy::SetCanonicalDuration", [this, self, canonical]() {
|
|
mDuration.Connect(canonical);
|
|
mWatchManager.Watch(mDuration, &ReaderProxy::UpdateDuration);
|
|
});
|
|
nsresult rv = mReader->OwnerThread()->Dispatch(r.forget());
|
|
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
|
Unused << rv;
|
|
}
|
|
|
|
} // namespace mozilla
|