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. */
15 #include "portable_io.h"
21 struct aac_afh_context
{
26 struct mp4_callback cb
;
29 static ssize_t
aac_afh_read_cb(void *user_data
, void *dest
, size_t want
)
31 struct aac_afh_context
*c
= user_data
;
34 if (want
== 0 || c
->fpos
>= c
->mapsize
)
36 have
= c
->mapsize
- c
->fpos
;
37 rv
= PARA_MIN(have
, want
);
38 PARA_DEBUG_LOG("reading %zu bytes @%zu\n", rv
, c
->fpos
);
39 memcpy(dest
, c
->map
+ c
->fpos
, rv
);
44 static off_t
aac_afh_seek_cb(void *user_data
, off_t offset
, int whence
)
46 struct aac_afh_context
*c
= user_data
;
48 if (whence
== SEEK_SET
)
50 else if (whence
== SEEK_CUR
)
52 else if (whence
== SEEK_END
)
53 c
->fpos
= c
->mapsize
+ offset
;
59 static int aac_afh_open(const void *map
, size_t mapsize
, void **afh_context
)
62 struct aac_afh_context
*c
= alloc(sizeof(*c
));
67 c
->cb
.read
= aac_afh_read_cb
;
68 c
->cb
.seek
= aac_afh_seek_cb
;
71 ret
= mp4_open(&c
->cb
, &c
->mp4
);
82 static void aac_afh_close(void *afh_context
)
84 struct aac_afh_context
*c
= afh_context
;
89 static int aac_afh_get_chunk(uint32_t chunk_num
, void *afh_context
,
90 const char **buf
, uint32_t *len
)
92 struct aac_afh_context
*c
= afh_context
;
97 ret
= mp4_set_sample_position(c
->mp4
, chunk_num
);
101 ret
= mp4_get_sample_size(c
->mp4
, chunk_num
, &ss
);
104 if (ss
+ offset
> c
->mapsize
) /* file got truncated?! */
105 return -E_MP4_CORRUPT
;
106 *buf
= c
->map
+ offset
;
111 static void aac_afh_get_taginfo(const struct mp4
*mp4
, struct taginfo
*tags
)
113 tags
->artist
= mp4_get_tag_value(mp4
, "artist");
114 tags
->title
= mp4_get_tag_value(mp4
, "title");
115 tags
->year
= mp4_get_tag_value(mp4
, "date");
116 tags
->album
= mp4_get_tag_value(mp4
, "album");
117 tags
->comment
= mp4_get_tag_value(mp4
, "comment");
121 * Init m4a file and write some tech data to given pointers.
123 static int aac_get_file_info(char *map
, size_t numbytes
, __a_unused
int fd
,
124 struct afh_info
*afhi
)
127 struct aac_afh_context
*c
;
128 uint64_t milliseconds
;
132 ret
= aac_afh_open(map
, numbytes
, (void **)&c
);
136 afhi
->frequency
= mp4_get_sample_rate(c
->mp4
);
137 assert(afhi
->frequency
> 0);
138 afhi
->channels
= mp4_get_channel_count(c
->mp4
);
139 assert(afhi
->channels
> 0);
140 afhi
->chunks_total
= mp4_num_samples(c
->mp4
);
141 assert(afhi
->chunks_total
> 0);
143 afhi
->max_chunk_size
= 0;
144 for (n
= 0; n
< afhi
->chunks_total
; n
++) {
145 ret
= aac_afh_get_chunk(n
, c
, &buf
, &len
);
148 afhi
->max_chunk_size
= PARA_MAX(afhi
->max_chunk_size
, len
);
150 milliseconds
= mp4_get_duration(c
->mp4
);
151 afhi
->seconds_total
= milliseconds
/ 1000;
152 ms2tv(milliseconds
/ afhi
->chunks_total
, &afhi
->chunk_tv
);
153 if (aac_afh_get_chunk(0, c
, &buf
, &len
) < 0)
155 numbytes
-= buf
- map
;
156 afhi
->bitrate
= 8 * numbytes
/ afhi
->seconds_total
/ 1000;
157 aac_afh_get_taginfo(c
->mp4
, &afhi
->tags
);
164 static ssize_t
aac_afh_meta_read_cb(void *user_data
, void *dest
, size_t want
)
166 int fd
= *(int *)user_data
;
167 return read(fd
, dest
, want
);
170 static off_t
aac_afh_meta_seek_cb(void *user_data
, off_t offset
, int whence
)
172 int fd
= *(int *)user_data
;
173 off_t ret
= lseek(fd
, offset
, whence
);
175 assert(ret
!= (off_t
)-1);
179 static ssize_t
aac_afh_meta_write_cb(void *user_data
, void *dest
, size_t count
)
181 int fd
= *(int *)user_data
;
182 return write(fd
, dest
, count
);
185 static int aac_afh_meta_truncate_cb(void *user_data
)
187 int fd
= *(int *)user_data
;
188 off_t offset
= lseek(fd
, 0, SEEK_CUR
);
189 return ftruncate(fd
, offset
);
192 static void replace_or_add_tag(const char *item
, const char *value
,
193 struct mp4_metadata
*meta
)
198 for (n
= 0; n
< meta
->count
; n
++) {
200 if (strcasecmp(t
->item
, item
))
203 t
->value
= para_strdup(value
);
206 /* item not found, add new tag */
207 meta
->tags
= para_realloc(meta
->tags
, (meta
->count
+ 1)
208 * sizeof(struct mp4_tag
));
209 t
= meta
->tags
+ meta
->count
;
210 t
->item
= para_strdup(item
);
211 t
->value
= para_strdup(value
);
215 static int aac_afh_rewrite_tags(const char *map
, size_t mapsize
,
216 struct taginfo
*tags
, int fd
, __a_unused
const char *filename
)
219 struct mp4_metadata
*metadata
;
221 struct mp4_callback cb
= {
222 .read
= aac_afh_meta_read_cb
,
223 .seek
= aac_afh_meta_seek_cb
,
224 .write
= aac_afh_meta_write_cb
,
225 .truncate
= aac_afh_meta_truncate_cb
,
229 ret
= write_all(fd
, map
, mapsize
);
232 lseek(fd
, 0, SEEK_SET
);
234 ret
= mp4_open_meta(&cb
, &mp4
);
237 metadata
= mp4_get_meta(mp4
);
238 PARA_NOTICE_LOG("%u metadata item(s) found\n", metadata
->count
);
239 replace_or_add_tag("artist", tags
->artist
, metadata
);
240 replace_or_add_tag("title", tags
->title
, metadata
);
241 replace_or_add_tag("album", tags
->album
, metadata
);
242 replace_or_add_tag("date", tags
->year
, metadata
);
243 replace_or_add_tag("comment", tags
->comment
, metadata
);
244 ret
= mp4_update_meta(mp4
);
249 static const char * const aac_suffixes
[] = {"m4a", "mp4", NULL
};
252 * The audio format handler for the Advanced Audio Codec.
254 * This is only compiled in if the faad library is installed.
256 const struct audio_format_handler aac_afh
= {
257 .get_file_info
= aac_get_file_info
,
258 .suffixes
= aac_suffixes
,
259 .rewrite_tags
= aac_afh_rewrite_tags
,
260 .open
= aac_afh_open
,
261 .get_chunk
= aac_afh_get_chunk
,
262 .close
= aac_afh_close
,