OpusEncoderPlugin.cxx 9.13 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright 2003-2017 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"
#include "OpusEncoderPlugin.hxx"
22
#include "OggEncoder.hxx"
23
#include "AudioFormat.hxx"
24
#include "config/ConfigError.hxx"
25
#include "util/Alloc.hxx"
26
#include "system/ByteOrder.hxx"
27
#include "util/StringUtil.hxx"
28 29 30 31

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

32 33
#include <stdexcept>

34
#include <assert.h>
35
#include <stdlib.h>
36

37
namespace {
38

39
class OpusEncoder final : public OggEncoder {
40
	const AudioFormat audio_format;
41

42
	const size_t frame_size;
43

44 45 46
	const size_t buffer_frames, buffer_size;
	size_t buffer_position = 0;
	uint8_t *const buffer;
47

48
	::OpusEncoder *const enc;
49 50 51

	unsigned char buffer2[1275 * 3 + 7];

52 53
	int lookahead;

54
	ogg_int64_t packetno = 0;
55

56
	ogg_int64_t granulepos = 0;
57

58
public:
59
	OpusEncoder(AudioFormat &_audio_format, ::OpusEncoder *_enc, bool _chaining);
60
	~OpusEncoder() override;
61

62
	/* virtual methods from class Encoder */
63 64
	void End() override;
	void Write(const void *data, size_t length) override;
65

66 67
	void PreTag() override;
	void SendTag(const Tag &tag) override;
68

69
private:
70 71
	void DoEncode(bool eos);
	void WriteSilence(unsigned fill_frames);
72

73
	void GenerateHeaders(const Tag *tag);
74
	void GenerateHead();
75
	void GenerateTags(const Tag *tag);
76 77
};

78
class PreparedOpusEncoder final : public PreparedEncoder {
79 80 81
	opus_int32 bitrate;
	int complexity;
	int signal;
82
	const bool chaining;
83

84
public:
85
	PreparedOpusEncoder(const ConfigBlock &block);
86 87

	/* virtual methods from class PreparedEncoder */
88
	Encoder *Open(AudioFormat &audio_format) override;
89 90 91 92

	const char *GetMimeType() const override {
		return "audio/ogg";
	}
93 94
};

95
PreparedOpusEncoder::PreparedOpusEncoder(const ConfigBlock &block)
96
	:chaining(block.GetBlockValue("opustags", false))
97
{
98
	const char *value = block.GetBlockValue("bitrate", "auto");
99
	if (strcmp(value, "auto") == 0)
100
		bitrate = OPUS_AUTO;
101
	else if (strcmp(value, "max") == 0)
102
		bitrate = OPUS_BITRATE_MAX;
103 104
	else {
		char *endptr;
105
		bitrate = strtoul(value, &endptr, 10);
106
		if (endptr == value || *endptr != 0 ||
107 108
		    bitrate < 500 || bitrate > 512000)
			throw std::runtime_error("Invalid bit rate");
109 110
	}

111
	complexity = block.GetBlockValue("complexity", 10u);
112 113
	if (complexity > 10)
		throw std::runtime_error("Invalid complexity");
114

115
	value = block.GetBlockValue("signal", "auto");
116
	if (strcmp(value, "auto") == 0)
117
		signal = OPUS_AUTO;
118
	else if (strcmp(value, "voice") == 0)
119
		signal = OPUS_SIGNAL_VOICE;
120
	else if (strcmp(value, "music") == 0)
121
		signal = OPUS_SIGNAL_MUSIC;
122 123
	else
		throw std::runtime_error("Invalid signal");
124 125
}

126
static PreparedEncoder *
127
opus_encoder_init(const ConfigBlock &block)
128
{
129
	return new PreparedOpusEncoder(block);
130 131
}

132 133
OpusEncoder::OpusEncoder(AudioFormat &_audio_format, ::OpusEncoder *_enc, bool _chaining)
	:OggEncoder(_chaining),
134 135 136 137 138 139 140 141
	 audio_format(_audio_format),
	 frame_size(_audio_format.GetFrameSize()),
	 buffer_frames(_audio_format.sample_rate / 50),
	 buffer_size(frame_size * buffer_frames),
	 buffer((unsigned char *)xalloc(buffer_size)),
	 enc(_enc)
{
	opus_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&lookahead));
