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/. */
7 #include "ADTSDemuxer.h"
10 #include "VideoUtils.h"
11 #include "mozilla/UniquePtr.h"
14 extern mozilla::LazyLogModule gMediaDemuxerLog
;
15 #define ADTSLOG(msg, ...) \
16 DDMOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, msg, ##__VA_ARGS__)
17 #define ADTSLOGV(msg, ...) \
18 DDMOZ_LOG(gMediaDemuxerLog, LogLevel::Verbose, msg, ##__VA_ARGS__)
23 // adts::FrameHeader - Holds the ADTS frame header and its parsing
26 // ADTS Frame Structure
28 // 11111111 1111BCCD EEFFFFGH HHIJKLMM MMMMMMMM MMMOOOOO OOOOOOPP(QQQQQQQQ
31 // Header consists of 7 or 9 bytes(without or with CRC).
32 // Letter Length(bits) Description
33 // { sync } 12 syncword 0xFFF, all bits must be 1
34 // B 1 MPEG Version: 0 for MPEG-4, 1 for MPEG-2
35 // C 2 Layer: always 0
36 // D 1 protection absent, Warning, set to 1 if there is no
37 // CRC and 0 if there is CRC
38 // E 2 profile, the MPEG-4 Audio Object Type minus 1
39 // F 4 MPEG-4 Sampling Frequency Index (15 is forbidden)
40 // H 3 MPEG-4 Channel Configuration (in the case of 0, the
41 // channel configuration is sent via an in-band PCE)
42 // M 13 frame length, this value must include 7 or 9 bytes of
43 // header length: FrameLength =
44 // (ProtectionAbsent == 1 ? 7 : 9) + size(AACFrame)
45 // O 11 Buffer fullness
46 // P 2 Number of AAC frames(RDBs) in ADTS frame minus 1, for
47 // maximum compatibility always use 1 AAC frame per ADTS
49 // Q 16 CRC if protection absent is 0
52 uint32_t mFrameLength
;
57 uint8_t mSamplingIndex
;
58 uint8_t mChannelConfig
;
59 uint8_t mNumAACFrames
;
62 // Returns whether aPtr matches a valid ADTS header sync marker
63 static bool MatchesSync(const uint8_t* aPtr
) {
64 return aPtr
[0] == 0xFF && (aPtr
[1] & 0xF6) == 0xF0;
67 FrameHeader() { Reset(); }
70 size_t HeaderSize() const { return (mHaveCrc
) ? 9 : 7; }
72 bool IsValid() const { return mFrameLength
> 0; }
74 // Resets the state to allow for a new parsing session.
75 void Reset() { PodZero(this); }
77 // Returns whether the byte creates a valid sequence up to this point.
78 bool Parse(const uint8_t* aPtr
) {
79 const uint8_t* p
= aPtr
;
81 if (!MatchesSync(p
)) {
85 // AAC has 1024 samples per frame per channel.
88 mHaveCrc
= !(p
[1] & 0x01);
89 mObjectType
= ((p
[2] & 0xC0) >> 6) + 1;
90 mSamplingIndex
= (p
[2] & 0x3C) >> 2;
91 mChannelConfig
= (p
[2] & 0x01) << 2 | (p
[3] & 0xC0) >> 6;
93 (p
[3] & 0x03) << 11 | (p
[4] & 0xFF) << 3 | (p
[5] & 0xE0) >> 5;
94 mNumAACFrames
= (p
[6] & 0x03) + 1;
96 static const int32_t SAMPLE_RATES
[16] = {96000, 88200, 64000, 48000, 44100,
97 32000, 24000, 22050, 16000, 12000,
99 mSampleRate
= SAMPLE_RATES
[mSamplingIndex
];
101 MOZ_ASSERT(mChannelConfig
< 8);
102 mChannels
= (mChannelConfig
== 7) ? 8 : mChannelConfig
;
108 // adts::Frame - Frame meta container used to parse and hold a frame
109 // header and side info.
112 Frame() : mOffset(0), mHeader() {}
114 int64_t Offset() const { return mOffset
; }
115 size_t Length() const {
116 // TODO: If fields are zero'd when invalid, this check wouldn't be
118 if (!mHeader
.IsValid()) {
122 return mHeader
.mFrameLength
;
125 // Returns the offset to the start of frame's raw data.
126 int64_t PayloadOffset() const { return mOffset
+ mHeader
.HeaderSize(); }
128 // Returns the length of the frame's raw data (excluding the header) in bytes.
129 size_t PayloadLength() const {
130 // TODO: If fields are zero'd when invalid, this check wouldn't be
132 if (!mHeader
.IsValid()) {
136 return mHeader
.mFrameLength
- mHeader
.HeaderSize();
139 // Returns the parsed frame header.
140 const FrameHeader
& Header() const { return mHeader
; }
142 bool IsValid() const { return mHeader
.IsValid(); }
144 // Resets the frame header and data.
150 // Returns whether the valid
151 bool Parse(int64_t aOffset
, const uint8_t* aStart
, const uint8_t* aEnd
) {
152 MOZ_ASSERT(aStart
&& aEnd
);
155 const uint8_t* ptr
= aStart
;
156 // Require at least 7 bytes of data at the end of the buffer for the minimum
157 // ADTS frame header.
158 while (ptr
< aEnd
- 7 && !found
) {
159 found
= mHeader
.Parse(ptr
);
163 mOffset
= aOffset
+ (ptr
- aStart
) - 1;
169 // The offset to the start of the header.
172 // The currently parsed frame header.
178 // Returns the currently parsed frame. Reset via Reset or EndFrameSession.
179 const Frame
& CurrentFrame() const { return mFrame
; }
181 // Returns the first parsed frame. Reset via Reset.
182 const Frame
& FirstFrame() const { return mFirstFrame
; }
184 // Resets the parser. Don't use between frames as first frame data is reset.
190 // Clear the last parsed frame to allow for next frame parsing, i.e.:
191 // - sets PrevFrame to CurrentFrame
192 // - resets the CurrentFrame
193 // - resets ID3Header if no valid header was parsed yet
194 void EndFrameSession() { mFrame
.Reset(); }
196 // Parses contents of given ByteReader for a valid frame header and returns
197 // true if one was found. After returning, the variable passed to
198 // 'aBytesToSkip' holds the amount of bytes to be skipped (if any) in order to
199 // jump across a large ID3v2 tag spanning multiple buffers.
200 bool Parse(int64_t aOffset
, const uint8_t* aStart
, const uint8_t* aEnd
) {
201 const bool found
= mFrame
.Parse(aOffset
, aStart
, aEnd
);
203 if (mFrame
.Length() && !mFirstFrame
.Length()) {
204 mFirstFrame
= mFrame
;
211 // We keep the first parsed frame around for static info access, the
212 // previously parsed frame for debugging and the currently parsed frame.
217 // Initialize the AAC AudioSpecificConfig.
218 // Only handles two-byte version for AAC-LC.
219 static void InitAudioSpecificConfig(const Frame
& frame
,
220 MediaByteBuffer
* aBuffer
) {
221 const FrameHeader
& header
= frame
.Header();
222 MOZ_ASSERT(header
.IsValid());
224 int audioObjectType
= header
.mObjectType
;
225 int samplingFrequencyIndex
= header
.mSamplingIndex
;
226 int channelConfig
= header
.mChannelConfig
;
229 asc
[0] = (audioObjectType
& 0x1F) << 3 | (samplingFrequencyIndex
& 0x0E) >> 1;
230 asc
[1] = (samplingFrequencyIndex
& 0x01) << 7 | (channelConfig
& 0x0F) << 3;
232 aBuffer
->AppendElements(asc
, 2);
237 using media::TimeUnit
;
241 ADTSDemuxer::ADTSDemuxer(MediaResource
* aSource
) : mSource(aSource
) {
242 DDLINKCHILD("source", aSource
);
245 bool ADTSDemuxer::InitInternal() {
246 if (!mTrackDemuxer
) {
247 mTrackDemuxer
= new ADTSTrackDemuxer(mSource
);
248 DDLINKCHILD("track demuxer", mTrackDemuxer
.get());
250 return mTrackDemuxer
->Init();
253 RefPtr
<ADTSDemuxer::InitPromise
> ADTSDemuxer::Init() {
254 if (!InitInternal()) {
255 ADTSLOG("Init() failure: waiting for data");
257 return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_METADATA_ERR
,
261 ADTSLOG("Init() successful");
262 return InitPromise::CreateAndResolve(NS_OK
, __func__
);
265 uint32_t ADTSDemuxer::GetNumberTracks(TrackInfo::TrackType aType
) const {
266 return (aType
== TrackInfo::kAudioTrack
) ? 1 : 0;
269 already_AddRefed
<MediaTrackDemuxer
> ADTSDemuxer::GetTrackDemuxer(
270 TrackInfo::TrackType aType
, uint32_t aTrackNumber
) {
271 if (!mTrackDemuxer
) {
275 return RefPtr
<ADTSTrackDemuxer
>(mTrackDemuxer
).forget();
278 bool ADTSDemuxer::IsSeekable() const {
279 int64_t length
= mSource
->GetLength();
280 if (length
> -1) return true;
285 ADTSTrackDemuxer::ADTSTrackDemuxer(MediaResource
* aSource
)
287 mParser(new adts::FrameParser()),
293 mSamplesPerSecond(0),
295 DDLINKCHILD("source", aSource
);
299 ADTSTrackDemuxer::~ADTSTrackDemuxer() { delete mParser
; }
301 bool ADTSTrackDemuxer::Init() {
302 FastSeek(TimeUnit::Zero());
303 // Read the first frame to fetch sample rate and other meta data.
304 RefPtr
<MediaRawData
> frame(GetNextFrame(FindNextFrame(true)));
306 ADTSLOG("Init StreamLength()=%" PRId64
" first-frame-found=%d",
307 StreamLength(), !!frame
);
313 // Rewind back to the stream begin to avoid dropping the first frame.
314 FastSeek(TimeUnit::Zero());
316 if (!mSamplesPerSecond
) {
321 mInfo
= MakeUnique
<AudioInfo
>();
324 mInfo
->mRate
= mSamplesPerSecond
;
325 mInfo
->mChannels
= mChannels
;
326 mInfo
->mBitDepth
= 16;
327 mInfo
->mDuration
= Duration();
329 // AAC Specific information
330 mInfo
->mMimeType
= "audio/mp4a-latm";
332 // Configure AAC codec-specific values.
333 // For AAC, mProfile and mExtendedProfile contain the audioObjectType from
334 // Table 1.3 -- Audio Profile definition, ISO/IEC 14496-3. Eg. 2 == AAC LC
335 mInfo
->mProfile
= mInfo
->mExtendedProfile
=
336 mParser
->FirstFrame().Header().mObjectType
;
337 InitAudioSpecificConfig(mParser
->FirstFrame(), mInfo
->mCodecSpecificConfig
);
339 ADTSLOG("Init mInfo={mRate=%u mChannels=%u mBitDepth=%u mDuration=%" PRId64
341 mInfo
->mRate
, mInfo
->mChannels
, mInfo
->mBitDepth
,
342 mInfo
->mDuration
.ToMicroseconds());
344 // AAC encoder delay is by default 2112 audio frames.
346 // https://developer.apple.com/library/content/documentation/QuickTime/QTFF/QTFFAppenG/QTFFAppenG.html
347 // So we always seek 2112 frames prior the seeking point.
348 mPreRoll
= TimeUnit::FromMicroseconds(2112 * 1000000ULL / mSamplesPerSecond
);
352 UniquePtr
<TrackInfo
> ADTSTrackDemuxer::GetInfo() const {
353 return mInfo
->Clone();
356 RefPtr
<ADTSTrackDemuxer::SeekPromise
> ADTSTrackDemuxer::Seek(
357 const TimeUnit
& aTime
) {
358 // Efficiently seek to the position.
359 const TimeUnit time
= aTime
> mPreRoll
? aTime
- mPreRoll
: TimeUnit::Zero();
361 // Correct seek position by scanning the next frames.
362 const TimeUnit seekTime
= ScanUntil(time
);
364 return SeekPromise::CreateAndResolve(seekTime
, __func__
);
367 TimeUnit
ADTSTrackDemuxer::FastSeek(const TimeUnit
& aTime
) {
368 ADTSLOG("FastSeek(%" PRId64
") avgFrameLen=%f mNumParsedFrames=%" PRIu64
369 " mFrameIndex=%" PRId64
" mOffset=%" PRIu64
,
370 aTime
.ToMicroseconds(), AverageFrameLength(), mNumParsedFrames
,
371 mFrameIndex
, mOffset
);
373 const int64_t firstFrameOffset
= mParser
->FirstFrame().Offset();
374 if (!aTime
.ToMicroseconds()) {
375 // Quick seek to the beginning of the stream.
376 mOffset
= firstFrameOffset
;
377 } else if (AverageFrameLength() > 0) {
379 firstFrameOffset
+ FrameIndexFromTime(aTime
) * AverageFrameLength();
382 if (mOffset
> firstFrameOffset
&& StreamLength() > 0) {
383 mOffset
= std::min(StreamLength() - 1, mOffset
);
386 mFrameIndex
= FrameIndexFromOffset(mOffset
);
387 mParser
->EndFrameSession();
389 ADTSLOG("FastSeek End avgFrameLen=%f mNumParsedFrames=%" PRIu64
390 " mFrameIndex=%" PRId64
" mFirstFrameOffset=%" PRIu64
391 " mOffset=%" PRIu64
" SL=%" PRIu64
"",
392 AverageFrameLength(), mNumParsedFrames
, mFrameIndex
, firstFrameOffset
,
393 mOffset
, StreamLength());
395 return Duration(mFrameIndex
);
398 TimeUnit
ADTSTrackDemuxer::ScanUntil(const TimeUnit
& aTime
) {
399 ADTSLOG("ScanUntil(%" PRId64
") avgFrameLen=%f mNumParsedFrames=%" PRIu64
400 " mFrameIndex=%" PRId64
" mOffset=%" PRIu64
,
401 aTime
.ToMicroseconds(), AverageFrameLength(), mNumParsedFrames
,
402 mFrameIndex
, mOffset
);
404 if (!aTime
.ToMicroseconds()) {
405 return FastSeek(aTime
);
408 if (Duration(mFrameIndex
) > aTime
) {
412 while (SkipNextFrame(FindNextFrame()) && Duration(mFrameIndex
+ 1) < aTime
) {
413 ADTSLOGV("ScanUntil* avgFrameLen=%f mNumParsedFrames=%" PRIu64
414 " mFrameIndex=%" PRId64
" mOffset=%" PRIu64
" Duration=%" PRId64
,
415 AverageFrameLength(), mNumParsedFrames
, mFrameIndex
, mOffset
,
416 Duration(mFrameIndex
+ 1).ToMicroseconds());
419 ADTSLOG("ScanUntil End avgFrameLen=%f mNumParsedFrames=%" PRIu64
420 " mFrameIndex=%" PRId64
" mOffset=%" PRIu64
,
421 AverageFrameLength(), mNumParsedFrames
, mFrameIndex
, mOffset
);
423 return Duration(mFrameIndex
);
426 RefPtr
<ADTSTrackDemuxer::SamplesPromise
> ADTSTrackDemuxer::GetSamples(
427 int32_t aNumSamples
) {
428 ADTSLOGV("GetSamples(%d) Begin mOffset=%" PRIu64
" mNumParsedFrames=%" PRIu64
429 " mFrameIndex=%" PRId64
" mTotalFrameLen=%" PRIu64
430 " mSamplesPerFrame=%d "
431 "mSamplesPerSecond=%d mChannels=%d",
432 aNumSamples
, mOffset
, mNumParsedFrames
, mFrameIndex
, mTotalFrameLen
,
433 mSamplesPerFrame
, mSamplesPerSecond
, mChannels
);
435 MOZ_ASSERT(aNumSamples
);
437 RefPtr
<SamplesHolder
> frames
= new SamplesHolder();
439 while (aNumSamples
--) {
440 RefPtr
<MediaRawData
> frame(GetNextFrame(FindNextFrame()));
442 frames
->AppendSample(frame
);
446 "GetSamples() End mSamples.Size()=%zu aNumSamples=%d mOffset=%" PRIu64
447 " mNumParsedFrames=%" PRIu64
" mFrameIndex=%" PRId64
448 " mTotalFrameLen=%" PRIu64
449 " mSamplesPerFrame=%d mSamplesPerSecond=%d "
451 frames
->GetSamples().Length(), aNumSamples
, mOffset
, mNumParsedFrames
,
452 mFrameIndex
, mTotalFrameLen
, mSamplesPerFrame
, mSamplesPerSecond
,
455 if (frames
->GetSamples().IsEmpty()) {
456 return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM
,
460 return SamplesPromise::CreateAndResolve(frames
, __func__
);
463 void ADTSTrackDemuxer::Reset() {
469 FastSeek(TimeUnit::Zero());
472 RefPtr
<ADTSTrackDemuxer::SkipAccessPointPromise
>
473 ADTSTrackDemuxer::SkipToNextRandomAccessPoint(const TimeUnit
& aTimeThreshold
) {
474 // Will not be called for audio-only resources.
475 return SkipAccessPointPromise::CreateAndReject(
476 SkipFailureHolder(NS_ERROR_DOM_MEDIA_DEMUXER_ERR
, 0), __func__
);
479 int64_t ADTSTrackDemuxer::GetResourceOffset() const { return mOffset
; }
481 media::TimeIntervals
ADTSTrackDemuxer::GetBuffered() {
482 auto duration
= Duration();
484 if (!duration
.IsPositive()) {
485 return media::TimeIntervals();
488 AutoPinned
<MediaResource
> stream(mSource
.GetResource());
489 return GetEstimatedBufferedTimeRanges(stream
, duration
.ToMicroseconds());
492 int64_t ADTSTrackDemuxer::StreamLength() const { return mSource
.GetLength(); }
494 TimeUnit
ADTSTrackDemuxer::Duration() const {
495 if (!mNumParsedFrames
) {
496 return TimeUnit::FromMicroseconds(-1);
499 const int64_t streamLen
= StreamLength();
501 // Unknown length, we can't estimate duration.
502 return TimeUnit::FromMicroseconds(-1);
504 const int64_t firstFrameOffset
= mParser
->FirstFrame().Offset();
505 int64_t numFrames
= (streamLen
- firstFrameOffset
) / AverageFrameLength();
506 return Duration(numFrames
);
509 TimeUnit
ADTSTrackDemuxer::Duration(int64_t aNumFrames
) const {
510 if (!mSamplesPerSecond
) {
511 return TimeUnit::FromMicroseconds(-1);
514 return FramesToTimeUnit(aNumFrames
* mSamplesPerFrame
, mSamplesPerSecond
);
517 const adts::Frame
& ADTSTrackDemuxer::FindNextFrame(
518 bool findFirstFrame
/*= false*/) {
519 static const int BUFFER_SIZE
= 4096;
520 static const int MAX_SKIPPED_BYTES
= 10 * BUFFER_SIZE
;
522 ADTSLOGV("FindNext() Begin mOffset=%" PRIu64
" mNumParsedFrames=%" PRIu64
523 " mFrameIndex=%" PRId64
" mTotalFrameLen=%" PRIu64
524 " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
525 mOffset
, mNumParsedFrames
, mFrameIndex
, mTotalFrameLen
,
526 mSamplesPerFrame
, mSamplesPerSecond
, mChannels
);
528 uint8_t buffer
[BUFFER_SIZE
];
531 bool foundFrame
= false;
532 int64_t frameHeaderOffset
= mOffset
;
534 // Prepare the parser for the next frame parsing session.
535 mParser
->EndFrameSession();
537 // Check whether we've found a valid ADTS frame.
538 while (!foundFrame
) {
539 if ((read
= Read(buffer
, frameHeaderOffset
, BUFFER_SIZE
)) == 0) {
540 ADTSLOG("FindNext() EOS without a frame");
544 if (frameHeaderOffset
- mOffset
> MAX_SKIPPED_BYTES
) {
545 ADTSLOG("FindNext() exceeded MAX_SKIPPED_BYTES without a frame");
549 const adts::Frame
& currentFrame
= mParser
->CurrentFrame();
550 foundFrame
= mParser
->Parse(frameHeaderOffset
, buffer
, buffer
+ read
);
551 if (findFirstFrame
&& foundFrame
) {
552 // Check for sync marker after the found frame, since it's
553 // possible to find sync marker in AAC data. If sync marker
554 // exists after the current frame then we've found a frame
556 int64_t nextFrameHeaderOffset
=
557 currentFrame
.Offset() + currentFrame
.Length();
558 int32_t read
= Read(buffer
, nextFrameHeaderOffset
, 2);
559 if (read
!= 2 || !adts::FrameHeader::MatchesSync(buffer
)) {
560 frameHeaderOffset
= currentFrame
.Offset() + 1;
571 // Minimum header size is 7 bytes.
572 int64_t advance
= read
- 7;
574 // Check for offset overflow.
575 if (frameHeaderOffset
+ advance
<= frameHeaderOffset
) {
579 frameHeaderOffset
+= advance
;
582 if (!foundFrame
|| !mParser
->CurrentFrame().Length()) {
584 "FindNext() Exit foundFrame=%d mParser->CurrentFrame().Length()=%zu ",
585 foundFrame
, mParser
->CurrentFrame().Length());
587 return mParser
->CurrentFrame();
590 ADTSLOGV("FindNext() End mOffset=%" PRIu64
" mNumParsedFrames=%" PRIu64
591 " mFrameIndex=%" PRId64
" frameHeaderOffset=%" PRId64
592 " mTotalFrameLen=%" PRIu64
593 " mSamplesPerFrame=%d mSamplesPerSecond=%d"
595 mOffset
, mNumParsedFrames
, mFrameIndex
, frameHeaderOffset
,
596 mTotalFrameLen
, mSamplesPerFrame
, mSamplesPerSecond
, mChannels
);
598 return mParser
->CurrentFrame();
601 bool ADTSTrackDemuxer::SkipNextFrame(const adts::Frame
& aFrame
) {
602 if (!mNumParsedFrames
|| !aFrame
.Length()) {
603 RefPtr
<MediaRawData
> frame(GetNextFrame(aFrame
));
609 ADTSLOGV("SkipNext() End mOffset=%" PRIu64
" mNumParsedFrames=%" PRIu64
610 " mFrameIndex=%" PRId64
" mTotalFrameLen=%" PRIu64
611 " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
612 mOffset
, mNumParsedFrames
, mFrameIndex
, mTotalFrameLen
,
613 mSamplesPerFrame
, mSamplesPerSecond
, mChannels
);
618 already_AddRefed
<MediaRawData
> ADTSTrackDemuxer::GetNextFrame(
619 const adts::Frame
& aFrame
) {
620 ADTSLOG("GetNext() Begin({mOffset=%" PRId64
623 aFrame
.Offset(), aFrame
.Header().HeaderSize(),
624 aFrame
.PayloadLength());
625 if (!aFrame
.IsValid()) return nullptr;
627 const int64_t offset
= aFrame
.PayloadOffset();
628 const uint32_t length
= aFrame
.PayloadLength();
630 RefPtr
<MediaRawData
> frame
= new MediaRawData();
631 frame
->mOffset
= offset
;
633 UniquePtr
<MediaRawDataWriter
> frameWriter(frame
->CreateWriter());
634 if (!frameWriter
->SetSize(length
)) {
635 ADTSLOG("GetNext() Exit failed to allocated media buffer");
639 const uint32_t read
= Read(frameWriter
->Data(), offset
, length
);
640 if (read
!= length
) {
641 ADTSLOG("GetNext() Exit read=%u frame->Size()=%zu", read
, frame
->Size());
647 frame
->mTime
= Duration(mFrameIndex
- 1);
648 frame
->mDuration
= Duration(1);
649 frame
->mTimecode
= frame
->mTime
;
650 frame
->mKeyframe
= true;
652 MOZ_ASSERT(!frame
->mTime
.IsNegative());
653 MOZ_ASSERT(frame
->mDuration
.IsPositive());
655 ADTSLOGV("GetNext() End mOffset=%" PRIu64
" mNumParsedFrames=%" PRIu64
656 " mFrameIndex=%" PRId64
" mTotalFrameLen=%" PRIu64
657 " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
658 mOffset
, mNumParsedFrames
, mFrameIndex
, mTotalFrameLen
,
659 mSamplesPerFrame
, mSamplesPerSecond
, mChannels
);
661 return frame
.forget();
664 int64_t ADTSTrackDemuxer::FrameIndexFromOffset(int64_t aOffset
) const {
665 int64_t frameIndex
= 0;
667 if (AverageFrameLength() > 0) {
669 (aOffset
- mParser
->FirstFrame().Offset()) / AverageFrameLength();
672 ADTSLOGV("FrameIndexFromOffset(%" PRId64
") -> %" PRId64
, aOffset
,
674 return std::max
<int64_t>(0, frameIndex
);
677 int64_t ADTSTrackDemuxer::FrameIndexFromTime(const TimeUnit
& aTime
) const {
678 int64_t frameIndex
= 0;
679 if (mSamplesPerSecond
> 0 && mSamplesPerFrame
> 0) {
680 frameIndex
= aTime
.ToSeconds() * mSamplesPerSecond
/ mSamplesPerFrame
- 1;
683 ADTSLOGV("FrameIndexFromOffset(%fs) -> %" PRId64
, aTime
.ToSeconds(),
685 return std::max
<int64_t>(0, frameIndex
);
688 void ADTSTrackDemuxer::UpdateState(const adts::Frame
& aFrame
) {
689 int32_t frameLength
= aFrame
.Length();
691 if (mTotalFrameLen
+ frameLength
< mTotalFrameLen
) {
692 // These variables have a linear dependency and are only used to derive the
693 // average frame length.
695 mNumParsedFrames
/= 2;
698 // Full frame parsed, move offset to its end.
699 mOffset
= aFrame
.Offset() + frameLength
;
700 mTotalFrameLen
+= frameLength
;
702 if (!mSamplesPerFrame
) {
703 const adts::FrameHeader
& header
= aFrame
.Header();
704 mSamplesPerFrame
= header
.mSamples
;
705 mSamplesPerSecond
= header
.mSampleRate
;
706 mChannels
= header
.mChannels
;
711 MOZ_ASSERT(mFrameIndex
> 0);
714 int32_t ADTSTrackDemuxer::Read(uint8_t* aBuffer
, int64_t aOffset
,
716 ADTSLOGV("ADTSTrackDemuxer::Read(%p %" PRId64
" %d)", aBuffer
, aOffset
,
719 const int64_t streamLen
= StreamLength();
720 if (mInfo
&& streamLen
> 0) {
721 // Prevent blocking reads after successful initialization.
722 aSize
= std::min
<int64_t>(aSize
, streamLen
- aOffset
);
726 ADTSLOGV("ADTSTrackDemuxer::Read -> ReadAt(%d)", aSize
);
727 const nsresult rv
= mSource
.ReadAt(aOffset
, reinterpret_cast<char*>(aBuffer
),
728 static_cast<uint32_t>(aSize
), &read
);
729 NS_ENSURE_SUCCESS(rv
, 0);
730 return static_cast<int32_t>(read
);
733 double ADTSTrackDemuxer::AverageFrameLength() const {
734 if (mNumParsedFrames
) {
735 return static_cast<double>(mTotalFrameLen
) / mNumParsedFrames
;
742 bool ADTSDemuxer::ADTSSniffer(const uint8_t* aData
, const uint32_t aLength
) {
746 if (!adts::FrameHeader::MatchesSync(aData
)) {
749 auto parser
= MakeUnique
<adts::FrameParser
>();
751 if (!parser
->Parse(0, aData
, aData
+ aLength
)) {
754 const adts::Frame
& currentFrame
= parser
->CurrentFrame();
755 // Check for sync marker after the found frame, since it's
756 // possible to find sync marker in AAC data. If sync marker
757 // exists after the current frame then we've found a frame
759 int64_t nextFrameHeaderOffset
= currentFrame
.Offset() + currentFrame
.Length();
760 return int64_t(aLength
) > nextFrameHeaderOffset
&&
761 aLength
- nextFrameHeaderOffset
>= 2 &&
762 adts::FrameHeader::MatchesSync(aData
+ nextFrameHeaderOffset
);
765 } // namespace mozilla