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