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