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