flac_plugin.c 13.3 KB
Newer Older
Warren Dukes's avatar
Warren Dukes committed
1
/* the Music Player Daemon (MPD)
2
 * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
Warren Dukes's avatar
Warren Dukes committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * This project's homepage is: 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

19
#include "_flac_common.h"
Warren Dukes's avatar
Warren Dukes committed
20 21
#include "../utils.h"
#include "../log.h"
Warren Dukes's avatar
Warren Dukes committed
22

23 24
#include <assert.h>

25
/* this code was based on flac123, from flac-tools */
Warren Dukes's avatar
Warren Dukes committed
26

27
static flac_read_status flacRead(mpd_unused const flac_decoder * flacDec,
28
                                  FLAC__byte buf[],
29
				  flac_read_status_size_t *bytes,
30
				  void *fdata)
Avuton Olrich's avatar
Avuton Olrich committed
31 32
{
	FlacData *data = (FlacData *) fdata;
33 34
	size_t r;

Max Kellermann's avatar
Max Kellermann committed
35
	r = decoder_read(data->decoder, data->inStream, (void *)buf, *bytes);
36
	*bytes = r;
Avuton Olrich's avatar
Avuton Olrich committed
37

38 39
	if (r == 0) {
		if (decoder_get_command(data->decoder) != DECODE_COMMAND_NONE ||
40
		    input_stream_eof(data->inStream))
41
			return flac_read_status_eof;
42
		else
43
			return flac_read_status_abort;
44
	}
45

46
	return flac_read_status_continue;
47 48
}

49
static flac_seek_status flacSeek(mpd_unused const flac_decoder * flacDec,
50 51
				 FLAC__uint64 offset,
				 void *fdata)
52
{
Avuton Olrich's avatar
Avuton Olrich committed
53
	FlacData *data = (FlacData *) fdata;
54

55
	if (!input_stream_seek(data->inStream, offset, SEEK_SET))
56
		return flac_seek_status_error;
57

58
	return flac_seek_status_ok;
59 60
}

61
static flac_tell_status flacTell(mpd_unused const flac_decoder * flacDec,
62 63
				 FLAC__uint64 * offset,
				 void *fdata)
64
{
Avuton Olrich's avatar
Avuton Olrich committed
65
	FlacData *data = (FlacData *) fdata;
66

Avuton Olrich's avatar
Avuton Olrich committed
67
	*offset = (long)(data->inStream->offset);
68

69
	return flac_tell_status_ok;
70 71
}

72
static flac_length_status flacLength(mpd_unused const flac_decoder * flacDec,
73 74
				     FLAC__uint64 * length,
				     void *fdata)
75
{
Avuton Olrich's avatar
Avuton Olrich committed
76
	FlacData *data = (FlacData *) fdata;
77

Avuton Olrich's avatar
Avuton Olrich committed
78
	*length = (size_t) (data->inStream->size);
79

80
	return flac_length_status_ok;
81 82
}

83
static FLAC__bool flacEOF(mpd_unused const flac_decoder * flacDec, void *fdata)
Avuton Olrich's avatar
Avuton Olrich committed
84 85 86
{
	FlacData *data = (FlacData *) fdata;

87 88
	return (decoder_get_command(data->decoder) != DECODE_COMMAND_NONE &&
		decoder_get_command(data->decoder) != DECODE_COMMAND_SEEK) ||
89
		input_stream_eof(data->inStream);
90 91
}

92
static void flacError(mpd_unused const flac_decoder *dec,
Avuton Olrich's avatar
Avuton Olrich committed
93
		      FLAC__StreamDecoderErrorStatus status, void *fdata)
94
{
Avuton Olrich's avatar
Avuton Olrich committed
95
	flac_error_common_cb("flac", status, (FlacData *) fdata);
Warren Dukes's avatar
Warren Dukes committed
96 97
}

