flac_plugin.c 23.2 KB
Newer Older
1 2 3
/*
 * Copyright (C) 2003-2009 The Music Player Daemon Project
 * http://www.musicpd.org
Warren Dukes's avatar
Warren Dukes committed
4 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.
Warren Dukes's avatar
Warren Dukes committed
18 19
 */

20
#include "_flac_common.h"
Warren Dukes's avatar
Warren Dukes committed
21

22 23
#include <glib.h>

24
#include <assert.h>
25
#include <unistd.h>
26

27 28 29
#include <sys/stat.h>
#include <sys/types.h>

30 31 32 33
#ifdef HAVE_CUE /* libcue */
#include "../cue/cue_tag.h"
#endif

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

Max Kellermann's avatar
Max Kellermann committed
36 37 38 39
static flac_read_status
flac_read_cb(G_GNUC_UNUSED const flac_decoder *fd,
	     FLAC__byte buf[], flac_read_status_size_t *bytes,
	     void *fdata)
Avuton Olrich's avatar
Avuton Olrich committed
40
{
Max Kellermann's avatar
Max Kellermann committed
41
	struct flac_data *data = fdata;
42 43
	size_t r;

Max Kellermann's avatar
Max Kellermann committed
44 45
	r = decoder_read(data->decoder, data->input_stream,
			 (void *)buf, *bytes);
46
	*bytes = r;
Avuton Olrich's avatar
Avuton Olrich committed
47

48 49
	if (r == 0) {
		if (decoder_get_command(data->decoder) != DECODE_COMMAND_NONE ||
Max Kellermann's avatar
Max Kellermann committed
50
		    input_stream_eof(data->input_stream))
51
			return flac_read_status_eof;
52
		else
53
			return flac_read_status_abort;
54
	}
55

56
	return flac_read_status_continue;
57 58
}

Max Kellermann's avatar
Max Kellermann committed
59 60 61
static flac_seek_status
flac_seek_cb(G_GNUC_UNUSED const flac_decoder *fd,
	     FLAC__uint64 offset, void *fdata)
62
{
Max Kellermann's avatar
Max Kellermann committed
63
	struct flac_data *data = (struct flac_data *) fdata;
64

Max Kellermann's avatar
Max Kellermann committed
65
	if (!input_stream_seek(data->input_stream, offset, SEEK_SET))
66
		return flac_seek_status_error;
67

68
	return flac_seek_status_ok;
69 70
}

Max Kellermann's avatar
Max Kellermann committed
71 72 73
static flac_tell_status
flac_tell_cb(G_GNUC_UNUSED const flac_decoder *fd,
	     FLAC__uint64 * offset, void *fdata)
74
{
Max Kellermann's avatar
Max Kellermann committed
75
	struct flac_data *data = (struct flac_data *) fdata;
76

Max Kellermann's avatar
Max Kellermann committed
77
	*offset = (long)(data->input_stream->offset);
78

79
	return flac_tell_status_ok;
80 81
}

Max Kellermann's avatar
Max Kellermann committed
82 83 84
static flac_length_status
flac_length_cb(G_GNUC_UNUSED const flac_decoder *fd,
	       FLAC__uint64 * length, void *fdata)
85
{
Max Kellermann's avatar
Max Kellermann committed
86
	struct flac_data *data = (struct flac_data *) fdata;
87

Max Kellermann's avatar
Max Kellermann committed
88
	if (data->input_stream->size < 0)
89 90
		return flac_length_status_unsupported;

Max Kellermann's avatar
Max Kellermann committed
91
	*length = (size_t) (data->input_stream->size);
92

93
	return flac_length_status_ok;
94 95
}

Max Kellermann's avatar
Max Kellermann committed
96 97
static FLAC__bool
flac_eof_cb(G_GNUC_UNUSED const flac_decoder *fd, void *fdata)
Avuton Olrich's avatar
Avuton Olrich committed
98
{
Max Kellermann's avatar
Max Kellermann committed
99
	struct flac_data *data = (struct flac_data *) fdata;
Avuton Olrich's avatar
Avuton Olrich committed
100

101 102
	return (decoder_get_command(data->decoder) != DECODE_COMMAND_NONE &&
		decoder_get_command(data->decoder) != DECODE_COMMAND_SEEK) ||
Max Kellermann's avatar
Max Kellermann committed
103
		input_stream_eof(data->input_stream);
104 105
}

