FaadDecoderPlugin.cxx 10.8 KB
Newer Older
1
/*
2
 * Copyright 2003-2018 The Music Player Daemon Project
3 4
 * http://www.musicpd.org
 *
5 6 7 8 9 10 11 12 13
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
14 15 16 17
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 19
 */

20
#include "FaadDecoderPlugin.hxx"
21 22
#include "../DecoderAPI.hxx"
#include "../DecoderBuffer.hxx"
Max Kellermann's avatar
Max Kellermann committed
23
#include "input/InputStream.hxx"
24
#include "CheckAudioFormat.hxx"
25
#include "tag/Handler.hxx"
26
#include "util/ScopeExit.hxx"
27
#include "util/ConstBuffer.hxx"
28
#include "util/Domain.hxx"
29
#include "Log.hxx"
30

31 32
#include <neaacdec.h>

33
#include <cmath>
34
#include <exception>
35

36
#include <assert.h>
Max Kellermann's avatar
Max Kellermann committed
37
#include <string.h>
38

Max Kellermann's avatar
Max Kellermann committed
39
static const unsigned adts_sample_rates[] =
Avuton Olrich's avatar
Avuton Olrich committed
40 41 42
    { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
	16000, 12000, 11025, 8000, 7350, 0, 0, 0
};
43

44
static constexpr Domain faad_decoder_domain("faad_decoder");
45

46 47 48 49
/**
 * Check whether the buffer head is an AAC frame, and return the frame
 * length.  Returns 0 if it is not a frame.
 */
Max Kellermann's avatar
Max Kellermann committed
50
static size_t
51
adts_check_frame(const unsigned char *data)
52 53
{
	/* check syncword */
54
	if (!((data[0] == 0xFF) && ((data[1] & 0xF6) == 0xF0)))
55 56
		return 0;

57 58 59
	return (((unsigned int)data[3] & 0x3) << 11) |
		(((unsigned int)data[4]) << 3) |
		(data[5] >> 5);
60 61
}

Max Kellermann's avatar
Max Kellermann committed
62 63 64 65
/**
 * Find the next AAC frame in the buffer.  Returns 0 if no frame is
 * found or if not enough data is available.
 */
Max Kellermann's avatar
Max Kellermann committed
66
static size_t
67
adts_find_frame(DecoderBuffer &buffer)
Max Kellermann's avatar
Max Kellermann committed
68
{
69
	while (true) {
70
		auto data = ConstBuffer<uint8_t>::FromVoid(buffer.Need(8));
71 72 73
		if (data.IsNull())
			/* failed */
			return 0;
Max Kellermann's avatar
Max Kellermann committed
74

75
		/* find the 0xff marker */
76 77
		const uint8_t *p = (const uint8_t *)
			memchr(data.data, 0xff, data.size);
78
		if (p == nullptr) {
79
			/* no marker - discard the buffer */
80
			buffer.Clear();
81 82 83
			continue;
		}

84
		if (p > data.data) {
85
			/* discard data before 0xff */
86
			buffer.Consume(p - data.data);
87 88
			continue;
		}
Max Kellermann's avatar
Max Kellermann committed
89 90

		/* is it a frame? */
Max Kellermann's avatar
Max Kellermann committed
91
		const size_t frame_length = adts_check_frame(data.data);
92 93 94
		if (frame_length == 0) {
			/* it's just some random 0xff byte; discard it
			   and continue searching */
95
			buffer.Consume(1);
96 97 98
			continue;
		}

99
		if (buffer.Need(frame_length).IsNull()) {
100 101
			/* not enough data; discard this frame to
			   prevent a possible buffer overflow */
102
			buffer.Clear();
103 104
			continue;
		}
Max Kellermann's avatar
Max Kellermann committed
105

106 107 108
		/* found a full frame! */
		return frame_length;
	}
Max Kellermann's avatar
Max Kellermann committed
109 110
}

