1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/MediaQueue.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,200 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 +#if !defined(MediaQueue_h_) 1.10 +#define MediaQueue_h_ 1.11 + 1.12 +#include "nsDeque.h" 1.13 +#include "nsTArray.h" 1.14 +#include "mozilla/ReentrantMonitor.h" 1.15 +#include "mozilla/RefPtr.h" 1.16 +#include "MediaTaskQueue.h" 1.17 + 1.18 +namespace mozilla { 1.19 + 1.20 +// Thread and type safe wrapper around nsDeque. 1.21 +template <class T> 1.22 +class MediaQueueDeallocator : public nsDequeFunctor { 1.23 + virtual void* operator() (void* anObject) { 1.24 + delete static_cast<T*>(anObject); 1.25 + return nullptr; 1.26 + } 1.27 +}; 1.28 + 1.29 +template <class T> class MediaQueue : private nsDeque { 1.30 + public: 1.31 + 1.32 + MediaQueue() 1.33 + : nsDeque(new MediaQueueDeallocator<T>()), 1.34 + mReentrantMonitor("mediaqueue"), 1.35 + mEndOfStream(false) 1.36 + {} 1.37 + 1.38 + ~MediaQueue() { 1.39 + Reset(); 1.40 + } 1.41 + 1.42 + inline int32_t GetSize() { 1.43 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.44 + return nsDeque::GetSize(); 1.45 + } 1.46 + 1.47 + inline void Push(T* aItem) { 1.48 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.49 + nsDeque::Push(aItem); 1.50 + } 1.51 + 1.52 + inline void PushFront(T* aItem) { 1.53 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.54 + nsDeque::PushFront(aItem); 1.55 + } 1.56 + 1.57 + inline T* PopFront() { 1.58 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.59 + T* rv = static_cast<T*>(nsDeque::PopFront()); 1.60 + if (rv) { 1.61 + NotifyPopListeners(); 1.62 + } 1.63 + return rv; 1.64 + } 1.65 + 1.66 + inline T* Peek() { 1.67 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.68 + return static_cast<T*>(nsDeque::Peek()); 1.69 + } 1.70 + 1.71 + inline T* PeekFront() { 1.72 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.73 + return static_cast<T*>(nsDeque::PeekFront()); 1.74 + } 1.75 + 1.76 + inline void Empty() { 1.77 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.78 + nsDeque::Empty(); 1.79 + } 1.80 + 1.81 + inline void Erase() { 1.82 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.83 + nsDeque::Erase(); 1.84 + } 1.85 + 1.86 + void Reset() { 1.87 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.88 + while (GetSize() > 0) { 1.89 + T* x = PopFront(); 1.90 + delete x; 1.91 + } 1.92 + mEndOfStream = false; 1.93 + } 1.94 + 1.95 + bool AtEndOfStream() { 1.96 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.97 + return GetSize() == 0 && mEndOfStream; 1.98 + } 1.99 + 1.100 + // Returns true if the media queue has had its last item added to it. 1.101 + // This happens when the media stream has been completely decoded. Note this 1.102 + // does not mean that the corresponding stream has finished playback. 1.103 + bool IsFinished() { 1.104 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.105 + return mEndOfStream; 1.106 + } 1.107 + 1.108 + // Informs the media queue that it won't be receiving any more items. 1.109 + void Finish() { 1.110 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.111 + mEndOfStream = true; 1.112 + } 1.113 + 1.114 + // Returns the approximate number of microseconds of items in the queue. 1.115 + int64_t Duration() { 1.116 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.117 + if (GetSize() < 2) { 1.118 + return 0; 1.119 + } 1.120 + T* last = Peek(); 1.121 + T* first = PeekFront(); 1.122 + return last->mTime - first->mTime; 1.123 + } 1.124 + 1.125 + void LockedForEach(nsDequeFunctor& aFunctor) const { 1.126 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.127 + ForEach(aFunctor); 1.128 + } 1.129 + 1.130 + // Extracts elements from the queue into aResult, in order. 1.131 + // Elements whose start time is before aTime are ignored. 1.132 + void GetElementsAfter(int64_t aTime, nsTArray<T*>* aResult) { 1.133 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.134 + if (!GetSize()) 1.135 + return; 1.136 + int32_t i; 1.137 + for (i = GetSize() - 1; i > 0; --i) { 1.138 + T* v = static_cast<T*>(ObjectAt(i)); 1.139 + if (v->GetEndTime() < aTime) 1.140 + break; 1.141 + } 1.142 + // Elements less than i have a end time before aTime. It's also possible 1.143 + // that the element at i has a end time before aTime, but that's OK. 1.144 + for (; i < GetSize(); ++i) { 1.145 + aResult->AppendElement(static_cast<T*>(ObjectAt(i))); 1.146 + } 1.147 + } 1.148 + 1.149 + uint32_t FrameCount() { 1.150 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.151 + uint32_t frames = 0; 1.152 + for (int32_t i = 0; i < GetSize(); ++i) { 1.153 + T* v = static_cast<T*>(ObjectAt(i)); 1.154 + frames += v->mFrames; 1.155 + } 1.156 + return frames; 1.157 + } 1.158 + 1.159 + void ClearListeners() { 1.160 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.161 + mPopListeners.Clear(); 1.162 + } 1.163 + 1.164 + void AddPopListener(nsIRunnable* aRunnable, MediaTaskQueue* aTaskQueue) { 1.165 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.166 + mPopListeners.AppendElement(Listener(aRunnable, aTaskQueue)); 1.167 + } 1.168 + 1.169 +private: 1.170 + mutable ReentrantMonitor mReentrantMonitor; 1.171 + 1.172 + struct Listener { 1.173 + Listener(nsIRunnable* aRunnable, MediaTaskQueue* aTaskQueue) 1.174 + : mRunnable(aRunnable) 1.175 + , mTarget(aTaskQueue) 1.176 + { 1.177 + } 1.178 + Listener(const Listener& aOther) 1.179 + : mRunnable(aOther.mRunnable) 1.180 + , mTarget(aOther.mTarget) 1.181 + { 1.182 + } 1.183 + RefPtr<nsIRunnable> mRunnable; 1.184 + RefPtr<MediaTaskQueue> mTarget; 1.185 + }; 1.186 + 1.187 + nsTArray<Listener> mPopListeners; 1.188 + 1.189 + void NotifyPopListeners() { 1.190 + for (uint32_t i = 0; i < mPopListeners.Length(); i++) { 1.191 + Listener& l = mPopListeners[i]; 1.192 + l.mTarget->Dispatch(l.mRunnable); 1.193 + } 1.194 + } 1.195 + 1.196 + // True when we've decoded the last frame of data in the 1.197 + // bitstream for which we're queueing frame data. 1.198 + bool mEndOfStream; 1.199 +}; 1.200 + 1.201 +} // namespace mozilla 1.202 + 1.203 +#endif