98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
#if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7
static void flacPrintErroredState(FLAC__SeekableStreamDecoderState state)
{
	const char *str = ""; /* "" to silence compiler warning */
	switch (state) {
	case FLAC__SEEKABLE_STREAM_DECODER_OK:
	case FLAC__SEEKABLE_STREAM_DECODER_SEEKING:
	case FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM:
		return;
	case FLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR:
		str = "allocation error";
		break;
	case FLAC__SEEKABLE_STREAM_DECODER_READ_ERROR:
		str = "read error";
		break;
	case FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR:
		str = "seek error";
		break;
	case FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR:
		str = "seekable stream error";
		break;
	case FLAC__SEEKABLE_STREAM_DECODER_ALREADY_INITIALIZED:
		str = "decoder already initialized";
		break;
	case FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK:
		str = "invalid callback";
		break;
	case FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED:
		str = "decoder uninitialized";
	}
	ERROR("flac %s\n", str);
}

static int flac_init(FLAC__SeekableStreamDecoder *dec,
                     FLAC__SeekableStreamDecoderReadCallback read_cb,
                     FLAC__SeekableStreamDecoderSeekCallback seek_cb,
                     FLAC__SeekableStreamDecoderTellCallback tell_cb,
                     FLAC__SeekableStreamDecoderLengthCallback length_cb,
                     FLAC__SeekableStreamDecoderEofCallback eof_cb,
                     FLAC__SeekableStreamDecoderWriteCallback write_cb,
                     FLAC__SeekableStreamDecoderMetadataCallback metadata_cb,
                     FLAC__SeekableStreamDecoderErrorCallback error_cb,
                     void *data)
{
	int s = 1;
	s &= FLAC__seekable_stream_decoder_set_read_callback(dec, read_cb);
	s &= FLAC__seekable_stream_decoder_set_seek_callback(dec, seek_cb);
	s &= FLAC__seekable_stream_decoder_set_tell_callback(dec, tell_cb);
	s &= FLAC__seekable_stream_decoder_set_length_callback(dec, length_cb);
	s &= FLAC__seekable_stream_decoder_set_eof_callback(dec, eof_cb);
	s &= FLAC__seekable_stream_decoder_set_write_callback(dec, write_cb);
	s &= FLAC__seekable_stream_decoder_set_metadata_callback(dec,
	                                                         metadata_cb);
	s &= FLAC__seekable_stream_decoder_set_metadata_respond(dec,
	                                  FLAC__METADATA_TYPE_VORBIS_COMMENT);
	s &= FLAC__seekable_stream_decoder_set_error_callback(dec, error_cb);
	s &= FLAC__seekable_stream_decoder_set_client_data(dec, data);
	if (!s || (FLAC__seekable_stream_decoder_init(dec) !=
	           FLAC__SEEKABLE_STREAM_DECODER_OK))
		return 0;
	return 1;
}
#else /* FLAC_API_VERSION_CURRENT >= 7 */
161
static void flacPrintErroredState(FLAC__StreamDecoderState state)
162
{
163
	const char *str = ""; /* "" to silence compiler warning */
Avuton Olrich's avatar
Avuton Olrich committed
164
	switch (state) {
165 166 167 168 169 170 171 172
	case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
	case FLAC__STREAM_DECODER_READ_METADATA:
	case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
	case FLAC__STREAM_DECODER_READ_FRAME:
	case FLAC__STREAM_DECODER_END_OF_STREAM:
		return;
	case FLAC__STREAM_DECODER_OGG_ERROR:
		str = "error in the Ogg layer";
173
		break;
174 175
	case FLAC__STREAM_DECODER_SEEK_ERROR:
		str = "seek error";
Warren Dukes's avatar
Warren Dukes committed
176
		break;
177 178
	case FLAC__STREAM_DECODER_ABORTED:
		str = "decoder aborted by read";
Warren Dukes's avatar
Warren Dukes committed
179
		break;
180 181
	case FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR:
		str = "allocation error";
Warren Dukes's avatar
Warren Dukes committed
182
		break;
183 184
	case FLAC__STREAM_DECODER_UNINITIALIZED:
		str = "decoder uninitialized";
Warren Dukes's avatar
Warren Dukes committed
185
	}
186
	ERROR("flac %s\n", str);
Warren Dukes's avatar
Warren Dukes committed
187
}
188
#endif /* FLAC_API_VERSION_CURRENT >= 7 */
Warren Dukes's avatar
Warren Dukes committed
189

