flac_plugin.c 13.8 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 <assert.h>
22
#include <unistd.h>
23

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

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

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

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

45
	return flac_read_status_continue;
46 47
}

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

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

57
	return flac_seek_status_ok;
58 59
}

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

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

68
	return flac_tell_status_ok;
69 70
}

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

77 78 79
	if (data->inStream->size < 0)
		return flac_length_status_unsupported;

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

82
	return flac_length_status_ok;
83 84
}

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

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

94
static void flacError(mpd_unused const flac_decoder *dec,
Avuton Olrich's avatar
Avuton Olrich committed
95
		      FLAC__StreamDecoderErrorStatus status, void *fdata)
96
{
Avuton Olrich's avatar
Avuton Olrich committed
97
	flac_error_common_cb("flac", status, (FlacData *) fdata);
Warren Dukes's avatar
Warren Dukes committed
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
#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";
	}
130 131

	g_warning("%s\n", str);
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 161 162 163
}

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 */
164
static void flacPrintErroredState(FLAC__StreamDecoderState state)
165
{
166
	const char *str = ""; /* "" to silence compiler warning */
Avuton Olrich's avatar
Avuton Olrich committed
167
	switch (state) {
168 169 170 171 172 173 174 175
	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";
176
		break;
177 178
	case FLAC__STREAM_DECODER_SEEK_ERROR:
		str = "seek error";
Warren Dukes's avatar
Warren Dukes committed
179
		break;
180 181
	case FLAC__STREAM_DECODER_ABORTED:
		str = "decoder aborted by read";
Warren Dukes's avatar
Warren Dukes committed
182
		break;
183 184
	case FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR:
		str = "allocation error";
Warren Dukes's avatar
Warren Dukes committed
185
		break;
186 187
	case FLAC__STREAM_DECODER_UNINITIALIZED:
		str = "decoder uninitialized";
Warren Dukes's avatar
Warren Dukes committed
188
	}
189 190

	g_warning("%s\n", str);
Warren Dukes's avatar
Warren Dukes committed
191
}
192
#endif /* FLAC_API_VERSION_CURRENT >= 7 */
Warren Dukes's avatar
Warren Dukes committed
193

194
static void flacMetadata(mpd_unused const flac_decoder * dec,
Avuton Olrich's avatar
Avuton Olrich committed
195
			 const FLAC__StreamMetadata * block, void *vdata)
196
{
Avuton Olrich's avatar
Avuton Olrich committed
197
	flac_metadata_common_cb(block, (FlacData *) vdata);
Warren Dukes's avatar
Warren Dukes committed
198 199
}

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

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

213
	flac_get_decode_position(dec, &newPosition);
214
	if (data->position && newPosition >= data->position) {
215 216
		assert(timeChange >= 0);

Avuton Olrich's avatar
Avuton Olrich committed
217 218 219
		data->bitRate =
		    ((newPosition - data->position) * 8.0 / timeChange)
		    / 1000 + 0.5;
220 221
	}
	data->position = newPosition;
Warren Dukes's avatar
Warren Dukes committed
222

223
	return flac_common_write(data, frame, buf);
Warren Dukes's avatar
Warren Dukes committed
224 225
}

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

233
	*vorbisCommentFound = false;
Warren Dukes's avatar
Warren Dukes committed
234 235

	it = FLAC__metadata_simple_iterator_new();
Avuton Olrich's avatar
Avuton Olrich committed
236
	if (!FLAC__metadata_simple_iterator_init(it, file, 1, 0)) {
237 238 239 240 241 242
		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
243
		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT:
244
			err = "illegal input";
Avuton Olrich's avatar
Avuton Olrich committed
245 246
			break;
		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE:
247
			err = "error opening file";
Avuton Olrich's avatar
Avuton Olrich committed
248 249
			break;
		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE:
250
			err = "not a FLAC file";
Avuton Olrich's avatar
Avuton Olrich committed
251 252
			break;
		default:
253
			err = FLAC__Metadata_SimpleIteratorStatusString[s];
254
		}
255 256
		g_debug("Reading '%s' metadata gave the following error: %s\n",
			file, err);
