OpusDecoderPlugin.cxx 12 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2014 The Music Player Daemon Project
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * http://www.musicpd.org
 *
 * 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.
 *
 * 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.
 */

#include "config.h" /* must be first for large file support */
#include "OpusDecoderPlugin.h"
22
#include "OpusDomain.hxx"
23 24
#include "OpusHead.hxx"
#include "OpusTags.hxx"
25
#include "OggFind.hxx"
26
#include "OggSyncState.hxx"
27
#include "../DecoderAPI.hxx"
28
#include "OggCodec.hxx"
29
#include "tag/TagHandler.hxx"
30
#include "tag/TagBuilder.hxx"
Max Kellermann's avatar
Max Kellermann committed
31
#include "input/InputStream.hxx"
32
#include "util/Error.hxx"
33
#include "Log.hxx"
34 35 36 37

#include <opus.h>
#include <ogg/ogg.h>

Max Kellermann's avatar
Max Kellermann committed
38
#include <string.h>
39
#include <stdio.h>
40

41
static constexpr opus_int32 opus_sample_rate = 48000;
42

43 44 45 46 47 48
/**
 * Allocate an output buffer for 16 bit PCM samples big enough to hold
 * a quarter second, larger than 120ms required by libopus.
 */
static constexpr unsigned opus_output_buffer_frames = opus_sample_rate / 4;

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
gcc_pure
static bool
IsOpusHead(const ogg_packet &packet)
{
	return packet.bytes >= 8 && memcmp(packet.packet, "OpusHead", 8) == 0;
}

gcc_pure
static bool
IsOpusTags(const ogg_packet &packet)
{
	return packet.bytes >= 8 && memcmp(packet.packet, "OpusTags", 8) == 0;
}

static bool
64
mpd_opus_init(gcc_unused const config_param &param)
65
{
66
	LogDebug(opus_domain, opus_get_version_string());
67 68 69 70 71

	return true;
}

class MPDOpusDecoder {
72
	Decoder &decoder;
73
	InputStream &input_stream;
74 75 76

	ogg_stream_state os;

77 78
	OpusDecoder *opus_decoder;
	opus_int16 *output_buffer;
79

80 81 82 83 84 85 86 87
	/**
	 * If non-zero, then a previous Opus stream has been found
	 * already with this number of channels.  If opus_decoder is
	 * nullptr, then its end-of-stream packet has been found
	 * already.
	 */
	unsigned previous_channels;

88
	bool os_initialized;
89 90 91

	int opus_serialno;

92 93
	ogg_int64_t eos_granulepos;

94 95 96
	size_t frame_size;

public:
97
	MPDOpusDecoder(Decoder &_decoder,
98
		       InputStream &_input_stream)
99 100
		:decoder(_decoder), input_stream(_input_stream),
		 opus_decoder(nullptr),
101
		 output_buffer(nullptr),
102
		 previous_channels(0),
103
		 os_initialized(false) {}
104 105
	~MPDOpusDecoder();

106 107
	bool ReadFirstPage(OggSyncState &oy);
	bool ReadNextPage(OggSyncState &oy);
108

109 110 111
	DecoderCommand HandlePackets();
	DecoderCommand HandlePacket(const ogg_packet &packet);
	DecoderCommand HandleBOS(const ogg_packet &packet);
112
	DecoderCommand HandleEOS();
113 114
	DecoderCommand HandleTags(const ogg_packet &packet);
	DecoderCommand HandleAudio(const ogg_packet &packet);
115

116
	bool Seek(OggSyncState &oy, uint64_t where_frame);
117 118 119 120
};

MPDOpusDecoder::~MPDOpusDecoder()
{
121
	delete[] output_buffer;
122 123 124 125 126 127 128 129

	if (opus_decoder != nullptr)
		opus_decoder_destroy(opus_decoder);

	if (os_initialized)
		ogg_stream_clear(&os);
}

130
inline bool
131
MPDOpusDecoder::ReadFirstPage(OggSyncState &oy)
132
{
133 134
	assert(!os_initialized);

135
	if (!oy.ExpectFirstPage(os))
136 137 138 139 140 141 142
		return false;

	os_initialized = true;
	return true;
}

