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