From 1e02c6b88b6eaa04bec3670ee6e557274883d485 Mon Sep 17 00:00:00 2001 From: Knut Forkalsrud Date: Sun, 8 Nov 2009 11:26:09 -0800 Subject: [PATCH] Initial work on detecting video and audio files. --- .../forkalsrud/album/exif/OggIdentifier.java | 94 ++++++++++++++++++ .../album/exif/OggIdentifierTest.java | 30 ++++++ src/org/forkalsrud/album/exif/musicheader.ogg | Bin 0 -> 1024 bytes src/org/forkalsrud/album/exif/videoheader.ogg | Bin 0 -> 1024 bytes 4 files changed, 124 insertions(+) create mode 100644 src/org/forkalsrud/album/exif/OggIdentifier.java create mode 100644 src/org/forkalsrud/album/exif/OggIdentifierTest.java create mode 100644 src/org/forkalsrud/album/exif/musicheader.ogg create mode 100644 src/org/forkalsrud/album/exif/videoheader.ogg diff --git a/src/org/forkalsrud/album/exif/OggIdentifier.java b/src/org/forkalsrud/album/exif/OggIdentifier.java new file mode 100644 index 0000000..8e4e63a --- /dev/null +++ b/src/org/forkalsrud/album/exif/OggIdentifier.java @@ -0,0 +1,94 @@ +/** + * + */ +package org.forkalsrud.album.exif; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + + +/** + * @author knut + * + */ +public class OggIdentifier { + + static Codec getIdentifier(File f) throws IOException { + + return getIdentifier(new FileInputStream(f)); + } + + static Codec getIdentifier(InputStream is) throws IOException { + + byte[] header = new byte[1024]; + int len = is.read(header); + + if (len < 100) { + return null; + } + + // Make sure the OggS magic marker is there + for (int i = 0; i < MAGIC.length; i++) { + if (header[i] != MAGIC[i]) { + return null; + } + } + + for (Codec c : CODECS) { + if (c.matches(header, 28)) { + return c; + } + } + return null; + } + + static byte[] MAGIC = "OggS".getBytes(); + + static class Codec { + byte[] magic; + String mimeType; + + public String getMimeType() { + return mimeType; + } + + public Codec(String mimeType, char... magic) { + this.magic = new byte[magic.length]; + for (int i = 0; i < magic.length; i++) { + this.magic[i] = (byte)magic[i]; + } + this.mimeType = mimeType; + } + + public boolean matches(byte[] src, int offset) { + + for (int i = 0; i < magic.length; i++) { + if (src[offset + i] != magic[i]) { + return false; + } + } + return true; + } + } + + + static Codec[] CODECS = new Codec[] { + new Codec("video/ogg; codecs=dirac", 'B', 'B', 'C', 'D', '\0'), + new Codec("video/ogg; codecs=flac", (char)177, 'F', 'L', 'A', 'C'), + new Codec("video/ogg; codecs=theora", (char)0x80, 't', 'h', 'e', 'o', 'r', 'a'), + new Codec("audio/ogg; codecs=vorbis", (char)0x01, 'v', 'o', 'r', 'b', 'i', 's'), + new Codec("application/ogg; codecs=celt", 'C', 'E', 'L', 'T', ' ', ' ', ' ', ' '), + new Codec("application/ogg; codecs=cmml", 'C', 'M', 'M', 'L', '\0', '\0', '\0', '\0'), + new Codec("application/ogg; codecs=jng", (char)213, 'J', 'N', 'G', '\r', '\n', ' ', '\n'), + new Codec("application/ogg; codecs=kate", (char)0x80, 'k', 'a', 't', 'e', '\0', '\0', '\0'), + new Codec("application/ogg; codecs=midi", 'O', 'g', 'g', 'm', 'i', 'd', 'i', '\0'), + new Codec("application/ogg; codecs=mng", (char)212, 'M', 'N', 'G', '\r', '\n', ' ', '\n'), + new Codec("audio/ogg; codecs=pcm", 'P', 'C', 'M', ' ', ' ', ' ', ' ', ' '), + new Codec("application/ogg; codecs=png", (char)212, 'P', 'N', 'G', '\r', '\n', ' ', '\n'), + new Codec("audio/ogg; codecs=speex", 'S', 'p', 'e', 'e', 'x', ' ', ' ', ' '), + new Codec("video/ogg; codecs=yuv4mpeg", 'Y', 'U', 'V', '4', 'M', 'P', 'E', 'G'), + }; + +} diff --git a/src/org/forkalsrud/album/exif/OggIdentifierTest.java b/src/org/forkalsrud/album/exif/OggIdentifierTest.java new file mode 100644 index 0000000..bcda11f --- /dev/null +++ b/src/org/forkalsrud/album/exif/OggIdentifierTest.java @@ -0,0 +1,30 @@ +package org.forkalsrud.album.exif; + +import org.forkalsrud.album.exif.OggIdentifier.Codec; + +import junit.framework.TestCase; + +public class OggIdentifierTest extends TestCase { + + public void testVideoIdentifier() throws Exception { + + Codec codec = OggIdentifier.getIdentifier(getClass().getResourceAsStream("videoheader.ogg")); + assertNotNull(codec); + assertEquals("video/ogg; codecs=theora", codec.getMimeType()); + } + + + public void testAudioIdentifier() throws Exception { + + Codec codec = OggIdentifier.getIdentifier(getClass().getResourceAsStream("musicheader.ogg")); + assertNotNull(codec); + assertEquals("audio/ogg; codecs=vorbis", codec.getMimeType()); + } + + + public void testInvalidIdentifier() throws Exception { + + Codec codec = OggIdentifier.getIdentifier(getClass().getResourceAsStream("OggIdentifierTest.class")); + assertNull(codec); + } +} diff --git a/src/org/forkalsrud/album/exif/musicheader.ogg b/src/org/forkalsrud/album/exif/musicheader.ogg new file mode 100644 index 0000000000000000000000000000000000000000..19eda10886b7c8c15813e5ac8cd301d7cbd29c96 GIT binary patch literal 1024 zcmYjOZ)h837=P0-@7A@+IY+4_OYgwKq6V762`OA4*LIRN+vJ+nm~w{_Rl7@0Fz4EN%5!6?)d9iuq_j*pLz!5@Z``y0b`9r>T> zNCN^QgSQz3X@mMSz zN<`y#j5-J78kx9u<0?JIQ1&-;);GtlF=G@H53z=`r!&1ok4zcBYXE$!Wmw7f5F4)a z4)JKPi}4V@zOwCSpFCCQPUY|icUSBDnaeA?hWlNXD=QJ=`3n#5(Z$Qrj_{`sU!N|0 zV&!fveD3)0FLe0gxr_N*znOnB2i}Q%{~iEu8^AuEGSTQS99Gs^+@=d9QYI&|42@27 zm6aTtki=+p8cL*Q;jt331C1pO=S}p!z#Y0!g5MDLTAZYNn+3(pV>Eg*DN$%Yk2$rz z)JXv=BbO4G6D9c5gGPxI=4|79-OU7VaYvMvVXGq2&)18xkL@n2 zmc)iA3&|r2T@B?5d(9+9@B2eJ64~LfvixJP>Ocs-PHy>i@m07%Dj80H7Q68jA#{zK zNh6ICype7T?4hgOgta0<@K{+9;DJ89RFpGNZ%HhWat4~5=yG7*CO4B5E9^N!5}v(#SHKC)Fl2I+fngypFBeMcJPdRXpX%uF1i?3!Ry?4v2o( zUH;QI?zZg-No@E_hDnnM!7tjfjbPq^egR{7@eyluYL?J^VXu|MO3E}V6_Fk8z@;|X zgYUEzD7ldS6joOI*x!q)z}4(qJ#5Zi!4sZ!vEfgX=%op3cC8WYE>|wl*6dePT+MzT zquqApG4!l*Z|PGBfpf%K4{I!`kH)R*+XAc?D@*=#LEeR%}RfYR{PVqx1K%G=SOnOE0E+21+*H8XA<$TmKDU`t>$G9b3t^Do0^uBiPV DqA?37#J8q zsu-bk!vTL3Q=V%$R)OS&7|cI2$}yJZ7bRsDg9O+bc7rGeh6VT8!SoJBuueDt*$*;0 z<>#ceJVyWFz`haU6lDemhKS693_bs%bcLMEq!6$J6+9J;3=Av`4U7yFj1`O&3_<2K zL3HdptMPs3*=&ieD?Pmgisw8t>&CSitm6es1 zmH99j9BP7qMn^DkP-NJ!kg=)R_`-n$4-FSDK3wqNB4bnYl;DPkf{B++OPL=kCIv5X zyH;|s$+(17tX=f52+Py5^670Mtw+D9v$>TS3Mw{zGcz+YR193A2BI4mx0#ulnHhZn z@dyJ$Mn*=*#zRbv5ULqUv491eSy&hw4}mBaMhL~m1m>}EKq(I9M}M|o;58QB=hXY) zRp;KFX-aq9r61TAbt=U@xN)*JYo%0Lc+wjumM00{`j&Y=H@J1R?O3R0TI>{Tb3JYFTQ0nx#jn&B??E2Lw>JX5}xcRc`DQKtz7Ay2@g`U z4Y!|@KUxvTS$X@PaNlMAjL$2Tk{L_0jWt)8-shP%VexN=y<8PHp2bdFP_ALS_}ot4 zZM$!1H%)b8i5IFry6BoE`yD0Ov+KVLZ0T)FI(0#MxoVL{_4c`*Rja&OD(9$sUCR-d zKFYD~z$J$#AD!>+djEe@a%GN4^UViQrE`yqX&bg5NOf0sTa=k{>;J2uJ8$}Q?D!`) zWv1M+5&IzdwS-%nN!RenDUejlwf?v=<}9WEjc;o9wcI&WR;#-qY=^M7+ODLA&+6r? zmN*Dye|;CXT-bXn+w;f`omtYYQ`_c0>Q~-x5$fs1^y1v6q`>uuP91&n7M(giN&oHc3A3~8&bTFBnE%%(n%7lB@Q}`$yOrOTe74VZ bQi{1zqH9#Wob^nN$MaoXE5*X}r`Q1imIadZ literal 0 HcmV?d00001