Max Kellermann's avatar
Max Kellermann committed
106 107 108
static void
flac_error_cb(G_GNUC_UNUSED const flac_decoder *fd,
	      FLAC__StreamDecoderErrorStatus status, void *fdata)
109
{
Max Kellermann's avatar
Max Kellermann committed
110
	flac_error_common_cb("flac", status, (struct flac_data *) fdata);
Warren Dukes's avatar
Warren Dukes committed
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
#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";
	}
143 144

	g_warning("%s\n", str);
145 146
}

147 148 149 150 151 152 153 154 155 156 157
static bool
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)
158
{
159 160 161 162 163 164 165 166 167 168 169
	return FLAC__seekable_stream_decoder_set_read_callback(dec, read_cb) &&
		FLAC__seekable_stream_decoder_set_seek_callback(dec, seek_cb) &&
		FLAC__seekable_stream_decoder_set_tell_callback(dec, tell_cb) &&
		FLAC__seekable_stream_decoder_set_length_callback(dec, length_cb) &&
		FLAC__seekable_stream_decoder_set_eof_callback(dec, eof_cb) &&
		FLAC__seekable_stream_decoder_set_write_callback(dec, write_cb) &&
		FLAC__seekable_stream_decoder_set_metadata_callback(dec, metadata_cb) &&
		FLAC__seekable_stream_decoder_set_metadata_respond(dec, FLAC__METADATA_TYPE_VORBIS_COMMENT) &&
		FLAC__seekable_stream_decoder_set_error_callback(dec, error_cb) &&
		FLAC__seekable_stream_decoder_set_client_data(dec, data) &&
		FLAC__seekable_stream_decoder_init(dec) == FLAC__SEEKABLE_STREAM_DECODER_OK;
170 171
}
#else /* FLAC_API_VERSION_CURRENT >= 7 */
172
static void flacPrintErroredState(FLAC__StreamDecoderState state)
173
{
174
	const char *str = ""; /* "" to silence compiler warning */
Avuton Olrich's avatar
Avuton Olrich committed
175
	switch (state) {
176 177 178 179 180 181 182 183
	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";
184
		break;
185 186
	case FLAC__STREAM_DECODER_SEEK_ERROR:
		str = "seek error";
Warren Dukes's avatar
Warren Dukes committed
187
		break;
188 189
	case FLAC__STREAM_DECODER_ABORTED:
		str = "decoder aborted by read";
Warren Dukes's avatar
Warren Dukes committed
190
		break;
191 192
	case FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR:
		str = "allocation error";
Warren Dukes's avatar
Warren Dukes committed
193
		break;
194 195
	case FLAC__STREAM_DECODER_UNINITIALIZED:
		str = "decoder uninitialized";
Warren Dukes's avatar
Warren Dukes committed
196
	}
197 198

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

202
static void flacMetadata(G_GNUC_UNUSED const flac_decoder * dec,
Avuton Olrich's avatar
Avuton Olrich committed
203
			 const FLAC__StreamMetadata * block, void *vdata)
204
{
Max Kellermann's avatar
Max Kellermann committed
205
	flac_metadata_common_cb(block, (struct flac_data *) vdata);
Warren Dukes's avatar
Warren Dukes committed
206 207
}

Max Kellermann's avatar
Max Kellermann committed
208 209 210
static FLAC__StreamDecoderWriteStatus
flac_write_cb(const flac_decoder *dec, const FLAC__Frame *frame,
	      const FLAC__int32 *const buf[], void *vdata)
211
{
Warren Dukes's avatar
Warren Dukes committed
212
	FLAC__uint32 samples = frame->header.blocksize;
Max Kellermann's avatar
Max Kellermann committed
213
	struct flac_data *data = (struct flac_data *) vdata;
214 215
	float timeChange;
	FLAC__uint64 newPosition = 0;
Avuton Olrich's avatar
Avuton Olrich committed
216 217 218 219

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

220
	flac_get_decode_position(dec, &newPosition);
221
	if (data->position && newPosition >= data->position) {
222 223
		assert(timeChange >= 0);

Max Kellermann's avatar
Max Kellermann committed
224
		data->bit_rate =
Avuton Olrich's avatar
Avuton Olrich committed
225 226
		    ((newPosition - data->position) * 8.0 / timeChange)
		    / 1000 + 0.5;
227 228
	}
	data->position = newPosition;
Warren Dukes's avatar
Warren Dukes committed
229

230
	return flac_common_write(data, frame, buf);
Warren Dukes's avatar
Warren Dukes committed
231 232
}

233
static struct tag *
234
flac_tag_load(const char *file, const char *char_tnum)
Avuton Olrich's avatar
Avuton Olrich committed
235
{
236
	struct tag *tag;
Avuton Olrich's avatar
Avuton Olrich committed
237 238
	FLAC__Metadata_SimpleIterator *it;
	FLAC__StreamMetadata *block = NULL;
Warren Dukes's avatar
Warren Dukes committed
239 240

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

266
	tag = tag_new();
Warren Dukes's avatar
Warren Dukes committed
267 268
	do {
		block = FLAC__metadata_simple_iterator_get_block(it);
Avuton Olrich's avatar
Avuton Olrich committed
269 270 271
		if (!block)
			break;
		if (block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
272
			flac_vorbis_comments_to_tag(tag, char_tnum, block);
Avuton Olrich's avatar
Avuton Olrich committed
273
		} else if (block->type == FLAC__METADATA_TYPE_STREAMINFO) {
274
			tag->time = ((float)block->data.stream_info.total_samples) /
Avuton Olrich's avatar
Avuton Olrich committed
275
			    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

	FLAC__metadata_simple_iterator_delete(it);
281 282 283 284 285 286 287

	if (!tag_is_defined(tag)) {
		tag_free(tag);
		tag = NULL;
	}

	return tag;
Warren Dukes's avatar
Warren Dukes committed
288 289
}

290 291 292 293 294 295 296
#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7

static struct tag *
flac_cue_tag_load(const char *file)
{
	struct tag* tag = NULL;
	char* char_tnum = NULL;
297
	char* ptr = NULL;
298 299 300
	unsigned int tnum = 0;
	unsigned int sample_rate = 0;
	FLAC__uint64 track_time = 0;
301
#ifdef HAVE_CUE /* libcue */
302
	FLAC__StreamMetadata* vc;
303 304
	char* cs_filename;
	FILE* cs_file;
305
#endif /* libcue */
306
	FLAC__StreamMetadata* si = FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO);
307
	FLAC__StreamMetadata* cs;
308 309

	tnum = flac_vtrack_tnum(file);
310
	char_tnum = g_strdup_printf("%u", tnum);
311

312 313 314 315 316 317
	ptr = strrchr(file, '/');
	*ptr = '\0';

#ifdef HAVE_CUE /* libcue */
	if (FLAC__metadata_get_tags(file, &vc))
	{
318 319
		for (unsigned i = 0; i < vc->data.vorbis_comment.num_comments;
		     i++)
320 321 322 323 324 325 326 327 328 329 330
		{
			if ((ptr = (char*)vc->data.vorbis_comment.comments[i].entry) != NULL)
			{
				if (g_ascii_strncasecmp(ptr, "cuesheet", 8) == 0)
				{
					while (*(++ptr) != '=');
					tag = cue_tag_string(   ++ptr,
								tnum);
				}
			}
		}
331

332 333
		FLAC__metadata_object_delete(vc);
	}
334 335 336 337 338 339 340 341 342 343 344 345

	if (tag == NULL) {
		cs_filename = g_strconcat(file, ".cue", NULL);

		cs_file = fopen(cs_filename, "rt");
		g_free(cs_filename);

		if (cs_file != NULL) {
			tag = cue_tag_file(cs_file, tnum);
			fclose(cs_file);
		}
	}
346
#endif /* libcue */
347

348 349
	if (tag == NULL)
		tag = flac_tag_load(file, char_tnum);
350

351 352
	if (char_tnum != NULL) {
		tag_add_item(tag, TAG_TRACK, char_tnum);
353 354 355 356 357 358
		g_free(char_tnum);
	}

	if (FLAC__metadata_get_streaminfo(file, si))
	{
		sample_rate = si->data.stream_info.sample_rate;
359
		FLAC__metadata_object_delete(si);
360 361 362 363 364 365 366
	}

	if (FLAC__metadata_get_cuesheet(file, &cs))
	{
		if (cs->data.cue_sheet.tracks != NULL
				&& (tnum <= cs->data.cue_sheet.num_tracks - 1))
		{
367
			track_time = cs->data.cue_sheet.tracks[tnum].offset
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
				- cs->data.cue_sheet.tracks[tnum - 1].offset;
		}
		FLAC__metadata_object_delete(cs);
	}

	if (sample_rate != 0)
	{
		tag->time = (unsigned int)(track_time/sample_rate);
	}

	return tag;
}

#endif /* FLAC_API_VERSION_CURRENT >= 7 */

Max Kellermann's avatar
Max Kellermann committed
383 384
static struct tag *
flac_tag_dup(const char *file)
Avuton Olrich's avatar
Avuton Olrich committed
385
{
386 387 388 389 390 391 392
#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7
	struct stat st;

	if (stat(file, &st) < 0)
		return flac_cue_tag_load(file);
	else
#endif /* FLAC_API_VERSION_CURRENT >= 7 */
393
		return flac_tag_load(file, NULL);
Warren Dukes's avatar
Warren Dukes committed
394 395
}

396
static void
Max Kellermann's avatar
Max Kellermann committed
397 398
flac_decode_internal(struct decoder * decoder,
		     struct input_stream *input_stream,
399
		     bool is_ogg)
400
{
Max Kellermann's avatar
Max Kellermann committed
401 402
	flac_decoder *flac_dec;
	struct flac_data data;
Max Kellermann's avatar
Max Kellermann committed
403
	enum decoder_command cmd;
404
	const char *err = NULL;
405

Max Kellermann's avatar
Max Kellermann committed
406
	if (!(flac_dec = flac_new()))
407
		return;
Max Kellermann's avatar
Max Kellermann committed
408
	flac_data_init(&data, decoder, input_stream);
409
	data.tag = tag_new();
410

411
#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7
Max Kellermann's avatar
Max Kellermann committed
412
        if(!FLAC__stream_decoder_set_metadata_respond(flac_dec, FLAC__METADATA_TYPE_VORBIS_COMMENT))
413
        {
414
                g_debug("Failed to set metadata respond\n");
415 416 417
        }
#endif

418
	if (is_ogg) {
Max Kellermann's avatar
Max Kellermann committed
419 420 421 422 423
		if (!flac_ogg_init(flac_dec, flac_read_cb,
				   flac_seek_cb, flac_tell_cb,
				   flac_length_cb, flac_eof_cb,
				   flac_write_cb, flacMetadata,
				   flac_error_cb, (void *)&data)) {
424 425 426 427
			err = "doing Ogg init()";
			goto fail;
		}
	} else {
Max Kellermann's avatar
Max Kellermann committed
428 429 430 431 432
		if (!flac_init(flac_dec, flac_read_cb,
			       flac_seek_cb, flac_tell_cb,
			       flac_length_cb, flac_eof_cb,
			       flac_write_cb, flacMetadata,
			       flac_error_cb, (void *)&data)) {
433 434 435
			err = "doing init()";
			goto fail;
		}
436 437
	}

Max Kellermann's avatar
Max Kellermann committed
438
	if (!flac_process_metadata(flac_dec)) {
439 440
		err = "problem reading metadata";
		goto fail;
441 442
	}

443 444 445 446 447 448 449 450
	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;
	}

451
	decoder_initialized(decoder, &data.audio_format,
Max Kellermann's avatar
Max Kellermann committed
452
			    input_stream->seekable, data.total_time);
453

454
	while (true) {
Max Kellermann's avatar
Max Kellermann committed
455 456 457 458 459 460 461 462
		if (!tag_is_empty(data.tag)) {
			cmd = decoder_tag(decoder, input_stream, data.tag);
			tag_free(data.tag);
			data.tag = tag_new();
		} else
			cmd = decoder_get_command(decoder);

		if (cmd == DECODE_COMMAND_SEEK) {
Max Kellermann's avatar
Max Kellermann committed
463
			FLAC__uint64 seek_sample = decoder_seek_where(decoder) *
464
			    data.audio_format.sample_rate + 0.5;
Max Kellermann's avatar
Max Kellermann committed
465 466
			if (flac_seek_absolute(flac_dec, seek_sample)) {
				data.time = ((float)seek_sample) /
467
				    data.audio_format.sample_rate;
468
				data.position = 0;
469
				decoder_command_finished(decoder);
470
			} else
471
				decoder_seek_error(decoder);
472 473
		} else if (cmd == DECODE_COMMAND_STOP ||
			   flac_get_state(flac_dec) == flac_decoder_eof)
474
			break;
475 476 477 478 479 480

		if (!flac_process_single(flac_dec)) {
			cmd = decoder_get_command(decoder);
			if (cmd != DECODE_COMMAND_SEEK)
				break;
		}
481
	}
Max Kellermann's avatar
Max Kellermann committed
482
	if (cmd != DECODE_COMMAND_STOP) {
Max Kellermann's avatar
Max Kellermann committed
483 484
		flacPrintErroredState(flac_get_state(flac_dec));
		flac_finish(flac_dec);
485 486 487
	}

fail:
Max Kellermann's avatar
Max Kellermann committed
488 489
	if (data.replay_gain_info)
		replay_gain_info_free(data.replay_gain_info);
490

Max Kellermann's avatar
Max Kellermann committed
491 492
	tag_free(data.tag);

Max Kellermann's avatar
Max Kellermann committed
493 494
	if (flac_dec)
		flac_delete(flac_dec);
495

496 497
	if (err)
		g_warning("%s\n", err);
498 499
}

500
static void
Max Kellermann's avatar
Max Kellermann committed
501
flac_decode(struct decoder * decoder, struct input_stream *input_stream)
502
{
Max Kellermann's avatar
Max Kellermann committed
503
	flac_decode_internal(decoder, input_stream, false);
504 505
}

506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542
#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7

/**
 * @brief Decode a flac file with embedded cue sheets
 * @param const char* fname filename on fs
 */
static void
flac_container_decode(struct decoder* decoder,
		     const char* fname,
		     bool is_ogg)
{
	unsigned int tnum = 0;
	FLAC__uint64 t_start = 0;
	FLAC__uint64 t_end = 0;
	FLAC__uint64 track_time = 0;
	FLAC__StreamMetadata* cs = NULL;

	flac_decoder *flac_dec;
	struct flac_data data;
	const char *err = NULL;

	char* pathname = g_strdup(fname);
	char* slash = strrchr(pathname, '/');
	*slash = '\0';

	tnum = flac_vtrack_tnum(fname);

	cs = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET);

	FLAC__metadata_get_cuesheet(pathname, &cs);

	if (cs != NULL)
	{
		if (cs->data.cue_sheet.tracks != NULL
				&& (tnum <= cs->data.cue_sheet.num_tracks - 1))
		{
			t_start = cs->data.cue_sheet.tracks[tnum - 1].offset;
543 544
			t_end = cs->data.cue_sheet.tracks[tnum].offset;
			track_time = cs->data.cue_sheet.tracks[tnum].offset
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616
				- cs->data.cue_sheet.tracks[tnum - 1].offset;
		}

		FLAC__metadata_object_delete(cs);
	}
	else
	{
		g_free(pathname);
		return;
	}

	if (!(flac_dec = flac_new()))
	{
		g_free(pathname);
		return;
	}

	flac_data_init(&data, decoder, NULL);

#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7
        if(!FLAC__stream_decoder_set_metadata_respond(flac_dec, FLAC__METADATA_TYPE_VORBIS_COMMENT))
        {
                g_debug("Failed to set metadata respond\n");
        }
#endif


	if (is_ogg)
	{
		if (FLAC__stream_decoder_init_ogg_file(	flac_dec,
							pathname,
							flac_write_cb,
							flacMetadata,
							flac_error_cb,
							(void*) &data	)
			!= FLAC__STREAM_DECODER_INIT_STATUS_OK		)
		{
			err = "doing Ogg init()";
			goto fail;
		}
	}
	else
	{
		if (FLAC__stream_decoder_init_file(	flac_dec,
							pathname,
							flac_write_cb,
							flacMetadata,
							flac_error_cb,
							(void*) &data	)
			!= FLAC__STREAM_DECODER_INIT_STATUS_OK		)
		{
			err = "doing init()";
			goto fail;
		}
	}

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

	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;
	}

	// set track time (order is important: after stream init)
