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/. */
10 #include "MediaDataDemuxer.h"
11 #include "MediaResource.h"
12 #include "NesteggPacketHolder.h"
18 typedef struct nestegg nestegg
;
22 class WebMBufferedState
;
24 // Queue for holding MediaRawData samples
25 class MediaRawDataQueue
{
26 typedef std::deque
<RefPtr
<MediaRawData
>> ContainerType
;
29 uint32_t GetSize() { return mQueue
.size(); }
31 void Push(MediaRawData
* aItem
) { mQueue
.push_back(aItem
); }
33 void Push(already_AddRefed
<MediaRawData
>&& aItem
) {
34 mQueue
.push_back(std::move(aItem
));
37 void PushFront(MediaRawData
* aItem
) { mQueue
.push_front(aItem
); }
39 void PushFront(already_AddRefed
<MediaRawData
>&& aItem
) {
40 mQueue
.push_front(std::move(aItem
));
43 void PushFront(MediaRawDataQueue
&& aOther
) {
44 while (!aOther
.mQueue
.empty()) {
45 PushFront(aOther
.Pop());
49 already_AddRefed
<MediaRawData
> PopFront() {
50 RefPtr
<MediaRawData
> result
= std::move(mQueue
.front());
52 return result
.forget();
55 already_AddRefed
<MediaRawData
> Pop() {
56 RefPtr
<MediaRawData
> result
= std::move(mQueue
.back());
58 return result
.forget();
62 while (!mQueue
.empty()) {
67 MediaRawDataQueue
& operator=(const MediaRawDataQueue
& aOther
) = delete;
69 const RefPtr
<MediaRawData
>& First() const { return mQueue
.front(); }
71 const RefPtr
<MediaRawData
>& Last() const { return mQueue
.back(); }
73 // Methods for range-based for loops.
74 ContainerType::iterator
begin() { return mQueue
.begin(); }
76 ContainerType::const_iterator
begin() const { return mQueue
.begin(); }
78 ContainerType::iterator
end() { return mQueue
.end(); }
80 ContainerType::const_iterator
end() const { return mQueue
.end(); }
86 class WebMTrackDemuxer
;
88 DDLoggedTypeDeclNameAndBase(WebMDemuxer
, MediaDataDemuxer
);
89 DDLoggedTypeNameAndBase(WebMTrackDemuxer
, MediaTrackDemuxer
);
91 class WebMDemuxer
: public MediaDataDemuxer
,
92 public DecoderDoctorLifeLogger
<WebMDemuxer
> {
94 explicit WebMDemuxer(MediaResource
* aResource
);
95 // Indicate if the WebMDemuxer is to be used with MediaSource. In which
96 // case the demuxer will stop reads to the last known complete block.
98 MediaResource
* aResource
, bool aIsMediaSource
,
99 Maybe
<media::TimeUnit
> aFrameEndTimeBeforeRecreateDemuxer
= Nothing());
101 RefPtr
<InitPromise
> Init() override
;
103 uint32_t GetNumberTracks(TrackInfo::TrackType aType
) const override
;
105 UniquePtr
<TrackInfo
> GetTrackInfo(TrackInfo::TrackType aType
,
106 size_t aTrackNumber
) const;
108 already_AddRefed
<MediaTrackDemuxer
> GetTrackDemuxer(
109 TrackInfo::TrackType aType
, uint32_t aTrackNumber
) override
;
111 bool IsSeekable() const override
;
113 bool IsSeekableOnlyInBufferedRanges() const override
;
115 UniquePtr
<EncryptionInfo
> GetCrypto() override
;
117 bool GetOffsetForTime(uint64_t aTime
, int64_t* aOffset
);
119 // Demux next WebM packet and append samples to MediaRawDataQueue
120 nsresult
GetNextPacket(TrackInfo::TrackType aType
,
121 MediaRawDataQueue
* aSamples
);
123 void Reset(TrackInfo::TrackType aType
);
125 // Pushes a packet to the front of the audio packet queue.
126 void PushAudioPacket(NesteggPacketHolder
* aItem
);
128 // Pushes a packet to the front of the video packet queue.
129 void PushVideoPacket(NesteggPacketHolder
* aItem
);
131 // Public accessor for nestegg callbacks
132 bool IsMediaSource() const { return mIsMediaSource
; }
134 int64_t LastWebMBlockOffset() const { return mLastWebMBlockOffset
; }
136 struct NestEggContext
{
137 NestEggContext(WebMDemuxer
* aParent
, MediaResource
* aResource
)
138 : mParent(aParent
), mResource(aResource
), mContext(nullptr) {}
144 // Public accessor for nestegg callbacks
146 bool IsMediaSource() const { return mParent
->IsMediaSource(); }
147 MediaResourceIndex
* GetResource() { return &mResource
; }
149 int64_t GetEndDataOffset() const {
150 return (!mParent
->IsMediaSource() || mParent
->LastWebMBlockOffset() < 0)
151 ? mResource
.GetLength()
152 : mParent
->LastWebMBlockOffset();
155 WebMDemuxer
* mParent
;
156 MediaResourceIndex mResource
;
161 friend class WebMTrackDemuxer
;
164 void InitBufferedState();
165 int64_t FloorDefaultDurationToTimecodeScale(nestegg
* aContext
,
166 unsigned aTrackNumber
);
167 nsresult
ReadMetadata();
168 void NotifyDataArrived() override
;
169 void NotifyDataRemoved() override
;
170 void EnsureUpToDateIndex();
172 // A helper to catch bad intervals during `GetBuffered`.
173 // Verifies if the interval given by start and end is valid, returning true if
174 // it is, or false if not. Logs failure reason if the interval is invalid.
175 bool IsBufferedIntervalValid(uint64_t start
, uint64_t end
);
177 media::TimeIntervals
GetBuffered();
178 nsresult
SeekInternal(TrackInfo::TrackType aType
,
179 const media::TimeUnit
& aTarget
);
180 CryptoTrack
GetTrackCrypto(TrackInfo::TrackType aType
, size_t aTrackNumber
);
182 // Read a packet from the nestegg file. Returns nullptr if all packets for
183 // the particular track have been read. Pass TrackInfo::kVideoTrack or
184 // TrackInfo::kVideoTrack to indicate the type of the packet we want to read.
185 nsresult
NextPacket(TrackInfo::TrackType aType
,
186 RefPtr
<NesteggPacketHolder
>& aPacket
);
188 // Internal method that demuxes the next packet from the stream. The caller
189 // is responsible for making sure it doesn't get lost.
190 nsresult
DemuxPacket(TrackInfo::TrackType aType
,
191 RefPtr
<NesteggPacketHolder
>& aPacket
);
193 // libnestegg audio and video context for webm container.
194 // Access on reader's thread only.
195 NestEggContext mVideoContext
;
196 NestEggContext mAudioContext
;
197 MediaResourceIndex
& Resource(TrackInfo::TrackType aType
) {
198 return aType
== TrackInfo::kVideoTrack
? mVideoContext
.mResource
199 : mAudioContext
.mResource
;
201 nestegg
* Context(TrackInfo::TrackType aType
) const {
202 return aType
== TrackInfo::kVideoTrack
? mVideoContext
.mContext
203 : mAudioContext
.mContext
;
207 nsTArray
<RefPtr
<WebMTrackDemuxer
>> mDemuxers
;
209 // Parser state and computed offset-time mappings. Shared by multiple
210 // readers when decoder has been cloned. Main thread only.
211 RefPtr
<WebMBufferedState
> mBufferedState
;
212 RefPtr
<MediaByteBuffer
> mInitData
;
214 // Queue of video and audio packets that have been read but not decoded.
215 WebMPacketQueue mVideoPackets
;
216 WebMPacketQueue mAudioPackets
;
218 // Index of video and audio track to play
219 uint32_t mVideoTrack
;
220 uint32_t mAudioTrack
;
222 // Nanoseconds to discard after seeking.
223 uint64_t mSeekPreroll
;
225 // Calculate the frame duration from the last decodeable frame using the
226 // previous frame's timestamp. In microseconds.
227 Maybe
<int64_t> mLastAudioFrameTime
;
228 Maybe
<int64_t> mLastVideoFrameTime
;
230 Maybe
<media::TimeUnit
> mVideoFrameEndTimeBeforeReset
;
232 // Codec ID of audio track
234 // Codec ID of video track
236 // Default durations of blocks for each track, in microseconds
237 int64_t mAudioDefaultDuration
;
238 int64_t mVideoDefaultDuration
;
240 // Booleans to indicate if we have audio and/or video data
245 // The last complete block parsed by the WebMBufferedState. -1 if not set.
246 // We cache those values rather than retrieving them for performance reasons
247 // as nestegg only performs 1-byte read at a time.
248 int64_t mLastWebMBlockOffset
;
249 const bool mIsMediaSource
;
250 // Discard padding in WebM cannot occur more than once. This is set to true if
251 // a discard padding element has been found and processed, and the decoding is
252 // expected to error out if another discard padding element is found
253 // subsequently in the byte stream.
254 bool mProcessedDiscardPadding
= false;
256 EncryptionInfo mCrypto
;
259 class WebMTrackDemuxer
: public MediaTrackDemuxer
,
260 public DecoderDoctorLifeLogger
<WebMTrackDemuxer
> {
262 WebMTrackDemuxer(WebMDemuxer
* aParent
, TrackInfo::TrackType aType
,
263 uint32_t aTrackNumber
);
265 UniquePtr
<TrackInfo
> GetInfo() const override
;
267 RefPtr
<SeekPromise
> Seek(const media::TimeUnit
& aTime
) override
;
269 RefPtr
<SamplesPromise
> GetSamples(int32_t aNumSamples
= 1) override
;
271 void Reset() override
;
273 nsresult
GetNextRandomAccessPoint(media::TimeUnit
* aTime
) override
;
275 RefPtr
<SkipAccessPointPromise
> SkipToNextRandomAccessPoint(
276 const media::TimeUnit
& aTimeThreshold
) override
;
278 media::TimeIntervals
GetBuffered() override
;
280 int64_t GetEvictionOffset(const media::TimeUnit
& aTime
) override
;
282 void BreakCycles() override
;
285 friend class WebMDemuxer
;
287 void UpdateSamples(const nsTArray
<RefPtr
<MediaRawData
>>& aSamples
);
288 void SetNextKeyFrameTime();
289 nsresult
NextSample(RefPtr
<MediaRawData
>& aData
);
290 RefPtr
<WebMDemuxer
> mParent
;
291 TrackInfo::TrackType mType
;
292 UniquePtr
<TrackInfo
> mInfo
;
293 Maybe
<media::TimeUnit
> mNextKeyframeTime
;
296 // Queued samples extracted by the demuxer, but not yet returned.
297 MediaRawDataQueue mSamples
;
300 } // namespace mozilla