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