617
	data.total_time = ((float)track_time / (float)data.audio_format.sample_rate);
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823
	data.position = 0;

	decoder_initialized(decoder, &data.audio_format,
			    true, data.total_time);

	// seek to song start (order is important: after decoder init)
	flac_seek_absolute(flac_dec, (FLAC__uint64)t_start);

	while (true)
	{
		if (!flac_process_single(flac_dec))
			break;

		// we only need to break at the end of track if we are in "cue mode"
		if (data.time >= data.total_time)
		{
			flacPrintErroredState(flac_get_state(flac_dec));
			flac_finish(flac_dec);
		}

		if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK)
		{
			FLAC__uint64 seek_sample = t_start +
				(decoder_seek_where(decoder) * data.audio_format.sample_rate);

			//if (seek_sample >= t_start && seek_sample <= t_end && data.total_time > 30)
			if (seek_sample >= t_start && seek_sample <= t_end)
			{
				if (flac_seek_absolute(flac_dec, (FLAC__uint64)seek_sample))
				{
					data.time = (float)(seek_sample - t_start) /
					    data.audio_format.sample_rate;
					data.position = 0;

					decoder_command_finished(decoder);
				}
				else
					decoder_seek_error(decoder);
					//decoder_command_finished(decoder);
			}
		}
		else if (flac_get_state(flac_dec) == flac_decoder_eof)
			break;
	}

	if (decoder_get_command(decoder) != DECODE_COMMAND_STOP)
	{
		flacPrintErroredState(flac_get_state(flac_dec));
		flac_finish(flac_dec);
	}

