Coverage Report

Created: 2018-09-25 14:53

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