Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 :
7 : #include "FlacDemuxer.h"
8 :
9 : #include "mozilla/Maybe.h"
10 : #include "mozilla/SizePrintfMacros.h"
11 : #include "mp4_demuxer/BitReader.h"
12 : #include "nsAutoPtr.h"
13 : #include "prenv.h"
14 : #include "FlacFrameParser.h"
15 : #include "VideoUtils.h"
16 : #include "TimeUnits.h"
17 :
18 : extern mozilla::LazyLogModule gMediaDemuxerLog;
19 : #define LOG(msg, ...) \
20 : MOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, ("FlacDemuxer " msg, ##__VA_ARGS__))
21 : #define LOGV(msg, ...) \
22 : MOZ_LOG(gMediaDemuxerLog, LogLevel::Verbose, ("FlacDemuxer " msg, ##__VA_ARGS__))
23 :
24 : using namespace mozilla::media;
25 :
26 : namespace mozilla {
27 : namespace flac {
28 :
29 : // flac::FrameHeader - Holds the flac frame header and its parsing
30 : // state.
31 :
32 : #define FLAC_MAX_CHANNELS 8
33 : #define FLAC_MIN_BLOCKSIZE 16
34 : #define FLAC_MAX_BLOCKSIZE 65535
35 : #define FLAC_MIN_FRAME_SIZE 11
36 : #define FLAC_MAX_FRAME_HEADER_SIZE 16
37 : #define FLAC_MAX_FRAME_SIZE (FLAC_MAX_FRAME_HEADER_SIZE \
38 : +FLAC_MAX_BLOCKSIZE*FLAC_MAX_CHANNELS*3)
39 :
40 0 : class FrameHeader
41 : {
42 : public:
43 0 : const AudioInfo& Info() const { return mInfo; }
44 :
45 0 : uint32_t Size() const { return mSize; }
46 :
47 0 : bool IsValid() const { return mValid; }
48 :
49 : // Return the index (in samples) from the beginning of the track.
50 0 : int64_t Index() const { return mIndex; }
51 :
52 : // Parse the current packet and check that it made a valid flac frame header.
53 : // From https://xiph.org/flac/format.html#frame_header
54 : // A valid header is one that can be decoded without error and that has a
55 : // valid CRC.
56 : // aPacket must points to a buffer that is at least FLAC_MAX_FRAME_HEADER_SIZE
57 : // bytes.
58 0 : bool Parse(const uint8_t* aPacket)
59 : {
60 0 : mp4_demuxer::BitReader br(aPacket, FLAC_MAX_FRAME_HEADER_SIZE * 8);
61 :
62 : // Frame sync code.
63 0 : if ((br.ReadBits(15) & 0x7fff) != 0x7ffc) {
64 0 : return false;
65 : }
66 :
67 : // Variable block size stream code.
68 0 : mVariableBlockSize = br.ReadBit();
69 :
70 : // Block size and sample rate codes.
71 0 : int bs_code = br.ReadBits(4);
72 0 : int sr_code = br.ReadBits(4);
73 :
74 : // Channels and decorrelation.
75 0 : int ch_mode = br.ReadBits(4);
76 0 : if (ch_mode < FLAC_MAX_CHANNELS) {
77 0 : mInfo.mChannels = ch_mode + 1;
78 0 : } else if (ch_mode < FLAC_MAX_CHANNELS + FLAC_CHMODE_MID_SIDE) {
79 : // This is a special flac channels, we can't handle those yet. Treat it
80 : // as stereo.
81 0 : mInfo.mChannels = 2;
82 : } else {
83 : // invalid channel mode
84 0 : return false;
85 : }
86 :
87 : // Bits per sample.
88 0 : int bps_code = br.ReadBits(3);
89 0 : if (bps_code == 3 || bps_code == 7) {
90 : // Invalid sample size code.
91 0 : return false;
92 : }
93 0 : mInfo.mBitDepth = FlacSampleSizeTable[bps_code];
94 :
95 : // Reserved bit, most be 1.
96 0 : if (br.ReadBit()) {
97 : // Broken stream, invalid padding.
98 0 : return false;
99 : }
100 :
101 : // Sample or frame count.
102 0 : int64_t frame_or_sample_num = br.ReadUTF8();
103 0 : if (frame_or_sample_num < 0) {
104 : // Sample/frame number invalid.
105 0 : return false;
106 : }
107 :
108 : // Blocksize
109 0 : if (bs_code == 0) {
110 : // reserved blocksize code
111 0 : return false;
112 0 : } else if (bs_code == 6) {
113 0 : mBlocksize = br.ReadBits(8) + 1;
114 0 : } else if (bs_code == 7) {
115 0 : mBlocksize = br.ReadBits(16) + 1;
116 : } else {
117 0 : mBlocksize = FlacBlocksizeTable[bs_code];
118 : }
119 :
120 : // The sample index is either:
121 : // 1- coded sample number if blocksize is variable or
122 : // 2- coded frame number if blocksize is known.
123 : // A frame is made of Blocksize sample.
124 0 : mIndex = mVariableBlockSize ? frame_or_sample_num
125 0 : : frame_or_sample_num * mBlocksize;
126 :
127 : // Sample rate.
128 0 : if (sr_code < 12) {
129 0 : mInfo.mRate = FlacSampleRateTable[sr_code];
130 0 : } else if (sr_code == 12) {
131 0 : mInfo.mRate = br.ReadBits(8) * 1000;
132 0 : } else if (sr_code == 13) {
133 0 : mInfo.mRate = br.ReadBits(16);
134 0 : } else if (sr_code == 14) {
135 0 : mInfo.mRate = br.ReadBits(16) * 10;
136 : } else {
137 : // Illegal sample rate code.
138 0 : return false;
139 : }
140 :
141 : // Header CRC-8 check.
142 0 : uint8_t crc = 0;
143 0 : for (uint32_t i = 0; i < br.BitCount() / 8; i++) {
144 0 : crc = CRC8Table[crc ^ aPacket[i]];
145 : }
146 0 : mValid = crc == br.ReadBits(8);
147 0 : mSize = br.BitCount() / 8;
148 :
149 0 : if (mValid) {
150 : // Set the mimetype to make it a valid AudioInfo.
151 0 : mInfo.mMimeType = "audio/flac";
152 : }
153 :
154 0 : return mValid;
155 : }
156 :
157 : private:
158 : friend class Frame;
159 : enum
160 : {
161 : FLAC_CHMODE_INDEPENDENT = 0,
162 : FLAC_CHMODE_LEFT_SIDE,
163 : FLAC_CHMODE_RIGHT_SIDE,
164 : FLAC_CHMODE_MID_SIDE,
165 : };
166 : AudioInfo mInfo;
167 : // Index in samples from start;
168 : int64_t mIndex = 0;
169 : bool mVariableBlockSize = false;
170 : uint32_t mBlocksize = 0;;
171 : uint32_t mSize = 0;
172 : bool mValid = false;
173 :
174 : static const int FlacSampleRateTable[16];
175 : static const int32_t FlacBlocksizeTable[16];
176 : static const uint8_t FlacSampleSizeTable[8];
177 : static const uint8_t CRC8Table[256];
178 : };
179 :
180 : const int FrameHeader::FlacSampleRateTable[16] =
181 : {
182 : 0,
183 : 88200, 176400, 192000,
184 : 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000,
185 : 0, 0, 0, 0
186 : };
187 :
188 : const int32_t FrameHeader::FlacBlocksizeTable[16] =
189 : {
190 : 0 , 192 , 576<<0, 576<<1, 576<<2, 576<<3, 0, 0,
191 : 256<<0, 256<<1, 256<<2, 256<<3, 256<<4, 256<<5, 256<<6, 256<<7
192 : };
193 :
194 : const uint8_t FrameHeader::FlacSampleSizeTable[8] = { 0, 8, 12, 0, 16, 20, 24, 0 };
195 :
196 : const uint8_t FrameHeader::CRC8Table[256] =
197 : {
198 : 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
199 : 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
200 : 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
201 : 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
202 : 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
203 : 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
204 : 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
205 : 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
206 : 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
207 : 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
208 : 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
209 : 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
210 : 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
211 : 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
212 : 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
213 : 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
214 : 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
215 : 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
216 : 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
217 : 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
218 : 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
219 : 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
220 : 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
221 : 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
222 : 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
223 : 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
224 : 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
225 : 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
226 : 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
227 : 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
228 : 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
229 : 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
230 : };
231 :
232 : // flac::Frame - Frame meta container used to parse and hold a frame
233 : // header and side info.
234 0 : class Frame
235 : {
236 : public:
237 :
238 : // The FLAC signature is made of 14 bits set to 1; however the 15th bit is
239 : // mandatorily set to 0, so we need to find either of 0xfffc or 0xfffd 2-bytes
240 : // signature. We first use a bitmask to see if 0xfc or 0xfd is present. And if
241 : // so we check for the whole signature.
242 : // aData must be pointing to a buffer at least
243 : // aLength + FLAC_MAX_FRAME_HEADER_SIZE bytes.
244 0 : int64_t FindNext(const uint8_t* aData, const uint32_t aLength)
245 : {
246 0 : uint32_t modOffset = aLength % 4;
247 : uint32_t i, j;
248 :
249 0 : for (i = 0; i < modOffset; i++) {
250 0 : if ((BigEndian::readUint16(aData + i) & 0xfffe) == 0xfff8) {
251 0 : if (mHeader.Parse(aData + i)) {
252 0 : return i;
253 : }
254 : }
255 : }
256 :
257 0 : for (; i < aLength; i += 4) {
258 0 : uint32_t x = BigEndian::readUint32(aData + i);
259 0 : if (((x & ~(x + 0x01010101)) & 0x80808080)) {
260 0 : for (j = 0; j < 4; j++) {
261 0 : if ((BigEndian::readUint16(aData + i + j) & 0xfffe) == 0xfff8) {
262 0 : if (mHeader.Parse(aData + i + j)) {
263 0 : return i + j;
264 : }
265 : }
266 : }
267 : }
268 : }
269 0 : return -1;
270 : }
271 :
272 : // Find the next frame start in the current resource.
273 : // On exit return true, offset is set and resource points to the frame found.
274 0 : bool FindNext(MediaResourceIndex& aResource)
275 : {
276 : static const int BUFFER_SIZE = 4096;
277 :
278 0 : Reset();
279 :
280 0 : nsTArray<char> buffer;
281 0 : int64_t originalOffset = aResource.Tell();
282 0 : int64_t offset = originalOffset;
283 0 : uint32_t innerOffset = 0;
284 :
285 0 : do {
286 0 : uint32_t read = 0;
287 0 : buffer.SetLength(BUFFER_SIZE + innerOffset);
288 : nsresult rv =
289 0 : aResource.Read(buffer.Elements() + innerOffset, BUFFER_SIZE, &read);
290 0 : if (NS_FAILED(rv)) {
291 0 : return false;
292 : }
293 :
294 0 : if (read < FLAC_MAX_FRAME_HEADER_SIZE) {
295 : // Assume that we can't have a valid frame in such small content, we
296 : // must have reached EOS.
297 : // So we're done.
298 0 : mEOS = true;
299 0 : return false;
300 : }
301 :
302 0 : const size_t bufSize = read + innerOffset - FLAC_MAX_FRAME_HEADER_SIZE;
303 : int64_t foundOffset =
304 0 : FindNext(reinterpret_cast<uint8_t*>(buffer.Elements()), bufSize);
305 :
306 0 : if (foundOffset >= 0) {
307 0 : SetOffset(aResource, foundOffset + offset);
308 0 : return true;
309 : }
310 :
311 : // Scan the next block;
312 0 : offset += bufSize;
313 0 : buffer.RemoveElementsAt(0, bufSize);
314 0 : innerOffset = buffer.Length();
315 0 : } while (offset - originalOffset < FLAC_MAX_FRAME_SIZE);
316 :
317 0 : return false;
318 : }
319 :
320 0 : int64_t Offset() const { return mOffset; }
321 :
322 0 : const AudioInfo& Info() const { return Header().Info(); }
323 :
324 0 : void SetEndOffset(int64_t aOffset) { mSize = aOffset - mOffset; }
325 :
326 0 : void SetEndTime(int64_t aIndex)
327 : {
328 0 : if (aIndex > Header().mIndex) {
329 0 : mDuration = aIndex - Header().mIndex;
330 : }
331 0 : }
332 :
333 0 : uint32_t Size() const { return mSize; }
334 :
335 0 : TimeUnit Time() const
336 : {
337 0 : if (!IsValid()) {
338 0 : return TimeUnit::Invalid();
339 : }
340 0 : MOZ_ASSERT(Header().Info().mRate, "Invalid Frame. Need Header");
341 0 : return FramesToTimeUnit(Header().mIndex, Header().Info().mRate);
342 : }
343 :
344 0 : TimeUnit Duration() const
345 : {
346 0 : if (!IsValid()) {
347 0 : return TimeUnit();
348 : }
349 0 : MOZ_ASSERT(Header().Info().mRate, "Invalid Frame. Need Header");
350 0 : return FramesToTimeUnit(mDuration, Header().Info().mRate);
351 : }
352 :
353 : // Returns the parsed frame header.
354 0 : const FrameHeader& Header() const { return mHeader; }
355 :
356 0 : bool IsValid() const { return mHeader.IsValid(); }
357 :
358 0 : bool EOS() const { return mEOS; }
359 :
360 0 : void SetRate(uint32_t aRate) { mHeader.mInfo.mRate = aRate; };
361 :
362 0 : void SetBitDepth(uint32_t aBitDepth) { mHeader.mInfo.mBitDepth = aBitDepth; }
363 :
364 0 : void SetInvalid() { mHeader.mValid = false; }
365 :
366 : // Resets the frame header and data.
367 0 : void Reset() { *this = Frame(); }
368 :
369 : private:
370 0 : void SetOffset(MediaResourceIndex& aResource, int64_t aOffset)
371 : {
372 0 : mOffset = aOffset;
373 0 : aResource.Seek(SEEK_SET, mOffset);
374 0 : }
375 :
376 : // The offset to the start of the header.
377 : int64_t mOffset = 0;
378 : uint32_t mSize = 0;
379 : uint32_t mDuration = 0;
380 : bool mEOS = false;
381 :
382 : // The currently parsed frame header.
383 : FrameHeader mHeader;
384 :
385 : };
386 :
387 0 : class FrameParser
388 : {
389 : public:
390 :
391 : // Returns the currently parsed frame. Reset via EndFrameSession.
392 0 : const Frame& CurrentFrame() const { return mFrame; }
393 :
394 : // Returns the first parsed frame.
395 0 : const Frame& FirstFrame() const { return mFirstFrame; }
396 :
397 : // Clear the last parsed frame to allow for next frame parsing
398 0 : void EndFrameSession()
399 : {
400 0 : mNextFrame.Reset();
401 0 : mFrame.Reset();
402 0 : }
403 :
404 : // Attempt to find the next frame.
405 0 : bool FindNextFrame(MediaResourceIndex& aResource)
406 : {
407 0 : mFrame = mNextFrame;
408 0 : if (GetNextFrame(aResource)) {
409 0 : if (!mFrame.IsValid()) {
410 0 : mFrame = mNextFrame;
411 : // We need two frames to be able to start playing (or have reached EOS).
412 0 : GetNextFrame(aResource);
413 : }
414 : }
415 :
416 0 : if (mFrame.IsValid()) {
417 0 : if (mNextFrame.EOS()) {
418 0 : mFrame.SetEndOffset(aResource.Tell());
419 0 : } else if (mNextFrame.IsValid()) {
420 0 : mFrame.SetEndOffset(mNextFrame.Offset());
421 0 : mFrame.SetEndTime(mNextFrame.Header().Index());
422 : }
423 : }
424 :
425 0 : if (!mFirstFrame.IsValid()) {
426 0 : mFirstFrame = mFrame;
427 : }
428 0 : return mFrame.IsValid();
429 : }
430 :
431 : // Convenience methods to external FlacFrameParser ones.
432 0 : bool IsHeaderBlock(const uint8_t* aPacket, size_t aLength) const
433 : {
434 0 : return mParser.IsHeaderBlock(aPacket, aLength);
435 : }
436 :
437 0 : uint32_t HeaderBlockLength(const uint8_t* aPacket) const
438 : {
439 0 : return mParser.HeaderBlockLength(aPacket);
440 : }
441 :
442 0 : bool DecodeHeaderBlock(const uint8_t* aPacket, size_t aLength)
443 : {
444 0 : return mParser.DecodeHeaderBlock(aPacket, aLength);
445 : }
446 :
447 0 : bool HasFullMetadata() const { return mParser.HasFullMetadata(); }
448 :
449 0 : AudioInfo Info() const { return mParser.mInfo; }
450 :
451 : // Return a hash table with tag metadata.
452 0 : MetadataTags* GetTags() const { return mParser.GetTags(); }
453 :
454 : private:
455 0 : bool GetNextFrame(MediaResourceIndex& aResource)
456 : {
457 0 : while (mNextFrame.FindNext(aResource)) {
458 : // Move our offset slightly, so that we don't find the same frame at the
459 : // next FindNext call.
460 0 : aResource.Seek(SEEK_CUR, mNextFrame.Header().Size());
461 0 : if (mFrame.IsValid()
462 0 : && mNextFrame.Offset() - mFrame.Offset() < FLAC_MAX_FRAME_SIZE
463 0 : && !CheckCRC16AtOffset(mFrame.Offset(),
464 : mNextFrame.Offset(),
465 : aResource)) {
466 : // The frame doesn't match its CRC or would be too far, skip it..
467 0 : continue;
468 : }
469 0 : CheckFrameData();
470 0 : break;
471 : }
472 0 : return mNextFrame.IsValid();
473 : }
474 :
475 0 : bool CheckFrameData()
476 : {
477 0 : if (mNextFrame.Header().Info().mRate == 0
478 0 : || mNextFrame.Header().Info().mBitDepth == 0) {
479 0 : if (!Info().IsValid()) {
480 : // We can only use the STREAMINFO data if we have one.
481 0 : mNextFrame.SetInvalid();
482 : } else {
483 0 : if (mNextFrame.Header().Info().mRate == 0) {
484 0 : mNextFrame.SetRate(Info().mRate);
485 : }
486 0 : if (mNextFrame.Header().Info().mBitDepth == 0) {
487 0 : mNextFrame.SetBitDepth(Info().mBitDepth);
488 : }
489 : }
490 : }
491 0 : return mNextFrame.IsValid();
492 : }
493 :
494 0 : bool CheckCRC16AtOffset(int64_t aStart, int64_t aEnd,
495 : MediaResourceIndex& aResource) const
496 : {
497 0 : int64_t size = aEnd - aStart;
498 0 : if (size <= 0) {
499 0 : return false;
500 : }
501 0 : UniquePtr<char[]> buffer(new char[size]);
502 0 : uint32_t read = 0;
503 0 : if (NS_FAILED(aResource.ReadAt(aStart, buffer.get(),
504 : size, &read))
505 0 : || read != size) {
506 0 : NS_WARNING("Couldn't read frame content");
507 0 : return false;
508 : }
509 :
510 0 : uint16_t crc = 0;
511 0 : uint8_t* buf = reinterpret_cast<uint8_t*>(buffer.get());
512 0 : const uint8_t *end = buf + size;
513 0 : while (buf < end) {
514 0 : crc = CRC16Table[((uint8_t)crc) ^ *buf++] ^ (crc >> 8);
515 : }
516 0 : return !crc;
517 : }
518 :
519 : const uint16_t CRC16Table[256] =
520 : {
521 : 0x0000, 0x0580, 0x0F80, 0x0A00, 0x1B80, 0x1E00, 0x1400, 0x1180,
522 : 0x3380, 0x3600, 0x3C00, 0x3980, 0x2800, 0x2D80, 0x2780, 0x2200,
523 : 0x6380, 0x6600, 0x6C00, 0x6980, 0x7800, 0x7D80, 0x7780, 0x7200,
524 : 0x5000, 0x5580, 0x5F80, 0x5A00, 0x4B80, 0x4E00, 0x4400, 0x4180,
525 : 0xC380, 0xC600, 0xCC00, 0xC980, 0xD800, 0xDD80, 0xD780, 0xD200,
526 : 0xF000, 0xF580, 0xFF80, 0xFA00, 0xEB80, 0xEE00, 0xE400, 0xE180,
527 : 0xA000, 0xA580, 0xAF80, 0xAA00, 0xBB80, 0xBE00, 0xB400, 0xB180,
528 : 0x9380, 0x9600, 0x9C00, 0x9980, 0x8800, 0x8D80, 0x8780, 0x8200,
529 : 0x8381, 0x8601, 0x8C01, 0x8981, 0x9801, 0x9D81, 0x9781, 0x9201,
530 : 0xB001, 0xB581, 0xBF81, 0xBA01, 0xAB81, 0xAE01, 0xA401, 0xA181,
531 : 0xE001, 0xE581, 0xEF81, 0xEA01, 0xFB81, 0xFE01, 0xF401, 0xF181,
532 : 0xD381, 0xD601, 0xDC01, 0xD981, 0xC801, 0xCD81, 0xC781, 0xC201,
533 : 0x4001, 0x4581, 0x4F81, 0x4A01, 0x5B81, 0x5E01, 0x5401, 0x5181,
534 : 0x7381, 0x7601, 0x7C01, 0x7981, 0x6801, 0x6D81, 0x6781, 0x6201,
535 : 0x2381, 0x2601, 0x2C01, 0x2981, 0x3801, 0x3D81, 0x3781, 0x3201,
536 : 0x1001, 0x1581, 0x1F81, 0x1A01, 0x0B81, 0x0E01, 0x0401, 0x0181,
537 : 0x0383, 0x0603, 0x0C03, 0x0983, 0x1803, 0x1D83, 0x1783, 0x1203,
538 : 0x3003, 0x3583, 0x3F83, 0x3A03, 0x2B83, 0x2E03, 0x2403, 0x2183,
539 : 0x6003, 0x6583, 0x6F83, 0x6A03, 0x7B83, 0x7E03, 0x7403, 0x7183,
540 : 0x5383, 0x5603, 0x5C03, 0x5983, 0x4803, 0x4D83, 0x4783, 0x4203,
541 : 0xC003, 0xC583, 0xCF83, 0xCA03, 0xDB83, 0xDE03, 0xD403, 0xD183,
542 : 0xF383, 0xF603, 0xFC03, 0xF983, 0xE803, 0xED83, 0xE783, 0xE203,
543 : 0xA383, 0xA603, 0xAC03, 0xA983, 0xB803, 0xBD83, 0xB783, 0xB203,
544 : 0x9003, 0x9583, 0x9F83, 0x9A03, 0x8B83, 0x8E03, 0x8403, 0x8183,
545 : 0x8002, 0x8582, 0x8F82, 0x8A02, 0x9B82, 0x9E02, 0x9402, 0x9182,
546 : 0xB382, 0xB602, 0xBC02, 0xB982, 0xA802, 0xAD82, 0xA782, 0xA202,
547 : 0xE382, 0xE602, 0xEC02, 0xE982, 0xF802, 0xFD82, 0xF782, 0xF202,
548 : 0xD002, 0xD582, 0xDF82, 0xDA02, 0xCB82, 0xCE02, 0xC402, 0xC182,
549 : 0x4382, 0x4602, 0x4C02, 0x4982, 0x5802, 0x5D82, 0x5782, 0x5202,
550 : 0x7002, 0x7582, 0x7F82, 0x7A02, 0x6B82, 0x6E02, 0x6402, 0x6182,
551 : 0x2002, 0x2582, 0x2F82, 0x2A02, 0x3B82, 0x3E02, 0x3402, 0x3182,
552 : 0x1382, 0x1602, 0x1C02, 0x1982, 0x0802, 0x0D82, 0x0782, 0x0202,
553 : };
554 :
555 : FlacFrameParser mParser;
556 : // We keep the first parsed frame around for static info access
557 : // and the currently parsed frame.
558 : Frame mFirstFrame;
559 : Frame mNextFrame;
560 : Frame mFrame;
561 : };
562 :
563 : } // namespace flac
564 :
565 : // FlacDemuxer
566 :
567 0 : FlacDemuxer::FlacDemuxer(MediaResource* aSource) : mSource(aSource) { }
568 :
569 : bool
570 0 : FlacDemuxer::InitInternal()
571 : {
572 0 : if (!mTrackDemuxer) {
573 0 : mTrackDemuxer = new FlacTrackDemuxer(mSource);
574 : }
575 0 : return mTrackDemuxer->Init();
576 : }
577 :
578 : RefPtr<FlacDemuxer::InitPromise>
579 0 : FlacDemuxer::Init()
580 : {
581 0 : if (!InitInternal()) {
582 0 : LOG("Init() failure: waiting for data");
583 :
584 : return InitPromise::CreateAndReject(
585 0 : NS_ERROR_DOM_MEDIA_DEMUXER_ERR, __func__);
586 : }
587 :
588 0 : LOG("Init() successful");
589 0 : return InitPromise::CreateAndResolve(NS_OK, __func__);
590 : }
591 :
592 : bool
593 0 : FlacDemuxer::HasTrackType(TrackInfo::TrackType aType) const
594 : {
595 0 : return aType == TrackInfo::kAudioTrack;
596 : }
597 :
598 : uint32_t
599 0 : FlacDemuxer::GetNumberTracks(TrackInfo::TrackType aType) const
600 : {
601 0 : return (aType == TrackInfo::kAudioTrack) ? 1 : 0;
602 : }
603 :
604 : already_AddRefed<MediaTrackDemuxer>
605 0 : FlacDemuxer::GetTrackDemuxer(TrackInfo::TrackType aType, uint32_t aTrackNumber)
606 : {
607 0 : if (!mTrackDemuxer) {
608 0 : return nullptr;
609 : }
610 :
611 0 : return RefPtr<FlacTrackDemuxer>(mTrackDemuxer).forget();
612 : }
613 :
614 : bool
615 0 : FlacDemuxer::IsSeekable() const
616 : {
617 0 : return mTrackDemuxer && mTrackDemuxer->IsSeekable();
618 : }
619 :
620 : // FlacTrackDemuxer
621 0 : FlacTrackDemuxer::FlacTrackDemuxer(MediaResource* aSource)
622 : : mSource(aSource)
623 0 : , mParser(new flac::FrameParser())
624 0 : , mTotalFrameLen(0)
625 : {
626 0 : Reset();
627 0 : }
628 :
629 0 : FlacTrackDemuxer::~FlacTrackDemuxer()
630 : {
631 0 : }
632 :
633 : bool
634 0 : FlacTrackDemuxer::Init()
635 : {
636 : static const int BUFFER_SIZE = 4096;
637 :
638 : // First check if we have a valid Flac start.
639 : char buffer[BUFFER_SIZE];
640 : const uint8_t* ubuffer = // only needed due to type constraints of ReadAt.
641 0 : reinterpret_cast<uint8_t*>(buffer);
642 0 : int64_t offset = 0;
643 :
644 0 : do {
645 0 : uint32_t read = 0;
646 0 : nsresult ret = mSource.ReadAt(offset, buffer, BUFFER_SIZE, &read);
647 0 : if (NS_FAILED(ret) || read < BUFFER_SIZE) {
648 : // Assume that if we can't read that many bytes while parsing the header,
649 : // that something is wrong.
650 0 : return false;
651 : }
652 0 : if (!mParser->IsHeaderBlock(ubuffer, BUFFER_SIZE)) {
653 : // Not a header and we haven't reached the end of the metadata blocks.
654 : // Will fall back to using the frames header instead.
655 0 : break;
656 : }
657 0 : uint32_t sizeHeader = mParser->HeaderBlockLength(ubuffer);
658 : RefPtr<MediaByteBuffer> block =
659 0 : mSource.MediaReadAt(offset, sizeHeader);
660 0 : if (!block || block->Length() != sizeHeader) {
661 0 : break;
662 : }
663 0 : if (!mParser->DecodeHeaderBlock(block->Elements(), sizeHeader)) {
664 0 : break;
665 : }
666 0 : offset += sizeHeader;
667 0 : } while (!mParser->HasFullMetadata());
668 :
669 : // First flac frame is found after the metadata.
670 : // Can seek there immediately to avoid reparsing it all.
671 0 : mSource.Seek(SEEK_SET, offset);
672 :
673 : // Find the first frame to fully initialise our parser.
674 0 : if (mParser->FindNextFrame(mSource)) {
675 : // Ensure that the next frame returned will be the first.
676 0 : mSource.Seek(SEEK_SET, mParser->FirstFrame().Offset());
677 0 : mParser->EndFrameSession();
678 0 : } else if (!mParser->Info().IsValid() || !mParser->FirstFrame().IsValid()) {
679 : // We must find at least a frame to determine the metadata.
680 : // We can't play this stream.
681 0 : return false;
682 : }
683 :
684 0 : if (!mParser->Info().IsValid() || !mParser->Info().mDuration.IsPositive()) {
685 : // Check if we can look at the last frame for the end time to determine the
686 : // duration when we don't have any.
687 0 : TimeAtEnd();
688 : }
689 :
690 0 : return true;
691 : }
692 :
693 : UniquePtr<TrackInfo>
694 0 : FlacTrackDemuxer::GetInfo() const
695 : {
696 0 : if (mParser->Info().IsValid()) {
697 : // We have a proper metadata header.
698 0 : UniquePtr<TrackInfo> info = mParser->Info().Clone();
699 0 : nsAutoPtr<MetadataTags> tags(mParser->GetTags());
700 0 : if (tags) {
701 0 : for (auto iter = tags->Iter(); !iter.Done(); iter.Next()) {
702 0 : info->mTags.AppendElement(MetadataTag(iter.Key(), iter.Data()));
703 : }
704 : }
705 0 : return info;
706 0 : } else if (mParser->FirstFrame().Info().IsValid()) {
707 : // Use the first frame header.
708 0 : UniquePtr<TrackInfo> info = mParser->FirstFrame().Info().Clone();
709 0 : info->mDuration = Duration();
710 0 : return info;
711 : }
712 0 : return nullptr;
713 : }
714 :
715 : bool
716 0 : FlacTrackDemuxer::IsSeekable() const
717 : {
718 : // For now we only allow seeking if a STREAMINFO block was found and with
719 : // a known number of samples (duration is set).
720 0 : return mParser->Info().IsValid() && mParser->Info().mDuration.IsPositive();
721 : }
722 :
723 : RefPtr<FlacTrackDemuxer::SeekPromise>
724 0 : FlacTrackDemuxer::Seek(const TimeUnit& aTime)
725 : {
726 : // Efficiently seek to the position.
727 0 : FastSeek(aTime);
728 : // Correct seek position by scanning the next frames.
729 0 : const TimeUnit seekTime = ScanUntil(aTime);
730 :
731 0 : return SeekPromise::CreateAndResolve(seekTime, __func__);
732 : }
733 :
734 : TimeUnit
735 0 : FlacTrackDemuxer::FastSeek(const TimeUnit& aTime)
736 : {
737 0 : LOG("FastSeek(%f) avgFrameLen=%f mParsedFramesDuration=%f offset=%" PRId64,
738 : aTime.ToSeconds(), AverageFrameLength(),
739 : mParsedFramesDuration.ToSeconds(), GetResourceOffset());
740 :
741 : // Invalidate current frames in the parser.
742 0 : mParser->EndFrameSession();
743 :
744 0 : if (!mParser->FirstFrame().IsValid()) {
745 : // Something wrong, and there's nothing to seek to anyway, so we can
746 : // do whatever here.
747 0 : mSource.Seek(SEEK_SET, 0);
748 0 : return TimeUnit();
749 : }
750 :
751 0 : if (aTime <= mParser->FirstFrame().Time()) {
752 : // We're attempting to seek prior the first frame, return the first frame.
753 0 : mSource.Seek(SEEK_SET, mParser->FirstFrame().Offset());
754 0 : return mParser->FirstFrame().Time();
755 : }
756 :
757 : // We look for the seek position using a bisection search, starting where the
758 : // estimated position might be using the average frame length.
759 : // Typically, with flac such approximation is typically useless.
760 :
761 : // Estimate where the position might be.
762 : int64_t pivot =
763 0 : aTime.ToSeconds() * AverageFrameLength() + mParser->FirstFrame().Offset();
764 :
765 : // Time in seconds where we can stop seeking and will continue using
766 : // ScanUntil.
767 : static const int GAP_THRESHOLD = 5;
768 0 : int64_t first = mParser->FirstFrame().Offset();
769 0 : int64_t last = mSource.GetLength();
770 0 : Maybe<int64_t> lastFoundOffset;
771 0 : uint32_t iterations = 0;
772 0 : TimeUnit timeSeekedTo;
773 :
774 : do {
775 0 : iterations++;
776 0 : mSource.Seek(SEEK_SET, pivot);
777 0 : flac::Frame frame;
778 0 : if (!frame.FindNext(mSource)) {
779 0 : NS_WARNING("We should have found a point");
780 0 : break;
781 : }
782 0 : timeSeekedTo = frame.Time();
783 :
784 0 : LOGV("FastSeek: interation:%u found:%f @ %" PRId64,
785 : iterations, timeSeekedTo.ToSeconds(), frame.Offset());
786 :
787 0 : if (lastFoundOffset && lastFoundOffset.ref() == frame.Offset()) {
788 : // Same frame found twice. We're done.
789 0 : break;
790 : }
791 0 : lastFoundOffset = Some(frame.Offset());
792 :
793 0 : if (frame.Time() == aTime) {
794 0 : break;
795 : }
796 0 : if (aTime > frame.Time()
797 0 : && aTime - frame.Time() <= TimeUnit::FromSeconds(GAP_THRESHOLD)) {
798 : // We're close enough to the target, experimentation shows that bisection
799 : // search doesn't help much after that.
800 0 : break;
801 : }
802 0 : if (frame.Time() > aTime) {
803 0 : last = pivot;
804 0 : pivot -= (pivot - first) / 2;
805 : } else {
806 0 : first = pivot;
807 0 : pivot += (last - pivot) / 2;
808 0 : }
809 : } while (true);
810 :
811 0 : if (lastFoundOffset) {
812 0 : mSource.Seek(SEEK_SET, lastFoundOffset.ref());
813 : }
814 :
815 0 : return timeSeekedTo;
816 : }
817 :
818 : TimeUnit
819 0 : FlacTrackDemuxer::ScanUntil(const TimeUnit& aTime)
820 : {
821 0 : LOG("ScanUntil(%f avgFrameLen=%f mParsedFramesDuration=%f offset=%" PRId64,
822 : aTime.ToSeconds(), AverageFrameLength(),
823 : mParsedFramesDuration.ToSeconds(), mParser->CurrentFrame().Offset());
824 :
825 0 : if (!mParser->FirstFrame().IsValid()
826 0 : || aTime <= mParser->FirstFrame().Time()) {
827 0 : return FastSeek(aTime);
828 : }
829 :
830 0 : int64_t previousOffset = 0;
831 0 : TimeUnit previousTime;
832 0 : while (FindNextFrame().IsValid() && mParser->CurrentFrame().Time() < aTime) {
833 0 : previousOffset = mParser->CurrentFrame().Offset();
834 0 : previousTime = mParser->CurrentFrame().Time();
835 : }
836 :
837 0 : if (!mParser->CurrentFrame().IsValid()) {
838 : // We reached EOS.
839 0 : return Duration();
840 : }
841 :
842 : // Seek back to the last frame found prior the target.
843 0 : mParser->EndFrameSession();
844 0 : mSource.Seek(SEEK_SET, previousOffset);
845 0 : return previousTime;
846 : }
847 :
848 : RefPtr<FlacTrackDemuxer::SamplesPromise>
849 0 : FlacTrackDemuxer::GetSamples(int32_t aNumSamples)
850 : {
851 0 : LOGV("GetSamples(%d) Begin offset=%" PRId64 " mParsedFramesDuration=%f"
852 : " mTotalFrameLen=%" PRIu64,
853 : aNumSamples, GetResourceOffset(), mParsedFramesDuration.ToSeconds(),
854 : mTotalFrameLen);
855 :
856 0 : if (!aNumSamples) {
857 : return SamplesPromise::CreateAndReject(
858 0 : NS_ERROR_DOM_MEDIA_DEMUXER_ERR, __func__);
859 : }
860 :
861 0 : RefPtr<SamplesHolder> frames = new SamplesHolder();
862 :
863 0 : while (aNumSamples--) {
864 0 : RefPtr<MediaRawData> frame(GetNextFrame(FindNextFrame()));
865 0 : if (!frame)
866 0 : break;
867 :
868 0 : frames->mSamples.AppendElement(frame);
869 : }
870 :
871 0 : LOGV("GetSamples() End mSamples.Length=%" PRIuSIZE " aNumSamples=%d offset=%" PRId64
872 : " mParsedFramesDuration=%f mTotalFrameLen=%" PRIu64,
873 : frames->mSamples.Length(), aNumSamples, GetResourceOffset(),
874 : mParsedFramesDuration.ToSeconds(), mTotalFrameLen);
875 :
876 0 : if (frames->mSamples.IsEmpty()) {
877 : return SamplesPromise::CreateAndReject(
878 0 : NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
879 : }
880 :
881 0 : return SamplesPromise::CreateAndResolve(frames, __func__);
882 : }
883 :
884 : void
885 0 : FlacTrackDemuxer::Reset()
886 : {
887 0 : LOG("Reset()");
888 0 : MOZ_ASSERT(mParser);
889 0 : if (mParser->FirstFrame().IsValid()) {
890 0 : mSource.Seek(SEEK_SET, mParser->FirstFrame().Offset());
891 : } else {
892 0 : mSource.Seek(SEEK_SET, 0);
893 : }
894 0 : mParser->EndFrameSession();
895 0 : }
896 :
897 : RefPtr<FlacTrackDemuxer::SkipAccessPointPromise>
898 0 : FlacTrackDemuxer::SkipToNextRandomAccessPoint(const TimeUnit& aTimeThreshold)
899 : {
900 : // Will not be called for audio-only resources.
901 : return SkipAccessPointPromise::CreateAndReject(
902 0 : SkipFailureHolder(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, 0), __func__);
903 : }
904 :
905 : int64_t
906 0 : FlacTrackDemuxer::GetResourceOffset() const
907 : {
908 0 : return mSource.Tell();
909 : }
910 :
911 : TimeIntervals
912 0 : FlacTrackDemuxer::GetBuffered()
913 : {
914 0 : TimeUnit duration = Duration();
915 :
916 0 : if (duration <= TimeUnit()) {
917 0 : return TimeIntervals();
918 : }
919 :
920 : // We could simply parse the cached data instead and read the timestamps.
921 : // However, for now this will do.
922 0 : AutoPinned<MediaResource> stream(mSource.GetResource());
923 0 : return GetEstimatedBufferedTimeRanges(stream, duration.ToMicroseconds());
924 : }
925 :
926 : const flac::Frame&
927 0 : FlacTrackDemuxer::FindNextFrame()
928 : {
929 0 : LOGV("FindNext() Begin offset=%" PRId64 " mParsedFramesDuration=%f"
930 : " mTotalFrameLen=%" PRIu64,
931 : GetResourceOffset(), mParsedFramesDuration.ToSeconds(), mTotalFrameLen);
932 :
933 0 : if (mParser->FindNextFrame(mSource)) {
934 : // Update our current progress stats.
935 0 : mParsedFramesDuration =
936 : std::max(mParsedFramesDuration,
937 0 : mParser->CurrentFrame().Time() - mParser->FirstFrame().Time()
938 0 : + mParser->CurrentFrame().Duration());
939 0 : mTotalFrameLen =
940 0 : std::max<uint64_t>(mTotalFrameLen,
941 0 : mParser->CurrentFrame().Offset()
942 0 : - mParser->FirstFrame().Offset()
943 0 : + mParser->CurrentFrame().Size());
944 :
945 0 : LOGV("FindNext() End time=%f offset=%" PRId64 " mParsedFramesDuration=%f"
946 : " mTotalFrameLen=%" PRIu64,
947 : mParser->CurrentFrame().Time().ToSeconds(), GetResourceOffset(),
948 : mParsedFramesDuration.ToSeconds(), mTotalFrameLen);
949 : }
950 :
951 0 : return mParser->CurrentFrame();
952 : }
953 :
954 : already_AddRefed<MediaRawData>
955 0 : FlacTrackDemuxer::GetNextFrame(const flac::Frame& aFrame)
956 : {
957 0 : if (!aFrame.IsValid()) {
958 0 : LOG("GetNextFrame() EOS");
959 0 : return nullptr;
960 : }
961 :
962 0 : LOG("GetNextFrame() Begin(time=%f offset=%" PRId64 " size=%u)",
963 : aFrame.Time().ToSeconds(), aFrame.Offset(), aFrame.Size());
964 :
965 0 : const int64_t offset = aFrame.Offset();
966 0 : const uint32_t size = aFrame.Size();
967 :
968 0 : RefPtr<MediaRawData> frame = new MediaRawData();
969 0 : frame->mOffset = offset;
970 :
971 0 : nsAutoPtr<MediaRawDataWriter> frameWriter(frame->CreateWriter());
972 0 : if (!frameWriter->SetSize(size)) {
973 0 : LOG("GetNext() Exit failed to allocated media buffer");
974 0 : return nullptr;
975 : }
976 :
977 0 : const uint32_t read = Read(frameWriter->Data(), offset, size);
978 0 : if (read != size) {
979 0 : LOG("GetNextFrame() Exit read=%u frame->Size=%" PRIuSIZE, read, frame->Size());
980 0 : return nullptr;
981 : }
982 :
983 0 : frame->mTime = aFrame.Time();
984 0 : frame->mDuration = aFrame.Duration();
985 0 : frame->mTimecode = frame->mTime;
986 0 : frame->mOffset = aFrame.Offset();
987 0 : frame->mKeyframe = true;
988 :
989 0 : MOZ_ASSERT(!frame->mTime.IsNegative());
990 0 : MOZ_ASSERT(!frame->mDuration.IsNegative());
991 :
992 0 : return frame.forget();
993 : }
994 :
995 : int32_t
996 0 : FlacTrackDemuxer::Read(uint8_t* aBuffer, int64_t aOffset, int32_t aSize)
997 : {
998 0 : uint32_t read = 0;
999 0 : const nsresult rv = mSource.ReadAt(aOffset, reinterpret_cast<char*>(aBuffer),
1000 0 : static_cast<uint32_t>(aSize), &read);
1001 0 : NS_ENSURE_SUCCESS(rv, 0);
1002 0 : return static_cast<int32_t>(read);
1003 : }
1004 :
1005 : double
1006 0 : FlacTrackDemuxer::AverageFrameLength() const
1007 : {
1008 0 : if (mParsedFramesDuration.ToMicroseconds()) {
1009 0 : return mTotalFrameLen / mParsedFramesDuration.ToSeconds();
1010 : }
1011 :
1012 0 : return 0.0;
1013 : }
1014 :
1015 : TimeUnit
1016 0 : FlacTrackDemuxer::Duration() const
1017 : {
1018 0 : return std::max(mParsedFramesDuration, mParser->Info().mDuration);
1019 : }
1020 :
1021 : TimeUnit
1022 0 : FlacTrackDemuxer::TimeAtEnd()
1023 : {
1024 : // Scan the last 128kB if available to determine the last frame.
1025 : static const int OFFSET_FROM_END = 128 * 1024;
1026 :
1027 : // Seek to the end of the file and attempt to find the last frame.
1028 0 : MediaResourceIndex source(mSource.GetResource());
1029 0 : TimeUnit previousDuration;
1030 0 : TimeUnit previousTime;
1031 :
1032 0 : const int64_t streamLen = mSource.GetLength();
1033 0 : if (streamLen < 0) {
1034 0 : return TimeUnit::FromInfinity();
1035 : }
1036 :
1037 0 : flac::FrameParser parser;
1038 :
1039 0 : source.Seek(SEEK_SET, std::max<int64_t>(0LL, streamLen - OFFSET_FROM_END));
1040 0 : while (parser.FindNextFrame(source)) {
1041 : // FFmpeg flac muxer can generate a last frame with earlier than the others.
1042 0 : previousTime = std::max(previousTime, parser.CurrentFrame().Time());
1043 0 : if (parser.CurrentFrame().Duration() > TimeUnit()) {
1044 : // The last frame doesn't have a duration, so only update our duration
1045 : // if we do have one.
1046 0 : previousDuration = parser.CurrentFrame().Duration();
1047 : }
1048 0 : if (source.Tell() >= streamLen) {
1049 : // Limit the read, in case the length change half-way.
1050 0 : break;
1051 : }
1052 : }
1053 :
1054 : // Update our current progress stats.
1055 : mParsedFramesDuration =
1056 0 : previousTime + previousDuration - mParser->FirstFrame().Time();
1057 0 : mTotalFrameLen = streamLen - mParser->FirstFrame().Offset();
1058 :
1059 0 : return mParsedFramesDuration;
1060 : }
1061 :
1062 : /* static */ bool
1063 0 : FlacDemuxer::FlacSniffer(const uint8_t* aData, const uint32_t aLength)
1064 : {
1065 0 : if (aLength < FLAC_MAX_FRAME_HEADER_SIZE) {
1066 0 : return false;
1067 : }
1068 :
1069 0 : flac::Frame frame;
1070 0 : return frame.FindNext(aData, aLength - FLAC_MAX_FRAME_HEADER_SIZE) >= 0;
1071 : }
1072 :
1073 : } // namespace mozilla
|