flac_plugin.c 23.1 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 302 303
#ifdef HAVE_CUE /* libcue */
	FLAC__StreamMetadata* vc = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
#endif /* libcue */
304 305 306 307
	FLAC__StreamMetadata* si = FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO);
	FLAC__StreamMetadata* cs = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET);

	tnum = flac_vtrack_tnum(file);
308
	char_tnum = g_strdup_printf("%u", tnum);
309

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

#ifdef HAVE_CUE /* libcue */
	if (FLAC__metadata_get_tags(file, &vc))
	{
316 317
		for (unsigned i = 0; i < vc->data.vorbis_comment.num_comments;
		     i++)
318 319 320 321 322 323 324 325 326 327 328 329 330 331
		{
			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);
				}
			}
		}
		FLAC__metadata_object_delete(vc);
	}
#endif /* libcue */
332

333 334
	if (tag == NULL)
		tag = flac_tag_load(file, char_tnum);
335 336 337 338 339 340 341 342 343 344 345 346

	if (char_tnum != NULL)
	{
		tag_add_item(	tag,
				TAG_ITEM_TRACK,
				char_tnum);
		g_free(char_tnum);
	}

	if (FLAC__metadata_get_streaminfo(file, si))
	{
		sample_rate = si->data.stream_info.sample_rate;
347
		FLAC__metadata_object_delete(si);
348 349 350 351 352 353 354
	}

	if (FLAC__metadata_get_cuesheet(file, &cs))
	{
		if (cs->data.cue_sheet.tracks != NULL
				&& (tnum <= cs->data.cue_sheet.num_tracks - 1))
		{
355
			track_time = cs->data.cue_sheet.tracks[tnum].offset
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
				- 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
371 372
static struct tag *
flac_tag_dup(const char *file)
Avuton Olrich's avatar
Avuton Olrich committed
373
{
374 375 376 377 378 379 380
#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 */
381
		return flac_tag_load(file, NULL);
Warren Dukes's avatar
Warren Dukes committed
382 383
}

384
static void
Max Kellermann's avatar
Max Kellermann committed
385 386
flac_decode_internal(struct decoder * decoder,
		     struct input_stream *input_stream,
387
		     bool is_ogg)
388
{
Max Kellermann's avatar
Max Kellermann committed
389 390
	flac_decoder *flac_dec;
	struct flac_data data;
Max Kellermann's avatar
Max Kellermann committed
391
	enum decoder_command cmd;
392
	const char *err = NULL;
393

Max Kellermann's avatar
Max Kellermann committed
394
	if (!(flac_dec = flac_new()))
395
		return;
Max Kellermann's avatar
Max Kellermann committed
396
	flac_data_init(&data, decoder, input_stream);
397

398
#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7
Max Kellermann's avatar
Max Kellermann committed
399
        if(!FLAC__stream_decoder_set_metadata_respond(flac_dec, FLAC__METADATA_TYPE_VORBIS_COMMENT))
400
        {
401
                g_debug("Failed to set metadata respond\n");
402 403 404
        }
#endif

405
	if (is_ogg) {
Max Kellermann's avatar
Max Kellermann committed
406 407 408 409 410
		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)) {
411 412 413 414
			err = "doing Ogg init()";
			goto fail;
		}
	} else {
Max Kellermann's avatar
Max Kellermann committed
415 416 417 418 419
		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)) {
420 421 422
			err = "doing init()";
			goto fail;
		}
423 424
	}

Max Kellermann's avatar
Max Kellermann committed
425 426
	data.tag = tag_new();

Max Kellermann's avatar
Max Kellermann committed
427
	if (!flac_process_metadata(flac_dec)) {
428 429
		err = "problem reading metadata";
		goto fail;
430 431
	}

432 433 434 435 436 437 438 439
	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;
	}

440
	decoder_initialized(decoder, &data.audio_format,
Max Kellermann's avatar
Max Kellermann committed
441
			    input_stream->seekable, data.total_time);
442

443
	while (true) {
Max Kellermann's avatar
Max Kellermann committed
444 445 446 447 448 449 450 451
		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
452
			FLAC__uint64 seek_sample = decoder_seek_where(decoder) *
453
			    data.audio_format.sample_rate + 0.5;
Max Kellermann's avatar
Max Kellermann committed
454 455
			if (flac_seek_absolute(flac_dec, seek_sample)) {
				data.time = ((float)seek_sample) /
456
				    data.audio_format.sample_rate;
457
				data.position = 0;
458
				decoder_command_finished(decoder);
459
			} else
460
				decoder_seek_error(decoder);
461 462
		} else if (cmd == DECODE_COMMAND_STOP ||
			   flac_get_state(flac_dec) == flac_decoder_eof)