111
static SignedSongTime
112
adts_song_duration(DecoderBuffer &buffer)
Avuton Olrich's avatar
Avuton Olrich committed
113
{
114
	const InputStream &is = buffer.GetStream();
115
	const bool estimate = !is.CheapSeeking();
116
	if (estimate && !is.KnownSize())
117
		return SignedSongTime::Negative();
118

119
	unsigned sample_rate = 0;
120 121

	/* Read all frames to ensure correct time and bitrate */
122 123
	unsigned frames = 0;
	for (;; frames++) {
124
		const unsigned frame_length = adts_find_frame(buffer);
125 126
		if (frame_length == 0)
			break;
127

128
		if (frames == 0) {
129
			auto data = ConstBuffer<uint8_t>::FromVoid(buffer.Read());
130
			assert(!data.empty());
131
			assert(frame_length <= data.size);
132

133
			sample_rate = adts_sample_rates[(data.data[2] & 0x3c) >> 2];
134 135
			if (sample_rate == 0)
				break;
136 137
		}

138
		buffer.Consume(frame_length);
139 140 141 142 143 144 145 146 147

		if (estimate && frames == 128) {
			/* if this is a remote file, don't slurp the
			   whole file just for checking the song
			   duration; instead, stop after some time and
			   extrapolate the song duration from what we
			   have until now */

			const auto offset = is.GetOffset()
148
				- buffer.GetAvailable();
149
			if (offset <= 0)
150
				return SignedSongTime::Negative();
151

152
			const auto file_size = is.GetSize();
153 154 155
			frames = (frames * file_size) / offset;
			break;
		}
156 157
	}

158
	if (sample_rate == 0)
159
		return SignedSongTime::Negative();
160

161 162
	return SignedSongTime::FromScale<uint64_t>(frames * uint64_t(1024),
						   sample_rate);
163 164
}

165
static SignedSongTime
166
faad_song_duration(DecoderBuffer &buffer, InputStream &is)
167
{
168
	auto data = ConstBuffer<uint8_t>::FromVoid(buffer.Need(5));
169
	if (data.IsNull())
170
		return SignedSongTime::Negative();
171

172
	size_t tagsize = 0;
173
	if (data.size >= 10 && !memcmp(data.data, "ID3", 3)) {
174 175
		/* skip the ID3 tag */

176 177
		tagsize = (data.data[6] << 21) | (data.data[7] << 14) |
		    (data.data[8] << 7) | (data.data[9] << 0);
178

Avuton Olrich's avatar
Avuton Olrich committed
179
		tagsize += 10;
180

181
		if (!buffer.Skip(tagsize))
182
			return SignedSongTime::Negative();
183

184
		data = ConstBuffer<uint8_t>::FromVoid(buffer.Need(5));
185
		if (data.IsNull())
186
			return SignedSongTime::Negative();
187 188
	}

Max Kellermann's avatar
Max Kellermann committed
189
	if (data.size >= 8 && adts_check_frame(data.data) > 0) {
190
		/* obtain the duration from the ADTS header */
191 192

		if (!is.IsSeekable())
193
			return SignedSongTime::Negative();
194

195
		auto song_length = adts_song_duration(buffer);
196

197 198
		try {
			is.LockSeek(tagsize);
199
		} catch (...) {
200
		}
201

202
		buffer.Clear();
203

204
		return song_length;
205
	} else if (data.size >= 5 && memcmp(data.data, "ADIF", 4) == 0) {
206
		/* obtain the duration from the ADIF header */
207 208

		if (!is.KnownSize())
209
			return SignedSongTime::Negative();
210

211
		size_t skip_size = (data.data[4] & 0x80) ? 9 : 0;
212

213
		if (8 + skip_size > data.size)
214 215
			/* not enough data yet; skip parsing this
			   header */
216
			return SignedSongTime::Negative();
217

Max Kellermann's avatar
Max Kellermann committed
218
		unsigned bit_rate = ((data.data[4 + skip_size] & 0x0F) << 19) |
219 220 221
			(data.data[5 + skip_size] << 11) |
			(data.data[6 + skip_size] << 3) |
			(data.data[7 + skip_size] & 0xE0);
Max Kellermann's avatar
Max Kellermann committed
222

223
		const auto size = is.GetSize();
224
		if (bit_rate == 0)
225
			return SignedSongTime::Negative();
226

227
		return SongTime::FromScale(size, bit_rate / 8);
228
	} else
229
		return SignedSongTime::Negative();
230 231
}

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
static NeAACDecHandle
faad_decoder_new()
{
	const NeAACDecHandle decoder = NeAACDecOpen();

	NeAACDecConfigurationPtr config =
		NeAACDecGetCurrentConfiguration(decoder);
	config->outputFormat = FAAD_FMT_16BIT;
	config->downMatrix = 1;
	config->dontUpSampleImplicitSBR = 0;
	NeAACDecSetConfiguration(decoder, config);

	return decoder;
}

