61
|
1 /*
|
|
2 * The contents of this file are subject to the Mozilla Public
|
|
3 * License Version 1.1 (the "License"); you may not use this file
|
|
4 * except in compliance with the License. You may obtain a copy of
|
|
5 * the License at http://www.mozilla.org/MPL/
|
|
6 *
|
|
7 * Software distributed under the License is distributed on an "AS
|
|
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
9 * implied. See the License for the specific language governing
|
|
10 * rights and limitations under the License.
|
|
11 *
|
|
12 * The Original Code is MPEG4IP.
|
|
13 *
|
|
14 * The Initial Developer of the Original Code is Cisco Systems Inc.
|
|
15 * Portions created by Cisco Systems Inc. are
|
|
16 * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved.
|
|
17 *
|
|
18 * Contributor(s):
|
|
19 * M. Bakker mbakker at nero.com
|
|
20 *
|
|
21 * Apple iTunes Metadata handling
|
|
22 */
|
|
23
|
|
24 /**
|
|
25
|
|
26 The iTunes tagging seems to support any tag field name
|
|
27 but there are some predefined fields, also known from the QuickTime format
|
|
28
|
|
29 predefined fields (the ones I know of until now):
|
|
30 - ©nam : Name of the song/movie (string)
|
|
31 - ©ART : Name of the artist/performer (string)
|
|
32 - ©wrt : Name of the writer (string)
|
|
33 - ©alb : Name of the album (string)
|
|
34 - ©day : Year (4 bytes, e.g. "2003") (string)
|
|
35 - ©too : Tool(s) used to create the file (string)
|
|
36 - ©cmt : Comment (string)
|
|
37 - ©gen : Custom genre (string)
|
201
|
38 - ©grp : Grouping (string)
|
61
|
39 - trkn : Tracknumber (8 byte string)
|
|
40 16 bit: empty
|
|
41 16 bit: tracknumber
|
|
42 16 bit: total tracks on album
|
|
43 16 bit: empty
|
|
44 - disk : Disknumber (8 byte string)
|
|
45 16 bit: empty
|
|
46 16 bit: disknumber
|
|
47 16 bit: total number of disks
|
|
48 16 bit: empty
|
|
49 - gnre : Genre (16 bit genre) (ID3v1 index + 1)
|
|
50 - cpil : Part of a compilation (1 byte, 1 or 0)
|
|
51 - tmpo : Tempo in BPM (16 bit)
|
|
52 - covr : Cover art (xx bytes binary data)
|
|
53 - ---- : Free form metadata, can have any name and any data
|
|
54
|
|
55 **/
|
|
56
|
|
57 #include "mp4common.h"
|
|
58
|
|
59 bool MP4File::GetMetadataByIndex(u_int32_t index,
|
|
60 const char** ppName,
|
|
61 u_int8_t** ppValue, u_int32_t* pValueSize)
|
|
62 {
|
|
63 char s[256];
|
|
64
|
|
65 sprintf(s, "moov.udta.meta.ilst.*[%u].data.metadata", index);
|
|
66 GetBytesProperty(s, ppValue, pValueSize);
|
|
67
|
|
68 sprintf(s, "moov.udta.meta.ilst.*[%u]", index);
|
|
69 MP4Atom* pParent = m_pRootAtom->FindAtom(s);
|
|
70 *ppName = pParent->GetType();
|
|
71
|
|
72 /* check for free form tagfield */
|
|
73 if (memcmp(*ppName, "----", 4) == 0)
|
|
74 {
|
|
75 u_int8_t* pV;
|
|
76 u_int32_t VSize = 0;
|
|
77 char *pN;
|
|
78
|
|
79 sprintf(s, "moov.udta.meta.ilst.*[%u].name.metadata", index);
|
|
80 GetBytesProperty(s, &pV, &VSize);
|
|
81
|
|
82 pN = (char*)malloc((VSize+1)*sizeof(char));
|
|
83 memset(pN, 0, (VSize+1)*sizeof(char));
|
|
84 memcpy(pN, pV, VSize*sizeof(char));
|
|
85
|
|
86 *ppName = pN;
|
|
87 }
|
|
88
|
|
89 return true;
|
|
90 }
|
|
91
|
|
92 bool MP4File::CreateMetadataAtom(const char* name)
|
|
93 {
|
|
94 char s[256];
|
|
95 char t[256];
|
|
96
|
|
97 sprintf(t, "udta.meta.ilst.%s.data", name);
|
|
98 sprintf(s, "moov.udta.meta.ilst.%s.data", name);
|
|
99 AddDescendantAtoms("moov", t);
|
|
100 MP4Atom *pMetaAtom = m_pRootAtom->FindAtom(s);
|
|
101
|
|
102 if (!pMetaAtom)
|
|
103 return false;
|
|
104
|
|
105 /* some fields need special flags set */
|
|
106 if ((uint8_t)name[0] == 0251)
|
|
107 {
|
|
108 pMetaAtom->SetFlags(0x1);
|
|
109 } else if ((memcmp(name, "cpil", 4) == 0) || (memcmp(name, "tmpo", 4) == 0)) {
|
|
110 pMetaAtom->SetFlags(0x15);
|
|
111 }
|
|
112
|
|
113 MP4Atom *pHdlrAtom = m_pRootAtom->FindAtom("moov.udta.meta.hdlr");
|
|
114 MP4StringProperty *pStringProperty = NULL;
|
|
115 MP4BytesProperty *pBytesProperty = NULL;
|
|
116 ASSERT(pHdlrAtom);
|
|
117
|
|
118 pHdlrAtom->FindProperty(
|
|
119 "hdlr.handlerType", (MP4Property**)&pStringProperty);
|
|
120 ASSERT(pStringProperty);
|
|
121 pStringProperty->SetValue("mdir");
|
|
122
|
|
123 u_int8_t val[12];
|
|
124 memset(val, 0, 12*sizeof(u_int8_t));
|
|
125 val[0] = 0x61;
|
|
126 val[1] = 0x70;
|
|
127 val[2] = 0x70;
|
|
128 val[3] = 0x6c;
|
|
129 pHdlrAtom->FindProperty(
|
|
130 "hdlr.reserved2", (MP4Property**)&pBytesProperty);
|
|
131 ASSERT(pBytesProperty);
|
|
132 pBytesProperty->SetReadOnly(false);
|
|
133 pBytesProperty->SetValue(val, 12);
|
|
134 pBytesProperty->SetReadOnly(true);
|
|
135
|
|
136 return true;
|
|
137 }
|
|
138
|
201
|
139 bool MP4File::DeleteMetadataAtom(const char* name)
|
61
|
140 {
|
|
141 MP4Atom *pMetaAtom = NULL;
|
201
|
142 char s[256];
|
|
143
|
|
144 sprintf(s, "moov.udta.meta.ilst.%s", name);
|
61
|
145 pMetaAtom = m_pRootAtom->FindAtom(s);
|
|
146
|
201
|
147 /* if it exists, delete it */
|
|
148 if (pMetaAtom)
|
61
|
149 {
|
201
|
150 MP4Atom *pParent = pMetaAtom->GetParentAtom();
|
|
151
|
|
152 pParent->DeleteChildAtom(pMetaAtom);
|
61
|
153
|
201
|
154 delete pMetaAtom;
|
|
155
|
|
156 return true;
|
61
|
157 }
|
|
158
|
201
|
159 return false;
|
61
|
160 }
|
|
161
|
201
|
162 bool MP4File::SetMetadataString (const char *atom, const char *value)
|
|
163 {
|
|
164 char atomstring[40];
|
|
165 MP4Atom *pMetaAtom;
|
|
166 MP4BytesProperty *pMetadataProperty = NULL;
|
|
167 sprintf(atomstring, "moov.udta.meta.ilst.%s.data", atom);
|
|
168
|
|
169 pMetaAtom = m_pRootAtom->FindAtom(atomstring);
|
|
170
|
|
171 if (!pMetaAtom)
|
|
172 {
|
|
173 if (!CreateMetadataAtom(atom))
|
|
174 return false;
|
|
175
|
|
176 pMetaAtom = m_pRootAtom->FindAtom(atomstring);
|
|
177 }
|
|
178
|
|
179 pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
|
|
180 ASSERT(pMetadataProperty);
|
|
181
|
|
182 pMetadataProperty->SetValue((u_int8_t*)value, strlen(value));
|
|
183
|
|
184 return true;
|
|
185 }
|
|
186
|
|
187 bool MP4File::GetMetadataString (const char *atom, char **value)
|
61
|
188 {
|
|
189 unsigned char *val = NULL;
|
|
190 u_int32_t valSize = 0;
|
201
|
191 char atomstring[60];
|
|
192 sprintf(atomstring, "moov.udta.meta.ilst.%s.data.metadata", atom);
|
61
|
193
|
201
|
194 *value = NULL;
|
61
|
195
|
201
|
196 GetBytesProperty(atomstring, (u_int8_t**)&val, &valSize);
|
61
|
197
|
|
198 if (valSize > 0)
|
|
199 {
|
|
200 *value = (char*)malloc((valSize+1)*sizeof(unsigned char));
|
|
201 memset(*value, 0, (valSize+1)*sizeof(unsigned char));
|
|
202 memcpy(*value, val, valSize*sizeof(unsigned char));
|
|
203 return true;
|
201
|
204 }
|
|
205 return false;
|
|
206 }
|
|
207
|
|
208 bool MP4File::SetMetadataName(const char* value)
|
|
209 {
|
|
210 return SetMetadataString("\251nam", value);
|
|
211 }
|
|
212
|
|
213 bool MP4File::GetMetadataName(char** value)
|
|
214 {
|
|
215 return GetMetadataString("\251nam", value);
|
|
216 }
|
|
217
|
|
218 bool MP4File::DeleteMetadataName()
|
|
219 {
|
|
220 return DeleteMetadataAtom("\251nam");
|
|
221 }
|
|
222
|
|
223 bool MP4File::SetMetadataWriter(const char* value)
|
|
224 {
|
|
225 return SetMetadataString("\251wrt", value);
|
|
226 }
|
|
227
|
|
228 bool MP4File::GetMetadataWriter(char** value)
|
|
229 {
|
|
230 return GetMetadataString("\251wrt", value);
|
|
231 }
|
|
232
|
|
233 bool MP4File::DeleteMetadataWriter()
|
|
234 {
|
|
235 return DeleteMetadataAtom("\251wrt");
|
|
236 }
|
|
237
|
|
238 bool MP4File::SetMetadataAlbum(const char* value)
|
|
239 {
|
|
240 return SetMetadataString("\251alb", value);
|
|
241 }
|
|
242
|
|
243 bool MP4File::GetMetadataAlbum(char** value)
|
|
244 {
|
|
245 return GetMetadataString("\251alb", value);
|
|
246 }
|
|
247
|
|
248 bool MP4File::DeleteMetadataAlbum()
|
|
249 {
|
|
250 return DeleteMetadataAtom("\251alb");
|
61
|
251 }
|
|
252
|
|
253 bool MP4File::SetMetadataArtist(const char* value)
|
|
254 {
|
201
|
255 return SetMetadataString("\251ART", value);
|
61
|
256 }
|
|
257
|
|
258 bool MP4File::GetMetadataArtist(char** value)
|
|
259 {
|
201
|
260 return GetMetadataString("\251ART", value);
|
|
261 }
|
61
|
262
|
201
|
263 bool MP4File::DeleteMetadataArtist()
|
|
264 {
|
|
265 return DeleteMetadataAtom("\251ART");
|
61
|
266 }
|
|
267
|
|
268 bool MP4File::SetMetadataTool(const char* value)
|
|
269 {
|
201
|
270 return SetMetadataString("\251too", value);
|
61
|
271 }
|
|
272
|
|
273 bool MP4File::GetMetadataTool(char** value)
|
|
274 {
|
201
|
275 return GetMetadataString("\251too", value);
|
|
276 }
|
61
|
277
|
201
|
278 bool MP4File::DeleteMetadataTool()
|
|
279 {
|
|
280 return DeleteMetadataAtom("\251too");
|
61
|
281 }
|
|
282
|
|
283 bool MP4File::SetMetadataComment(const char* value)
|
|
284 {
|
201
|
285 return SetMetadataString("\251cmt", value);
|
61
|
286 }
|
|
287
|
|
288 bool MP4File::GetMetadataComment(char** value)
|
|
289 {
|
201
|
290 return GetMetadataString("\251cmt", value);
|
|
291 }
|
61
|
292
|
201
|
293 bool MP4File::DeleteMetadataComment()
|
|
294 {
|
|
295 return DeleteMetadataAtom("\251cmt");
|
61
|
296 }
|
|
297
|
|
298 bool MP4File::SetMetadataYear(const char* value)
|
|
299 {
|
201
|
300 if (strlen(value) != 4) return false;
|
61
|
301
|
201
|
302 return SetMetadataString("\251day", value);
|
61
|
303 }
|
|
304
|
|
305 bool MP4File::GetMetadataYear(char** value)
|
|
306 {
|
201
|
307 return GetMetadataString("\251day", value);
|
|
308 }
|
61
|
309
|
201
|
310 bool MP4File::DeleteMetadataYear()
|
|
311 {
|
|
312 return DeleteMetadataAtom("\251day");
|
61
|
313 }
|
|
314
|
|
315 bool MP4File::SetMetadataTrack(u_int16_t track, u_int16_t totalTracks)
|
|
316 {
|
|
317 unsigned char t[9];
|
|
318 const char *s = "moov.udta.meta.ilst.trkn.data";
|
|
319 MP4BytesProperty *pMetadataProperty = NULL;
|
|
320 MP4Atom *pMetaAtom = NULL;
|
|
321
|
|
322 pMetaAtom = m_pRootAtom->FindAtom(s);
|
|
323
|
|
324 if (!pMetaAtom)
|
|
325 {
|
|
326 if (!CreateMetadataAtom("trkn"))
|
|
327 return false;
|
|
328
|
|
329 pMetaAtom = m_pRootAtom->FindAtom(s);
|
|
330 }
|
|
331
|
|
332 memset(t, 0, 9*sizeof(unsigned char));
|
|
333 t[2] = (unsigned char)(track>>8)&0xFF;
|
|
334 t[3] = (unsigned char)(track)&0xFF;
|
|
335 t[4] = (unsigned char)(totalTracks>>8)&0xFF;
|
|
336 t[5] = (unsigned char)(totalTracks)&0xFF;
|
|
337
|
|
338 pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
|
|
339 ASSERT(pMetadataProperty);
|
|
340
|
|
341 pMetadataProperty->SetValue((u_int8_t*)t, 8);
|
|
342
|
|
343 return true;
|
|
344 }
|
|
345
|
|
346 bool MP4File::GetMetadataTrack(u_int16_t* track, u_int16_t* totalTracks)
|
|
347 {
|
|
348 unsigned char *val = NULL;
|
|
349 u_int32_t valSize = 0;
|
|
350 const char *s = "moov.udta.meta.ilst.trkn.data.metadata";
|
|
351
|
|
352 *track = 0;
|
|
353 *totalTracks = 0;
|
|
354
|
201
|
355 GetBytesProperty(s, (u_int8_t**)&val, &valSize);
|
|
356
|
61
|
357 if (valSize != 8)
|
|
358 return false;
|
|
359
|
|
360 *track = (u_int16_t)(val[3]);
|
|
361 *track += (u_int16_t)(val[2]<<8);
|
|
362 *totalTracks = (u_int16_t)(val[5]);
|
|
363 *totalTracks += (u_int16_t)(val[4]<<8);
|
|
364
|
|
365 return true;
|
|
366 }
|
|
367
|
201
|
368 bool MP4File::DeleteMetadataTrack()
|
|
369 {
|
|
370 return DeleteMetadataAtom("trkn");
|
|
371 }
|
|
372
|
61
|
373 bool MP4File::SetMetadataDisk(u_int16_t disk, u_int16_t totalDisks)
|
|
374 {
|
|
375 unsigned char t[9];
|
|
376 const char *s = "moov.udta.meta.ilst.disk.data";
|
|
377 MP4BytesProperty *pMetadataProperty = NULL;
|
|
378 MP4Atom *pMetaAtom = NULL;
|
|
379
|
|
380 pMetaAtom = m_pRootAtom->FindAtom(s);
|
|
381
|
|
382 if (!pMetaAtom)
|
|
383 {
|
|
384 if (!CreateMetadataAtom("disk"))
|
|
385 return false;
|
|
386
|
|
387 pMetaAtom = m_pRootAtom->FindAtom(s);
|
|
388 }
|
|
389
|
|
390 memset(t, 0, 9*sizeof(unsigned char));
|
|
391 t[2] = (unsigned char)(disk>>8)&0xFF;
|
|
392 t[3] = (unsigned char)(disk)&0xFF;
|
|
393 t[4] = (unsigned char)(totalDisks>>8)&0xFF;
|
|
394 t[5] = (unsigned char)(totalDisks)&0xFF;
|
|
395
|
|
396 pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
|
|
397 ASSERT(pMetadataProperty);
|
|
398
|
|
399 pMetadataProperty->SetValue((u_int8_t*)t, 8);
|
|
400
|
|
401 return true;
|
|
402 }
|
|
403
|
|
404 bool MP4File::GetMetadataDisk(u_int16_t* disk, u_int16_t* totalDisks)
|
|
405 {
|
|
406 unsigned char *val = NULL;
|
|
407 u_int32_t valSize = 0;
|
|
408 const char *s = "moov.udta.meta.ilst.disk.data.metadata";
|
|
409
|
|
410 *disk = 0;
|
|
411 *totalDisks = 0;
|
|
412
|
201
|
413 GetBytesProperty(s, (u_int8_t**)&val, &valSize);
|
|
414
|
61
|
415 if (valSize != 8)
|
|
416 return false;
|
|
417
|
|
418 *disk = (u_int16_t)(val[3]);
|
|
419 *disk += (u_int16_t)(val[2]<<8);
|
|
420 *totalDisks = (u_int16_t)(val[5]);
|
|
421 *totalDisks += (u_int16_t)(val[4]<<8);
|
|
422
|
|
423 return true;
|
|
424 }
|
|
425
|
201
|
426 bool MP4File::DeleteMetadataDisk()
|
|
427 {
|
|
428 return DeleteMetadataAtom("disk");
|
|
429 }
|
|
430
|
61
|
431 static const char* ID3v1GenreList[] = {
|
|
432 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
|
|
433 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
|
|
434 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
|
|
435 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
|
|
436 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk",
|
|
437 "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House",
|
|
438 "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
|
|
439 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock",
|
|
440 "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk",
|
|
441 "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta",
|
|
442 "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
|
|
443 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
|
|
444 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
|
|
445 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing",
|
|
446 "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde",
|
|
447 "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
|
|
448 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
|
|
449 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
|
|
450 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
|
|
451 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet",
|
|
452 "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall",
|
|
453 "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
|
|
454 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
|
|
455 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover", "Contemporary C",
|
|
456 "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop",
|
|
457 "SynthPop",
|
|
458 };
|
|
459
|
|
460 int GenreToString(char** GenreStr, const int genre)
|
|
461 {
|
|
462 if (genre > 0 &&
|
|
463 genre <= (int)(sizeof(ID3v1GenreList)/sizeof(*ID3v1GenreList)))
|
|
464 {
|
|
465 *GenreStr = (char*)malloc((strlen(ID3v1GenreList[genre-1])+1)*sizeof(char));
|
|
466 memset(*GenreStr, 0, (strlen(ID3v1GenreList[genre-1])+1)*sizeof(char));
|
|
467 strcpy(*GenreStr, ID3v1GenreList[genre-1]);
|
|
468 return 0;
|
|
469 } else {
|
|
470 *GenreStr = (char*)malloc(2*sizeof(char));
|
|
471 memset(*GenreStr, 0, 2*sizeof(char));
|
|
472 return 1;
|
|
473 }
|
|
474 }
|
|
475
|
|
476 int StringToGenre(const char* GenreStr)
|
|
477 {
|
|
478 unsigned int i;
|
|
479
|
|
480 for (i = 0; i < sizeof(ID3v1GenreList)/sizeof(*ID3v1GenreList); i++)
|
|
481 {
|
|
482 if (strcasecmp(GenreStr, ID3v1GenreList[i]) == 0)
|
|
483 return i+1;
|
|
484 }
|
|
485 return 0;
|
|
486 }
|
|
487
|
|
488 bool MP4File::SetMetadataGenre(const char* value)
|
|
489 {
|
|
490 u_int16_t genreIndex = 0;
|
|
491 unsigned char t[3];
|
|
492 MP4BytesProperty *pMetadataProperty = NULL;
|
|
493 MP4Atom *pMetaAtom = NULL;
|
|
494
|
|
495 genreIndex = StringToGenre(value);
|
|
496
|
201
|
497 const char *s = "moov.udta.meta.ilst.gnre.data";
|
|
498 const char *sroot = "moov.udta.meta.ilst.gnre";
|
|
499 const char *s2 = "moov.udta.meta.ilst.\251gen.data";
|
|
500 const char *s2root = "moov.udta.meta.ilst.\251gen";
|
61
|
501 if (genreIndex != 0)
|
|
502 {
|
201
|
503 pMetaAtom = m_pRootAtom->FindAtom(s);
|
61
|
504 if (!pMetaAtom)
|
|
505 {
|
|
506 if (!CreateMetadataAtom("gnre"))
|
|
507 return false;
|
|
508
|
|
509 pMetaAtom = m_pRootAtom->FindAtom(s);
|
|
510 }
|
|
511
|
|
512 memset(t, 0, 3*sizeof(unsigned char));
|
|
513 t[0] = (unsigned char)(genreIndex>>8)&0xFF;
|
|
514 t[1] = (unsigned char)(genreIndex)&0xFF;
|
|
515
|
|
516 pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
|
|
517 ASSERT(pMetadataProperty);
|
|
518
|
|
519 pMetadataProperty->SetValue((u_int8_t*)t, 2);
|
201
|
520
|
|
521 // remove other style of genre atom, if this one is added
|
|
522 pMetaAtom = m_pRootAtom->FindAtom(s2root);
|
|
523 if (pMetaAtom != NULL) {
|
|
524 MP4Atom *pParent = pMetaAtom->GetParentAtom();
|
|
525 pParent->DeleteChildAtom(pMetaAtom);
|
|
526 delete pMetaAtom;
|
|
527 }
|
|
528
|
|
529
|
|
530 (void)DeleteMetadataAtom( "\251gen" );
|
61
|
531
|
|
532 return true;
|
|
533 } else {
|
|
534 pMetaAtom = m_pRootAtom->FindAtom(s2);
|
|
535
|
|
536 if (!pMetaAtom)
|
|
537 {
|
|
538 if (!CreateMetadataAtom("\251gen"))
|
|
539 return false;
|
|
540
|
|
541 pMetaAtom = m_pRootAtom->FindAtom(s2);
|
|
542 }
|
|
543
|
|
544 pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
|
|
545 ASSERT(pMetadataProperty);
|
|
546
|
|
547 pMetadataProperty->SetValue((u_int8_t*)value, strlen(value));
|
|
548
|
201
|
549 // remove other gnre atom if this one is entered
|
|
550 pMetaAtom = m_pRootAtom->FindAtom(sroot);
|
|
551 if (pMetaAtom != NULL) {
|
|
552 MP4Atom *pParent = pMetaAtom->GetParentAtom();
|
|
553 pParent->DeleteChildAtom(pMetaAtom);
|
|
554 delete pMetaAtom;
|
|
555 }
|
61
|
556 return true;
|
|
557 }
|
|
558
|
|
559 return false;
|
|
560 }
|
|
561
|
|
562 bool MP4File::GetMetadataGenre(char** value)
|
|
563 {
|
|
564 u_int16_t genreIndex = 0;
|
|
565 unsigned char *val = NULL;
|
|
566 u_int32_t valSize = 0;
|
|
567 const char *t = "moov.udta.meta.ilst.gnre";
|
|
568 const char *s = "moov.udta.meta.ilst.gnre.data.metadata";
|
|
569
|
201
|
570 *value = NULL;
|
|
571
|
61
|
572 MP4Atom *gnre = FindAtom(t);
|
|
573
|
|
574 if (gnre)
|
|
575 {
|
|
576 GetBytesProperty(s, (u_int8_t**)&val, &valSize);
|
|
577
|
|
578 if (valSize != 2)
|
|
579 return false;
|
|
580
|
|
581 genreIndex = (u_int16_t)(val[1]);
|
|
582 genreIndex += (u_int16_t)(val[0]<<8);
|
|
583
|
|
584 GenreToString(value, genreIndex);
|
|
585
|
201
|
586 (void)DeleteMetadataAtom( "gnre" );
|
|
587
|
61
|
588 return true;
|
|
589 } else {
|
|
590 const char *s2 = "moov.udta.meta.ilst.\251gen.data.metadata";
|
|
591
|
|
592 val = NULL;
|
|
593 valSize = 0;
|
|
594
|
|
595 GetBytesProperty(s2, (u_int8_t**)&val, &valSize);
|
|
596
|
|
597 if (valSize > 0)
|
|
598 {
|
|
599 *value = (char*)malloc((valSize+1)*sizeof(unsigned char));
|
|
600 memset(*value, 0, (valSize+1)*sizeof(unsigned char));
|
|
601 memcpy(*value, val, valSize*sizeof(unsigned char));
|
|
602 return true;
|
|
603 } else {
|
|
604 return false;
|
|
605 }
|
|
606 }
|
|
607
|
|
608 return false;
|
|
609 }
|
|
610
|
201
|
611 bool MP4File::DeleteMetadataGenre()
|
|
612 {
|
|
613 bool val1 = DeleteMetadataAtom("\251gen");
|
|
614 bool val2 = DeleteMetadataAtom("gnre");
|
|
615 return val1 || val2;
|
|
616 }
|
|
617
|
|
618 bool MP4File::SetMetadataGrouping(const char* value)
|
|
619 {
|
|
620 return SetMetadataString("\251grp", value);
|
|
621 }
|
|
622
|
|
623 bool MP4File::GetMetadataGrouping(char** value)
|
|
624 {
|
|
625 return GetMetadataString("\251grp", value);
|
|
626 }
|
|
627
|
|
628 bool MP4File::DeleteMetadataGrouping()
|
|
629 {
|
|
630 return DeleteMetadataAtom("\251grp");
|
|
631 }
|
|
632
|
61
|
633 bool MP4File::SetMetadataTempo(u_int16_t tempo)
|
|
634 {
|
|
635 unsigned char t[3];
|
|
636 const char *s = "moov.udta.meta.ilst.tmpo.data";
|
|
637 MP4BytesProperty *pMetadataProperty = NULL;
|
|
638 MP4Atom *pMetaAtom = NULL;
|
|
639
|
|
640 pMetaAtom = m_pRootAtom->FindAtom(s);
|
|
641
|
|
642 if (!pMetaAtom)
|
|
643 {
|
|
644 if (!CreateMetadataAtom("tmpo"))
|
|
645 return false;
|
|
646
|
|
647 pMetaAtom = m_pRootAtom->FindAtom(s);
|
|
648 }
|
|
649
|
|
650 memset(t, 0, 3*sizeof(unsigned char));
|
|
651 t[0] = (unsigned char)(tempo>>8)&0xFF;
|
|
652 t[1] = (unsigned char)(tempo)&0xFF;
|
|
653
|
|
654 pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
|
|
655 ASSERT(pMetadataProperty);
|
|
656
|
|
657 pMetadataProperty->SetValue((u_int8_t*)t, 2);
|
|
658
|
|
659 return true;
|
|
660 }
|
|
661
|
|
662 bool MP4File::GetMetadataTempo(u_int16_t* tempo)
|
|
663 {
|
|
664 unsigned char *val = NULL;
|
|
665 u_int32_t valSize = 0;
|
|
666 const char *s = "moov.udta.meta.ilst.tmpo.data.metadata";
|
|
667
|
|
668 *tempo = 0;
|
|
669
|
201
|
670 GetBytesProperty(s, (u_int8_t**)&val, &valSize);
|
|
671
|
61
|
672 if (valSize != 2)
|
|
673 return false;
|
|
674
|
|
675 *tempo = (u_int16_t)(val[1]);
|
|
676 *tempo += (u_int16_t)(val[0]<<8);
|
|
677
|
|
678 return true;
|
|
679 }
|
|
680
|
201
|
681 bool MP4File::DeleteMetadataTempo()
|
|
682 {
|
|
683 return DeleteMetadataAtom("tmpo");
|
|
684 }
|
|
685
|
61
|
686 bool MP4File::SetMetadataCompilation(u_int8_t compilation)
|
|
687 {
|
|
688 const char *s = "moov.udta.meta.ilst.cpil.data";
|
|
689 MP4BytesProperty *pMetadataProperty = NULL;
|
|
690 MP4Atom *pMetaAtom = NULL;
|
|
691
|
|
692 pMetaAtom = m_pRootAtom->FindAtom(s);
|
|
693
|
|
694 if (!pMetaAtom)
|
|
695 {
|
|
696 if (!CreateMetadataAtom("cpil"))
|
|
697 return false;
|
|
698
|
|
699 pMetaAtom = m_pRootAtom->FindAtom(s);
|
|
700 }
|
|
701
|
|
702 pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
|
|
703 ASSERT(pMetadataProperty);
|
|
704
|
|
705 compilation &= 0x1;
|
|
706 pMetadataProperty->SetValue((u_int8_t*)&compilation, 1);
|
|
707
|
|
708 return true;
|
|
709 }
|
|
710
|
|
711 bool MP4File::GetMetadataCompilation(u_int8_t* compilation)
|
|
712 {
|
|
713 unsigned char *val = NULL;
|
|
714 u_int32_t valSize = 0;
|
|
715 const char *s = "moov.udta.meta.ilst.cpil.data.metadata";
|
|
716
|
|
717 *compilation = 0;
|
|
718
|
201
|
719 GetBytesProperty(s, (u_int8_t**)&val, &valSize);
|
|
720
|
61
|
721 if (valSize != 1)
|
|
722 return false;
|
|
723
|
|
724 *compilation = (u_int16_t)(val[0]);
|
|
725
|
|
726 return true;
|
|
727 }
|
|
728
|
201
|
729 bool MP4File::DeleteMetadataCompilation()
|
|
730 {
|
|
731 return DeleteMetadataAtom("cpil");
|
|
732 }
|
|
733
|
61
|
734 bool MP4File::SetMetadataCoverArt(u_int8_t *coverArt, u_int32_t size)
|
|
735 {
|
|
736 const char *s = "moov.udta.meta.ilst.covr.data";
|
|
737 MP4BytesProperty *pMetadataProperty = NULL;
|
|
738 MP4Atom *pMetaAtom = NULL;
|
|
739
|
|
740 pMetaAtom = m_pRootAtom->FindAtom(s);
|
|
741
|
|
742 if (!pMetaAtom)
|
|
743 {
|
|
744 if (!CreateMetadataAtom("covr"))
|
|
745 return false;
|
|
746
|
|
747 pMetaAtom = m_pRootAtom->FindAtom(s);
|
|
748 }
|
|
749
|
|
750 pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
|
|
751 ASSERT(pMetadataProperty);
|
|
752
|
|
753 pMetadataProperty->SetValue(coverArt, size);
|
|
754
|
|
755 return true;
|
|
756 }
|
|
757
|
|
758 bool MP4File::GetMetadataCoverArt(u_int8_t **coverArt, u_int32_t *size)
|
|
759 {
|
|
760 const char *s = "moov.udta.meta.ilst.covr.data.metadata";
|
201
|
761
|
|
762 *coverArt = NULL;
|
|
763 *size = 0;
|
|
764
|
61
|
765 GetBytesProperty(s, coverArt, size);
|
|
766
|
|
767 if (size == 0)
|
|
768 return false;
|
|
769
|
|
770 return true;
|
|
771 }
|
|
772
|
201
|
773 bool MP4File::DeleteMetadataCoverArt()
|
|
774 {
|
|
775 return DeleteMetadataAtom("covr");
|
|
776 }
|
|
777
|
61
|
778 bool MP4File::SetMetadataFreeForm(char *name, u_int8_t* pValue, u_int32_t valueSize)
|
|
779 {
|
|
780 MP4Atom *pMetaAtom = NULL;
|
|
781 MP4BytesProperty *pMetadataProperty = NULL;
|
|
782 char s[256];
|
|
783 int i = 0;
|
|
784
|
|
785 while (1)
|
|
786 {
|
|
787 MP4BytesProperty *pMetadataProperty;
|
|
788
|
|
789 sprintf(s, "moov.udta.meta.ilst.----[%u].name", i);
|
|
790
|
|
791 MP4Atom *pTagAtom = m_pRootAtom->FindAtom(s);
|
|
792
|
|
793 if (!pTagAtom)
|
|
794 break;
|
|
795
|
|
796 pTagAtom->FindProperty("name.metadata", (MP4Property**)&pMetadataProperty);
|
|
797 if (pMetadataProperty)
|
|
798 {
|
|
799 u_int8_t* pV;
|
|
800 u_int32_t VSize = 0;
|
|
801
|
|
802 pMetadataProperty->GetValue(&pV, &VSize);
|
|
803
|
|
804 if (VSize != 0)
|
|
805 {
|
|
806 if (memcmp(pV, name, VSize) == 0)
|
|
807 {
|
|
808 sprintf(s, "moov.udta.meta.ilst.----[%u].data.metadata", i);
|
|
809 SetBytesProperty(s, pValue, valueSize);
|
|
810
|
|
811 return true;
|
|
812 }
|
|
813 }
|
|
814 }
|
|
815
|
|
816 i++;
|
|
817 }
|
|
818
|
|
819 /* doesn't exist yet, create it */
|
|
820 char t[256];
|
|
821
|
|
822 sprintf(t, "udta.meta.ilst.----[%u]", i);
|
|
823 sprintf(s, "moov.udta.meta.ilst.----[%u].data", i);
|
|
824 AddDescendantAtoms("moov", t);
|
|
825
|
|
826 pMetaAtom = m_pRootAtom->FindAtom(s);
|
|
827
|
|
828 if (!pMetaAtom)
|
|
829 return false;
|
|
830
|
|
831 pMetaAtom->SetFlags(0x1);
|
|
832
|
|
833 MP4Atom *pHdlrAtom = m_pRootAtom->FindAtom("moov.udta.meta.hdlr");
|
|
834 MP4StringProperty *pStringProperty = NULL;
|
|
835 MP4BytesProperty *pBytesProperty = NULL;
|
|
836 ASSERT(pHdlrAtom);
|
|
837
|
|
838 pHdlrAtom->FindProperty(
|
|
839 "hdlr.handlerType", (MP4Property**)&pStringProperty);
|
|
840 ASSERT(pStringProperty);
|
|
841 pStringProperty->SetValue("mdir");
|
|
842
|
|
843 u_int8_t val[12];
|
|
844 memset(val, 0, 12*sizeof(u_int8_t));
|
|
845 val[0] = 0x61;
|
|
846 val[1] = 0x70;
|
|
847 val[2] = 0x70;
|
|
848 val[3] = 0x6c;
|
|
849 pHdlrAtom->FindProperty(
|
|
850 "hdlr.reserved2", (MP4Property**)&pBytesProperty);
|
|
851 ASSERT(pBytesProperty);
|
|
852 pBytesProperty->SetReadOnly(false);
|
|
853 pBytesProperty->SetValue(val, 12);
|
|
854 pBytesProperty->SetReadOnly(true);
|
|
855
|
|
856 pMetaAtom = m_pRootAtom->FindAtom(s);
|
|
857 pMetaAtom->FindProperty("data.metadata", (MP4Property**)&pMetadataProperty);
|
|
858 ASSERT(pMetadataProperty);
|
|
859 pMetadataProperty->SetValue(pValue, valueSize);
|
|
860
|
|
861 sprintf(s, "moov.udta.meta.ilst.----[%u].name", i);
|
|
862 pMetaAtom = m_pRootAtom->FindAtom(s);
|
|
863 pMetaAtom->FindProperty("name.metadata", (MP4Property**)&pMetadataProperty);
|
|
864 ASSERT(pMetadataProperty);
|
|
865 pMetadataProperty->SetValue((u_int8_t*)name, strlen(name));
|
|
866
|
|
867 sprintf(s, "moov.udta.meta.ilst.----[%u].mean", i);
|
|
868 pMetaAtom = m_pRootAtom->FindAtom(s);
|
|
869 pMetaAtom->FindProperty("mean.metadata", (MP4Property**)&pMetadataProperty);
|
|
870 ASSERT(pMetadataProperty);
|
|
871 pMetadataProperty->SetValue((u_int8_t*)"com.apple.iTunes", 16); /* ?? */
|
|
872
|
|
873 return true;
|
|
874 }
|
|
875
|
|
876 bool MP4File::GetMetadataFreeForm(char *name, u_int8_t** ppValue, u_int32_t *pValueSize)
|
|
877 {
|
|
878 char s[256];
|
|
879 int i = 0;
|
|
880
|
201
|
881 *ppValue = NULL;
|
|
882 *pValueSize = 0;
|
|
883
|
61
|
884 while (1)
|
|
885 {
|
|
886 MP4BytesProperty *pMetadataProperty;
|
|
887
|
|
888 sprintf(s, "moov.udta.meta.ilst.----[%u].name", i);
|
|
889
|
|
890 MP4Atom *pTagAtom = m_pRootAtom->FindAtom(s);
|
|
891
|
|
892 if (!pTagAtom)
|
|
893 return false;
|
|
894
|
|
895 pTagAtom->FindProperty("name.metadata", (MP4Property**)&pMetadataProperty);
|
|
896 if (pMetadataProperty)
|
|
897 {
|
|
898 u_int8_t* pV;
|
|
899 u_int32_t VSize = 0;
|
|
900
|
|
901 pMetadataProperty->GetValue(&pV, &VSize);
|
|
902
|
|
903 if (VSize != 0)
|
|
904 {
|
|
905 if (memcmp(pV, name, VSize) == 0)
|
|
906 {
|
|
907 sprintf(s, "moov.udta.meta.ilst.----[%u].data.metadata", i);
|
|
908 GetBytesProperty(s, ppValue, pValueSize);
|
|
909
|
|
910 return true;
|
|
911 }
|
|
912 }
|
|
913 }
|
|
914
|
|
915 i++;
|
|
916 }
|
|
917 }
|
|
918
|
201
|
919 bool MP4File::DeleteMetadataFreeForm(char *name)
|
|
920 {
|
|
921 char s[256];
|
|
922 int i = 0;
|
|
923
|
|
924 while (1)
|
|
925 {
|
|
926 MP4BytesProperty *pMetadataProperty;
|
|
927
|
|
928 sprintf(s, "moov.udta.meta.ilst.----[%u].name", i);
|
|
929
|
|
930 MP4Atom *pTagAtom = m_pRootAtom->FindAtom(s);
|
|
931
|
|
932 if (!pTagAtom)
|
|
933 return false;
|
|
934
|
|
935 pTagAtom->FindProperty("name.metadata", (MP4Property**)&pMetadataProperty);
|
|
936 if (pMetadataProperty)
|
|
937 {
|
|
938 u_int8_t* pV;
|
|
939 u_int32_t VSize = 0;
|
|
940
|
|
941 pMetadataProperty->GetValue(&pV, &VSize);
|
|
942
|
|
943 if (VSize != 0)
|
|
944 {
|
|
945 if (memcmp(pV, name, VSize) == 0)
|
|
946 {
|
|
947 sprintf(s, "----[%u]", i);
|
|
948
|
|
949 return DeleteMetadataAtom(s);
|
|
950 }
|
|
951 }
|
|
952 }
|
|
953
|
|
954 i++;
|
|
955 }
|
|
956 }
|
|
957
|
61
|
958 bool MP4File::MetadataDelete()
|
|
959 {
|
|
960 MP4Atom *pMetaAtom = NULL;
|
|
961 char s[256];
|
|
962
|
|
963 sprintf(s, "moov.udta.meta");
|
|
964 pMetaAtom = m_pRootAtom->FindAtom(s);
|
|
965
|
|
966 /* if it exists, delete it */
|
|
967 if (pMetaAtom)
|
|
968 {
|
|
969 MP4Atom *pParent = pMetaAtom->GetParentAtom();
|
|
970
|
|
971 pParent->DeleteChildAtom(pMetaAtom);
|
|
972
|
|
973 delete pMetaAtom;
|
|
974
|
|
975 return true;
|
|
976 }
|
|
977
|
|
978 return false;
|
|
979 }
|