463
			break;
464 465 466 467 468 469

		if (!flac_process_single(flac_dec)) {
			cmd = decoder_get_command(decoder);
			if (cmd != DECODE_COMMAND_SEEK)
				break;
		}
470
	}
Max Kellermann's avatar
Max Kellermann committed
471
	if (cmd != DECODE_COMMAND_STOP) {
Max Kellermann's avatar
Max Kellermann committed
472 473
		flacPrintErroredState(flac_get_state(flac_dec));
		flac_finish(flac_dec);
474 475 476
	}

fail:
Max Kellermann's avatar
Max Kellermann committed
477 478
	if (data.replay_gain_info)
		replay_gain_info_free(data.replay_gain_info);
479

Max Kellermann's avatar
Max Kellermann committed
480 481
	tag_free(data.tag);

Max Kellermann's avatar
Max Kellermann committed
482 483
	if (flac_dec)
		flac_delete(flac_dec);
484

485 486
	if (err)
		g_warning("%s\n", err);
487 488
}

489
static void
Max Kellermann's avatar
Max Kellermann committed
490
flac_decode(struct decoder * decoder, struct input_stream *input_stream)
491
{
Max Kellermann's avatar
Max Kellermann committed
492
	flac_decode_internal(decoder, input_stream, false);
493 494
}

495 496 497 498 499 500 501 502 503 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
#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;
532 533
			t_end = cs->data.cue_sheet.tracks[tnum].offset;
			track_time = cs->data.cue_sheet.tracks[tnum].offset
534 535 536 537 538 539 540 541 542 543 544 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
				- 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)
606
	data.total_time = ((float)track_time / (float)data.audio_format.sample_rate);
607 608 609 610 611 612 613 614 615 616 617 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
	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 */

813 814
#ifndef HAVE_OGGFLAC

815
static bool
816
oggflac_init(G_GNUC_UNUSED const struct config_param *param)
817
{
818
#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7
819
	return !!FLAC_API_SUPPORTS_OGG_FLAC;
820 821 822 823
#else
	/* disable oggflac when libflac is too old */
	return false;
#endif
824 825
}

826 827
#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7

Max Kellermann's avatar
Max Kellermann committed
828 829
static struct tag *
oggflac_tag_dup(const char *file)
830
{
831
	struct tag *ret = NULL;
832 833 834 835 836 837 838 839
	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);
840 841

	ret = tag_new();
842 843 844 845
	do {
		if (!(block = FLAC__metadata_iterator_get_block(it)))
			break;
		if (block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
846
			flac_vorbis_comments_to_tag(ret, NULL, block);
847 848 849 850 851 852 853
		} 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);
854 855 856 857 858 859

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

860 861
out:
	FLAC__metadata_chain_delete(chain);
862 863 864
	return ret;
}

865
static void
Max Kellermann's avatar
Max Kellermann committed
866
oggflac_decode(struct decoder *decoder, struct input_stream *input_stream)
867
{
Max Kellermann's avatar
Max Kellermann committed
868
	if (ogg_stream_type_detect(input_stream) != FLAC)
869
		return;
870

871 872
	/* rewind the stream, because ogg_stream_type_detect() has
	   moved it */
Max Kellermann's avatar
Max Kellermann committed
873
	input_stream_seek(input_stream, 0, SEEK_SET);
874

Max Kellermann's avatar
Max Kellermann committed
875
	flac_decode_internal(decoder, input_stream, true);
876 877
}

878 879 880 881 882 883 884
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
};
885

886 887
#endif /* FLAC_API_VERSION_CURRENT >= 7 */

Max Kellermann's avatar
Max Kellermann committed
888
const struct decoder_plugin oggflac_decoder_plugin = {
889
	.name = "oggflac",
890
	.init = oggflac_init,
891
#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT > 7
892 893 894 895
	.stream_decode = oggflac_decode,
	.tag_dup = oggflac_tag_dup,
	.suffixes = oggflac_suffixes,
	.mime_types = oggflac_mime_types
896
#endif
897
};
898

899
#endif /* HAVE_OGGFLAC */
900

Max Kellermann's avatar
Max Kellermann committed
901
static const char *const flac_suffixes[] = { "flac", NULL };
902 903 904
static const char *const flac_mime_types[] = {
	"audio/x-flac", "application/x-flac", NULL
};
Warren Dukes's avatar
Warren Dukes committed
905

Max Kellermann's avatar
Max Kellermann committed
906
const struct decoder_plugin flac_decoder_plugin = {
907 908
	.name = "flac",
	.stream_decode = flac_decode,
909 910 911
#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
912 913
	.tag_dup = flac_tag_dup,
	.suffixes = flac_suffixes,
914 915 916 917
	.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
918
};