summaryrefslogtreecommitdiffstats
path: root/dom/media/ReaderProxy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/ReaderProxy.cpp')
-rw-r--r--dom/media/ReaderProxy.cpp216
1 files changed, 216 insertions, 0 deletions
diff --git a/dom/media/ReaderProxy.cpp b/dom/media/ReaderProxy.cpp
new file mode 100644
index 0000000000..fcdcd3376c
--- /dev/null
+++ b/dom/media/ReaderProxy.cpp
@@ -0,0 +1,216 @@
+/* -*- 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/CDMProxy.h"
+#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;
+}
+
+void ReaderProxy::UpdateMediaEngineId(uint64_t aMediaEngineId) {
+ MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+ nsCOMPtr<nsIRunnable> r = NewRunnableMethod<uint64_t>(
+ "MediaFormatReader::UpdateMediaEngineId", mReader,
+ &MediaFormatReader::UpdateMediaEngineId, aMediaEngineId);
+ nsresult rv = mReader->OwnerThread()->Dispatch(r.forget());
+ MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
+ Unused << rv;
+}
+
+RefPtr<SetCDMPromise> ReaderProxy::SetCDMProxy(CDMProxy* aProxy) {
+ return InvokeAsync<RefPtr<CDMProxy>>(mReader->OwnerThread(), mReader.get(),
+ __func__,
+ &MediaFormatReader::SetCDMProxy, aProxy);
+}
+
+} // namespace mozilla