Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
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 "WaveDemuxer.h"
8 :
9 : #include <inttypes.h>
10 : #include <algorithm>
11 :
12 : #include "mozilla/Assertions.h"
13 : #include "mozilla/EndianUtils.h"
14 : #include "nsAutoPtr.h"
15 : #include "VideoUtils.h"
16 : #include "TimeUnits.h"
17 : #include "prenv.h"
18 :
19 : using mozilla::media::TimeUnit;
20 : using mozilla::media::TimeIntervals;
21 : using mp4_demuxer::ByteReader;
22 :
23 : namespace mozilla {
24 :
25 : // WAVDemuxer
26 :
27 0 : WAVDemuxer::WAVDemuxer(MediaResource* aSource)
28 0 : : mSource(aSource)
29 : {
30 0 : }
31 :
32 : bool
33 0 : WAVDemuxer::InitInternal()
34 : {
35 0 : if (!mTrackDemuxer) {
36 0 : mTrackDemuxer = new WAVTrackDemuxer(mSource.GetResource());
37 : }
38 0 : return mTrackDemuxer->Init();
39 : }
40 :
41 : RefPtr<WAVDemuxer::InitPromise>
42 0 : WAVDemuxer::Init()
43 : {
44 0 : if (!InitInternal()) {
45 : return InitPromise::CreateAndReject(
46 0 : NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
47 : }
48 0 : return InitPromise::CreateAndResolve(NS_OK, __func__);
49 : }
50 :
51 : bool
52 0 : WAVDemuxer::HasTrackType(TrackInfo::TrackType aType) const
53 : {
54 0 : return aType == TrackInfo::kAudioTrack;
55 : }
56 :
57 : uint32_t
58 0 : WAVDemuxer::GetNumberTracks(TrackInfo::TrackType aType) const
59 : {
60 0 : return aType == TrackInfo::kAudioTrack ? 1u : 0u;
61 : }
62 :
63 : already_AddRefed<MediaTrackDemuxer>
64 0 : WAVDemuxer::GetTrackDemuxer(TrackInfo::TrackType aType, uint32_t aTrackNumber)
65 : {
66 0 : if (!mTrackDemuxer) {
67 0 : return nullptr;
68 : }
69 0 : return RefPtr<WAVTrackDemuxer>(mTrackDemuxer).forget();
70 : }
71 :
72 : bool
73 0 : WAVDemuxer::IsSeekable() const
74 : {
75 0 : return true;
76 : }
77 :
78 : // WAVTrackDemuxer
79 :
80 0 : WAVTrackDemuxer::WAVTrackDemuxer(MediaResource* aSource)
81 : : mSource(aSource)
82 : , mOffset(0)
83 : , mFirstChunkOffset(0)
84 : , mNumParsedChunks(0)
85 : , mChunkIndex(0)
86 : , mTotalChunkLen(0)
87 : , mSamplesPerChunk(0)
88 : , mSamplesPerSecond(0)
89 0 : , mChannels(0)
90 : {
91 0 : Reset();
92 0 : }
93 :
94 : bool
95 0 : WAVTrackDemuxer::Init()
96 : {
97 0 : Reset();
98 0 : FastSeek(TimeUnit());
99 :
100 0 : if (!mInfo) {
101 0 : mInfo = MakeUnique<AudioInfo>();
102 : }
103 :
104 0 : if (!RIFFParserInit()) {
105 0 : return false;
106 : }
107 :
108 : while (true) {
109 0 : if (!HeaderParserInit()) {
110 0 : return false;
111 : }
112 :
113 0 : uint32_t aChunkName = mHeaderParser.GiveHeader().ChunkName();
114 0 : uint32_t aChunkSize = mHeaderParser.GiveHeader().ChunkSize();
115 :
116 0 : if (aChunkName == FRMT_CODE) {
117 0 : if (!FmtChunkParserInit()) {
118 0 : return false;
119 : }
120 0 : } else if (aChunkName == LIST_CODE) {
121 0 : mHeaderParser.Reset();
122 0 : uint64_t endOfListChunk = static_cast<uint64_t>(mOffset) + aChunkSize;
123 0 : if (endOfListChunk > UINT32_MAX) {
124 0 : return false;
125 : }
126 0 : if (!ListChunkParserInit(aChunkSize)) {
127 0 : mOffset = endOfListChunk;
128 : }
129 0 : } else if (aChunkName == DATA_CODE) {
130 0 : mDataLength = aChunkSize;
131 0 : if (mFirstChunkOffset != mOffset) {
132 0 : mFirstChunkOffset = mOffset;
133 : }
134 0 : break;
135 : } else {
136 0 : mOffset += aChunkSize; // Skip other irrelevant chunks.
137 : }
138 0 : if (mOffset & 1) {
139 : // Wave files are 2-byte aligned so we need to round up
140 0 : mOffset += 1;
141 : }
142 0 : mHeaderParser.Reset();
143 0 : }
144 :
145 0 : if (mDataLength > StreamLength() - mFirstChunkOffset) {
146 0 : mDataLength = StreamLength() - mFirstChunkOffset;
147 : }
148 :
149 0 : mSamplesPerSecond = mFmtParser.FmtChunk().SampleRate();
150 0 : mChannels = mFmtParser.FmtChunk().Channels();
151 0 : mSampleFormat = mFmtParser.FmtChunk().SampleFormat();
152 0 : if (!mSamplesPerSecond || !mChannels || !mSampleFormat) {
153 0 : return false;
154 : }
155 0 : mSamplesPerChunk = DATA_CHUNK_SIZE * 8 / mChannels / mSampleFormat;
156 :
157 0 : mInfo->mRate = mSamplesPerSecond;
158 0 : mInfo->mChannels = mChannels;
159 0 : mInfo->mBitDepth = mSampleFormat;
160 0 : mInfo->mProfile = mFmtParser.FmtChunk().WaveFormat() & 0x00FF;
161 0 : mInfo->mExtendedProfile = (mFmtParser.FmtChunk().WaveFormat() & 0xFF00) >> 8;
162 0 : mInfo->mMimeType = "audio/wave; codecs=";
163 0 : mInfo->mMimeType.AppendInt(mFmtParser.FmtChunk().WaveFormat());
164 0 : mInfo->mDuration = Duration();
165 :
166 0 : return mInfo->mDuration.IsPositive();
167 : }
168 :
169 : bool
170 0 : WAVTrackDemuxer::RIFFParserInit()
171 : {
172 0 : RefPtr<MediaRawData> riffHeader = GetFileHeader(FindRIFFHeader());
173 0 : if (!riffHeader) {
174 0 : return false;
175 : }
176 0 : ByteReader RIFFReader(riffHeader->Data(), 12);
177 0 : mRIFFParser.Parse(RIFFReader);
178 0 : return mRIFFParser.RiffHeader().IsValid(11);
179 : }
180 :
181 : bool
182 0 : WAVTrackDemuxer::HeaderParserInit()
183 : {
184 0 : RefPtr<MediaRawData> header = GetFileHeader(FindChunkHeader());
185 0 : if (!header) {
186 0 : return false;
187 : }
188 0 : ByteReader HeaderReader(header->Data(), 8);
189 0 : mHeaderParser.Parse(HeaderReader);
190 0 : return true;
191 : }
192 :
193 : bool
194 0 : WAVTrackDemuxer::FmtChunkParserInit()
195 : {
196 0 : RefPtr<MediaRawData> fmtChunk = GetFileHeader(FindFmtChunk());
197 0 : if (!fmtChunk) {
198 0 : return false;
199 : }
200 : ByteReader fmtReader(fmtChunk->Data(),
201 0 : mHeaderParser.GiveHeader().ChunkSize());
202 0 : mFmtParser.Parse(fmtReader);
203 0 : return true;
204 : }
205 :
206 : bool
207 0 : WAVTrackDemuxer::ListChunkParserInit(uint32_t aChunkSize)
208 : {
209 0 : uint32_t bytesRead = 0;
210 :
211 0 : RefPtr<MediaRawData> infoTag = GetFileHeader(FindInfoTag());
212 0 : if (!infoTag) {
213 0 : return false;
214 : }
215 0 : ByteReader infoTagReader(infoTag->Data(), 4);
216 0 : if (!infoTagReader.CanRead32() || infoTagReader.ReadU32() != INFO_CODE) {
217 0 : return false;
218 : }
219 :
220 0 : bytesRead += 4;
221 :
222 0 : while (bytesRead < aChunkSize) {
223 0 : if (!HeaderParserInit()) {
224 0 : return false;
225 : }
226 :
227 0 : bytesRead += 8;
228 :
229 0 : uint32_t id = mHeaderParser.GiveHeader().ChunkName();
230 0 : uint32_t length = mHeaderParser.GiveHeader().ChunkSize();
231 :
232 : // SubChunk Length Cannot Exceed List Chunk length.
233 0 : if (length > aChunkSize - bytesRead) {
234 0 : length = aChunkSize - bytesRead;
235 : }
236 :
237 0 : MediaByteRange mRange = { mOffset, mOffset + length };
238 0 : RefPtr<MediaRawData> mChunkData = GetFileHeader(mRange);
239 0 : if (!mChunkData) {
240 0 : return false;
241 : }
242 :
243 0 : const char* rawData = reinterpret_cast<const char*>(mChunkData->Data());
244 :
245 0 : nsCString val(rawData, length);
246 0 : if (length > 0 && val[length - 1] == '\0') {
247 0 : val.SetLength(length - 1);
248 : }
249 :
250 0 : if (length % 2) {
251 0 : mOffset += 1;
252 0 : length += length % 2;
253 : }
254 :
255 0 : bytesRead += length;
256 :
257 0 : if (!IsUTF8(val)) {
258 0 : mHeaderParser.Reset();
259 0 : continue;
260 : }
261 :
262 0 : switch (id) {
263 : case 0x49415254: // IART
264 0 : mInfo->mTags.AppendElement(
265 0 : MetadataTag(NS_LITERAL_CSTRING("artist"), val));
266 0 : break;
267 : case 0x49434d54: // ICMT
268 0 : mInfo->mTags.AppendElement(
269 0 : MetadataTag(NS_LITERAL_CSTRING("comments"), val));
270 0 : break;
271 : case 0x49474e52: // IGNR
272 0 : mInfo->mTags.AppendElement(
273 0 : MetadataTag(NS_LITERAL_CSTRING("genre"), val));
274 0 : break;
275 : case 0x494e414d: // INAM
276 0 : mInfo->mTags.AppendElement(
277 0 : MetadataTag(NS_LITERAL_CSTRING("name"), val));
278 0 : break;
279 : }
280 :
281 0 : mHeaderParser.Reset();
282 : }
283 0 : return true;
284 : }
285 :
286 : media::TimeUnit
287 0 : WAVTrackDemuxer::SeekPosition() const
288 : {
289 0 : TimeUnit pos = Duration(mChunkIndex);
290 0 : if (Duration() > TimeUnit()) {
291 0 : pos = std::min(Duration(), pos);
292 : }
293 0 : return pos;
294 : }
295 :
296 : RefPtr<MediaRawData>
297 0 : WAVTrackDemuxer::DemuxSample()
298 : {
299 0 : return GetNextChunk(FindNextChunk());
300 : }
301 :
302 : UniquePtr<TrackInfo>
303 0 : WAVTrackDemuxer::GetInfo() const
304 : {
305 0 : return mInfo->Clone();
306 : }
307 :
308 : RefPtr<WAVTrackDemuxer::SeekPromise>
309 0 : WAVTrackDemuxer::Seek(const TimeUnit& aTime)
310 : {
311 0 : FastSeek(aTime);
312 0 : const TimeUnit seekTime = ScanUntil(aTime);
313 0 : return SeekPromise::CreateAndResolve(seekTime, __func__);
314 : }
315 :
316 : TimeUnit
317 0 : WAVTrackDemuxer::FastSeek(const TimeUnit& aTime)
318 : {
319 0 : if (aTime.ToMicroseconds()) {
320 0 : mChunkIndex = ChunkIndexFromTime(aTime);
321 : } else {
322 0 : mChunkIndex = 0;
323 : }
324 :
325 0 : mOffset = OffsetFromChunkIndex(mChunkIndex);
326 :
327 0 : if (mOffset > mFirstChunkOffset && StreamLength() > 0) {
328 0 : mOffset = std::min(StreamLength() - 1, mOffset);
329 : }
330 :
331 0 : return Duration(mChunkIndex);
332 : }
333 :
334 : TimeUnit
335 0 : WAVTrackDemuxer::ScanUntil(const TimeUnit& aTime)
336 : {
337 0 : if (!aTime.ToMicroseconds()) {
338 0 : return FastSeek(aTime);
339 : }
340 :
341 0 : if (Duration(mChunkIndex) > aTime) {
342 0 : FastSeek(aTime);
343 : }
344 :
345 0 : return SeekPosition();
346 : }
347 :
348 : RefPtr<WAVTrackDemuxer::SamplesPromise>
349 0 : WAVTrackDemuxer::GetSamples(int32_t aNumSamples)
350 : {
351 0 : MOZ_ASSERT(aNumSamples);
352 :
353 0 : RefPtr<SamplesHolder> datachunks = new SamplesHolder();
354 :
355 0 : while (aNumSamples--) {
356 0 : RefPtr<MediaRawData> datachunk = GetNextChunk(FindNextChunk());
357 0 : if (!datachunk) {
358 0 : break;
359 : }
360 0 : datachunks->mSamples.AppendElement(datachunk);
361 : }
362 :
363 0 : if (datachunks->mSamples.IsEmpty()) {
364 : return SamplesPromise::CreateAndReject(
365 0 : NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
366 : }
367 :
368 0 : return SamplesPromise::CreateAndResolve(datachunks, __func__);
369 : }
370 :
371 : void
372 0 : WAVTrackDemuxer::Reset()
373 : {
374 0 : FastSeek(TimeUnit());
375 0 : mParser.Reset();
376 0 : mHeaderParser.Reset();
377 0 : mRIFFParser.Reset();
378 0 : mFmtParser.Reset();
379 0 : }
380 :
381 : RefPtr<WAVTrackDemuxer::SkipAccessPointPromise>
382 0 : WAVTrackDemuxer::SkipToNextRandomAccessPoint(const TimeUnit& aTimeThreshold)
383 : {
384 : return SkipAccessPointPromise::CreateAndReject(
385 0 : SkipFailureHolder(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, 0), __func__);
386 : }
387 :
388 : int64_t
389 0 : WAVTrackDemuxer::GetResourceOffset() const
390 : {
391 0 : return mOffset;
392 : }
393 :
394 : TimeIntervals
395 0 : WAVTrackDemuxer::GetBuffered()
396 : {
397 0 : TimeUnit duration = Duration();
398 :
399 0 : if (duration <= TimeUnit()) {
400 0 : return TimeIntervals();
401 : }
402 :
403 0 : AutoPinned<MediaResource> stream(mSource.GetResource());
404 0 : return GetEstimatedBufferedTimeRanges(stream, duration.ToMicroseconds());
405 : }
406 :
407 : int64_t
408 0 : WAVTrackDemuxer::StreamLength() const
409 : {
410 0 : return mSource.GetLength();
411 : }
412 :
413 : TimeUnit
414 0 : WAVTrackDemuxer::Duration() const
415 : {
416 0 : if (!mDataLength ||!mChannels || !mSampleFormat) {
417 0 : return TimeUnit();
418 : }
419 :
420 : int64_t numSamples =
421 0 : static_cast<int64_t>(mDataLength) * 8 / mChannels / mSampleFormat;
422 :
423 0 : int64_t numUSeconds = USECS_PER_S * numSamples / mSamplesPerSecond;
424 :
425 0 : if (USECS_PER_S * numSamples % mSamplesPerSecond > mSamplesPerSecond / 2) {
426 0 : numUSeconds++;
427 : }
428 :
429 0 : return TimeUnit::FromMicroseconds(numUSeconds);
430 : }
431 :
432 : TimeUnit
433 0 : WAVTrackDemuxer::Duration(int64_t aNumDataChunks) const
434 : {
435 0 : if (!mSamplesPerSecond || !mSamplesPerChunk) {
436 0 : return TimeUnit();
437 : }
438 : const double usPerDataChunk =
439 0 : USECS_PER_S * static_cast<double>(mSamplesPerChunk) / mSamplesPerSecond;
440 0 : return TimeUnit::FromMicroseconds(aNumDataChunks * usPerDataChunk);
441 : }
442 :
443 : TimeUnit
444 0 : WAVTrackDemuxer::DurationFromBytes(uint32_t aNumBytes) const
445 : {
446 0 : if (!mSamplesPerSecond || !mChannels || !mSampleFormat) {
447 0 : return TimeUnit();
448 : }
449 :
450 0 : int64_t numSamples = aNumBytes * 8 / mChannels / mSampleFormat;
451 :
452 0 : int64_t numUSeconds = USECS_PER_S * numSamples / mSamplesPerSecond;
453 :
454 0 : if (USECS_PER_S * numSamples % mSamplesPerSecond > mSamplesPerSecond / 2) {
455 0 : numUSeconds++;
456 : }
457 :
458 0 : return TimeUnit::FromMicroseconds(numUSeconds);
459 : }
460 :
461 : MediaByteRange
462 0 : WAVTrackDemuxer::FindNextChunk()
463 : {
464 0 : if (mOffset + DATA_CHUNK_SIZE < mFirstChunkOffset + mDataLength) {
465 0 : return { mOffset, mOffset + DATA_CHUNK_SIZE };
466 : } else {
467 0 : return { mOffset, mFirstChunkOffset + mDataLength };
468 : }
469 : }
470 :
471 : MediaByteRange
472 0 : WAVTrackDemuxer::FindChunkHeader()
473 : {
474 0 : return { mOffset, mOffset + CHUNK_HEAD_SIZE };
475 : }
476 :
477 : MediaByteRange
478 0 : WAVTrackDemuxer::FindRIFFHeader()
479 : {
480 0 : return { mOffset, mOffset + RIFF_CHUNK_SIZE };
481 : }
482 :
483 : MediaByteRange
484 0 : WAVTrackDemuxer::FindFmtChunk()
485 : {
486 0 : return { mOffset, mOffset + mHeaderParser.GiveHeader().ChunkSize() };
487 : }
488 :
489 : MediaByteRange
490 0 : WAVTrackDemuxer::FindListChunk()
491 : {
492 0 : return { mOffset, mOffset + mHeaderParser.GiveHeader().ChunkSize() };
493 : }
494 :
495 : MediaByteRange
496 0 : WAVTrackDemuxer::FindInfoTag()
497 : {
498 0 : return { mOffset, mOffset + 4 };
499 : }
500 :
501 : bool
502 0 : WAVTrackDemuxer::SkipNextChunk(const MediaByteRange& aRange)
503 : {
504 0 : UpdateState(aRange);
505 0 : return true;
506 : }
507 :
508 : already_AddRefed<MediaRawData>
509 0 : WAVTrackDemuxer::GetNextChunk(const MediaByteRange& aRange)
510 : {
511 0 : if (!aRange.Length()) {
512 0 : return nullptr;
513 : }
514 :
515 0 : RefPtr<MediaRawData> datachunk = new MediaRawData();
516 0 : datachunk->mOffset = aRange.mStart;
517 :
518 0 : nsAutoPtr<MediaRawDataWriter> chunkWriter(datachunk->CreateWriter());
519 0 : if (!chunkWriter->SetSize(aRange.Length())) {
520 0 : return nullptr;
521 : }
522 :
523 : const uint32_t read =
524 0 : Read(chunkWriter->Data(), datachunk->mOffset, datachunk->Size());
525 :
526 0 : if (read != aRange.Length()) {
527 0 : return nullptr;
528 : }
529 :
530 0 : UpdateState(aRange);
531 0 : ++mNumParsedChunks;
532 0 : ++mChunkIndex;
533 :
534 0 : datachunk->mTime = Duration(mChunkIndex - 1);
535 :
536 0 : if (static_cast<uint32_t>(mChunkIndex) * DATA_CHUNK_SIZE < mDataLength) {
537 0 : datachunk->mDuration = Duration(1);
538 : } else {
539 : uint32_t mBytesRemaining =
540 0 : mDataLength - mChunkIndex * DATA_CHUNK_SIZE;
541 0 : datachunk->mDuration = DurationFromBytes(mBytesRemaining);
542 : }
543 0 : datachunk->mTimecode = datachunk->mTime;
544 0 : datachunk->mKeyframe = true;
545 :
546 0 : MOZ_ASSERT(!datachunk->mTime.IsNegative());
547 0 : MOZ_ASSERT(!datachunk->mDuration.IsNegative());
548 :
549 0 : return datachunk.forget();
550 : }
551 :
552 : already_AddRefed<MediaRawData>
553 0 : WAVTrackDemuxer::GetFileHeader(const MediaByteRange& aRange)
554 : {
555 0 : if (!aRange.Length()) {
556 0 : return nullptr;
557 : }
558 :
559 0 : RefPtr<MediaRawData> fileHeader = new MediaRawData();
560 0 : fileHeader->mOffset = aRange.mStart;
561 :
562 0 : nsAutoPtr<MediaRawDataWriter> headerWriter(fileHeader->CreateWriter());
563 0 : if (!headerWriter->SetSize(aRange.Length())) {
564 0 : return nullptr;
565 : }
566 :
567 : const uint32_t read =
568 0 : Read(headerWriter->Data(), fileHeader->mOffset, fileHeader->Size());
569 :
570 0 : if (read != aRange.Length()) {
571 0 : return nullptr;
572 : }
573 :
574 0 : UpdateState(aRange);
575 :
576 0 : return fileHeader.forget();
577 : }
578 :
579 : int64_t
580 0 : WAVTrackDemuxer::OffsetFromChunkIndex(int64_t aChunkIndex) const
581 : {
582 0 : return mFirstChunkOffset + aChunkIndex * DATA_CHUNK_SIZE;
583 : }
584 :
585 : int64_t
586 0 : WAVTrackDemuxer::ChunkIndexFromOffset(int64_t aOffset) const
587 : {
588 0 : int64_t chunkIndex = (aOffset - mFirstChunkOffset) / DATA_CHUNK_SIZE;
589 0 : return std::max<int64_t>(0, chunkIndex);
590 : }
591 :
592 : int64_t
593 0 : WAVTrackDemuxer::ChunkIndexFromTime(const media::TimeUnit& aTime) const
594 : {
595 0 : if (!mSamplesPerChunk || !mSamplesPerSecond) {
596 0 : return 0;
597 : }
598 : int64_t chunkIndex =
599 0 : (aTime.ToSeconds() * mSamplesPerSecond / mSamplesPerChunk) - 1;
600 0 : return chunkIndex;
601 : }
602 :
603 : void
604 0 : WAVTrackDemuxer::UpdateState(const MediaByteRange& aRange)
605 : {
606 : // Full chunk parsed, move offset to its end.
607 0 : mOffset = aRange.mEnd;
608 0 : mTotalChunkLen += aRange.Length();
609 0 : }
610 :
611 : int32_t
612 0 : WAVTrackDemuxer::Read(uint8_t* aBuffer, int64_t aOffset, int32_t aSize)
613 : {
614 0 : const int64_t streamLen = StreamLength();
615 0 : if (mInfo && streamLen > 0) {
616 0 : aSize = std::min<int64_t>(aSize, streamLen - aOffset);
617 : }
618 0 : uint32_t read = 0;
619 0 : const nsresult rv = mSource.ReadAt(aOffset,
620 : reinterpret_cast<char*>(aBuffer),
621 : static_cast<uint32_t>(aSize),
622 0 : &read);
623 0 : NS_ENSURE_SUCCESS(rv, 0);
624 0 : return static_cast<int32_t>(read);
625 : }
626 :
627 : // RIFFParser
628 :
629 : uint32_t
630 0 : RIFFParser::Parse(ByteReader& aReader)
631 : {
632 0 : while (aReader.CanRead8() && !mRiffHeader.ParseNext(aReader.ReadU8())) { }
633 :
634 0 : if (mRiffHeader.IsValid()) {
635 0 : return RIFF_CHUNK_SIZE;
636 : }
637 :
638 0 : return 0;
639 : }
640 :
641 : void
642 0 : RIFFParser::Reset()
643 : {
644 0 : mRiffHeader.Reset();
645 0 : }
646 :
647 : const RIFFParser::RIFFHeader&
648 0 : RIFFParser::RiffHeader() const
649 : {
650 0 : return mRiffHeader;
651 : }
652 :
653 : // RIFFParser::RIFFHeader
654 :
655 0 : RIFFParser::RIFFHeader::RIFFHeader()
656 : {
657 0 : Reset();
658 0 : }
659 :
660 : void
661 0 : RIFFParser::RIFFHeader::Reset()
662 : {
663 0 : memset(mRaw, 0, sizeof(mRaw));
664 0 : mPos = 0;
665 0 : }
666 :
667 : bool
668 0 : RIFFParser::RIFFHeader::ParseNext(uint8_t c)
669 : {
670 0 : if (!Update(c)) {
671 0 : Reset();
672 0 : if (!Update(c)) {
673 0 : Reset();
674 : }
675 : }
676 0 : return IsValid();
677 : }
678 :
679 : bool
680 0 : RIFFParser::RIFFHeader::IsValid(int aPos) const
681 : {
682 0 : if (aPos > -1 && aPos < 4) {
683 0 : return RIFF[aPos] == mRaw[aPos];
684 0 : } else if (aPos > 7 && aPos < 12) {
685 0 : return WAVE[aPos - 8] == mRaw[aPos];
686 : } else {
687 0 : return true;
688 : }
689 : }
690 :
691 : bool
692 0 : RIFFParser::RIFFHeader::IsValid() const
693 : {
694 0 : return mPos >= RIFF_CHUNK_SIZE;
695 : }
696 :
697 : bool
698 0 : RIFFParser::RIFFHeader::Update(uint8_t c)
699 : {
700 0 : if (mPos < RIFF_CHUNK_SIZE) {
701 0 : mRaw[mPos] = c;
702 : }
703 0 : return IsValid(mPos++);
704 : }
705 :
706 : // HeaderParser
707 :
708 : uint32_t
709 0 : HeaderParser::Parse(ByteReader& aReader)
710 : {
711 0 : while (aReader.CanRead8() && !mHeader.ParseNext(aReader.ReadU8())) { }
712 :
713 0 : if (mHeader.IsValid()) {
714 0 : return CHUNK_HEAD_SIZE;
715 : }
716 :
717 0 : return 0;
718 : }
719 :
720 : void
721 0 : HeaderParser::Reset()
722 : {
723 0 : mHeader.Reset();
724 0 : }
725 :
726 : const HeaderParser::ChunkHeader&
727 0 : HeaderParser::GiveHeader() const
728 : {
729 0 : return mHeader;
730 : }
731 :
732 : // HeaderParser::ChunkHeader
733 :
734 0 : HeaderParser::ChunkHeader::ChunkHeader()
735 : {
736 0 : Reset();
737 0 : }
738 :
739 : void
740 0 : HeaderParser::ChunkHeader::Reset()
741 : {
742 0 : memset(mRaw, 0, sizeof(mRaw));
743 0 : mPos = 0;
744 0 : }
745 :
746 : bool
747 0 : HeaderParser::ChunkHeader::ParseNext(uint8_t c)
748 : {
749 0 : Update(c);
750 0 : return IsValid();
751 : }
752 :
753 : bool
754 0 : HeaderParser::ChunkHeader::IsValid() const
755 : {
756 0 : return mPos >= CHUNK_HEAD_SIZE;
757 : }
758 :
759 : uint32_t
760 0 : HeaderParser::ChunkHeader::ChunkName() const
761 : {
762 0 : return ((mRaw[0] << 24)
763 0 : | (mRaw[1] << 16)
764 0 : | (mRaw[2] << 8 )
765 0 : | (mRaw[3]));
766 : }
767 :
768 : uint32_t
769 0 : HeaderParser::ChunkHeader::ChunkSize() const
770 : {
771 0 : return ((mRaw[7] << 24)
772 0 : | (mRaw[6] << 16)
773 0 : | (mRaw[5] << 8 )
774 0 : | (mRaw[4]));
775 : }
776 :
777 : void
778 0 : HeaderParser::ChunkHeader::Update(uint8_t c)
779 : {
780 0 : if (mPos < CHUNK_HEAD_SIZE) {
781 0 : mRaw[mPos++] = c;
782 : }
783 0 : }
784 :
785 : // FormatParser
786 :
787 : uint32_t
788 0 : FormatParser::Parse(ByteReader& aReader)
789 : {
790 0 : while (aReader.CanRead8() && !mFmtChunk.ParseNext(aReader.ReadU8())) { }
791 :
792 0 : if (mFmtChunk.IsValid()) {
793 0 : return FMT_CHUNK_MIN_SIZE;
794 : }
795 :
796 0 : return 0;
797 : }
798 :
799 : void
800 0 : FormatParser::Reset()
801 : {
802 0 : mFmtChunk.Reset();
803 0 : }
804 :
805 : const FormatParser::FormatChunk&
806 0 : FormatParser::FmtChunk() const
807 : {
808 0 : return mFmtChunk;
809 : }
810 :
811 : // FormatParser::FormatChunk
812 :
813 0 : FormatParser::FormatChunk::FormatChunk()
814 : {
815 0 : Reset();
816 0 : }
817 :
818 : void
819 0 : FormatParser::FormatChunk::Reset()
820 : {
821 0 : memset(mRaw, 0, sizeof(mRaw));
822 0 : mPos = 0;
823 0 : }
824 :
825 : uint16_t
826 0 : FormatParser::FormatChunk::WaveFormat() const
827 : {
828 0 : return (mRaw[1] << 8) | (mRaw[0]);
829 : }
830 :
831 : uint16_t
832 0 : FormatParser::FormatChunk::Channels() const
833 : {
834 0 : return (mRaw[3] << 8) | (mRaw[2]);
835 : }
836 :
837 : uint32_t
838 0 : FormatParser::FormatChunk::SampleRate() const
839 : {
840 0 : return (mRaw[7] << 24)
841 0 : | (mRaw[6] << 16)
842 0 : | (mRaw[5] << 8)
843 0 : | (mRaw[4]);
844 : }
845 :
846 : uint16_t
847 0 : FormatParser::FormatChunk::FrameSize() const
848 : {
849 0 : return (mRaw[13] << 8) | (mRaw[12]);
850 : }
851 :
852 : uint16_t
853 0 : FormatParser::FormatChunk::SampleFormat() const
854 : {
855 0 : return (mRaw[15] << 8) | (mRaw[14]);
856 : }
857 :
858 : bool
859 0 : FormatParser::FormatChunk::ParseNext(uint8_t c)
860 : {
861 0 : Update(c);
862 0 : return IsValid();
863 : }
864 :
865 : bool
866 0 : FormatParser::FormatChunk::IsValid() const
867 : {
868 0 : return (FrameSize() == SampleRate() * Channels() / 8)
869 0 : && (mPos >= FMT_CHUNK_MIN_SIZE);
870 : }
871 :
872 : void
873 0 : FormatParser::FormatChunk::Update(uint8_t c)
874 : {
875 0 : if (mPos < FMT_CHUNK_MIN_SIZE) {
876 0 : mRaw[mPos++] = c;
877 : }
878 0 : }
879 :
880 : // DataParser
881 :
882 0 : DataParser::DataParser()
883 : {
884 0 : }
885 :
886 : void
887 0 : DataParser::Reset()
888 : {
889 0 : mChunk.Reset();
890 0 : }
891 :
892 : const DataParser::DataChunk&
893 0 : DataParser::CurrentChunk() const
894 : {
895 0 : return mChunk;
896 : }
897 :
898 : // DataParser::DataChunk
899 :
900 : void
901 0 : DataParser::DataChunk::Reset()
902 : {
903 0 : mPos = 0;
904 0 : }
905 :
906 : } // namespace mozilla
|