summaryrefslogtreecommitdiffstats
path: root/dom/media/wave/WaveDemuxer.h
blob: a7ab65c002596fc350afdb821a05a579fb2c9d8b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
/* This Source Code Form is subject to the terms of the Mozilla Public
 * Licence, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef WAV_DEMUXER_H_
#define WAV_DEMUXER_H_

#include "MediaDataDemuxer.h"
#include "MediaResource.h"

namespace mozilla {
class BufferReader;

static const uint32_t FRMT_CODE = 0x666d7420;
static const uint32_t DATA_CODE = 0x64617461;
static const uint32_t LIST_CODE = 0x4c495354;
static const uint32_t INFO_CODE = 0x494e464f;

static const uint8_t RIFF[4] = {'R', 'I', 'F', 'F'};
static const uint8_t WAVE[4] = {'W', 'A', 'V', 'E'};

static const uint16_t RIFF_CHUNK_SIZE = 12;
static const uint16_t CHUNK_HEAD_SIZE = 8;
static const uint16_t FMT_CHUNK_MIN_SIZE = 16;
static const uint16_t DATA_CHUNK_SIZE = 768;

class WAVTrackDemuxer;

DDLoggedTypeDeclNameAndBase(WAVDemuxer, MediaDataDemuxer);
DDLoggedTypeNameAndBase(WAVTrackDemuxer, MediaTrackDemuxer);

class WAVDemuxer : public MediaDataDemuxer,
                   public DecoderDoctorLifeLogger<WAVDemuxer> {
 public:
  // MediaDataDemuxer interface.
  explicit WAVDemuxer(MediaResource* aSource);
  RefPtr<InitPromise> Init() override;
  uint32_t GetNumberTracks(TrackInfo::TrackType aType) const override;
  already_AddRefed<MediaTrackDemuxer> GetTrackDemuxer(
      TrackInfo::TrackType aType, uint32_t aTrackNumber) override;
  bool IsSeekable() const override;

 private:
  // Synchronous Initialization.
  bool InitInternal();

  MediaResourceIndex mSource;
  RefPtr<WAVTrackDemuxer> mTrackDemuxer;
};

class RIFFParser {
 private:
  class RIFFHeader;

 public:
  const RIFFHeader& RiffHeader() const;

  Result<uint32_t, nsresult> Parse(BufferReader& aReader);

  void Reset();

 private:
  class RIFFHeader {
   public:
    RIFFHeader();
    void Reset();

    bool IsValid() const;
    bool IsValid(int aPos) const;

    bool ParseNext(uint8_t c);

   private:
    bool Update(uint8_t c);

    uint8_t mRaw[RIFF_CHUNK_SIZE];

    int mPos;
  };

  RIFFHeader mRiffHeader;
};

class HeaderParser {
 private:
  class ChunkHeader;

 public:
  const ChunkHeader& GiveHeader() const;

  Result<uint32_t, nsresult> Parse(BufferReader& aReader);

  void Reset();

 private:
  class ChunkHeader {
   public:
    ChunkHeader();
    void Reset();

    bool IsValid() const;

    uint32_t ChunkName() const;
    uint32_t ChunkSize() const;

    bool ParseNext(uint8_t c);

   private:
    void Update(uint8_t c);

    uint8_t mRaw[CHUNK_HEAD_SIZE];

    int mPos;
  };

  ChunkHeader mHeader;
};

class FormatParser {
 private:
  class FormatChunk;

 public:
  const FormatChunk& FmtChunk() const;

  Result<uint32_t, nsresult> Parse(BufferReader& aReader);

  void Reset();

 private:
  class FormatChunk {
   public:
    FormatChunk();
    void Reset();

    uint16_t WaveFormat() const;
    uint16_t Channels() const;
    uint32_t SampleRate() const;
    uint16_t FrameSize() const;
    uint16_t SampleFormat() const;

    bool IsValid() const;
    bool ParseNext(uint8_t c);

   private:
    void Update(uint8_t c);

    uint8_t mRaw[FMT_CHUNK_MIN_SIZE];

    int mPos;
  };

  FormatChunk mFmtChunk;
};

class DataParser {
 private:
  class DataChunk;

 public:
  DataParser();

  const DataChunk& CurrentChunk() const;

  void Reset();

 private:
  class DataChunk {
   public:
    void Reset();

   private:
    int mPos;  // To Check Alignment
  };

  DataChunk mChunk;
};

class WAVTrackDemuxer : public MediaTrackDemuxer,
                        public DecoderDoctorLifeLogger<WAVTrackDemuxer> {
 public:
  explicit WAVTrackDemuxer(MediaResource* aSource);

  bool Init();

  int64_t StreamLength() const;

  media::TimeUnit Duration() const;
  media::TimeUnit Duration(int64_t aNumDataChunks) const;
  media::TimeUnit DurationFromBytes(uint32_t aNumBytes) const;

  media::TimeUnit SeekPosition() const;

  RefPtr<MediaRawData> DemuxSample();

  // MediaTrackDemuxer interface.
  UniquePtr<TrackInfo> GetInfo() const override;
  RefPtr<SeekPromise> Seek(const media::TimeUnit& aTime) override;
  RefPtr<SamplesPromise> GetSamples(int32_t aNumSamples) override;
  void Reset() override;
  RefPtr<SkipAccessPointPromise> SkipToNextRandomAccessPoint(
      const media::TimeUnit& aTimeThreshold) override;
  int64_t GetResourceOffset() const override;
  media::TimeIntervals GetBuffered() override;

 private:
  ~WAVTrackDemuxer() = default;

  media::TimeUnit FastSeek(const media::TimeUnit& aTime);
  media::TimeUnit ScanUntil(const media::TimeUnit& aTime);

  MediaByteRange FindNextChunk();

  MediaByteRange FindChunkHeader();
  MediaByteRange FindRIFFHeader();
  MediaByteRange FindFmtChunk();
  MediaByteRange FindListChunk();
  MediaByteRange FindInfoTag();

  bool RIFFParserInit();
  bool HeaderParserInit();
  bool FmtChunkParserInit();
  bool ListChunkParserInit(uint32_t aChunkSize);

  bool SkipNextChunk(const MediaByteRange& aRange);

  already_AddRefed<MediaRawData> GetNextChunk(const MediaByteRange& aRange);
  already_AddRefed<MediaRawData> GetFileHeader(const MediaByteRange& aRange);

  void UpdateState(const MediaByteRange& aRange);

  uint64_t OffsetFromChunkIndex(uint32_t aChunkIndex) const;
  uint64_t ChunkIndexFromTime(const media::TimeUnit& aTime) const;

  uint32_t Read(uint8_t* aBuffer, int64_t aOffset, int32_t aSize);

  MediaResourceIndex mSource;

  DataParser mParser;
  RIFFParser mRIFFParser;
  HeaderParser mHeaderParser;

  FormatParser mFmtParser;
  // ListChunkParser mListChunkParser;

  uint64_t mOffset;
  uint64_t mFirstChunkOffset;

  uint32_t mNumParsedChunks;
  uint32_t mChunkIndex;

  uint32_t mDataLength;
  uint64_t mTotalChunkLen;

  uint32_t mSamplesPerChunk;
  uint32_t mSamplesPerSecond;

  uint32_t mChannels;
  uint32_t mSampleFormat;

  UniquePtr<AudioInfo> mInfo;
};

}  // namespace mozilla

#endif