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