2 * Copyright (C) 2011 Andre Noll <maan@tuebingen.mpg.de>
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>
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
;
87 static int meta_close_cb(FLAC__IOHandle __a_unused handle
)
92 static const FLAC__IOCallbacks meta_callbacks
= {
98 .close
= meta_close_cb
101 static void free_tags(struct taginfo
*tags
)
103 freep(&tags
->artist
);
107 freep(&tags
->comment
);
110 static bool copy_if_tag_type(const char *tag
, int taglen
, const char *type
,
113 char *q
= key_value_copy(tag
, taglen
, type
);
121 static void flac_read_vorbis_comments(FLAC__StreamMetadata_VorbisComment
*vc
,
122 struct taginfo
*tags
)
125 FLAC__StreamMetadata_VorbisComment_Entry
*comment
= vc
->comments
;
127 PARA_INFO_LOG("found %u vorbis comments\n", vc
->num_comments
);
128 for (i
= 0; i
< vc
->num_comments
; i
++) {
129 char *e
= (char *)comment
[i
].entry
;
130 int len
= comment
[i
].length
;
131 if (copy_if_tag_type(e
, len
, "artist", &tags
->artist
))
133 if (copy_if_tag_type(e
, len
, "title", &tags
->title
))
135 if (copy_if_tag_type(e
, len
, "album", &tags
->album
))
137 if (copy_if_tag_type(e
, len
, "year", &tags
->year
))
139 if (copy_if_tag_type(e
, len
, "comment", &tags
->comment
))
145 * FLAC__metadata_object_vorbiscomment_replace_comment() is buggy in some
146 * libFLAC versions (see commit e95399c1 in the flac git repository). Hence we
147 * use delete and add as a workaround.
149 static int flac_replace_vorbis_comment(FLAC__StreamMetadata
*b
,
150 const char *tag
, const char* val
)
153 FLAC__StreamMetadata_VorbisComment_Entry entry
;
156 PARA_INFO_LOG("replacing %s\n", tag
);
157 ret
= FLAC__metadata_object_vorbiscomment_remove_entries_matching(
160 return -E_FLAC_REPLACE_COMMENT
;
161 ok
= FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(
162 &entry
, tag
, val
? val
: "");
164 return -E_FLAC_REPLACE_COMMENT
;
165 ok
= FLAC__metadata_object_vorbiscomment_append_comment(b
, entry
,
166 false /* no copy */);
169 return -E_FLAC_REPLACE_COMMENT
;
174 static int flac_replace_vorbis_comments(FLAC__Metadata_Chain
*chain
,
175 FLAC__StreamMetadata
*b
, struct taginfo
*tags
)
180 ret
= flac_replace_vorbis_comment(b
, "artist", tags
->artist
);
183 ret
= flac_replace_vorbis_comment(b
, "title", tags
->title
);
186 ret
= flac_replace_vorbis_comment(b
, "album", tags
->album
);
189 ret
= flac_replace_vorbis_comment(b
, "year", tags
->year
);
192 ret
= flac_replace_vorbis_comment(b
, "comment", tags
->comment
);
196 * Even if padding is disabled, libflac will try to modify the original
197 * file inplace if the metadata size has not changed. This won't work
198 * here though, because the original file is mapped read-only. Since
199 * there is no option to force the use of a temp file we work around
200 * this shortcoming by adding a dummy entry which increases the size of
201 * the meta data. If the entry already exists, we simply remove it.
203 ok
= FLAC__metadata_chain_check_if_tempfile_needed(chain
,
204 false /* no padding */);
206 PARA_INFO_LOG("adding/removing dummy comment\n");
207 ret
= FLAC__metadata_object_vorbiscomment_remove_entries_matching(
210 return -E_FLAC_REPLACE_COMMENT
;
211 if (ret
== 0) { /* nothing was removed */
212 ret
= flac_replace_vorbis_comment(b
, "comment2",
213 "avoid inplace write");
217 assert(FLAC__metadata_chain_check_if_tempfile_needed(chain
,
218 false /* no padding */));
223 static int flac_init_meta(struct private_flac_afh_data
*pfad
,
224 FLAC__Metadata_Chain
**chainp
, FLAC__Metadata_Iterator
**iterp
)
228 FLAC__Metadata_Chain
*chain
;
229 FLAC__Metadata_Iterator
*iter
;
233 chain
= FLAC__metadata_chain_new();
235 return -E_FLAC_CHAIN_ALLOC
;
236 ret
= -E_FLAC_CHAIN_READ
;
237 ok
= FLAC__metadata_chain_read_with_callbacks(chain
, pfad
,
241 ret
= -E_FLAC_ITER_ALLOC
;
242 iter
= FLAC__metadata_iterator_new();
245 FLAC__metadata_iterator_init(iter
, chain
);
250 FLAC__metadata_chain_delete(chain
);
254 static int flac_read_meta(struct private_flac_afh_data
*pfad
)
257 FLAC__Metadata_Chain
*chain
;
258 FLAC__Metadata_Iterator
*iter
;
259 FLAC__StreamMetadata_StreamInfo
*info
= NULL
;
262 ret
= flac_init_meta(pfad
, &chain
, &iter
);
266 FLAC__StreamMetadata
*b
;
267 b
= FLAC__metadata_iterator_get_block(iter
);
270 if (b
->type
== FLAC__METADATA_TYPE_STREAMINFO
) {
271 info
= &b
->data
.stream_info
;
272 ret
= -E_FLAC_VARBLOCK
;
273 if (info
->min_blocksize
!= info
->max_blocksize
)
275 pfad
->afhi
->frequency
= info
->sample_rate
;
276 pfad
->afhi
->channels
= info
->channels
;
277 pfad
->blocksize
= info
->min_blocksize
;
279 if (b
->type
== FLAC__METADATA_TYPE_VORBIS_COMMENT
)
280 flac_read_vorbis_comments(&b
->data
.vorbis_comment
,
282 ok
= FLAC__metadata_iterator_next(iter
);
286 ret
= info
? 0: -E_FLAC_STREAMINFO
;
288 FLAC__metadata_iterator_delete(iter
);
289 FLAC__metadata_chain_delete(chain
);
291 free_tags(&pfad
->afhi
->tags
);
295 static FLAC__StreamDecoderReadStatus
read_cb(
296 __a_unused
const FLAC__StreamDecoder
*decoder
,
297 FLAC__byte buffer
[], size_t *bytes
, void *client_data
)
299 struct private_flac_afh_data
*pfad
= client_data
;
302 *bytes
= copy_data(pfad
, buffer
, *bytes
);
304 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM
;
306 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE
;
309 static FLAC__StreamDecoderTellStatus
tell_cb(
310 __a_unused
const FLAC__StreamDecoder
*decoder
,
311 FLAC__uint64
*absolute_byte_offset
, void *client_data
)
313 struct private_flac_afh_data
*pfad
= client_data
;
315 *absolute_byte_offset
= pfad
->fpos
;
316 return FLAC__STREAM_DECODER_TELL_STATUS_OK
;
319 /* libflac insists on this callback being present. */
320 static FLAC__StreamDecoderWriteStatus
write_cb(
321 __a_unused
const FLAC__StreamDecoder
*decoder
,
322 __a_unused
const FLAC__Frame
*frame
,
323 __a_unused
const FLAC__int32
*const buffer
[],
324 __a_unused
void *client_data
)
326 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE
;
329 static void error_cb(
330 __a_unused
const FLAC__StreamDecoder
*decoder
,
331 FLAC__StreamDecoderErrorStatus status
,
332 __a_unused
void *client_data
)
334 PARA_ERROR_LOG("%s\n", FLAC__StreamDecoderErrorStatusString
[status
]);
337 static int flac_afh_read_chunks(struct private_flac_afh_data
*pfad
)
339 FLAC__StreamDecoder
*decoder
;
340 FLAC__StreamDecoderInitStatus init_status
;
343 unsigned chunk_table_size
= 0;
345 struct afh_info
*afhi
= pfad
->afhi
;
347 PARA_INFO_LOG("reading chunk table\n");
348 afhi
->chunk_table
= NULL
;
349 decoder
= FLAC__stream_decoder_new();
351 return -E_FLAC_AFH_DECODER_ALLOC
;
352 ret
= -E_FLAC_AFH_DECODER_INIT
;
353 init_status
= FLAC__stream_decoder_init_stream(
365 if (init_status
!= FLAC__STREAM_DECODER_INIT_STATUS_OK
)
367 ret
= -E_FLAC_SKIP_META
;
368 ok
= FLAC__stream_decoder_process_until_end_of_metadata(decoder
);
373 FLAC__StreamDecoderState state
;
375 ret
= -E_FLAC_DECODE_POS
;
376 ok
= FLAC__stream_decoder_get_decode_position(decoder
, &pos
);
379 if (c
>= chunk_table_size
) {
380 chunk_table_size
= 2 * chunk_table_size
+ 100;
381 afhi
->chunk_table
= para_realloc(afhi
->chunk_table
,
382 chunk_table_size
* sizeof(uint32_t));
384 afhi
->chunk_table
[c
] = pos
;
386 ok
= FLAC__stream_decoder_skip_single_frame(decoder
);
389 state
= FLAC__stream_decoder_get_state(decoder
);
390 if (state
== FLAC__STREAM_DECODER_END_OF_STREAM
)
393 afhi
->chunks_total
= c
;
396 FLAC__stream_decoder_finish(decoder
);
397 FLAC__stream_decoder_delete(decoder
);
399 freep(&afhi
->chunk_table
);
403 static int flac_get_file_info(char *map
, size_t map_bytes
, __a_unused
int fd
,
404 struct afh_info
*afhi
)
406 struct private_flac_afh_data pfad_struct
= {
408 .map_bytes
= map_bytes
,
410 }, *pfad
= &pfad_struct
;
414 afhi
->header_len
= 0;
415 ret
= flac_read_meta(pfad
);
419 ret
= flac_afh_read_chunks(pfad
);
421 free_tags(&afhi
->tags
);
424 afhi
->techinfo
= make_message("blocksize: %u", pfad
->blocksize
);
425 afhi
->seconds_total
= DIV_ROUND_UP(afhi
->chunks_total
* pfad
->blocksize
,
427 afhi
->bitrate
= pfad
->map_bytes
* 8 / afhi
->seconds_total
/ 1024;
428 chunk_time
= (double)pfad
->blocksize
/ afhi
->frequency
;
429 afhi
->chunk_tv
.tv_sec
= chunk_time
;
430 chunk_time
*= 1000 * 1000;
431 chunk_time
-= afhi
->chunk_tv
.tv_sec
* 1000 * 1000;
432 afhi
->chunk_tv
.tv_usec
= chunk_time
;
436 static size_t temp_write_cb(const void *ptr
, size_t size
, size_t nmemb
,
437 FLAC__IOHandle handle
)
439 int ret
, fd
= *(int *)handle
;
440 size_t n
= size
* nmemb
; /* FIXME: possible overflow */
442 ret
= write_all(fd
, ptr
, n
);
445 * libflac expects POSIX semantics: If an error occurs, or the end of
446 * the file is reached, the return value is a short item count or zero.
449 PARA_ERROR_LOG("%s\n", para_strerror(-ret
));
455 /* only the write callback needs to be supplied for writing the temp file. */
456 static const FLAC__IOCallbacks temp_callbacks
= {
457 .write
= temp_write_cb
,
460 static int flac_write_chain(FLAC__Metadata_Chain
*chain
,
461 struct private_flac_afh_data
*pfad
, int fd
)
465 ok
= FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain
,
466 false /* no padding*/, pfad
,
467 meta_callbacks
, &fd
, temp_callbacks
);
469 FLAC__Metadata_ChainStatus st
;
470 st
= FLAC__metadata_chain_status(chain
);
471 PARA_ERROR_LOG("chain status: %d\n", st
);
472 if (st
== FLAC__METADATA_CHAIN_STATUS_READ_ERROR
)
473 PARA_ERROR_LOG("read error\n");
474 return -E_FLAC_WRITE_CHAIN
;
479 static int flac_rewrite_tags(const char *map
, size_t map_bytes
,
480 struct taginfo
*tags
, int fd
, __a_unused
const char *filename
)
483 FLAC__Metadata_Chain
*chain
;
484 FLAC__Metadata_Iterator
*iter
;
485 FLAC__StreamMetadata
*b
= NULL
;
487 struct private_flac_afh_data
*pfad
= para_calloc(sizeof(*pfad
));
490 pfad
->map_bytes
= map_bytes
;
493 ret
= flac_init_meta(pfad
, &chain
, &iter
);
496 for (ok
= true; ok
; ok
= FLAC__metadata_iterator_next(iter
)) {
497 b
= FLAC__metadata_iterator_get_block(iter
);
499 if (b
->type
== FLAC__METADATA_TYPE_VORBIS_COMMENT
)
503 ret
= -E_FLAC_REPLACE_COMMENT
;
506 ret
= flac_replace_vorbis_comments(chain
, b
, tags
);
509 ret
= flac_write_chain(chain
, pfad
, fd
);
511 FLAC__metadata_iterator_delete(iter
);
512 FLAC__metadata_chain_delete(chain
);
518 static const char* flac_suffixes
[] = {"flac", NULL
};
521 * The init function of the flac audio format handler.
523 * \param afh pointer to the struct to initialize
525 void flac_afh_init(struct audio_format_handler
*afh
)
527 afh
->get_file_info
= flac_get_file_info
,
528 afh
->suffixes
= flac_suffixes
;
529 afh
->rewrite_tags
= flac_rewrite_tags
;