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"
15 inline TrackTicks
RateConvertTicksRoundDown(TrackRate aOutRate
,
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
,
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
;
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.
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.
56 Track(TrackID aID
, StreamTime aStart
, MediaSegment
* aSegment
)
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");
70 ~Track() { MOZ_COUNT_DTOR(Track
); }
74 if (mSegment
->GetType() == T::StaticType()) {
75 return static_cast<T
*>(mSegment
.get());
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; }
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);
114 amount
+= mSegment
->SizeOfIncludingThis(aMallocSizeOf
);
120 friend class StreamTracks
;
122 // Start offset is in ticks at rate mRate
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
;
129 // True when the track ends with the data in mSegment
131 // True after NotifiedEnded() has been called.
135 class MOZ_STACK_CLASS CompareTracksByID final
{
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();
151 mGraphRateIsSet(false)
154 MOZ_COUNT_CTOR(StreamTracks
);
156 ~StreamTracks() { MOZ_COUNT_DTOR(StreamTracks
); }
158 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf
) const {
160 amount
+= mTracks
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
161 for (size_t i
= 0; i
< mTracks
.Length(); i
++) {
162 amount
+= mTracks
[i
]->SizeOfIncludingThis(aMallocSizeOf
);
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
;
174 MOZ_ASSERT(!mGraphRateIsSet
);
175 mGraphRateIsSet
= true;
179 TrackRate
GraphRate() const {
180 MOZ_ASSERT(mGraphRateIsSet
);
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());
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
210 StreamTime
GetLatestTrackEnd() const;
213 void DumpTrackInfo() const;
216 Track
* FindTrack(TrackID aID
) const;
218 class MOZ_STACK_CLASS TrackIter final
{
221 * Iterate through the tracks of aBuffer in order of ID.
223 explicit TrackIter(const StreamTracks
& aBuffer
)
224 : mBuffer(&aBuffer
.mTracks
),
226 mType(static_cast<MediaSegment::Type
>(0)),
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) {
235 bool IsEnded() const { return mIndex
>= mBuffer
->Length(); }
240 Track
* get() const { return mBuffer
->ElementAt(mIndex
); }
241 Track
& operator*() { return *mBuffer
->ElementAt(mIndex
); }
242 Track
* operator->() { return mBuffer
->ElementAt(mIndex
); }
246 if (!mMatchType
) return;
247 while (mIndex
< mBuffer
->Length() &&
248 mBuffer
->ElementAt(mIndex
)->GetType() != mType
) {
253 const nsTArray
<nsAutoPtr
<Track
>>* mBuffer
;
255 MediaSegment::Type mType
;
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.
272 * Returns the latest time passed to ForgetUpTo.
274 StreamTime
GetForgottenDuration() const { return mForgottenTime
; }
276 bool GetAndResetTracksDirty() {
281 mTracksDirty
= false;
286 TrackRate mGraphRate
; // StreamTime per second
287 StreamTime mForgottenTime
;
290 // All known tracks for this StreamTracks
291 nsTArray
<nsAutoPtr
<Track
>> mTracks
;
295 bool mGraphRateIsSet
;
299 } // namespace mozilla
301 #endif /* MOZILLA_STREAMTRACKS_H_ */