tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ADTSDemuxer.cpp (19834B)


      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 "ADTSDemuxer.h"
      8 
      9 #include <inttypes.h>
     10 
     11 #include "Adts.h"
     12 #include "TimeUnits.h"
     13 #include "VideoUtils.h"
     14 #include "mozilla/Logging.h"
     15 #include "mozilla/UniquePtr.h"
     16 
     17 #define LOG(msg, ...) \
     18  MOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, msg, ##__VA_ARGS__)
     19 #define ADTSLOG(msg, ...) \
     20  DDMOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, msg, ##__VA_ARGS__)
     21 #define ADTSLOGV(msg, ...) \
     22  DDMOZ_LOG(gMediaDemuxerLog, LogLevel::Verbose, msg, ##__VA_ARGS__)
     23 
     24 namespace mozilla {
     25 
     26 using media::TimeUnit;
     27 
     28 // ADTSDemuxer
     29 
     30 ADTSDemuxer::ADTSDemuxer(MediaResource* aSource) : mSource(aSource) {
     31  DDLINKCHILD("source", aSource);
     32 }
     33 
     34 bool ADTSDemuxer::InitInternal() {
     35  if (!mTrackDemuxer) {
     36    mTrackDemuxer = new ADTSTrackDemuxer(mSource);
     37    DDLINKCHILD("track demuxer", mTrackDemuxer.get());
     38  }
     39  return mTrackDemuxer->Init();
     40 }
     41 
     42 RefPtr<ADTSDemuxer::InitPromise> ADTSDemuxer::Init() {
     43  if (!InitInternal()) {
     44    ADTSLOG("Init() failure: waiting for data");
     45 
     46    return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_METADATA_ERR,
     47                                        __func__);
     48  }
     49 
     50  ADTSLOG("Init() successful");
     51  return InitPromise::CreateAndResolve(NS_OK, __func__);
     52 }
     53 
     54 uint32_t ADTSDemuxer::GetNumberTracks(TrackInfo::TrackType aType) const {
     55  return (aType == TrackInfo::kAudioTrack) ? 1 : 0;
     56 }
     57 
     58 already_AddRefed<MediaTrackDemuxer> ADTSDemuxer::GetTrackDemuxer(
     59    TrackInfo::TrackType aType, uint32_t aTrackNumber) {
     60  if (!mTrackDemuxer) {
     61    return nullptr;
     62  }
     63 
     64  return RefPtr<ADTSTrackDemuxer>(mTrackDemuxer).forget();
     65 }
     66 
     67 bool ADTSDemuxer::IsSeekable() const {
     68  int64_t length = mSource->GetLength();
     69  return length > -1;
     70 }
     71 
     72 // ADTSTrackDemuxer
     73 ADTSTrackDemuxer::ADTSTrackDemuxer(MediaResource* aSource)
     74    : mSource(aSource),
     75      mParser(new ADTS::FrameParser()),
     76      mOffset(0),
     77      mNumParsedFrames(0),
     78      mFrameIndex(0),
     79      mTotalFrameLen(0),
     80      mSamplesPerFrame(0),
     81      mSamplesPerSecond(0),
     82      mChannels(0) {
     83  DDLINKCHILD("source", aSource);
     84  Reset();
     85 }
     86 
     87 ADTSTrackDemuxer::~ADTSTrackDemuxer() { delete mParser; }
     88 
     89 bool ADTSTrackDemuxer::Init() {
     90  FastSeek(TimeUnit::Zero());
     91  // Read the first frame to fetch sample rate and other meta data.
     92  RefPtr<MediaRawData> frame(GetNextFrame(FindNextFrame(true)));
     93 
     94  ADTSLOG("Init StreamLength()=%" PRId64 " first-frame-found=%d",
     95          StreamLength(), !!frame);
     96 
     97  if (!frame) {
     98    return false;
     99  }
    100 
    101  // Rewind back to the stream begin to avoid dropping the first frame.
    102  FastSeek(TimeUnit::Zero());
    103 
    104  if (!mSamplesPerSecond) {
    105    return false;
    106  }
    107 
    108  if (!mInfo) {
    109    mInfo = MakeUnique<AudioInfo>();
    110  }
    111 
    112  mInfo->mRate = mSamplesPerSecond;
    113  mInfo->mChannels = mChannels;
    114  mInfo->mBitDepth = 16;
    115  mInfo->mDuration = Duration();
    116 
    117  // AAC Specific information
    118  mInfo->mMimeType = "audio/mp4a-latm";
    119 
    120  // Configure AAC codec-specific values.
    121  // For AAC, mProfile and mExtendedProfile contain the audioObjectType from
    122  // Table 1.3 -- Audio Profile definition, ISO/IEC 14496-3. Eg. 2 == AAC LC
    123  mInfo->mProfile = mInfo->mExtendedProfile =
    124      mParser->FirstFrame().Header().mObjectType;
    125  AudioCodecSpecificBinaryBlob blob;
    126  InitAudioSpecificConfig(mParser->FirstFrame(), blob.mBinaryBlob);
    127  mInfo->mCodecSpecificConfig = AudioCodecSpecificVariant{std::move(blob)};
    128 
    129  ADTSLOG("Init mInfo={mRate=%u mChannels=%u mBitDepth=%u mDuration=%" PRId64
    130          "}",
    131          mInfo->mRate, mInfo->mChannels, mInfo->mBitDepth,
    132          mInfo->mDuration.ToMicroseconds());
    133 
    134  // AAC encoder delay can be 2112 (typical value when using Apple AAC encoder),
    135  // or 1024 (typical value when encoding using fdk_aac, often via ffmpeg).
    136  // See
    137  // https://developer.apple.com/library/content/documentation/QuickTime/QTFF/QTFFAppenG/QTFFAppenG.html
    138  // In an attempt to not trim valid audio data, and because ADTS doesn't
    139  // provide a way to know this pre-roll value, this offets by 1024 frames.
    140  mPreRoll = TimeUnit(1024, mSamplesPerSecond);
    141  return mChannels;
    142 }
    143 
    144 UniquePtr<TrackInfo> ADTSTrackDemuxer::GetInfo() const {
    145  return mInfo->Clone();
    146 }
    147 
    148 RefPtr<ADTSTrackDemuxer::SeekPromise> ADTSTrackDemuxer::Seek(
    149    const TimeUnit& aTime) {
    150  // Efficiently seek to the position.
    151  const TimeUnit time = aTime > mPreRoll ? aTime - mPreRoll : TimeUnit::Zero();
    152  FastSeek(time);
    153  // Correct seek position by scanning the next frames.
    154  const TimeUnit seekTime = ScanUntil(time);
    155 
    156  return SeekPromise::CreateAndResolve(seekTime, __func__);
    157 }
    158 
    159 TimeUnit ADTSTrackDemuxer::FastSeek(const TimeUnit& aTime) {
    160  ADTSLOG("FastSeek(%" PRId64 ") avgFrameLen=%f mNumParsedFrames=%" PRIu64
    161          " mFrameIndex=%" PRId64 " mOffset=%" PRIu64,
    162          aTime.ToMicroseconds(), AverageFrameLength(), mNumParsedFrames,
    163          mFrameIndex, mOffset);
    164 
    165  const uint64_t firstFrameOffset = mParser->FirstFrame().Offset();
    166  if (!aTime.ToMicroseconds()) {
    167    // Quick seek to the beginning of the stream.
    168    mOffset = firstFrameOffset;
    169  } else if (AverageFrameLength() > 0) {
    170    mOffset =
    171        firstFrameOffset +
    172        AssertedCast<uint64_t>(AssertedCast<double>(FrameIndexFromTime(aTime)) *
    173                               AverageFrameLength());
    174  }
    175 
    176  const int64_t streamLength = StreamLength();
    177  if (mOffset > firstFrameOffset && streamLength > 0) {
    178    mOffset = std::min(static_cast<uint64_t>(streamLength - 1), mOffset);
    179  }
    180 
    181  mFrameIndex = FrameIndexFromOffset(mOffset);
    182  mParser->EndFrameSession();
    183 
    184  ADTSLOG("FastSeek End avgFrameLen=%f mNumParsedFrames=%" PRIu64
    185          " mFrameIndex=%" PRId64 " mFirstFrameOffset=%" PRIu64
    186          " mOffset=%" PRIu64 " SL=%" PRIu64 "",
    187          AverageFrameLength(), mNumParsedFrames, mFrameIndex, firstFrameOffset,
    188          mOffset, streamLength);
    189 
    190  return Duration(mFrameIndex);
    191 }
    192 
    193 TimeUnit ADTSTrackDemuxer::ScanUntil(const TimeUnit& aTime) {
    194  ADTSLOG("ScanUntil(%" PRId64 ") avgFrameLen=%f mNumParsedFrames=%" PRIu64
    195          " mFrameIndex=%" PRId64 " mOffset=%" PRIu64,
    196          aTime.ToMicroseconds(), AverageFrameLength(), mNumParsedFrames,
    197          mFrameIndex, mOffset);
    198 
    199  if (!aTime.ToMicroseconds()) {
    200    return FastSeek(aTime);
    201  }
    202 
    203  if (Duration(mFrameIndex) > aTime) {
    204    FastSeek(aTime);
    205  }
    206 
    207  while (SkipNextFrame(FindNextFrame()) && Duration(mFrameIndex + 1) < aTime) {
    208    ADTSLOGV("ScanUntil* avgFrameLen=%f mNumParsedFrames=%" PRIu64
    209             " mFrameIndex=%" PRId64 " mOffset=%" PRIu64 " Duration=%" PRId64,
    210             AverageFrameLength(), mNumParsedFrames, mFrameIndex, mOffset,
    211             Duration(mFrameIndex + 1).ToMicroseconds());
    212  }
    213 
    214  ADTSLOG("ScanUntil End avgFrameLen=%f mNumParsedFrames=%" PRIu64
    215          " mFrameIndex=%" PRId64 " mOffset=%" PRIu64,
    216          AverageFrameLength(), mNumParsedFrames, mFrameIndex, mOffset);
    217 
    218  return Duration(mFrameIndex);
    219 }
    220 
    221 RefPtr<ADTSTrackDemuxer::SamplesPromise> ADTSTrackDemuxer::GetSamples(
    222    int32_t aNumSamples) {
    223  ADTSLOGV("GetSamples(%d) Begin mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
    224           " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
    225           " mSamplesPerFrame=%d "
    226           "mSamplesPerSecond=%d mChannels=%d",
    227           aNumSamples, mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
    228           mSamplesPerFrame, mSamplesPerSecond, mChannels);
    229 
    230  MOZ_ASSERT(aNumSamples);
    231 
    232  RefPtr<SamplesHolder> frames = new SamplesHolder();
    233 
    234  while (aNumSamples--) {
    235    RefPtr<MediaRawData> frame(GetNextFrame(FindNextFrame()));
    236    if (!frame) break;
    237    frames->AppendSample(std::move(frame));
    238  }
    239 
    240  ADTSLOGV(
    241      "GetSamples() End mSamples.Size()=%zu aNumSamples=%d mOffset=%" PRIu64
    242      " mNumParsedFrames=%" PRIu64 " mFrameIndex=%" PRId64
    243      " mTotalFrameLen=%" PRIu64
    244      " mSamplesPerFrame=%d mSamplesPerSecond=%d "
    245      "mChannels=%d",
    246      frames->GetSamples().Length(), aNumSamples, mOffset, mNumParsedFrames,
    247      mFrameIndex, mTotalFrameLen, mSamplesPerFrame, mSamplesPerSecond,
    248      mChannels);
    249 
    250  if (frames->GetSamples().IsEmpty()) {
    251    return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM,
    252                                           __func__);
    253  }
    254 
    255  return SamplesPromise::CreateAndResolve(frames, __func__);
    256 }
    257 
    258 void ADTSTrackDemuxer::Reset() {
    259  ADTSLOG("Reset()");
    260  MOZ_ASSERT(mParser);
    261  if (mParser) {
    262    mParser->Reset();
    263  }
    264  FastSeek(TimeUnit::Zero());
    265 }
    266 
    267 RefPtr<ADTSTrackDemuxer::SkipAccessPointPromise>
    268 ADTSTrackDemuxer::SkipToNextRandomAccessPoint(const TimeUnit& aTimeThreshold) {
    269  // Will not be called for audio-only resources.
    270  return SkipAccessPointPromise::CreateAndReject(
    271      SkipFailureHolder(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, 0), __func__);
    272 }
    273 
    274 int64_t ADTSTrackDemuxer::GetResourceOffset() const {
    275  return AssertedCast<int64_t>(mOffset);
    276 }
    277 
    278 media::TimeIntervals ADTSTrackDemuxer::GetBuffered() {
    279  auto duration = Duration();
    280 
    281  if (duration.IsInfinite()) {
    282    return media::TimeIntervals();
    283  }
    284 
    285  AutoPinned<MediaResource> stream(mSource.GetResource());
    286  return GetEstimatedBufferedTimeRanges(stream, duration.ToMicroseconds());
    287 }
    288 
    289 int64_t ADTSTrackDemuxer::StreamLength() const { return mSource.GetLength(); }
    290 
    291 TimeUnit ADTSTrackDemuxer::Duration() const {
    292  if (!mNumParsedFrames) {
    293    return TimeUnit::Invalid();
    294  }
    295 
    296  const int64_t streamLen = StreamLength();
    297  if (streamLen < 0) {
    298    // Unknown length, we can't estimate duration, this is probably a live
    299    // stream.
    300    return TimeUnit::FromInfinity();
    301  }
    302  const int64_t firstFrameOffset =
    303      AssertedCast<int64_t>(mParser->FirstFrame().Offset());
    304  int64_t numFrames =
    305      AssertedCast<int64_t>(AssertedCast<double>(streamLen - firstFrameOffset) /
    306                            AverageFrameLength());
    307  return Duration(numFrames);
    308 }
    309 
    310 TimeUnit ADTSTrackDemuxer::Duration(int64_t aNumFrames) const {
    311  if (!mSamplesPerSecond) {
    312    return TimeUnit::Invalid();
    313  }
    314 
    315  return TimeUnit(aNumFrames * mSamplesPerFrame, mSamplesPerSecond);
    316 }
    317 
    318 const ADTS::Frame& ADTSTrackDemuxer::FindNextFrame(
    319    bool findFirstFrame /*= false*/) {
    320  static const int BUFFER_SIZE = 4096;
    321  static const int MAX_SKIPPED_BYTES = 10 * BUFFER_SIZE;
    322 
    323  ADTSLOGV("FindNext() Begin mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
    324           " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
    325           " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
    326           mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
    327           mSamplesPerFrame, mSamplesPerSecond, mChannels);
    328 
    329  uint8_t buffer[BUFFER_SIZE];
    330  uint32_t read = 0;
    331 
    332  bool foundFrame = false;
    333  uint64_t frameHeaderOffset = mOffset;
    334 
    335  // Prepare the parser for the next frame parsing session.
    336  mParser->EndFrameSession();
    337 
    338  // Check whether we've found a valid ADTS frame.
    339  while (!foundFrame) {
    340    if ((read = Read(buffer, AssertedCast<int64_t>(frameHeaderOffset),
    341                     BUFFER_SIZE)) == 0) {
    342      ADTSLOG("FindNext() EOS without a frame");
    343      break;
    344    }
    345 
    346    if (frameHeaderOffset - mOffset > MAX_SKIPPED_BYTES) {
    347      ADTSLOG("FindNext() exceeded MAX_SKIPPED_BYTES without a frame");
    348      break;
    349    }
    350 
    351    const ADTS::Frame& currentFrame = mParser->CurrentFrame();
    352    foundFrame = mParser->Parse(frameHeaderOffset, buffer, buffer + read);
    353    if (findFirstFrame && foundFrame) {
    354      // Check for sync marker after the found frame, since it's
    355      // possible to find sync marker in AAC data. If sync marker
    356      // exists after the current frame then we've found a frame
    357      // header.
    358      uint64_t nextFrameHeaderOffset =
    359          currentFrame.Offset() + currentFrame.Length();
    360      uint32_t read =
    361          Read(buffer, AssertedCast<int64_t>(nextFrameHeaderOffset), 2);
    362      if (read != 2 || !ADTS::FrameHeader::MatchesSync(buffer)) {
    363        frameHeaderOffset = currentFrame.Offset() + 1;
    364        mParser->Reset();
    365        foundFrame = false;
    366        continue;
    367      }
    368    }
    369 
    370    if (foundFrame) {
    371      break;
    372    }
    373 
    374    // Minimum header size is 7 bytes.
    375    uint64_t advance = read - 7;
    376 
    377    // Check for offset overflow.
    378    if (frameHeaderOffset + advance <= frameHeaderOffset) {
    379      break;
    380    }
    381 
    382    frameHeaderOffset += advance;
    383  }
    384 
    385  if (!foundFrame || !mParser->CurrentFrame().Length()) {
    386    ADTSLOG(
    387        "FindNext() Exit foundFrame=%d mParser->CurrentFrame().Length()=%zu ",
    388        foundFrame, mParser->CurrentFrame().Length());
    389    mParser->Reset();
    390    return mParser->CurrentFrame();
    391  }
    392 
    393  ADTSLOGV("FindNext() End mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
    394           " mFrameIndex=%" PRId64 " frameHeaderOffset=%" PRId64
    395           " mTotalFrameLen=%" PRIu64
    396           " mSamplesPerFrame=%d mSamplesPerSecond=%d"
    397           " mChannels=%d",
    398           mOffset, mNumParsedFrames, mFrameIndex, frameHeaderOffset,
    399           mTotalFrameLen, mSamplesPerFrame, mSamplesPerSecond, mChannels);
    400 
    401  return mParser->CurrentFrame();
    402 }
    403 
    404 bool ADTSTrackDemuxer::SkipNextFrame(const ADTS::Frame& aFrame) {
    405  if (!mNumParsedFrames || !aFrame.Length()) {
    406    RefPtr<MediaRawData> frame(GetNextFrame(aFrame));
    407    return frame;
    408  }
    409 
    410  UpdateState(aFrame);
    411 
    412  ADTSLOGV("SkipNext() End mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
    413           " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
    414           " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
    415           mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
    416           mSamplesPerFrame, mSamplesPerSecond, mChannels);
    417 
    418  return true;
    419 }
    420 
    421 already_AddRefed<MediaRawData> ADTSTrackDemuxer::GetNextFrame(
    422    const ADTS::Frame& aFrame) {
    423  ADTSLOG("GetNext() Begin({mOffset=%" PRIu64 " HeaderSize()=%" PRIu64
    424          " Length()=%zu})",
    425          aFrame.Offset(), aFrame.Header().HeaderSize(),
    426          aFrame.PayloadLength());
    427  if (!aFrame.IsValid()) return nullptr;
    428 
    429  const int64_t offset = AssertedCast<int64_t>(aFrame.PayloadOffset());
    430  const uint32_t length = aFrame.PayloadLength();
    431 
    432  RefPtr<MediaRawData> frame = new MediaRawData();
    433  frame->mOffset = offset;
    434 
    435  UniquePtr<MediaRawDataWriter> frameWriter(frame->CreateWriter());
    436  if (!frameWriter->SetSize(length)) {
    437    ADTSLOG("GetNext() Exit failed to allocated media buffer");
    438    return nullptr;
    439  }
    440 
    441  const uint32_t read =
    442      Read(frameWriter->Data(), offset, AssertedCast<int32_t>(length));
    443  if (read != length) {
    444    ADTSLOG("GetNext() Exit read=%u frame->Size()=%zu", read, frame->Size());
    445    return nullptr;
    446  }
    447 
    448  UpdateState(aFrame);
    449 
    450  TimeUnit rawpts = Duration(mFrameIndex - 1) - mPreRoll;
    451  TimeUnit rawDuration = Duration(1);
    452  TimeUnit rawend = rawpts + rawDuration;
    453 
    454  frame->mTime = std::max(TimeUnit::Zero(), rawpts);
    455  frame->mDuration = Duration(1);
    456  frame->mTimecode = frame->mTime;
    457  frame->mKeyframe = true;
    458 
    459  // Handle decoder delay. A packet must be trimmed if its pts, adjusted for
    460  // decoder delay, is negative. A packet can be trimmed entirely.
    461  if (rawpts.IsNegative()) {
    462    frame->mDuration = std::max(TimeUnit::Zero(), rawend - frame->mTime);
    463  }
    464 
    465  // ADTS frames can have a presentation duration of zero, e.g. when a frame is
    466  // part of preroll.
    467  MOZ_ASSERT(frame->mDuration.IsPositiveOrZero());
    468 
    469  ADTSLOG("ADTS packet demuxed: pts [%lf, %lf] (duration: %lf)",
    470          frame->mTime.ToSeconds(), frame->GetEndTime().ToSeconds(),
    471          frame->mDuration.ToSeconds());
    472 
    473  // Indicate original packet information to trim after decoding.
    474  if (frame->mDuration != rawDuration) {
    475    frame->mOriginalPresentationWindow =
    476        Some(media::TimeInterval{rawpts, rawend});
    477    ADTSLOG("Total packet time excluding trimming: [%lf, %lf]",
    478            rawpts.ToSeconds(), rawend.ToSeconds());
    479  }
    480 
    481  ADTSLOGV("GetNext() End mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
    482           " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
    483           " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
    484           mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
    485           mSamplesPerFrame, mSamplesPerSecond, mChannels);
    486 
    487  return frame.forget();
    488 }
    489 
    490 int64_t ADTSTrackDemuxer::FrameIndexFromOffset(uint64_t aOffset) const {
    491  int64_t frameIndex = 0;
    492 
    493  if (AverageFrameLength() > 0) {
    494    frameIndex = AssertedCast<int64_t>(
    495        AssertedCast<double>(aOffset - mParser->FirstFrame().Offset()) /
    496        AverageFrameLength());
    497    MOZ_ASSERT(frameIndex >= 0);
    498  }
    499 
    500  ADTSLOGV("FrameIndexFromOffset(%" PRId64 ") -> %" PRId64, aOffset,
    501           frameIndex);
    502  return frameIndex;
    503 }
    504 
    505 int64_t ADTSTrackDemuxer::FrameIndexFromTime(const TimeUnit& aTime) const {
    506  int64_t frameIndex = 0;
    507  if (mSamplesPerSecond > 0 && mSamplesPerFrame > 0) {
    508    frameIndex = AssertedCast<int64_t>(aTime.ToSeconds() * mSamplesPerSecond /
    509                                       mSamplesPerFrame) -
    510                 1;
    511  }
    512 
    513  ADTSLOGV("FrameIndexFromOffset(%fs) -> %" PRId64, aTime.ToSeconds(),
    514           frameIndex);
    515  return std::max<int64_t>(0, frameIndex);
    516 }
    517 
    518 void ADTSTrackDemuxer::UpdateState(const ADTS::Frame& aFrame) {
    519  uint32_t frameLength = aFrame.Length();
    520  // Prevent overflow.
    521  if (mTotalFrameLen + frameLength < mTotalFrameLen) {
    522    // These variables have a linear dependency and are only used to derive the
    523    // average frame length.
    524    mTotalFrameLen /= 2;
    525    mNumParsedFrames /= 2;
    526  }
    527 
    528  // Full frame parsed, move offset to its end.
    529  mOffset = aFrame.Offset() + frameLength;
    530  mTotalFrameLen += frameLength;
    531 
    532  if (!mSamplesPerFrame) {
    533    const ADTS::FrameHeader& header = aFrame.Header();
    534    mSamplesPerFrame = header.mSamples;
    535    mSamplesPerSecond = header.mSampleRate;
    536    mChannels = header.mChannels;
    537  }
    538 
    539  ++mNumParsedFrames;
    540  ++mFrameIndex;
    541  MOZ_ASSERT(mFrameIndex > 0);
    542 }
    543 
    544 uint32_t ADTSTrackDemuxer::Read(uint8_t* aBuffer, int64_t aOffset,
    545                                int32_t aSize) {
    546  ADTSLOGV("ADTSTrackDemuxer::Read(%p %" PRId64 " %d)", aBuffer, aOffset,
    547           aSize);
    548 
    549  const int64_t streamLen = StreamLength();
    550  if (mInfo && streamLen > 0) {
    551    int64_t max = streamLen > aOffset ? streamLen - aOffset : 0;
    552    // Prevent blocking reads after successful initialization.
    553    aSize = std::min<int32_t>(aSize, AssertedCast<int32_t>(max));
    554  }
    555 
    556  uint32_t read = 0;
    557  ADTSLOGV("ADTSTrackDemuxer::Read        -> ReadAt(%d)", aSize);
    558  const nsresult rv = mSource.ReadAt(aOffset, reinterpret_cast<char*>(aBuffer),
    559                                     static_cast<uint32_t>(aSize), &read);
    560  NS_ENSURE_SUCCESS(rv, 0);
    561  return read;
    562 }
    563 
    564 double ADTSTrackDemuxer::AverageFrameLength() const {
    565  if (mNumParsedFrames) {
    566    return AssertedCast<double>(mTotalFrameLen) /
    567           AssertedCast<double>(mNumParsedFrames);
    568  }
    569 
    570  return 0.0;
    571 }
    572 
    573 /* static */
    574 bool ADTSDemuxer::ADTSSniffer(const uint8_t* aData, const uint32_t aLength) {
    575  if (aLength < 7) {
    576    return false;
    577  }
    578  if (!ADTS::FrameHeader::MatchesSync(Span(aData, aLength))) {
    579    return false;
    580  }
    581  auto parser = MakeUnique<ADTS::FrameParser>();
    582 
    583  if (!parser->Parse(0, aData, aData + aLength)) {
    584    return false;
    585  }
    586  const ADTS::Frame& currentFrame = parser->CurrentFrame();
    587  // Check for sync marker after the found frame, since it's
    588  // possible to find sync marker in AAC data. If sync marker
    589  // exists after the current frame then we've found a frame
    590  // header.
    591  uint64_t nextFrameHeaderOffset =
    592      currentFrame.Offset() + currentFrame.Length();
    593  return aLength > nextFrameHeaderOffset &&
    594         aLength - nextFrameHeaderOffset >= 2 &&
    595         ADTS::FrameHeader::MatchesSync(Span(aData + nextFrameHeaderOffset,
    596                                             aLength - nextFrameHeaderOffset));
    597 }
    598 
    599 }  // namespace mozilla
    600 
    601 #undef LOG
    602 #undef ADTSLOG
    603 #undef ADTSLOGV