/src/mozilla-central/dom/media/platforms/agnostic/WAVDecoder.cpp
Line | Count | Source (jump to first uncovered line) |
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 "BufferReader.h" |
9 | | #include "WAVDecoder.h" |
10 | | #include "mozilla/SyncRunnable.h" |
11 | | #include "VideoUtils.h" |
12 | | |
13 | | namespace mozilla { |
14 | | |
15 | | int16_t |
16 | | DecodeALawSample(uint8_t aValue) |
17 | 0 | { |
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 | 0 | case 0: |
25 | 0 | sample += 8; |
26 | 0 | break; |
27 | 0 | case 1: |
28 | 0 | sample += 0x108; |
29 | 0 | break; |
30 | 0 | default: |
31 | 0 | sample += 0x108; |
32 | 0 | sample <<= exponent - 1; |
33 | 0 | } |
34 | 0 | return sign * sample; |
35 | 0 | } |
36 | | |
37 | | int16_t |
38 | | DecodeULawSample(uint8_t aValue) |
39 | 0 | { |
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 | 0 | } |
47 | | |
48 | | WaveDataDecoder::WaveDataDecoder(const CreateDecoderParams& aParams) |
49 | | : mInfo(aParams.AudioConfig()) |
50 | | , mTaskQueue(aParams.mTaskQueue) |
51 | 0 | { |
52 | 0 | } |
53 | | |
54 | | RefPtr<ShutdownPromise> |
55 | | WaveDataDecoder::Shutdown() |
56 | 0 | { |
57 | 0 | RefPtr<WaveDataDecoder> self = this; |
58 | 0 | return InvokeAsync(mTaskQueue, __func__, [self]() { |
59 | 0 | return ShutdownPromise::CreateAndResolve(true, __func__); |
60 | 0 | }); |
61 | 0 | } |
62 | | |
63 | | RefPtr<MediaDataDecoder::InitPromise> |
64 | | WaveDataDecoder::Init() |
65 | 0 | { |
66 | 0 | return InitPromise::CreateAndResolve(TrackInfo::kAudioTrack, __func__); |
67 | 0 | } |
68 | | |
69 | | RefPtr<MediaDataDecoder::DecodePromise> |
70 | | WaveDataDecoder::Decode(MediaRawData* aSample) |
71 | 0 | { |
72 | 0 | return InvokeAsync<MediaRawData*>(mTaskQueue, this, __func__, |
73 | 0 | &WaveDataDecoder::ProcessDecode, aSample); |
74 | 0 | } |
75 | | |
76 | | RefPtr<MediaDataDecoder::DecodePromise> |
77 | | WaveDataDecoder::ProcessDecode(MediaRawData* aSample) |
78 | 0 | { |
79 | 0 | size_t aLength = aSample->Size(); |
80 | 0 | BufferReader aReader(aSample->Data(), aLength); |
81 | 0 | int64_t aOffset = aSample->mOffset; |
82 | 0 |
|
83 | 0 | int32_t frames = aLength * 8 / mInfo.mBitDepth / mInfo.mChannels; |
84 | 0 |
|
85 | 0 | AlignedAudioBuffer buffer(frames * mInfo.mChannels); |
86 | 0 | if (!buffer) { |
87 | 0 | return DecodePromise::CreateAndReject( |
88 | 0 | MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__), __func__); |
89 | 0 | } |
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 | auto res = aReader.ReadU8(); |
94 | 0 | if (res.isErr()) { |
95 | 0 | return DecodePromise::CreateAndReject( |
96 | 0 | MediaResult(res.unwrapErr(), __func__), __func__); |
97 | 0 | } |
98 | 0 | int16_t decoded = DecodeALawSample(res.unwrap()); |
99 | 0 | buffer[i * mInfo.mChannels + j] = |
100 | 0 | IntegerToAudioSample<AudioDataValue>(decoded); |
101 | 0 | } else if (mInfo.mProfile == 7) { //ULAW Data |
102 | 0 | auto res = aReader.ReadU8(); |
103 | 0 | if (res.isErr()) { |
104 | 0 | return DecodePromise::CreateAndReject( |
105 | 0 | MediaResult(res.unwrapErr(), __func__), __func__); |
106 | 0 | } |
107 | 0 | int16_t decoded = DecodeULawSample(res.unwrap()); |
108 | 0 | buffer[i * mInfo.mChannels + j] = |
109 | 0 | IntegerToAudioSample<AudioDataValue>(decoded); |
110 | 0 | } else { //PCM Data |
111 | 0 | if (mInfo.mBitDepth == 8) { |
112 | 0 | auto res = aReader.ReadU8(); |
113 | 0 | if (res.isErr()) { |
114 | 0 | return DecodePromise::CreateAndReject( |
115 | 0 | MediaResult(res.unwrapErr(), __func__), __func__); |
116 | 0 | } |
117 | 0 | buffer[i * mInfo.mChannels + j] = |
118 | 0 | UInt8bitToAudioSample<AudioDataValue>(res.unwrap()); |
119 | 0 | } else if (mInfo.mBitDepth == 16) { |
120 | 0 | auto res = aReader.ReadLE16(); |
121 | 0 | if (res.isErr()) { |
122 | 0 | return DecodePromise::CreateAndReject( |
123 | 0 | MediaResult(res.unwrapErr(), __func__), __func__); |
124 | 0 | } |
125 | 0 | buffer[i * mInfo.mChannels + j] = |
126 | 0 | IntegerToAudioSample<AudioDataValue>(res.unwrap()); |
127 | 0 | } else if (mInfo.mBitDepth == 24) { |
128 | 0 | auto res = aReader.ReadLE24(); |
129 | 0 | if (res.isErr()) { |
130 | 0 | return DecodePromise::CreateAndReject( |
131 | 0 | MediaResult(res.unwrapErr(), __func__), __func__); |
132 | 0 | } |
133 | 0 | buffer[i * mInfo.mChannels + j] = |
134 | 0 | Int24bitToAudioSample<AudioDataValue>(res.unwrap()); |
135 | 0 | } |
136 | 0 | } |
137 | 0 | } |
138 | 0 | } |
139 | 0 |
|
140 | 0 | auto duration = FramesToTimeUnit(frames, mInfo.mRate); |
141 | 0 |
|
142 | 0 | return DecodePromise::CreateAndResolve( |
143 | 0 | DecodedData{ new AudioData(aOffset, aSample->mTime, duration, frames, |
144 | 0 | std::move(buffer), mInfo.mChannels, mInfo.mRate) }, |
145 | 0 | __func__); |
146 | 0 | } |
147 | | |
148 | | RefPtr<MediaDataDecoder::DecodePromise> |
149 | | WaveDataDecoder::Drain() |
150 | 0 | { |
151 | 0 | return InvokeAsync(mTaskQueue, __func__, [] { |
152 | 0 | return DecodePromise::CreateAndResolve(DecodedData(), __func__); |
153 | 0 | }); |
154 | 0 | } |
155 | | |
156 | | RefPtr<MediaDataDecoder::FlushPromise> |
157 | | WaveDataDecoder::Flush() |
158 | 0 | { |
159 | 0 | return InvokeAsync(mTaskQueue, __func__, []() { |
160 | 0 | return FlushPromise::CreateAndResolve(true, __func__); |
161 | 0 | }); |
162 | 0 | } |
163 | | |
164 | | /* static */ |
165 | | bool |
166 | | WaveDataDecoder::IsWave(const nsACString& aMimeType) |
167 | 0 | { |
168 | 0 | // Some WebAudio uses "audio/x-wav", |
169 | 0 | // WAVdemuxer uses "audio/wave; codecs=aNum". |
170 | 0 | return aMimeType.EqualsLiteral("audio/x-wav") || |
171 | 0 | aMimeType.EqualsLiteral("audio/wave; codecs=1") || |
172 | 0 | aMimeType.EqualsLiteral("audio/wave; codecs=6") || |
173 | 0 | aMimeType.EqualsLiteral("audio/wave; codecs=7") || |
174 | 0 | aMimeType.EqualsLiteral("audio/wave; codecs=65534"); |
175 | 0 | } |
176 | | |
177 | | } // namespace mozilla |
178 | | #undef LOG |