2 * Copyright (C) 2011 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. */
11 #include <FLAC/stream_decoder.h>
12 #include <FLAC/metadata.h>
19 struct private_flac_afh_data
{
23 struct afh_info
*afhi
;
27 static size_t copy_data(struct private_flac_afh_data
*pfad
, void *buf
,
30 size_t copy
, have
= pfad
->map_bytes
- pfad
->fpos
;
34 copy
= have
< want
? have
: want
;
35 memcpy(buf
, pfad
->map
+ pfad
->fpos
, copy
);
40 static size_t meta_read_cb(void *ptr
, size_t size
, size_t nmemb
,
41 FLAC__IOHandle handle
)
43 struct private_flac_afh_data
*pfad
= handle
;
44 return copy_data(pfad
, ptr
, nmemb
* size
);
47 static int meta_seek_cb(FLAC__IOHandle handle
, FLAC__int64 offset
, int whence
)
49 struct private_flac_afh_data
*pfad
= handle
;
56 if (offset
>= pfad
->map_bytes
)
61 if (pfad
->fpos
+ offset
>= pfad
->map_bytes
)
66 if (offset
>= pfad
->map_bytes
)
75 static FLAC__int64
meta_tell_cb(FLAC__IOHandle handle
)
77 struct private_flac_afh_data
*pfad
= handle
;
81 static int meta_eof_cb(FLAC__IOHandle handle
)
83 struct private_flac_afh_data
*pfad
= handle
;
84 return pfad
->fpos
== pfad
->map_bytes
- 1;
87 static int meta_close_cb(FLAC__IOHandle __a_unused handle
)
92 static void free_tags(struct taginfo
*tags
)
98 freep(&tags
->comment
);
101 static bool copy_if_tag_type(const char *tag
, int taglen
, const char *type
,
104 char *q
= key_value_copy(tag
, taglen
, type
);
112 static void flac_read_vorbis_comments(FLAC__StreamMetadata_VorbisComment
*vc
,
113 struct taginfo
*tags
)
116 FLAC__StreamMetadata_VorbisComment_Entry
*comment
= vc
->comments
;
118 PARA_INFO_LOG("found %u vorbis comments\n", vc
->num_comments
);
119 for (i
= 0; i
< vc
->num_comments
; i
++) {
120 char *e
= (char *)comment
[i
].entry
;
121 int len
= comment
[i
].length
;
122 if (copy_if_tag_type(e
, len
, "artist", &tags
->artist
))
124 if (copy_if_tag_type(e
, len
, "title", &tags
->title
))
126 if (copy_if_tag_type(e
, len
, "album", &tags
->album
))
128 if (copy_if_tag_type(e
, len
, "year", &tags
->year
))
130 if (copy_if_tag_type(e
, len
, "comment", &tags
->comment
))
135 static int flac_read_meta(struct private_flac_afh_data
*pfad
)
138 FLAC__IOCallbacks meta_callbacks
= {
139 .read
= meta_read_cb
,
141 .seek
= meta_seek_cb
,
142 .tell
= meta_tell_cb
,
144 .close
= meta_close_cb
146 FLAC__Metadata_Chain
*chain
;
147 FLAC__Metadata_Iterator
*iter
;
148 FLAC__StreamMetadata_StreamInfo
*info
= NULL
;
151 chain
= FLAC__metadata_chain_new();
153 return -E_FLAC_CHAIN_ALLOC
;
154 ret
= -E_FLAC_CHAIN_READ
;
155 ok
= FLAC__metadata_chain_read_with_callbacks(chain
, pfad
,
159 ret
= -E_FLAC_ITER_ALLOC
;
160 iter
= FLAC__metadata_iterator_new();
163 FLAC__metadata_iterator_init(iter
, chain
);
165 FLAC__StreamMetadata
*b
;
166 b
= FLAC__metadata_iterator_get_block(iter
);
169 if (b
->type
== FLAC__METADATA_TYPE_STREAMINFO
) {
170 info
= &b
->data
.stream_info
;
171 ret
= -E_FLAC_VARBLOCK
;
172 if (info
->min_blocksize
!= info
->max_blocksize
)
174 pfad
->afhi
->frequency
= info
->sample_rate
;
175 pfad
->afhi
->channels
= info
->channels
;
176 pfad
->blocksize
= info
->min_blocksize
;
178 if (b
->type
== FLAC__METADATA_TYPE_VORBIS_COMMENT
)
179 flac_read_vorbis_comments(&b
->data
.vorbis_comment
,
181 ok
= FLAC__metadata_iterator_next(iter
);
185 ret
= info
? 0: -E_FLAC_STREAMINFO
;
187 FLAC__metadata_iterator_delete(iter
);
189 FLAC__metadata_chain_delete(chain
);
191 free_tags(&pfad
->afhi
->tags
);
195 static FLAC__StreamDecoderReadStatus
read_cb(
196 __a_unused
const FLAC__StreamDecoder
*decoder
,
197 FLAC__byte buffer
[], size_t *bytes
, void *client_data
)
199 struct private_flac_afh_data
*pfad
= client_data
;
202 *bytes
= copy_data(pfad
, buffer
, *bytes
);
204 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM
;
206 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE
;
209 static FLAC__StreamDecoderTellStatus
tell_cb(
210 __a_unused
const FLAC__StreamDecoder
*decoder
,
211 FLAC__uint64
*absolute_byte_offset
, void *client_data
)
213 struct private_flac_afh_data
*pfad
= client_data
;
215 *absolute_byte_offset
= pfad
->fpos
;
216 return FLAC__STREAM_DECODER_TELL_STATUS_OK
;
219 /* libflac insits on this callback being present. */
220 static FLAC__StreamDecoderWriteStatus
write_cb(
221 __a_unused
const FLAC__StreamDecoder
*decoder
,
222 __a_unused
const FLAC__Frame
*frame
,
223 __a_unused
const FLAC__int32
*const buffer
[],
224 __a_unused
void *client_data
)
226 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE
;
229 static void error_cb(
230 __a_unused
const FLAC__StreamDecoder
*decoder
,
231 FLAC__StreamDecoderErrorStatus status
,
232 __a_unused
void *client_data
)
234 PARA_ERROR_LOG("%s\n", FLAC__StreamDecoderErrorStatusString
[status
]);
237 static int flac_afh_read_chunks(struct private_flac_afh_data
*pfad
)
239 FLAC__StreamDecoder
*decoder
;
240 FLAC__StreamDecoderInitStatus init_status
;
243 unsigned chunk_table_size
= 0;
245 struct afh_info
*afhi
= pfad
->afhi
;
247 PARA_INFO_LOG("reading chunk table\n");
248 afhi
->chunk_table
= NULL
;
249 decoder
= FLAC__stream_decoder_new();
251 return -E_FLAC_AFH_DECODER_ALLOC
;
252 ret
= -E_FLAC_AFH_DECODER_INIT
;
253 init_status
= FLAC__stream_decoder_init_stream(
265 if (init_status
!= FLAC__STREAM_DECODER_INIT_STATUS_OK
)
267 ret
= -E_FLAC_SKIP_META
;
268 ok
= FLAC__stream_decoder_process_until_end_of_metadata(decoder
);
273 FLAC__StreamDecoderState state
;
275 ret
= -E_FLAC_DECODE_POS
;
276 ok
= FLAC__stream_decoder_get_decode_position(decoder
, &pos
);
279 if (c
>= chunk_table_size
) {
280 chunk_table_size
= 2 * chunk_table_size
+ 100;
281 afhi
->chunk_table
= para_realloc(afhi
->chunk_table
,
282 chunk_table_size
* sizeof(uint32_t));
284 afhi
->chunk_table
[c
] = pos
;
286 ok
= FLAC__stream_decoder_skip_single_frame(decoder
);
289 state
= FLAC__stream_decoder_get_state(decoder
);
290 if (state
== FLAC__STREAM_DECODER_END_OF_STREAM
)
293 afhi
->chunks_total
= c
;
296 FLAC__stream_decoder_finish(decoder
);
297 FLAC__stream_decoder_delete(decoder
);
299 freep(&afhi
->chunk_table
);
303 static int flac_get_file_info(char *map
, size_t map_bytes
, __a_unused
int fd
,
304 struct afh_info
*afhi
)
306 struct private_flac_afh_data pfad_struct
= {
308 .map_bytes
= map_bytes
,
310 }, *pfad
= &pfad_struct
;
314 afhi
->header_len
= 0;
315 ret
= flac_read_meta(pfad
);
319 ret
= flac_afh_read_chunks(pfad
);
321 free_tags(&afhi
->tags
);
324 afhi
->techinfo
= make_message("blocksize: %u", pfad
->blocksize
);
325 afhi
->seconds_total
= DIV_ROUND_UP(afhi
->chunks_total
* pfad
->blocksize
,
327 afhi
->bitrate
= pfad
->map_bytes
* 8 / afhi
->seconds_total
/ 1024;
328 chunk_time
= (double)pfad
->blocksize
/ afhi
->frequency
;
329 afhi
->chunk_tv
.tv_sec
= chunk_time
;
330 chunk_time
*= 1000 * 1000;
331 chunk_time
-= afhi
->chunk_tv
.tv_sec
* 1000 * 1000;
332 afhi
->chunk_tv
.tv_usec
= chunk_time
;
336 static const char* flac_suffixes
[] = {"flac", NULL
};
339 * The init function of the flac audio format handler.
341 * \param afh pointer to the struct to initialize
343 void flac_afh_init(struct audio_format_handler
*afh
)
345 afh
->get_file_info
= flac_get_file_info
,
346 afh
->suffixes
= flac_suffixes
;