LCOV - code coverage report
Current view: top level - dom/media - MediaDecoder.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 4 838 0.5 %
Date: 2017-07-14 16:53:18 Functions: 1 136 0.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "MediaDecoder.h"
       8             : 
       9             : #include "AudioChannelService.h"
      10             : #include "ImageContainer.h"
      11             : #include "Layers.h"
      12             : #include "MediaDecoderStateMachine.h"
      13             : #include "MediaResource.h"
      14             : #include "MediaShutdownManager.h"
      15             : #include "VideoFrameContainer.h"
      16             : #include "VideoUtils.h"
      17             : #include "mozilla/AbstractThread.h"
      18             : #include "mozilla/FloatingPoint.h"
      19             : #include "mozilla/MathAlgorithms.h"
      20             : #include "mozilla/Preferences.h"
      21             : #include "mozilla/StaticPtr.h"
      22             : #include "mozilla/Telemetry.h"
      23             : #include "mozilla/dom/AudioTrack.h"
      24             : #include "mozilla/dom/AudioTrackList.h"
      25             : #include "mozilla/dom/HTMLMediaElement.h"
      26             : #include "mozilla/dom/VideoTrack.h"
      27             : #include "mozilla/dom/VideoTrackList.h"
      28             : #include "mozilla/layers/ShadowLayers.h"
      29             : #include "nsComponentManagerUtils.h"
      30             : #include "nsError.h"
      31             : #include "nsIMemoryReporter.h"
      32             : #include "nsIObserver.h"
      33             : #include "nsPrintfCString.h"
      34             : #include "nsTArray.h"
      35             : #include <algorithm>
      36             : #include <limits>
      37             : 
      38             : #ifdef MOZ_ANDROID_OMX
      39             : #include "AndroidBridge.h"
      40             : #endif
      41             : 
      42             : using namespace mozilla::dom;
      43             : using namespace mozilla::layers;
      44             : using namespace mozilla::media;
      45             : 
      46             : namespace mozilla {
      47             : 
      48             : // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
      49             : // GetTickCount() and conflicts with MediaDecoder::GetCurrentTime implementation.
      50             : #ifdef GetCurrentTime
      51             : #undef GetCurrentTime
      52             : #endif
      53             : 
      54             : // avoid redefined macro in unified build
      55             : #undef LOG
      56             : #undef DUMP
      57             : 
      58             : LazyLogModule gMediaDecoderLog("MediaDecoder");
      59             : #define LOG(x, ...) \
      60             :   MOZ_LOG(gMediaDecoderLog, LogLevel::Debug, ("Decoder=%p " x, this, ##__VA_ARGS__))
      61             : 
      62             : #define DUMP(x, ...) \
      63             :   printf_stderr("%s\n", nsPrintfCString("Decoder=%p " x, this, ##__VA_ARGS__).get())
      64             : 
      65             : #define NS_DispatchToMainThread(...) CompileError_UseAbstractMainThreadInstead
      66             : 
      67             : static const char*
      68           0 : ToPlayStateStr(MediaDecoder::PlayState aState)
      69             : {
      70           0 :   switch (aState) {
      71           0 :     case MediaDecoder::PLAY_STATE_START:    return "START";
      72           0 :     case MediaDecoder::PLAY_STATE_LOADING:  return "LOADING";
      73           0 :     case MediaDecoder::PLAY_STATE_PAUSED:   return "PAUSED";
      74           0 :     case MediaDecoder::PLAY_STATE_PLAYING:  return "PLAYING";
      75           0 :     case MediaDecoder::PLAY_STATE_ENDED:    return "ENDED";
      76           0 :     case MediaDecoder::PLAY_STATE_SHUTDOWN: return "SHUTDOWN";
      77           0 :     default: MOZ_ASSERT_UNREACHABLE("Invalid playState.");
      78             :   }
      79             :   return "UNKNOWN";
      80             : }
      81             : 
      82             : class MediaMemoryTracker : public nsIMemoryReporter
      83             : {
      84             :   virtual ~MediaMemoryTracker();
      85             : 
      86             :   NS_DECL_THREADSAFE_ISUPPORTS
      87             :   NS_DECL_NSIMEMORYREPORTER
      88             : 
      89           0 :   MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf);
      90             : 
      91             :   MediaMemoryTracker();
      92             :   void InitMemoryReporter();
      93             : 
      94             :   static StaticRefPtr<MediaMemoryTracker> sUniqueInstance;
      95             : 
      96           0 :   static MediaMemoryTracker* UniqueInstance()
      97             :   {
      98           0 :     if (!sUniqueInstance) {
      99           0 :       sUniqueInstance = new MediaMemoryTracker();
     100           0 :       sUniqueInstance->InitMemoryReporter();
     101             :     }
     102           0 :     return sUniqueInstance;
     103             :   }
     104             : 
     105             :   typedef nsTArray<MediaDecoder*> DecodersArray;
     106           0 :   static DecodersArray& Decoders()
     107             :   {
     108           0 :     return UniqueInstance()->mDecoders;
     109             :   }
     110             : 
     111             :   DecodersArray mDecoders;
     112             : 
     113             : public:
     114           0 :   static void AddMediaDecoder(MediaDecoder* aDecoder)
     115             :   {
     116           0 :     Decoders().AppendElement(aDecoder);
     117           0 :   }
     118             : 
     119           0 :   static void RemoveMediaDecoder(MediaDecoder* aDecoder)
     120             :   {
     121           0 :     DecodersArray& decoders = Decoders();
     122           0 :     decoders.RemoveElement(aDecoder);
     123           0 :     if (decoders.IsEmpty()) {
     124           0 :       sUniqueInstance = nullptr;
     125             :     }
     126           0 :   }
     127             : };
     128             : 
     129           3 : StaticRefPtr<MediaMemoryTracker> MediaMemoryTracker::sUniqueInstance;
     130             : 
     131             : LazyLogModule gMediaTimerLog("MediaTimer");
     132             : 
     133             : constexpr TimeUnit MediaDecoder::DEFAULT_NEXT_FRAME_AVAILABLE_BUFFERED;
     134             : 
     135             : void
     136           3 : MediaDecoder::InitStatics()
     137             : {
     138           3 :   MOZ_ASSERT(NS_IsMainThread());
     139           3 : }
     140             : 
     141           0 : NS_IMPL_ISUPPORTS(MediaMemoryTracker, nsIMemoryReporter)
     142             : 
     143           0 : NS_IMPL_ISUPPORTS0(MediaDecoder)
     144             : 
     145             : void
     146           0 : MediaDecoder::NotifyOwnerActivityChanged(bool aIsDocumentVisible,
     147             :                                          Visibility aElementVisibility,
     148             :                                          bool aIsElementInTree)
     149             : {
     150           0 :   MOZ_ASSERT(NS_IsMainThread());
     151           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     152           0 :   SetElementVisibility(aIsDocumentVisible, aElementVisibility, aIsElementInTree);
     153             : 
     154           0 :   NotifyCompositor();
     155           0 : }
     156             : 
     157             : void
     158           0 : MediaDecoder::Pause()
     159             : {
     160           0 :   MOZ_ASSERT(NS_IsMainThread());
     161           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     162           0 :   if (mPlayState == PLAY_STATE_LOADING || IsEnded()) {
     163           0 :     mNextState = PLAY_STATE_PAUSED;
     164           0 :     return;
     165             :   }
     166           0 :   ChangeState(PLAY_STATE_PAUSED);
     167             : }
     168             : 
     169             : void
     170           0 : MediaDecoder::SetVolume(double aVolume)
     171             : {
     172           0 :   MOZ_ASSERT(NS_IsMainThread());
     173           0 :   mVolume = aVolume;
     174           0 : }
     175             : 
     176             : void
     177           0 : MediaDecoder::AddOutputStream(ProcessedMediaStream* aStream,
     178             :                               bool aFinishWhenEnded)
     179             : {
     180           0 :   MOZ_ASSERT(NS_IsMainThread());
     181           0 :   MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load().");
     182           0 :   mDecoderStateMachine->AddOutputStream(aStream, aFinishWhenEnded);
     183           0 : }
     184             : 
     185             : void
     186           0 : MediaDecoder::RemoveOutputStream(MediaStream* aStream)
     187             : {
     188           0 :   MOZ_ASSERT(NS_IsMainThread());
     189           0 :   MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load().");
     190           0 :   mDecoderStateMachine->RemoveOutputStream(aStream);
     191           0 : }
     192             : 
     193             : double
     194           0 : MediaDecoder::GetDuration()
     195             : {
     196           0 :   MOZ_ASSERT(NS_IsMainThread());
     197           0 :   return mDuration;
     198             : }
     199             : 
     200             : void
     201           0 : MediaDecoder::SetInfinite(bool aInfinite)
     202             : {
     203           0 :   MOZ_ASSERT(NS_IsMainThread());
     204           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     205           0 :   mInfiniteStream = aInfinite;
     206           0 :   DurationChanged();
     207           0 : }
     208             : 
     209             : bool
     210           0 : MediaDecoder::IsInfinite() const
     211             : {
     212           0 :   MOZ_ASSERT(NS_IsMainThread());
     213           0 :   return mInfiniteStream;
     214             : }
     215             : 
     216             : #define INIT_MIRROR(name, val) \
     217             :   name(mOwner->AbstractMainThread(), val, "MediaDecoder::" #name " (Mirror)")
     218             : #define INIT_CANONICAL(name, val) \
     219             :   name(mOwner->AbstractMainThread(), val, "MediaDecoder::" #name " (Canonical)")
     220             : 
     221           0 : MediaDecoder::MediaDecoder(MediaDecoderInit& aInit)
     222           0 :   : mWatchManager(this, aInit.mOwner->AbstractMainThread())
     223             :   , mLogicalPosition(0.0)
     224           0 :   , mDuration(std::numeric_limits<double>::quiet_NaN())
     225           0 :   , mCDMProxyPromise(mCDMProxyPromiseHolder.Ensure(__func__))
     226             :   , mIgnoreProgressData(false)
     227             :   , mInfiniteStream(false)
     228           0 :   , mOwner(aInit.mOwner)
     229           0 :   , mAbstractMainThread(aInit.mOwner->AbstractMainThread())
     230           0 :   , mFrameStats(new FrameStatistics())
     231           0 :   , mVideoFrameContainer(aInit.mOwner->GetVideoFrameContainer())
     232             :   , mPinnedForSeek(false)
     233           0 :   , mAudioChannel(aInit.mAudioChannel)
     234           0 :   , mMinimizePreroll(aInit.mMinimizePreroll)
     235             :   , mFiredMetadataLoaded(false)
     236             :   , mIsDocumentVisible(false)
     237             :   , mElementVisibility(Visibility::UNTRACKED)
     238             :   , mIsElementInTree(false)
     239             :   , mForcedHidden(false)
     240           0 :   , mHasSuspendTaint(aInit.mHasSuspendTaint)
     241           0 :   , mPlaybackRate(aInit.mPlaybackRate)
     242           0 :   , INIT_MIRROR(mBuffered, TimeIntervals())
     243           0 :   , INIT_MIRROR(mNextFrameStatus, MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE)
     244           0 :   , INIT_MIRROR(mCurrentPosition, TimeUnit::Zero())
     245           0 :   , INIT_MIRROR(mStateMachineDuration, NullableTimeUnit())
     246           0 :   , INIT_MIRROR(mPlaybackPosition, 0)
     247           0 :   , INIT_MIRROR(mIsAudioDataAudible, false)
     248           0 :   , INIT_CANONICAL(mVolume, aInit.mVolume)
     249           0 :   , INIT_CANONICAL(mPreservesPitch, aInit.mPreservesPitch)
     250           0 :   , INIT_CANONICAL(mLooping, aInit.mLooping)
     251           0 :   , INIT_CANONICAL(mExplicitDuration, Maybe<double>())
     252           0 :   , INIT_CANONICAL(mPlayState, PLAY_STATE_LOADING)
     253           0 :   , INIT_CANONICAL(mNextState, PLAY_STATE_PAUSED)
     254           0 :   , INIT_CANONICAL(mLogicallySeeking, false)
     255           0 :   , INIT_CANONICAL(mSameOriginMedia, false)
     256           0 :   , INIT_CANONICAL(mMediaPrincipalHandle, PRINCIPAL_HANDLE_NONE)
     257           0 :   , INIT_CANONICAL(mPlaybackBytesPerSecond, 0.0)
     258           0 :   , INIT_CANONICAL(mPlaybackRateReliable, true)
     259           0 :   , INIT_CANONICAL(mDecoderPosition, 0)
     260             :   , mTelemetryReported(false)
     261           0 :   , mIsMediaElement(!!mOwner->GetMediaElement())
     262           0 :   , mElement(mOwner->GetMediaElement())
     263           0 :   , mContainerType(aInit.mContainerType)
     264             : {
     265           0 :   MOZ_ASSERT(NS_IsMainThread());
     266           0 :   MOZ_ASSERT(mAbstractMainThread);
     267           0 :   MediaMemoryTracker::AddMediaDecoder(this);
     268             : 
     269             :   //
     270             :   // Initialize watchers.
     271             :   //
     272             : 
     273             :   // mDuration
     274           0 :   mWatchManager.Watch(mStateMachineDuration, &MediaDecoder::DurationChanged);
     275             : 
     276             :   // readyState
     277           0 :   mWatchManager.Watch(mPlayState, &MediaDecoder::UpdateReadyState);
     278           0 :   mWatchManager.Watch(mNextFrameStatus, &MediaDecoder::UpdateReadyState);
     279             :   // ReadyState computation depends on MediaDecoder::CanPlayThrough, which
     280             :   // depends on the download rate.
     281           0 :   mWatchManager.Watch(mBuffered, &MediaDecoder::UpdateReadyState);
     282             : 
     283             :   // mLogicalPosition
     284           0 :   mWatchManager.Watch(mCurrentPosition, &MediaDecoder::UpdateLogicalPosition);
     285           0 :   mWatchManager.Watch(mPlayState, &MediaDecoder::UpdateLogicalPosition);
     286           0 :   mWatchManager.Watch(mLogicallySeeking, &MediaDecoder::UpdateLogicalPosition);
     287             : 
     288             :   // mIgnoreProgressData
     289           0 :   mWatchManager.Watch(mLogicallySeeking, &MediaDecoder::SeekingChanged);
     290             : 
     291           0 :   mWatchManager.Watch(mIsAudioDataAudible,
     292           0 :                       &MediaDecoder::NotifyAudibleStateChanged);
     293             : 
     294           0 :   MediaShutdownManager::InitStatics();
     295           0 : }
     296             : 
     297             : #undef INIT_MIRROR
     298             : #undef INIT_CANONICAL
     299             : 
     300             : void
     301           0 : MediaDecoder::Shutdown()
     302             : {
     303           0 :   MOZ_ASSERT(NS_IsMainThread());
     304           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     305             : 
     306             :   // Unwatch all watch targets to prevent further notifications.
     307           0 :   mWatchManager.Shutdown();
     308             : 
     309           0 :   mCDMProxyPromiseHolder.RejectIfExists(true, __func__);
     310             : 
     311           0 :   DiscardOngoingSeekIfExists();
     312             : 
     313             :   // This changes the decoder state to SHUTDOWN and does other things
     314             :   // necessary to unblock the state machine thread if it's blocked, so
     315             :   // the asynchronous shutdown in nsDestroyStateMachine won't deadlock.
     316           0 :   if (mDecoderStateMachine) {
     317           0 :     mTimedMetadataListener.Disconnect();
     318           0 :     mMetadataLoadedListener.Disconnect();
     319           0 :     mFirstFrameLoadedListener.Disconnect();
     320           0 :     mOnPlaybackEvent.Disconnect();
     321           0 :     mOnPlaybackErrorEvent.Disconnect();
     322           0 :     mOnDecoderDoctorEvent.Disconnect();
     323           0 :     mOnMediaNotSeekable.Disconnect();
     324             : 
     325           0 :     mDecoderStateMachine->BeginShutdown()
     326             :       ->Then(mAbstractMainThread, __func__, this,
     327             :              &MediaDecoder::FinishShutdown,
     328           0 :              &MediaDecoder::FinishShutdown);
     329             :   } else {
     330             :     // Ensure we always unregister asynchronously in order not to disrupt
     331             :     // the hashtable iterating in MediaShutdownManager::Shutdown().
     332           0 :     RefPtr<MediaDecoder> self = this;
     333             :     nsCOMPtr<nsIRunnable> r =
     334           0 :       NS_NewRunnableFunction("MediaDecoder::Shutdown", [self]() {
     335           0 :         self->mVideoFrameContainer = nullptr;
     336           0 :         MediaShutdownManager::Instance().Unregister(self);
     337           0 :       });
     338           0 :     mAbstractMainThread->Dispatch(r.forget());
     339             :   }
     340             : 
     341             :   // Force any outstanding seek and byterange requests to complete
     342             :   // to prevent shutdown from deadlocking.
     343           0 :   if (mResource) {
     344           0 :     mResource->Close();
     345             :   }
     346             : 
     347             :   // Ask the owner to remove its audio/video tracks.
     348           0 :   GetOwner()->RemoveMediaTracks();
     349             : 
     350           0 :   ChangeState(PLAY_STATE_SHUTDOWN);
     351           0 :   mOwner = nullptr;
     352           0 : }
     353             : 
     354             : void
     355           0 : MediaDecoder::NotifyXPCOMShutdown()
     356             : {
     357           0 :   MOZ_ASSERT(NS_IsMainThread());
     358           0 :   if (auto owner = GetOwner()) {
     359           0 :     owner->NotifyXPCOMShutdown();
     360             :   }
     361           0 :   MOZ_DIAGNOSTIC_ASSERT(IsShutdown());
     362             : 
     363             :   // Don't cause grief to release builds by ensuring Shutdown()
     364             :   // is always called during shutdown phase.
     365           0 :   if (!IsShutdown()) {
     366           0 :     Shutdown();
     367             :   }
     368           0 : }
     369             : 
     370           0 : MediaDecoder::~MediaDecoder()
     371             : {
     372           0 :   MOZ_ASSERT(NS_IsMainThread());
     373           0 :   MOZ_DIAGNOSTIC_ASSERT(IsShutdown());
     374           0 :   MediaMemoryTracker::RemoveMediaDecoder(this);
     375           0 :   UnpinForSeek();
     376           0 : }
     377             : 
     378             : void
     379           0 : MediaDecoder::OnPlaybackEvent(MediaEventType aEvent)
     380             : {
     381           0 :   switch (aEvent) {
     382             :     case MediaEventType::PlaybackStarted:
     383           0 :       mPlaybackStatistics.Start();
     384           0 :       break;
     385             :     case MediaEventType::PlaybackStopped:
     386           0 :       mPlaybackStatistics.Stop();
     387           0 :       ComputePlaybackRate();
     388           0 :       break;
     389             :     case MediaEventType::PlaybackEnded:
     390           0 :       PlaybackEnded();
     391           0 :       break;
     392             :     case MediaEventType::SeekStarted:
     393           0 :       SeekingStarted();
     394           0 :       break;
     395             :     case MediaEventType::Invalidate:
     396           0 :       Invalidate();
     397           0 :       break;
     398             :     case MediaEventType::EnterVideoSuspend:
     399           0 :       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozentervideosuspend"));
     400           0 :       break;
     401             :     case MediaEventType::ExitVideoSuspend:
     402           0 :       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozexitvideosuspend"));
     403           0 :       break;
     404             :     case MediaEventType::StartVideoSuspendTimer:
     405           0 :       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozstartvideosuspendtimer"));
     406           0 :       break;
     407             :     case MediaEventType::CancelVideoSuspendTimer:
     408           0 :       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozcancelvideosuspendtimer"));
     409           0 :       break;
     410             :     case MediaEventType::VideoOnlySeekBegin:
     411           0 :       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozvideoonlyseekbegin"));
     412           0 :       break;
     413             :     case MediaEventType::VideoOnlySeekCompleted:
     414           0 :       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozvideoonlyseekcompleted"));
     415             :   }
     416           0 : }
     417             : 
     418             : void
     419           0 : MediaDecoder::OnPlaybackErrorEvent(const MediaResult& aError)
     420             : {
     421           0 :   DecodeError(aError);
     422           0 : }
     423             : 
     424             : void
     425           0 : MediaDecoder::OnDecoderDoctorEvent(DecoderDoctorEvent aEvent)
     426             : {
     427           0 :   MOZ_ASSERT(NS_IsMainThread());
     428             :   // OnDecoderDoctorEvent is disconnected at shutdown time.
     429           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     430           0 :   nsIDocument* doc = GetOwner()->GetDocument();
     431           0 :   if (!doc) {
     432           0 :     return;
     433             :   }
     434           0 :   DecoderDoctorDiagnostics diags;
     435           0 :   diags.StoreEvent(doc, aEvent, __func__);
     436             : }
     437             : 
     438             : void
     439           0 : MediaDecoder::FinishShutdown()
     440             : {
     441           0 :   MOZ_ASSERT(NS_IsMainThread());
     442           0 :   mDecoderStateMachine->BreakCycles();
     443           0 :   SetStateMachine(nullptr);
     444           0 :   mVideoFrameContainer = nullptr;
     445           0 :   MediaShutdownManager::Instance().Unregister(this);
     446           0 : }
     447             : 
     448             : nsresult
     449           0 : MediaDecoder::InitializeStateMachine()
     450             : {
     451           0 :   MOZ_ASSERT(NS_IsMainThread());
     452           0 :   NS_ASSERTION(mDecoderStateMachine, "Cannot initialize null state machine!");
     453             : 
     454           0 :   nsresult rv = mDecoderStateMachine->Init(this);
     455           0 :   NS_ENSURE_SUCCESS(rv, rv);
     456             : 
     457             :   // If some parameters got set before the state machine got created,
     458             :   // set them now
     459           0 :   SetStateMachineParameters();
     460             : 
     461           0 :   return NS_OK;
     462             : }
     463             : 
     464             : void
     465           0 : MediaDecoder::SetStateMachineParameters()
     466             : {
     467           0 :   MOZ_ASSERT(NS_IsMainThread());
     468           0 :   if (mPlaybackRate != 1 && mPlaybackRate != 0) {
     469           0 :     mDecoderStateMachine->DispatchSetPlaybackRate(mPlaybackRate);
     470             :   }
     471           0 :   mTimedMetadataListener = mDecoderStateMachine->TimedMetadataEvent().Connect(
     472           0 :     mAbstractMainThread, this, &MediaDecoder::OnMetadataUpdate);
     473           0 :   mMetadataLoadedListener = mDecoderStateMachine->MetadataLoadedEvent().Connect(
     474           0 :     mAbstractMainThread, this, &MediaDecoder::MetadataLoaded);
     475             :   mFirstFrameLoadedListener =
     476           0 :     mDecoderStateMachine->FirstFrameLoadedEvent().Connect(
     477           0 :       mAbstractMainThread, this, &MediaDecoder::FirstFrameLoaded);
     478             : 
     479           0 :   mOnPlaybackEvent = mDecoderStateMachine->OnPlaybackEvent().Connect(
     480           0 :     mAbstractMainThread, this, &MediaDecoder::OnPlaybackEvent);
     481           0 :   mOnPlaybackErrorEvent = mDecoderStateMachine->OnPlaybackErrorEvent().Connect(
     482           0 :     mAbstractMainThread, this, &MediaDecoder::OnPlaybackErrorEvent);
     483           0 :   mOnDecoderDoctorEvent = mDecoderStateMachine->OnDecoderDoctorEvent().Connect(
     484           0 :     mAbstractMainThread, this, &MediaDecoder::OnDecoderDoctorEvent);
     485           0 :   mOnMediaNotSeekable = mDecoderStateMachine->OnMediaNotSeekable().Connect(
     486           0 :     mAbstractMainThread, this, &MediaDecoder::OnMediaNotSeekable);
     487           0 : }
     488             : 
     489             : nsresult
     490           0 : MediaDecoder::Play()
     491             : {
     492           0 :   MOZ_ASSERT(NS_IsMainThread());
     493             : 
     494           0 :   NS_ASSERTION(mDecoderStateMachine != nullptr, "Should have state machine.");
     495           0 :   if (mPlaybackRate == 0) {
     496           0 :     return NS_OK;
     497             :   }
     498             : 
     499           0 :   if (IsEnded()) {
     500           0 :     return Seek(0, SeekTarget::PrevSyncPoint);
     501           0 :   } else if (mPlayState == PLAY_STATE_LOADING) {
     502           0 :     mNextState = PLAY_STATE_PLAYING;
     503           0 :     return NS_OK;
     504             :   }
     505             : 
     506           0 :   ChangeState(PLAY_STATE_PLAYING);
     507           0 :   return NS_OK;
     508             : }
     509             : 
     510             : nsresult
     511           0 : MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType)
     512             : {
     513           0 :   MOZ_ASSERT(NS_IsMainThread());
     514           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     515             : 
     516           0 :   MOZ_ASSERT(aTime >= 0.0, "Cannot seek to a negative value.");
     517             : 
     518           0 :   int64_t timeUsecs = TimeUnit::FromSeconds(aTime).ToMicroseconds();
     519             : 
     520           0 :   mLogicalPosition = aTime;
     521             : 
     522           0 :   mLogicallySeeking = true;
     523           0 :   SeekTarget target = SeekTarget(timeUsecs, aSeekType);
     524           0 :   CallSeek(target);
     525             : 
     526           0 :   if (mPlayState == PLAY_STATE_ENDED) {
     527           0 :     PinForSeek();
     528           0 :     ChangeState(GetOwner()->GetPaused() ? PLAY_STATE_PAUSED : PLAY_STATE_PLAYING);
     529             :   }
     530           0 :   return NS_OK;
     531             : }
     532             : 
     533             : void
     534           0 : MediaDecoder::DiscardOngoingSeekIfExists()
     535             : {
     536           0 :   MOZ_ASSERT(NS_IsMainThread());
     537           0 :   mSeekRequest.DisconnectIfExists();
     538           0 :   GetOwner()->AsyncRejectSeekDOMPromiseIfExists();
     539           0 : }
     540             : 
     541             : void
     542           0 : MediaDecoder::CallSeek(const SeekTarget& aTarget)
     543             : {
     544           0 :   MOZ_ASSERT(NS_IsMainThread());
     545           0 :   DiscardOngoingSeekIfExists();
     546             : 
     547           0 :   mDecoderStateMachine->InvokeSeek(aTarget)
     548           0 :   ->Then(mAbstractMainThread, __func__, this,
     549           0 :          &MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected)
     550           0 :   ->Track(mSeekRequest);
     551           0 : }
     552             : 
     553             : double
     554           0 : MediaDecoder::GetCurrentTime()
     555             : {
     556           0 :   MOZ_ASSERT(NS_IsMainThread());
     557           0 :   return mLogicalPosition;
     558             : }
     559             : 
     560             : already_AddRefed<nsIPrincipal>
     561           0 : MediaDecoder::GetCurrentPrincipal()
     562             : {
     563           0 :   MOZ_ASSERT(NS_IsMainThread());
     564           0 :   return mResource ? mResource->GetCurrentPrincipal() : nullptr;
     565             : }
     566             : 
     567             : void
     568           0 : MediaDecoder::OnMetadataUpdate(TimedMetadata&& aMetadata)
     569             : {
     570           0 :   MOZ_ASSERT(NS_IsMainThread());
     571           0 :   GetOwner()->RemoveMediaTracks();
     572           0 :   MetadataLoaded(MakeUnique<MediaInfo>(*aMetadata.mInfo),
     573           0 :                  UniquePtr<MetadataTags>(aMetadata.mTags.forget()),
     574           0 :                  MediaDecoderEventVisibility::Observable);
     575           0 :   FirstFrameLoaded(Move(aMetadata.mInfo),
     576           0 :                    MediaDecoderEventVisibility::Observable);
     577           0 : }
     578             : 
     579             : void
     580           0 : MediaDecoder::MetadataLoaded(UniquePtr<MediaInfo> aInfo,
     581             :                              UniquePtr<MetadataTags> aTags,
     582             :                              MediaDecoderEventVisibility aEventVisibility)
     583             : {
     584           0 :   MOZ_ASSERT(NS_IsMainThread());
     585           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     586             : 
     587           0 :   LOG("MetadataLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d",
     588             :       aInfo->mAudio.mChannels, aInfo->mAudio.mRate,
     589             :       aInfo->HasAudio(), aInfo->HasVideo());
     590             : 
     591           0 :   mMediaSeekable = aInfo->mMediaSeekable;
     592           0 :   mMediaSeekableOnlyInBufferedRanges = aInfo->mMediaSeekableOnlyInBufferedRanges;
     593           0 :   mInfo = aInfo.release();
     594           0 :   GetOwner()->ConstructMediaTracks(mInfo);
     595             : 
     596             :   // Make sure the element and the frame (if any) are told about
     597             :   // our new size.
     598           0 :   if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) {
     599           0 :     mFiredMetadataLoaded = true;
     600           0 :     GetOwner()->MetadataLoaded(
     601           0 :       mInfo, nsAutoPtr<const MetadataTags>(aTags.release()));
     602             :   }
     603             :   // Invalidate() will end up calling GetOwner()->UpdateMediaSize with the last
     604             :   // dimensions retrieved from the video frame container. The video frame
     605             :   // container contains more up to date dimensions than aInfo.
     606             :   // So we call Invalidate() after calling GetOwner()->MetadataLoaded to ensure
     607             :   // the media element has the latest dimensions.
     608           0 :   Invalidate();
     609             : 
     610           0 :   EnsureTelemetryReported();
     611           0 : }
     612             : 
     613             : void
     614           0 : MediaDecoder::EnsureTelemetryReported()
     615             : {
     616           0 :   MOZ_ASSERT(NS_IsMainThread());
     617             : 
     618           0 :   if (mTelemetryReported || !mInfo) {
     619             :     // Note: sometimes we get multiple MetadataLoaded calls (for example
     620             :     // for chained ogg). So we ensure we don't report duplicate results for
     621             :     // these resources.
     622           0 :     return;
     623             :   }
     624             : 
     625           0 :   nsTArray<nsCString> codecs;
     626           0 :   if (mInfo->HasAudio()
     627           0 :       && !mInfo->mAudio.GetAsAudioInfo()->mMimeType.IsEmpty()) {
     628           0 :     codecs.AppendElement(mInfo->mAudio.GetAsAudioInfo()->mMimeType);
     629             :   }
     630           0 :   if (mInfo->HasVideo()
     631           0 :       && !mInfo->mVideo.GetAsVideoInfo()->mMimeType.IsEmpty()) {
     632           0 :     codecs.AppendElement(mInfo->mVideo.GetAsVideoInfo()->mMimeType);
     633             :   }
     634           0 :   if (codecs.IsEmpty()) {
     635             :     codecs.AppendElement(
     636           0 :       nsPrintfCString("resource; %s", ContainerType().OriginalString().Data()));
     637             :   }
     638           0 :   for (const nsCString& codec : codecs) {
     639           0 :     LOG("Telemetry MEDIA_CODEC_USED= '%s'", codec.get());
     640           0 :     Telemetry::Accumulate(Telemetry::HistogramID::MEDIA_CODEC_USED, codec);
     641             :   }
     642             : 
     643           0 :   mTelemetryReported = true;
     644             : }
     645             : 
     646             : const char*
     647           0 : MediaDecoder::PlayStateStr()
     648             : {
     649           0 :   MOZ_ASSERT(NS_IsMainThread());
     650           0 :   return ToPlayStateStr(mPlayState);
     651             : }
     652             : 
     653             : void
     654           0 : MediaDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
     655             :                                MediaDecoderEventVisibility aEventVisibility)
     656             : {
     657           0 :   MOZ_ASSERT(NS_IsMainThread());
     658           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     659             : 
     660           0 :   LOG("FirstFrameLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d "
     661             :       "mPlayState=%s",
     662             :       aInfo->mAudio.mChannels, aInfo->mAudio.mRate, aInfo->HasAudio(),
     663             :       aInfo->HasVideo(), PlayStateStr());
     664             : 
     665           0 :   mInfo = aInfo.forget();
     666             : 
     667           0 :   Invalidate();
     668             : 
     669             :   // This can run cache callbacks.
     670           0 :   mResource->EnsureCacheUpToDate();
     671             : 
     672             :   // The element can run javascript via events
     673             :   // before reaching here, so only change the
     674             :   // state if we're still set to the original
     675             :   // loading state.
     676           0 :   if (mPlayState == PLAY_STATE_LOADING) {
     677           0 :     ChangeState(mNextState);
     678             :   }
     679             : 
     680             :   // Run NotifySuspendedStatusChanged now to give us a chance to notice
     681             :   // that autoplay should run.
     682           0 :   NotifySuspendedStatusChanged();
     683             : 
     684             :   // GetOwner()->FirstFrameLoaded() might call us back. Put it at the bottom of
     685             :   // this function to avoid unexpected shutdown from reentrant calls.
     686           0 :   if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) {
     687           0 :     GetOwner()->FirstFrameLoaded();
     688             :   }
     689           0 : }
     690             : 
     691             : void
     692           0 : MediaDecoder::NetworkError()
     693             : {
     694           0 :   MOZ_ASSERT(NS_IsMainThread());
     695           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     696           0 :   GetOwner()->NetworkError();
     697           0 : }
     698             : 
     699             : void
     700           0 : MediaDecoder::DecodeError(const MediaResult& aError)
     701             : {
     702           0 :   MOZ_ASSERT(NS_IsMainThread());
     703           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     704           0 :   GetOwner()->DecodeError(aError);
     705           0 : }
     706             : 
     707             : void
     708           0 : MediaDecoder::UpdateSameOriginStatus(bool aSameOrigin)
     709             : {
     710           0 :   MOZ_ASSERT(NS_IsMainThread());
     711           0 :   mSameOriginMedia = aSameOrigin;
     712           0 : }
     713             : 
     714             : bool
     715           0 : MediaDecoder::IsSeeking() const
     716             : {
     717           0 :   MOZ_ASSERT(NS_IsMainThread());
     718           0 :   return mLogicallySeeking;
     719             : }
     720             : 
     721             : bool
     722           0 : MediaDecoder::OwnerHasError() const
     723             : {
     724           0 :   MOZ_ASSERT(NS_IsMainThread());
     725           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     726           0 :   return GetOwner()->HasError();
     727             : }
     728             : 
     729             : already_AddRefed<GMPCrashHelper>
     730           0 : MediaDecoder::GetCrashHelper()
     731             : {
     732           0 :   MOZ_ASSERT(NS_IsMainThread());
     733           0 :   return GetOwner()->CreateGMPCrashHelper();
     734             : }
     735             : 
     736             : bool
     737           0 : MediaDecoder::IsEnded() const
     738             : {
     739           0 :   MOZ_ASSERT(NS_IsMainThread());
     740           0 :   return mPlayState == PLAY_STATE_ENDED;
     741             : }
     742             : 
     743             : bool
     744           0 : MediaDecoder::IsShutdown() const
     745             : {
     746           0 :   MOZ_ASSERT(NS_IsMainThread());
     747           0 :   return mPlayState == PLAY_STATE_SHUTDOWN;
     748             : }
     749             : 
     750             : void
     751           0 : MediaDecoder::PlaybackEnded()
     752             : {
     753           0 :   MOZ_ASSERT(NS_IsMainThread());
     754           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     755             : 
     756           0 :   if (mLogicallySeeking || mPlayState == PLAY_STATE_LOADING ||
     757           0 :       mPlayState == PLAY_STATE_ENDED) {
     758           0 :     LOG("MediaDecoder::PlaybackEnded bailed out, "
     759             :         "mLogicallySeeking=%d mPlayState=%s",
     760             :         mLogicallySeeking.Ref(), ToPlayStateStr(mPlayState));
     761           0 :     return;
     762             :   }
     763             : 
     764           0 :   LOG("MediaDecoder::PlaybackEnded");
     765             : 
     766           0 :   ChangeState(PLAY_STATE_ENDED);
     767           0 :   InvalidateWithFlags(VideoFrameContainer::INVALIDATE_FORCE);
     768           0 :   GetOwner()->PlaybackEnded();
     769             : 
     770             :   // This must be called after |GetOwner()->PlaybackEnded()| call above, in
     771             :   // order to fire the required durationchange.
     772           0 :   if (IsInfinite()) {
     773           0 :     SetInfinite(false);
     774             :   }
     775             : }
     776             : 
     777             : MediaStatistics
     778           0 : MediaDecoder::GetStatistics()
     779             : {
     780           0 :   MOZ_ASSERT(NS_IsMainThread());
     781           0 :   MOZ_ASSERT(mResource);
     782             : 
     783             :   MediaStatistics result;
     784           0 :   result.mDownloadRate =
     785           0 :     mResource->GetDownloadRate(&result.mDownloadRateReliable);
     786           0 :   result.mDownloadPosition = mResource->GetCachedDataEnd(mDecoderPosition);
     787           0 :   result.mTotalBytes = mResource->GetLength();
     788           0 :   result.mPlaybackRate = mPlaybackBytesPerSecond;
     789           0 :   result.mPlaybackRateReliable = mPlaybackRateReliable;
     790           0 :   result.mDecoderPosition = mDecoderPosition;
     791           0 :   result.mPlaybackPosition = mPlaybackPosition;
     792           0 :   return result;
     793             : }
     794             : 
     795             : void
     796           0 : MediaDecoder::ComputePlaybackRate()
     797             : {
     798           0 :   MOZ_ASSERT(NS_IsMainThread());
     799           0 :   MOZ_ASSERT(mResource);
     800             : 
     801           0 :   int64_t length = mResource->GetLength();
     802           0 :   if (mozilla::IsFinite<double>(mDuration)
     803           0 :       && mDuration > 0
     804           0 :       && length >= 0) {
     805           0 :     mPlaybackRateReliable = true;
     806           0 :     mPlaybackBytesPerSecond = length / mDuration;
     807           0 :     return;
     808             :   }
     809             : 
     810           0 :   bool reliable = false;
     811           0 :   mPlaybackBytesPerSecond = mPlaybackStatistics.GetRateAtLastStop(&reliable);
     812           0 :   mPlaybackRateReliable = reliable;
     813             : }
     814             : 
     815             : void
     816           0 : MediaDecoder::UpdatePlaybackRate()
     817             : {
     818           0 :   MOZ_ASSERT(NS_IsMainThread());
     819           0 :   MOZ_ASSERT(mResource);
     820             : 
     821           0 :   ComputePlaybackRate();
     822           0 :   uint32_t rate = mPlaybackBytesPerSecond;
     823             : 
     824           0 :   if (mPlaybackRateReliable) {
     825             :     // Avoid passing a zero rate
     826           0 :     rate = std::max(rate, 1u);
     827             :   } else {
     828             :     // Set a minimum rate of 10,000 bytes per second ... sometimes we just
     829             :     // don't have good data
     830           0 :     rate = std::max(rate, 10000u);
     831             :   }
     832             : 
     833           0 :   mResource->SetPlaybackRate(rate);
     834           0 : }
     835             : 
     836             : void
     837           0 : MediaDecoder::NotifySuspendedStatusChanged()
     838             : {
     839           0 :   MOZ_ASSERT(NS_IsMainThread());
     840           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     841           0 :   if (mResource) {
     842           0 :     bool suspended = mResource->IsSuspendedByCache();
     843           0 :     GetOwner()->NotifySuspendedByCache(suspended);
     844             :   }
     845           0 : }
     846             : 
     847             : bool
     848           0 : MediaDecoder::ShouldThrottleDownload()
     849             : {
     850             :   // We throttle the download if either the throttle override pref is set
     851             :   // (so that we can always throttle in Firefox on mobile) or if the download
     852             :   // is fast enough that there's no concern about playback being interrupted.
     853           0 :   MOZ_ASSERT(NS_IsMainThread());
     854           0 :   NS_ENSURE_TRUE(mDecoderStateMachine, false);
     855             : 
     856           0 :   int64_t length = mResource->GetLength();
     857           0 :   if (length > 0 &&
     858           0 :       length <= int64_t(MediaPrefs::MediaMemoryCacheMaxSize()) * 1024) {
     859             :     // Don't throttle the download of small resources. This is to speed
     860             :     // up seeking, as seeks into unbuffered ranges would require starting
     861             :     // up a new HTTP transaction, which adds latency.
     862           0 :     return false;
     863             :   }
     864             : 
     865           0 :   if (Preferences::GetBool("media.throttle-regardless-of-download-rate",
     866             :                            false)) {
     867           0 :     return true;
     868             :   }
     869             : 
     870           0 :   MediaStatistics stats = GetStatistics();
     871           0 :   if (!stats.mDownloadRateReliable || !stats.mPlaybackRateReliable) {
     872           0 :     return false;
     873             :   }
     874             :   uint32_t factor =
     875           0 :     std::max(2u, Preferences::GetUint("media.throttle-factor", 2));
     876           0 :   return stats.mDownloadRate > factor * stats.mPlaybackRate;
     877             : }
     878             : 
     879             : void
     880           0 : MediaDecoder::DownloadProgressed()
     881             : {
     882           0 :   MOZ_ASSERT(NS_IsMainThread());
     883           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     884           0 :   UpdatePlaybackRate();
     885           0 :   GetOwner()->DownloadProgressed();
     886           0 :   mResource->ThrottleReadahead(ShouldThrottleDownload());
     887           0 : }
     888             : 
     889             : void
     890           0 : MediaDecoder::NotifyDownloadEnded(nsresult aStatus)
     891             : {
     892           0 :   MOZ_ASSERT(NS_IsMainThread());
     893           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     894             : 
     895           0 :   LOG("NotifyDownloadEnded, status=%" PRIx32, static_cast<uint32_t>(aStatus));
     896             : 
     897           0 :   if (aStatus == NS_BINDING_ABORTED) {
     898             :     // Download has been cancelled by user.
     899           0 :     GetOwner()->LoadAborted();
     900           0 :     return;
     901             :   }
     902             : 
     903           0 :   UpdatePlaybackRate();
     904             : 
     905           0 :   if (NS_SUCCEEDED(aStatus)) {
     906             :     // A final progress event will be fired by the MediaResource calling
     907             :     // DownloadSuspended on the element.
     908             :     // Also NotifySuspendedStatusChanged() will be called to update readyState
     909             :     // if download ended with success.
     910           0 :   } else if (aStatus != NS_BASE_STREAM_CLOSED) {
     911           0 :     NetworkError();
     912             :   }
     913             : }
     914             : 
     915             : void
     916           0 : MediaDecoder::NotifyPrincipalChanged()
     917             : {
     918           0 :   MOZ_ASSERT(NS_IsMainThread());
     919           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     920           0 :   nsCOMPtr<nsIPrincipal> newPrincipal = GetCurrentPrincipal();
     921           0 :   mMediaPrincipalHandle = MakePrincipalHandle(newPrincipal);
     922           0 :   GetOwner()->NotifyDecoderPrincipalChanged();
     923           0 : }
     924             : 
     925             : void
     926           0 : MediaDecoder::NotifyBytesConsumed(int64_t aBytes, int64_t aOffset)
     927             : {
     928           0 :   MOZ_ASSERT(NS_IsMainThread());
     929           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     930             : 
     931           0 :   if (mIgnoreProgressData) {
     932           0 :     return;
     933             :   }
     934             : 
     935           0 :   MOZ_ASSERT(mDecoderStateMachine);
     936           0 :   if (aOffset >= mDecoderPosition) {
     937           0 :     mPlaybackStatistics.AddBytes(aBytes);
     938             :   }
     939           0 :   mDecoderPosition = aOffset + aBytes;
     940             : }
     941             : 
     942             : void
     943           0 : MediaDecoder::OnSeekResolved()
     944             : {
     945           0 :   MOZ_ASSERT(NS_IsMainThread());
     946           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     947           0 :   mSeekRequest.Complete();
     948             : 
     949             :   {
     950             :     // An additional seek was requested while the current seek was
     951             :     // in operation.
     952           0 :     UnpinForSeek();
     953           0 :     mLogicallySeeking = false;
     954             :   }
     955             : 
     956             :   // Ensure logical position is updated after seek.
     957           0 :   UpdateLogicalPositionInternal();
     958             : 
     959           0 :   GetOwner()->SeekCompleted();
     960           0 :   GetOwner()->AsyncResolveSeekDOMPromiseIfExists();
     961           0 : }
     962             : 
     963             : void
     964           0 : MediaDecoder::OnSeekRejected()
     965             : {
     966           0 :   MOZ_ASSERT(NS_IsMainThread());
     967           0 :   mSeekRequest.Complete();
     968           0 :   mLogicallySeeking = false;
     969           0 :   GetOwner()->AsyncRejectSeekDOMPromiseIfExists();
     970           0 : }
     971             : 
     972             : void
     973           0 : MediaDecoder::SeekingStarted()
     974             : {
     975           0 :   MOZ_ASSERT(NS_IsMainThread());
     976           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     977           0 :   GetOwner()->SeekStarted();
     978           0 : }
     979             : 
     980             : void
     981           0 : MediaDecoder::ChangeState(PlayState aState)
     982             : {
     983           0 :   MOZ_ASSERT(NS_IsMainThread());
     984           0 :   MOZ_ASSERT(!IsShutdown(), "SHUTDOWN is the final state.");
     985             : 
     986           0 :   if (mNextState == aState) {
     987           0 :     mNextState = PLAY_STATE_PAUSED;
     988             :   }
     989             : 
     990           0 :   LOG("ChangeState %s => %s", PlayStateStr(), ToPlayStateStr(aState));
     991           0 :   mPlayState = aState;
     992             : 
     993           0 :   if (mPlayState == PLAY_STATE_PLAYING) {
     994           0 :     GetOwner()->ConstructMediaTracks(mInfo);
     995           0 :   } else if (IsEnded()) {
     996           0 :     GetOwner()->RemoveMediaTracks();
     997             :   }
     998           0 : }
     999             : 
    1000             : void
    1001           0 : MediaDecoder::UpdateLogicalPositionInternal()
    1002             : {
    1003           0 :   MOZ_ASSERT(NS_IsMainThread());
    1004           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
    1005             : 
    1006           0 :   double currentPosition = CurrentPosition().ToSeconds();
    1007           0 :   if (mPlayState == PLAY_STATE_ENDED) {
    1008           0 :     currentPosition = std::max(currentPosition, mDuration);
    1009             :   }
    1010           0 :   bool logicalPositionChanged = mLogicalPosition != currentPosition;
    1011           0 :   mLogicalPosition = currentPosition;
    1012             : 
    1013             :   // Invalidate the frame so any video data is displayed.
    1014             :   // Do this before the timeupdate event so that if that
    1015             :   // event runs JavaScript that queries the media size, the
    1016             :   // frame has reflowed and the size updated beforehand.
    1017           0 :   Invalidate();
    1018             : 
    1019           0 :   if (logicalPositionChanged) {
    1020           0 :     FireTimeUpdate();
    1021             :   }
    1022           0 : }
    1023             : 
    1024             : void
    1025           0 : MediaDecoder::DurationChanged()
    1026             : {
    1027           0 :   MOZ_ASSERT(NS_IsMainThread());
    1028           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
    1029             : 
    1030           0 :   double oldDuration = mDuration;
    1031           0 :   if (IsInfinite()) {
    1032           0 :     mDuration = std::numeric_limits<double>::infinity();
    1033           0 :   } else if (mExplicitDuration.Ref().isSome()) {
    1034           0 :     mDuration = mExplicitDuration.Ref().ref();
    1035           0 :   } else if (mStateMachineDuration.Ref().isSome()) {
    1036           0 :     mDuration = mStateMachineDuration.Ref().ref().ToSeconds();
    1037             :   }
    1038             : 
    1039           0 :   if (mDuration == oldDuration || IsNaN(mDuration)) {
    1040           0 :     return;
    1041             :   }
    1042             : 
    1043           0 :   LOG("Duration changed to %f", mDuration);
    1044             : 
    1045             :   // Duration has changed so we should recompute playback rate
    1046           0 :   UpdatePlaybackRate();
    1047             : 
    1048             :   // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=28822 for a discussion
    1049             :   // of whether we should fire durationchange on explicit infinity.
    1050           0 :   if (mFiredMetadataLoaded
    1051           0 :       && (!mozilla::IsInfinite<double>(mDuration)
    1052           0 :           || mExplicitDuration.Ref().isSome())) {
    1053           0 :     GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
    1054             :   }
    1055             : 
    1056           0 :   if (CurrentPosition() > TimeUnit::FromSeconds(mDuration)) {
    1057           0 :     Seek(mDuration, SeekTarget::Accurate);
    1058             :   }
    1059             : }
    1060             : 
    1061             : void
    1062           0 : MediaDecoder::NotifyCompositor()
    1063             : {
    1064           0 :   MediaDecoderOwner* owner = GetOwner();
    1065           0 :   NS_ENSURE_TRUE_VOID(owner);
    1066             : 
    1067           0 :   nsIDocument* ownerDoc = owner->GetDocument();
    1068           0 :   NS_ENSURE_TRUE_VOID(ownerDoc);
    1069             : 
    1070             :   RefPtr<LayerManager> layerManager =
    1071           0 :     nsContentUtils::LayerManagerForDocument(ownerDoc);
    1072           0 :   if (layerManager) {
    1073           0 :     RefPtr<KnowsCompositor> knowsCompositor = layerManager->AsShadowForwarder();
    1074           0 :     mCompositorUpdatedEvent.Notify(knowsCompositor);
    1075             :   }
    1076             : }
    1077             : 
    1078             : void
    1079           0 : MediaDecoder::SetElementVisibility(bool aIsDocumentVisible,
    1080             :                                    Visibility aElementVisibility,
    1081             :                                    bool aIsElementInTree)
    1082             : {
    1083           0 :   MOZ_ASSERT(NS_IsMainThread());
    1084           0 :   mIsDocumentVisible = aIsDocumentVisible;
    1085           0 :   mElementVisibility = aElementVisibility;
    1086           0 :   mIsElementInTree = aIsElementInTree;
    1087           0 :   UpdateVideoDecodeMode();
    1088           0 : }
    1089             : 
    1090             : void
    1091           0 : MediaDecoder::SetForcedHidden(bool aForcedHidden)
    1092             : {
    1093           0 :   MOZ_ASSERT(NS_IsMainThread());
    1094           0 :   mForcedHidden = aForcedHidden;
    1095           0 :   UpdateVideoDecodeMode();
    1096           0 : }
    1097             : 
    1098             : void
    1099           0 : MediaDecoder::SetSuspendTaint(bool aTainted)
    1100             : {
    1101           0 :   MOZ_ASSERT(NS_IsMainThread());
    1102           0 :   mHasSuspendTaint = aTainted;
    1103           0 :   UpdateVideoDecodeMode();
    1104           0 : }
    1105             : 
    1106             : void
    1107           0 : MediaDecoder::UpdateVideoDecodeMode()
    1108             : {
    1109             :   // The MDSM may yet be set.
    1110           0 :   if (!mDecoderStateMachine) {
    1111           0 :     return;
    1112             :   }
    1113             : 
    1114             :   // If an element is in-tree with UNTRACKED visibility, the visibility is
    1115             :   // incomplete and don't update the video decode mode.
    1116           0 :   if (mIsElementInTree && mElementVisibility == Visibility::UNTRACKED) {
    1117           0 :     return;
    1118             :   }
    1119             : 
    1120             :   // If mHasSuspendTaint is set, never suspend the video decoder.
    1121           0 :   if (mHasSuspendTaint) {
    1122           0 :     mDecoderStateMachine->SetVideoDecodeMode(VideoDecodeMode::Normal);
    1123           0 :     return;
    1124             :   }
    1125             : 
    1126             :   // Don't suspend elements that is not in tree.
    1127           0 :   if (!mIsElementInTree) {
    1128           0 :     mDecoderStateMachine->SetVideoDecodeMode(VideoDecodeMode::Normal);
    1129           0 :     return;
    1130             :   }
    1131             : 
    1132             :   // If mForcedHidden is set, suspend the video decoder anyway.
    1133           0 :   if (mForcedHidden) {
    1134           0 :     mDecoderStateMachine->SetVideoDecodeMode(VideoDecodeMode::Suspend);
    1135           0 :     return;
    1136             :   }
    1137             : 
    1138             :   // Otherwise, depends on the owner's visibility state.
    1139             :   // A element is visible only if its document is visible and the element
    1140             :   // itself is visible.
    1141           0 :   if (mIsDocumentVisible &&
    1142           0 :       mElementVisibility == Visibility::APPROXIMATELY_VISIBLE) {
    1143           0 :     mDecoderStateMachine->SetVideoDecodeMode(VideoDecodeMode::Normal);
    1144             :   } else {
    1145           0 :     mDecoderStateMachine->SetVideoDecodeMode(VideoDecodeMode::Suspend);
    1146             :   }
    1147             : }
    1148             : 
    1149             : bool
    1150           0 : MediaDecoder::HasSuspendTaint() const
    1151             : {
    1152           0 :   MOZ_ASSERT(NS_IsMainThread());
    1153           0 :   return mHasSuspendTaint;
    1154             : }
    1155             : 
    1156             : bool
    1157           0 : MediaDecoder::IsTransportSeekable()
    1158             : {
    1159           0 :   MOZ_ASSERT(NS_IsMainThread());
    1160           0 :   return GetResource()->IsTransportSeekable();
    1161             : }
    1162             : 
    1163             : bool
    1164           0 : MediaDecoder::IsMediaSeekable()
    1165             : {
    1166           0 :   MOZ_ASSERT(NS_IsMainThread());
    1167           0 :   NS_ENSURE_TRUE(GetStateMachine(), false);
    1168           0 :   return mMediaSeekable;
    1169             : }
    1170             : 
    1171             : media::TimeIntervals
    1172           0 : MediaDecoder::GetSeekable()
    1173             : {
    1174           0 :   MOZ_ASSERT(NS_IsMainThread());
    1175             : 
    1176           0 :   if (IsNaN(GetDuration())) {
    1177             :     // We do not have a duration yet, we can't determine the seekable range.
    1178           0 :     return TimeIntervals();
    1179             :   }
    1180             : 
    1181             :   // We can seek in buffered range if the media is seekable. Also, we can seek
    1182             :   // in unbuffered ranges if the transport level is seekable (local file or the
    1183             :   // server supports range requests, etc.) or in cue-less WebMs
    1184           0 :   if (mMediaSeekableOnlyInBufferedRanges) {
    1185           0 :     return GetBuffered();
    1186           0 :   } else if (!IsMediaSeekable()) {
    1187           0 :     return media::TimeIntervals();
    1188           0 :   } else if (!IsTransportSeekable()) {
    1189           0 :     return GetBuffered();
    1190             :   } else {
    1191             :     return media::TimeIntervals(
    1192           0 :       media::TimeInterval(TimeUnit::Zero(),
    1193           0 :                           IsInfinite()
    1194           0 :                           ? TimeUnit::FromInfinity()
    1195           0 :                           : TimeUnit::FromSeconds(GetDuration())));
    1196             :   }
    1197             : }
    1198             : 
    1199             : void
    1200           0 : MediaDecoder::SetFragmentEndTime(double aTime)
    1201             : {
    1202           0 :   MOZ_ASSERT(NS_IsMainThread());
    1203           0 :   if (mDecoderStateMachine) {
    1204           0 :     mDecoderStateMachine->DispatchSetFragmentEndTime(
    1205           0 :       TimeUnit::FromSeconds(aTime));
    1206             :   }
    1207           0 : }
    1208             : 
    1209             : void
    1210           0 : MediaDecoder::Suspend()
    1211             : {
    1212           0 :   MOZ_ASSERT(NS_IsMainThread());
    1213           0 :   if (mResource) {
    1214           0 :     mResource->Suspend(true);
    1215             :   }
    1216           0 : }
    1217             : 
    1218             : void
    1219           0 : MediaDecoder::Resume()
    1220             : {
    1221           0 :   MOZ_ASSERT(NS_IsMainThread());
    1222           0 :   if (mResource) {
    1223           0 :     mResource->Resume();
    1224             :   }
    1225           0 : }
    1226             : 
    1227             : void
    1228           0 : MediaDecoder::SetLoadInBackground(bool aLoadInBackground)
    1229             : {
    1230           0 :   MOZ_ASSERT(NS_IsMainThread());
    1231           0 :   if (mResource) {
    1232           0 :     mResource->SetLoadInBackground(aLoadInBackground);
    1233             :   }
    1234           0 : }
    1235             : 
    1236             : void
    1237           0 : MediaDecoder::SetPlaybackRate(double aPlaybackRate)
    1238             : {
    1239           0 :   MOZ_ASSERT(NS_IsMainThread());
    1240             : 
    1241           0 :   double oldRate = mPlaybackRate;
    1242           0 :   mPlaybackRate = aPlaybackRate;
    1243           0 :   if (aPlaybackRate == 0) {
    1244           0 :     Pause();
    1245           0 :     return;
    1246             :   }
    1247             : 
    1248             : 
    1249           0 :   if (oldRate == 0 && !GetOwner()->GetPaused()) {
    1250             :     // PlaybackRate is no longer null.
    1251             :     // Restart the playback if the media was playing.
    1252           0 :     Play();
    1253             :   }
    1254             : 
    1255           0 :   if (mDecoderStateMachine) {
    1256           0 :     mDecoderStateMachine->DispatchSetPlaybackRate(aPlaybackRate);
    1257             :   }
    1258             : }
    1259             : 
    1260             : void
    1261           0 : MediaDecoder::SetPreservesPitch(bool aPreservesPitch)
    1262             : {
    1263           0 :   MOZ_ASSERT(NS_IsMainThread());
    1264           0 :   mPreservesPitch = aPreservesPitch;
    1265           0 : }
    1266             : 
    1267             : void
    1268           0 : MediaDecoder::SetLooping(bool aLooping)
    1269             : {
    1270           0 :   MOZ_ASSERT(NS_IsMainThread());
    1271           0 :   mLooping = aLooping;
    1272           0 : }
    1273             : 
    1274             : void
    1275           0 : MediaDecoder::ConnectMirrors(MediaDecoderStateMachine* aObject)
    1276             : {
    1277           0 :   MOZ_ASSERT(NS_IsMainThread());
    1278           0 :   MOZ_ASSERT(aObject);
    1279           0 :   mStateMachineDuration.Connect(aObject->CanonicalDuration());
    1280           0 :   mBuffered.Connect(aObject->CanonicalBuffered());
    1281           0 :   mNextFrameStatus.Connect(aObject->CanonicalNextFrameStatus());
    1282           0 :   mCurrentPosition.Connect(aObject->CanonicalCurrentPosition());
    1283           0 :   mPlaybackPosition.Connect(aObject->CanonicalPlaybackOffset());
    1284           0 :   mIsAudioDataAudible.Connect(aObject->CanonicalIsAudioDataAudible());
    1285           0 : }
    1286             : 
    1287             : void
    1288           0 : MediaDecoder::DisconnectMirrors()
    1289             : {
    1290           0 :   MOZ_ASSERT(NS_IsMainThread());
    1291           0 :   mStateMachineDuration.DisconnectIfConnected();
    1292           0 :   mBuffered.DisconnectIfConnected();
    1293           0 :   mNextFrameStatus.DisconnectIfConnected();
    1294           0 :   mCurrentPosition.DisconnectIfConnected();
    1295           0 :   mPlaybackPosition.DisconnectIfConnected();
    1296           0 :   mIsAudioDataAudible.DisconnectIfConnected();
    1297           0 : }
    1298             : 
    1299             : void
    1300           0 : MediaDecoder::SetStateMachine(MediaDecoderStateMachine* aStateMachine)
    1301             : {
    1302           0 :   MOZ_ASSERT(NS_IsMainThread());
    1303           0 :   MOZ_ASSERT_IF(aStateMachine, !mDecoderStateMachine);
    1304           0 :   mDecoderStateMachine = aStateMachine;
    1305           0 :   if (aStateMachine) {
    1306           0 :     ConnectMirrors(aStateMachine);
    1307           0 :     UpdateVideoDecodeMode();
    1308             :   } else {
    1309           0 :     DisconnectMirrors();
    1310             :   }
    1311           0 : }
    1312             : 
    1313             : ImageContainer*
    1314           0 : MediaDecoder::GetImageContainer()
    1315             : {
    1316           0 :   return mVideoFrameContainer ? mVideoFrameContainer->GetImageContainer()
    1317           0 :                               : nullptr;
    1318             : }
    1319             : 
    1320             : void
    1321           0 : MediaDecoder::InvalidateWithFlags(uint32_t aFlags)
    1322             : {
    1323           0 :   if (mVideoFrameContainer) {
    1324           0 :     mVideoFrameContainer->InvalidateWithFlags(aFlags);
    1325             :   }
    1326           0 : }
    1327             : 
    1328             : void
    1329           0 : MediaDecoder::Invalidate()
    1330             : {
    1331           0 :   if (mVideoFrameContainer) {
    1332           0 :     mVideoFrameContainer->Invalidate();
    1333             :   }
    1334           0 : }
    1335             : 
    1336             : // Constructs the time ranges representing what segments of the media
    1337             : // are buffered and playable.
    1338             : media::TimeIntervals
    1339           0 : MediaDecoder::GetBuffered()
    1340             : {
    1341           0 :   MOZ_ASSERT(NS_IsMainThread());
    1342           0 :   return mBuffered.Ref();
    1343             : }
    1344             : 
    1345             : size_t
    1346           0 : MediaDecoder::SizeOfVideoQueue()
    1347             : {
    1348           0 :   MOZ_ASSERT(NS_IsMainThread());
    1349           0 :   if (mDecoderStateMachine) {
    1350           0 :     return mDecoderStateMachine->SizeOfVideoQueue();
    1351             :   }
    1352           0 :   return 0;
    1353             : }
    1354             : 
    1355             : size_t
    1356           0 : MediaDecoder::SizeOfAudioQueue()
    1357             : {
    1358           0 :   MOZ_ASSERT(NS_IsMainThread());
    1359           0 :   if (mDecoderStateMachine) {
    1360           0 :     return mDecoderStateMachine->SizeOfAudioQueue();
    1361             :   }
    1362           0 :   return 0;
    1363             : }
    1364             : 
    1365           0 : void MediaDecoder::AddSizeOfResources(ResourceSizes* aSizes)
    1366             : {
    1367           0 :   MOZ_ASSERT(NS_IsMainThread());
    1368           0 :   if (GetResource()) {
    1369           0 :     aSizes->mByteSize +=
    1370           0 :       GetResource()->SizeOfIncludingThis(aSizes->mMallocSizeOf);
    1371             :   }
    1372           0 : }
    1373             : 
    1374             : void
    1375           0 : MediaDecoder::NotifyDataArrivedInternal()
    1376             : {
    1377           0 :   MOZ_ASSERT(NS_IsMainThread());
    1378           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
    1379           0 :   mReader->OwnerThread()->Dispatch(
    1380           0 :     NewRunnableMethod("MediaDecoderReader::NotifyDataArrived",
    1381           0 :                       mReader.get(),
    1382           0 :                       &MediaDecoderReader::NotifyDataArrived));
    1383           0 : }
    1384             : 
    1385             : void
    1386           0 : MediaDecoder::NotifyDataArrived()
    1387             : {
    1388           0 :   NotifyDataArrivedInternal();
    1389           0 :   DownloadProgressed();
    1390           0 : }
    1391             : 
    1392             : // Provide access to the state machine object
    1393             : MediaDecoderStateMachine*
    1394           0 : MediaDecoder::GetStateMachine() const
    1395             : {
    1396           0 :   MOZ_ASSERT(NS_IsMainThread());
    1397           0 :   return mDecoderStateMachine;
    1398             : }
    1399             : 
    1400             : void
    1401           0 : MediaDecoder::FireTimeUpdate()
    1402             : {
    1403           0 :   MOZ_ASSERT(NS_IsMainThread());
    1404           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
    1405           0 :   GetOwner()->FireTimeUpdate(true);
    1406           0 : }
    1407             : 
    1408             : void
    1409           0 : MediaDecoder::PinForSeek()
    1410             : {
    1411           0 :   MOZ_ASSERT(NS_IsMainThread());
    1412           0 :   MediaResource* resource = GetResource();
    1413           0 :   if (!resource || mPinnedForSeek) {
    1414           0 :     return;
    1415             :   }
    1416           0 :   mPinnedForSeek = true;
    1417           0 :   resource->Pin();
    1418             : }
    1419             : 
    1420             : void
    1421           0 : MediaDecoder::UnpinForSeek()
    1422             : {
    1423           0 :   MOZ_ASSERT(NS_IsMainThread());
    1424           0 :   MediaResource* resource = GetResource();
    1425           0 :   if (!resource || !mPinnedForSeek) {
    1426           0 :     return;
    1427             :   }
    1428           0 :   mPinnedForSeek = false;
    1429           0 :   resource->Unpin();
    1430             : }
    1431             : 
    1432             : bool
    1433           0 : MediaDecoder::CanPlayThrough()
    1434             : {
    1435           0 :   MOZ_ASSERT(NS_IsMainThread());
    1436           0 :   NS_ENSURE_TRUE(mDecoderStateMachine, false);
    1437           0 :   return GetStatistics().CanPlayThrough();
    1438             : }
    1439             : 
    1440             : RefPtr<MediaDecoder::CDMProxyPromise>
    1441           0 : MediaDecoder::RequestCDMProxy() const
    1442             : {
    1443           0 :   return mCDMProxyPromise;
    1444             : }
    1445             : 
    1446             : void
    1447           0 : MediaDecoder::SetCDMProxy(CDMProxy* aProxy)
    1448             : {
    1449           0 :   MOZ_ASSERT(NS_IsMainThread());
    1450           0 :   MOZ_ASSERT(aProxy);
    1451             : 
    1452           0 :   mCDMProxyPromiseHolder.ResolveIfExists(aProxy, __func__);
    1453           0 : }
    1454             : 
    1455             : bool
    1456           0 : MediaDecoder::IsOpusEnabled()
    1457             : {
    1458           0 :   return Preferences::GetBool("media.opus.enabled");
    1459             : }
    1460             : 
    1461             : bool
    1462           0 : MediaDecoder::IsOggEnabled()
    1463             : {
    1464           0 :   return Preferences::GetBool("media.ogg.enabled");
    1465             : }
    1466             : 
    1467             : bool
    1468           0 : MediaDecoder::IsWaveEnabled()
    1469             : {
    1470           0 :   return Preferences::GetBool("media.wave.enabled");
    1471             : }
    1472             : 
    1473             : bool
    1474           0 : MediaDecoder::IsWebMEnabled()
    1475             : {
    1476           0 :   return Preferences::GetBool("media.webm.enabled");
    1477             : }
    1478             : 
    1479             : #ifdef MOZ_ANDROID_OMX
    1480             : bool
    1481             : MediaDecoder::IsAndroidMediaPluginEnabled()
    1482             : {
    1483             :   return jni::GetAPIVersion() < 16
    1484             :          && Preferences::GetBool("media.plugins.enabled");
    1485             : }
    1486             : #endif
    1487             : 
    1488             : NS_IMETHODIMP
    1489           0 : MediaMemoryTracker::CollectReports(nsIHandleReportCallback* aHandleReport,
    1490             :                                    nsISupports* aData, bool aAnonymize)
    1491             : {
    1492             :   // NB: When resourceSizes' ref count goes to 0 the promise will report the
    1493             :   //     resources memory and finish the asynchronous memory report.
    1494             :   RefPtr<MediaDecoder::ResourceSizes> resourceSizes =
    1495           0 :       new MediaDecoder::ResourceSizes(MediaMemoryTracker::MallocSizeOf);
    1496             : 
    1497           0 :   nsCOMPtr<nsIHandleReportCallback> handleReport = aHandleReport;
    1498           0 :   nsCOMPtr<nsISupports> data = aData;
    1499             : 
    1500           0 :   resourceSizes->Promise()->Then(
    1501             :       // Don't use SystemGroup::AbstractMainThreadFor() for
    1502             :       // handleReport->Callback() will run scripts.
    1503           0 :       AbstractThread::MainThread(),
    1504             :       __func__,
    1505           0 :       [handleReport, data] (size_t size) {
    1506           0 :         handleReport->Callback(
    1507           0 :             EmptyCString(), NS_LITERAL_CSTRING("explicit/media/resources"),
    1508             :             KIND_HEAP, UNITS_BYTES, size,
    1509           0 :             NS_LITERAL_CSTRING("Memory used by media resources including "
    1510             :                                "streaming buffers, caches, etc."),
    1511           0 :             data);
    1512             : 
    1513             :         nsCOMPtr<nsIMemoryReporterManager> imgr =
    1514           0 :           do_GetService("@mozilla.org/memory-reporter-manager;1");
    1515             : 
    1516           0 :         if (imgr) {
    1517           0 :           imgr->EndReport();
    1518             :         }
    1519           0 :       },
    1520           0 :       [] (size_t) { /* unused reject function */ });
    1521             : 
    1522           0 :   int64_t video = 0;
    1523           0 :   int64_t audio = 0;
    1524           0 :   DecodersArray& decoders = Decoders();
    1525           0 :   for (size_t i = 0; i < decoders.Length(); ++i) {
    1526           0 :     MediaDecoder* decoder = decoders[i];
    1527           0 :     video += decoder->SizeOfVideoQueue();
    1528           0 :     audio += decoder->SizeOfAudioQueue();
    1529           0 :     decoder->AddSizeOfResources(resourceSizes);
    1530             :   }
    1531             : 
    1532           0 :   MOZ_COLLECT_REPORT(
    1533             :     "explicit/media/decoded/video", KIND_HEAP, UNITS_BYTES, video,
    1534           0 :     "Memory used by decoded video frames.");
    1535             : 
    1536           0 :   MOZ_COLLECT_REPORT(
    1537             :     "explicit/media/decoded/audio", KIND_HEAP, UNITS_BYTES, audio,
    1538           0 :     "Memory used by decoded audio chunks.");
    1539             : 
    1540           0 :   return NS_OK;
    1541             : }
    1542             : 
    1543             : MediaDecoderOwner*
    1544           0 : MediaDecoder::GetOwner() const
    1545             : {
    1546           0 :   MOZ_ASSERT(NS_IsMainThread());
    1547             :   // Check object lifetime when mOwner points to a media element.
    1548           0 :   MOZ_DIAGNOSTIC_ASSERT(!mOwner || !mIsMediaElement || mElement);
    1549             :   // mOwner is valid until shutdown.
    1550           0 :   return mOwner;
    1551             : }
    1552             : 
    1553             : MediaDecoderOwner::NextFrameStatus
    1554           0 : MediaDecoder::NextFrameBufferedStatus()
    1555             : {
    1556           0 :   MOZ_ASSERT(NS_IsMainThread());
    1557             :   // Next frame hasn't been decoded yet.
    1558             :   // Use the buffered range to consider if we have the next frame available.
    1559           0 :   auto currentPosition = CurrentPosition();
    1560             :   media::TimeInterval interval(
    1561             :     currentPosition,
    1562           0 :     currentPosition + DEFAULT_NEXT_FRAME_AVAILABLE_BUFFERED);
    1563           0 :   return GetBuffered().Contains(interval)
    1564           0 :          ? MediaDecoderOwner::NEXT_FRAME_AVAILABLE
    1565           0 :          : MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
    1566             : }
    1567             : 
    1568             : nsCString
    1569           0 : MediaDecoder::GetDebugInfo()
    1570             : {
    1571           0 :   return nsPrintfCString(
    1572             :     "MediaDecoder State: channels=%u rate=%u hasAudio=%d hasVideo=%d "
    1573             :     "mPlayState=%s mdsm=%p",
    1574           0 :     mInfo ? mInfo->mAudio.mChannels : 0, mInfo ? mInfo->mAudio.mRate : 0,
    1575           0 :     mInfo ? mInfo->HasAudio() : 0, mInfo ? mInfo->HasVideo() : 0,
    1576           0 :     PlayStateStr(), GetStateMachine());
    1577             : }
    1578             : 
    1579             : void
    1580           0 : MediaDecoder::DumpDebugInfo()
    1581             : {
    1582           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
    1583           0 :   nsCString str = GetDebugInfo();
    1584             : 
    1585           0 :   nsAutoCString readerStr;
    1586           0 :   GetMozDebugReaderData(readerStr);
    1587           0 :   if (!readerStr.IsEmpty()) {
    1588           0 :     str += "\nreader data:\n";
    1589           0 :     str += readerStr;
    1590             :   }
    1591             : 
    1592           0 :   if (!GetStateMachine()) {
    1593           0 :     DUMP("%s", str.get());
    1594           0 :     return;
    1595             :   }
    1596             : 
    1597           0 :   RefPtr<MediaDecoder> self = this;
    1598           0 :   GetStateMachine()->RequestDebugInfo()->Then(
    1599           0 :     SystemGroup::AbstractMainThreadFor(TaskCategory::Other), __func__,
    1600           0 :     [this, self, str] (const nsACString& aString) {
    1601           0 :       DUMP("%s", str.get());
    1602           0 :       DUMP("%s", aString.Data());
    1603           0 :     },
    1604           0 :     [this, self, str] () {
    1605           0 :       DUMP("%s", str.get());
    1606           0 :     });
    1607             : }
    1608             : 
    1609             : RefPtr<MediaDecoder::DebugInfoPromise>
    1610           0 : MediaDecoder::RequestDebugInfo()
    1611             : {
    1612           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
    1613             : 
    1614           0 :   auto str = GetDebugInfo();
    1615           0 :   if (!GetStateMachine()) {
    1616           0 :     return DebugInfoPromise::CreateAndResolve(str, __func__);
    1617             :   }
    1618             : 
    1619           0 :   return GetStateMachine()->RequestDebugInfo()->Then(
    1620           0 :     SystemGroup::AbstractMainThreadFor(TaskCategory::Other), __func__,
    1621           0 :     [str] (const nsACString& aString) {
    1622           0 :       nsCString result = str + nsCString("\n") + aString;
    1623           0 :       return DebugInfoPromise::CreateAndResolve(result, __func__);
    1624             :     },
    1625           0 :     [str] () {
    1626             :       return DebugInfoPromise::CreateAndResolve(str, __func__);
    1627           0 :     });
    1628             : }
    1629             : 
    1630             : void
    1631           0 : MediaDecoder::NotifyAudibleStateChanged()
    1632             : {
    1633           0 :   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
    1634           0 :   GetOwner()->SetAudibleState(mIsAudioDataAudible);
    1635           0 : }
    1636             : 
    1637           0 : MediaMemoryTracker::MediaMemoryTracker()
    1638             : {
    1639           0 : }
    1640             : 
    1641             : void
    1642           0 : MediaMemoryTracker::InitMemoryReporter()
    1643             : {
    1644           0 :   RegisterWeakAsyncMemoryReporter(this);
    1645           0 : }
    1646             : 
    1647           0 : MediaMemoryTracker::~MediaMemoryTracker()
    1648             : {
    1649           0 :   UnregisterWeakMemoryReporter(this);
    1650           0 : }
    1651             : 
    1652             : } // namespace mozilla
    1653             : 
    1654             : // avoid redefined macro in unified build
    1655             : #undef DUMP
    1656             : #undef LOG
    1657             : #undef NS_DispatchToMainThread

Generated by: LCOV version 1.13