inline bool
143
MPDOpusDecoder::ReadNextPage(OggSyncState &oy)
144 145 146 147
{
	assert(os_initialized);

	ogg_page page;
148
	if (!oy.ExpectPage(page))
149 150
		return false;

151
	const auto page_serialno = ogg_page_serialno(&page);
152
	if (page_serialno != os.serialno)
153 154 155
		ogg_stream_reset_serialno(&os, page_serialno);

	ogg_stream_pagein(&os, &page);
156
	return true;
157 158
}

159
inline DecoderCommand
160 161
MPDOpusDecoder::HandlePackets()
{
162 163
	ogg_packet packet;
	while (ogg_stream_packetout(&os, &packet) == 1) {
164 165
		auto cmd = HandlePacket(packet);
		if (cmd != DecoderCommand::NONE)
166 167 168
			return cmd;
	}

169
	return DecoderCommand::NONE;
170 171
}

172
inline DecoderCommand
173 174 175
MPDOpusDecoder::HandlePacket(const ogg_packet &packet)
{
	if (packet.e_o_s)
176
		return HandleEOS();
177 178 179

	if (packet.b_o_s)
		return HandleBOS(packet);
180 181
	else if (opus_decoder == nullptr) {
		LogDebug(opus_domain, "BOS packet expected");
182
		return DecoderCommand::STOP;
183
	}
184 185 186 187 188 189 190

	if (IsOpusTags(packet))
		return HandleTags(packet);

	return HandleAudio(packet);
}

191 192 193 194 195 196 197 198 199 200 201 202
/**
 * Load the end-of-stream packet and restore the previous file
 * position.
 */
static bool
LoadEOSPacket(InputStream &is, Decoder *decoder, int serialno,
	      ogg_packet &packet)
{
	if (!is.CheapSeeking())
		/* we do this for local files only, because seeking
		   around remote files is expensive and not worth the
		   troubl */
203
		return false;
204

205
	const auto old_offset = is.GetOffset();
206 207 208 209 210 211 212 213 214 215 216

	/* create temporary Ogg objects for seeking and parsing the
	   EOS packet */
	OggSyncState oy(is, decoder);
	ogg_stream_state os;
	ogg_stream_init(&os, serialno);

	bool result = OggSeekFindEOS(oy, os, packet, is);
	ogg_stream_clear(&os);

	/* restore the previous file position */
217
	is.LockSeek(old_offset, IgnoreError());
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238

	return result;
}

/**
 * Load the end-of-stream granulepos and restore the previous file
 * position.
 *
 * @return -1 on error
 */
gcc_pure
static ogg_int64_t
LoadEOSGranulePos(InputStream &is, Decoder *decoder, int serialno)
{
	ogg_packet packet;
	if (!LoadEOSPacket(is, decoder, serialno, packet))
		return -1;

	return packet.granulepos;
}

239
inline DecoderCommand
240 241 242 243
MPDOpusDecoder::HandleBOS(const ogg_packet &packet)
{
	assert(packet.b_o_s);

244 245
	if (opus_decoder != nullptr || !IsOpusHead(packet)) {
		LogDebug(opus_domain, "BOS packet must be OpusHead");
246
		return DecoderCommand::STOP;
247
	}
248 249 250

	unsigned channels;
	if (!ScanOpusHeader(packet.packet, packet.bytes, channels) ||
251 252
	    !audio_valid_channel_count(channels)) {
		LogDebug(opus_domain, "Malformed BOS packet");
253
		return DecoderCommand::STOP;
254
	}
255 256

	assert(opus_decoder == nullptr);
257 258 259 260 261 262 263 264
	assert((previous_channels == 0) == (output_buffer == nullptr));

	if (previous_channels != 0 && channels != previous_channels) {
		FormatWarning(opus_domain,
			      "Next stream has different channels (%u -> %u)",
			      previous_channels, channels);
		return DecoderCommand::STOP;
	}
265 266 267 268 269 270 271 272 273 274

	opus_serialno = os.serialno;

	/* TODO: parse attributes from the OpusHead (sample rate,
	   channels, ...) */

	int opus_error;
	opus_decoder = opus_decoder_create(opus_sample_rate, channels,
					   &opus_error);
	if (opus_decoder == nullptr) {
275 276
		FormatError(opus_domain, "libopus error: %s",
			    opus_strerror(opus_error));
277
		return DecoderCommand::STOP;
278 279
	}

280 281 282 283 284 285 286
	if (previous_channels != 0) {
		/* decoder was already initialized by the previous
		   stream; skip the rest of this method */
		LogDebug(opus_domain, "Found another stream");
		return decoder_get_command(decoder);
	}

287 288
	eos_granulepos = LoadEOSGranulePos(input_stream, &decoder,
					   opus_serialno);
289 290 291 292
	const auto duration = eos_granulepos >= 0
		? SignedSongTime::FromScale<uint64_t>(eos_granulepos,
						      opus_sample_rate)
		: SignedSongTime::Negative();
293

294
	previous_channels = channels;
295 296
	const AudioFormat audio_format(opus_sample_rate,
				       SampleFormat::S16, channels);
297 298
	decoder_initialized(decoder, audio_format,
			    eos_granulepos > 0, duration);
299
	frame_size = audio_format.GetFrameSize();
300

301 302
	output_buffer = new opus_int16[opus_output_buffer_frames
				       * audio_format.channels];
303 304 305 306

	return decoder_get_command(decoder);
}