fail:
	if (pathname)
		g_free(pathname);

	if (data.replay_gain_info)
		replay_gain_info_free(data.replay_gain_info);

	if (flac_dec)
		flac_delete(flac_dec);

	if (err)
		g_warning("%s\n", err);
}

/**
 * @brief Open a flac file for decoding
 * @param const char* fname filename on fs
 */
static void
flac_filedecode_internal(struct decoder* decoder,
		     const char* fname,
		     bool is_ogg)
{
	flac_decoder *flac_dec;
	struct flac_data data;
	const char *err = NULL;
	unsigned int flac_err_state = 0;

	if (!(flac_dec = flac_new()))
		return;

	flac_data_init(&data, decoder, NULL);

#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7
        if(!FLAC__stream_decoder_set_metadata_respond(flac_dec, FLAC__METADATA_TYPE_VORBIS_COMMENT))
        {
                g_debug("Failed to set metadata respond\n");
        }
#endif


	if (is_ogg)
	{
		if (	(flac_err_state = FLAC__stream_decoder_init_ogg_file(	flac_dec,
										fname,
										flac_write_cb,
										flacMetadata,
										flac_error_cb,
										(void*) &data	))
			== FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE)
		{
			flac_container_decode(decoder, fname, is_ogg);
		}
		else if (flac_err_state != FLAC__STREAM_DECODER_INIT_STATUS_OK)
		{
			err = "doing Ogg init()";
			goto fail;
		}
	}
	else
	{
		if (	(flac_err_state = FLAC__stream_decoder_init_file(	flac_dec,
										fname,
										flac_write_cb,
										flacMetadata,
										flac_error_cb,
										(void*) &data	))
			== FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE)
		{
			flac_container_decode(decoder, fname, is_ogg);
		}
		else if (flac_err_state != FLAC__STREAM_DECODER_INIT_STATUS_OK)
		{
			err = "doing init()";
			goto fail;
		}
	}

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

	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;
	}

	decoder_initialized(decoder, &data.audio_format,
			    true, data.total_time);

	while (true)
	{
		if (!flac_process_single(flac_dec))
			break;

		if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK)
		{
			FLAC__uint64 seek_sample = decoder_seek_where(decoder) *
			    data.audio_format.sample_rate + 0.5;
			if (flac_seek_absolute(flac_dec, seek_sample))
			{
				data.time = ((float)seek_sample) /
				    data.audio_format.sample_rate;
				data.position = 0;
				decoder_command_finished(decoder);
			}
			else
				decoder_seek_error(decoder);

		}
		else if (flac_get_state(flac_dec) == flac_decoder_eof)
			break;
	}

	if (decoder_get_command(decoder) != DECODE_COMMAND_STOP)
	{
		flacPrintErroredState(flac_get_state(flac_dec));
		flac_finish(flac_dec);
	}

