Bug 1572460 - Refactor `selection` out of the `InspectorFront`. r=yulia
[gecko.git] / dom / media / StreamTracks.h
blobec310ac70bfc517feb800baf1e777b51aa764767
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef MOZILLA_STREAMTRACKS_H_
7 #define MOZILLA_STREAMTRACKS_H_
9 #include "MediaSegment.h"
10 #include "nsAutoPtr.h"
11 #include "TrackID.h"
13 namespace mozilla {
15 inline TrackTicks RateConvertTicksRoundDown(TrackRate aOutRate,
16 TrackRate aInRate,
17 TrackTicks aTicks) {
18 MOZ_ASSERT(0 < aOutRate && aOutRate <= TRACK_RATE_MAX, "Bad out rate");
19 MOZ_ASSERT(0 < aInRate && aInRate <= TRACK_RATE_MAX, "Bad in rate");
20 MOZ_ASSERT(0 <= aTicks && aTicks <= TRACK_TICKS_MAX, "Bad ticks");
21 return (aTicks * aOutRate) / aInRate;
23 inline TrackTicks RateConvertTicksRoundUp(TrackRate aOutRate, TrackRate aInRate,
24 TrackTicks aTicks) {
25 MOZ_ASSERT(0 < aOutRate && aOutRate <= TRACK_RATE_MAX, "Bad out rate");
26 MOZ_ASSERT(0 < aInRate && aInRate <= TRACK_RATE_MAX, "Bad in rate");
27 MOZ_ASSERT(0 <= aTicks && aTicks <= TRACK_TICKS_MAX, "Bad ticks");
28 return (aTicks * aOutRate + aInRate - 1) / aInRate;
31 /**
32 * This object contains the decoded data for a stream's tracks.
33 * A StreamTracks can be appended to. Logically a StreamTracks only gets longer,
34 * but we also have the ability to "forget" data before a certain time that
35 * we know won't be used again. (We prune a whole number of seconds internally.)
37 * StreamTrackss should only be used from one thread at a time.
39 * A StreamTracks has a set of tracks that can be of arbitrary types ---
40 * the data for each track is a MediaSegment. The set of tracks can vary
41 * over the timeline of the StreamTracks.
43 class StreamTracks {
44 public:
45 /**
46 * Every track has a start time --- when it started in the StreamTracks.
47 * It has an end flag; when false, no end point is known; when true,
48 * the track ends when the data we have for the track runs out.
49 * Tracks have a unique ID assigned at creation. This allows us to identify
50 * the same track across StreamTrackss. A StreamTracks should never have
51 * two tracks with the same ID (even if they don't overlap in time).
52 * TODO Tracks can also be enabled and disabled over time.
53 * Takes ownership of aSegment.
55 class Track final {
56 Track(TrackID aID, StreamTime aStart, MediaSegment* aSegment)
57 : mStart(aStart),
58 mSegment(aSegment),
59 mID(aID),
60 mEnded(false),
61 mNotifiedEnded(false) {
62 MOZ_COUNT_CTOR(Track);
64 NS_ASSERTION(aID > TRACK_NONE, "Bad track ID");
65 NS_ASSERTION(0 <= aStart && aStart <= aSegment->GetDuration(),
66 "Bad start position");
69 public:
70 ~Track() { MOZ_COUNT_DTOR(Track); }
72 template <class T>
73 T* Get() const {
74 if (mSegment->GetType() == T::StaticType()) {
75 return static_cast<T*>(mSegment.get());
77 return nullptr;
80 MediaSegment* GetSegment() const { return mSegment; }
81 TrackID GetID() const { return mID; }
82 bool IsEnded() const { return mEnded; }
83 StreamTime GetStart() const { return mStart; }
84 StreamTime GetEnd() const { return mSegment->GetDuration(); }
85 MediaSegment::Type GetType() const { return mSegment->GetType(); }
86 bool NotifiedEnded() const { return mNotifiedEnded; }
88 void SetEnded() { mEnded = true; }
89 void NotifyEnded() {
90 MOZ_ASSERT(mEnded);
91 mNotifiedEnded = true;
93 void AppendFrom(Track* aTrack) {
94 NS_ASSERTION(!mEnded, "Can't append to ended track");
95 NS_ASSERTION(aTrack->mID == mID, "IDs must match");
96 NS_ASSERTION(aTrack->mStart == 0, "Source track must start at zero");
97 NS_ASSERTION(aTrack->mSegment->GetType() == GetType(),
98 "Track types must match");
100 mSegment->AppendFrom(aTrack->mSegment);
101 mEnded = aTrack->mEnded;
103 MediaSegment* RemoveSegment() { return mSegment.forget(); }
104 void ForgetUpTo(StreamTime aTime) { mSegment->ForgetUpTo(aTime); }
105 void FlushAfter(StreamTime aNewEnd) {
106 // Forget everything after a given endpoint
107 // a specified amount
108 mSegment->FlushAfter(aNewEnd);
111 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
112 size_t amount = aMallocSizeOf(this);
113 if (mSegment) {
114 amount += mSegment->SizeOfIncludingThis(aMallocSizeOf);
116 return amount;
119 private:
120 friend class StreamTracks;
122 // Start offset is in ticks at rate mRate
123 StreamTime mStart;
124 // The segment data starts at the start of the owning StreamTracks, i.e.,
125 // there's mStart silence/no video at the beginning.
126 nsAutoPtr<MediaSegment> mSegment;
127 // Unique ID
128 TrackID mID;
129 // True when the track ends with the data in mSegment
130 bool mEnded;
131 // True after NotifiedEnded() has been called.
132 bool mNotifiedEnded;
135 class MOZ_STACK_CLASS CompareTracksByID final {
136 public:
137 bool Equals(Track* aA, Track* aB) const {
138 return aA->GetID() == aB->GetID();
140 bool LessThan(Track* aA, Track* aB) const {
141 return aA->GetID() < aB->GetID();
145 StreamTracks()
146 : mGraphRate(0),
147 mForgottenTime(0),
148 mTracksDirty(false)
149 #ifdef DEBUG
151 mGraphRateIsSet(false)
152 #endif
154 MOZ_COUNT_CTOR(StreamTracks);
156 ~StreamTracks() { MOZ_COUNT_DTOR(StreamTracks); }
158 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
159 size_t amount = 0;
160 amount += mTracks.ShallowSizeOfExcludingThis(aMallocSizeOf);
161 for (size_t i = 0; i < mTracks.Length(); i++) {
162 amount += mTracks[i]->SizeOfIncludingThis(aMallocSizeOf);
164 return amount;
168 * Initialize the graph rate for use in calculating StreamTimes from track
169 * ticks. Called when a MediaStream's graph pointer is initialized.
171 void InitGraphRate(TrackRate aGraphRate) {
172 mGraphRate = aGraphRate;
173 #if DEBUG
174 MOZ_ASSERT(!mGraphRateIsSet);
175 mGraphRateIsSet = true;
176 #endif
179 TrackRate GraphRate() const {
180 MOZ_ASSERT(mGraphRateIsSet);
181 return mGraphRate;
185 * Takes ownership of aSegment. Don't do this while iterating, or while
186 * holding a Track reference.
187 * aSegment must have aStart worth of null data.
189 Track& AddTrack(TrackID aID, StreamTime aStart, MediaSegment* aSegment) {
190 NS_ASSERTION(!FindTrack(aID), "Track with this ID already exists");
192 Track* track = new Track(aID, aStart, aSegment);
193 mTracks.InsertElementSorted(track, CompareTracksByID());
194 mTracksDirty = true;
196 return *track;
200 * The end time for the StreamTracks is the latest time for which we have
201 * data for all tracks that haven't ended by that time.
203 StreamTime GetEarliestTrackEnd() const;
206 * Returns the earliest time >= 0 at which all tracks have ended and all
207 * their data has been played out, or STREAM_TIME_MAX if there is no such
208 * time.
210 StreamTime GetLatestTrackEnd() const;
212 #ifdef DEBUG
213 void DumpTrackInfo() const;
214 #endif
216 Track* FindTrack(TrackID aID) const;
218 class MOZ_STACK_CLASS TrackIter final {
219 public:
221 * Iterate through the tracks of aBuffer in order of ID.
223 explicit TrackIter(const StreamTracks& aBuffer)
224 : mBuffer(&aBuffer.mTracks),
225 mIndex(0),
226 mType(static_cast<MediaSegment::Type>(0)),
227 mMatchType(false) {}
229 * Iterate through the tracks of aBuffer with type aType, in order of ID.
231 TrackIter(const StreamTracks& aBuffer, MediaSegment::Type aType)
232 : mBuffer(&aBuffer.mTracks), mIndex(0), mType(aType), mMatchType(true) {
233 FindMatch();
235 bool IsEnded() const { return mIndex >= mBuffer->Length(); }
236 void Next() {
237 ++mIndex;
238 FindMatch();
240 Track* get() const { return mBuffer->ElementAt(mIndex); }
241 Track& operator*() { return *mBuffer->ElementAt(mIndex); }
242 Track* operator->() { return mBuffer->ElementAt(mIndex); }
244 private:
245 void FindMatch() {
246 if (!mMatchType) return;
247 while (mIndex < mBuffer->Length() &&
248 mBuffer->ElementAt(mIndex)->GetType() != mType) {
249 ++mIndex;
253 const nsTArray<nsAutoPtr<Track>>* mBuffer;
254 uint32_t mIndex;
255 MediaSegment::Type mType;
256 bool mMatchType;
258 friend class TrackIter;
261 * Forget stream data before aTime; they will no longer be needed.
262 * Also can forget entire tracks that have ended at or before aTime.
263 * Can't be used to forget beyond GetEnd().
265 void ForgetUpTo(StreamTime aTime);
267 * Clears out all Tracks and the data they are holding.
268 * MediaStreamGraph calls this during forced shutdown.
270 void Clear();
272 * Returns the latest time passed to ForgetUpTo.
274 StreamTime GetForgottenDuration() const { return mForgottenTime; }
276 bool GetAndResetTracksDirty() {
277 if (!mTracksDirty) {
278 return false;
281 mTracksDirty = false;
282 return true;
285 protected:
286 TrackRate mGraphRate; // StreamTime per second
287 StreamTime mForgottenTime;
289 private:
290 // All known tracks for this StreamTracks
291 nsTArray<nsAutoPtr<Track>> mTracks;
292 bool mTracksDirty;
294 #ifdef DEBUG
295 bool mGraphRateIsSet;
296 #endif
299 } // namespace mozilla
301 #endif /* MOZILLA_STREAMTRACKS_H_ */