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