247
/**
248
 * Wrapper for NeAACDecInit() which works around some API
249
 * inconsistencies in libfaad.
250 251
 *
 * Throws #std::runtime_error on error.
252
 */
253
static void
254
faad_decoder_init(NeAACDecHandle decoder, DecoderBuffer &buffer,
255
		  AudioFormat &audio_format)
256
{
257
	auto data = ConstBuffer<uint8_t>::FromVoid(buffer.Read());
258
	if (data.empty())
259
		throw std::runtime_error("Empty file");
260

261
	uint8_t channels;
262
	unsigned long sample_rate;
263 264
	long nbytes = NeAACDecInit(decoder,
				   /* deconst hack, libfaad requires this */
Max Kellermann's avatar
Max Kellermann committed
265 266
				   const_cast<unsigned char *>(data.data),
				   data.size,
267
				   &sample_rate, &channels);
268 269
	if (nbytes < 0)
		throw std::runtime_error("Not an AAC stream");
270

271
	buffer.Consume(nbytes);
272

273 274
	audio_format = CheckAudioFormat(sample_rate, SampleFormat::S16,
					channels);
275 276 277
}

/**
278
 * Wrapper for NeAACDecDecode() which works around some API
279 280 281
 * inconsistencies in libfaad.
 */
static const void *
282
faad_decoder_decode(NeAACDecHandle decoder, DecoderBuffer &buffer,
283
		    NeAACDecFrameInfo *frame_info)
284
{
285
	auto data = ConstBuffer<uint8_t>::FromVoid(buffer.Read());
286
	if (data.empty())
287
		return nullptr;
288

289
	return NeAACDecDecode(decoder, frame_info,
290
			      /* deconst hack, libfaad requires this */
291 292
			      const_cast<uint8_t *>(data.data),
			      data.size);
293 294
}

295
/**
296 297 298 299
 * Determine a song file's total playing time.
 *
 * The first return value specifies whether the file was recognized.
 * The second return value is the duration.
300
 */
301 302
static std::pair<bool, SignedSongTime>
faad_get_file_time(InputStream &is)
Avuton Olrich's avatar
Avuton Olrich committed
303
{
304 305
	DecoderBuffer buffer(nullptr, is,
			     FAAD_MIN_STREAMSIZE * MAX_CHANNELS);
306
	auto duration = faad_song_duration(buffer, is);
307
	bool recognized = !duration.IsNegative();
308

309
	if (!recognized) {
310
		NeAACDecHandle decoder = faad_decoder_new();
311
		AtScopeExit(decoder) { NeAACDecClose(decoder); };
312

313
		buffer.Fill();
314

315
		AudioFormat audio_format;
316 317
		try {
			faad_decoder_init(decoder, buffer, audio_format);
318
			recognized = true;
319
		} catch (...) {
320
		}
321
	}
322

323
	return std::make_pair(recognized, duration);
324 325
}

326
static void
327
faad_stream_decode(DecoderClient &client, InputStream &is,
328
		   DecoderBuffer &buffer, const NeAACDecHandle decoder)