190
static void flacMetadata(mpd_unused const flac_decoder * dec,
Avuton Olrich's avatar
Avuton Olrich committed
191
			 const FLAC__StreamMetadata * block, void *vdata)
192
{
Avuton Olrich's avatar
Avuton Olrich committed
193
	flac_metadata_common_cb(block, (FlacData *) vdata);
Warren Dukes's avatar
Warren Dukes committed
194 195
}

196 197
static FLAC__StreamDecoderWriteStatus flacWrite(const flac_decoder *dec,
                                                const FLAC__Frame * frame,
Avuton Olrich's avatar
Avuton Olrich committed
198 199
						const FLAC__int32 * const buf[],
						void *vdata)
200
{
Warren Dukes's avatar
Warren Dukes committed
201
	FLAC__uint32 samples = frame->header.blocksize;
202
	FlacData *data = (FlacData *) vdata;
203 204
	float timeChange;
	FLAC__uint64 newPosition = 0;
Avuton Olrich's avatar
Avuton Olrich committed
205 206 207 208

	timeChange = ((float)samples) / frame->header.sample_rate;
	data->time += timeChange;

209
	flac_get_decode_position(dec, &newPosition);
210
	if (data->position && newPosition >= data->position) {
211 212
		assert(timeChange >= 0);

Avuton Olrich's avatar
Avuton Olrich committed
213 214 215
		data->bitRate =
		    ((newPosition - data->position) * 8.0 / timeChange)
		    / 1000 + 0.5;
216 217
	}
	data->position = newPosition;
Warren Dukes's avatar
Warren Dukes committed
218

219
	return flac_common_write(data, frame, buf);
Warren Dukes's avatar
Warren Dukes committed
220 221
}

222
static struct tag *
223
flacMetadataDup(const char *file, bool *vorbisCommentFound)
Avuton Olrich's avatar
Avuton Olrich committed
224
{
225
	struct tag *ret = NULL;
Avuton Olrich's avatar
Avuton Olrich committed
226 227
	FLAC__Metadata_SimpleIterator *it;
	FLAC__StreamMetadata *block = NULL;
Warren Dukes's avatar
Warren Dukes committed
228

229
	*vorbisCommentFound = false;
Warren Dukes's avatar
Warren Dukes committed
230 231

	it = FLAC__metadata_simple_iterator_new();
Avuton Olrich's avatar
Avuton Olrich committed
232
	if (!FLAC__metadata_simple_iterator_init(it, file, 1, 0)) {
233 234 235 236 237 238
		const char *err;
		FLAC_API FLAC__Metadata_SimpleIteratorStatus s;

		s = FLAC__metadata_simple_iterator_status(it);

		switch (s) { /* slightly more human-friendly messages: */
Avuton Olrich's avatar
Avuton Olrich committed
239
		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT:
240
			err = "illegal input";
Avuton Olrich's avatar
Avuton Olrich committed
241 242
			break;
		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE:
243
			err = "error opening file";
Avuton Olrich's avatar
Avuton Olrich committed
244 245
			break;
		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE:
246
			err = "not a FLAC file";
Avuton Olrich's avatar
Avuton Olrich committed
247 248
			break;
		default:
249
			err = FLAC__Metadata_SimpleIteratorStatusString[s];
250
		}
251 252 253
		DEBUG("flacMetadataDup: Reading '%s' "
		      "metadata gave the following error: %s\n",
		      file, err);
Warren Dukes's avatar
Warren Dukes committed
254 255 256
		FLAC__metadata_simple_iterator_delete(it);
		return ret;
	}
Avuton Olrich's avatar
Avuton Olrich committed
257

Warren Dukes's avatar
Warren Dukes committed
258 259
	do {
		block = FLAC__metadata_simple_iterator_get_block(it);
Avuton Olrich's avatar
Avuton Olrich committed
260 261 262
		if (!block)
			break;
		if (block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
263 264
			ret = copyVorbisCommentBlockToMpdTag(block, ret);

Avuton Olrich's avatar
Avuton Olrich committed
265
			if (ret)
266
				*vorbisCommentFound = true;
Avuton Olrich's avatar
Avuton Olrich committed
267 268
		} else if (block->type == FLAC__METADATA_TYPE_STREAMINFO) {
			if (!ret)
269
				ret = tag_new();
Warren Dukes's avatar
Warren Dukes committed
270
			ret->time = ((float)block->data.stream_info.
Avuton Olrich's avatar
Avuton Olrich committed
271 272
				     total_samples) /
			    block->data.stream_info.sample_rate + 0.5;
Warren Dukes's avatar
Warren Dukes committed
273 274
		}
		FLAC__metadata_object_delete(block);
Avuton Olrich's avatar
Avuton Olrich committed
275
	} while (FLAC__metadata_simple_iterator_next(it));
Warren Dukes's avatar
Warren Dukes committed
276 277 278 279 280

	FLAC__metadata_simple_iterator_delete(it);
	return ret;
}

