Coverage Report

Created: 2018-09-25 14:53

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