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
)
42 have
= c
->mapsize
- c
->fpos
;
43 rv
= PARA_MIN(have
, (size_t)want
);
44 PARA_DEBUG_LOG("reading %zu bytes @%zu\n", rv
, c
->fpos
);
45 memcpy(dest
, c
->map
+ c
->fpos
, rv
);
50 static uint32_t aac_afh_seek_cb(void *user_data
, uint64_t pos
)
52 struct aac_afh_context
*c
= user_data
;
57 static int32_t aac_afh_get_track(mp4ff_t
*mp4ff
, mp4AudioSpecificConfig
*masc
)
59 int32_t i
, rc
, num_tracks
= mp4ff_total_tracks(mp4ff
);
61 assert(num_tracks
>= 0);
62 for (i
= 0; i
< num_tracks
; i
++) {
63 unsigned char *buf
= NULL
;
64 unsigned buf_size
= 0;
66 mp4ff_get_decoder_config(mp4ff
, i
, &buf
, &buf_size
);
68 rc
= NeAACDecAudioSpecificConfig(buf
, buf_size
, masc
);
75 return -1; /* no audio track */
78 static int aac_afh_open(const void *map
, size_t mapsize
, void **afh_context
)
81 struct aac_afh_context
*c
= para_malloc(sizeof(*c
));
86 c
->cb
.read
= aac_afh_read_cb
;
87 c
->cb
.seek
= aac_afh_seek_cb
;
91 c
->mp4ff
= mp4ff_open_read(&c
->cb
);
94 c
->track
= aac_afh_get_track(c
->mp4ff
, &c
->masc
);
101 mp4ff_close(c
->mp4ff
);
108 static void aac_afh_close(void *afh_context
)
110 struct aac_afh_context
*c
= afh_context
;
111 mp4ff_close(c
->mp4ff
);
116 * Libmp4ff function to reposition the file to the given sample.
118 * \param f The opaque handle returned by mp4ff_open_read().
119 * \param track The number of the (audio) track.
120 * \param sample Destination.
122 * We need this function to obtain the offset of the sample within the audio
123 * file. Unfortunately, it is not exposed in the mp4ff header.
125 * \return This function always returns 0.
127 int32_t mp4ff_set_sample_position(mp4ff_t
*f
, const int32_t track
, const int32_t sample
);
129 static int aac_afh_get_chunk(uint32_t chunk_num
, void *afh_context
,
130 const char **buf
, uint32_t *len
)
132 struct aac_afh_context
*c
= afh_context
;
136 assert(chunk_num
<= INT_MAX
);
137 /* this function always returns zero */
138 mp4ff_set_sample_position(c
->mp4ff
, c
->track
, chunk_num
);
140 ss
= mp4ff_read_sample_getsize(c
->mp4ff
, c
->track
, chunk_num
);
142 return -E_MP4FF_BAD_SAMPLE
;
143 assert(ss
+ offset
<= c
->mapsize
);
144 *buf
= c
->map
+ offset
;
149 static void _aac_afh_get_taginfo(const mp4ff_t
*mp4ff
, struct taginfo
*tags
)
151 mp4ff_meta_get_artist(mp4ff
, &tags
->artist
);
152 mp4ff_meta_get_title(mp4ff
, &tags
->title
);
153 mp4ff_meta_get_date(mp4ff
, &tags
->year
);
154 mp4ff_meta_get_album(mp4ff
, &tags
->album
);
155 mp4ff_meta_get_comment(mp4ff
, &tags
->comment
);
159 * Init m4a file and write some tech data to given pointers.
161 static int aac_get_file_info(char *map
, size_t numbytes
, __a_unused
int fd
,
162 struct afh_info
*afhi
)
166 struct aac_afh_context
*c
;
171 ret
= aac_afh_open(map
, numbytes
, (void **)&c
);
175 ret
= -E_MP4FF_BAD_SAMPLERATE
;
176 rv
= mp4ff_get_sample_rate(c
->mp4ff
, c
->track
);
179 afhi
->frequency
= rv
;
181 ret
= -E_MP4FF_BAD_CHANNEL_COUNT
;
182 rv
= mp4ff_get_channel_count(c
->mp4ff
, c
->track
);
187 ret
= -E_MP4FF_BAD_SAMPLE_COUNT
;
188 rv
= mp4ff_num_samples(c
->mp4ff
, c
->track
);
191 afhi
->chunks_total
= rv
;
192 afhi
->max_chunk_size
= 0;
193 for (n
= 0; n
< afhi
->chunks_total
; n
++) {
194 if (aac_afh_get_chunk(n
, c
, &buf
, &len
) < 0)
196 afhi
->max_chunk_size
= PARA_MAX(afhi
->max_chunk_size
, len
);
199 tmp
= c
->masc
.sbr_present_flag
== 1? 2048 : 1024;
200 afhi
->seconds_total
= tmp
* afhi
->chunks_total
/ afhi
->frequency
;
201 ms2tv(1000 * tmp
/ afhi
->frequency
, &afhi
->chunk_tv
);
203 if (aac_afh_get_chunk(0, c
, &buf
, &len
) >= 0)
204 numbytes
-= buf
- map
;
205 afhi
->bitrate
= 8 * numbytes
/ afhi
->seconds_total
/ 1000;
206 _aac_afh_get_taginfo(c
->mp4ff
, &afhi
->tags
);
213 static uint32_t aac_afh_meta_read_cb(void *user_data
, void *dest
, uint32_t want
)
215 int fd
= *(int *)user_data
;
216 return read(fd
, dest
, want
);
219 static uint32_t aac_afh_meta_seek_cb(void *user_data
, uint64_t pos
)
221 int fd
= *(int *)user_data
;
222 return lseek(fd
, pos
, SEEK_SET
);
225 static uint32_t aac_afh_meta_write_cb(void *user_data
, void *dest
, uint32_t want
)
227 int fd
= *(int *)user_data
;
228 return write(fd
, dest
, want
);
231 static uint32_t aac_afh_meta_truncate_cb(void *user_data
)
233 int fd
= *(int *)user_data
;
234 off_t offset
= lseek(fd
, 0, SEEK_CUR
);
235 return ftruncate(fd
, offset
);
238 static void replace_tag(mp4ff_tag_t
*tag
, const char *new_val
, bool *found
)
241 tag
->value
= para_strdup(new_val
);
245 static void add_tag(mp4ff_metadata_t
*md
, const char *item
, const char *value
)
247 md
->tags
[md
->count
].item
= para_strdup(item
);
248 md
->tags
[md
->count
].value
= para_strdup(value
);
252 static int aac_afh_rewrite_tags(const char *map
, size_t mapsize
,
253 struct taginfo
*tags
, int fd
, __a_unused
const char *filename
)
257 mp4ff_metadata_t metadata
;
259 mp4ff_callback_t cb
= {
260 .read
= aac_afh_meta_read_cb
,
261 .seek
= aac_afh_meta_seek_cb
,
262 .write
= aac_afh_meta_write_cb
,
263 .truncate
= aac_afh_meta_truncate_cb
,
266 bool found_artist
= false, found_title
= false, found_album
= false,
267 found_year
= false, found_comment
= false;
269 ret
= write_all(fd
, map
, mapsize
);
272 lseek(fd
, 0, SEEK_SET
);
274 mp4ff
= mp4ff_open_read_metaonly(&cb
);
276 return -E_MP4FF_OPEN
;
278 ret
= -E_MP4FF_META_READ
;
279 rv
= mp4ff_meta_get_num_items(mp4ff
);
283 PARA_NOTICE_LOG("%d metadata item(s) found\n", rv
);
285 metadata
.tags
= para_malloc((metadata
.count
+ 5) * sizeof(mp4ff_tag_t
));
286 for (i
= 0; i
< metadata
.count
; i
++) {
287 mp4ff_tag_t
*tag
= metadata
.tags
+ i
;
289 ret
= -E_MP4FF_META_READ
;
290 if (!mp4ff_meta_get_by_index(mp4ff
, i
, &tag
->item
, &tag
->value
))
292 PARA_INFO_LOG("found: %s: %s\n", tag
->item
, tag
->value
);
293 if (!strcmp(tag
->item
, "artist"))
294 replace_tag(tag
, tags
->artist
, &found_artist
);
295 else if (!strcmp(tag
->item
, "title"))
296 replace_tag(tag
, tags
->title
, &found_title
);
297 else if (!strcmp(tag
->item
, "album"))
298 replace_tag(tag
, tags
->album
, &found_album
);
299 else if (!strcmp(tag
->item
, "date"))
300 replace_tag(tag
, tags
->year
, &found_year
);
301 else if (!strcmp(tag
->item
, "comment"))
302 replace_tag(tag
, tags
->comment
, &found_comment
);
305 add_tag(&metadata
, "artist", tags
->artist
);
307 add_tag(&metadata
, "title", tags
->title
);
309 add_tag(&metadata
, "album", tags
->album
);
311 add_tag(&metadata
, "date", tags
->year
);
313 add_tag(&metadata
, "comment", tags
->comment
);
314 ret
= -E_MP4FF_META_WRITE
;
315 if (!mp4ff_meta_update(&cb
, &metadata
))
320 free(metadata
.tags
[i
- 1].item
);
321 free(metadata
.tags
[i
- 1].value
);
329 static const char * const aac_suffixes
[] = {"m4a", "mp4", NULL
};
332 * The audio format handler for the Advanced Audio Codec.
334 * This is only compiled in if the faad library is installed.
336 const struct audio_format_handler aac_afh
= {
337 .get_file_info
= aac_get_file_info
,
338 .suffixes
= aac_suffixes
,
339 .rewrite_tags
= aac_afh_rewrite_tags
,
340 .open
= aac_afh_open
,
341 .get_chunk
= aac_afh_get_chunk
,
342 .close
= aac_afh_close
,