fail:
	if (data.replay_gain_info)
		replay_gain_info_free(data.replay_gain_info);

	if (flac_dec)
		flac_delete(flac_dec);

	if (err)
		g_warning("%s\n", err);
}

/**
 * @brief	wrapper function for
 * 		flac_filedecode_internal method
 * 		for decoding without ogg
 */
static void
flac_filedecode(struct decoder *decoder, const char *fname)
{
	struct stat st;

	if (stat(fname, &st) < 0) {
		flac_container_decode(decoder, fname, false);
	} else 
		flac_filedecode_internal(decoder, fname, false);
}

#endif /* FLAC_API_VERSION_CURRENT >= 7 */

824 825
#ifndef HAVE_OGGFLAC

826
static bool
827
oggflac_init(G_GNUC_UNUSED const struct config_param *param)
828
{
829
#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7
830
	return !!FLAC_API_SUPPORTS_OGG_FLAC;
831 832 833 834
#else
	/* disable oggflac when libflac is too old */
	return false;
#endif
835 836
}

837 838
#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7

Max Kellermann's avatar
Max Kellermann committed
839 840
static struct tag *
oggflac_tag_dup(const char *file)
841
{
842
	struct tag *ret = NULL;
843 844 845 846 847 848 849 850
	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);
851 852

	ret = tag_new();
