1 /* Copyright (C) 2006 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
3 * based in parts on libfaad, Copyright (C) 2003-2005 M. Bakker,
7 /** \file aac_afh.c para_server's aac audio format handler. */
14 /* To get the mp4ff_tag_t and mp4ff_metadata_t typedefs. */
19 #include "portable_io.h"
25 struct aac_afh_context
{
31 mp4AudioSpecificConfig masc
;
35 static uint32_t aac_afh_read_cb(void *user_data
, void *dest
, uint32_t want
)
37 struct aac_afh_context
*c
= user_data
;
40 if (want
== 0 || c
->fpos
>= c
->mapsize
) {
41 PARA_INFO_LOG("failed attempt to read %u bytes @%zu\n", want
,
46 have
= c
->mapsize
- c
->fpos
;
47 rv
= PARA_MIN(have
, want
);
48 PARA_DEBUG_LOG("reading %u bytes @%zu\n", rv
, c
->fpos
);
49 memcpy(dest
, c
->map
+ c
->fpos
, rv
);
54 static uint32_t aac_afh_seek_cb(void *user_data
, uint64_t pos
)
56 struct aac_afh_context
*c
= user_data
;
61 static int32_t aac_afh_get_track(mp4ff_t
*mp4ff
, mp4AudioSpecificConfig
*masc
)
63 int32_t i
, rc
, num_tracks
= mp4ff_total_tracks(mp4ff
);
65 assert(num_tracks
>= 0);
66 for (i
= 0; i
< num_tracks
; i
++) {
67 unsigned char *buf
= NULL
;
68 unsigned buf_size
= 0;
70 mp4ff_get_decoder_config(mp4ff
, i
, &buf
, &buf_size
);
72 rc
= NeAACDecAudioSpecificConfig(buf
, buf_size
, masc
);
79 return -1; /* no audio track */
82 static int aac_afh_open(const void *map
, size_t mapsize
, void **afh_context
)
85 struct aac_afh_context
*c
= para_malloc(sizeof(*c
));
90 c
->cb
.read
= aac_afh_read_cb
;
91 c
->cb
.seek
= aac_afh_seek_cb
;
95 c
->mp4ff
= mp4ff_open_read(&c
->cb
);
98 c
->track
= aac_afh_get_track(c
->mp4ff
, &c
->masc
);
105 mp4ff_close(c
->mp4ff
);
112 static void aac_afh_close(void *afh_context
)
114 struct aac_afh_context
*c
= afh_context
;
115 mp4ff_close(c
->mp4ff
);
120 * Libmp4ff function to reposition the file to the given sample.
122 * \param f The opaque handle returned by mp4ff_open_read().
123 * \param track The number of the (audio) track.
124 * \param sample Destination.
126 * We need this function to obtain the offset of the sample within the audio
127 * file. Unfortunately, it is not exposed in the mp4ff header.
129 * \return This function always returns 0.
131 int32_t mp4ff_set_sample_position(mp4ff_t
*f
, const int32_t track
, const int32_t sample
);
133 static int aac_afh_get_chunk(long unsigned chunk_num
, void *afh_context
,
134 const char **buf
, size_t *len
)
136 struct aac_afh_context
*c
= afh_context
;
140 assert(chunk_num
<= INT_MAX
);
141 /* this function always returns zero */
142 mp4ff_set_sample_position(c
->mp4ff
, c
->track
, chunk_num
);
144 ss
= mp4ff_read_sample_getsize(c
->mp4ff
, c
->track
, chunk_num
);
146 return -E_MP4FF_BAD_SAMPLE
;
147 assert(ss
+ offset
<= c
->mapsize
);
148 *buf
= c
->map
+ offset
;
153 static void _aac_afh_get_taginfo(const mp4ff_t
*mp4ff
, struct taginfo
*tags
)
155 mp4ff_meta_get_artist(mp4ff
, &tags
->artist
);
156 mp4ff_meta_get_title(mp4ff
, &tags
->title
);
157 mp4ff_meta_get_date(mp4ff
, &tags
->year
);
158 mp4ff_meta_get_album(mp4ff
, &tags
->album
);
159 mp4ff_meta_get_comment(mp4ff
, &tags
->comment
);
163 * Init m4a file and write some tech data to given pointers.
165 static int aac_get_file_info(char *map
, size_t numbytes
, __a_unused
int fd
,
166 struct afh_info
*afhi
)
170 struct aac_afh_context
*c
;
176 ret
= aac_afh_open(map
, numbytes
, (void **)&c
);
180 ret
= -E_MP4FF_BAD_SAMPLERATE
;
181 rv
= mp4ff_get_sample_rate(c
->mp4ff
, c
->track
);
184 afhi
->frequency
= rv
;
186 ret
= -E_MP4FF_BAD_CHANNEL_COUNT
;
187 rv
= mp4ff_get_channel_count(c
->mp4ff
, c
->track
);
192 ret
= -E_MP4FF_BAD_SAMPLE_COUNT
;
193 rv
= mp4ff_num_samples(c
->mp4ff
, c
->track
);
196 afhi
->chunks_total
= rv
;
197 afhi
->max_chunk_size
= 0;
198 for (n
= 0; n
< afhi
->chunks_total
; n
++) {
199 if (aac_afh_get_chunk(n
, c
, &buf
, &sz
) < 0)
201 afhi
->max_chunk_size
= PARA_MAX((size_t)afhi
->max_chunk_size
, sz
);
204 tmp
= c
->masc
.sbr_present_flag
== 1? 2048 : 1024;
205 afhi
->seconds_total
= tmp
* afhi
->chunks_total
/ afhi
->frequency
;
206 ms2tv(1000 * tmp
/ afhi
->frequency
, &afhi
->chunk_tv
);
208 if (aac_afh_get_chunk(0, c
, &buf
, &sz
) >= 0)
209 numbytes
-= buf
- map
;
210 afhi
->bitrate
= 8 * numbytes
/ afhi
->seconds_total
/ 1000;
211 _aac_afh_get_taginfo(c
->mp4ff
, &afhi
->tags
);
218 static uint32_t aac_afh_meta_read_cb(void *user_data
, void *dest
, uint32_t want
)
220 int fd
= *(int *)user_data
;
221 return read(fd
, dest
, want
);
224 static uint32_t aac_afh_meta_seek_cb(void *user_data
, uint64_t pos
)
226 int fd
= *(int *)user_data
;
227 return lseek(fd
, pos
, SEEK_SET
);
230 static uint32_t aac_afh_meta_write_cb(void *user_data
, void *dest
, uint32_t want
)
232 int fd
= *(int *)user_data
;
233 return write(fd
, dest
, want
);
236 static uint32_t aac_afh_meta_truncate_cb(void *user_data
)
238 int fd
= *(int *)user_data
;
239 off_t offset
= lseek(fd
, 0, SEEK_CUR
);
240 return ftruncate(fd
, offset
);
243 static void replace_tag(mp4ff_tag_t
*tag
, const char *new_val
, bool *found
)
246 tag
->value
= para_strdup(new_val
);
250 static void add_tag(mp4ff_metadata_t
*md
, const char *item
, const char *value
)
252 md
->tags
[md
->count
].item
= para_strdup(item
);
253 md
->tags
[md
->count
].value
= para_strdup(value
);
257 static int aac_afh_rewrite_tags(const char *map
, size_t mapsize
,
258 struct taginfo
*tags
, int fd
, __a_unused
const char *filename
)
262 mp4ff_metadata_t metadata
;
264 mp4ff_callback_t cb
= {
265 .read
= aac_afh_meta_read_cb
,
266 .seek
= aac_afh_meta_seek_cb
,
267 .write
= aac_afh_meta_write_cb
,
268 .truncate
= aac_afh_meta_truncate_cb
,
271 bool found_artist
= false, found_title
= false, found_album
= false,
272 found_year
= false, found_comment
= false;
274 ret
= write_all(fd
, map
, mapsize
);
277 lseek(fd
, 0, SEEK_SET
);
279 mp4ff
= mp4ff_open_read_metaonly(&cb
);
281 return -E_MP4FF_OPEN
;
283 ret
= -E_MP4FF_META_READ
;
284 rv
= mp4ff_meta_get_num_items(mp4ff
);
288 PARA_NOTICE_LOG("%d metadata item(s) found\n", rv
);
290 metadata
.tags
= para_malloc((metadata
.count
+ 5) * sizeof(mp4ff_tag_t
));
291 for (i
= 0; i
< metadata
.count
; i
++) {
292 mp4ff_tag_t
*tag
= metadata
.tags
+ i
;
294 ret
= -E_MP4FF_META_READ
;
295 if (mp4ff_meta_get_by_index(mp4ff
, i
,
296 &tag
->item
, &tag
->value
) < 0)
298 PARA_INFO_LOG("found: %s: %s\n", tag
->item
, tag
->value
);
299 if (!strcmp(tag
->item
, "artist"))
300 replace_tag(tag
, tags
->artist
, &found_artist
);
301 else if (!strcmp(tag
->item
, "title"))
302 replace_tag(tag
, tags
->title
, &found_title
);
303 else if (!strcmp(tag
->item
, "album"))
304 replace_tag(tag
, tags
->album
, &found_album
);
305 else if (!strcmp(tag
->item
, "date"))
306 replace_tag(tag
, tags
->year
, &found_year
);
307 else if (!strcmp(tag
->item
, "comment"))
308 replace_tag(tag
, tags
->comment
, &found_comment
);
311 add_tag(&metadata
, "artist", tags
->artist
);
313 add_tag(&metadata
, "title", tags
->title
);
315 add_tag(&metadata
, "album", tags
->album
);
317 add_tag(&metadata
, "date", tags
->year
);
319 add_tag(&metadata
, "comment", tags
->comment
);
320 ret
= -E_MP4FF_META_WRITE
;
321 if (mp4ff_meta_update(&cb
, &metadata
) < 0)
326 free(metadata
.tags
[i
- 1].item
);
327 free(metadata
.tags
[i
- 1].value
);
335 static const char * const aac_suffixes
[] = {"m4a", "mp4", NULL
};
338 * The audio format handler for the Advanced Audio Codec.
340 * This is only compiled in if the faad library is installed.
342 const struct audio_format_handler aac_afh
= {
343 .get_file_info
= aac_get_file_info
,
344 .suffixes
= aac_suffixes
,
345 .rewrite_tags
= aac_afh_rewrite_tags
,
346 .open
= aac_afh_open
,
347 .get_chunk
= aac_afh_get_chunk
,
348 .close
= aac_afh_close
,