Coverage Report

Created: 2018-09-25 14:53

/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