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 "TimeUnits.h"
10 #include "VideoUtils.h"
11 #include "mozilla/UniquePtr.h"
12 #include <inttypes.h>
13
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__)
19
20 namespace mozilla {
21 namespace adts {
22
23 // adts::FrameHeader - Holds the ADTS frame header and its parsing
24 // state.
25 //
26 // ADTS Frame Structure
27 //
28 // 11111111 1111BCCD EEFFFFGH HHIJKLMM MMMMMMMM MMMOOOOO OOOOOOPP(QQQQQQQQ
29 // QQQQQQQQ)
30 //
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
48 // frame
49 // Q 16 CRC if protection absent is 0
50 class FrameHeader {
51 public:
52 uint32_t mFrameLength;
53 uint32_t mSampleRate;
54 uint32_t mSamples;
55 uint32_t mChannels;
56 uint8_t mObjectType;
57 uint8_t mSamplingIndex;
58 uint8_t mChannelConfig;
59 uint8_t mNumAACFrames;
60 bool mHaveCrc;
61
62 // Returns whether aPtr matches a valid ADTS header sync marker
MatchesSync(const uint8_t * aPtr)63 static bool MatchesSync(const uint8_t* aPtr) {
64 return aPtr[0] == 0xFF && (aPtr[1] & 0xF6) == 0xF0;
65 }
66
FrameHeader()67 FrameHeader() { Reset(); }
68
69 // Header size
HeaderSize() const70 uint64_t HeaderSize() const { return (mHaveCrc) ? 9 : 7; }
71
IsValid() const72 bool IsValid() const { return mFrameLength > 0; }
73
74 // Resets the state to allow for a new parsing session.
Reset()75 void Reset() { PodZero(this); }
76
77 // Returns whether the byte creates a valid sequence up to this point.
Parse(const uint8_t * aPtr)78 bool Parse(const uint8_t* aPtr) {
79 const uint8_t* p = aPtr;
80
81 if (!MatchesSync(p)) {
82 return false;
83 }
84
85 // AAC has 1024 samples per frame per channel.
86 mSamples = 1024;
87
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;
92 mFrameLength = static_cast<uint32_t>(
93 (p[3] & 0x03) << 11 | (p[4] & 0xFF) << 3 | (p[5] & 0xE0) >> 5);
94 mNumAACFrames = (p[6] & 0x03) + 1;
95
96 static const uint32_t SAMPLE_RATES[16] = {96000, 88200, 64000, 48000, 44100,
97 32000, 24000, 22050, 16000, 12000,
98 11025, 8000, 7350};
99 mSampleRate = SAMPLE_RATES[mSamplingIndex];
100
101 MOZ_ASSERT(mChannelConfig < 8);
102 mChannels = (mChannelConfig == 7) ? 8 : mChannelConfig;
103
104 return true;
105 }
106 };
107
108 // adts::Frame - Frame meta container used to parse and hold a frame
109 // header and side info.
110 class Frame {
111 public:
Frame()112 Frame() : mOffset(0), mHeader() {}
113
Offset() const114 uint64_t Offset() const { return mOffset; }
Length() const115 size_t Length() const {
116 // TODO: If fields are zero'd when invalid, this check wouldn't be
117 // necessary.
118 if (!mHeader.IsValid()) {
119 return 0;
120 }
121
122 return mHeader.mFrameLength;
123 }
124
125 // Returns the offset to the start of frame's raw data.
PayloadOffset() const126 uint64_t PayloadOffset() const { return mOffset + mHeader.HeaderSize(); }
127
128 // Returns the length of the frame's raw data (excluding the header) in bytes.
PayloadLength() const129 size_t PayloadLength() const {
130 // TODO: If fields are zero'd when invalid, this check wouldn't be
131 // necessary.
132 if (!mHeader.IsValid()) {
133 return 0;
134 }
135
136 return mHeader.mFrameLength - mHeader.HeaderSize();
137 }
138
139 // Returns the parsed frame header.
Header() const140 const FrameHeader& Header() const { return mHeader; }
141
IsValid() const142 bool IsValid() const { return mHeader.IsValid(); }
143
144 // Resets the frame header and data.
Reset()145 void Reset() {
146 mHeader.Reset();
147 mOffset = 0;
148 }
149
150 // Returns whether the valid
Parse(uint64_t aOffset,const uint8_t * aStart,const uint8_t * aEnd)151 bool Parse(uint64_t aOffset, const uint8_t* aStart, const uint8_t* aEnd) {
152 MOZ_ASSERT(aStart && aEnd);
153
154 bool found = false;
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);
160 ptr++;
161 }
162
163 mOffset = aOffset + (static_cast<size_t>(ptr - aStart)) - 1u;
164
165 return found;
166 }
167
168 private:
169 // The offset to the start of the header.
170 uint64_t mOffset;
171
172 // The currently parsed frame header.
173 FrameHeader mHeader;
174 };
175
176 class FrameParser {
177 public:
178 // Returns the currently parsed frame. Reset via Reset or EndFrameSession.
CurrentFrame() const179 const Frame& CurrentFrame() const { return mFrame; }
180
181 // Returns the first parsed frame. Reset via Reset.
FirstFrame() const182 const Frame& FirstFrame() const { return mFirstFrame; }
183
184 // Resets the parser. Don't use between frames as first frame data is reset.
Reset()185 void Reset() {
186 EndFrameSession();
187 mFirstFrame.Reset();
188 }
189
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
EndFrameSession()194 void EndFrameSession() { mFrame.Reset(); }
195
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.
Parse(uint64_t aOffset,const uint8_t * aStart,const uint8_t * aEnd)200 bool Parse(uint64_t aOffset, const uint8_t* aStart, const uint8_t* aEnd) {
201 const bool found = mFrame.Parse(aOffset, aStart, aEnd);
202
203 if (mFrame.Length() && !mFirstFrame.Length()) {
204 mFirstFrame = mFrame;
205 }
206
207 return found;
208 }
209
210 private:
211 // We keep the first parsed frame around for static info access, the
212 // previously parsed frame for debugging and the currently parsed frame.
213 Frame mFirstFrame;
214 Frame mFrame;
215 };
216
217 // Initialize the AAC AudioSpecificConfig.
218 // Only handles two-byte version for AAC-LC.
InitAudioSpecificConfig(const Frame & frame,MediaByteBuffer * aBuffer)219 static void InitAudioSpecificConfig(const Frame& frame,
220 MediaByteBuffer* aBuffer) {
221 const FrameHeader& header = frame.Header();
222 MOZ_ASSERT(header.IsValid());
223
224 int audioObjectType = header.mObjectType;
225 int samplingFrequencyIndex = header.mSamplingIndex;
226 int channelConfig = header.mChannelConfig;
227
228 uint8_t asc[2];
229 asc[0] = (audioObjectType & 0x1F) << 3 | (samplingFrequencyIndex & 0x0E) >> 1;
230 asc[1] = (samplingFrequencyIndex & 0x01) << 7 | (channelConfig & 0x0F) << 3;
231
232 aBuffer->AppendElements(asc, 2);
233 }
234
235 } // namespace adts
236
237 using media::TimeUnit;
238
239 // ADTSDemuxer
240
ADTSDemuxer(MediaResource * aSource)241 ADTSDemuxer::ADTSDemuxer(MediaResource* aSource) : mSource(aSource) {
242 DDLINKCHILD("source", aSource);
243 }
244
InitInternal()245 bool ADTSDemuxer::InitInternal() {
246 if (!mTrackDemuxer) {
247 mTrackDemuxer = new ADTSTrackDemuxer(mSource);
248 DDLINKCHILD("track demuxer", mTrackDemuxer.get());
249 }
250 return mTrackDemuxer->Init();
251 }
252
Init()253 RefPtr<ADTSDemuxer::InitPromise> ADTSDemuxer::Init() {
254 if (!InitInternal()) {
255 ADTSLOG("Init() failure: waiting for data");
256
257 return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_METADATA_ERR,
258 __func__);
259 }
260
261 ADTSLOG("Init() successful");
262 return InitPromise::CreateAndResolve(NS_OK, __func__);
263 }
264
GetNumberTracks(TrackInfo::TrackType aType) const265 uint32_t ADTSDemuxer::GetNumberTracks(TrackInfo::TrackType aType) const {
266 return (aType == TrackInfo::kAudioTrack) ? 1 : 0;
267 }
268
GetTrackDemuxer(TrackInfo::TrackType aType,uint32_t aTrackNumber)269 already_AddRefed<MediaTrackDemuxer> ADTSDemuxer::GetTrackDemuxer(
270 TrackInfo::TrackType aType, uint32_t aTrackNumber) {
271 if (!mTrackDemuxer) {
272 return nullptr;
273 }
274
275 return RefPtr<ADTSTrackDemuxer>(mTrackDemuxer).forget();
276 }
277
IsSeekable() const278 bool ADTSDemuxer::IsSeekable() const {
279 int64_t length = mSource->GetLength();
280 if (length > -1) return true;
281 return false;
282 }
283
284 // ADTSTrackDemuxer
ADTSTrackDemuxer(MediaResource * aSource)285 ADTSTrackDemuxer::ADTSTrackDemuxer(MediaResource* aSource)
286 : mSource(aSource),
287 mParser(new adts::FrameParser()),
288 mOffset(0),
289 mNumParsedFrames(0),
290 mFrameIndex(0),
291 mTotalFrameLen(0),
292 mSamplesPerFrame(0),
293 mSamplesPerSecond(0),
294 mChannels(0) {
295 DDLINKCHILD("source", aSource);
296 Reset();
297 }
298
~ADTSTrackDemuxer()299 ADTSTrackDemuxer::~ADTSTrackDemuxer() { delete mParser; }
300
Init()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)));
305
306 ADTSLOG("Init StreamLength()=%" PRId64 " first-frame-found=%d",
307 StreamLength(), !!frame);
308
309 if (!frame) {
310 return false;
311 }
312
313 // Rewind back to the stream begin to avoid dropping the first frame.
314 FastSeek(TimeUnit::Zero());
315
316 if (!mSamplesPerSecond) {
317 return false;
318 }
319
320 if (!mInfo) {
321 mInfo = MakeUnique<AudioInfo>();
322 }
323
324 mInfo->mRate = mSamplesPerSecond;
325 mInfo->mChannels = mChannels;
326 mInfo->mBitDepth = 16;
327 mInfo->mDuration = Duration();
328
329 // AAC Specific information
330 mInfo->mMimeType = "audio/mp4a-latm";
331
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);
338
339 ADTSLOG("Init mInfo={mRate=%u mChannels=%u mBitDepth=%u mDuration=%" PRId64
340 "}",
341 mInfo->mRate, mInfo->mChannels, mInfo->mBitDepth,
342 mInfo->mDuration.ToMicroseconds());
343
344 // AAC encoder delay is by default 2112 audio frames.
345 // See
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);
349 return mChannels;
350 }
351
GetInfo() const352 UniquePtr<TrackInfo> ADTSTrackDemuxer::GetInfo() const {
353 return mInfo->Clone();
354 }
355
Seek(const TimeUnit & aTime)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();
360 FastSeek(time);
361 // Correct seek position by scanning the next frames.
362 const TimeUnit seekTime = ScanUntil(time);
363
364 return SeekPromise::CreateAndResolve(seekTime, __func__);
365 }
366
FastSeek(const TimeUnit & aTime)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);
372
373 const uint64_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) {
378 mOffset =
379 firstFrameOffset + FrameIndexFromTime(aTime) * AverageFrameLength();
380 }
381
382 const int64_t streamLength = StreamLength();
383 if (mOffset > firstFrameOffset && streamLength > 0) {
384 mOffset = std::min(static_cast<uint64_t>(streamLength - 1), mOffset);
385 }
386
387 mFrameIndex = FrameIndexFromOffset(mOffset);
388 mParser->EndFrameSession();
389
390 ADTSLOG("FastSeek End avgFrameLen=%f mNumParsedFrames=%" PRIu64
391 " mFrameIndex=%" PRId64 " mFirstFrameOffset=%" PRIu64
392 " mOffset=%" PRIu64 " SL=%" PRIu64 "",
393 AverageFrameLength(), mNumParsedFrames, mFrameIndex, firstFrameOffset,
394 mOffset, streamLength);
395
396 return Duration(mFrameIndex);
397 }
398
ScanUntil(const TimeUnit & aTime)399 TimeUnit ADTSTrackDemuxer::ScanUntil(const TimeUnit& aTime) {
400 ADTSLOG("ScanUntil(%" PRId64 ") avgFrameLen=%f mNumParsedFrames=%" PRIu64
401 " mFrameIndex=%" PRId64 " mOffset=%" PRIu64,
402 aTime.ToMicroseconds(), AverageFrameLength(), mNumParsedFrames,
403 mFrameIndex, mOffset);
404
405 if (!aTime.ToMicroseconds()) {
406 return FastSeek(aTime);
407 }
408
409 if (Duration(mFrameIndex) > aTime) {
410 FastSeek(aTime);
411 }
412
413 while (SkipNextFrame(FindNextFrame()) && Duration(mFrameIndex + 1) < aTime) {
414 ADTSLOGV("ScanUntil* avgFrameLen=%f mNumParsedFrames=%" PRIu64
415 " mFrameIndex=%" PRId64 " mOffset=%" PRIu64 " Duration=%" PRId64,
416 AverageFrameLength(), mNumParsedFrames, mFrameIndex, mOffset,
417 Duration(mFrameIndex + 1).ToMicroseconds());
418 }
419
420 ADTSLOG("ScanUntil End avgFrameLen=%f mNumParsedFrames=%" PRIu64
421 " mFrameIndex=%" PRId64 " mOffset=%" PRIu64,
422 AverageFrameLength(), mNumParsedFrames, mFrameIndex, mOffset);
423
424 return Duration(mFrameIndex);
425 }
426
GetSamples(int32_t aNumSamples)427 RefPtr<ADTSTrackDemuxer::SamplesPromise> ADTSTrackDemuxer::GetSamples(
428 int32_t aNumSamples) {
429 ADTSLOGV("GetSamples(%d) Begin mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
430 " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
431 " mSamplesPerFrame=%d "
432 "mSamplesPerSecond=%d mChannels=%d",
433 aNumSamples, mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
434 mSamplesPerFrame, mSamplesPerSecond, mChannels);
435
436 MOZ_ASSERT(aNumSamples);
437
438 RefPtr<SamplesHolder> frames = new SamplesHolder();
439
440 while (aNumSamples--) {
441 RefPtr<MediaRawData> frame(GetNextFrame(FindNextFrame()));
442 if (!frame) break;
443 frames->AppendSample(frame);
444 }
445
446 ADTSLOGV(
447 "GetSamples() End mSamples.Size()=%zu aNumSamples=%d mOffset=%" PRIu64
448 " mNumParsedFrames=%" PRIu64 " mFrameIndex=%" PRId64
449 " mTotalFrameLen=%" PRIu64
450 " mSamplesPerFrame=%d mSamplesPerSecond=%d "
451 "mChannels=%d",
452 frames->GetSamples().Length(), aNumSamples, mOffset, mNumParsedFrames,
453 mFrameIndex, mTotalFrameLen, mSamplesPerFrame, mSamplesPerSecond,
454 mChannels);
455
456 if (frames->GetSamples().IsEmpty()) {
457 return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM,
458 __func__);
459 }
460
461 return SamplesPromise::CreateAndResolve(frames, __func__);
462 }
463
Reset()464 void ADTSTrackDemuxer::Reset() {
465 ADTSLOG("Reset()");
466 MOZ_ASSERT(mParser);
467 if (mParser) {
468 mParser->Reset();
469 }
470 FastSeek(TimeUnit::Zero());
471 }
472
473 RefPtr<ADTSTrackDemuxer::SkipAccessPointPromise>
SkipToNextRandomAccessPoint(const TimeUnit & aTimeThreshold)474 ADTSTrackDemuxer::SkipToNextRandomAccessPoint(const TimeUnit& aTimeThreshold) {
475 // Will not be called for audio-only resources.
476 return SkipAccessPointPromise::CreateAndReject(
477 SkipFailureHolder(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, 0), __func__);
478 }
479
GetResourceOffset() const480 int64_t ADTSTrackDemuxer::GetResourceOffset() const { return mOffset; }
481
GetBuffered()482 media::TimeIntervals ADTSTrackDemuxer::GetBuffered() {
483 auto duration = Duration();
484
485 if (!duration.IsPositive()) {
486 return media::TimeIntervals();
487 }
488
489 AutoPinned<MediaResource> stream(mSource.GetResource());
490 return GetEstimatedBufferedTimeRanges(stream, duration.ToMicroseconds());
491 }
492
StreamLength() const493 int64_t ADTSTrackDemuxer::StreamLength() const { return mSource.GetLength(); }
494
Duration() const495 TimeUnit ADTSTrackDemuxer::Duration() const {
496 if (!mNumParsedFrames) {
497 return TimeUnit::FromMicroseconds(-1);
498 }
499
500 const int64_t streamLen = StreamLength();
501 if (streamLen < 0) {
502 // Unknown length, we can't estimate duration.
503 return TimeUnit::FromMicroseconds(-1);
504 }
505 const int64_t firstFrameOffset = mParser->FirstFrame().Offset();
506 int64_t numFrames = (streamLen - firstFrameOffset) / AverageFrameLength();
507 return Duration(numFrames);
508 }
509
Duration(int64_t aNumFrames) const510 TimeUnit ADTSTrackDemuxer::Duration(int64_t aNumFrames) const {
511 if (!mSamplesPerSecond) {
512 return TimeUnit::FromMicroseconds(-1);
513 }
514
515 return FramesToTimeUnit(aNumFrames * mSamplesPerFrame, mSamplesPerSecond);
516 }
517
FindNextFrame(bool findFirstFrame)518 const adts::Frame& ADTSTrackDemuxer::FindNextFrame(
519 bool findFirstFrame /*= false*/) {
520 static const int BUFFER_SIZE = 4096;
521 static const int MAX_SKIPPED_BYTES = 10 * BUFFER_SIZE;
522
523 ADTSLOGV("FindNext() Begin mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
524 " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
525 " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
526 mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
527 mSamplesPerFrame, mSamplesPerSecond, mChannels);
528
529 uint8_t buffer[BUFFER_SIZE];
530 uint32_t read = 0;
531
532 bool foundFrame = false;
533 uint64_t frameHeaderOffset = mOffset;
534
535 // Prepare the parser for the next frame parsing session.
536 mParser->EndFrameSession();
537
538 // Check whether we've found a valid ADTS frame.
539 while (!foundFrame) {
540 if ((read = Read(buffer, frameHeaderOffset, BUFFER_SIZE)) == 0) {
541 ADTSLOG("FindNext() EOS without a frame");
542 break;
543 }
544
545 if (frameHeaderOffset - mOffset > MAX_SKIPPED_BYTES) {
546 ADTSLOG("FindNext() exceeded MAX_SKIPPED_BYTES without a frame");
547 break;
548 }
549
550 const adts::Frame& currentFrame = mParser->CurrentFrame();
551 foundFrame = mParser->Parse(frameHeaderOffset, buffer, buffer + read);
552 if (findFirstFrame && foundFrame) {
553 // Check for sync marker after the found frame, since it's
554 // possible to find sync marker in AAC data. If sync marker
555 // exists after the current frame then we've found a frame
556 // header.
557 uint64_t nextFrameHeaderOffset =
558 currentFrame.Offset() + currentFrame.Length();
559 uint32_t read = Read(buffer, nextFrameHeaderOffset, 2);
560 if (read != 2 || !adts::FrameHeader::MatchesSync(buffer)) {
561 frameHeaderOffset = currentFrame.Offset() + 1;
562 mParser->Reset();
563 foundFrame = false;
564 continue;
565 }
566 }
567
568 if (foundFrame) {
569 break;
570 }
571
572 // Minimum header size is 7 bytes.
573 uint64_t advance = read - 7;
574
575 // Check for offset overflow.
576 if (frameHeaderOffset + advance <= frameHeaderOffset) {
577 break;
578 }
579
580 frameHeaderOffset += advance;
581 }
582
583 if (!foundFrame || !mParser->CurrentFrame().Length()) {
584 ADTSLOG(
585 "FindNext() Exit foundFrame=%d mParser->CurrentFrame().Length()=%zu ",
586 foundFrame, mParser->CurrentFrame().Length());
587 mParser->Reset();
588 return mParser->CurrentFrame();
589 }
590
591 ADTSLOGV("FindNext() End mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
592 " mFrameIndex=%" PRId64 " frameHeaderOffset=%" PRId64
593 " mTotalFrameLen=%" PRIu64
594 " mSamplesPerFrame=%d mSamplesPerSecond=%d"
595 " mChannels=%d",
596 mOffset, mNumParsedFrames, mFrameIndex, frameHeaderOffset,
597 mTotalFrameLen, mSamplesPerFrame, mSamplesPerSecond, mChannels);
598
599 return mParser->CurrentFrame();
600 }
601
SkipNextFrame(const adts::Frame & aFrame)602 bool ADTSTrackDemuxer::SkipNextFrame(const adts::Frame& aFrame) {
603 if (!mNumParsedFrames || !aFrame.Length()) {
604 RefPtr<MediaRawData> frame(GetNextFrame(aFrame));
605 return frame;
606 }
607
608 UpdateState(aFrame);
609
610 ADTSLOGV("SkipNext() End mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
611 " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
612 " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
613 mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
614 mSamplesPerFrame, mSamplesPerSecond, mChannels);
615
616 return true;
617 }
618
GetNextFrame(const adts::Frame & aFrame)619 already_AddRefed<MediaRawData> ADTSTrackDemuxer::GetNextFrame(
620 const adts::Frame& aFrame) {
621 ADTSLOG("GetNext() Begin({mOffset=%" PRIu64 " HeaderSize()=%" PRIu64
622 " Length()=%zu})",
623 aFrame.Offset(), aFrame.Header().HeaderSize(),
624 aFrame.PayloadLength());
625 if (!aFrame.IsValid()) return nullptr;
626
627 const int64_t offset = aFrame.PayloadOffset();
628 const uint32_t length = aFrame.PayloadLength();
629
630 RefPtr<MediaRawData> frame = new MediaRawData();
631 frame->mOffset = offset;
632
633 UniquePtr<MediaRawDataWriter> frameWriter(frame->CreateWriter());
634 if (!frameWriter->SetSize(length)) {
635 ADTSLOG("GetNext() Exit failed to allocated media buffer");
636 return nullptr;
637 }
638
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());
642 return nullptr;
643 }
644
645 UpdateState(aFrame);
646
647 frame->mTime = Duration(mFrameIndex - 1);
648 frame->mDuration = Duration(1);
649 frame->mTimecode = frame->mTime;
650 frame->mKeyframe = true;
651
652 MOZ_ASSERT(!frame->mTime.IsNegative());
653 MOZ_ASSERT(frame->mDuration.IsPositive());
654
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);
660
661 return frame.forget();
662 }
663
FrameIndexFromOffset(uint64_t aOffset) const664 int64_t ADTSTrackDemuxer::FrameIndexFromOffset(uint64_t aOffset) const {
665 uint64_t frameIndex = 0;
666
667 if (AverageFrameLength() > 0) {
668 frameIndex =
669 (aOffset - mParser->FirstFrame().Offset()) / AverageFrameLength();
670 }
671
672 ADTSLOGV("FrameIndexFromOffset(%" PRId64 ") -> %" PRId64, aOffset,
673 frameIndex);
674 return frameIndex;
675 }
676
FrameIndexFromTime(const TimeUnit & aTime) const677 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;
681 }
682
683 ADTSLOGV("FrameIndexFromOffset(%fs) -> %" PRId64, aTime.ToSeconds(),
684 frameIndex);
685 return std::max<int64_t>(0, frameIndex);
686 }
687
UpdateState(const adts::Frame & aFrame)688 void ADTSTrackDemuxer::UpdateState(const adts::Frame& aFrame) {
689 uint32_t frameLength = aFrame.Length();
690 // Prevent overflow.
691 if (mTotalFrameLen + frameLength < mTotalFrameLen) {
692 // These variables have a linear dependency and are only used to derive the
693 // average frame length.
694 mTotalFrameLen /= 2;
695 mNumParsedFrames /= 2;
696 }
697
698 // Full frame parsed, move offset to its end.
699 mOffset = aFrame.Offset() + frameLength;
700 mTotalFrameLen += frameLength;
701
702 if (!mSamplesPerFrame) {
703 const adts::FrameHeader& header = aFrame.Header();
704 mSamplesPerFrame = header.mSamples;
705 mSamplesPerSecond = header.mSampleRate;
706 mChannels = header.mChannels;
707 }
708
709 ++mNumParsedFrames;
710 ++mFrameIndex;
711 MOZ_ASSERT(mFrameIndex > 0);
712 }
713
Read(uint8_t * aBuffer,int64_t aOffset,int32_t aSize)714 uint32_t ADTSTrackDemuxer::Read(uint8_t* aBuffer, int64_t aOffset,
715 int32_t aSize) {
716 ADTSLOGV("ADTSTrackDemuxer::Read(%p %" PRId64 " %d)", aBuffer, aOffset,
717 aSize);
718
719 const int64_t streamLen = StreamLength();
720 if (mInfo && streamLen > 0) {
721 int64_t max = streamLen > aOffset ? streamLen - aOffset : 0;
722 // Prevent blocking reads after successful initialization.
723 aSize = std::min<int64_t>(aSize, max);
724 }
725
726 uint32_t read = 0;
727 ADTSLOGV("ADTSTrackDemuxer::Read -> ReadAt(%d)", aSize);
728 const nsresult rv = mSource.ReadAt(aOffset, reinterpret_cast<char*>(aBuffer),
729 static_cast<uint32_t>(aSize), &read);
730 NS_ENSURE_SUCCESS(rv, 0);
731 return read;
732 }
733
AverageFrameLength() const734 double ADTSTrackDemuxer::AverageFrameLength() const {
735 if (mNumParsedFrames) {
736 return static_cast<double>(mTotalFrameLen) / mNumParsedFrames;
737 }
738
739 return 0.0;
740 }
741
742 /* static */
ADTSSniffer(const uint8_t * aData,const uint32_t aLength)743 bool ADTSDemuxer::ADTSSniffer(const uint8_t* aData, const uint32_t aLength) {
744 if (aLength < 7) {
745 return false;
746 }
747 if (!adts::FrameHeader::MatchesSync(aData)) {
748 return false;
749 }
750 auto parser = MakeUnique<adts::FrameParser>();
751
752 if (!parser->Parse(0, aData, aData + aLength)) {
753 return false;
754 }
755 const adts::Frame& currentFrame = parser->CurrentFrame();
756 // Check for sync marker after the found frame, since it's
757 // possible to find sync marker in AAC data. If sync marker
758 // exists after the current frame then we've found a frame
759 // header.
760 uint64_t nextFrameHeaderOffset =
761 currentFrame.Offset() + currentFrame.Length();
762 MOZ_ASSERT(aLength >= nextFrameHeaderOffset);
763 return aLength > nextFrameHeaderOffset &&
764 aLength - nextFrameHeaderOffset >= 2 &&
765 adts::FrameHeader::MatchesSync(aData + nextFrameHeaderOffset);
766 }
767
768 } // namespace mozilla
769