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