Warren Dukes's avatar
Warren Dukes committed
257 258 259
		FLAC__metadata_simple_iterator_delete(it);
		return ret;
	}
Avuton Olrich's avatar
Avuton Olrich committed
260

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

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

	FLAC__metadata_simple_iterator_delete(it);
	return ret;
}

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

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

	return ret;
}

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

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

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


326 327 328 329 330 331 332 333 334 335 336 337 338 339
	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;
		}
340 341 342 343 344
	}

	if (!flac_process_metadata(flacDec)) {
		err = "problem reading metadata";
		goto fail;
345 346
	}

347 348 349 350 351 352 353 354
	if (!audio_format_valid(&data.audio_format)) {
		g_warning("Invalid audio format: %u:%u:%u\n",
			  data.audio_format.sample_rate,
			  data.audio_format.bits,
			  data.audio_format.channels);
		goto fail;
	}

355 356
	decoder_initialized(decoder, &data.audio_format,
			    inStream->seekable, data.total_time);
357

358
	while (true) {
359
		if (!flac_process_single(flacDec))
360
			break;
361
		if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK) {
362
			FLAC__uint64 sampleToSeek = decoder_seek_where(decoder) *
363
			    data.audio_format.sample_rate + 0.5;
364
			if (flac_seek_absolute(flacDec, sampleToSeek)) {
365
				data.time = ((float)sampleToSeek) /
366
				    data.audio_format.sample_rate;
367
				data.position = 0;
368
				decoder_command_finished(decoder);
369
			} else
370
				decoder_seek_error(decoder);
371 372
		} else if (flac_get_state(flacDec) == flac_decoder_eof)
			break;
373
	}
374
	if (decoder_get_command(decoder) != DECODE_COMMAND_STOP) {
375 376
		flacPrintErroredState(flac_get_state(flacDec));
		flac_finish(flacDec);
377 378 379 380
	}

fail:
	if (data.replayGainInfo)
381
		replay_gain_info_free(data.replayGainInfo);
382 383

	if (flacDec)
384
		flac_delete(flacDec);
385

386 387
	if (err)
		g_warning("%s\n", err);
388 389
}

390
static void
391
flac_decode(struct decoder * decoder, struct input_stream *inStream)
392
{
393
	flac_decode_internal(decoder, inStream, false);
394 395
}

396 397
#ifndef HAVE_OGGFLAC

398 399 400
static bool
oggflac_init(void)
{
401
#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7
402
	return !!FLAC_API_SUPPORTS_OGG_FLAC;
403 404 405 406
#else
	/* disable oggflac when libflac is too old */
	return false;
#endif
407 408
}

409 410
#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7

411
static struct tag *oggflac_tag_dup(const char *file)
412
{
413
	struct tag *ret = NULL;
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
	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)
429
				ret = tag_new();
430 431 432 433 434 435 436 437
			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);
438 439 440
	return ret;
}

441
static void
442
oggflac_decode(struct decoder *decoder, struct input_stream *inStream)
443
{
444
	if (ogg_stream_type_detect(inStream) != FLAC)
445
		return;
446

447 448 449 450
	/* rewind the stream, because ogg_stream_type_detect() has
	   moved it */
	input_stream_seek(inStream, 0, SEEK_SET);

451
	flac_decode_internal(decoder, inStream, true);
452 453
}

454 455 456 457 458 459 460
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
};
461

462 463
#endif /* FLAC_API_VERSION_CURRENT >= 7 */

464
const struct decoder_plugin oggflacPlugin = {
465
	.name = "oggflac",
466
	.init = oggflac_init,
467
#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7
468 469 470 471
	.stream_decode = oggflac_decode,
	.tag_dup = oggflac_tag_dup,
	.suffixes = oggflac_suffixes,
	.mime_types = oggflac_mime_types
472
#endif
473
};
474

475
#endif /* HAVE_OGGFLAC */
476

477 478 479 480
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
481

482
const struct decoder_plugin flacPlugin = {
483 484 485 486 487
	.name = "flac",
	.stream_decode = flac_decode,
	.tag_dup = flacTagDup,
	.suffixes = flacSuffixes,
	.mime_types = flac_mime_types
Warren Dukes's avatar
Warren Dukes committed
488
};