853 854 855 856
	do {
		if (!(block = FLAC__metadata_iterator_get_block(it)))
			break;
		if (block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
857
			flac_vorbis_comments_to_tag(ret, NULL, block);
858 859 860 861 862 863 864
		} else if (block->type == FLAC__METADATA_TYPE_STREAMINFO) {
			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);
865 866 867 868 869 870

	if (!tag_is_defined(ret)) {
		tag_free(ret);
		ret = NULL;
	}

871 872
out:
	FLAC__metadata_chain_delete(chain);
873 874 875
	return ret;
}

876
static void
Max Kellermann's avatar
Max Kellermann committed
877
oggflac_decode(struct decoder *decoder, struct input_stream *input_stream)
878
{
Max Kellermann's avatar
Max Kellermann committed
879
	if (ogg_stream_type_detect(input_stream) != FLAC)
880
		return;
881

882 883
	/* rewind the stream, because ogg_stream_type_detect() has
	   moved it */
Max Kellermann's avatar
Max Kellermann committed
884
	input_stream_seek(input_stream, 0, SEEK_SET);
885

Max Kellermann's avatar
Max Kellermann committed
886
	flac_decode_internal(decoder, input_stream, true);
887 888
}

889 890 891 892 893 894 895
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
};
896

897 898
#endif /* FLAC_API_VERSION_CURRENT >= 7 */

