LCOV - code coverage report
Current view: top level - dom/media - MediaDecoderReader.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 169 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 50 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             : 
       7             : #include "MediaDecoderReader.h"
       8             : 
       9             : #include "AbstractMediaDecoder.h"
      10             : #include "ImageContainer.h"
      11             : #include "MediaPrefs.h"
      12             : #include "MediaResource.h"
      13             : #include "VideoUtils.h"
      14             : #include "mozilla/Mutex.h"
      15             : #include "mozilla/SharedThreadPool.h"
      16             : #include "mozilla/TaskQueue.h"
      17             : #include "mozilla/mozalloc.h"
      18             : #include "nsPrintfCString.h"
      19             : #include <algorithm>
      20             : #include <stdint.h>
      21             : 
      22             : using namespace mozilla::media;
      23             : 
      24             : namespace mozilla {
      25             : 
      26             : // Un-comment to enable logging of seek bisections.
      27             : //#define SEEK_LOGGING
      28             : 
      29             : extern LazyLogModule gMediaDecoderLog;
      30             : 
      31             : // avoid redefined macro in unified build
      32             : #undef FMT
      33             : #undef DECODER_LOG
      34             : #undef DECODER_WARN
      35             : 
      36             : #define FMT(x, ...) "Decoder=%p " x, mDecoder, ##__VA_ARGS__
      37             : #define DECODER_LOG(...) MOZ_LOG(gMediaDecoderLog, LogLevel::Debug,   (FMT(__VA_ARGS__)))
      38             : #define DECODER_WARN(...) NS_WARNING(nsPrintfCString(FMT(__VA_ARGS__)).get())
      39             : 
      40           0 : class VideoQueueMemoryFunctor : public nsDequeFunctor {
      41             : public:
      42           0 :   VideoQueueMemoryFunctor() : mSize(0) {}
      43             : 
      44           0 :   MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf);
      45             : 
      46           0 :   virtual void* operator()(void* aObject) {
      47           0 :     const VideoData* v = static_cast<const VideoData*>(aObject);
      48           0 :     mSize += v->SizeOfIncludingThis(MallocSizeOf);
      49           0 :     return nullptr;
      50             :   }
      51             : 
      52             :   size_t mSize;
      53             : };
      54             : 
      55             : 
      56           0 : class AudioQueueMemoryFunctor : public nsDequeFunctor {
      57             : public:
      58           0 :   AudioQueueMemoryFunctor() : mSize(0) {}
      59             : 
      60           0 :   MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf);
      61             : 
      62           0 :   virtual void* operator()(void* aObject) {
      63           0 :     const AudioData* audioData = static_cast<const AudioData*>(aObject);
      64           0 :     mSize += audioData->SizeOfIncludingThis(MallocSizeOf);
      65           0 :     return nullptr;
      66             :   }
      67             : 
      68             :   size_t mSize;
      69             : };
      70             : 
      71           0 : MediaDecoderReader::MediaDecoderReader(const MediaDecoderReaderInit& aInit)
      72             :   : mAudioCompactor(mAudioQueue)
      73           0 :   , mDecoder(aInit.mDecoder)
      74             :   , mTaskQueue(new TaskQueue(
      75           0 :       GetMediaThreadPool(MediaThreadType::PLAYBACK),
      76             :       "MediaDecoderReader::mTaskQueue",
      77           0 :       /* aSupportsTailDispatch = */ true))
      78           0 :   , mBuffered(mTaskQueue, TimeIntervals(), "MediaDecoderReader::mBuffered (Canonical)")
      79             :   , mIgnoreAudioOutputFormat(false)
      80             :   , mHitAudioDecodeError(false)
      81             :   , mShutdown(false)
      82           0 :   , mResource(aInit.mResource)
      83             : {
      84           0 :   MOZ_COUNT_CTOR(MediaDecoderReader);
      85           0 :   MOZ_ASSERT(NS_IsMainThread());
      86           0 : }
      87             : 
      88             : nsresult
      89           0 : MediaDecoderReader::Init()
      90             : {
      91           0 :   return InitInternal();
      92             : }
      93             : 
      94           0 : MediaDecoderReader::~MediaDecoderReader()
      95             : {
      96           0 :   MOZ_ASSERT(mShutdown);
      97           0 :   MOZ_COUNT_DTOR(MediaDecoderReader);
      98           0 : }
      99             : 
     100           0 : size_t MediaDecoderReader::SizeOfVideoQueueInBytes() const
     101             : {
     102           0 :   VideoQueueMemoryFunctor functor;
     103           0 :   mVideoQueue.LockedForEach(functor);
     104           0 :   return functor.mSize;
     105             : }
     106             : 
     107           0 : size_t MediaDecoderReader::SizeOfAudioQueueInBytes() const
     108             : {
     109           0 :   AudioQueueMemoryFunctor functor;
     110           0 :   mAudioQueue.LockedForEach(functor);
     111           0 :   return functor.mSize;
     112             : }
     113             : 
     114           0 : size_t MediaDecoderReader::SizeOfVideoQueueInFrames()
     115             : {
     116           0 :   return mVideoQueue.GetSize();
     117             : }
     118             : 
     119           0 : size_t MediaDecoderReader::SizeOfAudioQueueInFrames()
     120             : {
     121           0 :   return mAudioQueue.GetSize();
     122             : }
     123             : 
     124             : void
     125           0 : MediaDecoderReader::UpdateDuration(const media::TimeUnit& aDuration)
     126             : {
     127           0 :   MOZ_ASSERT(OnTaskQueue());
     128           0 :   mDuration = Some(aDuration);
     129           0 :   UpdateBuffered();
     130           0 : }
     131             : 
     132           0 : nsresult MediaDecoderReader::ResetDecode(TrackSet aTracks)
     133             : {
     134           0 :   if (aTracks.contains(TrackInfo::kVideoTrack)) {
     135           0 :     VideoQueue().Reset();
     136           0 :     mBaseVideoPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
     137             :   }
     138             : 
     139           0 :   if (aTracks.contains(TrackInfo::kAudioTrack)) {
     140           0 :     AudioQueue().Reset();
     141           0 :     mBaseAudioPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
     142             :   }
     143             : 
     144           0 :   return NS_OK;
     145             : }
     146             : 
     147             : RefPtr<MediaDecoderReader::VideoDataPromise>
     148           0 : MediaDecoderReader::DecodeToFirstVideoData()
     149             : {
     150           0 :   MOZ_ASSERT(OnTaskQueue());
     151             :   typedef VideoDataPromise PromiseType;
     152           0 :   RefPtr<PromiseType::Private> p = new PromiseType::Private(__func__);
     153           0 :   RefPtr<MediaDecoderReader> self = this;
     154           0 :   InvokeUntil([self] () -> bool {
     155           0 :     MOZ_ASSERT(self->OnTaskQueue());
     156           0 :     NS_ENSURE_TRUE(!self->mShutdown, false);
     157           0 :     bool skip = false;
     158           0 :     if (!self->DecodeVideoFrame(skip, media::TimeUnit::Zero())) {
     159           0 :       self->VideoQueue().Finish();
     160           0 :       return !!self->VideoQueue().PeekFront();
     161             :     }
     162           0 :     return true;
     163           0 :   }, [self] () -> bool {
     164           0 :     MOZ_ASSERT(self->OnTaskQueue());
     165           0 :     return self->VideoQueue().GetSize();
     166           0 :   })->Then(OwnerThread(), __func__, [self, p] () {
     167           0 :     p->Resolve(self->VideoQueue().PeekFront(), __func__);
     168           0 :   }, [p] () {
     169             :     // We don't have a way to differentiate EOS, error, and shutdown here. :-(
     170           0 :     p->Reject(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
     171           0 :   });
     172             : 
     173           0 :   return p.forget();
     174             : }
     175             : 
     176             : void
     177           0 : MediaDecoderReader::UpdateBuffered()
     178             : {
     179           0 :   MOZ_ASSERT(OnTaskQueue());
     180           0 :   NS_ENSURE_TRUE_VOID(!mShutdown);
     181           0 :   mBuffered = GetBuffered();
     182             : }
     183             : 
     184             : void
     185           0 : MediaDecoderReader::VisibilityChanged()
     186           0 : {}
     187             : 
     188             : media::TimeIntervals
     189           0 : MediaDecoderReader::GetBuffered()
     190             : {
     191           0 :   MOZ_ASSERT(OnTaskQueue());
     192             : 
     193           0 :   if (mDuration.isNothing()) {
     194           0 :     return TimeIntervals();
     195             :   }
     196             : 
     197           0 :   AutoPinned<MediaResource> stream(mResource);
     198           0 :   return GetEstimatedBufferedTimeRanges(stream, mDuration->ToMicroseconds());
     199             : }
     200             : 
     201             : RefPtr<MediaDecoderReader::MetadataPromise>
     202           0 : MediaDecoderReader::AsyncReadMetadata()
     203             : {
     204           0 :   MOZ_ASSERT(OnTaskQueue());
     205           0 :   DECODER_LOG("MediaDecoderReader::AsyncReadMetadata");
     206             : 
     207             :   // Attempt to read the metadata.
     208           0 :   MetadataHolder metadata;
     209           0 :   metadata.mInfo = MakeUnique<MediaInfo>();
     210           0 :   MetadataTags* tags = nullptr;
     211           0 :   nsresult rv = ReadMetadata(metadata.mInfo.get(), &tags);
     212           0 :   metadata.mTags.reset(tags);
     213           0 :   metadata.mInfo->AssertValid();
     214             : 
     215             :   // Update the buffer ranges before resolving the metadata promise. Bug 1320258.
     216           0 :   UpdateBuffered();
     217             : 
     218             :   // We're not waiting for anything. If we didn't get the metadata, that's an
     219             :   // error.
     220           0 :   if (NS_FAILED(rv) || !metadata.mInfo->HasValidMedia()) {
     221           0 :     DECODER_WARN("ReadMetadata failed, rv=%" PRIx32 " HasValidMedia=%d",
     222           0 :                  static_cast<uint32_t>(rv), metadata.mInfo->HasValidMedia());
     223           0 :     return MetadataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
     224             :   }
     225             : 
     226             :   // Success!
     227           0 :   return MetadataPromise::CreateAndResolve(Move(metadata), __func__);
     228             : }
     229             : 
     230           0 : class ReRequestVideoWithSkipTask : public Runnable
     231             : {
     232             : public:
     233           0 :   ReRequestVideoWithSkipTask(MediaDecoderReader* aReader,
     234             :                              const media::TimeUnit& aTimeThreshold)
     235           0 :     : Runnable("ReRequestVideoWithSkipTask")
     236             :     , mReader(aReader)
     237           0 :     , mTimeThreshold(aTimeThreshold)
     238             :   {
     239           0 :   }
     240             : 
     241           0 :   NS_IMETHOD Run() override
     242             :   {
     243           0 :     MOZ_ASSERT(mReader->OnTaskQueue());
     244             : 
     245             :     // Make sure ResetDecode hasn't been called in the mean time.
     246           0 :     if (!mReader->mBaseVideoPromise.IsEmpty()) {
     247           0 :       mReader->RequestVideoData(mTimeThreshold);
     248             :     }
     249             : 
     250           0 :     return NS_OK;
     251             :   }
     252             : 
     253             : private:
     254             :   RefPtr<MediaDecoderReader> mReader;
     255             :   const media::TimeUnit mTimeThreshold;
     256             : };
     257             : 
     258           0 : class ReRequestAudioTask : public Runnable
     259             : {
     260             : public:
     261           0 :   explicit ReRequestAudioTask(MediaDecoderReader* aReader)
     262           0 :     : Runnable("ReRequestAudioTask")
     263           0 :     , mReader(aReader)
     264             :   {
     265           0 :   }
     266             : 
     267           0 :   NS_IMETHOD Run() override
     268             :   {
     269           0 :     MOZ_ASSERT(mReader->OnTaskQueue());
     270             : 
     271             :     // Make sure ResetDecode hasn't been called in the mean time.
     272           0 :     if (!mReader->mBaseAudioPromise.IsEmpty()) {
     273           0 :       mReader->RequestAudioData();
     274             :     }
     275             : 
     276           0 :     return NS_OK;
     277             :   }
     278             : 
     279             : private:
     280             :   RefPtr<MediaDecoderReader> mReader;
     281             : };
     282             : 
     283             : RefPtr<MediaDecoderReader::VideoDataPromise>
     284           0 : MediaDecoderReader::RequestVideoData(const media::TimeUnit& aTimeThreshold)
     285             : {
     286           0 :   RefPtr<VideoDataPromise> p = mBaseVideoPromise.Ensure(__func__);
     287           0 :   bool skip = false;
     288           0 :   while (VideoQueue().GetSize() == 0 &&
     289           0 :          !VideoQueue().IsFinished()) {
     290           0 :     if (!DecodeVideoFrame(skip, aTimeThreshold)) {
     291           0 :       VideoQueue().Finish();
     292           0 :     } else if (skip) {
     293             :       // We still need to decode more data in order to skip to the next
     294             :       // keyframe. Post another task to the decode task queue to decode
     295             :       // again. We don't just decode straight in a loop here, as that
     296             :       // would hog the decode task queue.
     297             :       RefPtr<nsIRunnable> task(
     298           0 :         new ReRequestVideoWithSkipTask(this, aTimeThreshold));
     299           0 :       mTaskQueue->Dispatch(task.forget());
     300           0 :       return p;
     301             :     }
     302             :   }
     303           0 :   if (VideoQueue().GetSize() > 0) {
     304           0 :     RefPtr<VideoData> v = VideoQueue().PopFront();
     305           0 :     mBaseVideoPromise.Resolve(v, __func__);
     306           0 :   } else if (VideoQueue().IsFinished()) {
     307           0 :     mBaseVideoPromise.Reject(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
     308             :   } else {
     309           0 :     MOZ_ASSERT(false, "Dropping this promise on the floor");
     310             :   }
     311             : 
     312           0 :   return p;
     313             : }
     314             : 
     315             : RefPtr<MediaDecoderReader::AudioDataPromise>
     316           0 : MediaDecoderReader::RequestAudioData()
     317             : {
     318           0 :   RefPtr<AudioDataPromise> p = mBaseAudioPromise.Ensure(__func__);
     319           0 :   while (AudioQueue().GetSize() == 0 &&
     320           0 :          !AudioQueue().IsFinished()) {
     321           0 :     if (!DecodeAudioData()) {
     322           0 :       AudioQueue().Finish();
     323           0 :       break;
     324             :     }
     325             :     // AudioQueue size is still zero, post a task to try again. Don't spin
     326             :     // waiting in this while loop since it somehow prevents audio EOS from
     327             :     // coming in gstreamer 1.x when there is still video buffer waiting to be
     328             :     // consumed. (|mVideoSinkBufferCount| > 0)
     329           0 :     if (AudioQueue().GetSize() == 0) {
     330           0 :       RefPtr<nsIRunnable> task(new ReRequestAudioTask(this));
     331           0 :       mTaskQueue->Dispatch(task.forget());
     332           0 :       return p;
     333             :     }
     334             :   }
     335           0 :   if (AudioQueue().GetSize() > 0) {
     336           0 :     RefPtr<AudioData> a = AudioQueue().PopFront();
     337           0 :     mBaseAudioPromise.Resolve(a, __func__);
     338           0 :   } else if (AudioQueue().IsFinished()) {
     339           0 :     mBaseAudioPromise.Reject(mHitAudioDecodeError
     340             :                              ? NS_ERROR_DOM_MEDIA_FATAL_ERR
     341           0 :                              : NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
     342           0 :     mHitAudioDecodeError = false;
     343             :   } else {
     344           0 :     MOZ_ASSERT(false, "Dropping this promise on the floor");
     345             :   }
     346             : 
     347           0 :   return p;
     348             : }
     349             : 
     350             : RefPtr<ShutdownPromise>
     351           0 : MediaDecoderReader::Shutdown()
     352             : {
     353           0 :   MOZ_ASSERT(OnTaskQueue());
     354           0 :   mShutdown = true;
     355             : 
     356           0 :   mBaseAudioPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
     357           0 :   mBaseVideoPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
     358             : 
     359           0 :   ReleaseResources();
     360           0 :   mBuffered.DisconnectAll();
     361             : 
     362           0 :   mDecoder = nullptr;
     363             : 
     364           0 :   return mTaskQueue->BeginShutdown();
     365             : }
     366             : 
     367             : } // namespace mozilla

Generated by: LCOV version 1.13