281
static struct tag *flacTagDup(const char *file)
Avuton Olrich's avatar
Avuton Olrich committed
282
{
283
	struct tag *ret = NULL;
284
	bool foundVorbisComment = false;
Warren Dukes's avatar
Warren Dukes committed
285

286
	ret = flacMetadataDup(file, &foundVorbisComment);
Avuton Olrich's avatar
Avuton Olrich committed
287 288 289
	if (!ret) {
		DEBUG("flacTagDup: Failed to grab information from: %s\n",
		      file);
290 291
		return NULL;
	}
Avuton Olrich's avatar
Avuton Olrich committed
292
	if (!foundVorbisComment) {
293
		struct tag *temp = tag_id3_load(file);
Avuton Olrich's avatar
Avuton Olrich committed
294
		if (temp) {
Warren Dukes's avatar
Warren Dukes committed
295
			temp->time = ret->time;
296
			tag_free(ret);
Warren Dukes's avatar
Warren Dukes committed
297 298 299 300 301 302 303
			ret = temp;
		}
	}

	return ret;
}

304
static bool
305
flac_decode_internal(struct decoder * decoder, struct input_stream *inStream,
306
		     bool is_ogg)
307
{
308
	flac_decoder *flacDec;
309
	FlacData data;
310
	const char *err = NULL;
311

312
	if (!(flacDec = flac_new()))
313
		return false;
Max Kellermann's avatar
Max Kellermann committed
314
	init_FlacData(&data, decoder, inStream);
315

316
#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7
317 318 319 320 321 322 323
        if(!FLAC__stream_decoder_set_metadata_respond(flacDec, FLAC__METADATA_TYPE_VORBIS_COMMENT))
        {
                DEBUG(__FILE__": Failed to set metadata respond\n");
        }
#endif


324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
	if (is_ogg) {
		if (!flac_ogg_init(flacDec, flacRead, flacSeek, flacTell,
		                   flacLength, flacEOF, flacWrite, flacMetadata,
			           flacError, (void *)&data)) {
			err = "doing Ogg init()";
			goto fail;
		}
	} else {
		if (!flac_init(flacDec, flacRead, flacSeek, flacTell,
		               flacLength, flacEOF, flacWrite, flacMetadata,
			       flacError, (void *)&data)) {
			err = "doing init()";
			goto fail;
		}
		if (!flac_process_metadata(flacDec)) {
			err = "problem reading metadata";
			goto fail;
		}
342 343
	}

344 345
	decoder_initialized(decoder, &data.audio_format,
			    inStream->seekable, data.total_time);
346

347
	while (true) {
348
		if (!flac_process_single(flacDec))
349
			break;
350
		if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK) {
351
			FLAC__uint64 sampleToSeek = decoder_seek_where(decoder) *
352
			    data.audio_format.sample_rate + 0.5;
353
			if (flac_seek_absolute(flacDec, sampleToSeek)) {
354
				data.time = ((float)sampleToSeek) /
355
				    data.audio_format.sample_rate;
356
				data.position = 0;
357
				decoder_command_finished(decoder);
358
			} else
359
				decoder_seek_error(decoder);
360 361
		} else if (flac_get_state(flacDec) == flac_decoder_eof)
			break;
362
	}
