Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
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 : #if !defined(MediaQueue_h_)
7 : #define MediaQueue_h_
8 :
9 : #include "mozilla/ReentrantMonitor.h"
10 : #include "mozilla/TaskQueue.h"
11 :
12 : #include "nsDeque.h"
13 : #include "MediaEventSource.h"
14 : #include "TimeUnits.h"
15 :
16 : namespace mozilla {
17 :
18 : // Thread and type safe wrapper around nsDeque.
19 : template <class T>
20 0 : class MediaQueueDeallocator : public nsDequeFunctor {
21 0 : virtual void* operator() (void* aObject) {
22 0 : RefPtr<T> releaseMe = dont_AddRef(static_cast<T*>(aObject));
23 0 : return nullptr;
24 : }
25 : };
26 :
27 : template <class T>
28 : class MediaQueue : private nsDeque {
29 : public:
30 0 : MediaQueue()
31 0 : : nsDeque(new MediaQueueDeallocator<T>()),
32 : mReentrantMonitor("mediaqueue"),
33 0 : mEndOfStream(false)
34 0 : {}
35 :
36 0 : ~MediaQueue() {
37 0 : Reset();
38 0 : }
39 :
40 0 : inline size_t GetSize() const {
41 0 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
42 0 : return nsDeque::GetSize();
43 : }
44 :
45 0 : inline void Push(T* aItem) {
46 0 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
47 0 : MOZ_ASSERT(!mEndOfStream);
48 0 : MOZ_ASSERT(aItem);
49 0 : NS_ADDREF(aItem);
50 0 : MOZ_ASSERT(aItem->GetEndTime() >= aItem->mTime);
51 0 : nsDeque::Push(aItem);
52 0 : mPushEvent.Notify(RefPtr<T>(aItem));
53 0 : }
54 :
55 0 : inline already_AddRefed<T> PopFront() {
56 0 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
57 0 : RefPtr<T> rv = dont_AddRef(static_cast<T*>(nsDeque::PopFront()));
58 0 : if (rv) {
59 0 : mPopEvent.Notify(rv);
60 : }
61 0 : return rv.forget();
62 : }
63 :
64 0 : inline RefPtr<T> PeekFront() const {
65 0 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
66 0 : return static_cast<T*>(nsDeque::PeekFront());
67 : }
68 :
69 0 : void Reset() {
70 0 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
71 0 : while (GetSize() > 0) {
72 0 : RefPtr<T> x = dont_AddRef(static_cast<T*>(nsDeque::PopFront()));
73 : }
74 0 : mEndOfStream = false;
75 0 : }
76 :
77 0 : bool AtEndOfStream() const {
78 0 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
79 0 : return GetSize() == 0 && mEndOfStream;
80 : }
81 :
82 : // Returns true if the media queue has had its last item added to it.
83 : // This happens when the media stream has been completely decoded. Note this
84 : // does not mean that the corresponding stream has finished playback.
85 0 : bool IsFinished() const {
86 0 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
87 0 : return mEndOfStream;
88 : }
89 :
90 : // Informs the media queue that it won't be receiving any more items.
91 0 : void Finish() {
92 0 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
93 0 : if (!mEndOfStream) {
94 0 : mEndOfStream = true;
95 0 : mFinishEvent.Notify();
96 : }
97 0 : }
98 :
99 : // Returns the approximate number of microseconds of items in the queue.
100 0 : int64_t Duration() {
101 0 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
102 0 : if (GetSize() == 0) {
103 0 : return 0;
104 : }
105 0 : T* last = static_cast<T*>(nsDeque::Peek());
106 0 : T* first = static_cast<T*>(nsDeque::PeekFront());
107 0 : return (last->GetEndTime() - first->mTime).ToMicroseconds();
108 : }
109 :
110 0 : void LockedForEach(nsDequeFunctor& aFunctor) const {
111 0 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
112 0 : ForEach(aFunctor);
113 0 : }
114 :
115 : // Extracts elements from the queue into aResult, in order.
116 : // Elements whose start time is before aTime are ignored.
117 0 : void GetElementsAfter(int64_t aTime, nsTArray<RefPtr<T>>* aResult) {
118 0 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
119 0 : if (GetSize() == 0)
120 0 : return;
121 : size_t i;
122 0 : for (i = GetSize() - 1; i > 0; --i) {
123 0 : T* v = static_cast<T*>(ObjectAt(i));
124 0 : if (v->GetEndTime().ToMicroseconds() < aTime)
125 0 : break;
126 : }
127 : // Elements less than i have a end time before aTime. It's also possible
128 : // that the element at i has a end time before aTime, but that's OK.
129 0 : for (; i < GetSize(); ++i) {
130 0 : RefPtr<T> elem = static_cast<T*>(ObjectAt(static_cast<size_t>(i)));
131 0 : aResult->AppendElement(elem);
132 : }
133 : }
134 :
135 0 : void GetElementsAfter(const media::TimeUnit& aTime,
136 : nsTArray<RefPtr<T>>* aResult) {
137 0 : GetElementsAfter(aTime.ToMicroseconds(), aResult);
138 0 : }
139 :
140 0 : void GetFirstElements(uint32_t aMaxElements, nsTArray<RefPtr<T>>* aResult) {
141 0 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
142 0 : for (size_t i = 0; i < aMaxElements && i < GetSize(); ++i) {
143 0 : *aResult->AppendElement() = static_cast<T*>(ObjectAt(i));
144 : }
145 0 : }
146 :
147 0 : uint32_t FrameCount() {
148 0 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
149 0 : uint32_t frames = 0;
150 0 : for (size_t i = 0; i < GetSize(); ++i) {
151 0 : T* v = static_cast<T*>(ObjectAt(i));
152 0 : frames += v->mFrames;
153 : }
154 0 : return frames;
155 : }
156 :
157 0 : MediaEventSource<RefPtr<T>>& PopEvent() {
158 0 : return mPopEvent;
159 : }
160 :
161 0 : MediaEventSource<RefPtr<T>>& PushEvent() {
162 0 : return mPushEvent;
163 : }
164 :
165 0 : MediaEventSource<void>& FinishEvent() {
166 0 : return mFinishEvent;
167 : }
168 :
169 : private:
170 : mutable ReentrantMonitor mReentrantMonitor;
171 : MediaEventProducer<RefPtr<T>> mPopEvent;
172 : MediaEventProducer<RefPtr<T>> mPushEvent;
173 : MediaEventProducer<void> mFinishEvent;
174 : // True when we've decoded the last frame of data in the
175 : // bitstream for which we're queueing frame data.
176 : bool mEndOfStream;
177 : };
178 :
179 : } // namespace mozilla
180 :
181 : #endif
|