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/Logging.h"
12 #include "mozilla/UniquePtr.h"
15 extern mozilla::LazyLogModule gMediaDemuxerLog
;
16 #define LOG(msg, ...) \
17 MOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, msg, ##__VA_ARGS__)
18 #define ADTSLOG(msg, ...) \
19 DDMOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, msg, ##__VA_ARGS__)
20 #define ADTSLOGV(msg, ...) \
21 DDMOZ_LOG(gMediaDemuxerLog, LogLevel::Verbose, msg, ##__VA_ARGS__)
26 // adts::FrameHeader - Holds the ADTS frame header and its parsing
29 // ADTS Frame Structure
31 // 11111111 1111BCCD EEFFFFGH HHIJKLMM MMMMMMMM MMMOOOOO OOOOOOPP(QQQQQQQQ
34 // Header consists of 7 or 9 bytes(without or with CRC).
35 // Letter Length(bits) Description
36 // { sync } 12 syncword 0xFFF, all bits must be 1
37 // B 1 MPEG Version: 0 for MPEG-4, 1 for MPEG-2
38 // C 2 Layer: always 0
39 // D 1 protection absent, Warning, set to 1 if there is no
40 // CRC and 0 if there is CRC
41 // E 2 profile, the MPEG-4 Audio Object Type minus 1
42 // F 4 MPEG-4 Sampling Frequency Index (15 is forbidden)
43 // H 3 MPEG-4 Channel Configuration (in the case of 0, the
44 // channel configuration is sent via an in-band PCE)
45 // M 13 frame length, this value must include 7 or 9 bytes of
46 // header length: FrameLength =
47 // (ProtectionAbsent == 1 ? 7 : 9) + size(AACFrame)
48 // O 11 Buffer fullness
49 // P 2 Number of AAC frames(RDBs) in ADTS frame minus 1, for
50 // maximum compatibility always use 1 AAC frame per ADTS
52 // Q 16 CRC if protection absent is 0
55 uint32_t mFrameLength
{};
56 uint32_t mSampleRate
{};
59 uint8_t mObjectType
{};
60 uint8_t mSamplingIndex
{};
61 uint8_t mChannelConfig
{};
62 uint8_t mNumAACFrames
{};
65 // Returns whether aPtr matches a valid ADTS header sync marker
66 static bool MatchesSync(const uint8_t* aPtr
) {
67 return aPtr
[0] == 0xFF && (aPtr
[1] & 0xF6) == 0xF0;
70 FrameHeader() { Reset(); }
73 uint64_t HeaderSize() const { return (mHaveCrc
) ? 9 : 7; }
75 bool IsValid() const { return mFrameLength
> 0; }
77 // Resets the state to allow for a new parsing session.
78 void Reset() { PodZero(this); }
80 // Returns whether the byte creates a valid sequence up to this point.
81 bool Parse(const uint8_t* aPtr
) {
82 const uint8_t* p
= aPtr
;
84 if (!MatchesSync(p
)) {
88 // AAC has 1024 samples per frame per channel.
91 mHaveCrc
= !(p
[1] & 0x01);
92 mObjectType
= ((p
[2] & 0xC0) >> 6) + 1;
93 mSamplingIndex
= (p
[2] & 0x3C) >> 2;
94 mChannelConfig
= (p
[2] & 0x01) << 2 | (p
[3] & 0xC0) >> 6;
95 mFrameLength
= static_cast<uint32_t>(
96 (p
[3] & 0x03) << 11 | (p
[4] & 0xFF) << 3 | (p
[5] & 0xE0) >> 5);
97 mNumAACFrames
= (p
[6] & 0x03) + 1;
99 static const uint32_t SAMPLE_RATES
[] = {96000, 88200, 64000, 48000, 44100,
100 32000, 24000, 22050, 16000, 12000,
102 if (mSamplingIndex
>= ArrayLength(SAMPLE_RATES
)) {
103 LOG(("ADTS: Init() failure: invalid sample-rate index value: %" PRIu32
108 mSampleRate
= SAMPLE_RATES
[mSamplingIndex
];
110 MOZ_ASSERT(mChannelConfig
< 8);
111 mChannels
= (mChannelConfig
== 7) ? 8 : mChannelConfig
;
117 // adts::Frame - Frame meta container used to parse and hold a frame
118 // header and side info.
121 Frame() : mOffset(0), mHeader() {}
123 uint64_t Offset() const { return mOffset
; }
124 size_t Length() const {
125 // TODO: If fields are zero'd when invalid, this check wouldn't be
127 if (!mHeader
.IsValid()) {
131 return mHeader
.mFrameLength
;
134 // Returns the offset to the start of frame's raw data.
135 uint64_t PayloadOffset() const { return mOffset
+ mHeader
.HeaderSize(); }
137 // Returns the length of the frame's raw data (excluding the header) in bytes.
138 size_t PayloadLength() const {
139 // TODO: If fields are zero'd when invalid, this check wouldn't be
141 if (!mHeader
.IsValid()) {
145 return mHeader
.mFrameLength
- mHeader
.HeaderSize();
148 // Returns the parsed frame header.
149 const FrameHeader
& Header() const { return mHeader
; }
151 bool IsValid() const { return mHeader
.IsValid(); }
153 // Resets the frame header and data.
159 // Returns whether the valid
160 bool Parse(uint64_t aOffset
, const uint8_t* aStart
, const uint8_t* aEnd
) {
161 MOZ_ASSERT(aStart
&& aEnd
);
164 const uint8_t* ptr
= aStart
;
165 // Require at least 7 bytes of data at the end of the buffer for the minimum
166 // ADTS frame header.
167 while (ptr
< aEnd
- 7 && !found
) {
168 found
= mHeader
.Parse(ptr
);
172 mOffset
= aOffset
+ (static_cast<size_t>(ptr
- aStart
)) - 1u;
178 // The offset to the start of the header.
181 // The currently parsed frame header.
187 // Returns the currently parsed frame. Reset via Reset or EndFrameSession.
188 const Frame
& CurrentFrame() const { return mFrame
; }
190 // Returns the first parsed frame. Reset via Reset.
191 const Frame
& FirstFrame() const { return mFirstFrame
; }
193 // Resets the parser. Don't use between frames as first frame data is reset.
199 // Clear the last parsed frame to allow for next frame parsing, i.e.:
200 // - sets PrevFrame to CurrentFrame
201 // - resets the CurrentFrame
202 // - resets ID3Header if no valid header was parsed yet
203 void EndFrameSession() { mFrame
.Reset(); }
205 // Parses contents of given ByteReader for a valid frame header and returns
206 // true if one was found. After returning, the variable passed to
207 // 'aBytesToSkip' holds the amount of bytes to be skipped (if any) in order to
208 // jump across a large ID3v2 tag spanning multiple buffers.
209 bool Parse(uint64_t aOffset
, const uint8_t* aStart
, const uint8_t* aEnd
) {
210 const bool found
= mFrame
.Parse(aOffset
, aStart
, aEnd
);
212 if (mFrame
.Length() && !mFirstFrame
.Length()) {
213 mFirstFrame
= mFrame
;
220 // We keep the first parsed frame around for static info access, the
221 // previously parsed frame for debugging and the currently parsed frame.
226 // Initialize the AAC AudioSpecificConfig.
227 // Only handles two-byte version for AAC-LC.
228 static void InitAudioSpecificConfig(const Frame
& frame
,
229 MediaByteBuffer
* aBuffer
) {
230 const FrameHeader
& header
= frame
.Header();
231 MOZ_ASSERT(header
.IsValid());
233 int audioObjectType
= header
.mObjectType
;
234 int samplingFrequencyIndex
= header
.mSamplingIndex
;
235 int channelConfig
= header
.mChannelConfig
;
238 asc
[0] = (audioObjectType
& 0x1F) << 3 | (samplingFrequencyIndex
& 0x0E) >> 1;
239 asc
[1] = (samplingFrequencyIndex
& 0x01) << 7 | (channelConfig
& 0x0F) << 3;
241 aBuffer
->AppendElements(asc
, 2);
246 using media::TimeUnit
;
250 ADTSDemuxer::ADTSDemuxer(MediaResource
* aSource
) : mSource(aSource
) {
251 DDLINKCHILD("source", aSource
);
254 bool ADTSDemuxer::InitInternal() {
255 if (!mTrackDemuxer
) {
256 mTrackDemuxer
= new ADTSTrackDemuxer(mSource
);
257 DDLINKCHILD("track demuxer", mTrackDemuxer
.get());
259 return mTrackDemuxer
->Init();
262 RefPtr
<ADTSDemuxer::InitPromise
> ADTSDemuxer::Init() {
263 if (!InitInternal()) {
264 ADTSLOG("Init() failure: waiting for data");
266 return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_METADATA_ERR
,
270 ADTSLOG("Init() successful");
271 return InitPromise::CreateAndResolve(NS_OK
, __func__
);
274 uint32_t ADTSDemuxer::GetNumberTracks(TrackInfo::TrackType aType
) const {
275 return (aType
== TrackInfo::kAudioTrack
) ? 1 : 0;
278 already_AddRefed
<MediaTrackDemuxer
> ADTSDemuxer::GetTrackDemuxer(
279 TrackInfo::TrackType aType
, uint32_t aTrackNumber
) {
280 if (!mTrackDemuxer
) {
284 return RefPtr
<ADTSTrackDemuxer
>(mTrackDemuxer
).forget();
287 bool ADTSDemuxer::IsSeekable() const {
288 int64_t length
= mSource
->GetLength();
293 ADTSTrackDemuxer::ADTSTrackDemuxer(MediaResource
* aSource
)
295 mParser(new adts::FrameParser()),
301 mSamplesPerSecond(0),
303 DDLINKCHILD("source", aSource
);
307 ADTSTrackDemuxer::~ADTSTrackDemuxer() { delete mParser
; }
309 bool ADTSTrackDemuxer::Init() {
310 FastSeek(TimeUnit::Zero());
311 // Read the first frame to fetch sample rate and other meta data.
312 RefPtr
<MediaRawData
> frame(GetNextFrame(FindNextFrame(true)));
314 ADTSLOG("Init StreamLength()=%" PRId64
" first-frame-found=%d",
315 StreamLength(), !!frame
);
321 // Rewind back to the stream begin to avoid dropping the first frame.
322 FastSeek(TimeUnit::Zero());
324 if (!mSamplesPerSecond
) {
329 mInfo
= MakeUnique
<AudioInfo
>();
332 mInfo
->mRate
= mSamplesPerSecond
;
333 mInfo
->mChannels
= mChannels
;
334 mInfo
->mBitDepth
= 16;
335 mInfo
->mDuration
= Duration();
337 // AAC Specific information
338 mInfo
->mMimeType
= "audio/mp4a-latm";
340 // Configure AAC codec-specific values.
341 // For AAC, mProfile and mExtendedProfile contain the audioObjectType from
342 // Table 1.3 -- Audio Profile definition, ISO/IEC 14496-3. Eg. 2 == AAC LC
343 mInfo
->mProfile
= mInfo
->mExtendedProfile
=
344 mParser
->FirstFrame().Header().mObjectType
;
345 AudioCodecSpecificBinaryBlob blob
;
346 InitAudioSpecificConfig(mParser
->FirstFrame(), blob
.mBinaryBlob
);
347 mInfo
->mCodecSpecificConfig
= AudioCodecSpecificVariant
{std::move(blob
)};
349 ADTSLOG("Init mInfo={mRate=%u mChannels=%u mBitDepth=%u mDuration=%" PRId64
351 mInfo
->mRate
, mInfo
->mChannels
, mInfo
->mBitDepth
,
352 mInfo
->mDuration
.ToMicroseconds());
354 // AAC encoder delay can be 2112 (typical value when using Apple AAC encoder),
355 // or 1024 (typical value when encoding using fdk_aac, often via ffmpeg).
357 // https://developer.apple.com/library/content/documentation/QuickTime/QTFF/QTFFAppenG/QTFFAppenG.html
358 // In an attempt to not trim valid audio data, and because ADTS doesn't
359 // provide a way to know this pre-roll value, this offets by 1024 frames.
360 mPreRoll
= TimeUnit(1024, mSamplesPerSecond
);
364 UniquePtr
<TrackInfo
> ADTSTrackDemuxer::GetInfo() const {
365 return mInfo
->Clone();
368 RefPtr
<ADTSTrackDemuxer::SeekPromise
> ADTSTrackDemuxer::Seek(
369 const TimeUnit
& aTime
) {
370 // Efficiently seek to the position.
371 const TimeUnit time
= aTime
> mPreRoll
? aTime
- mPreRoll
: TimeUnit::Zero();
373 // Correct seek position by scanning the next frames.
374 const TimeUnit seekTime
= ScanUntil(time
);
376 return SeekPromise::CreateAndResolve(seekTime
, __func__
);
379 TimeUnit
ADTSTrackDemuxer::FastSeek(const TimeUnit
& aTime
) {
380 ADTSLOG("FastSeek(%" PRId64
") avgFrameLen=%f mNumParsedFrames=%" PRIu64
381 " mFrameIndex=%" PRId64
" mOffset=%" PRIu64
,
382 aTime
.ToMicroseconds(), AverageFrameLength(), mNumParsedFrames
,
383 mFrameIndex
, mOffset
);
385 const uint64_t firstFrameOffset
= mParser
->FirstFrame().Offset();
386 if (!aTime
.ToMicroseconds()) {
387 // Quick seek to the beginning of the stream.
388 mOffset
= firstFrameOffset
;
389 } else if (AverageFrameLength() > 0) {
392 AssertedCast
<uint64_t>(AssertedCast
<double>(FrameIndexFromTime(aTime
)) *
393 AverageFrameLength());
396 const int64_t streamLength
= StreamLength();
397 if (mOffset
> firstFrameOffset
&& streamLength
> 0) {
398 mOffset
= std::min(static_cast<uint64_t>(streamLength
- 1), mOffset
);
401 mFrameIndex
= FrameIndexFromOffset(mOffset
);
402 mParser
->EndFrameSession();
404 ADTSLOG("FastSeek End avgFrameLen=%f mNumParsedFrames=%" PRIu64
405 " mFrameIndex=%" PRId64
" mFirstFrameOffset=%" PRIu64
406 " mOffset=%" PRIu64
" SL=%" PRIu64
"",
407 AverageFrameLength(), mNumParsedFrames
, mFrameIndex
, firstFrameOffset
,
408 mOffset
, streamLength
);
410 return Duration(mFrameIndex
);
413 TimeUnit
ADTSTrackDemuxer::ScanUntil(const TimeUnit
& aTime
) {
414 ADTSLOG("ScanUntil(%" PRId64
") avgFrameLen=%f mNumParsedFrames=%" PRIu64
415 " mFrameIndex=%" PRId64
" mOffset=%" PRIu64
,
416 aTime
.ToMicroseconds(), AverageFrameLength(), mNumParsedFrames
,
417 mFrameIndex
, mOffset
);
419 if (!aTime
.ToMicroseconds()) {
420 return FastSeek(aTime
);
423 if (Duration(mFrameIndex
) > aTime
) {
427 while (SkipNextFrame(FindNextFrame()) && Duration(mFrameIndex
+ 1) < aTime
) {
428 ADTSLOGV("ScanUntil* avgFrameLen=%f mNumParsedFrames=%" PRIu64
429 " mFrameIndex=%" PRId64
" mOffset=%" PRIu64
" Duration=%" PRId64
,
430 AverageFrameLength(), mNumParsedFrames
, mFrameIndex
, mOffset
,
431 Duration(mFrameIndex
+ 1).ToMicroseconds());
434 ADTSLOG("ScanUntil End avgFrameLen=%f mNumParsedFrames=%" PRIu64
435 " mFrameIndex=%" PRId64
" mOffset=%" PRIu64
,
436 AverageFrameLength(), mNumParsedFrames
, mFrameIndex
, mOffset
);
438 return Duration(mFrameIndex
);
441 RefPtr
<ADTSTrackDemuxer::SamplesPromise
> ADTSTrackDemuxer::GetSamples(
442 int32_t aNumSamples
) {
443 ADTSLOGV("GetSamples(%d) Begin mOffset=%" PRIu64
" mNumParsedFrames=%" PRIu64
444 " mFrameIndex=%" PRId64
" mTotalFrameLen=%" PRIu64
445 " mSamplesPerFrame=%d "
446 "mSamplesPerSecond=%d mChannels=%d",
447 aNumSamples
, mOffset
, mNumParsedFrames
, mFrameIndex
, mTotalFrameLen
,
448 mSamplesPerFrame
, mSamplesPerSecond
, mChannels
);
450 MOZ_ASSERT(aNumSamples
);
452 RefPtr
<SamplesHolder
> frames
= new SamplesHolder();
454 while (aNumSamples
--) {
455 RefPtr
<MediaRawData
> frame(GetNextFrame(FindNextFrame()));
457 frames
->AppendSample(frame
);
461 "GetSamples() End mSamples.Size()=%zu aNumSamples=%d mOffset=%" PRIu64
462 " mNumParsedFrames=%" PRIu64
" mFrameIndex=%" PRId64
463 " mTotalFrameLen=%" PRIu64
464 " mSamplesPerFrame=%d mSamplesPerSecond=%d "
466 frames
->GetSamples().Length(), aNumSamples
, mOffset
, mNumParsedFrames
,
467 mFrameIndex
, mTotalFrameLen
, mSamplesPerFrame
, mSamplesPerSecond
,
470 if (frames
->GetSamples().IsEmpty()) {
471 return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM
,
475 return SamplesPromise::CreateAndResolve(frames
, __func__
);
478 void ADTSTrackDemuxer::Reset() {
484 FastSeek(TimeUnit::Zero());
487 RefPtr
<ADTSTrackDemuxer::SkipAccessPointPromise
>
488 ADTSTrackDemuxer::SkipToNextRandomAccessPoint(const TimeUnit
& aTimeThreshold
) {
489 // Will not be called for audio-only resources.
490 return SkipAccessPointPromise::CreateAndReject(
491 SkipFailureHolder(NS_ERROR_DOM_MEDIA_DEMUXER_ERR
, 0), __func__
);
494 int64_t ADTSTrackDemuxer::GetResourceOffset() const {
495 return AssertedCast
<int64_t>(mOffset
);
498 media::TimeIntervals
ADTSTrackDemuxer::GetBuffered() {
499 auto duration
= Duration();
501 if (duration
.IsInfinite()) {
502 return media::TimeIntervals();
505 AutoPinned
<MediaResource
> stream(mSource
.GetResource());
506 return GetEstimatedBufferedTimeRanges(stream
, duration
.ToMicroseconds());
509 int64_t ADTSTrackDemuxer::StreamLength() const { return mSource
.GetLength(); }
511 TimeUnit
ADTSTrackDemuxer::Duration() const {
512 if (!mNumParsedFrames
) {
513 return TimeUnit::Invalid();
516 const int64_t streamLen
= StreamLength();
518 // Unknown length, we can't estimate duration, this is probably a live
520 return TimeUnit::FromInfinity();
522 const int64_t firstFrameOffset
=
523 AssertedCast
<int64_t>(mParser
->FirstFrame().Offset());
525 AssertedCast
<int64_t>(AssertedCast
<double>(streamLen
- firstFrameOffset
) /
526 AverageFrameLength());
527 return Duration(numFrames
);
530 TimeUnit
ADTSTrackDemuxer::Duration(int64_t aNumFrames
) const {
531 if (!mSamplesPerSecond
) {
532 return TimeUnit::Invalid();
535 return TimeUnit(aNumFrames
* mSamplesPerFrame
, mSamplesPerSecond
);
538 const adts::Frame
& ADTSTrackDemuxer::FindNextFrame(
539 bool findFirstFrame
/*= false*/) {
540 static const int BUFFER_SIZE
= 4096;
541 static const int MAX_SKIPPED_BYTES
= 10 * BUFFER_SIZE
;
543 ADTSLOGV("FindNext() Begin mOffset=%" PRIu64
" mNumParsedFrames=%" PRIu64
544 " mFrameIndex=%" PRId64
" mTotalFrameLen=%" PRIu64
545 " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
546 mOffset
, mNumParsedFrames
, mFrameIndex
, mTotalFrameLen
,
547 mSamplesPerFrame
, mSamplesPerSecond
, mChannels
);
549 uint8_t buffer
[BUFFER_SIZE
];
552 bool foundFrame
= false;
553 uint64_t frameHeaderOffset
= mOffset
;
555 // Prepare the parser for the next frame parsing session.
556 mParser
->EndFrameSession();
558 // Check whether we've found a valid ADTS frame.
559 while (!foundFrame
) {
560 if ((read
= Read(buffer
, AssertedCast
<int64_t>(frameHeaderOffset
),
561 BUFFER_SIZE
)) == 0) {
562 ADTSLOG("FindNext() EOS without a frame");
566 if (frameHeaderOffset
- mOffset
> MAX_SKIPPED_BYTES
) {
567 ADTSLOG("FindNext() exceeded MAX_SKIPPED_BYTES without a frame");
571 const adts::Frame
& currentFrame
= mParser
->CurrentFrame();
572 foundFrame
= mParser
->Parse(frameHeaderOffset
, buffer
, buffer
+ read
);
573 if (findFirstFrame
&& foundFrame
) {
574 // Check for sync marker after the found frame, since it's
575 // possible to find sync marker in AAC data. If sync marker
576 // exists after the current frame then we've found a frame
578 uint64_t nextFrameHeaderOffset
=
579 currentFrame
.Offset() + currentFrame
.Length();
581 Read(buffer
, AssertedCast
<int64_t>(nextFrameHeaderOffset
), 2);
582 if (read
!= 2 || !adts::FrameHeader::MatchesSync(buffer
)) {
583 frameHeaderOffset
= currentFrame
.Offset() + 1;
594 // Minimum header size is 7 bytes.
595 uint64_t advance
= read
- 7;
597 // Check for offset overflow.
598 if (frameHeaderOffset
+ advance
<= frameHeaderOffset
) {
602 frameHeaderOffset
+= advance
;
605 if (!foundFrame
|| !mParser
->CurrentFrame().Length()) {
607 "FindNext() Exit foundFrame=%d mParser->CurrentFrame().Length()=%zu ",
608 foundFrame
, mParser
->CurrentFrame().Length());
610 return mParser
->CurrentFrame();
613 ADTSLOGV("FindNext() End mOffset=%" PRIu64
" mNumParsedFrames=%" PRIu64
614 " mFrameIndex=%" PRId64
" frameHeaderOffset=%" PRId64
615 " mTotalFrameLen=%" PRIu64
616 " mSamplesPerFrame=%d mSamplesPerSecond=%d"
618 mOffset
, mNumParsedFrames
, mFrameIndex
, frameHeaderOffset
,
619 mTotalFrameLen
, mSamplesPerFrame
, mSamplesPerSecond
, mChannels
);
621 return mParser
->CurrentFrame();
624 bool ADTSTrackDemuxer::SkipNextFrame(const adts::Frame
& aFrame
) {
625 if (!mNumParsedFrames
|| !aFrame
.Length()) {
626 RefPtr
<MediaRawData
> frame(GetNextFrame(aFrame
));
632 ADTSLOGV("SkipNext() End mOffset=%" PRIu64
" mNumParsedFrames=%" PRIu64
633 " mFrameIndex=%" PRId64
" mTotalFrameLen=%" PRIu64
634 " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
635 mOffset
, mNumParsedFrames
, mFrameIndex
, mTotalFrameLen
,
636 mSamplesPerFrame
, mSamplesPerSecond
, mChannels
);
641 already_AddRefed
<MediaRawData
> ADTSTrackDemuxer::GetNextFrame(
642 const adts::Frame
& aFrame
) {
643 ADTSLOG("GetNext() Begin({mOffset=%" PRIu64
" HeaderSize()=%" PRIu64
645 aFrame
.Offset(), aFrame
.Header().HeaderSize(),
646 aFrame
.PayloadLength());
647 if (!aFrame
.IsValid()) return nullptr;
649 const int64_t offset
= AssertedCast
<int64_t>(aFrame
.PayloadOffset());
650 const uint32_t length
= aFrame
.PayloadLength();
652 RefPtr
<MediaRawData
> frame
= new MediaRawData();
653 frame
->mOffset
= offset
;
655 UniquePtr
<MediaRawDataWriter
> frameWriter(frame
->CreateWriter());
656 if (!frameWriter
->SetSize(length
)) {
657 ADTSLOG("GetNext() Exit failed to allocated media buffer");
661 const uint32_t read
=
662 Read(frameWriter
->Data(), offset
, AssertedCast
<int32_t>(length
));
663 if (read
!= length
) {
664 ADTSLOG("GetNext() Exit read=%u frame->Size()=%zu", read
, frame
->Size());
670 TimeUnit rawpts
= Duration(mFrameIndex
- 1) - mPreRoll
;
671 TimeUnit rawDuration
= Duration(1);
672 TimeUnit rawend
= rawpts
+ rawDuration
;
674 frame
->mTime
= std::max(TimeUnit::Zero(), rawpts
);
675 frame
->mDuration
= Duration(1);
676 frame
->mTimecode
= frame
->mTime
;
677 frame
->mKeyframe
= true;
679 // Handle decoder delay. A packet must be trimmed if its pts, adjusted for
680 // decoder delay, is negative. A packet can be trimmed entirely.
681 if (rawpts
.IsNegative()) {
682 frame
->mDuration
= std::max(TimeUnit::Zero(), rawend
- frame
->mTime
);
685 // ADTS frames can have a presentation duration of zero, e.g. when a frame is
687 MOZ_ASSERT(frame
->mDuration
.IsPositiveOrZero());
689 ADTSLOG("ADTS packet demuxed: pts [%lf, %lf] (duration: %lf)",
690 frame
->mTime
.ToSeconds(), frame
->GetEndTime().ToSeconds(),
691 frame
->mDuration
.ToSeconds());
693 // Indicate original packet information to trim after decoding.
694 if (frame
->mDuration
!= rawDuration
) {
695 frame
->mOriginalPresentationWindow
=
696 Some(media::TimeInterval
{rawpts
, rawend
});
697 ADTSLOG("Total packet time excluding trimming: [%lf, %lf]",
698 rawpts
.ToSeconds(), rawend
.ToSeconds());
701 ADTSLOGV("GetNext() End mOffset=%" PRIu64
" mNumParsedFrames=%" PRIu64
702 " mFrameIndex=%" PRId64
" mTotalFrameLen=%" PRIu64
703 " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
704 mOffset
, mNumParsedFrames
, mFrameIndex
, mTotalFrameLen
,
705 mSamplesPerFrame
, mSamplesPerSecond
, mChannels
);
707 return frame
.forget();
710 int64_t ADTSTrackDemuxer::FrameIndexFromOffset(uint64_t aOffset
) const {
711 int64_t frameIndex
= 0;
713 if (AverageFrameLength() > 0) {
714 frameIndex
= AssertedCast
<int64_t>(
715 AssertedCast
<double>(aOffset
- mParser
->FirstFrame().Offset()) /
716 AverageFrameLength());
717 MOZ_ASSERT(frameIndex
>= 0);
720 ADTSLOGV("FrameIndexFromOffset(%" PRId64
") -> %" PRId64
, aOffset
,
725 int64_t ADTSTrackDemuxer::FrameIndexFromTime(const TimeUnit
& aTime
) const {
726 int64_t frameIndex
= 0;
727 if (mSamplesPerSecond
> 0 && mSamplesPerFrame
> 0) {
728 frameIndex
= AssertedCast
<int64_t>(aTime
.ToSeconds() * mSamplesPerSecond
/
733 ADTSLOGV("FrameIndexFromOffset(%fs) -> %" PRId64
, aTime
.ToSeconds(),
735 return std::max
<int64_t>(0, frameIndex
);
738 void ADTSTrackDemuxer::UpdateState(const adts::Frame
& aFrame
) {
739 uint32_t frameLength
= aFrame
.Length();
741 if (mTotalFrameLen
+ frameLength
< mTotalFrameLen
) {
742 // These variables have a linear dependency and are only used to derive the
743 // average frame length.
745 mNumParsedFrames
/= 2;
748 // Full frame parsed, move offset to its end.
749 mOffset
= aFrame
.Offset() + frameLength
;
750 mTotalFrameLen
+= frameLength
;
752 if (!mSamplesPerFrame
) {
753 const adts::FrameHeader
& header
= aFrame
.Header();
754 mSamplesPerFrame
= header
.mSamples
;
755 mSamplesPerSecond
= header
.mSampleRate
;
756 mChannels
= header
.mChannels
;
761 MOZ_ASSERT(mFrameIndex
> 0);
764 uint32_t ADTSTrackDemuxer::Read(uint8_t* aBuffer
, int64_t aOffset
,
766 ADTSLOGV("ADTSTrackDemuxer::Read(%p %" PRId64
" %d)", aBuffer
, aOffset
,
769 const int64_t streamLen
= StreamLength();
770 if (mInfo
&& streamLen
> 0) {
771 int64_t max
= streamLen
> aOffset
? streamLen
- aOffset
: 0;
772 // Prevent blocking reads after successful initialization.
773 aSize
= std::min
<int32_t>(aSize
, AssertedCast
<int32_t>(max
));
777 ADTSLOGV("ADTSTrackDemuxer::Read -> ReadAt(%d)", aSize
);
778 const nsresult rv
= mSource
.ReadAt(aOffset
, reinterpret_cast<char*>(aBuffer
),
779 static_cast<uint32_t>(aSize
), &read
);
780 NS_ENSURE_SUCCESS(rv
, 0);
784 double ADTSTrackDemuxer::AverageFrameLength() const {
785 if (mNumParsedFrames
) {
786 return AssertedCast
<double>(mTotalFrameLen
) /
787 AssertedCast
<double>(mNumParsedFrames
);
794 bool ADTSDemuxer::ADTSSniffer(const uint8_t* aData
, const uint32_t aLength
) {
798 if (!adts::FrameHeader::MatchesSync(aData
)) {
801 auto parser
= MakeUnique
<adts::FrameParser
>();
803 if (!parser
->Parse(0, aData
, aData
+ aLength
)) {
806 const adts::Frame
& currentFrame
= parser
->CurrentFrame();
807 // Check for sync marker after the found frame, since it's
808 // possible to find sync marker in AAC data. If sync marker
809 // exists after the current frame then we've found a frame
811 uint64_t nextFrameHeaderOffset
=
812 currentFrame
.Offset() + currentFrame
.Length();
813 return aLength
> nextFrameHeaderOffset
&&
814 aLength
- nextFrameHeaderOffset
>= 2 &&
815 adts::FrameHeader::MatchesSync(aData
+ nextFrameHeaderOffset
);
818 } // namespace mozilla