Source code

Revision control

Other Tools

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 "VorbisDecoder.h"
8
#include "VorbisUtils.h"
9
#include "XiphExtradata.h"
10
11
#include "mozilla/PodOperations.h"
12
#include "mozilla/SyncRunnable.h"
13
#include "VideoUtils.h"
14
15
#undef LOG
16
#define LOG(type, msg) MOZ_LOG(sPDMLog, type, msg)
17
18
namespace mozilla {
19
20
ogg_packet InitVorbisPacket(const unsigned char* aData, size_t aLength,
21
bool aBOS, bool aEOS, int64_t aGranulepos,
22
int64_t aPacketNo) {
23
ogg_packet packet;
24
packet.packet = const_cast<unsigned char*>(aData);
25
packet.bytes = aLength;
26
packet.b_o_s = aBOS;
27
packet.e_o_s = aEOS;
28
packet.granulepos = aGranulepos;
29
packet.packetno = aPacketNo;
30
return packet;
31
}
32
33
VorbisDataDecoder::VorbisDataDecoder(const CreateDecoderParams& aParams)
34
: mInfo(aParams.AudioConfig()),
35
mTaskQueue(aParams.mTaskQueue),
36
mPacketCount(0),
37
mFrames(0) {
38
// Zero these member vars to avoid crashes in Vorbis clear functions when
39
// destructor is called before |Init|.
40
PodZero(&mVorbisBlock);
41
PodZero(&mVorbisDsp);
42
PodZero(&mVorbisInfo);
43
PodZero(&mVorbisComment);
44
}
45
46
VorbisDataDecoder::~VorbisDataDecoder() {
47
vorbis_block_clear(&mVorbisBlock);
48
vorbis_dsp_clear(&mVorbisDsp);
49
vorbis_info_clear(&mVorbisInfo);
50
vorbis_comment_clear(&mVorbisComment);
51
}
52
53
RefPtr<ShutdownPromise> VorbisDataDecoder::Shutdown() {
54
RefPtr<VorbisDataDecoder> self = this;
55
return InvokeAsync(mTaskQueue, __func__, [self]() {
56
return ShutdownPromise::CreateAndResolve(true, __func__);
57
});
58
}
59
60
RefPtr<MediaDataDecoder::InitPromise> VorbisDataDecoder::Init() {
61
vorbis_info_init(&mVorbisInfo);
62
vorbis_comment_init(&mVorbisComment);
63
PodZero(&mVorbisDsp);
64
PodZero(&mVorbisBlock);
65
66
AutoTArray<unsigned char*, 4> headers;
67
AutoTArray<size_t, 4> headerLens;
68
if (!XiphExtradataToHeaders(headers, headerLens,
69
mInfo.mCodecSpecificConfig->Elements(),
70
mInfo.mCodecSpecificConfig->Length())) {
71
return InitPromise::CreateAndReject(
72
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
73
RESULT_DETAIL("Could not get vorbis header.")),
74
__func__);
75
}
76
for (size_t i = 0; i < headers.Length(); i++) {
77
if (NS_FAILED(DecodeHeader(headers[i], headerLens[i]))) {
78
return InitPromise::CreateAndReject(
79
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
80
RESULT_DETAIL("Could not decode vorbis header.")),
81
__func__);
82
}
83
}
84
85
MOZ_ASSERT(mPacketCount == 3);
86
87
int r = vorbis_synthesis_init(&mVorbisDsp, &mVorbisInfo);
88
if (r) {
89
return InitPromise::CreateAndReject(
90
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
91
RESULT_DETAIL("Systhesis init fail.")),
92
__func__);
93
}
94
95
r = vorbis_block_init(&mVorbisDsp, &mVorbisBlock);
96
if (r) {
97
return InitPromise::CreateAndReject(
98
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
99
RESULT_DETAIL("Block init fail.")),
100
__func__);
101
}
102
103
if (mInfo.mRate != (uint32_t)mVorbisDsp.vi->rate) {
104
LOG(LogLevel::Warning,
105
("Invalid Vorbis header: container and codec rate do not match!"));
106
}
107
if (mInfo.mChannels != (uint32_t)mVorbisDsp.vi->channels) {
108
LOG(LogLevel::Warning,
109
("Invalid Vorbis header: container and codec channels do not match!"));
110
}
111
112
AudioConfig::ChannelLayout layout(mVorbisDsp.vi->channels);
113
if (!layout.IsValid()) {
114
return InitPromise::CreateAndReject(
115
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
116
RESULT_DETAIL("Invalid audio layout.")),
117
__func__);
118
}
119
120
return InitPromise::CreateAndResolve(TrackInfo::kAudioTrack, __func__);
121
}
122
123
nsresult VorbisDataDecoder::DecodeHeader(const unsigned char* aData,
124
size_t aLength) {
125
bool bos = mPacketCount == 0;
126
ogg_packet pkt =
127
InitVorbisPacket(aData, aLength, bos, false, 0, mPacketCount++);
128
MOZ_ASSERT(mPacketCount <= 3);
129
130
int r = vorbis_synthesis_headerin(&mVorbisInfo, &mVorbisComment, &pkt);
131
return r == 0 ? NS_OK : NS_ERROR_FAILURE;
132
}
133
134
RefPtr<MediaDataDecoder::DecodePromise> VorbisDataDecoder::Decode(
135
MediaRawData* aSample) {
136
return InvokeAsync<MediaRawData*>(mTaskQueue, this, __func__,
137
&VorbisDataDecoder::ProcessDecode, aSample);
138
}
139
140
RefPtr<MediaDataDecoder::DecodePromise> VorbisDataDecoder::ProcessDecode(
141
MediaRawData* aSample) {
142
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
143
144
const unsigned char* aData = aSample->Data();
145
size_t aLength = aSample->Size();
146
int64_t aOffset = aSample->mOffset;
147
148
MOZ_ASSERT(mPacketCount >= 3);
149
150
if (!mLastFrameTime ||
151
mLastFrameTime.ref() != aSample->mTime.ToMicroseconds()) {
152
// We are starting a new block.
153
mFrames = 0;
154
mLastFrameTime = Some(aSample->mTime.ToMicroseconds());
155
}
156
157
ogg_packet pkt =
158
InitVorbisPacket(aData, aLength, false, aSample->mEOS,
159
aSample->mTimecode.ToMicroseconds(), mPacketCount++);
160
161
int err = vorbis_synthesis(&mVorbisBlock, &pkt);
162
if (err) {
163
return DecodePromise::CreateAndReject(
164
MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
165
RESULT_DETAIL("vorbis_synthesis:%d", err)),
166
__func__);
167
}
168
169
err = vorbis_synthesis_blockin(&mVorbisDsp, &mVorbisBlock);
170
if (err) {
171
return DecodePromise::CreateAndReject(
172
MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
173
RESULT_DETAIL("vorbis_synthesis_blockin:%d", err)),
174
__func__);
175
}
176
177
VorbisPCMValue** pcm = 0;
178
int32_t frames = vorbis_synthesis_pcmout(&mVorbisDsp, &pcm);
179
if (frames == 0) {
180
return DecodePromise::CreateAndResolve(DecodedData(), __func__);
181
}
182
183
DecodedData results;
184
while (frames > 0) {
185
uint32_t channels = mVorbisDsp.vi->channels;
186
uint32_t rate = mVorbisDsp.vi->rate;
187
AlignedAudioBuffer buffer(frames * channels);
188
if (!buffer) {
189
return DecodePromise::CreateAndReject(
190
MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__), __func__);
191
}
192
for (uint32_t j = 0; j < channels; ++j) {
193
VorbisPCMValue* channel = pcm[j];
194
for (uint32_t i = 0; i < uint32_t(frames); ++i) {
195
buffer[i * channels + j] = MOZ_CONVERT_VORBIS_SAMPLE(channel[i]);
196
}
197
}
198
199
auto duration = FramesToTimeUnit(frames, rate);
200
if (!duration.IsValid()) {
201
return DecodePromise::CreateAndReject(
202
MediaResult(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
203
RESULT_DETAIL("Overflow converting audio duration")),
204
__func__);
205
}
206
auto total_duration = FramesToTimeUnit(mFrames, rate);
207
if (!total_duration.IsValid()) {
208
return DecodePromise::CreateAndReject(
209
MediaResult(
210
NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
211
RESULT_DETAIL("Overflow converting audio total_duration")),
212
__func__);
213
}
214
215
auto time = total_duration + aSample->mTime;
216
if (!time.IsValid()) {
217
return DecodePromise::CreateAndReject(
218
MediaResult(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
219
RESULT_DETAIL(
220
"Overflow adding total_duration and aSample->mTime")),
221
__func__);
222
};
223
224
if (!mAudioConverter) {
225
const AudioConfig::ChannelLayout layout =
226
AudioConfig::ChannelLayout(channels, VorbisLayout(channels));
227
AudioConfig in(layout, channels, rate);
228
AudioConfig out(AudioConfig::ChannelLayout::SMPTEDefault(layout),
229
channels, rate);
230
mAudioConverter = MakeUnique<AudioConverter>(in, out);
231
}
232
MOZ_ASSERT(mAudioConverter->CanWorkInPlace());
233
AudioSampleBuffer data(std::move(buffer));
234
data = mAudioConverter->Process(std::move(data));
235
236
RefPtr<AudioData> audio =
237
new AudioData(aOffset, time, data.Forget(), channels, rate,
238
mAudioConverter->OutputConfig().Layout().Map());
239
MOZ_DIAGNOSTIC_ASSERT(duration == audio->mDuration, "must be equal");
240
results.AppendElement(std::move(audio));
241
mFrames += frames;
242
err = vorbis_synthesis_read(&mVorbisDsp, frames);
243
if (err) {
244
return DecodePromise::CreateAndReject(
245
MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
246
RESULT_DETAIL("vorbis_synthesis_read:%d", err)),
247
__func__);
248
}
249
250
frames = vorbis_synthesis_pcmout(&mVorbisDsp, &pcm);
251
}
252
return DecodePromise::CreateAndResolve(std::move(results), __func__);
253
}
254
255
RefPtr<MediaDataDecoder::DecodePromise> VorbisDataDecoder::Drain() {
256
return InvokeAsync(mTaskQueue, __func__, [] {
257
return DecodePromise::CreateAndResolve(DecodedData(), __func__);
258
});
259
}
260
261
RefPtr<MediaDataDecoder::FlushPromise> VorbisDataDecoder::Flush() {
262
RefPtr<VorbisDataDecoder> self = this;
263
return InvokeAsync(mTaskQueue, __func__, [self]() {
264
// Ignore failed results from vorbis_synthesis_restart. They
265
// aren't fatal and it fails when ResetDecode is called at a
266
// time when no vorbis data has been read.
267
vorbis_synthesis_restart(&self->mVorbisDsp);
268
self->mLastFrameTime.reset();
269
return FlushPromise::CreateAndResolve(true, __func__);
270
});
271
}
272
273
/* static */
274
bool VorbisDataDecoder::IsVorbis(const nsACString& aMimeType) {
275
return aMimeType.EqualsLiteral("audio/vorbis");
276
}
277
278
/* static */
279
const AudioConfig::Channel* VorbisDataDecoder::VorbisLayout(
280
uint32_t aChannels) {
282
// Section 4.3.9.
283
typedef AudioConfig::Channel Channel;
284
285
switch (aChannels) {
286
case 1: // the stream is monophonic
287
{
288
static const Channel config[] = {AudioConfig::CHANNEL_FRONT_CENTER};
289
return config;
290
}
291
case 2: // the stream is stereo. channel order: left, right
292
{
293
static const Channel config[] = {AudioConfig::CHANNEL_FRONT_LEFT,
294
AudioConfig::CHANNEL_FRONT_RIGHT};
295
return config;
296
}
297
case 3: // the stream is a 1d-surround encoding. channel order: left,
298
// center, right
299
{
300
static const Channel config[] = {AudioConfig::CHANNEL_FRONT_LEFT,
301
AudioConfig::CHANNEL_FRONT_CENTER,
302
AudioConfig::CHANNEL_FRONT_RIGHT};
303
return config;
304
}
305
case 4: // the stream is quadraphonic surround. channel order: front left,
306
// front right, rear left, rear right
307
{
308
static const Channel config[] = {
309
AudioConfig::CHANNEL_FRONT_LEFT, AudioConfig::CHANNEL_FRONT_RIGHT,
310
AudioConfig::CHANNEL_BACK_LEFT, AudioConfig::CHANNEL_BACK_RIGHT};
311
return config;
312
}
313
case 5: // the stream is five-channel surround. channel order: front left,
314
// center, front right, rear left, rear right
315
{
316
static const Channel config[] = {
317
AudioConfig::CHANNEL_FRONT_LEFT, AudioConfig::CHANNEL_FRONT_CENTER,
318
AudioConfig::CHANNEL_FRONT_RIGHT, AudioConfig::CHANNEL_BACK_LEFT,
319
AudioConfig::CHANNEL_BACK_RIGHT};
320
return config;
321
}
322
case 6: // the stream is 5.1 surround. channel order: front left, center,
323
// front right, rear left, rear right, LFE
324
{
325
static const Channel config[] = {
326
AudioConfig::CHANNEL_FRONT_LEFT, AudioConfig::CHANNEL_FRONT_CENTER,
327
AudioConfig::CHANNEL_FRONT_RIGHT, AudioConfig::CHANNEL_BACK_LEFT,
328
AudioConfig::CHANNEL_BACK_RIGHT, AudioConfig::CHANNEL_LFE};
329
return config;
330
}
331
case 7: // surround. channel order: front left, center, front right, side
332
// left, side right, rear center, LFE
333
{
334
static const Channel config[] = {
335
AudioConfig::CHANNEL_FRONT_LEFT, AudioConfig::CHANNEL_FRONT_CENTER,
336
AudioConfig::CHANNEL_FRONT_RIGHT, AudioConfig::CHANNEL_SIDE_LEFT,
337
AudioConfig::CHANNEL_SIDE_RIGHT, AudioConfig::CHANNEL_BACK_CENTER,
338
AudioConfig::CHANNEL_LFE};
339
return config;
340
}
341
case 8: // the stream is 7.1 surround. channel order: front left, center,
342
// front right, side left, side right, rear left, rear right, LFE
343
{
344
static const Channel config[] = {
345
AudioConfig::CHANNEL_FRONT_LEFT, AudioConfig::CHANNEL_FRONT_CENTER,
346
AudioConfig::CHANNEL_FRONT_RIGHT, AudioConfig::CHANNEL_SIDE_LEFT,
347
AudioConfig::CHANNEL_SIDE_RIGHT, AudioConfig::CHANNEL_BACK_LEFT,
348
AudioConfig::CHANNEL_BACK_RIGHT, AudioConfig::CHANNEL_LFE};
349
return config;
350
}
351
default:
352
return nullptr;
353
}
354
}
355
356
} // namespace mozilla
357
#undef LOG