1 /*
2 * Copyright 2003-2021 The Music Player Daemon Project
3 * http://www.musicpd.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "FaadDecoderPlugin.hxx"
21 #include "../DecoderAPI.hxx"
22 #include "../DecoderBuffer.hxx"
23 #include "input/InputStream.hxx"
24 #include "pcm/CheckAudioFormat.hxx"
25 #include "tag/Handler.hxx"
26 #include "util/ScopeExit.hxx"
27 #include "util/ConstBuffer.hxx"
28 #include "util/Domain.hxx"
29 #include "util/Math.hxx"
30 #include "Log.hxx"
31
32 #include <cassert>
33 #include <cstring>
34
35 #include <neaacdec.h>
36
37 static const unsigned adts_sample_rates[] =
38 { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
39 16000, 12000, 11025, 8000, 7350, 0, 0, 0
40 };
41
42 static constexpr Domain faad_decoder_domain("faad_decoder");
43
44 /**
45 * Check whether the buffer head is an AAC frame, and return the frame
46 * length. Returns 0 if it is not a frame.
47 */
48 static size_t
adts_check_frame(const unsigned char * data)49 adts_check_frame(const unsigned char *data)
50 {
51 /* check syncword */
52 if (!((data[0] == 0xFF) && ((data[1] & 0xF6) == 0xF0)))
53 return 0;
54
55 return (((unsigned int)data[3] & 0x3) << 11) |
56 (((unsigned int)data[4]) << 3) |
57 (data[5] >> 5);
58 }
59
60 /**
61 * Find the next AAC frame in the buffer. Returns 0 if no frame is
62 * found or if not enough data is available.
63 */
64 static size_t
adts_find_frame(DecoderBuffer & buffer)65 adts_find_frame(DecoderBuffer &buffer)
66 {
67 while (true) {
68 auto data = ConstBuffer<uint8_t>::FromVoid(buffer.Need(8));
69 if (data.IsNull())
70 /* failed */
71 return 0;
72
73 /* find the 0xff marker */
74 auto p = (const uint8_t *)std::memchr(data.data, 0xff, data.size);
75 if (p == nullptr) {
76 /* no marker - discard the buffer */
77 buffer.Clear();
78 continue;
79 }
80
81 if (p > data.data) {
82 /* discard data before 0xff */
83 buffer.Consume(p - data.data);
84 continue;
85 }
86
87 /* is it a frame? */
88 const size_t frame_length = adts_check_frame(data.data);
89 if (frame_length == 0) {
90 /* it's just some random 0xff byte; discard it
91 and continue searching */
92 buffer.Consume(1);
93 continue;
94 }
95
96 if (buffer.Need(frame_length).IsNull()) {
97 /* not enough data; discard this frame to
98 prevent a possible buffer overflow */
99 buffer.Clear();
100 continue;
101 }
102
103 /* found a full frame! */
104 return frame_length;
105 }
106 }
107
108 static SignedSongTime
adts_song_duration(DecoderBuffer & buffer)109 adts_song_duration(DecoderBuffer &buffer)
110 {
111 const InputStream &is = buffer.GetStream();
112 const bool estimate = !is.CheapSeeking();
113 if (estimate && !is.KnownSize())
114 return SignedSongTime::Negative();
115
116 unsigned sample_rate = 0;
117
118 /* Read all frames to ensure correct time and bitrate */
119 unsigned frames = 0;
120 for (;; frames++) {
121 const unsigned frame_length = adts_find_frame(buffer);
122 if (frame_length == 0)
123 break;
124
125 if (frames == 0) {
126 auto data = ConstBuffer<uint8_t>::FromVoid(buffer.Read());
127 assert(!data.empty());
128 assert(frame_length <= data.size);
129
130 sample_rate = adts_sample_rates[(data.data[2] & 0x3c) >> 2];
131 if (sample_rate == 0)
132 break;
133 }
134
135 buffer.Consume(frame_length);
136
137 if (estimate && frames == 128) {
138 /* if this is a remote file, don't slurp the
139 whole file just for checking the song
140 duration; instead, stop after some time and
141 extrapolate the song duration from what we
142 have until now */
143
144 const auto offset = is.GetOffset()
145 - buffer.GetAvailable();
146 if (offset <= 0)
147 return SignedSongTime::Negative();
148
149 const auto file_size = is.GetSize();
150 frames = (frames * file_size) / offset;
151 break;
152 }
153 }
154
155 if (sample_rate == 0)
156 return SignedSongTime::Negative();
157
158 return SignedSongTime::FromScale<uint64_t>(frames * uint64_t(1024),
159 sample_rate);
160 }
161
162 static SignedSongTime
faad_song_duration(DecoderBuffer & buffer,InputStream & is)163 faad_song_duration(DecoderBuffer &buffer, InputStream &is)
164 {
165 auto data = ConstBuffer<uint8_t>::FromVoid(buffer.Need(5));
166 if (data.IsNull())
167 return SignedSongTime::Negative();
168
169 size_t tagsize = 0;
170 if (data.size >= 10 && !memcmp(data.data, "ID3", 3)) {
171 /* skip the ID3 tag */
172
173 tagsize = (data.data[6] << 21) | (data.data[7] << 14) |
174 (data.data[8] << 7) | (data.data[9] << 0);
175
176 tagsize += 10;
177
178 if (!buffer.Skip(tagsize))
179 return SignedSongTime::Negative();
180
181 data = ConstBuffer<uint8_t>::FromVoid(buffer.Need(5));
182 if (data.IsNull())
183 return SignedSongTime::Negative();
184 }
185
186 if (data.size >= 8 && adts_check_frame(data.data) > 0) {
187 /* obtain the duration from the ADTS header */
188
189 if (!is.IsSeekable())
190 return SignedSongTime::Negative();
191
192 auto song_length = adts_song_duration(buffer);
193
194 try {
195 is.LockSeek(tagsize);
196 } catch (...) {
197 }
198
199 buffer.Clear();
200
201 return song_length;
202 } else if (data.size >= 5 && memcmp(data.data, "ADIF", 4) == 0) {
203 /* obtain the duration from the ADIF header */
204
205 if (!is.KnownSize())
206 return SignedSongTime::Negative();
207
208 size_t skip_size = (data.data[4] & 0x80) ? 9 : 0;
209
210 if (8 + skip_size > data.size)
211 /* not enough data yet; skip parsing this
212 header */
213 return SignedSongTime::Negative();
214
215 unsigned bit_rate = ((data.data[4 + skip_size] & 0x0F) << 19) |
216 (data.data[5 + skip_size] << 11) |
217 (data.data[6 + skip_size] << 3) |
218 (data.data[7 + skip_size] & 0xE0);
219
220 const auto size = is.GetSize();
221 if (bit_rate == 0)
222 return SignedSongTime::Negative();
223
224 return SongTime::FromScale(size, bit_rate / 8);
225 } else
226 return SignedSongTime::Negative();
227 }
228
229 static NeAACDecHandle
faad_decoder_new()230 faad_decoder_new()
231 {
232 auto decoder = NeAACDecOpen();
233
234 NeAACDecConfigurationPtr config =
235 NeAACDecGetCurrentConfiguration(decoder);
236 config->outputFormat = FAAD_FMT_16BIT;
237 config->downMatrix = 1;
238 config->dontUpSampleImplicitSBR = 0;
239 NeAACDecSetConfiguration(decoder, config);
240
241 return decoder;
242 }
243
244 /**
245 * Wrapper for NeAACDecInit() which works around some API
246 * inconsistencies in libfaad.
247 *
248 * Throws #std::runtime_error on error.
249 */
250 static void
faad_decoder_init(NeAACDecHandle decoder,DecoderBuffer & buffer,AudioFormat & audio_format)251 faad_decoder_init(NeAACDecHandle decoder, DecoderBuffer &buffer,
252 AudioFormat &audio_format)
253 {
254 auto data = ConstBuffer<uint8_t>::FromVoid(buffer.Read());
255 if (data.empty())
256 throw std::runtime_error("Empty file");
257
258 uint8_t channels;
259 unsigned long sample_rate;
260 long nbytes = NeAACDecInit(decoder,
261 /* deconst hack, libfaad requires this */
262 const_cast<unsigned char *>(data.data),
263 data.size,
264 &sample_rate, &channels);
265 if (nbytes < 0)
266 throw std::runtime_error("Not an AAC stream");
267
268 buffer.Consume(nbytes);
269
270 audio_format = CheckAudioFormat(sample_rate, SampleFormat::S16,
271 channels);
272 }
273
274 /**
275 * Wrapper for NeAACDecDecode() which works around some API
276 * inconsistencies in libfaad.
277 */
278 static const void *
faad_decoder_decode(NeAACDecHandle decoder,DecoderBuffer & buffer,NeAACDecFrameInfo * frame_info)279 faad_decoder_decode(NeAACDecHandle decoder, DecoderBuffer &buffer,
280 NeAACDecFrameInfo *frame_info)
281 {
282 auto data = ConstBuffer<uint8_t>::FromVoid(buffer.Read());
283 if (data.empty())
284 return nullptr;
285
286 return NeAACDecDecode(decoder, frame_info,
287 /* deconst hack, libfaad requires this */
288 const_cast<uint8_t *>(data.data),
289 data.size);
290 }
291
292 /**
293 * Determine a song file's total playing time.
294 *
295 * The first return value specifies whether the file was recognized.
296 * The second return value is the duration.
297 */
298 static std::pair<bool, SignedSongTime>
faad_get_file_time(InputStream & is)299 faad_get_file_time(InputStream &is)
300 {
301 DecoderBuffer buffer(nullptr, is,
302 FAAD_MIN_STREAMSIZE * MAX_CHANNELS);
303 auto duration = faad_song_duration(buffer, is);
304 bool recognized = !duration.IsNegative();
305
306 if (!recognized) {
307 NeAACDecHandle decoder = faad_decoder_new();
308 AtScopeExit(decoder) { NeAACDecClose(decoder); };
309
310 buffer.Fill();
311
312 AudioFormat audio_format;
313 try {
314 faad_decoder_init(decoder, buffer, audio_format);
315 recognized = true;
316 } catch (...) {
317 }
318 }
319
320 return {recognized, duration};
321 }
322
323 static void
faad_stream_decode(DecoderClient & client,InputStream & is,DecoderBuffer & buffer,NeAACDecHandle decoder)324 faad_stream_decode(DecoderClient &client, InputStream &is,
325 DecoderBuffer &buffer, NeAACDecHandle decoder)
326 {
327 const auto total_time = faad_song_duration(buffer, is);
328
329 if (adts_find_frame(buffer) == 0)
330 return;
331
332 /* initialize it */
333
334 AudioFormat audio_format;
335 faad_decoder_init(decoder, buffer, audio_format);
336
337 /* initialize the MPD core */
338
339 client.Ready(audio_format, false, total_time);
340
341 /* the decoder loop */
342
343 DecoderCommand cmd;
344 unsigned bit_rate = 0;
345 do {
346 /* find the next frame */
347
348 const size_t frame_size = adts_find_frame(buffer);
349 if (frame_size == 0)
350 /* end of file */
351 break;
352
353 /* decode it */
354
355 NeAACDecFrameInfo frame_info;
356 const void *const decoded =
357 faad_decoder_decode(decoder, buffer, &frame_info);
358
359 if (frame_info.error > 0) {
360 FmtWarning(faad_decoder_domain,
361 "error decoding AAC stream: {}",
362 NeAACDecGetErrorMessage(frame_info.error));
363 break;
364 }
365
366 if (frame_info.channels != audio_format.channels) {
367 FmtNotice(faad_decoder_domain,
368 "channel count changed from {} to {}",
369 audio_format.channels, frame_info.channels);
370 break;
371 }
372
373 if (frame_info.samplerate != audio_format.sample_rate) {
374 FmtNotice(faad_decoder_domain,
375 "sample rate changed from {} to {}",
376 audio_format.sample_rate,
377 frame_info.samplerate);
378 break;
379 }
380
381 buffer.Consume(frame_info.bytesconsumed);
382
383 /* update bit rate and position */
384
385 if (frame_info.samples > 0) {
386 bit_rate = lround(frame_info.bytesconsumed * 8.0 *
387 frame_info.channels * audio_format.sample_rate /
388 frame_info.samples / 1000);
389 }
390
391 /* send PCM samples to MPD */
392
393 cmd = client.SubmitData(is, decoded,
394 (size_t)frame_info.samples * 2,
395 bit_rate);
396 } while (cmd != DecoderCommand::STOP);
397 }
398
399 static void
faad_stream_decode(DecoderClient & client,InputStream & is)400 faad_stream_decode(DecoderClient &client, InputStream &is)
401 {
402 DecoderBuffer buffer(&client, is,
403 FAAD_MIN_STREAMSIZE * MAX_CHANNELS);
404
405 /* create the libfaad decoder */
406
407 auto decoder = faad_decoder_new();
408 AtScopeExit(decoder) { NeAACDecClose(decoder); };
409
410 faad_stream_decode(client, is, buffer, decoder);
411 }
412
413 static bool
faad_scan_stream(InputStream & is,TagHandler & handler)414 faad_scan_stream(InputStream &is, TagHandler &handler)
415 {
416 auto result = faad_get_file_time(is);
417 if (!result.first)
418 return false;
419
420 if (!result.second.IsNegative())
421 handler.OnDuration(SongTime(result.second));
422 return true;
423 }
424
425 static const char *const faad_suffixes[] = { "aac", nullptr };
426 static const char *const faad_mime_types[] = {
427 "audio/aac", "audio/aacp", nullptr
428 };
429
430 constexpr DecoderPlugin faad_decoder_plugin =
431 DecoderPlugin("faad", faad_stream_decode, faad_scan_stream)
432 .WithSuffixes(faad_suffixes)
433 .WithMimeTypes(faad_mime_types);
434