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 size_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 =
93 (p[3] & 0x03) << 11 | (p[4] & 0xFF) << 3 | (p[5] & 0xE0) >> 5;
94 mNumAACFrames = (p[6] & 0x03) + 1;
95
96 static const int32_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 int64_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 int64_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(int64_t aOffset,const uint8_t * aStart,const uint8_t * aEnd)151 bool Parse(int64_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 + (ptr - aStart) - 1;
164
165 return found;
166 }
167
168 private:
169 // The offset to the start of the header.
170 int64_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(int64_t aOffset,const uint8_t * aStart,const uint8_t * aEnd)200 bool Parse(int64_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 (!mInfo) {
317 mInfo = MakeUnique<AudioInfo>();
318 }
319
320 mInfo->mRate = mSamplesPerSecond;
321 mInfo->mChannels = mChannels;
322 mInfo->mBitDepth = 16;
323 mInfo->mDuration = Duration();
324
325 // AAC Specific information
326 mInfo->mMimeType = "audio/mp4a-latm";
327
328 // Configure AAC codec-specific values.
329 // For AAC, mProfile and mExtendedProfile contain the audioObjectType from
330 // Table 1.3 -- Audio Profile definition, ISO/IEC 14496-3. Eg. 2 == AAC LC
331 mInfo->mProfile = mInfo->mExtendedProfile =
332 mParser->FirstFrame().Header().mObjectType;
333 InitAudioSpecificConfig(mParser->FirstFrame(), mInfo->mCodecSpecificConfig);
334
335 ADTSLOG("Init mInfo={mRate=%u mChannels=%u mBitDepth=%u mDuration=%" PRId64
336 "}",
337 mInfo->mRate, mInfo->mChannels, mInfo->mBitDepth,
338 mInfo->mDuration.ToMicroseconds());
339
340 return mSamplesPerSecond && mChannels;
341 }
342
GetInfo() const343 UniquePtr<TrackInfo> ADTSTrackDemuxer::GetInfo() const {
344 return mInfo->Clone();
345 }
346
Seek(const TimeUnit & aTime)347 RefPtr<ADTSTrackDemuxer::SeekPromise> ADTSTrackDemuxer::Seek(
348 const TimeUnit& aTime) {
349 // Efficiently seek to the position.
350 FastSeek(aTime);
351 // Correct seek position by scanning the next frames.
352 const TimeUnit seekTime = ScanUntil(aTime);
353
354 return SeekPromise::CreateAndResolve(seekTime, __func__);
355 }
356
FastSeek(const TimeUnit & aTime)357 TimeUnit ADTSTrackDemuxer::FastSeek(const TimeUnit& aTime) {
358 ADTSLOG("FastSeek(%" PRId64 ") avgFrameLen=%f mNumParsedFrames=%" PRIu64
359 " mFrameIndex=%" PRId64 " mOffset=%" PRIu64,
360 aTime.ToMicroseconds(), AverageFrameLength(), mNumParsedFrames,
361 mFrameIndex, mOffset);
362
363 const int64_t firstFrameOffset = mParser->FirstFrame().Offset();
364 if (!aTime.ToMicroseconds()) {
365 // Quick seek to the beginning of the stream.
366 mOffset = firstFrameOffset;
367 } else if (AverageFrameLength() > 0) {
368 mOffset =
369 firstFrameOffset + FrameIndexFromTime(aTime) * AverageFrameLength();
370 }
371
372 if (mOffset > firstFrameOffset && StreamLength() > 0) {
373 mOffset = std::min(StreamLength() - 1, mOffset);
374 }
375
376 mFrameIndex = FrameIndexFromOffset(mOffset);
377 mParser->EndFrameSession();
378
379 ADTSLOG("FastSeek End avgFrameLen=%f mNumParsedFrames=%" PRIu64
380 " mFrameIndex=%" PRId64 " mFirstFrameOffset=%" PRIu64
381 " mOffset=%" PRIu64 " SL=%" PRIu64 "",
382 AverageFrameLength(), mNumParsedFrames, mFrameIndex, firstFrameOffset,
383 mOffset, StreamLength());
384
385 return Duration(mFrameIndex);
386 }
387
ScanUntil(const TimeUnit & aTime)388 TimeUnit ADTSTrackDemuxer::ScanUntil(const TimeUnit& aTime) {
389 ADTSLOG("ScanUntil(%" PRId64 ") avgFrameLen=%f mNumParsedFrames=%" PRIu64
390 " mFrameIndex=%" PRId64 " mOffset=%" PRIu64,
391 aTime.ToMicroseconds(), AverageFrameLength(), mNumParsedFrames,
392 mFrameIndex, mOffset);
393
394 if (!aTime.ToMicroseconds()) {
395 return FastSeek(aTime);
396 }
397
398 if (Duration(mFrameIndex) > aTime) {
399 FastSeek(aTime);
400 }
401
402 while (SkipNextFrame(FindNextFrame()) && Duration(mFrameIndex + 1) < aTime) {
403 ADTSLOGV("ScanUntil* avgFrameLen=%f mNumParsedFrames=%" PRIu64
404 " mFrameIndex=%" PRId64 " mOffset=%" PRIu64 " Duration=%" PRId64,
405 AverageFrameLength(), mNumParsedFrames, mFrameIndex, mOffset,
406 Duration(mFrameIndex + 1).ToMicroseconds());
407 }
408
409 ADTSLOG("ScanUntil End avgFrameLen=%f mNumParsedFrames=%" PRIu64
410 " mFrameIndex=%" PRId64 " mOffset=%" PRIu64,
411 AverageFrameLength(), mNumParsedFrames, mFrameIndex, mOffset);
412
413 return Duration(mFrameIndex);
414 }
415
GetSamples(int32_t aNumSamples)416 RefPtr<ADTSTrackDemuxer::SamplesPromise> ADTSTrackDemuxer::GetSamples(
417 int32_t aNumSamples) {
418 ADTSLOGV("GetSamples(%d) Begin mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
419 " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
420 " mSamplesPerFrame=%d "
421 "mSamplesPerSecond=%d mChannels=%d",
422 aNumSamples, mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
423 mSamplesPerFrame, mSamplesPerSecond, mChannels);
424
425 MOZ_ASSERT(aNumSamples);
426
427 RefPtr<SamplesHolder> frames = new SamplesHolder();
428
429 while (aNumSamples--) {
430 RefPtr<MediaRawData> frame(GetNextFrame(FindNextFrame()));
431 if (!frame) break;
432
433 frames->mSamples.AppendElement(frame);
434 }
435
436 ADTSLOGV(
437 "GetSamples() End mSamples.Size()=%zu aNumSamples=%d mOffset=%" PRIu64
438 " mNumParsedFrames=%" PRIu64 " mFrameIndex=%" PRId64
439 " mTotalFrameLen=%" PRIu64
440 " mSamplesPerFrame=%d mSamplesPerSecond=%d "
441 "mChannels=%d",
442 frames->mSamples.Length(), aNumSamples, mOffset, mNumParsedFrames,
443 mFrameIndex, mTotalFrameLen, mSamplesPerFrame, mSamplesPerSecond,
444 mChannels);
445
446 if (frames->mSamples.IsEmpty()) {
447 return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM,
448 __func__);
449 }
450
451 return SamplesPromise::CreateAndResolve(frames, __func__);
452 }
453
Reset()454 void ADTSTrackDemuxer::Reset() {
455 ADTSLOG("Reset()");
456 MOZ_ASSERT(mParser);
457 if (mParser) {
458 mParser->Reset();
459 }
460 FastSeek(TimeUnit::Zero());
461 }
462
463 RefPtr<ADTSTrackDemuxer::SkipAccessPointPromise>
SkipToNextRandomAccessPoint(const TimeUnit & aTimeThreshold)464 ADTSTrackDemuxer::SkipToNextRandomAccessPoint(const TimeUnit& aTimeThreshold) {
465 // Will not be called for audio-only resources.
466 return SkipAccessPointPromise::CreateAndReject(
467 SkipFailureHolder(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, 0), __func__);
468 }
469
GetResourceOffset() const470 int64_t ADTSTrackDemuxer::GetResourceOffset() const { return mOffset; }
471
GetBuffered()472 media::TimeIntervals ADTSTrackDemuxer::GetBuffered() {
473 auto duration = Duration();
474
475 if (!duration.IsPositive()) {
476 return media::TimeIntervals();
477 }
478
479 AutoPinned<MediaResource> stream(mSource.GetResource());
480 return GetEstimatedBufferedTimeRanges(stream, duration.ToMicroseconds());
481 }
482
StreamLength() const483 int64_t ADTSTrackDemuxer::StreamLength() const { return mSource.GetLength(); }
484
Duration() const485 TimeUnit ADTSTrackDemuxer::Duration() const {
486 if (!mNumParsedFrames) {
487 return TimeUnit::FromMicroseconds(-1);
488 }
489
490 const int64_t streamLen = StreamLength();
491 if (streamLen < 0) {
492 // Unknown length, we can't estimate duration.
493 return TimeUnit::FromMicroseconds(-1);
494 }
495 const int64_t firstFrameOffset = mParser->FirstFrame().Offset();
496 int64_t numFrames = (streamLen - firstFrameOffset) / AverageFrameLength();
497 return Duration(numFrames);
498 }
499
Duration(int64_t aNumFrames) const500 TimeUnit ADTSTrackDemuxer::Duration(int64_t aNumFrames) const {
501 if (!mSamplesPerSecond) {
502 return TimeUnit::FromMicroseconds(-1);
503 }
504
505 return FramesToTimeUnit(aNumFrames * mSamplesPerFrame, mSamplesPerSecond);
506 }
507
FindNextFrame(bool findFirstFrame)508 const adts::Frame& ADTSTrackDemuxer::FindNextFrame(
509 bool findFirstFrame /*= false*/) {
510 static const int BUFFER_SIZE = 4096;
511 static const int MAX_SKIPPED_BYTES = 10 * BUFFER_SIZE;
512
513 ADTSLOGV("FindNext() Begin mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
514 " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
515 " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
516 mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
517 mSamplesPerFrame, mSamplesPerSecond, mChannels);
518
519 uint8_t buffer[BUFFER_SIZE];
520 int32_t read = 0;
521
522 bool foundFrame = false;
523 int64_t frameHeaderOffset = mOffset;
524
525 // Prepare the parser for the next frame parsing session.
526 mParser->EndFrameSession();
527
528 // Check whether we've found a valid ADTS frame.
529 while (!foundFrame) {
530 if ((read = Read(buffer, frameHeaderOffset, BUFFER_SIZE)) == 0) {
531 ADTSLOG("FindNext() EOS without a frame");
532 break;
533 }
534
535 if (frameHeaderOffset - mOffset > MAX_SKIPPED_BYTES) {
536 ADTSLOG("FindNext() exceeded MAX_SKIPPED_BYTES without a frame");
537 break;
538 }
539
540 const adts::Frame& currentFrame = mParser->CurrentFrame();
541 foundFrame = mParser->Parse(frameHeaderOffset, buffer, buffer + read);
542 if (findFirstFrame && foundFrame) {
543 // Check for sync marker after the found frame, since it's
544 // possible to find sync marker in AAC data. If sync marker
545 // exists after the current frame then we've found a frame
546 // header.
547 int64_t nextFrameHeaderOffset =
548 currentFrame.Offset() + currentFrame.Length();
549 int32_t read = Read(buffer, nextFrameHeaderOffset, 2);
550 if (read != 2 || !adts::FrameHeader::MatchesSync(buffer)) {
551 frameHeaderOffset = currentFrame.Offset() + 1;
552 mParser->Reset();
553 foundFrame = false;
554 continue;
555 }
556 }
557
558 if (foundFrame) {
559 break;
560 }
561
562 // Minimum header size is 7 bytes.
563 int64_t advance = read - 7;
564
565 // Check for offset overflow.
566 if (frameHeaderOffset + advance <= frameHeaderOffset) {
567 break;
568 }
569
570 frameHeaderOffset += advance;
571 }
572
573 if (!foundFrame || !mParser->CurrentFrame().Length()) {
574 ADTSLOG(
575 "FindNext() Exit foundFrame=%d mParser->CurrentFrame().Length()=%zu ",
576 foundFrame, mParser->CurrentFrame().Length());
577 mParser->Reset();
578 return mParser->CurrentFrame();
579 }
580
581 ADTSLOGV("FindNext() End mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
582 " mFrameIndex=%" PRId64 " frameHeaderOffset=%" PRId64
583 " mTotalFrameLen=%" PRIu64
584 " mSamplesPerFrame=%d mSamplesPerSecond=%d"
585 " mChannels=%d",
586 mOffset, mNumParsedFrames, mFrameIndex, frameHeaderOffset,
587 mTotalFrameLen, mSamplesPerFrame, mSamplesPerSecond, mChannels);
588
589 return mParser->CurrentFrame();
590 }
591
SkipNextFrame(const adts::Frame & aFrame)592 bool ADTSTrackDemuxer::SkipNextFrame(const adts::Frame& aFrame) {
593 if (!mNumParsedFrames || !aFrame.Length()) {
594 RefPtr<MediaRawData> frame(GetNextFrame(aFrame));
595 return frame;
596 }
597
598 UpdateState(aFrame);
599
600 ADTSLOGV("SkipNext() End mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
601 " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
602 " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
603 mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
604 mSamplesPerFrame, mSamplesPerSecond, mChannels);
605
606 return true;
607 }
608
GetNextFrame(const adts::Frame & aFrame)609 already_AddRefed<MediaRawData> ADTSTrackDemuxer::GetNextFrame(
610 const adts::Frame& aFrame) {
611 ADTSLOG("GetNext() Begin({mOffset=%" PRId64
612 " HeaderSize()=%zu"
613 " Length()=%zu})",
614 aFrame.Offset(), aFrame.Header().HeaderSize(),
615 aFrame.PayloadLength());
616 if (!aFrame.IsValid()) return nullptr;
617
618 const int64_t offset = aFrame.PayloadOffset();
619 const uint32_t length = aFrame.PayloadLength();
620
621 RefPtr<MediaRawData> frame = new MediaRawData();
622 frame->mOffset = offset;
623
624 UniquePtr<MediaRawDataWriter> frameWriter(frame->CreateWriter());
625 if (!frameWriter->SetSize(length)) {
626 ADTSLOG("GetNext() Exit failed to allocated media buffer");
627 return nullptr;
628 }
629
630 const uint32_t read = Read(frameWriter->Data(), offset, length);
631 if (read != length) {
632 ADTSLOG("GetNext() Exit read=%u frame->Size()=%zu", read, frame->Size());
633 return nullptr;
634 }
635
636 UpdateState(aFrame);
637
638 frame->mTime = Duration(mFrameIndex - 1);
639 frame->mDuration = Duration(1);
640 frame->mTimecode = frame->mTime;
641 frame->mKeyframe = true;
642
643 MOZ_ASSERT(!frame->mTime.IsNegative());
644 MOZ_ASSERT(frame->mDuration.IsPositive());
645
646 ADTSLOGV("GetNext() End mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
647 " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
648 " mSamplesPerFrame=%d mSamplesPerSecond=%d mChannels=%d",
649 mOffset, mNumParsedFrames, mFrameIndex, mTotalFrameLen,
650 mSamplesPerFrame, mSamplesPerSecond, mChannels);
651
652 return frame.forget();
653 }
654
FrameIndexFromOffset(int64_t aOffset) const655 int64_t ADTSTrackDemuxer::FrameIndexFromOffset(int64_t aOffset) const {
656 int64_t frameIndex = 0;
657
658 if (AverageFrameLength() > 0) {
659 frameIndex =
660 (aOffset - mParser->FirstFrame().Offset()) / AverageFrameLength();
661 }
662
663 ADTSLOGV("FrameIndexFromOffset(%" PRId64 ") -> %" PRId64, aOffset,
664 frameIndex);
665 return std::max<int64_t>(0, frameIndex);
666 }
667
FrameIndexFromTime(const TimeUnit & aTime) const668 int64_t ADTSTrackDemuxer::FrameIndexFromTime(const TimeUnit& aTime) const {
669 int64_t frameIndex = 0;
670 if (mSamplesPerSecond > 0 && mSamplesPerFrame > 0) {
671 frameIndex = aTime.ToSeconds() * mSamplesPerSecond / mSamplesPerFrame - 1;
672 }
673
674 ADTSLOGV("FrameIndexFromOffset(%fs) -> %" PRId64, aTime.ToSeconds(),
675 frameIndex);
676 return std::max<int64_t>(0, frameIndex);
677 }
678
UpdateState(const adts::Frame & aFrame)679 void ADTSTrackDemuxer::UpdateState(const adts::Frame& aFrame) {
680 int32_t frameLength = aFrame.Length();
681 // Prevent overflow.
682 if (mTotalFrameLen + frameLength < mTotalFrameLen) {
683 // These variables have a linear dependency and are only used to derive the
684 // average frame length.
685 mTotalFrameLen /= 2;
686 mNumParsedFrames /= 2;
687 }
688
689 // Full frame parsed, move offset to its end.
690 mOffset = aFrame.Offset() + frameLength;
691 mTotalFrameLen += frameLength;
692
693 if (!mSamplesPerFrame) {
694 const adts::FrameHeader& header = aFrame.Header();
695 mSamplesPerFrame = header.mSamples;
696 mSamplesPerSecond = header.mSampleRate;
697 mChannels = header.mChannels;
698 }
699
700 ++mNumParsedFrames;
701 ++mFrameIndex;
702 MOZ_ASSERT(mFrameIndex > 0);
703 }
704
Read(uint8_t * aBuffer,int64_t aOffset,int32_t aSize)705 int32_t ADTSTrackDemuxer::Read(uint8_t* aBuffer, int64_t aOffset,
706 int32_t aSize) {
707 ADTSLOGV("ADTSTrackDemuxer::Read(%p %" PRId64 " %d)", aBuffer, aOffset,
708 aSize);
709
710 const int64_t streamLen = StreamLength();
711 if (mInfo && streamLen > 0) {
712 // Prevent blocking reads after successful initialization.
713 aSize = std::min<int64_t>(aSize, streamLen - aOffset);
714 }
715
716 uint32_t read = 0;
717 ADTSLOGV("ADTSTrackDemuxer::Read -> ReadAt(%d)", aSize);
718 const nsresult rv = mSource.ReadAt(aOffset, reinterpret_cast<char*>(aBuffer),
719 static_cast<uint32_t>(aSize), &read);
720 NS_ENSURE_SUCCESS(rv, 0);
721 return static_cast<int32_t>(read);
722 }
723
AverageFrameLength() const724 double ADTSTrackDemuxer::AverageFrameLength() const {
725 if (mNumParsedFrames) {
726 return static_cast<double>(mTotalFrameLen) / mNumParsedFrames;
727 }
728
729 return 0.0;
730 }
731
ADTSSniffer(const uint8_t * aData,const uint32_t aLength)732 /* static */ bool ADTSDemuxer::ADTSSniffer(const uint8_t* aData,
733 const uint32_t aLength) {
734 if (aLength < 7) {
735 return false;
736 }
737 if (!adts::FrameHeader::MatchesSync(aData)) {
738 return false;
739 }
740 auto parser = MakeUnique<adts::FrameParser>();
741
742 if (!parser->Parse(0, aData, aData + aLength)) {
743 return false;
744 }
745 const adts::Frame& currentFrame = parser->CurrentFrame();
746 // Check for sync marker after the found frame, since it's
747 // possible to find sync marker in AAC data. If sync marker
748 // exists after the current frame then we've found a frame
749 // header.
750 int64_t nextFrameHeaderOffset = currentFrame.Offset() + currentFrame.Length();
751 return int64_t(aLength) > nextFrameHeaderOffset &&
752 aLength - nextFrameHeaderOffset >= 2 &&
753 adts::FrameHeader::MatchesSync(aData + nextFrameHeaderOffset);
754 }
755
756 } // namespace mozilla
757