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 "AudioSampleFormat.h"
8 : #include "WAVDecoder.h"
9 : #include "mozilla/SyncRunnable.h"
10 :
11 : using mp4_demuxer::ByteReader;
12 :
13 : namespace mozilla {
14 :
15 : int16_t
16 0 : DecodeALawSample(uint8_t aValue)
17 : {
18 0 : aValue = aValue ^ 0x55;
19 0 : int8_t sign = (aValue & 0x80) ? -1 : 1;
20 0 : uint8_t exponent = (aValue & 0x70) >> 4;
21 0 : uint8_t mantissa = aValue & 0x0F;
22 0 : int16_t sample = mantissa << 4;
23 0 : switch (exponent) {
24 : case 0:
25 0 : sample += 8;
26 0 : break;
27 : case 1:
28 0 : sample += 0x108;
29 0 : break;
30 : default:
31 0 : sample += 0x108;
32 0 : sample <<= exponent - 1;
33 : }
34 0 : return sign * sample;
35 : }
36 :
37 : int16_t
38 0 : DecodeULawSample(uint8_t aValue)
39 : {
40 0 : aValue = aValue ^ 0xFF;
41 0 : int8_t sign = (aValue & 0x80) ? -1 : 1;
42 0 : uint8_t exponent = (aValue & 0x70) >> 4;
43 0 : uint8_t mantissa = aValue & 0x0F;
44 0 : int16_t sample = (33 + 2 * mantissa) * (2 << (exponent + 1)) - 33;
45 0 : return sign * sample;
46 : }
47 :
48 0 : WaveDataDecoder::WaveDataDecoder(const CreateDecoderParams& aParams)
49 0 : : mInfo(aParams.AudioConfig())
50 0 : , mTaskQueue(aParams.mTaskQueue)
51 : {
52 0 : }
53 :
54 : RefPtr<ShutdownPromise>
55 0 : WaveDataDecoder::Shutdown()
56 : {
57 0 : RefPtr<WaveDataDecoder> self = this;
58 0 : return InvokeAsync(mTaskQueue, __func__, [self]() {
59 : return ShutdownPromise::CreateAndResolve(true, __func__);
60 0 : });
61 : }
62 :
63 : RefPtr<MediaDataDecoder::InitPromise>
64 0 : WaveDataDecoder::Init()
65 : {
66 0 : return InitPromise::CreateAndResolve(TrackInfo::kAudioTrack, __func__);
67 : }
68 :
69 : RefPtr<MediaDataDecoder::DecodePromise>
70 0 : WaveDataDecoder::Decode(MediaRawData* aSample)
71 : {
72 : return InvokeAsync<MediaRawData*>(mTaskQueue, this, __func__,
73 0 : &WaveDataDecoder::ProcessDecode, aSample);
74 : }
75 :
76 : RefPtr<MediaDataDecoder::DecodePromise>
77 0 : WaveDataDecoder::ProcessDecode(MediaRawData* aSample)
78 : {
79 0 : size_t aLength = aSample->Size();
80 0 : ByteReader aReader(aSample->Data(), aLength);
81 0 : int64_t aOffset = aSample->mOffset;
82 :
83 0 : int32_t frames = aLength * 8 / mInfo.mBitDepth / mInfo.mChannels;
84 :
85 0 : AlignedAudioBuffer buffer(frames * mInfo.mChannels);
86 0 : if (!buffer) {
87 : return DecodePromise::CreateAndReject(
88 0 : MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__), __func__);
89 : }
90 0 : for (int i = 0; i < frames; ++i) {
91 0 : for (unsigned int j = 0; j < mInfo.mChannels; ++j) {
92 0 : if (mInfo.mProfile == 6) { //ALAW Data
93 0 : uint8_t v = aReader.ReadU8();
94 0 : int16_t decoded = DecodeALawSample(v);
95 0 : buffer[i * mInfo.mChannels + j] =
96 0 : IntegerToAudioSample<AudioDataValue>(decoded);
97 0 : } else if (mInfo.mProfile == 7) { //ULAW Data
98 0 : uint8_t v = aReader.ReadU8();
99 0 : int16_t decoded = DecodeULawSample(v);
100 0 : buffer[i * mInfo.mChannels + j] =
101 0 : IntegerToAudioSample<AudioDataValue>(decoded);
102 : } else { //PCM Data
103 0 : if (mInfo.mBitDepth == 8) {
104 0 : uint8_t v = aReader.ReadU8();
105 0 : buffer[i * mInfo.mChannels + j] =
106 0 : UInt8bitToAudioSample<AudioDataValue>(v);
107 0 : } else if (mInfo.mBitDepth == 16) {
108 0 : int16_t v = aReader.ReadLE16();
109 0 : buffer[i * mInfo.mChannels + j] =
110 0 : IntegerToAudioSample<AudioDataValue>(v);
111 0 : } else if (mInfo.mBitDepth == 24) {
112 0 : int32_t v = aReader.ReadLE24();
113 0 : buffer[i * mInfo.mChannels + j] =
114 0 : Int24bitToAudioSample<AudioDataValue>(v);
115 : }
116 : }
117 : }
118 : }
119 :
120 0 : auto duration = FramesToTimeUnit(frames, mInfo.mRate);
121 :
122 : return DecodePromise::CreateAndResolve(
123 0 : DecodedData{ new AudioData(aOffset, aSample->mTime, duration, frames,
124 0 : Move(buffer), mInfo.mChannels, mInfo.mRate) },
125 0 : __func__);
126 : }
127 :
128 : RefPtr<MediaDataDecoder::DecodePromise>
129 0 : WaveDataDecoder::Drain()
130 : {
131 0 : return InvokeAsync(mTaskQueue, __func__, [] {
132 0 : return DecodePromise::CreateAndResolve(DecodedData(), __func__);
133 0 : });
134 : }
135 :
136 : RefPtr<MediaDataDecoder::FlushPromise>
137 0 : WaveDataDecoder::Flush()
138 : {
139 0 : return InvokeAsync(mTaskQueue, __func__, []() {
140 : return FlushPromise::CreateAndResolve(true, __func__);
141 0 : });
142 : }
143 :
144 : /* static */
145 : bool
146 0 : WaveDataDecoder::IsWave(const nsACString& aMimeType)
147 : {
148 : // Some WebAudio uses "audio/x-wav",
149 : // WAVdemuxer uses "audio/wave; codecs=aNum".
150 0 : return aMimeType.EqualsLiteral("audio/x-wav") ||
151 0 : aMimeType.EqualsLiteral("audio/wave; codecs=1") ||
152 0 : aMimeType.EqualsLiteral("audio/wave; codecs=6") ||
153 0 : aMimeType.EqualsLiteral("audio/wave; codecs=7") ||
154 0 : aMimeType.EqualsLiteral("audio/wave; codecs=65534");
155 : }
156 :
157 : } // namespace mozilla
158 : #undef LOG
|