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(WebMDemuxer_h_)
7 : #define WebMDemuxer_h_
8 :
9 : #include "nsTArray.h"
10 : #include "MediaDataDemuxer.h"
11 : #include "MediaResource.h"
12 : #include "NesteggPacketHolder.h"
13 : #include "mozilla/Move.h"
14 :
15 : #include <deque>
16 : #include <stdint.h>
17 :
18 : typedef struct nestegg nestegg;
19 :
20 : namespace mozilla {
21 :
22 : class WebMBufferedState;
23 :
24 : // Queue for holding MediaRawData samples
25 0 : class MediaRawDataQueue
26 : {
27 : public:
28 0 : uint32_t GetSize()
29 : {
30 0 : return mQueue.size();
31 : }
32 :
33 0 : void Push(MediaRawData* aItem)
34 : {
35 0 : mQueue.push_back(aItem);
36 0 : }
37 :
38 0 : void Push(already_AddRefed<MediaRawData>&& aItem)
39 : {
40 0 : mQueue.push_back(Move(aItem));
41 0 : }
42 :
43 : void PushFront(MediaRawData* aItem) {
44 : mQueue.push_front(aItem);
45 : }
46 :
47 0 : void PushFront(already_AddRefed<MediaRawData>&& aItem)
48 : {
49 0 : mQueue.push_front(Move(aItem));
50 0 : }
51 :
52 0 : void PushFront(MediaRawDataQueue&& aOther)
53 : {
54 0 : while (!aOther.mQueue.empty()) {
55 0 : PushFront(aOther.Pop());
56 : }
57 0 : }
58 :
59 0 : already_AddRefed<MediaRawData> PopFront()
60 : {
61 0 : RefPtr<MediaRawData> result = mQueue.front().forget();
62 0 : mQueue.pop_front();
63 0 : return result.forget();
64 : }
65 :
66 0 : already_AddRefed<MediaRawData> Pop()
67 : {
68 0 : RefPtr<MediaRawData> result = mQueue.back().forget();
69 0 : mQueue.pop_back();
70 0 : return result.forget();
71 : }
72 :
73 0 : void Reset()
74 : {
75 0 : while (!mQueue.empty()) {
76 0 : mQueue.pop_front();
77 : }
78 0 : }
79 :
80 : MediaRawDataQueue& operator=(const MediaRawDataQueue& aOther)
81 : {
82 : mQueue = aOther.mQueue;
83 : return *this;
84 : }
85 :
86 0 : const RefPtr<MediaRawData>& First() const
87 : {
88 0 : return mQueue.front();
89 : }
90 :
91 0 : const RefPtr<MediaRawData>& Last() const
92 : {
93 0 : return mQueue.back();
94 : }
95 :
96 : private:
97 : std::deque<RefPtr<MediaRawData>> mQueue;
98 : };
99 :
100 : class WebMTrackDemuxer;
101 :
102 : class WebMDemuxer : public MediaDataDemuxer
103 : {
104 : public:
105 : explicit WebMDemuxer(MediaResource* aResource);
106 : // Indicate if the WebMDemuxer is to be used with MediaSource. In which
107 : // case the demuxer will stop reads to the last known complete block.
108 : WebMDemuxer(MediaResource* aResource, bool aIsMediaSource);
109 :
110 : RefPtr<InitPromise> Init() override;
111 :
112 : bool HasTrackType(TrackInfo::TrackType aType) const override;
113 :
114 : uint32_t GetNumberTracks(TrackInfo::TrackType aType) const override;
115 :
116 : UniquePtr<TrackInfo> GetTrackInfo(TrackInfo::TrackType aType,
117 : size_t aTrackNumber) const;
118 :
119 : already_AddRefed<MediaTrackDemuxer>
120 : GetTrackDemuxer(TrackInfo::TrackType aType, uint32_t aTrackNumber) override;
121 :
122 : bool IsSeekable() const override;
123 :
124 : bool IsSeekableOnlyInBufferedRanges() const override;
125 :
126 : UniquePtr<EncryptionInfo> GetCrypto() override;
127 :
128 : bool GetOffsetForTime(uint64_t aTime, int64_t* aOffset);
129 :
130 : // Demux next WebM packet and append samples to MediaRawDataQueue
131 : nsresult GetNextPacket(TrackInfo::TrackType aType,
132 : MediaRawDataQueue *aSamples);
133 :
134 : nsresult Reset(TrackInfo::TrackType aType);
135 :
136 : // Pushes a packet to the front of the audio packet queue.
137 : void PushAudioPacket(NesteggPacketHolder* aItem);
138 :
139 : // Pushes a packet to the front of the video packet queue.
140 : void PushVideoPacket(NesteggPacketHolder* aItem);
141 :
142 : // Public accessor for nestegg callbacks
143 0 : bool IsMediaSource() const
144 : {
145 0 : return mIsMediaSource;
146 : }
147 :
148 0 : int64_t LastWebMBlockOffset() const
149 : {
150 0 : return mLastWebMBlockOffset;
151 : }
152 :
153 : struct NestEggContext
154 : {
155 0 : NestEggContext(WebMDemuxer* aParent, MediaResource* aResource)
156 0 : : mParent(aParent)
157 : , mResource(aResource)
158 0 : , mContext(nullptr)
159 : {
160 0 : }
161 :
162 : ~NestEggContext();
163 :
164 : int Init();
165 :
166 : // Public accessor for nestegg callbacks
167 :
168 0 : bool IsMediaSource() const { return mParent->IsMediaSource(); }
169 0 : MediaResourceIndex* GetResource() { return &mResource; }
170 :
171 0 : int64_t GetEndDataOffset() const
172 : {
173 0 : return (!mParent->IsMediaSource() || mParent->LastWebMBlockOffset() < 0)
174 0 : ? mResource.GetLength()
175 0 : : mParent->LastWebMBlockOffset();
176 : }
177 :
178 : WebMDemuxer* mParent;
179 : MediaResourceIndex mResource;
180 : nestegg* mContext;
181 : };
182 :
183 : private:
184 : friend class WebMTrackDemuxer;
185 :
186 : ~WebMDemuxer();
187 : void InitBufferedState();
188 : nsresult ReadMetadata();
189 : void NotifyDataArrived() override;
190 : void NotifyDataRemoved() override;
191 : void EnsureUpToDateIndex();
192 : media::TimeIntervals GetBuffered();
193 : nsresult SeekInternal(TrackInfo::TrackType aType,
194 : const media::TimeUnit& aTarget);
195 : CryptoTrack GetTrackCrypto(TrackInfo::TrackType aType, size_t aTrackNumber);
196 :
197 : // Read a packet from the nestegg file. Returns nullptr if all packets for
198 : // the particular track have been read. Pass TrackInfo::kVideoTrack or
199 : // TrackInfo::kVideoTrack to indicate the type of the packet we want to read.
200 : nsresult NextPacket(TrackInfo::TrackType aType,
201 : RefPtr<NesteggPacketHolder>& aPacket);
202 :
203 : // Internal method that demuxes the next packet from the stream. The caller
204 : // is responsible for making sure it doesn't get lost.
205 : nsresult DemuxPacket(TrackInfo::TrackType aType,
206 : RefPtr<NesteggPacketHolder>& aPacket);
207 :
208 : // libnestegg audio and video context for webm container.
209 : // Access on reader's thread only.
210 : NestEggContext mVideoContext;
211 : NestEggContext mAudioContext;
212 0 : MediaResourceIndex& Resource(TrackInfo::TrackType aType)
213 : {
214 : return aType == TrackInfo::kVideoTrack
215 0 : ? mVideoContext.mResource : mAudioContext.mResource;
216 : }
217 0 : nestegg* Context(TrackInfo::TrackType aType) const
218 : {
219 : return aType == TrackInfo::kVideoTrack
220 0 : ? mVideoContext.mContext : mAudioContext.mContext;
221 : }
222 :
223 : MediaInfo mInfo;
224 : nsTArray<RefPtr<WebMTrackDemuxer>> mDemuxers;
225 :
226 : // Parser state and computed offset-time mappings. Shared by multiple
227 : // readers when decoder has been cloned. Main thread only.
228 : RefPtr<WebMBufferedState> mBufferedState;
229 : RefPtr<MediaByteBuffer> mInitData;
230 :
231 :
232 : // Queue of video and audio packets that have been read but not decoded.
233 : WebMPacketQueue mVideoPackets;
234 : WebMPacketQueue mAudioPackets;
235 :
236 : // Index of video and audio track to play
237 : uint32_t mVideoTrack;
238 : uint32_t mAudioTrack;
239 :
240 : // Nanoseconds to discard after seeking.
241 : uint64_t mSeekPreroll;
242 :
243 : // Calculate the frame duration from the last decodeable frame using the
244 : // previous frame's timestamp. In NS.
245 : Maybe<int64_t> mLastAudioFrameTime;
246 : Maybe<int64_t> mLastVideoFrameTime;
247 :
248 : // Codec ID of audio track
249 : int mAudioCodec;
250 : // Codec ID of video track
251 : int mVideoCodec;
252 :
253 : // Booleans to indicate if we have audio and/or video data
254 : bool mHasVideo;
255 : bool mHasAudio;
256 : bool mNeedReIndex;
257 :
258 : // The last complete block parsed by the WebMBufferedState. -1 if not set.
259 : // We cache those values rather than retrieving them for performance reasons
260 : // as nestegg only performs 1-byte read at a time.
261 : int64_t mLastWebMBlockOffset;
262 : const bool mIsMediaSource;
263 :
264 : Maybe<nsIntSize> mLastSeenFrameSize;
265 : // This will be populated only if a resolution change occurs, otherwise it
266 : // will be left as null so the original metadata is used
267 : RefPtr<TrackInfoSharedPtr> mSharedVideoTrackInfo;
268 :
269 : EncryptionInfo mCrypto;
270 : };
271 :
272 : class WebMTrackDemuxer : public MediaTrackDemuxer
273 : {
274 : public:
275 : WebMTrackDemuxer(WebMDemuxer* aParent,
276 : TrackInfo::TrackType aType,
277 : uint32_t aTrackNumber);
278 :
279 : UniquePtr<TrackInfo> GetInfo() const override;
280 :
281 : RefPtr<SeekPromise> Seek(const media::TimeUnit& aTime) override;
282 :
283 : RefPtr<SamplesPromise> GetSamples(int32_t aNumSamples = 1) override;
284 :
285 : void Reset() override;
286 :
287 : nsresult GetNextRandomAccessPoint(media::TimeUnit* aTime) override;
288 :
289 : RefPtr<SkipAccessPointPromise> SkipToNextRandomAccessPoint(
290 : const media::TimeUnit& aTimeThreshold) override;
291 :
292 : media::TimeIntervals GetBuffered() override;
293 :
294 : int64_t GetEvictionOffset(const media::TimeUnit& aTime) override;
295 :
296 : void BreakCycles() override;
297 :
298 : private:
299 : friend class WebMDemuxer;
300 : ~WebMTrackDemuxer();
301 : void UpdateSamples(nsTArray<RefPtr<MediaRawData>>& aSamples);
302 : void SetNextKeyFrameTime();
303 : nsresult NextSample(RefPtr<MediaRawData>& aData);
304 : RefPtr<WebMDemuxer> mParent;
305 : TrackInfo::TrackType mType;
306 : UniquePtr<TrackInfo> mInfo;
307 : Maybe<media::TimeUnit> mNextKeyframeTime;
308 : bool mNeedKeyframe;
309 :
310 : // Queued samples extracted by the demuxer, but not yet returned.
311 : MediaRawDataQueue mSamples;
312 : };
313 :
314 : } // namespace mozilla
315 :
316 : #endif
|