1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "ADTSDemuxer.h"
8 
9 #include <inttypes.h>
10 
11 #include "nsAutoPtr.h"
12 #include "VideoUtils.h"
13 #include "TimeUnits.h"
14 #include "prenv.h"
15 
16 #ifdef PR_LOGGING
17 extern mozilla::LazyLogModule gMediaDemuxerLog;
18 #define ADTSLOG(msg, ...) \
19   MOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, ("ADTSDemuxer " msg, ##__VA_ARGS__))
20 #define ADTSLOGV(msg, ...) \
21   MOZ_LOG(gMediaDemuxerLog, LogLevel::Verbose, ("ADTSDemuxer " msg, ##__VA_ARGS__))
22 #else
23 #define ADTSLOG(msg, ...)  do {} while (false)
24 #define ADTSLOGV(msg, ...) do {} while (false)
25 #endif
26 
27 namespace mozilla {
28 namespace adts {
29 
30 // adts::FrameHeader - Holds the ADTS frame header and its parsing
31 // state.
32 //
33 // ADTS Frame Structure
34 //
35 // 11111111 1111BCCD EEFFFFGH HHIJKLMM MMMMMMMM MMMOOOOO OOOOOOPP(QQQQQQQQ QQQQQQQQ)
36 //
37 // Header consists of 7 or 9 bytes(without or with CRC).
38 // Letter   Length(bits)  Description
39 // { sync } 12            syncword 0xFFF, all bits must be 1
40 // B        1             MPEG Version: 0 for MPEG-4, 1 for MPEG-2
41 // C        2             Layer: always 0
42 // D        1             protection absent, Warning, set to 1 if there is no
43 //                        CRC and 0 if there is CRC
44 // E        2             profile, the MPEG-4 Audio Object Type minus 1
45 // F        4             MPEG-4 Sampling Frequency Index (15 is forbidden)
46 // H        3             MPEG-4 Channel Configuration (in the case of 0, the
47 //                        channel configuration is sent via an in-band PCE)
48 // M        13            frame length, this value must include 7 or 9 bytes of
49 //                        header length: FrameLength =
50 //                          (ProtectionAbsent == 1 ? 7 : 9) + size(AACFrame)
51 // O        11            Buffer fullness
52 // P        2             Number of AAC frames(RDBs) in ADTS frame minus 1, for
53 //                        maximum compatibility always use 1 AAC frame per ADTS
54 //                        frame
55 // Q        16            CRC if protection absent is 0
56 class FrameHeader {
57 public:
58   uint32_t mFrameLength;
59   uint32_t mSampleRate;
60   uint32_t mSamples;
61   uint32_t mChannels;
62   uint8_t  mObjectType;
63   uint8_t  mSamplingIndex;
64   uint8_t  mChannelConfig;
65   uint8_t  mNumAACFrames;
66   bool     mHaveCrc;
67 
68   // Returns whether aPtr matches a valid ADTS header sync marker
MatchesSync(const uint8_t * aPtr)69   static bool MatchesSync(const uint8_t* aPtr) {
70     return aPtr[0] == 0xFF && (aPtr[1] & 0xF6) == 0xF0;
71   }
72 
FrameHeader()73   FrameHeader() { Reset(); }
74 
75   // Header size
HeaderSize() const76   size_t HeaderSize() const { return (mHaveCrc) ? 9 : 7; }
77 
IsValid() const78   bool IsValid() const { return mFrameLength > 0; }
79 
80   // Resets the state to allow for a new parsing session.
Reset()81   void Reset() { PodZero(this); }
82 
83   // Returns whether the byte creates a valid sequence up to this point.
Parse(const uint8_t * aPtr)84   bool Parse(const uint8_t* aPtr) {
85     const uint8_t* p = aPtr;
86 
87     if (!MatchesSync(p)) {
88       return false;
89     }
90 
91     // AAC has 1024 samples per frame per channel.
92     mSamples = 1024;
93 
94     mHaveCrc = !(p[1] & 0x01);
95     mObjectType = ((p[2] & 0xC0) >> 6) + 1;
96     mSamplingIndex = (p[2] & 0x3C) >> 2;
97     mChannelConfig = (p[2] & 0x01) << 2 | (p[3] & 0xC0) >> 6;
98     mFrameLength = (p[3] & 0x03) << 11 | (p[4] & 0xFF) << 3 | (p[5] & 0xE0) >> 5;
99     mNumAACFrames = (p[6] & 0x03) + 1;
100 
101     static const int32_t SAMPLE_RATES[16] = {
102       96000, 88200, 64000, 48000,
103       44100, 32000, 24000, 22050,
104       16000, 12000, 11025,  8000,
105       7350
106     };
107     mSampleRate = SAMPLE_RATES[mSamplingIndex];
108 
109     MOZ_ASSERT(mChannelConfig < 8);
110     mChannels = (mChannelConfig == 7) ? 8 : mChannelConfig;
111 
112     return true;
113   }
114 };
115 
116 
117 // adts::Frame - Frame meta container used to parse and hold a frame
118 // header and side info.
119 class Frame {
120 public:
Frame()121   Frame() : mOffset(0), mHeader() {}
122 
Offset() const123   int64_t Offset() const { return mOffset; }
Length() const124   size_t Length() const {
125     // TODO: If fields are zero'd when invalid, this check wouldn't be necessary.
126     if (!mHeader.IsValid()) {
127       return 0;
128     }
129 
130     return mHeader.mFrameLength;
131   }
132 
133   // Returns the offset to the start of frame's raw data.
PayloadOffset() const134   int64_t PayloadOffset() const {
135     return mOffset + mHeader.HeaderSize();
136   }
137 
138   // Returns the length of the frame's raw data (excluding the header) in bytes.
PayloadLength() const139   size_t PayloadLength() const {
140     // TODO: If fields are zero'd when invalid, this check wouldn't be necessary.
141     if (!mHeader.IsValid()) {
142       return 0;
143     }
144 
145     return mHeader.mFrameLength - mHeader.HeaderSize();
146   }
147 
148   // Returns the parsed frame header.
Header() const149   const FrameHeader& Header() const {
150     return mHeader;
151   }
152 
IsValid() const153   bool IsValid() const {
154     return mHeader.IsValid();
155   }
156 
157   // Resets the frame header and data.
Reset()158   void Reset() {
159     mHeader.Reset();
160     mOffset = 0;
161   }
162 
163   // Returns whether the valid
Parse(int64_t aOffset,uint8_t * aStart,uint8_t * aEnd)164   bool Parse(int64_t aOffset, uint8_t* aStart, uint8_t* aEnd) {
165     MOZ_ASSERT(aStart && aEnd);
166 
167     bool found = false;
168     uint8_t* ptr = aStart;
169     // Require at least 7 bytes of data at the end of the buffer for the minimum
170     // ADTS frame header.
171     while (ptr < aEnd - 7 && !found) {
172       found = mHeader.Parse(ptr);
173       ptr++;
174     }
175 
176     mOffset = aOffset + (ptr - aStart) - 1;
177 
178     return found;
179   }
180 
181 private:
182   // The offset to the start of the header.
183   int64_t mOffset;
184 
185   // The currently parsed frame header.
186   FrameHeader mHeader;
187 };
188 
189 
190 class FrameParser {
191 public:
192 
193   // Returns the currently parsed frame. Reset via Reset or EndFrameSession.
CurrentFrame() const194   const Frame& CurrentFrame() const { return mFrame; }
195 
196 
197   // Returns the first parsed frame. Reset via Reset.
FirstFrame() const198   const Frame& FirstFrame() const { return mFirstFrame; }
199 
200   // Resets the parser. Don't use between frames as first frame data is reset.
Reset()201   void Reset() {
202     EndFrameSession();
203     mFirstFrame.Reset();
204   }
205 
206   // Clear the last parsed frame to allow for next frame parsing, i.e.:
207   // - sets PrevFrame to CurrentFrame
208   // - resets the CurrentFrame
209   // - resets ID3Header if no valid header was parsed yet
EndFrameSession()210   void EndFrameSession() {
211     mFrame.Reset();
212   }
213 
214   // Parses contents of given ByteReader for a valid frame header and returns true
215   // if one was found. After returning, the variable passed to 'aBytesToSkip' holds
216   // the amount of bytes to be skipped (if any) in order to jump across a large
217   // ID3v2 tag spanning multiple buffers.
Parse(int64_t aOffset,uint8_t * aStart,uint8_t * aEnd)218   bool Parse(int64_t aOffset, uint8_t* aStart, uint8_t* aEnd) {
219     const bool found = mFrame.Parse(aOffset, aStart, aEnd);
220 
221     if (mFrame.Length() && !mFirstFrame.Length()) {
222       mFirstFrame = mFrame;
223     }
224 
225     return found;
226   }
227 
228 private:
229   // We keep the first parsed frame around for static info access, the
230   // previously parsed frame for debugging and the currently parsed frame.
231   Frame mFirstFrame;
232   Frame mFrame;
233 };
234 
235 
236 // Return the AAC Profile Level Indication based upon sample rate and channels
237 // Information based upon table 1.10 from ISO/IEC 14496-3:2005(E)
238 static int8_t
ProfileLevelIndication(const Frame & frame)239 ProfileLevelIndication(const Frame& frame)
240 {
241   const FrameHeader& header = frame.Header();
242   MOZ_ASSERT(header.IsValid());
243 
244   if (!header.IsValid()) {
245     return 0;
246   }
247 
248   const int channels = header.mChannels;
249   const int sampleRate = header.mSampleRate;
250 
251   if (channels <= 2) {
252     if (sampleRate <= 24000) {
253       // AAC Profile  L1
254       return 0x28;
255     }
256     else if (sampleRate <= 48000) {
257       // AAC Profile  L2
258       return 0x29;
259     }
260   }
261   else if (channels <= 5) {
262     if (sampleRate <= 48000) {
263       // AAC Profile  L4
264       return 0x2A;
265     }
266     else if (sampleRate <= 96000) {
267       // AAC Profile  L5
268       return 0x2B;
269     }
270   }
271 
272   // TODO: Should this be 0xFE for 'no audio profile specified'?
273   return 0;
274 }
275 
276 
277 // Initialize the AAC AudioSpecificConfig.
278 // Only handles two-byte version for AAC-LC.
279 static void
InitAudioSpecificConfig(const Frame & frame,MediaByteBuffer * aBuffer)280 InitAudioSpecificConfig(const Frame& frame,
281                         MediaByteBuffer* aBuffer)
282 {
283   const FrameHeader& header = frame.Header();
284   MOZ_ASSERT(header.IsValid());
285 
286   int audioObjectType = header.mObjectType;
287   int samplingFrequencyIndex = header.mSamplingIndex;
288   int channelConfig = header.mChannelConfig;
289 
290   uint8_t asc[2];
291   asc[0] = (audioObjectType & 0x1F) << 3 | (samplingFrequencyIndex & 0x0E) >> 1;
292   asc[1] = (samplingFrequencyIndex & 0x01) << 7 | (channelConfig & 0x0F) << 3;
293 
294   aBuffer->AppendElements(asc, 2);
295 }
296 
297 } // namespace adts
298 
299 // ADTSDemuxer
300 
ADTSDemuxer(MediaResource * aSource)301 ADTSDemuxer::ADTSDemuxer(MediaResource* aSource)
302   : mSource(aSource)
303 {}
304 
305 bool
InitInternal()306 ADTSDemuxer::InitInternal()
307 {
308   if (!mTrackDemuxer) {
309     mTrackDemuxer = new ADTSTrackDemuxer(mSource);
310   }
311   return mTrackDemuxer->Init();
312 }
313 
314 RefPtr<ADTSDemuxer::InitPromise>
Init()315 ADTSDemuxer::Init()
316 {
317   if (!InitInternal()) {
318     ADTSLOG("Init() failure: waiting for data");
319 
320     return InitPromise::CreateAndReject(
321       NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
322   }
323 
324   ADTSLOG("Init() successful");
325   return InitPromise::CreateAndResolve(NS_OK, __func__);
326 }
327 
328 bool
HasTrackType(TrackInfo::TrackType aType) const329 ADTSDemuxer::HasTrackType(TrackInfo::TrackType aType) const
330 {
331   return aType == TrackInfo::kAudioTrack;
332 }
333 
334 uint32_t
GetNumberTracks(TrackInfo::TrackType aType) const335 ADTSDemuxer::GetNumberTracks(TrackInfo::TrackType aType) const
336 {
337   return (aType == TrackInfo::kAudioTrack) ? 1 : 0;
338 }
339 
340 already_AddRefed<MediaTrackDemuxer>
GetTrackDemuxer(TrackInfo::TrackType aType,uint32_t aTrackNumber)341 ADTSDemuxer::GetTrackDemuxer(TrackInfo::TrackType aType, uint32_t aTrackNumber)
342 {
343   if (!mTrackDemuxer) {
344     return nullptr;
345   }
346 
347   return RefPtr<ADTSTrackDemuxer>(mTrackDemuxer).forget();
348 }
349 
350 bool
IsSeekable() const351 ADTSDemuxer::IsSeekable() const
352 {
353   int64_t length = mSource->GetLength();
354   if (length > -1)
355     return true;
356   return false;
357 }
358 
359 
360 // ADTSTrackDemuxer
ADTSTrackDemuxer(MediaResource * aSource)361 ADTSTrackDemuxer::ADTSTrackDemuxer(MediaResource* aSource)
362   : mSource(aSource)
363   , mParser(new adts::FrameParser())
364   , mOffset(0)
365   , mNumParsedFrames(0)
366   , mFrameIndex(0)
367   , mTotalFrameLen(0)
368   , mSamplesPerFrame(0)
369   , mSamplesPerSecond(0)
370   , mChannels(0)
371 {
372   Reset();
373 }
374 
~ADTSTrackDemuxer()375 ADTSTrackDemuxer::~ADTSTrackDemuxer()
376 {
377   delete mParser;
378   mParser = nullptr;
379 }
380 
381 bool
Init()382 ADTSTrackDemuxer::Init()
383 {
384 
385   FastSeek(media::TimeUnit());
386   // Read the first frame to fetch sample rate and other meta data.
387   RefPtr<MediaRawData> frame(GetNextFrame(FindNextFrame(true)));
388 
389   ADTSLOG("Init StreamLength()=%" PRId64 " first-frame-found=%d",
390           StreamLength(), !!frame);
391 
392   if (!frame) {
393     return false;
394   }
395 
396   // Rewind back to the stream begin to avoid dropping the first frame.
397   FastSeek(media::TimeUnit());
398 
399   if (!mInfo) {
400     mInfo = MakeUnique<AudioInfo>();
401   }
402 
403   mInfo->mRate = mSamplesPerSecond;
404   mInfo->mChannels = mChannels;
405   mInfo->mBitDepth = 16;
406   mInfo->mDuration = Duration().ToMicroseconds();
407 
408   // AAC Specific information
409   mInfo->mMimeType = "audio/mp4a-latm";
410 
411   // Configure AAC codec-specific values.
412 
413   // According to
414   // https://msdn.microsoft.com/en-us/library/windows/desktop/dd742784%28v=vs.85%29.aspx,
415   // wAudioProfileLevelIndication, which is passed mInfo->mProfile, is
416   // a value from Table 1.12 -- audioProfileLevelIndication values, ISO/IEC 14496-3.
417   mInfo->mProfile = ProfileLevelIndication(mParser->FirstFrame());
418   // For AAC, mExtendedProfile contains the audioObjectType from Table
419   // 1.3 -- Audio Profile definition, ISO/IEC 14496-3. Eg. 2 == AAC LC
420   mInfo->mExtendedProfile = mParser->FirstFrame().Header().mObjectType;
421   InitAudioSpecificConfig(mParser->FirstFrame(), mInfo->mCodecSpecificConfig);
422 
423   ADTSLOG("Init mInfo={mRate=%u mChannels=%u mBitDepth=%u mDuration=%" PRId64 "}",
424           mInfo->mRate, mInfo->mChannels, mInfo->mBitDepth, mInfo->mDuration);
425 
426   return mSamplesPerSecond && mChannels;
427 }
428 
429 UniquePtr<TrackInfo>
GetInfo() const430 ADTSTrackDemuxer::GetInfo() const
431 {
432   return mInfo->Clone();
433 }
434 
435 RefPtr<ADTSTrackDemuxer::SeekPromise>
Seek(media::TimeUnit aTime)436 ADTSTrackDemuxer::Seek(media::TimeUnit aTime)
437 {
438   // Efficiently seek to the position.
439   FastSeek(aTime);
440   // Correct seek position by scanning the next frames.
441   const media::TimeUnit seekTime = ScanUntil(aTime);
442 
443   return SeekPromise::CreateAndResolve(seekTime, __func__);
444 }
445 
446 media::TimeUnit
FastSeek(const media::TimeUnit & aTime)447 ADTSTrackDemuxer::FastSeek(const media::TimeUnit& aTime)
448 {
449   ADTSLOG("FastSeek(%" PRId64 ") avgFrameLen=%f mNumParsedFrames=%" PRIu64
450          " mFrameIndex=%" PRId64 " mOffset=%" PRIu64,
451          aTime.ToMicroseconds(), AverageFrameLength(), mNumParsedFrames,
452          mFrameIndex, mOffset);
453 
454   const int64_t firstFrameOffset = mParser->FirstFrame().Offset();
455   if (!aTime.ToMicroseconds()) {
456     // Quick seek to the beginning of the stream.
457     mOffset = firstFrameOffset;
458   } else if (AverageFrameLength() > 0) {
459     mOffset = firstFrameOffset + FrameIndexFromTime(aTime) *
460       AverageFrameLength();
461   }
462 
463   if (mOffset > firstFrameOffset && StreamLength() > 0) {
464     mOffset = std::min(StreamLength() - 1, mOffset);
465   }
466 
467   mFrameIndex = FrameIndexFromOffset(mOffset);
468   mParser->EndFrameSession();
469 
470   ADTSLOG("FastSeek End avgFrameLen=%f mNumParsedFrames=%" PRIu64
471           " mFrameIndex=%" PRId64 " mFirstFrameOffset=%llu mOffset=%" PRIu64
472           " SL=%llu",
473           AverageFrameLength(), mNumParsedFrames, mFrameIndex,
474           firstFrameOffset, mOffset, StreamLength());
475 
476   return Duration(mFrameIndex);
477 }
478 
479 media::TimeUnit
ScanUntil(const media::TimeUnit & aTime)480 ADTSTrackDemuxer::ScanUntil(const media::TimeUnit& aTime)
481 {
482   ADTSLOG("ScanUntil(%" PRId64 ") avgFrameLen=%f mNumParsedFrames=%" PRIu64
483           " mFrameIndex=%" PRId64 " mOffset=%" PRIu64,
484           aTime.ToMicroseconds(), AverageFrameLength(), mNumParsedFrames,
485           mFrameIndex, mOffset);
486 
487   if (!aTime.ToMicroseconds()) {
488     return FastSeek(aTime);
489   }
490 
491   if (Duration(mFrameIndex) > aTime) {
492     FastSeek(aTime);
493   }
494 
495   while (SkipNextFrame(FindNextFrame()) && Duration(mFrameIndex + 1) < aTime) {
496     ADTSLOGV("ScanUntil* avgFrameLen=%f mNumParsedFrames=%" PRIu64
497              " mFrameIndex=%" PRId64 " mOffset=%" PRIu64 " Duration=%" PRId64,
498              AverageFrameLength(), mNumParsedFrames, mFrameIndex,
499              mOffset, Duration(mFrameIndex + 1).ToMicroseconds());
500   }
501 
502   ADTSLOG("ScanUntil End avgFrameLen=%f mNumParsedFrames=%" PRIu64
503           " mFrameIndex=%" PRId64 " mOffset=%" PRIu64,
504           AverageFrameLength(), mNumParsedFrames, mFrameIndex, mOffset);
505 
506   return Duration(mFrameIndex);
507 }
508 
509 RefPtr<ADTSTrackDemuxer::SamplesPromise>
GetSamples(int32_t aNumSamples)510 ADTSTrackDemuxer::GetSamples(int32_t aNumSamples)
511 {
512   ADTSLOGV("GetSamples(%d) Begin mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
513           " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64 " mSamplesPerFrame=%d "
514           "mSamplesPerSecond=%d mChannels=%d",
515           aNumSamples, mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
516           mSamplesPerFrame, mSamplesPerSecond, mChannels);
517 
518   MOZ_ASSERT(aNumSamples);
519 
520   RefPtr<SamplesHolder> frames = new SamplesHolder();
521 
522   while (aNumSamples--) {
523     RefPtr<MediaRawData> frame(GetNextFrame(FindNextFrame()));
524     if (!frame)
525       break;
526 
527     frames->mSamples.AppendElement(frame);
528   }
529 
530   ADTSLOGV("GetSamples() End mSamples.Size()=%d aNumSamples=%d mOffset=%" PRIu64
531           " mNumParsedFrames=%" PRIu64 " mFrameIndex=%" PRId64
532           " mTotalFrameLen=%" PRIu64 " mSamplesPerFrame=%d mSamplesPerSecond=%d "
533           "mChannels=%d",
534           frames->mSamples.Length(), aNumSamples, mOffset, mNumParsedFrames,
535           mFrameIndex, mTotalFrameLen, mSamplesPerFrame, mSamplesPerSecond,
536           mChannels);
537 
538   if (frames->mSamples.IsEmpty()) {
539     return SamplesPromise::CreateAndReject(
540       NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
541   }
542 
543   return SamplesPromise::CreateAndResolve(frames, __func__);
544 }
545 
546 void
Reset()547 ADTSTrackDemuxer::Reset()
548 {
549   ADTSLOG("Reset()");
550   MOZ_ASSERT(mParser);
551   if (mParser) {
552     mParser->Reset();
553   }
554   FastSeek(media::TimeUnit());
555 }
556 
557 RefPtr<ADTSTrackDemuxer::SkipAccessPointPromise>
SkipToNextRandomAccessPoint(media::TimeUnit aTimeThreshold)558 ADTSTrackDemuxer::SkipToNextRandomAccessPoint(media::TimeUnit aTimeThreshold)
559 {
560   // Will not be called for audio-only resources.
561   return SkipAccessPointPromise::CreateAndReject(
562     SkipFailureHolder(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, 0), __func__);
563 }
564 
565 int64_t
GetResourceOffset() const566 ADTSTrackDemuxer::GetResourceOffset() const
567 {
568   return mOffset;
569 }
570 
571 media::TimeIntervals
GetBuffered()572 ADTSTrackDemuxer::GetBuffered()
573 {
574   media::TimeUnit duration = Duration();
575 
576   if (duration <= media::TimeUnit()) {
577     return media::TimeIntervals();
578   }
579 
580   AutoPinned<MediaResource> stream(mSource.GetResource());
581   return GetEstimatedBufferedTimeRanges(stream, duration.ToMicroseconds());
582 }
583 
584 int64_t
StreamLength() const585 ADTSTrackDemuxer::StreamLength() const
586 {
587   return mSource.GetLength();
588 }
589 
590 media::TimeUnit
Duration() const591 ADTSTrackDemuxer::Duration() const
592 {
593   if (!mNumParsedFrames) {
594     return media::TimeUnit::FromMicroseconds(-1);
595   }
596 
597   const int64_t streamLen = StreamLength();
598   if (streamLen < 0) {
599     // Unknown length, we can't estimate duration.
600     return media::TimeUnit::FromMicroseconds(-1);
601   }
602   const int64_t firstFrameOffset = mParser->FirstFrame().Offset();
603   int64_t numFrames = (streamLen - firstFrameOffset) / AverageFrameLength();
604   return Duration(numFrames);
605 }
606 
607 media::TimeUnit
Duration(int64_t aNumFrames) const608 ADTSTrackDemuxer::Duration(int64_t aNumFrames) const
609 {
610   if (!mSamplesPerSecond) {
611     return media::TimeUnit::FromMicroseconds(-1);
612   }
613 
614   return FramesToTimeUnit(aNumFrames * mSamplesPerFrame, mSamplesPerSecond);
615 }
616 
617 const adts::Frame&
FindNextFrame(bool findFirstFrame)618 ADTSTrackDemuxer::FindNextFrame(bool findFirstFrame /*= false*/)
619 {
620   static const int BUFFER_SIZE = 4096;
621   static const int MAX_SKIPPED_BYTES = 10 * BUFFER_SIZE;
622 
623   ADTSLOGV("FindNext() Begin mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
624           " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
625           " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
626           mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
627           mSamplesPerFrame, mSamplesPerSecond, mChannels);
628 
629   uint8_t buffer[BUFFER_SIZE];
630   int32_t read = 0;
631 
632   bool foundFrame = false;
633   int64_t frameHeaderOffset = mOffset;
634 
635   // Prepare the parser for the next frame parsing session.
636   mParser->EndFrameSession();
637 
638   // Check whether we've found a valid ADTS frame.
639   while (!foundFrame) {
640     if ((read = Read(buffer, frameHeaderOffset, BUFFER_SIZE)) == 0) {
641       ADTSLOG("FindNext() EOS without a frame");
642       break;
643     }
644 
645     if (frameHeaderOffset - mOffset > MAX_SKIPPED_BYTES) {
646       ADTSLOG("FindNext() exceeded MAX_SKIPPED_BYTES without a frame");
647       break;
648     }
649 
650     const adts::Frame& currentFrame = mParser->CurrentFrame();
651     foundFrame = mParser->Parse(frameHeaderOffset, buffer, buffer + read);
652     if (findFirstFrame && foundFrame) {
653       // Check for sync marker after the found frame, since it's
654       // possible to find sync marker in AAC data. If sync marker
655       // exists after the current frame then we've found a frame
656       // header.
657       int64_t nextFrameHeaderOffset = currentFrame.Offset() + currentFrame.Length();
658       int32_t read = Read(buffer, nextFrameHeaderOffset, 2);
659       if (read != 2 || !adts::FrameHeader::MatchesSync(buffer)) {
660         frameHeaderOffset = currentFrame.Offset() + 1;
661         mParser->Reset();
662         foundFrame = false;
663         continue;
664       }
665     }
666 
667     if (foundFrame) {
668       break;
669     }
670 
671     // Minimum header size is 7 bytes.
672     int64_t advance = read - 7;
673 
674     // Check for offset overflow.
675     if (frameHeaderOffset + advance <= frameHeaderOffset) {
676       break;
677     }
678 
679     frameHeaderOffset += advance;
680   }
681 
682   if (!foundFrame || !mParser->CurrentFrame().Length()) {
683     ADTSLOG("FindNext() Exit foundFrame=%d mParser->CurrentFrame().Length()=%d ",
684            foundFrame, mParser->CurrentFrame().Length());
685     mParser->Reset();
686     return mParser->CurrentFrame();
687   }
688 
689   ADTSLOGV("FindNext() End mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
690           " mFrameIndex=%" PRId64 " frameHeaderOffset=%d"
691           " mTotalFrameLen=%" PRIu64 " mSamplesPerFrame=%d mSamplesPerSecond=%d"
692           " mChannels=%d",
693           mOffset, mNumParsedFrames, mFrameIndex, frameHeaderOffset,
694           mTotalFrameLen, mSamplesPerFrame, mSamplesPerSecond, mChannels);
695 
696   return mParser->CurrentFrame();
697 }
698 
699 bool
SkipNextFrame(const adts::Frame & aFrame)700 ADTSTrackDemuxer::SkipNextFrame(const adts::Frame& aFrame)
701 {
702   if (!mNumParsedFrames || !aFrame.Length()) {
703     RefPtr<MediaRawData> frame(GetNextFrame(aFrame));
704     return frame;
705   }
706 
707   UpdateState(aFrame);
708 
709   ADTSLOGV("SkipNext() End mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
710           " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
711           " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
712           mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
713           mSamplesPerFrame, mSamplesPerSecond, mChannels);
714 
715   return true;
716 }
717 
718 already_AddRefed<MediaRawData>
GetNextFrame(const adts::Frame & aFrame)719 ADTSTrackDemuxer::GetNextFrame(const adts::Frame& aFrame)
720 {
721   ADTSLOG("GetNext() Begin({mOffset=%" PRId64 " HeaderSize()=%d Length()=%d})",
722          aFrame.Offset(), aFrame.Header().HeaderSize(), aFrame.PayloadLength());
723   if (!aFrame.IsValid())
724     return nullptr;
725 
726   const int64_t offset = aFrame.PayloadOffset();
727   const uint32_t length = aFrame.PayloadLength();
728 
729   RefPtr<MediaRawData> frame = new MediaRawData();
730   frame->mOffset = offset;
731 
732   nsAutoPtr<MediaRawDataWriter> frameWriter(frame->CreateWriter());
733   if (!frameWriter->SetSize(length)) {
734     ADTSLOG("GetNext() Exit failed to allocated media buffer");
735     return nullptr;
736   }
737 
738   const uint32_t read = Read(frameWriter->Data(), offset, length);
739   if (read != length) {
740     ADTSLOG("GetNext() Exit read=%u frame->Size()=%u", read, frame->Size());
741     return nullptr;
742   }
743 
744   UpdateState(aFrame);
745 
746   frame->mTime = Duration(mFrameIndex - 1).ToMicroseconds();
747   frame->mDuration = Duration(1).ToMicroseconds();
748   frame->mTimecode = frame->mTime;
749   frame->mKeyframe = true;
750 
751   MOZ_ASSERT(frame->mTime >= 0);
752   MOZ_ASSERT(frame->mDuration > 0);
753 
754   ADTSLOGV("GetNext() End mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
755           " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
756           " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
757           mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
758           mSamplesPerFrame, mSamplesPerSecond, mChannels);
759 
760   return frame.forget();
761 }
762 
763 int64_t
FrameIndexFromOffset(int64_t aOffset) const764 ADTSTrackDemuxer::FrameIndexFromOffset(int64_t aOffset) const
765 {
766   int64_t frameIndex = 0;
767 
768   if (AverageFrameLength() > 0) {
769     frameIndex = (aOffset - mParser->FirstFrame().Offset()) / AverageFrameLength();
770   }
771 
772   ADTSLOGV("FrameIndexFromOffset(%" PRId64 ") -> %" PRId64, aOffset, frameIndex);
773   return std::max<int64_t>(0, frameIndex);
774 }
775 
776 int64_t
FrameIndexFromTime(const media::TimeUnit & aTime) const777 ADTSTrackDemuxer::FrameIndexFromTime(const media::TimeUnit& aTime) const
778 {
779   int64_t frameIndex = 0;
780   if (mSamplesPerSecond > 0 && mSamplesPerFrame > 0) {
781     frameIndex = aTime.ToSeconds() * mSamplesPerSecond / mSamplesPerFrame - 1;
782   }
783 
784   ADTSLOGV("FrameIndexFromOffset(%fs) -> %" PRId64, aTime.ToSeconds(), frameIndex);
785   return std::max<int64_t>(0, frameIndex);
786 }
787 
788 void
UpdateState(const adts::Frame & aFrame)789 ADTSTrackDemuxer::UpdateState(const adts::Frame& aFrame)
790 {
791   int32_t frameLength = aFrame.Length();
792   // Prevent overflow.
793   if (mTotalFrameLen + frameLength < mTotalFrameLen) {
794     // These variables have a linear dependency and are only used to derive the
795     // average frame length.
796     mTotalFrameLen /= 2;
797     mNumParsedFrames /= 2;
798   }
799 
800   // Full frame parsed, move offset to its end.
801   mOffset = aFrame.Offset() + frameLength;
802   mTotalFrameLen += frameLength;
803 
804   if (!mSamplesPerFrame) {
805     const adts::FrameHeader& header = aFrame.Header();
806     mSamplesPerFrame = header.mSamples;
807     mSamplesPerSecond = header.mSampleRate;
808     mChannels = header.mChannels;
809   }
810 
811   ++mNumParsedFrames;
812   ++mFrameIndex;
813   MOZ_ASSERT(mFrameIndex > 0);
814 }
815 
816 int32_t
Read(uint8_t * aBuffer,int64_t aOffset,int32_t aSize)817 ADTSTrackDemuxer::Read(uint8_t* aBuffer, int64_t aOffset, int32_t aSize)
818 {
819   ADTSLOGV("ADTSTrackDemuxer::Read(%p %" PRId64 " %d)", aBuffer, aOffset, aSize);
820 
821   const int64_t streamLen = StreamLength();
822   if (mInfo && streamLen > 0) {
823     // Prevent blocking reads after successful initialization.
824     aSize = std::min<int64_t>(aSize, streamLen - aOffset);
825   }
826 
827   uint32_t read = 0;
828   ADTSLOGV("ADTSTrackDemuxer::Read        -> ReadAt(%d)", aSize);
829   const nsresult rv = mSource.ReadAt(aOffset, reinterpret_cast<char*>(aBuffer),
830                                      static_cast<uint32_t>(aSize), &read);
831   NS_ENSURE_SUCCESS(rv, 0);
832   return static_cast<int32_t>(read);
833 }
834 
835 double
AverageFrameLength() const836 ADTSTrackDemuxer::AverageFrameLength() const
837 {
838   if (mNumParsedFrames) {
839     return static_cast<double>(mTotalFrameLen) / mNumParsedFrames;
840   }
841 
842   return 0.0;
843 }
844 
845 } // namespace mozilla
846