Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/OggCodecState.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(OggCodecState_h_)
7
#define OggCodecState_h_
8
9
#include <ogg/ogg.h>
10
// For MOZ_SAMPLE_TYPE_*
11
#include "FlacFrameParser.h"
12
#include "VideoUtils.h"
13
#include <nsDeque.h>
14
#include <nsTArray.h>
15
#include <nsClassHashtable.h>
16
17
#include <theora/theoradec.h>
18
#ifdef MOZ_TREMOR
19
#include <tremor/ivorbiscodec.h>
20
#else
21
#include <vorbis/codec.h>
22
#endif
23
24
// Uncomment the following to validate that we're predicting the number
25
// of Vorbis samples in each packet correctly.
26
#define VALIDATE_VORBIS_SAMPLE_CALCULATION
27
#ifdef  VALIDATE_VORBIS_SAMPLE_CALCULATION
28
#include <map>
29
#endif
30
31
struct OpusMSDecoder;
32
33
namespace mozilla {
34
35
class OpusParser;
36
37
struct OggPacketDeletePolicy
38
{
39
  void operator()(ogg_packet* aPacket) const
40
  {
41
    delete [] aPacket->packet;
42
    delete aPacket;
43
  }
44
};
45
46
using OggPacketPtr = UniquePtr<ogg_packet, OggPacketDeletePolicy>;
47
48
// Deallocates a packet, used in OggPacketQueue below.
49
class OggPacketDeallocator : public nsDequeFunctor
50
{
51
  virtual void operator()(void* aPacket) override
52
  {
53
    OggPacketDeletePolicy()(static_cast<ogg_packet*>(aPacket));
54
  }
55
};
56
57
// A queue of ogg_packets. When we read a page, we extract the page's packets
58
// and buffer them in the owning stream's OggCodecState. This is because
59
// if we're skipping up to the next keyframe in very large frame sized videos,
60
// there may be several megabytes of data between keyframes, and the
61
// ogg_stream_state would end up resizing its buffer every time we added a
62
// new 4KB page to the bitstream, which kills performance on Windows. This
63
// also gives us the option to timestamp packets rather than decoded
64
// frames/samples, reducing the amount of frames/samples we must decode to
65
// determine start-time at a particular offset, and gives us finer control
66
// over memory usage.
67
class OggPacketQueue : private nsDeque
68
{
69
public:
70
  OggPacketQueue() : nsDeque(new OggPacketDeallocator()) { }
71
  ~OggPacketQueue() { Erase(); }
72
  bool IsEmpty() { return nsDeque::GetSize() == 0; }
73
  void Append(OggPacketPtr aPacket);
74
  OggPacketPtr PopFront()
75
  {
76
    return OggPacketPtr(static_cast<ogg_packet*>(nsDeque::PopFront()));
77
  }
78
  ogg_packet* PeekFront()
79
  {
80
    return static_cast<ogg_packet*>(nsDeque::PeekFront());
81
  }
82
  OggPacketPtr Pop()
83
  {
84
    return OggPacketPtr(static_cast<ogg_packet*>(nsDeque::Pop()));
85
  }
86
  ogg_packet* operator[](size_t aIndex) const
87
  {
88
    return static_cast<ogg_packet*>(nsDeque::ObjectAt(aIndex));
89
  }
90
  size_t Length() const { return nsDeque::GetSize(); }
91
  void PushFront(OggPacketPtr aPacket)
92
  {
93
    nsDeque::PushFront(aPacket.release());
94
  }
95
  void Erase() { nsDeque::Erase(); }
96
};
97
98
// Encapsulates the data required for decoding an ogg bitstream and for
99
// converting granulepos to timestamps.
100
class OggCodecState
101
{
102
public:
103
  typedef mozilla::MetadataTags MetadataTags;
104
  // Ogg types we know about
105
  enum CodecType
106
  {
107
    TYPE_VORBIS=0,
108
    TYPE_THEORA,
109
    TYPE_OPUS,
110
    TYPE_SKELETON,
111
    TYPE_FLAC,
112
    TYPE_UNKNOWN
113
  };
114
115
  virtual ~OggCodecState();
116
117
  // Factory for creating nsCodecStates. Use instead of constructor.
118
  // aPage should be a beginning-of-stream page.
119
  static OggCodecState* Create(ogg_page* aPage);
120
121
  virtual CodecType GetType() { return TYPE_UNKNOWN; }
122
123
  // Reads a header packet. Returns false if an error was encountered
124
  // while reading header packets. Callers should check DoneReadingHeaders()
125
  // to determine if the last header has been read.
126
  // This function takes ownership of the packet and is responsible for
127
  // releasing it or queuing it for later processing.
128
  virtual bool DecodeHeader(OggPacketPtr aPacket)
129
  {
130
    return (mDoneReadingHeaders = true);
131
  }
132
133
  // Build a hash table with tag metadata parsed from the stream.
134
  virtual MetadataTags* GetTags()
135
  {
136
    return nullptr;
137
  }
138
139
  // Returns the end time that a granulepos represents.
140
  virtual int64_t Time(int64_t granulepos) { return -1; }
141
142
  // Returns the start time that a granulepos represents.
143
  virtual int64_t StartTime(int64_t granulepos) { return -1; }
144
145
  // Returns the duration of the given packet, if it can be determined.
146
  virtual int64_t PacketDuration(ogg_packet* aPacket) { return -1; }
147
148
  // Returns the start time of the given packet, if it can be determined.
149
  virtual int64_t PacketStartTime(ogg_packet* aPacket)
150
  {
151
    if (aPacket->granulepos < 0) {
152
      return -1;
153
    }
154
    int64_t endTime = Time(aPacket->granulepos);
155
    int64_t duration = PacketDuration(aPacket);
156
    if (duration > endTime) {
157
      // Audio preskip may eat a whole packet or more.
158
      return 0;
159
    } else {
160
      return endTime - duration;
161
    }
162
  }
163
164
  // Initializes the codec state.
165
  virtual bool Init() { return true; }
166
167
  // Returns true when this bitstream has finished reading all its
168
  // header packets.
169
  bool DoneReadingHeaders() { return mDoneReadingHeaders; }
170
171
  // Deactivates the bitstream. Only the primary video and audio bitstreams
172
  // should be active.
173
  void Deactivate()
174
  {
175
    mActive = false;
176
    mDoneReadingHeaders = true;
177
    Reset();
178
  }
179
180
  // Resets decoding state.
181
  virtual nsresult Reset();
182
183
  // Returns true if the OggCodecState thinks this packet is a header
184
  // packet. Note this does not verify the validity of the header packet,
185
  // it just guarantees that the packet is marked as a header packet (i.e.
186
  // it is definintely not a data packet). Do not use this to identify
187
  // streams, use it to filter header packets from data packets while
188
  // decoding.
189
  virtual bool IsHeader(ogg_packet* aPacket) { return false; }
190
191
  // Returns true if the OggCodecState thinks this packet represents a
192
  // keyframe, from which decoding can restart safely.
193
  virtual bool IsKeyframe(ogg_packet* aPacket) { return true; }
194
195
  // Returns true if there is a packet available for dequeueing in the stream.
196
  bool IsPacketReady();
197
198
  // Returns the next raw packet in the stream, or nullptr if there are no more
199
  // packets buffered in the packet queue. More packets can be buffered by
200
  // inserting one or more pages into the stream by calling PageIn().
201
  // The packet will have a valid granulepos.
202
  OggPacketPtr PacketOut();
203
204
  // Returns the next raw packet in the stream, or nullptr if there are no more
205
  // packets buffered in the packet queue, without consuming it.
206
  // The packet will have a valid granulepos.
207
  ogg_packet* PacketPeek();
208
209
  // Moves all raw packets from aOther to the front of the current packet queue.
210
  void PushFront(OggPacketQueue&& aOther);
211
212
  // Returns the next packet in the stream as a MediaRawData, or nullptr
213
  // if there are no more packets buffered in the packet queue. More packets
214
  // can be buffered by inserting one or more pages into the stream by calling
215
  // PageIn(). The packet will have a valid granulepos.
216
  virtual already_AddRefed<MediaRawData> PacketOutAsMediaRawData();
217
218
  // Extracts all packets from the page, and inserts them into the packet
219
  // queue. They can be extracted by calling PacketOut(). Packets from an
220
  // inactive stream are not buffered, i.e. this call has no effect for
221
  // inactive streams. Multiple pages may need to be inserted before
222
  // PacketOut() starts to return packets, as granulepos may need to be
223
  // captured.
224
  virtual nsresult PageIn(ogg_page* aPage);
225
226
  // Returns the maximum number of microseconds which a keyframe can be offset
227
  // from any given interframe.b
228
  virtual int64_t MaxKeyframeOffset() { return 0; }
229
  // Public access for mTheoraInfo.keyframe_granule_shift
230
  virtual int32_t KeyFrameGranuleJobs() { return 0; }
231
232
  // Number of packets read.
233
  uint64_t mPacketCount;
234
235
  // Serial number of the bitstream.
236
  uint32_t mSerial;
237
238
  // Ogg specific state.
239
  ogg_stream_state mState;
240
241
  // Queue of as yet undecoded packets. Packets are guaranteed to have
242
  // a valid granulepos.
243
  OggPacketQueue mPackets;
244
245
  // Is the bitstream active; whether we're decoding and playing this bitstream.
246
  bool mActive;
247
248
  // True when all headers packets have been read.
249
  bool mDoneReadingHeaders;
250
251
  virtual const TrackInfo* GetInfo() const
252
  {
253
    MOZ_RELEASE_ASSERT(false, "Can't be called directly");
254
    return nullptr;
255
  }
256
257
  // Validation utility for vorbis-style tag names.
258
  static bool IsValidVorbisTagName(nsCString& aName);
259
260
  // Utility method to parse and add a vorbis-style comment
261
  // to a metadata hash table. Most Ogg-encapsulated codecs
262
  // use the vorbis comment format for metadata.
263
  static bool AddVorbisComment(MetadataTags* aTags,
264
                        const char* aComment,
265
                        uint32_t aLength);
266
267
protected:
268
  // Constructs a new OggCodecState. aActive denotes whether the stream is
269
  // active. For streams of unsupported or unknown types, aActive should be
270
  // false.
271
  OggCodecState(ogg_page* aBosPage, bool aActive);
272
273
  // Deallocates all packets stored in mUnstamped, and clears the array.
274
  void ClearUnstamped();
275
276
  // Extracts packets out of mState until a data packet with a non -1
277
  // granulepos is encountered, or no more packets are readable. Header
278
  // packets are pushed into the packet queue immediately, and data packets
279
  // are buffered in mUnstamped. Once a non -1 granulepos packet is read
280
  // the granulepos of the packets in mUnstamped can be inferred, and they
281
  // can be pushed over to mPackets. Used by PageIn() implementations in
282
  // subclasses.
283
  nsresult PacketOutUntilGranulepos(bool& aFoundGranulepos);
284
285
  // Temporary buffer in which to store packets while we're reading packets
286
  // in order to capture granulepos.
287
  nsTArray<OggPacketPtr> mUnstamped;
288
289
  bool SetCodecSpecificConfig(MediaByteBuffer* aBuffer,
290
                              OggPacketQueue& aHeaders);
291
292
private:
293
  bool InternalInit();
294
};
295
296
class VorbisState : public OggCodecState
297
{
298
public:
299
  explicit VorbisState(ogg_page* aBosPage);
300
  virtual ~VorbisState();
301
302
  CodecType GetType() override { return TYPE_VORBIS; }
303
  bool DecodeHeader(OggPacketPtr aPacket) override;
304
  int64_t Time(int64_t granulepos) override;
305
  int64_t PacketDuration(ogg_packet* aPacket) override;
306
  bool Init() override;
307
  nsresult Reset() override;
308
  bool IsHeader(ogg_packet* aPacket) override;
309
  nsresult PageIn(ogg_page* aPage) override;
310
  const TrackInfo* GetInfo() const override { return &mInfo; }
311
312
  // Return a hash table with tag metadata.
313
  MetadataTags* GetTags() override;
314
315
private:
316
  AudioInfo mInfo;
317
  vorbis_info mVorbisInfo;
318
  vorbis_comment mComment;
319
  vorbis_dsp_state mDsp;
320
  vorbis_block mBlock;
321
  OggPacketQueue mHeaders;
322
323
  // Returns the end time that a granulepos represents.
324
  static int64_t Time(vorbis_info* aInfo, int64_t aGranulePos);
325
326
  // Reconstructs the granulepos of Vorbis packets stored in the mUnstamped
327
  // array.
328
  nsresult ReconstructVorbisGranulepos();
329
330
  // The "block size" of the previously decoded Vorbis packet, or 0 if we've
331
  // not yet decoded anything. This is used to calculate the number of samples
332
  // in a Vorbis packet, since each Vorbis packet depends on the previous
333
  // packet while being decoded.
334
  long mPrevVorbisBlockSize;
335
336
  // Granulepos (end sample) of the last decoded Vorbis packet. This is used
337
  // to calculate the Vorbis granulepos when we don't find a granulepos to
338
  // back-propagate from.
339
  int64_t mGranulepos;
340
341
#ifdef VALIDATE_VORBIS_SAMPLE_CALCULATION
342
  // When validating that we've correctly predicted Vorbis packets' number
343
  // of samples, we store each packet's predicted number of samples in this
344
  // map, and verify we decode the predicted number of samples.
345
  std::map<ogg_packet*, long> mVorbisPacketSamples;
346
#endif
347
348
  // Records that aPacket is predicted to have aSamples samples.
349
  // This function has no effect if VALIDATE_VORBIS_SAMPLE_CALCULATION
350
  // is not defined.
351
  void RecordVorbisPacketSamples(ogg_packet* aPacket, long aSamples);
352
353
  // Verifies that aPacket has had its number of samples predicted.
354
  // This function has no effect if VALIDATE_VORBIS_SAMPLE_CALCULATION
355
  // is not defined.
356
  void AssertHasRecordedPacketSamples(ogg_packet* aPacket);
357
358
public:
359
  // Asserts that the number of samples predicted for aPacket is aSamples.
360
  // This function has no effect if VALIDATE_VORBIS_SAMPLE_CALCULATION
361
  // is not defined.
362
  void ValidateVorbisPacketSamples(ogg_packet* aPacket, long aSamples);
363
364
};
365
366
// Returns 1 if the Theora info struct is decoding a media of Theora
367
// version (maj,min,sub) or later, otherwise returns 0.
368
int TheoraVersion(th_info* info,
369
                  unsigned char maj,
370
                  unsigned char min,
371
                  unsigned char sub);
372
373
class TheoraState : public OggCodecState
374
{
375
public:
376
  explicit TheoraState(ogg_page* aBosPage);
377
  virtual ~TheoraState();
378
379
  CodecType GetType() override { return TYPE_THEORA; }
380
  bool DecodeHeader(OggPacketPtr aPacket) override;
381
  int64_t Time(int64_t granulepos) override;
382
  int64_t StartTime(int64_t granulepos) override;
383
  int64_t PacketDuration(ogg_packet* aPacket) override;
384
  bool Init() override;
385
  nsresult Reset() override;
386
  bool IsHeader(ogg_packet* aPacket) override;
387
  bool IsKeyframe(ogg_packet* aPacket) override;
388
  nsresult PageIn(ogg_page* aPage) override;
389
  const TrackInfo* GetInfo() const override { return &mInfo; }
390
  int64_t MaxKeyframeOffset() override;
391
  int32_t KeyFrameGranuleJobs() override
392
  {
393
    return mTheoraInfo.keyframe_granule_shift;
394
  }
395
396
private:
397
  // Returns the end time that a granulepos represents.
398
  static int64_t Time(th_info* aInfo, int64_t aGranulePos);
399
400
  th_info mTheoraInfo;
401
  th_comment mComment;
402
  th_setup_info* mSetup;
403
  th_dec_ctx* mCtx;
404
405
  VideoInfo mInfo;
406
  OggPacketQueue mHeaders;
407
408
  // Reconstructs the granulepos of Theora packets stored in the
409
  // mUnstamped array. mUnstamped must be filled with consecutive packets from
410
  // the stream, with the last packet having a known granulepos. Using this
411
  // known granulepos, and the known frame numbers, we recover the granulepos
412
  // of all frames in the array. This enables us to determine their timestamps.
413
  void ReconstructTheoraGranulepos();
414
};
415
416
class OpusState : public OggCodecState
417
{
418
public:
419
  explicit OpusState(ogg_page* aBosPage);
420
  virtual ~OpusState();
421
422
  CodecType GetType() override { return TYPE_OPUS; }
423
  bool DecodeHeader(OggPacketPtr aPacket) override;
424
  int64_t Time(int64_t aGranulepos) override;
425
  int64_t PacketDuration(ogg_packet* aPacket) override;
426
  bool Init() override;
427
  nsresult Reset() override;
428
  nsresult Reset(bool aStart);
429
  bool IsHeader(ogg_packet* aPacket) override;
430
  nsresult PageIn(ogg_page* aPage) override;
431
  already_AddRefed<MediaRawData> PacketOutAsMediaRawData() override;
432
  const TrackInfo* GetInfo() const override { return &mInfo; }
433
434
  // Returns the end time that a granulepos represents.
435
  static int64_t Time(int aPreSkip, int64_t aGranulepos);
436
437
  // Construct and return a table of tags from the metadata header.
438
  MetadataTags* GetTags() override;
439
440
private:
441
  nsAutoPtr<OpusParser> mParser;
442
  OpusMSDecoder* mDecoder;
443
444
  // Granule position (end sample) of the last decoded Opus packet. This is
445
  // used to calculate the amount we should trim from the last packet.
446
  int64_t mPrevPacketGranulepos;
447
448
  // Reconstructs the granulepos of Opus packets stored in the
449
  // mUnstamped array. mUnstamped must be filled with consecutive packets from
450
  // the stream, with the last packet having a known granulepos. Using this
451
  // known granulepos, and the known frame numbers, we recover the granulepos
452
  // of all frames in the array. This enables us to determine their timestamps.
453
  bool ReconstructOpusGranulepos();
454
455
  // Granule position (end sample) of the last decoded Opus page. This is
456
  // used to calculate the Opus per-packet granule positions on the last page,
457
  // where we may need to trim some samples from the end.
458
  int64_t mPrevPageGranulepos;
459
  AudioInfo mInfo;
460
  OggPacketQueue mHeaders;
461
};
462
463
// Constructs a 32bit version number out of two 16 bit major,minor
464
// version numbers.
465
#define SKELETON_VERSION(major, minor) (((major)<<16)|(minor))
466
467
enum EMsgHeaderType
468
{
469
  eContentType,
470
  eRole,
471
  eName,
472
  eLanguage,
473
  eTitle,
474
  eDisplayHint,
475
  eAltitude,
476
  eTrackOrder,
477
  eTrackDependencies
478
};
479
480
typedef struct
481
{
482
  const char* mPatternToRecognize;
483
  EMsgHeaderType mMsgHeaderType;
484
} FieldPatternType;
485
486
// Stores the message information for different logical bitstream.
487
typedef struct
488
{
489
  nsClassHashtable<nsUint32HashKey, nsCString> mValuesStore;
490
} MessageField;
491
492
class SkeletonState : public OggCodecState
493
{
494
public:
495
  explicit SkeletonState(ogg_page* aBosPage);
496
  ~SkeletonState();
497
498
  nsClassHashtable<nsUint32HashKey, MessageField> mMsgFieldStore;
499
500
  CodecType GetType() override { return TYPE_SKELETON; }
501
  bool DecodeHeader(OggPacketPtr aPacket) override;
502
  int64_t Time(int64_t granulepos) override { return -1; }
503
  bool IsHeader(ogg_packet* aPacket) override { return true; }
504
505
  // Return true if the given time (in milliseconds) is within
506
  // the presentation time defined in the skeleton track.
507
0
  bool IsPresentable(int64_t aTime) { return aTime >= mPresentationTime; }
508
509
  // Stores the offset of the page on which a keyframe starts,
510
  // and its presentation time.
511
  class nsKeyPoint
512
  {
513
  public:
514
    nsKeyPoint()
515
      : mOffset(INT64_MAX)
516
      , mTime(INT64_MAX) {}
517
518
    nsKeyPoint(int64_t aOffset, int64_t aTime)
519
      : mOffset(aOffset)
520
      ,mTime(aTime) {}
521
522
    // Offset from start of segment/link-in-the-chain in bytes.
523
    int64_t mOffset;
524
525
    // Presentation time in usecs.
526
    int64_t mTime;
527
528
    bool IsNull()
529
    {
530
      return mOffset == INT64_MAX && mTime == INT64_MAX;
531
    }
532
  };
533
534
  // Stores a keyframe's byte-offset, presentation time and the serialno
535
  // of the stream it belongs to.
536
  class nsSeekTarget
537
  {
538
  public:
539
    nsSeekTarget() : mSerial(0) { }
540
    nsKeyPoint mKeyPoint;
541
    uint32_t mSerial;
542
    bool IsNull()
543
    {
544
      return mKeyPoint.IsNull() && mSerial == 0;
545
    }
546
  };
547
548
  // Determines from the seek index the keyframe which you must seek back to
549
  // in order to get all keyframes required to render all streams with
550
  // serialnos in aTracks, at time aTarget.
551
  nsresult IndexedSeekTarget(int64_t aTarget,
552
                             nsTArray<uint32_t>& aTracks,
553
                             nsSeekTarget& aResult);
554
555
  bool HasIndex() const
556
  {
557
    return mIndex.Count() > 0;
558
  }
559
560
  // Returns the duration of the active tracks in the media, if we have
561
  // an index. aTracks must be filled with the serialnos of the active tracks.
562
  // The duration is calculated as the greatest end time of all active tracks,
563
  // minus the smalled start time of all the active tracks.
564
  nsresult GetDuration(const nsTArray<uint32_t>& aTracks, int64_t& aDuration);
565
566
private:
567
568
  // Decodes an index packet. Returns false on failure.
569
  bool DecodeIndex(ogg_packet* aPacket);
570
  // Decodes an fisbone packet. Returns false on failure.
571
  bool DecodeFisbone(ogg_packet* aPacket);
572
573
  // Gets the keypoint you must seek to in order to get the keyframe required
574
  // to render the stream at time aTarget on stream with serial aSerialno.
575
  nsresult IndexedSeekTargetForTrack(uint32_t aSerialno,
576
                                     int64_t aTarget,
577
                                     nsKeyPoint& aResult);
578
579
  // Version of the decoded skeleton track, as per the SKELETON_VERSION macro.
580
  uint32_t mVersion;
581
582
  // Presentation time of the resource in milliseconds
583
  int64_t mPresentationTime;
584
585
  // Length of the resource in bytes.
586
  int64_t mLength;
587
588
  // Stores the keyframe index and duration information for a particular
589
  // stream.
590
  class nsKeyFrameIndex
591
  {
592
  public:
593
594
    nsKeyFrameIndex(int64_t aStartTime, int64_t aEndTime)
595
      : mStartTime(aStartTime)
596
      , mEndTime(aEndTime)
597
    {
598
      MOZ_COUNT_CTOR(nsKeyFrameIndex);
599
    }
600
601
    ~nsKeyFrameIndex()
602
    {
603
      MOZ_COUNT_DTOR(nsKeyFrameIndex);
604
    }
605
606
    void Add(int64_t aOffset, int64_t aTimeMs)
607
    {
608
      mKeyPoints.AppendElement(nsKeyPoint(aOffset, aTimeMs));
609
    }
610
611
    const nsKeyPoint& Get(uint32_t aIndex) const
612
    {
613
      return mKeyPoints[aIndex];
614
    }
615
616
    uint32_t Length() const
617
    {
618
      return mKeyPoints.Length();
619
    }
620
621
    // Presentation time of the first sample in this stream in usecs.
622
    const int64_t mStartTime;
623
624
    // End time of the last sample in this stream in usecs.
625
    const int64_t mEndTime;
626
627
  private:
628
    nsTArray<nsKeyPoint> mKeyPoints;
629
  };
630
631
  // Maps Ogg serialnos to the index-keypoint list.
632
  nsClassHashtable<nsUint32HashKey, nsKeyFrameIndex> mIndex;
633
};
634
635
class FlacState : public OggCodecState
636
{
637
public:
638
  explicit FlacState(ogg_page* aBosPage);
639
640
  CodecType GetType() override { return TYPE_FLAC; }
641
  bool DecodeHeader(OggPacketPtr aPacket) override;
642
  int64_t Time(int64_t granulepos) override;
643
  int64_t PacketDuration(ogg_packet* aPacket) override;
644
  bool IsHeader(ogg_packet* aPacket) override;
645
  nsresult PageIn(ogg_page* aPage) override;
646
647
  // Return a hash table with tag metadata.
648
  MetadataTags* GetTags() override;
649
650
  const TrackInfo* GetInfo() const override;
651
652
private:
653
  bool ReconstructFlacGranulepos(void);
654
655
  FlacFrameParser mParser;
656
};
657
658
} // namespace mozilla
659
660
#endif