2
* Entagged Audio Tag library
3
* Copyright (c) 2003-2005 Raphael Slinckx <raphael@slinckx.net>
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2.1 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
package org.jaudiotagger.tag.mp4;
21
import org.jaudiotagger.audio.generic.AbstractTag;
22
import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader;
23
import org.jaudiotagger.logging.ErrorMessage;
24
import org.jaudiotagger.tag.*;
25
import org.jaudiotagger.tag.datatype.Artwork;
26
import static org.jaudiotagger.tag.mp4.Mp4FieldKey.*;
27
import org.jaudiotagger.tag.mp4.field.*;
29
import java.util.ArrayList;
30
import java.util.EnumMap;
31
import java.util.List;
34
* A Logical representation of Mp4Tag, i.e the meta information stored in an Mp4 file underneath the
35
* moov.udt.meta.ilst atom.
37
public class Mp4Tag extends AbstractTag
40
private static final EnumMap<FieldKey, Mp4FieldKey> tagFieldToMp4Field = new EnumMap<FieldKey, Mp4FieldKey>(FieldKey.class);
42
//Mapping from generic key to mp4 key
45
tagFieldToMp4Field.put(FieldKey.ARTIST, Mp4FieldKey.ARTIST);
46
tagFieldToMp4Field.put(FieldKey.ALBUM, Mp4FieldKey.ALBUM);
47
tagFieldToMp4Field.put(FieldKey.TITLE, Mp4FieldKey.TITLE);
48
tagFieldToMp4Field.put(FieldKey.TRACK, Mp4FieldKey.TRACK);
49
tagFieldToMp4Field.put(FieldKey.YEAR, Mp4FieldKey.DAY);
50
tagFieldToMp4Field.put(FieldKey.GENRE, Mp4FieldKey.GENRE);
51
tagFieldToMp4Field.put(FieldKey.COMMENT, Mp4FieldKey.COMMENT);
52
tagFieldToMp4Field.put(FieldKey.ALBUM_ARTIST, Mp4FieldKey.ALBUM_ARTIST);
53
tagFieldToMp4Field.put(FieldKey.COMPOSER, Mp4FieldKey.COMPOSER);
54
tagFieldToMp4Field.put(FieldKey.GROUPING, Mp4FieldKey.GROUPING);
55
tagFieldToMp4Field.put(FieldKey.DISC_NO, Mp4FieldKey.DISCNUMBER);
56
tagFieldToMp4Field.put(FieldKey.BPM, Mp4FieldKey.BPM);
57
tagFieldToMp4Field.put(FieldKey.ENCODER, Mp4FieldKey.ENCODER);
58
tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_ARTISTID, Mp4FieldKey.MUSICBRAINZ_ARTISTID);
59
tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_RELEASEID, Mp4FieldKey.MUSICBRAINZ_ALBUMID);
60
tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_RELEASEARTISTID, Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID);
61
tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_TRACK_ID, Mp4FieldKey.MUSICBRAINZ_TRACKID);
62
tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_DISC_ID, Mp4FieldKey.MUSICBRAINZ_DISCID);
63
tagFieldToMp4Field.put(FieldKey.MUSICIP_ID, Mp4FieldKey.MUSICIP_PUID);
64
tagFieldToMp4Field.put(FieldKey.AMAZON_ID, Mp4FieldKey.ASIN);
65
tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_RELEASE_STATUS, Mp4FieldKey.MUSICBRAINZ_ALBUM_STATUS);
66
tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_RELEASE_TYPE, Mp4FieldKey.MUSICBRAINZ_ALBUM_TYPE);
67
tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY, Mp4FieldKey.RELEASECOUNTRY);
68
tagFieldToMp4Field.put(FieldKey.LYRICS, Mp4FieldKey.LYRICS);
69
tagFieldToMp4Field.put(FieldKey.IS_COMPILATION, Mp4FieldKey.COMPILATION);
70
tagFieldToMp4Field.put(FieldKey.ARTIST_SORT, Mp4FieldKey.ARTIST_SORT);
71
tagFieldToMp4Field.put(FieldKey.ALBUM_ARTIST_SORT, Mp4FieldKey.ALBUM_ARTIST_SORT);
72
tagFieldToMp4Field.put(FieldKey.ALBUM_SORT, Mp4FieldKey.ALBUM_SORT);
73
tagFieldToMp4Field.put(FieldKey.TITLE_SORT, Mp4FieldKey.TITLE_SORT);
74
tagFieldToMp4Field.put(FieldKey.COMPOSER_SORT, Mp4FieldKey.COMPOSER_SORT);
75
tagFieldToMp4Field.put(FieldKey.COVER_ART, Mp4FieldKey.ARTWORK);
76
tagFieldToMp4Field.put(FieldKey.ISRC, Mp4FieldKey.ISRC);
77
tagFieldToMp4Field.put(FieldKey.CATALOG_NO, Mp4FieldKey.CATALOGNO);
78
tagFieldToMp4Field.put(FieldKey.BARCODE, Mp4FieldKey.BARCODE);
79
tagFieldToMp4Field.put(FieldKey.RECORD_LABEL, Mp4FieldKey.LABEL);
80
tagFieldToMp4Field.put(FieldKey.LYRICIST, Mp4FieldKey.LYRICIST);
81
tagFieldToMp4Field.put(FieldKey.CONDUCTOR, Mp4FieldKey.CONDUCTOR);
82
tagFieldToMp4Field.put(FieldKey.REMIXER, Mp4FieldKey.REMIXER);
83
tagFieldToMp4Field.put(FieldKey.MOOD, Mp4FieldKey.MOOD);
84
tagFieldToMp4Field.put(FieldKey.MEDIA, Mp4FieldKey.MEDIA);
85
tagFieldToMp4Field.put(FieldKey.URL_OFFICIAL_RELEASE_SITE, Mp4FieldKey.URL_OFFICIAL_RELEASE_SITE);
86
tagFieldToMp4Field.put(FieldKey.URL_DISCOGS_RELEASE_SITE, Mp4FieldKey.URL_DISCOGS_RELEASE_SITE);
87
tagFieldToMp4Field.put(FieldKey.URL_WIKIPEDIA_RELEASE_SITE, Mp4FieldKey.URL_WIKIPEDIA_RELEASE_SITE);
88
tagFieldToMp4Field.put(FieldKey.URL_OFFICIAL_ARTIST_SITE, Mp4FieldKey.URL_OFFICIAL_ARTIST_SITE);
89
tagFieldToMp4Field.put(FieldKey.URL_DISCOGS_ARTIST_SITE, Mp4FieldKey.URL_DISCOGS_ARTIST_SITE);
90
tagFieldToMp4Field.put(FieldKey.URL_WIKIPEDIA_ARTIST_SITE, Mp4FieldKey.URL_WIKIPEDIA_ARTIST_SITE);
91
tagFieldToMp4Field.put(FieldKey.LANGUAGE, Mp4FieldKey.LANGUAGE);
92
tagFieldToMp4Field.put(FieldKey.KEY, Mp4FieldKey.KEY);
93
tagFieldToMp4Field.put(FieldKey.URL_LYRICS_SITE, Mp4FieldKey.URL_LYRICS_SITE);
94
tagFieldToMp4Field.put(FieldKey.TRACK_TOTAL, Mp4FieldKey.TRACK);
95
tagFieldToMp4Field.put(FieldKey.DISC_TOTAL, Mp4FieldKey.DISCNUMBER);
101
* <p>If the content can be parsed to one of the known values use the genre field otherwise
102
* use the custom field.
107
@SuppressWarnings({"JavaDoc"})
108
private TagField createGenreField(String content)
112
throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg());
114
if (Mp4GenreField.isValidGenre(content))
116
return new Mp4GenreField(content);
120
return new Mp4TagTextField(GENRE_CUSTOM.getFieldName(), content);
124
protected boolean isAllowedEncoding(String enc)
126
return enc.equals(Mp4BoxHeader.CHARSET_UTF_8);
129
public String toString()
131
return "Mpeg4 " + super.toString();
136
* Maps the generic key to the mp4 key and return the list of values for this field
140
@SuppressWarnings({"JavaDoc"})
142
public List<TagField> getFields(FieldKey genericKey) throws KeyNotFoundException
144
if (genericKey == null)
146
throw new KeyNotFoundException();
148
return super.get(tagFieldToMp4Field.get(genericKey).getFieldName());
153
* Retrieve the values that exists for this mp4keyId (this is the internalid actually used)
157
* @throws org.jaudiotagger.tag.KeyNotFoundException
160
public List<TagField> get(Mp4FieldKey mp4FieldKey) throws KeyNotFoundException
162
if (mp4FieldKey == null)
164
throw new KeyNotFoundException();
166
return super.get(mp4FieldKey.getFieldName());
170
* Retrieve the first value that exists for this generic key
175
public String getFirst(FieldKey genericKey) throws KeyNotFoundException
177
if (genericKey == null)
179
throw new KeyNotFoundException();
182
if(genericKey== FieldKey.GENRE)
184
List<TagField> genres = get(GENRE.getFieldName());
185
if (genres.size() == 0)
187
genres = get(GENRE_CUSTOM.getFieldName());
191
return ((TagTextField)genres.get(0)).getContent();
199
else if(genericKey== FieldKey.TRACK)
201
List<TagField> list = get(tagFieldToMp4Field.get(genericKey));
204
Mp4TrackField trackField = (Mp4TrackField)list.get(0);
205
if(trackField.getTrackNo()>0)
207
return String.valueOf(trackField.getTrackNo());
211
else if(genericKey== FieldKey.TRACK_TOTAL)
213
List<TagField> list = get(tagFieldToMp4Field.get(genericKey));
216
Mp4TrackField trackField = (Mp4TrackField)list.get(0);
217
if(trackField.getTrackTotal()>0)
219
return String.valueOf(trackField.getTrackTotal());
223
else if(genericKey== FieldKey.DISC_NO)
225
List<TagField> list = get(tagFieldToMp4Field.get(genericKey));
228
Mp4DiscNoField discField = (Mp4DiscNoField)list.get(0);
229
if(discField.getDiscNo()>0)
231
return String.valueOf(discField.getDiscNo());
236
else if(genericKey== FieldKey.DISC_TOTAL)
238
List<TagField> list = get(tagFieldToMp4Field.get(genericKey));
241
Mp4DiscNoField discField = (Mp4DiscNoField)list.get(0);
242
if(discField.getDiscTotal()>0)
244
return String.valueOf(discField.getDiscTotal());
250
return super.getFirst(tagFieldToMp4Field.get(genericKey).getFieldName());
256
* Retrieve the first value that exists for this mp4key
260
* @throws org.jaudiotagger.tag.KeyNotFoundException
262
public String getFirst(Mp4FieldKey mp4Key) throws KeyNotFoundException
266
throw new KeyNotFoundException();
268
return super.getFirst(mp4Key.getFieldName());
271
public Mp4TagField getFirstField(FieldKey genericKey) throws KeyNotFoundException
273
if (genericKey == null)
275
throw new KeyNotFoundException();
277
return (Mp4TagField)super.getFirstField(tagFieldToMp4Field.get(genericKey).getFieldName());
280
public Mp4TagField getFirstField(Mp4FieldKey mp4Key) throws KeyNotFoundException
284
throw new KeyNotFoundException();
286
return (Mp4TagField) super.getFirstField(mp4Key.getFieldName());
290
* Delete fields with this generic key
294
public void deleteField(FieldKey genericKey) throws KeyNotFoundException
296
if (genericKey == null)
298
throw new KeyNotFoundException();
300
super.deleteField(tagFieldToMp4Field.get(genericKey).getFieldName());
304
* Delete fields with this mp4key
307
* @throws org.jaudiotagger.tag.KeyNotFoundException
309
public void deleteTagField(Mp4FieldKey mp4Key) throws KeyNotFoundException
313
throw new KeyNotFoundException();
315
super.deleteField(mp4Key.getFieldName());
319
* Create discno field
321
* @param content can be any of the following
325
* @throws org.jaudiotagger.tag.FieldDataInvalidException
327
public TagField createDiscNoField(String content) throws FieldDataInvalidException
329
return new Mp4DiscNoField(content);
333
* Create artwork field
335
* @param data raw image data
337
* @throws org.jaudiotagger.tag.FieldDataInvalidException
339
public TagField createArtworkField(byte[] data)
341
return new Mp4TagCoverField(data);
345
* Create artwork field
349
public TagField createField(Artwork artwork) throws FieldDataInvalidException
351
return new Mp4TagCoverField(artwork.getBinaryData());
355
* Create Tag Field using generic key
357
* This should use the correct subclass for the key
362
* @throws KeyNotFoundException
363
* @throws FieldDataInvalidException
366
public TagField createField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException
370
throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg());
372
if (genericKey == null)
374
throw new KeyNotFoundException();
377
if(genericKey== FieldKey.TRACK)
379
return new Mp4TrackField(Integer.parseInt(value));
381
else if(genericKey== FieldKey.TRACK_TOTAL)
383
return new Mp4TrackField(0,Integer.parseInt(value));
385
else if(genericKey== FieldKey.DISC_NO)
387
return new Mp4DiscNoField(Integer.parseInt(value));
389
else if(genericKey== FieldKey.DISC_TOTAL)
391
return new Mp4DiscNoField(0,Integer.parseInt(value));
395
return createTagField(tagFieldToMp4Field.get(genericKey), value);
400
* Set field, special handling for track and disc because they hold two fields
405
public void setField(TagField field)
412
if(field.getId().equals(TRACK.getFieldName()))
414
List<TagField> list = fields.get(field.getId());
415
if(list==null||list.size()==0)
417
super.setField(field);
421
Mp4TrackField existingTrackField = (Mp4TrackField)list.get(0);
422
Mp4TrackField newTrackField = (Mp4TrackField)field;
423
Short trackNo = existingTrackField.getTrackNo();
424
Short trackTotal = existingTrackField.getTrackTotal();
425
if(newTrackField.getTrackNo()>0 )
427
trackNo = newTrackField.getTrackNo();
429
if(newTrackField.getTrackTotal()>0 )
431
trackTotal = newTrackField.getTrackTotal();
434
Mp4TrackField mergedTrackField = new Mp4TrackField(trackNo,trackTotal);
435
super.setField(mergedTrackField);
438
else if(field.getId().equals(DISCNUMBER.getFieldName()))
440
List<TagField> list = fields.get(field.getId());
441
if(list==null||list.size()==0)
443
super.setField(field);
447
Mp4DiscNoField existingDiscNoField = (Mp4DiscNoField)list.get(0);
448
Mp4DiscNoField newDiscNoField = (Mp4DiscNoField)field;
449
Short discNo = existingDiscNoField.getDiscNo();
450
Short discTotal = existingDiscNoField.getDiscTotal();
451
if(newDiscNoField.getDiscNo()>0 )
453
discNo = newDiscNoField.getDiscNo();
455
if(newDiscNoField.getDiscTotal()>0 )
457
discTotal = newDiscNoField.getDiscTotal();
460
Mp4DiscNoField mergedDiscNoField = new Mp4DiscNoField(discNo,discTotal);
461
super.setField(mergedDiscNoField);
466
super.setField(field);
471
* Create Tag Field using mp4 key
473
* Uses the correct subclass for the key
478
* @throws KeyNotFoundException
479
* @throws FieldDataInvalidException
481
public TagField createTagField(Mp4FieldKey mp4FieldKey, String value) throws KeyNotFoundException, FieldDataInvalidException
485
throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg());
487
if (mp4FieldKey == null)
489
throw new KeyNotFoundException();
493
//This is boolean stored as 1, but calling program might setField as 'true' so we handle this
496
if(value.equals("true"))
498
value= Mp4TagByteField.TRUE_VALUE;
500
return new Mp4TagByteField(mp4FieldKey, value, mp4FieldKey.getFieldLength());
508
return new Mp4TagByteField(mp4FieldKey, value, mp4FieldKey.getFieldLength());
511
return createGenreField(value);
514
case EPISODE_GLOBAL_ID:
515
return new Mp4TagTextNumberField(mp4FieldKey.getFieldName(), value);
518
return new Mp4DiscNoField(value);
521
return new Mp4TrackField(value);
523
case MUSICBRAINZ_TRACKID:
524
case MUSICBRAINZ_ARTISTID:
525
case MUSICBRAINZ_ALBUMID:
526
case MUSICBRAINZ_ALBUMARTISTID:
527
case MUSICBRAINZ_DISCID:
530
case MUSICBRAINZ_ALBUM_STATUS:
531
case MUSICBRAINZ_ALBUM_TYPE:
533
case PART_OF_GAPLESS_ALBUM:
537
case CDDB_TRACKNUMBER:
552
case URL_OFFICIAL_RELEASE_SITE:
553
case URL_DISCOGS_RELEASE_SITE:
554
case URL_WIKIPEDIA_RELEASE_SITE:
555
case URL_OFFICIAL_ARTIST_SITE:
556
case URL_DISCOGS_ARTIST_SITE:
557
case URL_WIKIPEDIA_ARTIST_SITE:
560
case URL_LYRICS_SITE:
561
return new Mp4TagReverseDnsField(mp4FieldKey, value);
564
throw new UnsupportedOperationException(ErrorMessage.ARTWORK_CANNOT_BE_CREATED_WITH_THIS_METHOD.getMsg());
567
return new Mp4TagTextField(mp4FieldKey.getFieldName(), value);
571
public List<Artwork> getArtworkList()
573
List<TagField> coverartList = get(Mp4FieldKey.ARTWORK);
574
List<Artwork> artworkList = new ArrayList<Artwork>(coverartList.size());
576
for(TagField next:coverartList)
578
Mp4TagCoverField mp4CoverArt = (Mp4TagCoverField)next;
579
Artwork artwork = new Artwork();
580
artwork.setBinaryData(mp4CoverArt.getData());
581
artwork.setMimeType(Mp4TagCoverField.getMimeTypeForImageType(mp4CoverArt.getFieldType()));
582
artworkList.add(artwork);
2
* Entagged Audio Tag library
3
* Copyright (c) 2003-2005 Raphael Slinckx <raphael@slinckx.net>
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2.1 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
package org.jaudiotagger.tag.mp4;
21
import org.jaudiotagger.audio.generic.AbstractTag;
22
import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader;
23
import org.jaudiotagger.logging.ErrorMessage;
24
import org.jaudiotagger.tag.*;
25
import org.jaudiotagger.tag.datatype.Artwork;
26
import static org.jaudiotagger.tag.mp4.Mp4FieldKey.*;
27
import org.jaudiotagger.tag.mp4.field.*;
28
import org.jaudiotagger.tag.vorbiscomment.VorbisCommentFieldKey;
30
import java.util.ArrayList;
31
import java.util.EnumMap;
32
import java.util.List;
35
* A Logical representation of Mp4Tag, i.e the meta information stored in an Mp4 file underneath the
36
* moov.udt.meta.ilst atom.
38
public class Mp4Tag extends AbstractTag
41
private static final EnumMap<FieldKey, Mp4FieldKey> tagFieldToMp4Field = new EnumMap<FieldKey, Mp4FieldKey>(FieldKey.class);
43
//Mapping from generic key to mp4 key
46
tagFieldToMp4Field.put(FieldKey.ALBUM, Mp4FieldKey.ALBUM);
47
tagFieldToMp4Field.put(FieldKey.ALBUM_ARTIST, Mp4FieldKey.ALBUM_ARTIST);
48
tagFieldToMp4Field.put(FieldKey.ALBUM_ARTIST_SORT, Mp4FieldKey.ALBUM_ARTIST_SORT);
49
tagFieldToMp4Field.put(FieldKey.ALBUM_SORT, Mp4FieldKey.ALBUM_SORT);
50
tagFieldToMp4Field.put(FieldKey.AMAZON_ID, Mp4FieldKey.ASIN);
51
tagFieldToMp4Field.put(FieldKey.ARTIST, Mp4FieldKey.ARTIST);
52
tagFieldToMp4Field.put(FieldKey.ARTIST_SORT, Mp4FieldKey.ARTIST_SORT);
53
tagFieldToMp4Field.put(FieldKey.BARCODE, Mp4FieldKey.BARCODE);
54
tagFieldToMp4Field.put(FieldKey.BPM, Mp4FieldKey.BPM);
55
tagFieldToMp4Field.put(FieldKey.CATALOG_NO, Mp4FieldKey.CATALOGNO);
56
tagFieldToMp4Field.put(FieldKey.COMMENT, Mp4FieldKey.COMMENT);
57
tagFieldToMp4Field.put(FieldKey.COMPOSER, Mp4FieldKey.COMPOSER);
58
tagFieldToMp4Field.put(FieldKey.COMPOSER_SORT, Mp4FieldKey.COMPOSER_SORT);
59
tagFieldToMp4Field.put(FieldKey.CONDUCTOR, Mp4FieldKey.CONDUCTOR);
60
tagFieldToMp4Field.put(FieldKey.COVER_ART, Mp4FieldKey.ARTWORK);
61
tagFieldToMp4Field.put(FieldKey.CUSTOM1, Mp4FieldKey.MM_CUSTOM_1);
62
tagFieldToMp4Field.put(FieldKey.CUSTOM2, Mp4FieldKey.MM_CUSTOM_2);
63
tagFieldToMp4Field.put(FieldKey.CUSTOM3, Mp4FieldKey.MM_CUSTOM_3);
64
tagFieldToMp4Field.put(FieldKey.CUSTOM4, Mp4FieldKey.MM_CUSTOM_4);
65
tagFieldToMp4Field.put(FieldKey.CUSTOM5, Mp4FieldKey.MM_CUSTOM_5);
66
tagFieldToMp4Field.put(FieldKey.DISC_NO, Mp4FieldKey.DISCNUMBER);
67
tagFieldToMp4Field.put(FieldKey.DISC_TOTAL, Mp4FieldKey.DISCNUMBER);
68
tagFieldToMp4Field.put(FieldKey.ENCODER, Mp4FieldKey.ENCODER);
69
tagFieldToMp4Field.put(FieldKey.FBPM, Mp4FieldKey.FBPM);
70
tagFieldToMp4Field.put(FieldKey.GENRE, Mp4FieldKey.GENRE);
71
tagFieldToMp4Field.put(FieldKey.GROUPING, Mp4FieldKey.GROUPING);
72
tagFieldToMp4Field.put(FieldKey.ISRC, Mp4FieldKey.ISRC);
73
tagFieldToMp4Field.put(FieldKey.IS_COMPILATION, Mp4FieldKey.COMPILATION);
74
tagFieldToMp4Field.put(FieldKey.KEY, Mp4FieldKey.KEY);
75
tagFieldToMp4Field.put(FieldKey.LANGUAGE, Mp4FieldKey.LANGUAGE);
76
tagFieldToMp4Field.put(FieldKey.LYRICIST, Mp4FieldKey.LYRICIST);
77
tagFieldToMp4Field.put(FieldKey.LYRICS, Mp4FieldKey.LYRICS);
78
tagFieldToMp4Field.put(FieldKey.MEDIA, Mp4FieldKey.MEDIA);
79
tagFieldToMp4Field.put(FieldKey.MOOD, Mp4FieldKey.MOOD);
80
tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_ARTISTID, Mp4FieldKey.MUSICBRAINZ_ARTISTID);
81
tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_DISC_ID, Mp4FieldKey.MUSICBRAINZ_DISCID);
82
tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_RELEASEARTISTID, Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID);
83
tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_RELEASEID, Mp4FieldKey.MUSICBRAINZ_ALBUMID);
84
tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY, Mp4FieldKey.RELEASECOUNTRY);
85
tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_RELEASE_GROUP_ID, Mp4FieldKey.MUSICBRAINZ_RELEASE_GROUPID);
86
tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_RELEASE_STATUS, Mp4FieldKey.MUSICBRAINZ_ALBUM_STATUS);
87
tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_RELEASE_TYPE, Mp4FieldKey.MUSICBRAINZ_ALBUM_TYPE);
88
tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_TRACK_ID, Mp4FieldKey.MUSICBRAINZ_TRACKID);
89
tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_WORK_ID, Mp4FieldKey.MUSICBRAINZ_WORKID);
90
tagFieldToMp4Field.put(FieldKey.MUSICIP_ID, Mp4FieldKey.MUSICIP_PUID);
91
tagFieldToMp4Field.put(FieldKey.OCCASION, Mp4FieldKey.OCCASION);
92
tagFieldToMp4Field.put(FieldKey.ORIGINAL_ALBUM, Mp4FieldKey.MM_ORIGINAL_ALBUM_TITLE);
93
tagFieldToMp4Field.put(FieldKey.ORIGINAL_ARTIST, Mp4FieldKey.MM_ORIGINAL_ARTIST);
94
tagFieldToMp4Field.put(FieldKey.ORIGINAL_LYRICIST, Mp4FieldKey.MM_ORIGINAL_LYRICIST);
95
tagFieldToMp4Field.put(FieldKey.ORIGINAL_YEAR, Mp4FieldKey.MM_ORIGINAL_YEAR);
96
tagFieldToMp4Field.put(FieldKey.QUALITY, Mp4FieldKey.QUALITY);
97
tagFieldToMp4Field.put(FieldKey.RATING, Mp4FieldKey.SCORE);
98
tagFieldToMp4Field.put(FieldKey.RECORD_LABEL, Mp4FieldKey.LABEL);
99
tagFieldToMp4Field.put(FieldKey.REMIXER, Mp4FieldKey.REMIXER);
100
tagFieldToMp4Field.put(FieldKey.SCRIPT, Mp4FieldKey.SCRIPT);
101
tagFieldToMp4Field.put(FieldKey.TAGS, Mp4FieldKey.TAGS);
102
tagFieldToMp4Field.put(FieldKey.TEMPO, Mp4FieldKey.TEMPO);
103
tagFieldToMp4Field.put(FieldKey.TITLE, Mp4FieldKey.TITLE);
104
tagFieldToMp4Field.put(FieldKey.TITLE_SORT, Mp4FieldKey.TITLE_SORT);
105
tagFieldToMp4Field.put(FieldKey.TRACK, Mp4FieldKey.TRACK);
106
tagFieldToMp4Field.put(FieldKey.TRACK_TOTAL, Mp4FieldKey.TRACK);
107
tagFieldToMp4Field.put(FieldKey.URL_DISCOGS_ARTIST_SITE, Mp4FieldKey.URL_DISCOGS_ARTIST_SITE);
108
tagFieldToMp4Field.put(FieldKey.URL_DISCOGS_RELEASE_SITE, Mp4FieldKey.URL_DISCOGS_RELEASE_SITE);
109
tagFieldToMp4Field.put(FieldKey.URL_LYRICS_SITE, Mp4FieldKey.URL_LYRICS_SITE);
110
tagFieldToMp4Field.put(FieldKey.URL_OFFICIAL_ARTIST_SITE, Mp4FieldKey.URL_OFFICIAL_ARTIST_SITE);
111
tagFieldToMp4Field.put(FieldKey.URL_OFFICIAL_RELEASE_SITE, Mp4FieldKey.URL_OFFICIAL_RELEASE_SITE);
112
tagFieldToMp4Field.put(FieldKey.URL_WIKIPEDIA_ARTIST_SITE, Mp4FieldKey.URL_WIKIPEDIA_ARTIST_SITE);
113
tagFieldToMp4Field.put(FieldKey.URL_WIKIPEDIA_RELEASE_SITE, Mp4FieldKey.URL_WIKIPEDIA_RELEASE_SITE);
114
tagFieldToMp4Field.put(FieldKey.YEAR, Mp4FieldKey.DAY);
115
tagFieldToMp4Field.put(FieldKey.ENGINEER, Mp4FieldKey.ENGINEER);
116
tagFieldToMp4Field.put(FieldKey.PRODUCER, Mp4FieldKey.PRODUCER);
117
tagFieldToMp4Field.put(FieldKey.DJMIXER, Mp4FieldKey.DJMIXER);
118
tagFieldToMp4Field.put(FieldKey.MIXER, Mp4FieldKey.MIXER);
119
tagFieldToMp4Field.put(FieldKey.ARRANGER, Mp4FieldKey.ARRANGER);
125
* <p>If the content can be parsed to one of the known values use the genre field otherwise
126
* use the custom field.
131
@SuppressWarnings({"JavaDoc"})
132
private TagField createGenreField(String content)
136
throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg());
138
if (Mp4GenreField.isValidGenre(content))
140
return new Mp4GenreField(content);
144
return new Mp4TagTextField(GENRE_CUSTOM.getFieldName(), content);
148
protected boolean isAllowedEncoding(String enc)
150
return enc.equals(Mp4BoxHeader.CHARSET_UTF_8);
153
public String toString()
155
return "Mpeg4 " + super.toString();
160
* Maps the generic key to the mp4 key and return the list of values for this field
164
@SuppressWarnings({"JavaDoc"})
166
public List<TagField> getFields(FieldKey genericKey) throws KeyNotFoundException
168
if (genericKey == null)
170
throw new KeyNotFoundException();
172
return super.getFields(tagFieldToMp4Field.get(genericKey).getFieldName());
177
* Retrieve the values that exists for this mp4keyId (this is the internalid actually used)
181
* @throws org.jaudiotagger.tag.KeyNotFoundException
184
public List<TagField> get(Mp4FieldKey mp4FieldKey) throws KeyNotFoundException
186
if (mp4FieldKey == null)
188
throw new KeyNotFoundException();
190
return super.getFields(mp4FieldKey.getFieldName());
194
* Retrieve the indexed value that exists for this generic key
199
public String getValue(FieldKey genericKey, int index) throws KeyNotFoundException
201
if (genericKey == null)
203
throw new KeyNotFoundException();
206
if(genericKey== FieldKey.GENRE)
208
List<TagField> genres = getFields(GENRE.getFieldName());
209
if (genres.size() == 0)
211
genres = getFields(GENRE_CUSTOM.getFieldName());
213
if(genres.size()>index)
215
return ((TagTextField)genres.get(index)).getContent();
223
else if(genericKey== FieldKey.TRACK)
225
List<TagField> list = get(tagFieldToMp4Field.get(genericKey));
226
if(list.size()>index)
228
Mp4TrackField trackField = (Mp4TrackField)list.get(index);
229
if(trackField.getTrackNo()>0)
231
return String.valueOf(trackField.getTrackNo());
235
else if(genericKey== FieldKey.TRACK_TOTAL)
237
List<TagField> list = get(tagFieldToMp4Field.get(genericKey));
238
if(list.size()>index)
240
Mp4TrackField trackField = (Mp4TrackField)list.get(index);
241
if(trackField.getTrackTotal()>0)
243
return String.valueOf(trackField.getTrackTotal());
247
else if(genericKey== FieldKey.DISC_NO)
249
List<TagField> list = get(tagFieldToMp4Field.get(genericKey));
250
if(list.size()>index)
252
Mp4DiscNoField discField = (Mp4DiscNoField)list.get(index);
253
if(discField.getDiscNo()>0)
255
return String.valueOf(discField.getDiscNo());
260
else if(genericKey== FieldKey.DISC_TOTAL)
262
List<TagField> list = get(tagFieldToMp4Field.get(genericKey));
263
if(list.size()>index)
265
Mp4DiscNoField discField = (Mp4DiscNoField)list.get(index);
266
if(discField.getDiscTotal()>0)
268
return String.valueOf(discField.getDiscTotal());
274
return super.getItem(tagFieldToMp4Field.get(genericKey).getFieldName(), index);
280
* Retrieve the first value that exists for this mp4key
284
* @throws org.jaudiotagger.tag.KeyNotFoundException
286
public String getFirst(Mp4FieldKey mp4Key) throws KeyNotFoundException
290
throw new KeyNotFoundException();
292
return super.getFirst(mp4Key.getFieldName());
295
public Mp4TagField getFirstField(FieldKey genericKey) throws KeyNotFoundException
297
if (genericKey == null)
299
throw new KeyNotFoundException();
301
return (Mp4TagField)super.getFirstField(tagFieldToMp4Field.get(genericKey).getFieldName());
304
public Mp4TagField getFirstField(Mp4FieldKey mp4Key) throws KeyNotFoundException
308
throw new KeyNotFoundException();
310
return (Mp4TagField) super.getFirstField(mp4Key.getFieldName());
314
* Delete fields with this generic key
318
public void deleteField(FieldKey genericKey) throws KeyNotFoundException
320
if (genericKey == null)
322
throw new KeyNotFoundException();
324
super.deleteField(tagFieldToMp4Field.get(genericKey).getFieldName());
328
* Delete fields with this mp4key
331
* @throws org.jaudiotagger.tag.KeyNotFoundException
333
public void deleteField(Mp4FieldKey mp4Key) throws KeyNotFoundException
337
throw new KeyNotFoundException();
339
super.deleteField(mp4Key.getFieldName());
343
* Create artwork field
345
* @param data raw image data
347
* @throws org.jaudiotagger.tag.FieldDataInvalidException
349
public TagField createArtworkField(byte[] data)
351
return new Mp4TagCoverField(data);
355
* Create artwork field
359
public TagField createField(Artwork artwork) throws FieldDataInvalidException
361
return new Mp4TagCoverField(artwork.getBinaryData());
365
* Create Tag Field using generic key
367
* This should use the correct subclass for the key
372
* @throws KeyNotFoundException
373
* @throws FieldDataInvalidException
376
public TagField createField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException
380
throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg());
382
if (genericKey == null)
384
throw new KeyNotFoundException();
387
//Special handling for these number fields
389
(genericKey== FieldKey.TRACK)||
390
(genericKey== FieldKey.TRACK_TOTAL)||
391
(genericKey== FieldKey.DISC_NO)||
392
(genericKey== FieldKey.DISC_TOTAL)
397
int number = Integer.parseInt(value);
398
if(genericKey== FieldKey.TRACK)
400
return new Mp4TrackField(number);
402
else if(genericKey== FieldKey.TRACK_TOTAL)
404
return new Mp4TrackField(0,number);
406
else if(genericKey== FieldKey.DISC_NO)
408
return new Mp4DiscNoField(number);
410
else if(genericKey== FieldKey.DISC_TOTAL)
412
return new Mp4DiscNoField(0,number);
415
catch(NumberFormatException nfe)
417
//If not number we want to convert to an expected exception (which is not a RuntimeException)
418
//so can be handled properly by calling program
419
throw new FieldDataInvalidException("Value "+value + " is not a number as required",nfe);
423
//Default for all other fields
424
return createField(tagFieldToMp4Field.get(genericKey), value);
429
* Set field, special handling for track and disc because they hold two fields
434
public void setField(TagField field)
441
if(field.getId().equals(TRACK.getFieldName()))
443
List<TagField> list = fields.get(field.getId());
444
if(list==null||list.size()==0)
446
super.setField(field);
450
Mp4TrackField existingTrackField = (Mp4TrackField)list.get(0);
451
Mp4TrackField newTrackField = (Mp4TrackField)field;
452
Short trackNo = existingTrackField.getTrackNo();
453
Short trackTotal = existingTrackField.getTrackTotal();
454
if(newTrackField.getTrackNo()>0 )
456
trackNo = newTrackField.getTrackNo();
458
if(newTrackField.getTrackTotal()>0 )
460
trackTotal = newTrackField.getTrackTotal();
463
Mp4TrackField mergedTrackField = new Mp4TrackField(trackNo,trackTotal);
464
super.setField(mergedTrackField);
467
else if(field.getId().equals(DISCNUMBER.getFieldName()))
469
List<TagField> list = fields.get(field.getId());
470
if(list==null||list.size()==0)
472
super.setField(field);
476
Mp4DiscNoField existingDiscNoField = (Mp4DiscNoField)list.get(0);
477
Mp4DiscNoField newDiscNoField = (Mp4DiscNoField)field;
478
Short discNo = existingDiscNoField.getDiscNo();
479
Short discTotal = existingDiscNoField.getDiscTotal();
480
if(newDiscNoField.getDiscNo()>0 )
482
discNo = newDiscNoField.getDiscNo();
484
if(newDiscNoField.getDiscTotal()>0 )
486
discTotal = newDiscNoField.getDiscTotal();
489
Mp4DiscNoField mergedDiscNoField = new Mp4DiscNoField(discNo,discTotal);
490
super.setField(mergedDiscNoField);
495
super.setField(field);
500
* Create Tag Field using mp4 key
502
* Uses the correct subclass for the key
507
* @throws KeyNotFoundException
508
* @throws FieldDataInvalidException
510
public TagField createField(Mp4FieldKey mp4FieldKey, String value) throws KeyNotFoundException, FieldDataInvalidException
514
throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg());
516
if (mp4FieldKey == null)
518
throw new KeyNotFoundException();
521
//This is boolean stored as 1, but calling program might setField as 'true' so we handle this
523
if(mp4FieldKey==Mp4FieldKey.COMPILATION)
525
if(value.equals("true"))
527
value= Mp4TagByteField.TRUE_VALUE;
529
return new Mp4TagByteField(mp4FieldKey, value, mp4FieldKey.getFieldLength());
531
else if(mp4FieldKey==Mp4FieldKey.GENRE)
533
return createGenreField(value);
535
else if(mp4FieldKey.getSubClassFieldType()==Mp4TagFieldSubType.DISC_NO)
537
return new Mp4DiscNoField(value);
539
else if(mp4FieldKey.getSubClassFieldType()==Mp4TagFieldSubType.TRACK_NO)
541
return new Mp4TrackField(value);
543
else if(mp4FieldKey.getSubClassFieldType()==Mp4TagFieldSubType.BYTE)
545
return new Mp4TagByteField(mp4FieldKey, value, mp4FieldKey.getFieldLength());
547
else if(mp4FieldKey.getSubClassFieldType()==Mp4TagFieldSubType.NUMBER)
549
return new Mp4TagTextNumberField(mp4FieldKey.getFieldName(), value);
551
else if(mp4FieldKey.getSubClassFieldType()==Mp4TagFieldSubType.REVERSE_DNS)
553
return new Mp4TagReverseDnsField(mp4FieldKey, value);
555
else if(mp4FieldKey.getSubClassFieldType()==Mp4TagFieldSubType.ARTWORK)
557
throw new UnsupportedOperationException(ErrorMessage.ARTWORK_CANNOT_BE_CREATED_WITH_THIS_METHOD.getMsg());
559
else if(mp4FieldKey.getSubClassFieldType()==Mp4TagFieldSubType.TEXT)
561
return new Mp4TagTextField(mp4FieldKey.getFieldName(), value);
563
else if(mp4FieldKey.getSubClassFieldType()==Mp4TagFieldSubType.UNKNOWN)
565
throw new UnsupportedOperationException(ErrorMessage.DO_NOT_KNOW_HOW_TO_CREATE_THIS_ATOM_TYPE.getMsg(mp4FieldKey.getFieldName()));
569
throw new UnsupportedOperationException(ErrorMessage.DO_NOT_KNOW_HOW_TO_CREATE_THIS_ATOM_TYPE.getMsg(mp4FieldKey.getFieldName()));
573
public List<Artwork> getArtworkList()
575
List<TagField> coverartList = get(Mp4FieldKey.ARTWORK);
576
List<Artwork> artworkList = new ArrayList<Artwork>(coverartList.size());
578
for(TagField next:coverartList)
580
Mp4TagCoverField mp4CoverArt = (Mp4TagCoverField)next;
581
Artwork artwork = new Artwork();
582
artwork.setBinaryData(mp4CoverArt.getData());
583
artwork.setMimeType(Mp4TagCoverField.getMimeTypeForImageType(mp4CoverArt.getFieldType()));
584
artworkList.add(artwork);