329
{
330
	const auto total_time = faad_song_duration(buffer, is);
331

332 333
	if (adts_find_frame(buffer) == 0)
		return;
334

335 336
	/* initialize it */

337
	AudioFormat audio_format;
338
	faad_decoder_init(decoder, buffer, audio_format);
339

340 341
	/* initialize the MPD core */

342
	client.Ready(audio_format, false, total_time);
343

344 345
	/* the decoder loop */

346
	DecoderCommand cmd;
347
	unsigned bit_rate = 0;
348
	do {
349 350
		/* find the next frame */

351
		const size_t frame_size = adts_find_frame(buffer);
352
		if (frame_size == 0)
353
			/* end of file */
354 355
			break;

356 357
		/* decode it */

358 359 360
		NeAACDecFrameInfo frame_info;
		const void *const decoded =
			faad_decoder_decode(decoder, buffer, &frame_info);
361

Max Kellermann's avatar
Max Kellermann committed
362
		if (frame_info.error > 0) {
363 364 365
			FormatWarning(faad_decoder_domain,
				      "error decoding AAC stream: %s",
				      NeAACDecGetErrorMessage(frame_info.error));
366 367 368
			break;
		}

369
		if (frame_info.channels != audio_format.channels) {
370 371 372
			FormatDefault(faad_decoder_domain,
				      "channel count changed from %u to %u",
				      audio_format.channels, frame_info.channels);
373 374
			break;
		}
375

376
		if (frame_info.samplerate != audio_format.sample_rate) {
377 378 379 380
			FormatDefault(faad_decoder_domain,
				      "sample rate changed from %u to %lu",
				      audio_format.sample_rate,
				      (unsigned long)frame_info.samplerate);
381
			break;
382 383
		}

384
		buffer.Consume(frame_info.bytesconsumed);
385

386 387
		/* update bit rate and position */

Max Kellermann's avatar
Max Kellermann committed
388
		if (frame_info.samples > 0) {
389 390 391
			bit_rate = lround(frame_info.bytesconsumed * 8.0 *
					  frame_info.channels * audio_format.sample_rate /
					  frame_info.samples / 1000);
392 393
		}

394 395
		/* send PCM samples to MPD */

396 397 398
		cmd = client.SubmitData(is, decoded,
					(size_t)frame_info.samples * 2,
					bit_rate);
399
	} while (cmd != DecoderCommand::STOP);
400 401 402
}

static void
403
faad_stream_decode(DecoderClient &client, InputStream &is)
404
{
405
	DecoderBuffer buffer(&client, is,
406
			     FAAD_MIN_STREAMSIZE * MAX_CHANNELS);
407 408 409 410

	/* create the libfaad decoder */

	const NeAACDecHandle decoder = faad_decoder_new();
411
	AtScopeExit(decoder) { NeAACDecClose(decoder); };
412

413
	faad_stream_decode(client, is, buffer, decoder);
414 415
}

416
static bool
417
faad_scan_stream(InputStream &is, TagHandler &handler) noexcept
Avuton Olrich's avatar
Avuton Olrich committed
418
{
419 420
	auto result = faad_get_file_time(is);
	if (!result.first)
421
		return false;
Warren Dukes's avatar
Warren Dukes committed
422

423
	if (!result.second.IsNegative())
424
		handler.OnDuration(SongTime(result.second));
425
	return true;
Warren Dukes's avatar
Warren Dukes committed
426 427
}

428
static const char *const faad_suffixes[] = { "aac", nullptr };
Max Kellermann's avatar
Max Kellermann committed
429
static const char *const faad_mime_types[] = {
430
	"audio/aac", "audio/aacp", nullptr
Max Kellermann's avatar
Max Kellermann committed
431
};
Warren Dukes's avatar
Warren Dukes committed
432

433
const DecoderPlugin faad_decoder_plugin = {
434 435 436 437 438 439 440 441 442 443
	"faad",
	nullptr,
	nullptr,
	faad_stream_decode,
	nullptr,
	nullptr,
	faad_scan_stream,
	nullptr,
	faad_suffixes,
	faad_mime_types,
Warren Dukes's avatar
Warren Dukes committed
444
};