diff options
Diffstat (limited to 'app/src/main/java/github/daneren2005/dsub/util/tags/OggFile.java')
-rw-r--r-- | app/src/main/java/github/daneren2005/dsub/util/tags/OggFile.java | 97 |
1 files changed, 75 insertions, 22 deletions
diff --git a/app/src/main/java/github/daneren2005/dsub/util/tags/OggFile.java b/app/src/main/java/github/daneren2005/dsub/util/tags/OggFile.java index d0b31671..0383c68a 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/tags/OggFile.java +++ b/app/src/main/java/github/daneren2005/dsub/util/tags/OggFile.java @@ -23,10 +23,11 @@ import java.io.RandomAccessFile; import java.util.HashMap; -public class OggFile extends Common { +public class OggFile extends Common implements PageInfo.PageParser { - private static final int OGG_PAGE_SIZE = 27; // Static size of an OGG Page - private static final int OGG_TYPE_COMMENT = 3; // ID of 'VorbisComment's + private static final int OGG_PAGE_SIZE = 27; // Static size of an OGG Page + private static final int OGG_TYPE_IDENTIFICATION = 1; // Identification header + private static final int OGG_TYPE_COMMENT = 3; // ID of 'VorbisComment's public OggFile() { } @@ -34,24 +35,46 @@ public class OggFile extends Common { public HashMap getTags(RandomAccessFile s) throws IOException { long offset = 0; int retry = 64; + boolean need_tags = true; + boolean need_id = true; + HashMap tags = new HashMap(); + HashMap identification = new HashMap(); for( ; retry > 0 ; retry-- ) { - long res[] = parse_ogg_page(s, offset); - if(res[2] == OGG_TYPE_COMMENT) { - tags = parse_ogg_vorbis_comment(s, offset+res[0], res[1]); + PageInfo pi = parse_stream_page(s, offset); + if(pi.type == OGG_TYPE_IDENTIFICATION) { + identification = parse_ogg_vorbis_identification(s, offset+pi.header_len, pi.payload_len); + need_id = false; + } else if(pi.type == OGG_TYPE_COMMENT) { + tags = parse_ogg_vorbis_comment(s, offset+pi.header_len, pi.payload_len); + need_tags = false; + } + offset += pi.header_len + pi.payload_len; + if (need_tags == false && need_id == false) { break; } - offset += res[0] + res[1]; } + + // Calculate duration in seconds + // Note that this calculation is WRONG: We would have to get the last + // packet to calculate the real length - but this is goot enough. + if (identification.containsKey("bitrate_nominal")) { + int br_nom = (Integer)identification.get("bitrate_nominal") / 8; + long file_length = s.length(); + if (file_length > 0 && br_nom > 0) { + tags.put("duration", (int)(file_length/br_nom)); + } + } + return tags; } - /* Parses the ogg page at offset 'offset' and returns - ** [header_size, payload_size, type] - */ - private long[] parse_ogg_page(RandomAccessFile s, long offset) throws IOException { + /** + * Parses the ogg page at offset 'offset' + */ + public PageInfo parse_stream_page(RandomAccessFile s, long offset) throws IOException { long[] result = new long[3]; // [header_size, payload_size] byte[] p_header = new byte[OGG_PAGE_SIZE]; // buffer for the page header byte[] scratch; @@ -78,18 +101,18 @@ public class OggFile extends Common { psize += b2u(scratch[i]); } } - - // populate result array - result[0] = (s.getFilePointer() - offset); - result[1] = psize; - result[2] = -1; - + + PageInfo pi = new PageInfo(); + pi.header_len = (s.getFilePointer() - offset); + pi.payload_len = psize; + pi.type = -1; + /* next byte is most likely the type -> pre-read */ if(psize >= 1 && s.read(p_header, 0, 1) == 1) { - result[2] = b2u(p_header[0]); + pi.type = b2u(p_header[0]); } - - return result; + + return pi; } /* In 'vorbiscomment' field is prefixed with \3vorbis in OGG files @@ -108,7 +131,37 @@ public class OggFile extends Common { if( (new String(pfx, 0, pfx_len)).equals("\3vorbis") == false ) xdie("Damaged packet found!"); - return parse_vorbis_comment(s, offset+pfx_len, pl_len-pfx_len); + return parse_vorbis_comment(s, this, offset+pfx_len, pl_len-pfx_len); } - + + /* + ** Returns a hashma with parsed vorbis identification header data + **/ + private HashMap parse_ogg_vorbis_identification(RandomAccessFile s, long offset, long pl_len) throws IOException { + /* Structure: + * 7 bytes of \1vorbis + * 4 bytes version + * 1 byte channels + * 4 bytes sampling rate + * 4 bytes bitrate max + * 4 bytes bitrate nominal + * 4 bytes bitrate min + **/ + HashMap id_hash = new HashMap(); + byte[] buff = new byte[28]; + + if(pl_len >= buff.length) { + s.seek(offset); + s.read(buff); + id_hash.put("version" , b2le32(buff, 7)); + id_hash.put("channels" , b2u(buff[11])); + id_hash.put("sampling_rate" , b2le32(buff, 12)); + id_hash.put("bitrate_minimal" , b2le32(buff, 16)); + id_hash.put("bitrate_nominal" , b2le32(buff, 20)); + id_hash.put("bitrate_maximal" , b2le32(buff, 24)); + } + + return id_hash; + } + }; |