Add Ogg Vorbis identifier.
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Thu, 14 Mar 2013 21:08:00 +0000 (22:08 +0100)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Thu, 14 Mar 2013 21:08:00 +0000 (22:08 +0100)
src/main/java/net/pterodactylus/sonitus/io/OggVorbisIdentifier.java [new file with mode: 0644]

diff --git a/src/main/java/net/pterodactylus/sonitus/io/OggVorbisIdentifier.java b/src/main/java/net/pterodactylus/sonitus/io/OggVorbisIdentifier.java
new file mode 100644 (file)
index 0000000..64ad2dd
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Sonitus - OggVorbisIdentifier.java - Copyright © 2013 David Roden
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sonitus.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import net.pterodactylus.sonitus.data.Format;
+
+import com.jcraft.jogg.Packet;
+import com.jcraft.jogg.Page;
+import com.jcraft.jogg.StreamState;
+import com.jcraft.jogg.SyncState;
+import com.jcraft.jorbis.Comment;
+import com.jcraft.jorbis.Info;
+
+/**
+ * Identifies Ogg Vorbis files.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class OggVorbisIdentifier {
+
+       /** The default size of the read buffer. */
+       private static final int BUFFER_SIZE = 4096;
+
+       /** Suppress default constructor. */
+       private OggVorbisIdentifier() {
+               /* nothing here. */
+       }
+
+       /**
+        * Tries to parse the given stream as Ogg Vorbis file and returns a {@link
+        * Format} describing the stream.
+        *
+        * @param inputStream
+        * @return
+        * @throws IOException
+        */
+       public static Format identify(InputStream inputStream) throws IOException {
+
+               /* stuff needed to decode Ogg. */
+               Packet packet = new Packet();
+               Page page = new Page();
+               StreamState streamState = new StreamState();
+               SyncState syncState = new SyncState();
+
+               /* stuff needed to decode Vorbis. */
+               Comment comment = new Comment();
+               Info info = new Info();
+
+               /* initialize jorbis. */
+               syncState.init();
+               int bufferSize = BUFFER_SIZE;
+               int index = syncState.buffer(bufferSize);
+               byte[] buffer = syncState.data;
+
+               boolean streamStateInitialized = false;
+               int packetsRead = 0;
+
+               /* read until we have read the three packets required to decode the header. */
+               while (packetsRead < 3) {
+                       int read = inputStream.read(buffer, index, bufferSize);
+                       syncState.wrote(read);
+                       switch (syncState.pageout(page)) {
+                               case -1:
+                                       throw new IOException("Hole in Ogg data!");
+                               case 1:
+                                       if (!streamStateInitialized) {
+                                               /* init stream state. */
+                                               streamState.init(page.serialno());
+                                               streamState.reset();
+                                               info.init();
+                                               comment.init();
+                                               streamStateInitialized = true;
+                                       }
+                                       if (streamState.pagein(page) == -1) {
+                                               throw new IOException("Error parsing Ogg data!");
+                                       }
+                                       switch (streamState.packetout(packet)) {
+                                               case -1:
+                                                       throw new IOException("Error parsing Ogg data!");
+                                               case 1:
+                                                       info.synthesis_headerin(comment, packet);
+                                                       packetsRead++;
+                                               default:
+                                                       /* continue. */
+                                       }
+
+                               default:
+                                       /* continue. */
+                       }
+                       index = syncState.buffer(bufferSize);
+                       buffer = syncState.data;
+               }
+
+               return new Format(info.channels, info.rate, "Vorbis");
+       }
+
+}