/* -*- 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::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::OnAudioDataRequestCompleted( RefPtr 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::OnAudioDataRequestFailed( const MediaResult& aError) { MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); return AudioDataPromise::CreateAndReject(aError, __func__); } RefPtr 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::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 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::Seek(const SeekTarget& aTarget) { MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); return SeekInternal(aTarget); } RefPtr 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::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 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 r = NewRunnableMethod("MediaFormatReader::ResetDecode", mReader, &MediaFormatReader::ResetDecode, aTracks); nsresult rv = mReader->OwnerThread()->Dispatch(r.forget()); MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); Unused << rv; } RefPtr ReaderProxy::Shutdown() { MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); mShutdown = true; RefPtr self = this; return InvokeAsync(mReader->OwnerThread(), __func__, [self]() { self->mDuration.DisconnectIfConnected(); self->mWatchManager.Shutdown(); return self->mReader->Shutdown(); }); } RefPtr 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::OnMetadataNotRead( const MediaResult& aError) { return MetadataPromise::CreateAndReject(aError, __func__); } void ReaderProxy::SetVideoBlankDecode(bool aIsBlankDecode) { MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); nsCOMPtr r = NewRunnableMethod( "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* aCanonical) { using DurationT = AbstractCanonical; RefPtr self = this; RefPtr canonical = aCanonical; nsCOMPtr 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