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