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