2 * Copyright (C) 2011-2014 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file flac_afh.c Audio format handler for flac files. */
10 #include <FLAC/stream_decoder.h>
11 #include <FLAC/metadata.h>
18 struct private_flac_afh_data {
22 struct afh_info *afhi;
26 static size_t copy_data(struct private_flac_afh_data *pfad, void *buf,
29 size_t copy, have = pfad->map_bytes - pfad->fpos;
33 copy = have < want? have : want;
34 memcpy(buf, pfad->map + pfad->fpos, copy);
39 static size_t meta_read_cb(void *ptr, size_t size, size_t nmemb,
40 FLAC__IOHandle handle)
42 struct private_flac_afh_data *pfad = handle;
43 return copy_data(pfad, ptr, nmemb * size);
46 static int meta_seek_cb(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
48 struct private_flac_afh_data *pfad = handle;
55 if (offset >= pfad->map_bytes)
60 if (pfad->fpos + offset >= pfad->map_bytes)
65 if (offset >= pfad->map_bytes)
74 static FLAC__int64 meta_tell_cb(FLAC__IOHandle handle)
76 struct private_flac_afh_data *pfad = handle;
80 static int meta_eof_cb(FLAC__IOHandle handle)
82 struct private_flac_afh_data *pfad = handle;
83 return pfad->fpos == pfad->map_bytes;
86 static int meta_close_cb(FLAC__IOHandle __a_unused handle)
91 static void free_tags(struct taginfo *tags)
97 freep(&tags->comment);
100 static bool copy_if_tag_type(const char *tag, int taglen, const char *type,
103 char *q = key_value_copy(tag, taglen, type);
111 static void flac_read_vorbis_comments(FLAC__StreamMetadata_VorbisComment *vc,
112 struct taginfo *tags)
115 FLAC__StreamMetadata_VorbisComment_Entry *comment = vc->comments;
117 PARA_INFO_LOG("found %u vorbis comments\n", vc->num_comments);
118 for (i = 0; i < vc->num_comments; i++) {
119 char *e = (char *)comment[i].entry;
120 int len = comment[i].length;
121 if (copy_if_tag_type(e, len, "artist", &tags->artist))
123 if (copy_if_tag_type(e, len, "title", &tags->title))
125 if (copy_if_tag_type(e, len, "album", &tags->album))
127 if (copy_if_tag_type(e, len, "year", &tags->year))
129 if (copy_if_tag_type(e, len, "comment", &tags->comment))
134 static int flac_read_meta(struct private_flac_afh_data *pfad)
137 FLAC__IOCallbacks meta_callbacks = {
138 .read = meta_read_cb,
140 .seek = meta_seek_cb,
141 .tell = meta_tell_cb,
143 .close = meta_close_cb
145 FLAC__Metadata_Chain *chain;
146 FLAC__Metadata_Iterator *iter;
147 FLAC__StreamMetadata_StreamInfo *info = NULL;
150 chain = FLAC__metadata_chain_new();
152 return -E_FLAC_CHAIN_ALLOC;
153 ret = -E_FLAC_CHAIN_READ;
154 ok = FLAC__metadata_chain_read_with_callbacks(chain, pfad,
158 ret = -E_FLAC_ITER_ALLOC;
159 iter = FLAC__metadata_iterator_new();
162 FLAC__metadata_iterator_init(iter, chain);
164 FLAC__StreamMetadata *b;
165 b = FLAC__metadata_iterator_get_block(iter);
168 if (b->type == FLAC__METADATA_TYPE_STREAMINFO) {
169 info = &b->data.stream_info;
170 ret = -E_FLAC_VARBLOCK;
171 if (info->min_blocksize != info->max_blocksize)
173 pfad->afhi->frequency = info->sample_rate;
174 pfad->afhi->channels = info->channels;
175 pfad->blocksize = info->min_blocksize;
177 if (b->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
178 flac_read_vorbis_comments(&b->data.vorbis_comment,
180 ok = FLAC__metadata_iterator_next(iter);
184 ret = info? 0: -E_FLAC_STREAMINFO;
186 FLAC__metadata_iterator_delete(iter);
188 FLAC__metadata_chain_delete(chain);
190 free_tags(&pfad->afhi->tags);
194 static FLAC__StreamDecoderReadStatus read_cb(
195 __a_unused const FLAC__StreamDecoder *decoder,
196 FLAC__byte buffer[], size_t *bytes, void *client_data)
198 struct private_flac_afh_data *pfad = client_data;
201 *bytes = copy_data(pfad, buffer, *bytes);
203 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
205 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
208 static FLAC__StreamDecoderTellStatus tell_cb(
209 __a_unused const FLAC__StreamDecoder *decoder,
210 FLAC__uint64 *absolute_byte_offset, void *client_data)
212 struct private_flac_afh_data *pfad = client_data;
214 *absolute_byte_offset = pfad->fpos;
215 return FLAC__STREAM_DECODER_TELL_STATUS_OK;
218 /* libflac insits on this callback being present. */
219 static FLAC__StreamDecoderWriteStatus write_cb(
220 __a_unused const FLAC__StreamDecoder *decoder,
221 __a_unused const FLAC__Frame *frame,
222 __a_unused const FLAC__int32 *const buffer[],
223 __a_unused void *client_data)
225 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
228 static void error_cb(
229 __a_unused const FLAC__StreamDecoder *decoder,
230 FLAC__StreamDecoderErrorStatus status,
231 __a_unused void *client_data)
233 PARA_ERROR_LOG("%s\n", FLAC__StreamDecoderErrorStatusString[status]);
236 static int flac_afh_read_chunks(struct private_flac_afh_data *pfad)
238 FLAC__StreamDecoder *decoder;
239 FLAC__StreamDecoderInitStatus init_status;
242 unsigned chunk_table_size = 0;
244 struct afh_info *afhi = pfad->afhi;
246 PARA_INFO_LOG("reading chunk table\n");
247 afhi->chunk_table = NULL;
248 decoder = FLAC__stream_decoder_new();
250 return -E_FLAC_AFH_DECODER_ALLOC;
251 ret = -E_FLAC_AFH_DECODER_INIT;
252 init_status = FLAC__stream_decoder_init_stream(
264 if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK)
266 ret = -E_FLAC_SKIP_META;
267 ok = FLAC__stream_decoder_process_until_end_of_metadata(decoder);
272 FLAC__StreamDecoderState state;
274 ret = -E_FLAC_DECODE_POS;
275 ok = FLAC__stream_decoder_get_decode_position(decoder, &pos);
278 if (c >= chunk_table_size) {
279 chunk_table_size = 2 * chunk_table_size + 100;
280 afhi->chunk_table = para_realloc(afhi->chunk_table,
281 chunk_table_size * sizeof(uint32_t));
283 afhi->chunk_table[c] = pos;
285 ok = FLAC__stream_decoder_skip_single_frame(decoder);
288 state = FLAC__stream_decoder_get_state(decoder);
289 if (state == FLAC__STREAM_DECODER_END_OF_STREAM)
292 afhi->chunks_total = c;
295 FLAC__stream_decoder_finish(decoder);
296 FLAC__stream_decoder_delete(decoder);
298 freep(&afhi->chunk_table);
302 static int flac_get_file_info(char *map, size_t map_bytes, __a_unused int fd,
303 struct afh_info *afhi)
305 struct private_flac_afh_data pfad_struct = {
307 .map_bytes = map_bytes,
309 }, *pfad = &pfad_struct;
313 afhi->header_len = 0;
314 ret = flac_read_meta(pfad);
318 ret = flac_afh_read_chunks(pfad);
320 free_tags(&afhi->tags);
323 afhi->techinfo = make_message("blocksize: %u", pfad->blocksize);
324 afhi->seconds_total = DIV_ROUND_UP(afhi->chunks_total * pfad->blocksize,
326 afhi->bitrate = pfad->map_bytes * 8 / afhi->seconds_total / 1024;
327 chunk_time = (double)pfad->blocksize / afhi->frequency;
328 afhi->chunk_tv.tv_sec = chunk_time;
329 chunk_time *= 1000 * 1000;
330 chunk_time -= afhi->chunk_tv.tv_sec * 1000 * 1000;
331 afhi->chunk_tv.tv_usec = chunk_time;
335 static const char* flac_suffixes[] = {"flac", NULL};
338 * The init function of the flac audio format handler.
340 * \param afh pointer to the struct to initialize
342 void flac_afh_init(struct audio_format_handler *afh)
344 afh->get_file_info = flac_get_file_info,
345 afh->suffixes = flac_suffixes;