307 308 309
inline DecoderCommand
MPDOpusDecoder::HandleEOS()
{
310 311 312 313 314 315 316 317 318 319 320
	if (eos_granulepos < 0 && previous_channels != 0) {
		/* allow chaining of (unseekable) streams */
		assert(opus_decoder != nullptr);
		assert(output_buffer != nullptr);

		opus_decoder_destroy(opus_decoder);
		opus_decoder = nullptr;

		return decoder_get_command(decoder);
	}

321 322 323
	return DecoderCommand::STOP;
}

324
inline DecoderCommand
325 326
MPDOpusDecoder::HandleTags(const ogg_packet &packet)
{
327
	ReplayGainInfo rgi;
328
	rgi.Clear();
329

330
	TagBuilder tag_builder;
331

332
	DecoderCommand cmd;
Max Kellermann's avatar
Max Kellermann committed
333
	if (ScanOpusTags(packet.packet, packet.bytes,
334
			 &rgi,
335 336
			 &add_tag_handler, &tag_builder) &&
	    !tag_builder.IsEmpty()) {
337 338
		decoder_replay_gain(decoder, &rgi);

339
		Tag tag = tag_builder.Commit();
340
		cmd = decoder_tag(decoder, input_stream, std::move(tag));
341
	} else
342 343 344 345 346
		cmd = decoder_get_command(decoder);

	return cmd;
}

347
inline DecoderCommand
348 349 350 351 352 353 354
MPDOpusDecoder::HandleAudio(const ogg_packet &packet)
{
	assert(opus_decoder != nullptr);

	int nframes = opus_decode(opus_decoder,
				  (const unsigned char*)packet.packet,
				  packet.bytes,
355
				  output_buffer, opus_output_buffer_frames,
356 357
				  0);
	if (nframes < 0) {
358 359
		FormatError(opus_domain, "libopus error: %s",
			    opus_strerror(nframes));
360
		return DecoderCommand::STOP;
361 362 363 364
	}

	if (nframes > 0) {
		const size_t nbytes = nframes * frame_size;
365 366 367 368
		auto cmd = decoder_data(decoder, input_stream,
					output_buffer, nbytes,
					0);
		if (cmd != DecoderCommand::NONE)
369
			return cmd;
370 371 372 373 374

		if (packet.granulepos > 0)
			decoder_timestamp(decoder,
					  double(packet.granulepos)
					  / opus_sample_rate);
375 376
	}

377
	return DecoderCommand::NONE;
378 379
}

380
bool
381
MPDOpusDecoder::Seek(OggSyncState &oy, uint64_t where_frame)
382 383
{
	assert(eos_granulepos > 0);
384 385
	assert(input_stream.IsSeekable());
	assert(input_stream.KnownSize());
386

387
	const ogg_int64_t where_granulepos(where_frame);
388 389 390 391

	/* interpolate the file offset where we expect to find the
	   given granule position */
	/* TODO: implement binary search */
392 393
	offset_type offset(where_granulepos * input_stream.GetSize()
			   / eos_granulepos);
394

395
	return OggSeekPageAtOffset(oy, os, input_stream, offset);
396 397
}

