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