Mercurial > audlegacy
comparison src/libaudtag/aac/aac.c @ 4887:0ddbd0025174 default tip
added libaudtag. (not used yet.)
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Wed, 05 May 2010 18:26:06 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4886:54b4f7aaca24 | 4887:0ddbd0025174 |
---|---|
1 /* | |
2 * Copyright 2009 Paula Stanciu | |
3 * | |
4 * This file is part of Audacious. | |
5 * | |
6 * Audacious is free software: you can redistribute it and/or modify it under | |
7 * the terms of the GNU General Public License as published by the Free Software | |
8 * Foundation, version 3 of the License. | |
9 * | |
10 * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY | |
11 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |
12 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |
13 * | |
14 * You should have received a copy of the GNU General Public License along with | |
15 * Audacious. If not, see <http://www.gnu.org/licenses/>. | |
16 * | |
17 * The Audacious team does not consider modular code linking to Audacious or | |
18 * using our public API to be a derived work. | |
19 */ | |
20 | |
21 #include <glib/gstdio.h> | |
22 #include <audlegacy/tuple.h> | |
23 #include <audlegacy/vfs.h> | |
24 #include "../tag_module.h" | |
25 #include "aac.h" | |
26 #include "../util.h" | |
27 | |
28 static const char *ID3v1GenreList[] = { | |
29 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", | |
30 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", | |
31 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", | |
32 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", | |
33 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", | |
34 "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", | |
35 "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass", | |
36 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", | |
37 "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", | |
38 "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", | |
39 "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", | |
40 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", | |
41 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", | |
42 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", | |
43 "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", | |
44 "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", | |
45 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", | |
46 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", | |
47 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", | |
48 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", | |
49 "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", | |
50 "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror", | |
51 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat", | |
52 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover", "Contemporary C", | |
53 "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", | |
54 "SynthPop", | |
55 }; | |
56 | |
57 gchar *atom_types[] = { "\251alb", "\251nam", "cprt", "\251art", "\251ART", "trkn", "\251day", "gnre", "desc" }; | |
58 | |
59 Atom *readAtom(VFSFile * fd) | |
60 { | |
61 guint32 size = read_BEuint32(fd); | |
62 if (size > vfs_fsize(fd)) | |
63 return NULL; | |
64 | |
65 Atom *atom = g_new0(Atom, 1); | |
66 atom->size = size; | |
67 atom->name = read_char_data(fd, 4); | |
68 atom->body = read_char_data(fd, atom->size - 8); | |
69 atom->type = 0; | |
70 return atom; | |
71 } | |
72 | |
73 void writeAtom(VFSFile * fd, Atom * atom) | |
74 { | |
75 write_BEuint32(fd, atom->size); | |
76 vfs_fwrite(atom->name, 4, 1, fd); | |
77 vfs_fwrite(atom->body, atom->size - 8, 1, fd); | |
78 } | |
79 | |
80 void printAtom(Atom * atom) | |
81 { | |
82 AUDDBG("size = %x\n", atom->size); | |
83 AUDDBG("name = %s\n", atom->name); | |
84 } | |
85 | |
86 StrDataAtom *readStrDataAtom(VFSFile * fd) | |
87 { | |
88 StrDataAtom *atom = g_new0(StrDataAtom, 1); | |
89 atom->atomsize = read_BEuint32(fd); | |
90 atom->name = read_char_data(fd, 4); | |
91 atom->datasize = read_BEuint32(fd); | |
92 atom->dataname = read_char_data(fd, 4); | |
93 atom->vflag = read_BEuint32(fd); | |
94 atom->nullData = read_BEuint32(fd); | |
95 atom->data = read_char_data(fd, atom->datasize - 16); | |
96 atom->type = 1; | |
97 return atom; | |
98 } | |
99 | |
100 void writeStrDataAtom(VFSFile * fd, StrDataAtom * atom) | |
101 { | |
102 write_BEuint32(fd, atom->atomsize); | |
103 vfs_fwrite(atom->name, 4, 1, fd); | |
104 write_BEuint32(fd, atom->datasize); | |
105 vfs_fwrite(atom->dataname, 4, 1, fd); | |
106 write_BEuint32(fd, atom->vflag); | |
107 write_BEuint32(fd, atom->nullData); | |
108 vfs_fwrite(atom->data, atom->datasize - 16, 1, fd); | |
109 } | |
110 | |
111 Atom *findAtom(VFSFile * fd, gchar * name) | |
112 { | |
113 Atom *atom = readAtom(fd); | |
114 while (strcmp(atom->name, name) && !vfs_feof(fd)) | |
115 { | |
116 g_free(atom); | |
117 atom = readAtom(fd); | |
118 } | |
119 if (vfs_feof(fd)) | |
120 { | |
121 g_free(atom); | |
122 AUDDBG("The atom %s could not be found\n", name); | |
123 return NULL; | |
124 } | |
125 return atom; | |
126 } | |
127 | |
128 Atom *getilstAtom(VFSFile * fd) | |
129 { | |
130 Atom *moov = findAtom(fd, MOOV); | |
131 | |
132 // search atom childs | |
133 vfs_fseek(fd, -(moov->size - 7), SEEK_CUR); | |
134 Atom *udta = findAtom(fd, UDTA); | |
135 | |
136 | |
137 vfs_fseek(fd, -(udta->size - 7), SEEK_CUR); | |
138 Atom *meta = findAtom(fd, META); | |
139 | |
140 vfs_fseek(fd, -(meta->size - 11), SEEK_CUR); | |
141 Atom *ilst = findAtom(fd, ILST); | |
142 | |
143 int zz = vfs_ftell(fd); | |
144 AUDDBG("zzz = %d\n", zz); | |
145 ilstFileOffset = vfs_ftell(fd) - ilst->size; | |
146 vfs_fseek(fd, -(ilst->size - 7), SEEK_CUR); | |
147 | |
148 return ilst; | |
149 | |
150 } | |
151 | |
152 int getAtomID(gchar * name) | |
153 { | |
154 g_return_val_if_fail(name != NULL, -1); | |
155 int i = 0; | |
156 for (i = 0; i < MP4_ITEMS_NO; i++) | |
157 { | |
158 if (!strcmp(name, atom_types[i])) | |
159 return i; | |
160 } | |
161 return -1; | |
162 } | |
163 | |
164 StrDataAtom *makeAtomWithData(const gchar * data, StrDataAtom * atom, int field) | |
165 { | |
166 guint32 charsize = strlen(data); | |
167 atom->atomsize = charsize + 24; | |
168 atom->name = atom_types[field]; | |
169 atom->datasize = charsize + 16; | |
170 atom->dataname = "data"; | |
171 atom->vflag = 0x0; | |
172 atom->nullData = 0x0; | |
173 atom->data = (gchar *) data; | |
174 atom->type = 1; | |
175 return atom; | |
176 | |
177 } | |
178 | |
179 void writeAtomListToFile(VFSFile * from, VFSFile * to, int offset, mowgli_list_t * list) | |
180 { | |
181 //read free atom if we have any :D | |
182 guint32 oset = ilstFileOffset + ilstAtom->size; | |
183 vfs_fseek(from, oset, SEEK_SET); | |
184 mowgli_list_t *atoms_before_free = mowgli_list_create(); | |
185 Atom *atom = readAtom(from); | |
186 while (strcmp(atom->name, "free") && !vfs_feof(from)) | |
187 { | |
188 mowgli_node_add(atom, mowgli_node_create(), atoms_before_free); | |
189 g_free(atom); | |
190 atom = readAtom(from); | |
191 } | |
192 g_free(atom); | |
193 if (vfs_feof(from)) | |
194 { | |
195 AUDDBG("No free atoms\n"); | |
196 g_free(atom); | |
197 atom = NULL; | |
198 } | |
199 | |
200 //write ilst atom header | |
201 gchar il[4] = ILST; | |
202 vfs_fwrite(&newilstSize, 4, 1, to); | |
203 vfs_fwrite(il, 4, 1, to); | |
204 //write ilst | |
205 | |
206 mowgli_node_t *n, *tn; | |
207 | |
208 MOWGLI_LIST_FOREACH_SAFE(n, tn, list->head) | |
209 { | |
210 if (((Atom *) (n->data))->type == 0) | |
211 { | |
212 writeAtom(to, (Atom *) (n->data)); | |
213 } | |
214 else | |
215 { | |
216 writeStrDataAtom(to, (StrDataAtom *) (n->data)); | |
217 } | |
218 } | |
219 | |
220 //write all atoms before free | |
221 if (atoms_before_free->count != 0) | |
222 { | |
223 | |
224 MOWGLI_LIST_FOREACH_SAFE(n, tn, list->head) | |
225 { | |
226 writeAtom(to, (Atom *) (n->data)); | |
227 } | |
228 } | |
229 if (atom != NULL) | |
230 { | |
231 atom->size -= newilstSize - ilstAtom->size; | |
232 } | |
233 writeAtom(to, atom); | |
234 } | |
235 | |
236 gboolean aac_can_handle_file(VFSFile * f) | |
237 { | |
238 Atom *first_atom = readAtom(f); | |
239 if (first_atom == NULL) | |
240 return FALSE; | |
241 if (!strcmp(first_atom->name, FTYP)) | |
242 return TRUE; | |
243 return FALSE; | |
244 } | |
245 | |
246 Tuple *aac_populate_tuple_from_file(Tuple * tuple, VFSFile * f) | |
247 { | |
248 if (ilstAtom) | |
249 g_free(ilstAtom); | |
250 ilstAtom = getilstAtom(f); | |
251 int size_read = 0; | |
252 | |
253 if (dataAtoms != NULL) | |
254 { | |
255 mowgli_node_t *n, *tn; | |
256 | |
257 MOWGLI_LIST_FOREACH_SAFE(n, tn, dataAtoms->head) | |
258 { | |
259 mowgli_node_delete(n, dataAtoms); | |
260 } | |
261 } | |
262 dataAtoms = mowgli_list_create(); | |
263 | |
264 while (size_read < ilstAtom->size) | |
265 { | |
266 Atom *at = readAtom(f); | |
267 mowgli_node_add(at, mowgli_node_create(), dataAtoms); | |
268 int atomtype = getAtomID(at->name); | |
269 if (atomtype == -1) | |
270 { | |
271 size_read += at->size; | |
272 continue; | |
273 } | |
274 g_free(at); | |
275 vfs_fseek(f, -(at->size), SEEK_CUR); | |
276 StrDataAtom *a = readStrDataAtom(f); | |
277 size_read += a->atomsize; | |
278 | |
279 switch (atomtype) | |
280 { | |
281 case MP4_ALBUM: | |
282 { | |
283 tuple_associate_string(tuple, FIELD_ALBUM, NULL, a->data); | |
284 } | |
285 break; | |
286 case MP4_TITLE: | |
287 { | |
288 tuple_associate_string(tuple, FIELD_TITLE, NULL, a->data); | |
289 } | |
290 break; | |
291 case MP4_COPYRIGHT: | |
292 { | |
293 tuple_associate_string(tuple, FIELD_COPYRIGHT, NULL, a->data); | |
294 } | |
295 break; | |
296 case MP4_ARTIST: | |
297 case MP4_ARTIST2: | |
298 { | |
299 tuple_associate_string(tuple, FIELD_ARTIST, NULL, a->data); | |
300 } | |
301 break; | |
302 case MP4_TRACKNR: | |
303 { | |
304 //tuple_associate_string(tuple,FIELD_ALBUM,NULL,a->data); | |
305 } | |
306 break; | |
307 case MP4_YEAR: | |
308 { | |
309 tuple_associate_int(tuple, FIELD_YEAR, NULL, atoi(a->data)); | |
310 } | |
311 break; | |
312 case MP4_GENRE: | |
313 { | |
314 guint8 *val = (guint8 *) (a->data + (a->datasize - 17)); | |
315 const gchar *genre = ID3v1GenreList[*val - 1]; | |
316 tuple_associate_string(tuple, FIELD_GENRE, NULL, genre); | |
317 } | |
318 break; | |
319 case MP4_COMMENT: | |
320 { | |
321 tuple_associate_string(tuple, FIELD_COMMENT, NULL, a->data); | |
322 } | |
323 break; | |
324 } | |
325 } | |
326 return tuple; | |
327 } | |
328 | |
329 gboolean aac_write_tuple_to_file(Tuple * tuple, VFSFile * f) | |
330 { | |
331 #ifdef BROKEN | |
332 return FALSE; | |
333 #endif | |
334 newilstSize = 0; | |
335 mowgli_node_t *n, *tn; | |
336 mowgli_list_t *newdataAtoms; | |
337 newdataAtoms = mowgli_list_create(); | |
338 | |
339 MOWGLI_LIST_FOREACH_SAFE(n, tn, dataAtoms->head) | |
340 { | |
341 int atomtype = getAtomID(((StrDataAtom *) (n->data))->name); | |
342 switch (atomtype) | |
343 { | |
344 case MP4_ALBUM: | |
345 { | |
346 const gchar *strVal = tuple_get_string(tuple, FIELD_ALBUM, NULL); | |
347 if (strVal != NULL) | |
348 { | |
349 StrDataAtom *atom = g_new0(StrDataAtom, 1); | |
350 atom = makeAtomWithData(strVal, atom, MP4_ALBUM); | |
351 mowgli_node_add(atom, mowgli_node_create(), newdataAtoms); | |
352 newilstSize += atom->atomsize; | |
353 } | |
354 else | |
355 { | |
356 mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); | |
357 newilstSize += ((Atom *) (n->data))->size; | |
358 } | |
359 } | |
360 break; | |
361 case MP4_TITLE: | |
362 { | |
363 const gchar *strVal = tuple_get_string(tuple, FIELD_TITLE, NULL); | |
364 if (strVal != NULL) | |
365 { | |
366 StrDataAtom *atom = g_new0(StrDataAtom, 1); | |
367 atom = makeAtomWithData(strVal, atom, MP4_TITLE); | |
368 mowgli_node_add(atom, mowgli_node_create(), newdataAtoms); | |
369 newilstSize += atom->atomsize; | |
370 } | |
371 else | |
372 { | |
373 mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); | |
374 newilstSize += ((Atom *) (n->data))->size; | |
375 } | |
376 } | |
377 break; | |
378 case MP4_COPYRIGHT: | |
379 { | |
380 const gchar *strVal = tuple_get_string(tuple, FIELD_COPYRIGHT, NULL); | |
381 if (strVal != NULL) | |
382 { | |
383 StrDataAtom *atom = g_new0(StrDataAtom, 1); | |
384 atom = makeAtomWithData(strVal, atom, MP4_COPYRIGHT); | |
385 mowgli_node_add(atom, mowgli_node_create(), newdataAtoms); | |
386 newilstSize += atom->atomsize; | |
387 } | |
388 else | |
389 { | |
390 mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); | |
391 newilstSize += ((Atom *) (n->data))->size; | |
392 } | |
393 } | |
394 break; | |
395 case MP4_ARTIST: | |
396 case MP4_ARTIST2: | |
397 { | |
398 const gchar *strVal = tuple_get_string(tuple, FIELD_ARTIST, NULL); | |
399 if (strVal != NULL) | |
400 { | |
401 StrDataAtom *atom = g_new0(StrDataAtom, 1); | |
402 atom = makeAtomWithData(strVal, atom, MP4_ARTIST2); | |
403 mowgli_node_add(atom, mowgli_node_create(), newdataAtoms); | |
404 newilstSize += atom->atomsize; | |
405 } | |
406 else | |
407 { | |
408 mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); | |
409 newilstSize += ((Atom *) (n->data))->size; | |
410 } | |
411 } | |
412 break; | |
413 case MP4_TRACKNR: | |
414 { | |
415 //tuple_associate_string(tuple,FIELD_ALBUM,NULL,a->data); | |
416 } | |
417 break; | |
418 case MP4_YEAR: | |
419 { | |
420 int iyear = tuple_get_int(tuple, FIELD_YEAR, NULL); | |
421 gchar *strVal = g_strdup_printf("%d", iyear); | |
422 if (strVal != NULL) | |
423 { | |
424 StrDataAtom *atom = g_new0(StrDataAtom, 1); | |
425 atom = makeAtomWithData(strVal, atom, MP4_YEAR); | |
426 mowgli_node_add(atom, mowgli_node_create(), newdataAtoms); | |
427 newilstSize += atom->atomsize; | |
428 } | |
429 else | |
430 { | |
431 mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); | |
432 newilstSize += ((Atom *) (n->data))->size; | |
433 } | |
434 } | |
435 break; | |
436 /* | |
437 case MP4_GENRE: | |
438 { | |
439 | |
440 guint8 *val = (guint8*)(a->data + (a->datasize-17)); | |
441 const gchar* genre = ID3v1GenreList[*val-1]; | |
442 tuple_associate_string(tuple,FIELD_GENRE,NULL,genre); | |
443 | |
444 }break; | |
445 */ | |
446 case MP4_COMMENT: | |
447 { | |
448 const gchar *strVal = tuple_get_string(tuple, FIELD_COMMENT, NULL); | |
449 if (strVal != NULL) | |
450 { | |
451 StrDataAtom *atom = g_new0(StrDataAtom, 1); | |
452 atom = makeAtomWithData(strVal, atom, MP4_COMMENT); | |
453 mowgli_node_add(atom, mowgli_node_create(), newdataAtoms); | |
454 newilstSize += atom->atomsize; | |
455 } | |
456 else | |
457 { | |
458 mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); | |
459 newilstSize += ((Atom *) (n->data))->size; | |
460 } | |
461 } | |
462 break; | |
463 default: | |
464 { | |
465 mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); | |
466 newilstSize += ((Atom *) (n->data))->size; | |
467 } | |
468 break; | |
469 } | |
470 } | |
471 | |
472 VFSFile *tmp; | |
473 const gchar *tmpdir = g_get_tmp_dir(); | |
474 gchar *tmp_path = g_strdup_printf("file://%s/%s", tmpdir, "tmp.mp4"); | |
475 tmp = vfs_fopen(tmp_path, "w"); | |
476 copyAudioData(f, tmp, 0, ilstFileOffset); | |
477 writeAtomListToFile(f, tmp, ilstFileOffset, newdataAtoms); | |
478 return TRUE; | |
479 } |