398
static void
399
mpd_opus_stream_decode(Decoder &decoder,
400
		       InputStream &input_stream)
401
{
402
	if (ogg_codec_detect(&decoder, input_stream) != OGG_CODEC_OPUS)
403 404 405 406
		return;

	/* rewind the stream, because ogg_codec_detect() has
	   moved it */
407
	input_stream.LockRewind(IgnoreError());
408 409

	MPDOpusDecoder d(decoder, input_stream);
410
	OggSyncState oy(input_stream, &decoder);
411

412
	if (!d.ReadFirstPage(oy))
413 414
		return;

415
	while (true) {
416
		auto cmd = d.HandlePackets();
417
		if (cmd == DecoderCommand::SEEK) {
418
			if (d.Seek(oy, decoder_seek_where_frame(decoder)))
419 420 421 422 423 424 425
				decoder_command_finished(decoder);
			else
				decoder_seek_error(decoder);

			continue;
		}

426
		if (cmd != DecoderCommand::NONE)
427 428
			break;

429
		if (!d.ReadNextPage(oy))
430
			break;
431 432 433 434
	}
}

static bool
435
mpd_opus_scan_stream(InputStream &is,
436 437
		     const struct tag_handler *handler, void *handler_ctx)
{
438
	OggSyncState oy(is);
439

440
	ogg_stream_state os;
441
	if (!oy.ExpectFirstPage(os))
442 443
		return false;

444 445
	/* read at most 64 more pages */
	unsigned remaining_pages = 64;
446

447 448
	unsigned remaining_packets = 4;

449 450 451
	bool result = false;

	ogg_packet packet;
452
	while (remaining_packets > 0) {
453 454 455 456 457 458 459 460 461 462
		int r = ogg_stream_packetout(&os, &packet);
		if (r < 0) {
			result = false;
			break;
		}

		if (r == 0) {
			if (remaining_pages-- == 0)
				break;

463
			if (!oy.ExpectPageIn(os)) {
464 465 466 467 468 469 470
				result = false;
				break;
			}

			continue;
		}

471 472
		--remaining_packets;

473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
		if (packet.b_o_s) {
			if (!IsOpusHead(packet))
				break;

			unsigned channels;
			if (!ScanOpusHeader(packet.packet, packet.bytes, channels) ||
			    !audio_valid_channel_count(channels)) {
				result = false;
				break;
			}

			result = true;
		} else if (!result)
			break;
		else if (IsOpusTags(packet)) {
			if (!ScanOpusTags(packet.packet, packet.bytes,
489
					  nullptr,
490 491 492 493 494 495 496
					  handler, handler_ctx))
				result = false;

			break;
		}
	}

497 498 499 500 501 502
	if (packet.e_o_s || OggSeekFindEOS(oy, os, packet, is)) {
		const auto duration =
			SongTime::FromScale<uint64_t>(packet.granulepos,
						      opus_sample_rate);
		tag_handler_invoke_duration(handler, handler_ctx, duration);
	}
503

504 505 506 507 508 509 510 511 512 513 514 515 516
	ogg_stream_clear(&os);

	return result;
}

static const char *const opus_suffixes[] = {
	"opus",
	"ogg",
	"oga",
	nullptr
};

static const char *const opus_mime_types[] = {
517 518 519 520 521 522 523
	/* the official MIME type (RFC 5334) */
	"audio/ogg",

	/* deprecated (RFC 5334) */
	"application/ogg",

	/* deprecated; from an early draft */
524 525 526 527
	"audio/opus",
	nullptr
};

528
const struct DecoderPlugin opus_decoder_plugin = {
529 530 531 532 533 534 535 536 537 538 539
	"opus",
	mpd_opus_init,
	nullptr,
	mpd_opus_stream_decode,
	nullptr,
	nullptr,
	mpd_opus_scan_stream,
	nullptr,
	opus_suffixes,
	opus_mime_types,
};