142
	GenerateHeaders(nullptr);
143 144 145
}

Encoder *
146
PreparedOpusEncoder::Open(AudioFormat &audio_format)
147 148
{
	/* libopus supports only 48 kHz */
149
	audio_format.sample_rate = 48000;
150

151 152
	if (audio_format.channels > 2)
		audio_format.channels = 1;
153

154
	switch (audio_format.format) {
155 156
	case SampleFormat::S16:
	case SampleFormat::FLOAT:
157 158
		break;

159
	case SampleFormat::S8:
160
		audio_format.format = SampleFormat::S16;
161 162 163
		break;

	default:
164
		audio_format.format = SampleFormat::FLOAT;
165 166 167
		break;
	}

168
	int error_code;
169 170 171 172
	auto *enc = opus_encoder_create(audio_format.sample_rate,
					audio_format.channels,
					OPUS_APPLICATION_AUDIO,
					&error_code);
173 174
	if (enc == nullptr)
		throw std::runtime_error(opus_strerror(error_code));
175

176 177 178
	opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate));
	opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
	opus_encoder_ctl(enc, OPUS_SET_SIGNAL(signal));
179

180
	return new OpusEncoder(audio_format, enc, chaining);
181 182
}

183
OpusEncoder::~OpusEncoder()
184 185 186 187 188
{
	free(buffer);
	opus_encoder_destroy(enc);
}

189 190
void
OpusEncoder::DoEncode(bool eos)
191
{
192
	assert(buffer_position == buffer_size || eos);
193 194

	opus_int32 result =
195 196
		audio_format.format == SampleFormat::S16
		? opus_encode(enc,
197 198 199 200
		              (const opus_int16 *)buffer,
		              buffer_frames,
		              buffer2,
		              sizeof(buffer2))
201
		: opus_encode_float(enc,
202 203 204 205
		                    (const float *)buffer,
		                    buffer_frames,
		                    buffer2,
		                    sizeof(buffer2));
206 207
	if (result < 0)
		throw std::runtime_error("Opus encoder error");
208

209
	granulepos += buffer_position / frame_size;
210

211
	ogg_packet packet;
212
	packet.packet = buffer2;
213 214 215
	packet.bytes = result;
	packet.b_o_s = false;
	packet.e_o_s = eos;
216 217 218
	packet.granulepos = granulepos;
	packet.packetno = packetno++;
	stream.PacketIn(packet);
219

220
	buffer_position = 0;
221 222
}

223 224
void
OpusEncoder::End()
225
{
226 227
	memset(buffer + buffer_position, 0,
	       buffer_size - buffer_position);
228
	DoEncode(true);
229
	Flush();
230 231
}

232 233
void
OpusEncoder::WriteSilence(unsigned fill_frames)
234 235
{
	size_t fill_bytes = fill_frames * frame_size;
236 237

	while (fill_bytes > 0) {
238
		size_t nbytes = buffer_size - buffer_position;
239 240 241
		if (nbytes > fill_bytes)
			nbytes = fill_bytes;

242 243
		memset(buffer + buffer_position, 0, nbytes);
		buffer_position += nbytes;
244 245
		fill_bytes -= nbytes;

246 247
		if (buffer_position == buffer_size)
			DoEncode(false);
248 249 250
	}
}

251 252
void
OpusEncoder::Write(const void *_data, size_t length)
253 254 255
{
	const uint8_t *data = (const uint8_t *)_data;

256
	if (lookahead > 0) {
257 258 259
		/* generate some silence at the beginning of the
		   stream */

260
		assert(buffer_position == 0);
261

262
		WriteSilence(lookahead);
263
		lookahead = 0;
264 265
	}

266
	while (length > 0) {
267
		size_t nbytes = buffer_size - buffer_position;
268 269 270
		if (nbytes > length)
			nbytes = length;

271
		memcpy(buffer + buffer_position, data, nbytes);
272 273
		data += nbytes;
		length -= nbytes;
274
		buffer_position += nbytes;
275

276 277
		if (buffer_position == buffer_size)
			DoEncode(false);
278 279 280
	}
}