363
	if (decoder_get_command(decoder) != DECODE_COMMAND_STOP) {
364 365
		flacPrintErroredState(flac_get_state(flacDec));
		flac_finish(flacDec);
366 367 368 369 370 371 372
	}

fail:
	if (data.replayGainInfo)
		freeReplayGainInfo(data.replayGainInfo);

	if (flacDec)
373
		flac_delete(flacDec);
374

375 376
	if (err) {
		ERROR("flac %s\n", err);
377
		return false;
378
	}
379
	return true;
380 381
}

382
static bool
383
flac_decode(struct decoder * decoder, struct input_stream *inStream)
384
{
385
	return flac_decode_internal(decoder, inStream, false);
386 387
}

388 389
#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7 && \
	!defined(HAVE_OGGFLAC)
390
static struct tag *oggflac_tag_dup(const char *file)
391
{
392
	struct tag *ret = NULL;
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
	FLAC__Metadata_Iterator *it;
	FLAC__StreamMetadata *block;
	FLAC__Metadata_Chain *chain = FLAC__metadata_chain_new();

	if (!(FLAC__metadata_chain_read_ogg(chain, file)))
		goto out;
	it = FLAC__metadata_iterator_new();
	FLAC__metadata_iterator_init(it, chain);
	do {
		if (!(block = FLAC__metadata_iterator_get_block(it)))
			break;
		if (block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
			ret = copyVorbisCommentBlockToMpdTag(block, ret);
		} else if (block->type == FLAC__METADATA_TYPE_STREAMINFO) {
			if (!ret)
408
				ret = tag_new();
409 410 411 412 413 414 415 416
			ret->time = ((float)block->data.stream_info.
				     total_samples) /
			    block->data.stream_info.sample_rate + 0.5;
		}
	} while (FLAC__metadata_iterator_next(it));
	FLAC__metadata_iterator_delete(it);
out:
	FLAC__metadata_chain_delete(chain);
417 418 419
	return ret;
}

420
static bool
421
oggflac_decode(struct decoder *decoder, struct input_stream *inStream)
422
{
423
	return flac_decode_internal(decoder, inStream, true);
424 425
}

426 427
static bool
oggflac_try_decode(struct input_stream *inStream)
428
{
429 430
	return FLAC_API_SUPPORTS_OGG_FLAC &&
		ogg_stream_type_detect(inStream) == FLAC;
431 432
}

433 434 435 436 437 438 439
static const char *const oggflac_suffixes[] = { "ogg", "oga", NULL };
static const char *const oggflac_mime_types[] = {
	"audio/x-flac+ogg",
	"application/ogg",
	"application/x-ogg",
	NULL
};
440

441
const struct decoder_plugin oggflacPlugin = {
442 443 444 445 446 447 448
	.name = "oggflac",
	.try_decode = oggflac_try_decode,
	.stream_decode = oggflac_decode,
	.tag_dup = oggflac_tag_dup,
	.suffixes = oggflac_suffixes,
	.mime_types = oggflac_mime_types
};
449 450 451

#endif /* FLAC_API_VERSION_CURRENT >= 7 */

452 453 454 455
static const char *const flacSuffixes[] = { "flac", NULL };
static const char *const flac_mime_types[] = {
	"audio/x-flac", "application/x-flac", NULL
};
Warren Dukes's avatar
Warren Dukes committed
456

457
const struct decoder_plugin flacPlugin = {
458 459 460 461 462
	.name = "flac",
	.stream_decode = flac_decode,
	.tag_dup = flacTagDup,
	.suffixes = flacSuffixes,
	.mime_types = flac_mime_types
Warren Dukes's avatar
Warren Dukes committed
463
};