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(OggDemuxer_h_)
7 : #define OggDemuxer_h_
8 :
9 : #include "nsTArray.h"
10 : #include "MediaDataDemuxer.h"
11 : #include "OggCodecState.h"
12 : #include "OggCodecStore.h"
13 : #include "MediaMetadataManager.h"
14 :
15 : namespace mozilla {
16 :
17 : class OggTrackDemuxer;
18 :
19 : class OggDemuxer : public MediaDataDemuxer
20 : {
21 : public:
22 : explicit OggDemuxer(MediaResource* aResource);
23 :
24 : RefPtr<InitPromise> Init() override;
25 :
26 : bool HasTrackType(TrackInfo::TrackType aType) const override;
27 :
28 : uint32_t GetNumberTracks(TrackInfo::TrackType aType) const override;
29 :
30 : already_AddRefed<MediaTrackDemuxer> GetTrackDemuxer(TrackInfo::TrackType aType,
31 : uint32_t aTrackNumber) override;
32 :
33 : bool IsSeekable() const override;
34 :
35 : UniquePtr<EncryptionInfo> GetCrypto() override;
36 :
37 : // Set the events to notify when chaining is encountered.
38 : void SetChainingEvents(TimedMetadataEventProducer* aMetadataEvent,
39 : MediaEventProducer<void>* aOnSeekableEvent);
40 :
41 : private:
42 :
43 : // helpers for friend OggTrackDemuxer
44 : UniquePtr<TrackInfo> GetTrackInfo(TrackInfo::TrackType aType, size_t aTrackNumber) const;
45 :
46 : struct nsAutoOggSyncState {
47 0 : nsAutoOggSyncState() {
48 0 : ogg_sync_init(&mState);
49 0 : }
50 0 : ~nsAutoOggSyncState() {
51 0 : ogg_sync_clear(&mState);
52 0 : }
53 : ogg_sync_state mState;
54 : };
55 : media::TimeIntervals GetBuffered(TrackInfo::TrackType aType);
56 : void FindStartTime(int64_t& aOutStartTime);
57 : void FindStartTime(TrackInfo::TrackType, int64_t& aOutStartTime);
58 :
59 : nsresult SeekInternal(TrackInfo::TrackType aType, const media::TimeUnit& aTarget);
60 :
61 : // Seeks to the keyframe preceding the target time using available
62 : // keyframe indexes.
63 : enum IndexedSeekResult
64 : {
65 : SEEK_OK, // Success.
66 : SEEK_INDEX_FAIL, // Failure due to no index, or invalid index.
67 : SEEK_FATAL_ERROR // Error returned by a stream operation.
68 : };
69 : IndexedSeekResult SeekToKeyframeUsingIndex(TrackInfo::TrackType aType, int64_t aTarget);
70 :
71 : // Rolls back a seek-using-index attempt, returning a failure error code.
72 : IndexedSeekResult RollbackIndexedSeek(TrackInfo::TrackType aType, int64_t aOffset);
73 :
74 : // Represents a section of contiguous media, with a start and end offset,
75 : // and the timestamps of the start and end of that range, that is cached.
76 : // Used to denote the extremities of a range in which we can seek quickly
77 : // (because it's cached).
78 : class SeekRange
79 : {
80 : public:
81 0 : SeekRange()
82 0 : : mOffsetStart(0)
83 : , mOffsetEnd(0)
84 : , mTimeStart(0)
85 0 : , mTimeEnd(0)
86 0 : {}
87 :
88 0 : SeekRange(int64_t aOffsetStart,
89 : int64_t aOffsetEnd,
90 : int64_t aTimeStart,
91 : int64_t aTimeEnd)
92 0 : : mOffsetStart(aOffsetStart)
93 : , mOffsetEnd(aOffsetEnd)
94 : , mTimeStart(aTimeStart)
95 0 : , mTimeEnd(aTimeEnd)
96 0 : {}
97 :
98 0 : bool IsNull() const {
99 0 : return mOffsetStart == 0 &&
100 0 : mOffsetEnd == 0 &&
101 0 : mTimeStart == 0 &&
102 0 : mTimeEnd == 0;
103 : }
104 :
105 : int64_t mOffsetStart, mOffsetEnd; // in bytes.
106 : int64_t mTimeStart, mTimeEnd; // in usecs.
107 : };
108 :
109 : nsresult GetSeekRanges(TrackInfo::TrackType aType, nsTArray<SeekRange>& aRanges);
110 : SeekRange SelectSeekRange(TrackInfo::TrackType aType,
111 : const nsTArray<SeekRange>& ranges,
112 : int64_t aTarget,
113 : int64_t aStartTime,
114 : int64_t aEndTime,
115 : bool aExact);
116 :
117 : // Seeks to aTarget usecs in the buffered range aRange using bisection search,
118 : // or to the keyframe prior to aTarget if we have video. aAdjustedTarget is
119 : // an adjusted version of the target used to account for Opus pre-roll, if
120 : // necessary. aStartTime must be the presentation time at the start of media,
121 : // and aEndTime the time at end of media. aRanges must be the time/byte ranges
122 : // buffered in the media cache as per GetSeekRanges().
123 : nsresult SeekInBufferedRange(TrackInfo::TrackType aType,
124 : int64_t aTarget,
125 : int64_t aAdjustedTarget,
126 : int64_t aStartTime,
127 : int64_t aEndTime,
128 : const nsTArray<SeekRange>& aRanges,
129 : const SeekRange& aRange);
130 :
131 : // Seeks to before aTarget usecs in media using bisection search. If the media
132 : // has video, this will seek to before the keyframe required to render the
133 : // media at aTarget. Will use aRanges in order to narrow the bisection
134 : // search space. aStartTime must be the presentation time at the start of
135 : // media, and aEndTime the time at end of media. aRanges must be the time/byte
136 : // ranges buffered in the media cache as per GetSeekRanges().
137 : nsresult SeekInUnbuffered(TrackInfo::TrackType aType,
138 : int64_t aTarget,
139 : int64_t aStartTime,
140 : int64_t aEndTime,
141 : const nsTArray<SeekRange>& aRanges);
142 :
143 : // Performs a seek bisection to move the media stream's read cursor to the
144 : // last ogg page boundary which has end time before aTarget usecs on both the
145 : // Theora and Vorbis bitstreams. Limits its search to data inside aRange;
146 : // i.e. it will only read inside of the aRange's start and end offsets.
147 : // aFuzz is the number of usecs of leniency we'll allow; we'll terminate the
148 : // seek when we land in the range (aTime - aFuzz, aTime) usecs.
149 : nsresult SeekBisection(TrackInfo::TrackType aType,
150 : int64_t aTarget,
151 : const SeekRange& aRange,
152 : uint32_t aFuzz);
153 :
154 : // Chunk size to read when reading Ogg files. Average Ogg page length
155 : // is about 4300 bytes, so we read the file in chunks larger than that.
156 : static const int PAGE_STEP = 8192;
157 :
158 : enum PageSyncResult
159 : {
160 : PAGE_SYNC_ERROR = 1,
161 : PAGE_SYNC_END_OF_RANGE= 2,
162 : PAGE_SYNC_OK = 3
163 : };
164 : static PageSyncResult PageSync(MediaResourceIndex* aResource,
165 : ogg_sync_state* aState,
166 : bool aCachedDataOnly,
167 : int64_t aOffset,
168 : int64_t aEndOffset,
169 : ogg_page* aPage,
170 : int& aSkippedBytes);
171 :
172 : // Demux next Ogg packet
173 : ogg_packet* GetNextPacket(TrackInfo::TrackType aType);
174 :
175 : nsresult Reset(TrackInfo::TrackType aType);
176 :
177 : static const nsString GetKind(const nsCString& aRole);
178 : static void InitTrack(MessageField* aMsgInfo,
179 : TrackInfo* aInfo,
180 : bool aEnable);
181 :
182 : // Really private!
183 : ~OggDemuxer();
184 :
185 : // Read enough of the file to identify track information and header
186 : // packets necessary for decoding to begin.
187 : nsresult ReadMetadata();
188 :
189 : // Read a page of data from the Ogg file. Returns true if a page has been
190 : // read, false if the page read failed or end of file reached.
191 : bool ReadOggPage(TrackInfo::TrackType aType, ogg_page* aPage);
192 :
193 : // Send a page off to the individual streams it belongs to.
194 : // Reconstructed packets, if any are ready, will be available
195 : // on the individual OggCodecStates.
196 : nsresult DemuxOggPage(TrackInfo::TrackType aType, ogg_page* aPage);
197 :
198 : // Read data and demux until a packet is available on the given stream state
199 : void DemuxUntilPacketAvailable(TrackInfo::TrackType aType, OggCodecState* aState);
200 :
201 : // Reads and decodes header packets for aState, until either header decode
202 : // fails, or is complete. Initializes the codec state before returning.
203 : // Returns true if reading headers and initializtion of the stream
204 : // succeeds.
205 : bool ReadHeaders(TrackInfo::TrackType aType, OggCodecState* aState);
206 :
207 : // Reads the next link in the chain.
208 : bool ReadOggChain(const media::TimeUnit& aLastEndTime);
209 :
210 : // Set this media as being a chain and notifies the state machine that the
211 : // media is no longer seekable.
212 : void SetChained();
213 :
214 : // Fills aTracks with the serial numbers of each active stream, for use by
215 : // various SkeletonState functions.
216 : void BuildSerialList(nsTArray<uint32_t>& aTracks);
217 :
218 : // Setup target bitstreams for decoding.
219 : void SetupTarget(OggCodecState** aSavedState, OggCodecState* aNewState);
220 : void SetupTargetSkeleton();
221 : void SetupMediaTracksInfo(const nsTArray<uint32_t>& aSerials);
222 : void FillTags(TrackInfo* aInfo, MetadataTags* aTags);
223 :
224 : // Compute an ogg page's checksum
225 : ogg_uint32_t GetPageChecksum(ogg_page* aPage);
226 :
227 : // Get the end time of aEndOffset. This is the playback position we'd reach
228 : // after playback finished at aEndOffset.
229 : int64_t RangeEndTime(TrackInfo::TrackType aType, int64_t aEndOffset);
230 :
231 : // Get the end time of aEndOffset, without reading before aStartOffset.
232 : // This is the playback position we'd reach after playback finished at
233 : // aEndOffset. If bool aCachedDataOnly is true, then we'll only read
234 : // from data which is cached in the media cached, otherwise we'll do
235 : // regular blocking reads from the media stream. If bool aCachedDataOnly
236 : // is true, this can safely be called on the main thread, otherwise it
237 : // must be called on the state machine thread.
238 : int64_t RangeEndTime(TrackInfo::TrackType aType,
239 : int64_t aStartOffset,
240 : int64_t aEndOffset,
241 : bool aCachedDataOnly);
242 :
243 : // Get the start time of the range beginning at aOffset. This is the start
244 : // time of the first aType sample we'd be able to play if we
245 : // started playback at aOffset.
246 : int64_t RangeStartTime(TrackInfo::TrackType aType, int64_t aOffset);
247 :
248 : MediaInfo mInfo;
249 : nsTArray<RefPtr<OggTrackDemuxer>> mDemuxers;
250 :
251 : // Map of codec-specific bitstream states.
252 : OggCodecStore mCodecStore;
253 :
254 : // Decode state of the Theora bitstream we're decoding, if we have video.
255 : OggCodecState* mTheoraState;
256 :
257 : // Decode state of the Vorbis bitstream we're decoding, if we have audio.
258 : OggCodecState* mVorbisState;
259 :
260 : // Decode state of the Opus bitstream we're decoding, if we have one.
261 : OggCodecState* mOpusState;
262 :
263 : // Get the bitstream decode state for the given track type
264 : // Decode state of the Flac bitstream we're decoding, if we have one.
265 : OggCodecState* mFlacState;
266 :
267 : OggCodecState* GetTrackCodecState(TrackInfo::TrackType aType) const;
268 : TrackInfo::TrackType GetCodecStateType(OggCodecState* aState) const;
269 :
270 : // Represents the user pref media.opus.enabled at the time our
271 : // contructor was called. We can't check it dynamically because
272 : // we're not on the main thread;
273 : bool mOpusEnabled;
274 :
275 : // Decode state of the Skeleton bitstream.
276 : SkeletonState* mSkeletonState;
277 :
278 : // Ogg decoding state.
279 0 : struct OggStateContext
280 : {
281 0 : explicit OggStateContext(MediaResource* aResource)
282 0 : : mResource(aResource), mNeedKeyframe(true) {}
283 : nsAutoOggSyncState mOggState;
284 : MediaResourceIndex mResource;
285 : Maybe<media::TimeUnit> mStartTime;
286 : bool mNeedKeyframe;
287 : };
288 :
289 : OggStateContext& OggState(TrackInfo::TrackType aType);
290 : ogg_sync_state* OggSyncState(TrackInfo::TrackType aType);
291 : MediaResourceIndex* Resource(TrackInfo::TrackType aType);
292 : MediaResourceIndex* CommonResource();
293 : OggStateContext mAudioOggState;
294 : OggStateContext mVideoOggState;
295 :
296 : Maybe<int64_t> mStartTime;
297 :
298 : // Booleans to indicate if we have audio and/or video data
299 : bool HasVideo() const;
300 : bool HasAudio() const;
301 0 : bool HasSkeleton() const
302 : {
303 0 : return mSkeletonState != 0 && mSkeletonState->mActive;
304 : }
305 : bool HaveStartTime () const;
306 : bool HaveStartTime (TrackInfo::TrackType aType);
307 : int64_t StartTime() const;
308 : int64_t StartTime(TrackInfo::TrackType aType);
309 :
310 : // The picture region inside Theora frame to be displayed, if we have
311 : // a Theora video track.
312 : nsIntRect mPicture;
313 :
314 : // True if we are decoding a chained ogg.
315 : bool mIsChained;
316 :
317 : // Total audio duration played so far.
318 : media::TimeUnit mDecodedAudioDuration;
319 :
320 : // Events manager
321 : TimedMetadataEventProducer* mTimedMetadataEvent;
322 : MediaEventProducer<void>* mOnSeekableEvent;
323 :
324 : // This will be populated only if a content change occurs, otherwise it
325 : // will be left as null so the original metadata is used.
326 : // It is updated once a chained ogg is encountered.
327 : // As Ogg chaining is only supported for audio, we only need an audio track
328 : // info.
329 : RefPtr<TrackInfoSharedPtr> mSharedAudioTrackInfo;
330 :
331 : friend class OggTrackDemuxer;
332 : };
333 :
334 : class OggTrackDemuxer : public MediaTrackDemuxer
335 : {
336 : public:
337 : OggTrackDemuxer(OggDemuxer* aParent,
338 : TrackInfo::TrackType aType,
339 : uint32_t aTrackNumber);
340 :
341 : UniquePtr<TrackInfo> GetInfo() const override;
342 :
343 : RefPtr<SeekPromise> Seek(const media::TimeUnit& aTime) override;
344 :
345 : RefPtr<SamplesPromise> GetSamples(int32_t aNumSamples = 1) override;
346 :
347 : void Reset() override;
348 :
349 : RefPtr<SkipAccessPointPromise> SkipToNextRandomAccessPoint(const media::TimeUnit& aTimeThreshold) override;
350 :
351 : media::TimeIntervals GetBuffered() override;
352 :
353 : void BreakCycles() override;
354 :
355 : private:
356 : ~OggTrackDemuxer();
357 : void SetNextKeyFrameTime();
358 : RefPtr<MediaRawData> NextSample();
359 : RefPtr<OggDemuxer> mParent;
360 : TrackInfo::TrackType mType;
361 : UniquePtr<TrackInfo> mInfo;
362 :
363 : // Queued sample extracted by the demuxer, but not yet returned.
364 : RefPtr<MediaRawData> mQueuedSample;
365 : };
366 : } // namespace mozilla
367 :
368 : #endif
|