Max Kellermann's avatar
Max Kellermann committed
899
const struct decoder_plugin oggflac_decoder_plugin = {
900
	.name = "oggflac",
901
	.init = oggflac_init,
902
#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7
903 904 905 906
	.stream_decode = oggflac_decode,
	.tag_dup = oggflac_tag_dup,
	.suffixes = oggflac_suffixes,
	.mime_types = oggflac_mime_types
907
#endif
908
};
909

910
#endif /* HAVE_OGGFLAC */
911

Max Kellermann's avatar
Max Kellermann committed
912
static const char *const flac_suffixes[] = { "flac", NULL };
913 914 915
static const char *const flac_mime_types[] = {
	"audio/x-flac", "application/x-flac", NULL
};
Warren Dukes's avatar
Warren Dukes committed
916

Max Kellermann's avatar
Max Kellermann committed
917
const struct decoder_plugin flac_decoder_plugin = {
918 919
	.name = "flac",
	.stream_decode = flac_decode,
920 921 922
#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7
	.file_decode = flac_filedecode,
#endif /* FLAC_API_VERSION_CURRENT >= 7 */
Max Kellermann's avatar
Max Kellermann committed
923 924
	.tag_dup = flac_tag_dup,
	.suffixes = flac_suffixes,
925 926 927 928
	.mime_types = flac_mime_types,
#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7
	.container_scan = flac_cue_track,
#endif /* FLAC_API_VERSION_CURRENT >= 7 */
Warren Dukes's avatar
Warren Dukes committed
929
};