From b39cc52ea416ee8e4fb29a852867735290eda77e Mon Sep 17 00:00:00 2001 From: Adrian Ulrich Date: Sun, 12 Feb 2017 17:49:54 +0100 Subject: [PATCH] sync with bastp and enable MP4 tagreader --- .../medialibrary/MediaMetadataExtractor.java | 1 + src/ch/blinkenlights/bastp/Mp4File.java | 71 ++++++++++++++++--- 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/ch/blinkenlights/android/medialibrary/MediaMetadataExtractor.java b/src/ch/blinkenlights/android/medialibrary/MediaMetadataExtractor.java index bbd8cfc9..c394fed7 100644 --- a/src/ch/blinkenlights/android/medialibrary/MediaMetadataExtractor.java +++ b/src/ch/blinkenlights/android/medialibrary/MediaMetadataExtractor.java @@ -326,6 +326,7 @@ public class MediaMetadataExtractor extends HashMap> { break; case "MP3/ID3v2": case "MP3/Lame": + case "MP4": // ^-- these tagreaders are not fully stable, but can be enabled on demand if(mForceBastp) { populateSelf(bastpTags); diff --git a/src/ch/blinkenlights/bastp/Mp4File.java b/src/ch/blinkenlights/bastp/Mp4File.java index 189c14b0..212633eb 100644 --- a/src/ch/blinkenlights/bastp/Mp4File.java +++ b/src/ch/blinkenlights/bastp/Mp4File.java @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2016 Ian Harmon + * Copyright (C) 2017 Google Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ch.blinkenlights.bastp; import java.io.IOException; @@ -30,8 +48,35 @@ public class Mp4File extends Common { // only these tags are returned. others may be parsed, but discarded. final static List ALLOWED_TAGS = Arrays.asList( "replaygain_track_gain", - "replaygain_album_gain" + "replaygain_album_gain", + "title", + "album", + "artist", + "genre", + "year", + "tracknumber", + "discnumber" ); + + // mapping between atom <-> vorbis tags + final static HashMap ATOM_TAGS; + static { + ATOM_TAGS = new HashMap(); + ATOM_TAGS.put("�nam", "title"); + ATOM_TAGS.put("�alb", "album"); + ATOM_TAGS.put("�ART", "artist"); + ATOM_TAGS.put("�gen", "genre"); + ATOM_TAGS.put("�day", "year"); + ATOM_TAGS.put("trkn", "tracknumber"); + ATOM_TAGS.put("disk", "discnumber"); + } + + // These tags are 32bit integers, not strings. + final static List BINARY_TAGS = Arrays.asList( + "tracknumber", + "discnumber" + ); + // maximum size for tag names or values final static int MAX_BUFFER_SIZE = 512; // only used when developing @@ -91,16 +136,18 @@ public class Mp4File extends Common { boolean approachingTagAtom = false; boolean onMetaAtom = false; boolean onTagAtom = false; + String fourAtom = null; // compare everything in the current path hierarchy and the new atom as well // this is a bit repetitive as-is, but shouldn't be noticeable for (int i = 0; i <= path.size(); i++) { String thisAtomName = (i < path.size()) ? path.get(i).name : atomName; - if ((i == 0 && thisAtomName.equals("moov")) || - (i == 1 && thisAtomName.equals("udta")) || - (i == 2 && thisAtomName.equals("meta")) || - (i == 3 && thisAtomName.equals("ilst")) || - (i == 4 && thisAtomName.equals("----")) || - (i == 5 && (thisAtomName.equals("name") || thisAtomName.equals("data"))) + if ((i == 0 && thisAtomName.equals("moov")) || + (i == 1 && thisAtomName.equals("udta")) || + (i == 2 && thisAtomName.equals("meta")) || + (i == 3 && thisAtomName.equals("ilst")) || + (i == 4 && thisAtomName.equals("----")) || + (i == 4 && ATOM_TAGS.containsKey(thisAtomName)) || + (i == 5 && (thisAtomName.equals("name") || thisAtomName.equals("data"))) ) { approachingTagAtom = true; // if we're at the end of the current hierarchy, mark if it's the [meta] or a tag atom. @@ -108,6 +155,10 @@ public class Mp4File extends Common { onMetaAtom = thisAtomName.equals("meta"); onTagAtom = (thisAtomName.equals("name") || thisAtomName.equals("data")); } + // depth is 4 and this is a known atom: rembemer this! + if (i == 4 && ATOM_TAGS.containsKey(thisAtomName)) { + fourAtom = ATOM_TAGS.get(thisAtomName); + } } // quit as soon as we know we're not on the road to a tag atom else { @@ -141,10 +192,14 @@ public class Mp4File extends Common { // skip flags/null bytes s.skipBytes(8); + // use the 'fourAtom' value if we did not have a tag name + tagName = (tagName == null ? fourAtom : tagName); // read the tag - String tagValue = new String(readIntoBuffer(s, atomSize-(ATOM_HEADER_SIZE+8))); + byte[] tagBuffer = readIntoBuffer(s, atomSize-(ATOM_HEADER_SIZE+8)); + if (ALLOWED_TAGS.contains(tagName)) { + String tagValue = (BINARY_TAGS.contains(tagName) ? String.format("%d", b2be32(tagBuffer, 0)) : new String(tagBuffer, "UTF-8")); if (PRINT_DEBUG) { System.out.println(String.format("parsed tag '%s': '%s'\n", tagName, tagValue)); }