1 /* Copyright (C) 2011 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
3 /** \file flac_afh.c Audio format handler for flac files. */
6 #include <FLAC/stream_decoder.h>
7 #include <FLAC/metadata.h>
15 struct private_flac_afh_data
{
19 struct afh_info
*afhi
;
23 static size_t copy_data(struct private_flac_afh_data
*pfad
, void *buf
,
26 size_t copy
, have
= pfad
->map_bytes
- pfad
->fpos
;
30 copy
= have
< want
? have
: want
;
31 memcpy(buf
, pfad
->map
+ pfad
->fpos
, copy
);
36 static size_t meta_read_cb(void *ptr
, size_t size
, size_t nmemb
,
37 FLAC__IOHandle handle
)
39 struct private_flac_afh_data
*pfad
= handle
;
40 return copy_data(pfad
, ptr
, nmemb
* size
);
43 static int meta_seek_cb(FLAC__IOHandle handle
, FLAC__int64 offset
, int whence
)
45 struct private_flac_afh_data
*pfad
= handle
;
52 if (offset
>= pfad
->map_bytes
)
57 if (pfad
->fpos
+ offset
>= pfad
->map_bytes
)
62 if (offset
>= pfad
->map_bytes
)
71 static FLAC__int64
meta_tell_cb(FLAC__IOHandle handle
)
73 struct private_flac_afh_data
*pfad
= handle
;
77 static int meta_eof_cb(FLAC__IOHandle handle
)
79 struct private_flac_afh_data
*pfad
= handle
;
80 return pfad
->fpos
== pfad
->map_bytes
;
83 static int meta_close_cb(FLAC__IOHandle __a_unused handle
)
88 static const FLAC__IOCallbacks meta_callbacks
= {
94 .close
= meta_close_cb
97 static void free_tags(struct taginfo
*tags
)
103 freep(&tags
->comment
);
106 static bool copy_if_tag_type(const char *tag
, int taglen
, const char *type
,
109 char *q
= key_value_copy(tag
, taglen
, type
);
117 static void flac_read_vorbis_comments(FLAC__StreamMetadata_VorbisComment
*vc
,
118 struct taginfo
*tags
)
121 FLAC__StreamMetadata_VorbisComment_Entry
*comment
= vc
->comments
;
123 PARA_INFO_LOG("found %u vorbis comments\n", vc
->num_comments
);
124 for (i
= 0; i
< vc
->num_comments
; i
++) {
125 char *e
= (char *)comment
[i
].entry
;
126 int len
= comment
[i
].length
;
127 if (copy_if_tag_type(e
, len
, "artist", &tags
->artist
))
129 if (copy_if_tag_type(e
, len
, "title", &tags
->title
))
131 if (copy_if_tag_type(e
, len
, "album", &tags
->album
))
133 if (copy_if_tag_type(e
, len
, "year", &tags
->year
))
135 if (copy_if_tag_type(e
, len
, "comment", &tags
->comment
))
141 * FLAC__metadata_object_vorbiscomment_replace_comment() is buggy in some
142 * libFLAC versions (see commit e95399c1 in the flac git repository). Hence we
143 * use delete and add as a workaround.
145 static int flac_replace_vorbis_comment(FLAC__StreamMetadata
*b
,
146 const char *tag
, const char* val
)
149 FLAC__StreamMetadata_VorbisComment_Entry entry
;
152 PARA_INFO_LOG("replacing %s\n", tag
);
153 ret
= FLAC__metadata_object_vorbiscomment_remove_entries_matching(
156 return -E_FLAC_REPLACE_COMMENT
;
157 ok
= FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(
158 &entry
, tag
, val
? val
: "");
160 return -E_FLAC_REPLACE_COMMENT
;
161 ok
= FLAC__metadata_object_vorbiscomment_append_comment(b
, entry
,
162 false /* no copy */);
165 return -E_FLAC_REPLACE_COMMENT
;
170 static int flac_replace_vorbis_comments(FLAC__Metadata_Chain
*chain
,
171 FLAC__StreamMetadata
*b
, struct taginfo
*tags
)
176 ret
= flac_replace_vorbis_comment(b
, "artist", tags
->artist
);
179 ret
= flac_replace_vorbis_comment(b
, "title", tags
->title
);
182 ret
= flac_replace_vorbis_comment(b
, "album", tags
->album
);
185 ret
= flac_replace_vorbis_comment(b
, "year", tags
->year
);
188 ret
= flac_replace_vorbis_comment(b
, "comment", tags
->comment
);
192 * Even if padding is disabled, libflac will try to modify the original
193 * file inplace if the metadata size has not changed. This won't work
194 * here though, because the original file is mapped read-only. Since
195 * there is no option to force the use of a temp file we work around
196 * this shortcoming by adding a dummy entry which increases the size of
197 * the meta data. If the entry already exists, we simply remove it.
199 ok
= FLAC__metadata_chain_check_if_tempfile_needed(chain
,
200 false /* no padding */);
202 PARA_INFO_LOG("adding/removing dummy comment\n");
203 ret
= FLAC__metadata_object_vorbiscomment_remove_entries_matching(
206 return -E_FLAC_REPLACE_COMMENT
;
207 if (ret
== 0) { /* nothing was removed */
208 ret
= flac_replace_vorbis_comment(b
, "comment2",
209 "avoid inplace write");
213 assert(FLAC__metadata_chain_check_if_tempfile_needed(chain
,
214 false /* no padding */));
219 static int flac_init_meta(struct private_flac_afh_data
*pfad
,
220 FLAC__Metadata_Chain
**chainp
, FLAC__Metadata_Iterator
**iterp
)
224 FLAC__Metadata_Chain
*chain
;
225 FLAC__Metadata_Iterator
*iter
;
229 chain
= FLAC__metadata_chain_new();
231 return -E_FLAC_CHAIN_ALLOC
;
232 ret
= -E_FLAC_CHAIN_READ
;
233 ok
= FLAC__metadata_chain_read_with_callbacks(chain
, pfad
,
237 ret
= -E_FLAC_ITER_ALLOC
;
238 iter
= FLAC__metadata_iterator_new();
241 FLAC__metadata_iterator_init(iter
, chain
);
246 FLAC__metadata_chain_delete(chain
);
250 static int flac_read_meta(struct private_flac_afh_data
*pfad
)
253 FLAC__Metadata_Chain
*chain
;
254 FLAC__Metadata_Iterator
*iter
;
255 FLAC__StreamMetadata_StreamInfo
*info
= NULL
;
258 ret
= flac_init_meta(pfad
, &chain
, &iter
);
262 FLAC__StreamMetadata
*b
;
263 b
= FLAC__metadata_iterator_get_block(iter
);
266 if (b
->type
== FLAC__METADATA_TYPE_STREAMINFO
) {
267 info
= &b
->data
.stream_info
;
268 ret
= -E_FLAC_VARBLOCK
;
269 if (info
->min_blocksize
!= info
->max_blocksize
)
271 pfad
->afhi
->frequency
= info
->sample_rate
;
272 pfad
->afhi
->channels
= info
->channels
;
273 pfad
->blocksize
= info
->min_blocksize
;
275 if (b
->type
== FLAC__METADATA_TYPE_VORBIS_COMMENT
)
276 flac_read_vorbis_comments(&b
->data
.vorbis_comment
,
278 ok
= FLAC__metadata_iterator_next(iter
);
282 ret
= info
? 0: -E_FLAC_STREAMINFO
;
284 FLAC__metadata_iterator_delete(iter
);
285 FLAC__metadata_chain_delete(chain
);
287 free_tags(&pfad
->afhi
->tags
);
291 static FLAC__StreamDecoderReadStatus
read_cb(
292 __a_unused
const FLAC__StreamDecoder
*decoder
,
293 FLAC__byte buffer
[], size_t *bytes
, void *client_data
)
295 struct private_flac_afh_data
*pfad
= client_data
;
298 *bytes
= copy_data(pfad
, buffer
, *bytes
);
300 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM
;
302 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE
;
305 static FLAC__StreamDecoderTellStatus
tell_cb(
306 __a_unused
const FLAC__StreamDecoder
*decoder
,
307 FLAC__uint64
*absolute_byte_offset
, void *client_data
)
309 struct private_flac_afh_data
*pfad
= client_data
;
311 *absolute_byte_offset
= pfad
->fpos
;
312 return FLAC__STREAM_DECODER_TELL_STATUS_OK
;
315 /* libflac insists on this callback being present. */
316 static FLAC__StreamDecoderWriteStatus
write_cb(
317 __a_unused
const FLAC__StreamDecoder
*decoder
,
318 __a_unused
const FLAC__Frame
*frame
,
319 __a_unused
const FLAC__int32
*const buffer
[],
320 __a_unused
void *client_data
)
322 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE
;
325 static void error_cb(
326 __a_unused
const FLAC__StreamDecoder
*decoder
,
327 FLAC__StreamDecoderErrorStatus status
,
328 __a_unused
void *client_data
)
330 PARA_ERROR_LOG("%s\n", FLAC__StreamDecoderErrorStatusString
[status
]);
333 static int flac_afh_read_chunks(struct private_flac_afh_data
*pfad
)
335 FLAC__StreamDecoder
*decoder
;
336 FLAC__StreamDecoderInitStatus init_status
;
339 unsigned chunk_table_size
= 0;
341 struct afh_info
*afhi
= pfad
->afhi
;
343 PARA_INFO_LOG("reading chunk table\n");
344 afhi
->chunk_table
= NULL
;
345 decoder
= FLAC__stream_decoder_new();
347 return -E_FLAC_AFH_DECODER_ALLOC
;
348 ret
= -E_FLAC_AFH_DECODER_INIT
;
349 init_status
= FLAC__stream_decoder_init_stream(
361 if (init_status
!= FLAC__STREAM_DECODER_INIT_STATUS_OK
)
363 ret
= -E_FLAC_SKIP_META
;
364 ok
= FLAC__stream_decoder_process_until_end_of_metadata(decoder
);
369 FLAC__StreamDecoderState state
;
371 ret
= -E_FLAC_DECODE_POS
;
372 ok
= FLAC__stream_decoder_get_decode_position(decoder
, &pos
);
375 if (c
>= chunk_table_size
) {
376 chunk_table_size
= 2 * chunk_table_size
+ 100;
377 afhi
->chunk_table
= para_realloc(afhi
->chunk_table
,
378 chunk_table_size
* sizeof(uint32_t));
380 afhi
->chunk_table
[c
] = pos
;
382 ok
= FLAC__stream_decoder_skip_single_frame(decoder
);
385 state
= FLAC__stream_decoder_get_state(decoder
);
386 if (state
== FLAC__STREAM_DECODER_END_OF_STREAM
)
389 afhi
->chunks_total
= c
;
390 set_max_chunk_size(afhi
);
393 FLAC__stream_decoder_finish(decoder
);
394 FLAC__stream_decoder_delete(decoder
);
396 freep(&afhi
->chunk_table
);
400 static int flac_get_file_info(char *map
, size_t map_bytes
, __a_unused
int fd
,
401 struct afh_info
*afhi
)
403 struct private_flac_afh_data pfad_struct
= {
405 .map_bytes
= map_bytes
,
407 }, *pfad
= &pfad_struct
;
411 afhi
->header_len
= 0;
412 ret
= flac_read_meta(pfad
);
416 ret
= flac_afh_read_chunks(pfad
);
418 free_tags(&afhi
->tags
);
421 afhi
->techinfo
= make_message("blocksize: %u", pfad
->blocksize
);
422 afhi
->seconds_total
= DIV_ROUND_UP(afhi
->chunks_total
* pfad
->blocksize
,
424 afhi
->bitrate
= pfad
->map_bytes
* 8 / afhi
->seconds_total
/ 1024;
425 chunk_time
= (double)pfad
->blocksize
/ afhi
->frequency
;
426 afhi
->chunk_tv
.tv_sec
= chunk_time
;
427 chunk_time
*= 1000 * 1000;
428 chunk_time
-= afhi
->chunk_tv
.tv_sec
* 1000 * 1000;
429 afhi
->chunk_tv
.tv_usec
= chunk_time
;
433 static size_t temp_write_cb(const void *ptr
, size_t size
, size_t nmemb
,
434 FLAC__IOHandle handle
)
436 int ret
, fd
= *(int *)handle
;
437 size_t n
= size
* nmemb
; /* FIXME: possible overflow */
439 ret
= write_all(fd
, ptr
, n
);
442 * libflac expects POSIX semantics: If an error occurs, or the end of
443 * the file is reached, the return value is a short item count or zero.
446 PARA_ERROR_LOG("%s\n", para_strerror(-ret
));
452 /* only the write callback needs to be supplied for writing the temp file. */
453 static const FLAC__IOCallbacks temp_callbacks
= {
454 .write
= temp_write_cb
,
457 static int flac_write_chain(FLAC__Metadata_Chain
*chain
,
458 struct private_flac_afh_data
*pfad
, int fd
)
462 ok
= FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain
,
463 false /* no padding*/, pfad
,
464 meta_callbacks
, &fd
, temp_callbacks
);
466 FLAC__Metadata_ChainStatus st
;
467 st
= FLAC__metadata_chain_status(chain
);
468 PARA_ERROR_LOG("chain status: %u\n", st
);
469 if (st
== FLAC__METADATA_CHAIN_STATUS_READ_ERROR
)
470 PARA_ERROR_LOG("read error\n");
471 return -E_FLAC_WRITE_CHAIN
;
476 static int flac_rewrite_tags(const char *map
, size_t map_bytes
,
477 struct taginfo
*tags
, int fd
, __a_unused
const char *filename
)
480 FLAC__Metadata_Chain
*chain
;
481 FLAC__Metadata_Iterator
*iter
;
482 FLAC__StreamMetadata
*b
= NULL
;
484 struct private_flac_afh_data
*pfad
= para_calloc(sizeof(*pfad
));
487 pfad
->map_bytes
= map_bytes
;
490 ret
= flac_init_meta(pfad
, &chain
, &iter
);
493 for (ok
= true; ok
; ok
= FLAC__metadata_iterator_next(iter
)) {
494 b
= FLAC__metadata_iterator_get_block(iter
);
496 if (b
->type
== FLAC__METADATA_TYPE_VORBIS_COMMENT
)
500 ret
= -E_FLAC_REPLACE_COMMENT
;
503 ret
= flac_replace_vorbis_comments(chain
, b
, tags
);
506 ret
= flac_write_chain(chain
, pfad
, fd
);
508 FLAC__metadata_iterator_delete(iter
);
509 FLAC__metadata_chain_delete(chain
);
515 static const char * const flac_suffixes
[] = {"flac", NULL
};
518 * The init function of the flac audio format handler.
520 * \param afh pointer to the struct to initialize
522 void flac_afh_init(struct audio_format_handler
*afh
)
524 afh
->get_file_info
= flac_get_file_info
,
525 afh
->suffixes
= flac_suffixes
;
526 afh
->rewrite_tags
= flac_rewrite_tags
;