LCOV - code coverage report
Current view: top level - dom/media/mediasource - MediaSourceDecoder.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 171 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 20 0.0 %
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             : #include "MediaSourceDecoder.h"
       7             : 
       8             : #include "mozilla/Logging.h"
       9             : #include "mozilla/dom/HTMLMediaElement.h"
      10             : #include "MediaDecoderStateMachine.h"
      11             : #include "MediaShutdownManager.h"
      12             : #include "MediaSource.h"
      13             : #include "MediaSourceResource.h"
      14             : #include "MediaSourceUtils.h"
      15             : #include "VideoUtils.h"
      16             : #include "MediaSourceDemuxer.h"
      17             : #include "SourceBufferList.h"
      18             : #include <algorithm>
      19             : 
      20             : extern mozilla::LogModule* GetMediaSourceLog();
      21             : 
      22             : #define MSE_DEBUG(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Debug, ("MediaSourceDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
      23             : #define MSE_DEBUGV(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Verbose, ("MediaSourceDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
      24             : 
      25             : using namespace mozilla::media;
      26             : 
      27             : namespace mozilla {
      28             : 
      29           0 : MediaSourceDecoder::MediaSourceDecoder(MediaDecoderInit& aInit)
      30             :   : MediaDecoder(aInit)
      31             :   , mMediaSource(nullptr)
      32           0 :   , mEnded(false)
      33             : {
      34           0 :   mExplicitDuration.Set(Some(UnspecifiedNaN<double>()));
      35           0 : }
      36             : 
      37             : MediaDecoderStateMachine*
      38           0 : MediaSourceDecoder::CreateStateMachine()
      39             : {
      40           0 :   MOZ_ASSERT(NS_IsMainThread());
      41           0 :   mDemuxer = new MediaSourceDemuxer(AbstractMainThread());
      42           0 :   MediaDecoderReaderInit init(this);
      43           0 :   init.mVideoFrameContainer = GetVideoFrameContainer();
      44           0 :   mReader = new MediaFormatReader(init, mDemuxer);
      45           0 :   return new MediaDecoderStateMachine(this, mReader);
      46             : }
      47             : 
      48             : nsresult
      49           0 : MediaSourceDecoder::Load(nsIPrincipal* aPrincipal)
      50             : {
      51           0 :   MOZ_ASSERT(NS_IsMainThread());
      52           0 :   MOZ_ASSERT(!GetStateMachine());
      53             : 
      54           0 :   mResource = new MediaSourceResource(aPrincipal);
      55             : 
      56           0 :   nsresult rv = MediaShutdownManager::Instance().Register(this);
      57           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
      58           0 :     return rv;
      59             :   }
      60             : 
      61           0 :   SetStateMachine(CreateStateMachine());
      62           0 :   if (!GetStateMachine()) {
      63           0 :     NS_WARNING("Failed to create state machine!");
      64           0 :     return NS_ERROR_FAILURE;
      65             :   }
      66             : 
      67           0 :   rv = GetStateMachine()->Init(this);
      68           0 :   NS_ENSURE_SUCCESS(rv, rv);
      69             : 
      70           0 :   SetStateMachineParameters();
      71           0 :   return NS_OK;
      72             : }
      73             : 
      74             : media::TimeIntervals
      75           0 : MediaSourceDecoder::GetSeekable()
      76             : {
      77           0 :   MOZ_ASSERT(NS_IsMainThread());
      78           0 :   if (!mMediaSource) {
      79           0 :     NS_WARNING("MediaSource element isn't attached");
      80           0 :     return media::TimeIntervals::Invalid();
      81             :   }
      82             : 
      83           0 :   media::TimeIntervals seekable;
      84           0 :   double duration = mMediaSource->Duration();
      85           0 :   if (IsNaN(duration)) {
      86             :     // Return empty range.
      87           0 :   } else if (duration > 0 && mozilla::IsInfinite(duration)) {
      88           0 :     media::TimeIntervals buffered = GetBuffered();
      89             : 
      90             :     // 1. If live seekable range is not empty:
      91           0 :     if (mMediaSource->HasLiveSeekableRange()) {
      92             :       // 1. Let union ranges be the union of live seekable range and the
      93             :       // HTMLMediaElement.buffered attribute.
      94             :       media::TimeIntervals unionRanges =
      95           0 :         buffered + mMediaSource->LiveSeekableRange();
      96             :       // 2. Return a single range with a start time equal to the earliest start
      97             :       // time in union ranges and an end time equal to the highest end time in
      98             :       // union ranges and abort these steps.
      99             :       seekable +=
     100           0 :         media::TimeInterval(unionRanges.GetStart(), unionRanges.GetEnd());
     101           0 :       return seekable;
     102             :     }
     103             : 
     104           0 :     if (buffered.Length()) {
     105           0 :       seekable += media::TimeInterval(TimeUnit::Zero(), buffered.GetEnd());
     106             :     }
     107             :   } else {
     108           0 :     seekable += media::TimeInterval(TimeUnit::Zero(),
     109           0 :                                     TimeUnit::FromSeconds(duration));
     110             :   }
     111           0 :   MSE_DEBUG("ranges=%s", DumpTimeRanges(seekable).get());
     112           0 :   return seekable;
     113             : }
     114             : 
     115             : media::TimeIntervals
     116           0 : MediaSourceDecoder::GetBuffered()
     117             : {
     118           0 :   MOZ_ASSERT(NS_IsMainThread());
     119             : 
     120           0 :   if (!mMediaSource) {
     121           0 :     NS_WARNING("MediaSource element isn't attached");
     122           0 :     return media::TimeIntervals::Invalid();
     123             :   }
     124           0 :   dom::SourceBufferList* sourceBuffers = mMediaSource->ActiveSourceBuffers();
     125           0 :   if (!sourceBuffers) {
     126             :     // Media source object is shutting down.
     127           0 :     return TimeIntervals();
     128             :   }
     129           0 :   TimeUnit highestEndTime;
     130           0 :   nsTArray<media::TimeIntervals> activeRanges;
     131           0 :   media::TimeIntervals buffered;
     132             : 
     133           0 :   for (uint32_t i = 0; i < sourceBuffers->Length(); i++) {
     134             :     bool found;
     135           0 :     dom::SourceBuffer* sb = sourceBuffers->IndexedGetter(i, found);
     136           0 :     MOZ_ASSERT(found);
     137             : 
     138           0 :     activeRanges.AppendElement(sb->GetTimeIntervals());
     139           0 :     highestEndTime =
     140           0 :       std::max(highestEndTime, activeRanges.LastElement().GetEnd());
     141             :   }
     142             : 
     143           0 :   buffered += media::TimeInterval(TimeUnit::Zero(), highestEndTime);
     144             : 
     145           0 :   for (auto& range : activeRanges) {
     146           0 :     if (mEnded && range.Length()) {
     147             :       // Set the end time on the last range to highestEndTime by adding a
     148             :       // new range spanning the current end time to highestEndTime, which
     149             :       // Normalize() will then merge with the old last range.
     150             :       range +=
     151           0 :         media::TimeInterval(range.GetEnd(), highestEndTime);
     152             :     }
     153           0 :     buffered.Intersection(range);
     154             :   }
     155             : 
     156           0 :   MSE_DEBUG("ranges=%s", DumpTimeRanges(buffered).get());
     157           0 :   return buffered;
     158             : }
     159             : 
     160             : void
     161           0 : MediaSourceDecoder::Shutdown()
     162             : {
     163           0 :   MOZ_ASSERT(NS_IsMainThread());
     164           0 :   MSE_DEBUG("Shutdown");
     165             :   // Detach first so that TrackBuffers are unused on the main thread when
     166             :   // shut down on the decode task queue.
     167           0 :   if (mMediaSource) {
     168           0 :     mMediaSource->Detach();
     169             :   }
     170           0 :   mDemuxer = nullptr;
     171             : 
     172           0 :   MediaDecoder::Shutdown();
     173           0 : }
     174             : 
     175             : void
     176           0 : MediaSourceDecoder::AttachMediaSource(dom::MediaSource* aMediaSource)
     177             : {
     178           0 :   MOZ_ASSERT(!mMediaSource && !GetStateMachine() && NS_IsMainThread());
     179           0 :   mMediaSource = aMediaSource;
     180           0 : }
     181             : 
     182             : void
     183           0 : MediaSourceDecoder::DetachMediaSource()
     184             : {
     185           0 :   MOZ_ASSERT(mMediaSource && NS_IsMainThread());
     186           0 :   mMediaSource = nullptr;
     187           0 : }
     188             : 
     189             : void
     190           0 : MediaSourceDecoder::Ended(bool aEnded)
     191             : {
     192           0 :   MOZ_ASSERT(NS_IsMainThread());
     193           0 :   static_cast<MediaSourceResource*>(mResource.get())->SetEnded(aEnded);
     194           0 :   if (aEnded) {
     195             :     // We want the MediaSourceReader to refresh its buffered range as it may
     196             :     // have been modified (end lined up).
     197           0 :     NotifyDataArrived();
     198             :   }
     199           0 :   mEnded = aEnded;
     200           0 : }
     201             : 
     202             : void
     203           0 : MediaSourceDecoder::AddSizeOfResources(ResourceSizes* aSizes)
     204             : {
     205           0 :   MOZ_ASSERT(NS_IsMainThread());
     206           0 :   if (GetDemuxer()) {
     207           0 :     GetDemuxer()->AddSizeOfResources(aSizes);
     208             :   }
     209           0 : }
     210             : 
     211             : void
     212           0 : MediaSourceDecoder::SetInitialDuration(int64_t aDuration)
     213             : {
     214           0 :   MOZ_ASSERT(NS_IsMainThread());
     215             :   // Only use the decoded duration if one wasn't already
     216             :   // set.
     217           0 :   if (!mMediaSource || !IsNaN(ExplicitDuration())) {
     218           0 :     return;
     219             :   }
     220           0 :   double duration = aDuration;
     221             :   // A duration of -1 is +Infinity.
     222           0 :   if (aDuration >= 0) {
     223           0 :     duration /= USECS_PER_S;
     224             :   }
     225           0 :   SetMediaSourceDuration(duration);
     226             : }
     227             : 
     228             : void
     229           0 : MediaSourceDecoder::SetMediaSourceDuration(double aDuration)
     230             : {
     231           0 :   MOZ_ASSERT(NS_IsMainThread());
     232           0 :   MOZ_ASSERT(!IsShutdown());
     233           0 :   if (aDuration >= 0) {
     234             :     int64_t checkedDuration;
     235           0 :     if (NS_FAILED(SecondsToUsecs(aDuration, checkedDuration))) {
     236             :       // INT64_MAX is used as infinity by the state machine.
     237             :       // We want a very bigger number, but not infinity.
     238           0 :       checkedDuration = INT64_MAX - 1;
     239             :     }
     240           0 :     SetExplicitDuration(aDuration);
     241             :   } else {
     242           0 :     SetExplicitDuration(PositiveInfinity<double>());
     243             :   }
     244           0 : }
     245             : 
     246             : void
     247           0 : MediaSourceDecoder::GetMozDebugReaderData(nsACString& aString)
     248             : {
     249           0 :   if (mReader && mDemuxer) {
     250             :     // This is definitely a MediaFormatReader. See CreateStateMachine() above.
     251           0 :     auto reader = static_cast<MediaFormatReader*>(mReader.get());
     252           0 :     reader->GetMozDebugReaderData(aString);
     253           0 :     mDemuxer->GetMozDebugReaderData(aString);
     254             :   }
     255           0 : }
     256             : 
     257             : double
     258           0 : MediaSourceDecoder::GetDuration()
     259             : {
     260           0 :   MOZ_ASSERT(NS_IsMainThread());
     261           0 :   return ExplicitDuration();
     262             : }
     263             : 
     264             : MediaDecoderOwner::NextFrameStatus
     265           0 : MediaSourceDecoder::NextFrameBufferedStatus()
     266             : {
     267           0 :   MOZ_ASSERT(NS_IsMainThread());
     268             : 
     269           0 :   if (!mMediaSource
     270           0 :       || mMediaSource->ReadyState() == dom::MediaSourceReadyState::Closed) {
     271           0 :     return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
     272             :   }
     273             : 
     274             :   // Next frame hasn't been decoded yet.
     275             :   // Use the buffered range to consider if we have the next frame available.
     276           0 :   auto currentPosition = CurrentPosition();
     277           0 :   TimeIntervals buffered = GetBuffered();
     278           0 :   buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ / 2);
     279             :   TimeInterval interval(
     280             :     currentPosition,
     281           0 :     currentPosition + DEFAULT_NEXT_FRAME_AVAILABLE_BUFFERED);
     282           0 :   return buffered.ContainsStrict(ClampIntervalToEnd(interval))
     283           0 :          ? MediaDecoderOwner::NEXT_FRAME_AVAILABLE
     284           0 :          : MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
     285             : }
     286             : 
     287             : bool
     288           0 : MediaSourceDecoder::CanPlayThrough()
     289             : {
     290           0 :   MOZ_ASSERT(NS_IsMainThread());
     291             : 
     292           0 :   if (NextFrameBufferedStatus() == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE) {
     293           0 :     return false;
     294             :   }
     295             : 
     296           0 :   if (IsNaN(mMediaSource->Duration())) {
     297             :     // Don't have any data yet.
     298           0 :     return false;
     299             :   }
     300           0 :   TimeUnit duration = TimeUnit::FromSeconds(mMediaSource->Duration());
     301           0 :   auto currentPosition = CurrentPosition();
     302           0 :   if (duration.IsInfinite()) {
     303             :     // We can't make an informed decision and just assume that it's a live
     304             :     // stream
     305           0 :     return true;
     306           0 :   } else if (duration <= currentPosition) {
     307           0 :     return true;
     308             :   }
     309             :   // If we have data up to the mediasource's duration or 30s ahead, we can
     310             :   // assume that we can play without interruption.
     311           0 :   TimeIntervals buffered = GetBuffered();
     312           0 :   buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ / 2);
     313             :   TimeUnit timeAhead =
     314           0 :     std::min(duration, currentPosition + TimeUnit::FromSeconds(30));
     315           0 :   TimeInterval interval(currentPosition, timeAhead);
     316           0 :   return buffered.ContainsStrict(ClampIntervalToEnd(interval));
     317             : }
     318             : 
     319             : void
     320           0 : MediaSourceDecoder::NotifyWaitingForKey()
     321             : {
     322           0 :   mWaitingForKeyEvent.Notify();
     323           0 : }
     324             : 
     325             : MediaEventSource<void>*
     326           0 : MediaSourceDecoder::WaitingForKeyEvent()
     327             : {
     328           0 :   return &mWaitingForKeyEvent;
     329             : }
     330             : 
     331             : TimeInterval
     332           0 : MediaSourceDecoder::ClampIntervalToEnd(const TimeInterval& aInterval)
     333             : {
     334           0 :   MOZ_ASSERT(NS_IsMainThread());
     335             : 
     336           0 :   if (!mEnded) {
     337           0 :     return aInterval;
     338             :   }
     339           0 :   TimeUnit duration = TimeUnit::FromSeconds(GetDuration());
     340           0 :   if (duration < aInterval.mStart) {
     341           0 :     return aInterval;
     342             :   }
     343             :   return TimeInterval(aInterval.mStart,
     344             :                       std::min(aInterval.mEnd, duration),
     345           0 :                       aInterval.mFuzz);
     346             : }
     347             : 
     348             : void
     349           0 : MediaSourceDecoder::NotifyInitDataArrived()
     350             : {
     351           0 :   MOZ_ASSERT(NS_IsMainThread());
     352             : 
     353           0 :   if (mDemuxer) {
     354           0 :     mDemuxer->NotifyInitDataArrived();
     355             :   }
     356           0 : }
     357             : 
     358             : #undef MSE_DEBUG
     359             : #undef MSE_DEBUGV
     360             : 
     361             : } // namespace mozilla

Generated by: LCOV version 1.13