281 282 283 284 285 286 287
void
OpusEncoder::GenerateHeaders(const Tag *tag)
{
	GenerateHead();
	GenerateTags(tag);
}

288 289
void
OpusEncoder::GenerateHead()
290 291 292 293
{
	unsigned char header[19];
	memcpy(header, "OpusHead", 8);
	header[8] = 1;
294 295 296
	header[9] = audio_format.channels;
	*(uint16_t *)(header + 10) = ToLE16(lookahead);
	*(uint32_t *)(header + 12) = ToLE32(audio_format.sample_rate);
297 298 299 300 301 302
	header[16] = 0;
	header[17] = 0;
	header[18] = 0;

	ogg_packet packet;
	packet.packet = header;
303
	packet.bytes = sizeof(header);
304 305 306
	packet.b_o_s = true;
	packet.e_o_s = false;
	packet.granulepos = 0;
307 308
	packet.packetno = packetno++;
	stream.PacketIn(packet);
309
	// flush not needed because libogg autoflushes on b_o_s flag
310 311
}

312
void
313
OpusEncoder::GenerateTags(const Tag *tag)
314 315 316 317
{
	const char *version = opus_get_version_string();
	size_t version_length = strlen(version);

318
	// len("OpusTags") + 4 byte version length + len(version) + 4 byte tag count
319
	size_t comments_size = 8 + 4 + version_length + 4;
320 321 322 323 324 325 326 327 328
	uint32_t tag_count = 0;
	if (tag) {
		for (const auto &item: *tag) {
			++tag_count;
			// 4 byte length + len(tagname) + len('=') + len(value)
			comments_size += 4 + strlen(tag_item_names[item.type]) + 1 + strlen(item.value);
		}
	}

329
	unsigned char *comments = (unsigned char *)xalloc(comments_size);
330 331
	unsigned char *p = comments;

332
	memcpy(comments, "OpusTags", 8);
333
	*(uint32_t *)(comments + 8) = ToLE32(version_length);
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
	p += 12;

	memcpy(p, version, version_length);
	p += version_length;

	tag_count = ToLE32(tag_count);
	memcpy(p, &tag_count, 4);
	p += 4;

	if (tag) {
		for (const auto &item: *tag) {
			size_t tag_name_len = strlen(tag_item_names[item.type]);
			size_t tag_val_len = strlen(item.value);
			uint32_t tag_len_le = ToLE32(tag_name_len + 1 + tag_val_len);

			memcpy(p, &tag_len_le, 4);
			p += 4;

			ToUpperASCII((char *)p, tag_item_names[item.type], tag_name_len + 1);
			p += tag_name_len;

			*p++ = '=';

			memcpy(p, item.value, tag_val_len);
			p += tag_val_len;
		}
	}
	assert(comments + comments_size == p);
362 363 364 365 366 367 368

	ogg_packet packet;
	packet.packet = comments;
	packet.bytes = comments_size;
	packet.b_o_s = false;
	packet.e_o_s = false;
	packet.granulepos = 0;
369 370
	packet.packetno = packetno++;
	stream.PacketIn(packet);
371
	Flush();
372

373
	free(comments);
374 375
}

376 377
void
OpusEncoder::PreTag()
378
{
379 380 381 382 383
	End();
	packetno = 0;
	granulepos = 0; // not really required, but useful to prevent wraparound
	opus_encoder_ctl(enc, OPUS_RESET_STATE);
}
384

385 386 387 388 389 390
void
OpusEncoder::SendTag(const Tag &tag)
{
	stream.Reinitialize(GenerateOggSerial());
	opus_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&lookahead));
	GenerateHeaders(&tag);
391
}
392

393 394
}

395
const EncoderPlugin opus_encoder_plugin = {
396 397 398
	"opus",
	opus_encoder_init,
};