import java.io.*; /***************************************************************************

DumpQuicktime: Dumps a Quicktime movie file to stdout.

Development Environment

  • Compiled under JDK 1.3.1
  • ***************************************************************************/ public class DumpQuicktime { /** Holds an array of atoms and their descriptions. Each element in the array represents one atom. The first 4 characters are the atom ID. The remainder of the string is the description. *//* ==================================================================== */ public final static String[] masAtomsAndDescriptions = { /*=================================================================*/ "???? -- Unknown Atom", "clip -- Clipping", "crgn -- Clipping Region", "dinf -- Data Information", "dref -- Data Reference", "edts -- Edit", "elst -- Edit List", "esds -- ESDS Atom (is 4 bytes longer than the length says it should be)", "free -- Unused space in the movie data file", "hdlr -- Handler Reference", "kmat -- Compressed Matte", "matt -- Track Matte", "mdat -- Movie Data", "mdhd -- Media Header", "mdia -- Media", "minf -- Media Information", "moov -- Movie", "mvhd -- Movie Header", "skip -- Unused space in the movie data file", "smhd -- Sound Media Information Header", "stbl -- Sample Table", "stco -- Chunk Offset", "stsc -- Sample-to-Chunk", "stsd -- Sample Description", "stsh -- Shadow Sync", "stss -- Sync Sample", "stsz -- Sample Size", "stts -- Time-to-Sample", "tkhd -- Track Header", "trak -- Track", "udta -- User-defined Data", "vmhd -- Video Media Information Header", "wide -- Wide File [Data & Resources]", /*=================================================================*/ }; /** Holds the quicktime file in memory. *//* ======================================== */ byte[] mabBuffer; /*=========================================================================* Construction/Initialization *=========================================================================*/ /* D U M P Q U I C K T I M E */ /** */ public DumpQuicktime (String sFilename) { File f; int iSize; FileInputStream fis; try { f = new File (sFilename); iSize = (int) f.length (); mabBuffer = new byte[iSize]; fis = new FileInputStream (f); fis.read (mabBuffer); fis.close (); } catch (Throwable t) { System.out.println ("(" + sFilename + ") unable to load the file"); } } /* M A I N */ /** The mainline routine. If this is run without commandline parameters * then a chart of the Quicktime atoms is printed out along with a * description of syntax to use to run the program. * */ public static void main (String[] asArgsIn) { int i; DumpQuicktime x; if (asArgsIn.length >= 1) { x = new DumpQuicktime (asArgsIn[0]); x.dumpMovie (asArgsIn[0]); } System.out.println ("\n*-------------Quicktime Atom Chart-------------*"); for (i = 1; i < masAtomsAndDescriptions.length; i++) { System.out.println (" " + masAtomsAndDescriptions[i]); } System.out.println ("*----------------------------------------------*"); System.out.println ("\n To dump a quicktime movie, provide the " + "filename as a parameter:\n"); System.out.println (" Usage: java DumpQuicktime moviename.mov\n"); System.out.println ("*----------------------------------------------*"); } /*=========================================================================* The following methods are in alphabetical order *=========================================================================*/ /* D U M P A T O M */ /** Dumps a single container atom or leaf atom. If the atom is a * container, this method recurses. If the atom is a leaf, the output * is written to standard out. * */ private int dumpAtom (DataInputStream disIn, int iAtomLengthIn, String sMarginIn) { int i; int iSize, iSize2; int iSampleSize; int iLength = 0; int iTotalLength = 0; int iAtomID; String s, s1; String sAtomID; byte[] abAtomID = new byte[4]; byte[] ab4 = new byte[4]; byte[] ab32 = new byte[32]; String sLine = "- - - - - - - - - - - - - - - - - - - - - - - - - - - " + "- - - - - - - -"; /* Each cycle of this loop dumps one atom. ======================================= */ while (iTotalLength < iAtomLengthIn) { try { /* Read the length and atom id. ============================ */ iLength = disIn.readInt (); // Length iTotalLength += iLength; disIn.read (abAtomID); // Atom ID sAtomID = new String (abAtomID); iAtomID = getAtomID (sAtomID); System.out.println (sMarginIn + "Atom = " + sAtomID + " -- " + getAtomDescription (iAtomID)); System.out.println (sMarginIn + "Size = " + iLength); if ((iLength <= 0) || (iLength >= mabBuffer.length)) { System.out.println ("Atom length error, halting"); System.exit (1); } /* If the atom is a container atom, recurse to dump it. ==================================================== */ if (isContainerAtom (sAtomID)) { sMarginIn += " "; dumpAtom (disIn, iLength - 8, sMarginIn); sMarginIn = sMarginIn.substring (0, sMarginIn.length () - 2); continue; } /* Process one leaf atom depending on its atom id. =============================================== */ if (sAtomID.equals ("mvhd")) { System.out.println (sMarginIn + sLine); System.out.println (sMarginIn + "Version(1) Flags(3) = 0x" + Integer.toString (disIn.readInt (), 16)); System.out.println (sMarginIn + "Creation Time = " + ((long) disIn.readInt () & 0xffffffffL) + " secs since midnight 1/1/1904"); System.out.println (sMarginIn + "Modification Time = " + ((long) disIn.readInt () & 0xffffffffL) + " secs since midnight 1/1/1904"); System.out.println (sMarginIn + "Time Scale = " + disIn.readInt () + " time units / second"); System.out.println (sMarginIn + "Duration = " + disIn.readInt () + " time units in movie"); System.out.println (sMarginIn + "Preferred Rate = " + disIn.readInt ()); System.out.println (sMarginIn + "Preferred Volume = " + disIn.readShort ()); System.out.println (sMarginIn + "Reserved (10 bytes) = " + disIn.readInt ()); disIn.readInt (); disIn.readShort (); System.out.println (sMarginIn + "Matrix = " + "\ta=" + disIn.readInt () + "\tb=" + disIn.readInt () + "\tu=" + disIn.readInt ()); System.out.println (sMarginIn + " to convert 1 coord " + "\tc=" + disIn.readInt () + "\td=" + disIn.readInt () + "\tv=" + disIn.readInt ()); System.out.println (sMarginIn + " system to another. " + "\tx=" + disIn.readInt () + "\ty=" + disIn.readInt () + "\tw=" + disIn.readInt ()); System.out.println (sMarginIn + "Preview Time = " + disIn.readInt () + " (time at which preview begins)"); System.out.println (sMarginIn + "Preview Duration = " + disIn.readInt () + " movie time units"); System.out.println (sMarginIn + "Poster Time = " + disIn.readInt () + " movie time units"); System.out.println (sMarginIn + "Selection Time = " + disIn.readInt () + " (start time of the current selection)"); System.out.println (sMarginIn + "Selection Duration = " + disIn.readInt () + " movie time units"); System.out.println (sMarginIn + "Current Time = " + disIn.readInt () + " (current time position in movie)"); System.out.println (sMarginIn + "Next Track ID = " + disIn.readInt () + " (ID to give next track added to this movie)"); System.out.println ("\n"); } else if (sAtomID.equals ("tkhd")) { System.out.println (sMarginIn + sLine); System.out.println (sMarginIn + "Version(1) Flags(3) = 0x" + Integer.toString (disIn.readInt (), 16)); System.out.println (sMarginIn + "Creation Time = " + ((long) disIn.readInt () & 0xffffffffL) + " secs since midnight 1/1/1904"); System.out.println (sMarginIn + "Modification Time = " + ((long) disIn.readInt () & 0xffffffffL) + " secs since midnight 1/1/1904"); System.out.println (sMarginIn + "Track ID = " + disIn.readInt ()); System.out.println (sMarginIn + "Reserved (4 bytes) = " + disIn.readInt ()); System.out.println (sMarginIn + "Duration = " + disIn.readInt ()); System.out.println (sMarginIn + "Reserved (8 bytes) = " + disIn.readInt ()); disIn.readInt (); System.out.println (sMarginIn + "Layer = " + (disIn.readShort () & 0xffff)); System.out.println (sMarginIn + "Alternate Group = " + (disIn.readShort () & 0xffff)); System.out.println (sMarginIn + "Volume = " + (disIn.readShort () & 0xffff)); System.out.println (sMarginIn + "Reserved (2 bytes) = " + (disIn.readShort () & 0xffff)); System.out.println (sMarginIn + "Matrix = " + "\ta=" + disIn.readInt () + "\tb=" + disIn.readInt () + "\tu=" + disIn.readInt ()); System.out.println (sMarginIn + " to convert 1 coord " + "\tc=" + disIn.readInt () + "\td=" + disIn.readInt () + "\tv=" + disIn.readInt ()); System.out.println (sMarginIn + " system to another. " + "\tx=" + disIn.readInt () + "\ty=" + disIn.readInt () + "\tw=" + disIn.readInt ()); System.out.println (sMarginIn + "Track Width = " + disIn.readInt ()); System.out.println (sMarginIn + "Track Height = " + disIn.readInt ()); System.out.println ("\n"); } else if (sAtomID.equals ("stsz")) { System.out.println (sMarginIn + sLine); System.out.println (sMarginIn + "Version(1) Flags(3) = 0x" + Integer.toString (disIn.readInt (), 16)); iSampleSize = disIn.readInt (); System.out.println (sMarginIn + "Sample Size = " + iSampleSize); iSize = disIn.readInt (); System.out.println (sMarginIn + "Number of Entries = " + iSize); if (iSampleSize == 0) { for (i = 0; i < iSize; i++) { s = ""; if (i < 100) s += " "; if (i < 10) s += " "; System.out.println (sMarginIn + " table[" + s + i + "] = " + disIn.readInt () + " bytes"); } } System.out.println ("\n"); } else if (sAtomID.equals ("stsd")) { System.out.println (sMarginIn + sLine); System.out.println (sMarginIn + "Version(1) Flags(3) = 0x" + Integer.toString (disIn.readInt (), 16) + " ???"); iSize = disIn.readInt (); System.out.println (sMarginIn + "Number of Entries = " + iSize + " ???"); for (i = 0; i < iSize; i++) { s1 = ""; if (i < 100) s1 += " "; if (i < 10) s1 += " "; s1 = "[" + s1 + i + "] "; s = " "; iSize2 = disIn.readInt (); System.out.println (sMarginIn + s1 + "Sample Desc Table Size = " + iSize2 + " bytes"); disIn.read (ab4); System.out.println (sMarginIn + s + "Encoding = " + new String (ab4)); System.out.println (sMarginIn + s + "Reserved (6 bytes) = " + disIn.readInt ()); disIn.readShort (); System.out.println (sMarginIn + s + "Data Reference Index = " + disIn.readShort () + " ('stsc' uses this)"); System.out.println (sMarginIn + s + "Compr Data Version Number = " + (disIn.readShort () & 0xffff)); System.out.println (sMarginIn + s + "Compr Data Revision Level = " + (disIn.readShort () & 0xffff)); disIn.read (ab4); System.out.println (sMarginIn + s + "Vendor = " + new String (ab4)); if (iSize2 == 36) // audio structure { System.out.println (sMarginIn + s + "Number of audio channels = " + (disIn.readShort () & 0xffff)); System.out.println (sMarginIn + s + "Sample width in bits = " + (disIn.readShort () & 0xffff) + " bits"); System.out.println (sMarginIn + s + "Compression ID = " + (disIn.readShort () & 0xffff)); System.out.println (sMarginIn + s + "Packet Size = " + (disIn.readShort () & 0xffff)); System.out.println (sMarginIn + s + "?? samplerate * 65536 ?? = " + disIn.readInt ()); } else if (iSize2 == 52) // another audio structure { System.out.println (sMarginIn + s + "Number of audio channels = " + (disIn.readShort () & 0xffff)); System.out.println (sMarginIn + s + "Sample width in bits = " + (disIn.readShort () & 0xffff) + " bits"); System.out.println (sMarginIn + s + "Compression ID = " + (disIn.readShort () & 0xffff)); System.out.println (sMarginIn + s + "Packet Size = " + (disIn.readShort () & 0xffff)); System.out.println (sMarginIn + s + "?? samplerate * 65536 ?? = " + disIn.readInt ()); System.out.println (sMarginIn + s + "?? 1 = " + disIn.readInt ()); System.out.println (sMarginIn + s + "?? 2 = " + disIn.readInt ()); System.out.println (sMarginIn + s + "?? 3 = " + disIn.readInt ()); System.out.println (sMarginIn + s + "?? 4 = " + disIn.readInt ()); } else // video structure { System.out.println (sMarginIn + s + "Temporal Quality = " + disIn.readInt ()); System.out.println (sMarginIn + s + "Spatial Quality = " + disIn.readInt ()); System.out.println (sMarginIn + s + "Image Width = " + (disIn.readShort () & 0xffff)); System.out.println (sMarginIn + s + "Image Height = " + (disIn.readShort () & 0xffff)); System.out.println (sMarginIn + s + "Horizontal Resolution = " + disIn.readInt () + " pixels/inch"); System.out.println (sMarginIn + s + "Vertical Resolution = " + disIn.readInt () + " pixels/inch"); System.out.println (sMarginIn + s + "Data Size = " + disIn.readInt ()); System.out.println (sMarginIn + s + "Num Frames / Sample = " + (disIn.readShort () & 0xffff)); disIn.read (ab32); System.out.println (sMarginIn + s + "Compression Vendor Name = " + new String (ab32)); System.out.println (sMarginIn + s + "Color Depth = " + (disIn.readShort () & 0xffff) + " bits/pixel"); System.out.println (sMarginIn + s + "Color Table = " + (disIn.readShort () & 0xffff) + " (65535 means use default table)"); } } System.out.println ("\n"); } else if (sAtomID.equals ("stts")) { System.out.println (sMarginIn + sLine); System.out.println (sMarginIn + "Version(1) Flags(3) = 0x" + Integer.toString (disIn.readInt (), 16)); iSize = disIn.readInt (); System.out.println (sMarginIn + "Number of Entries = " + iSize); for (i = 0; i < iSize; i++) { s = ""; if (i < 100) s += " "; if (i < 10) s += " "; System.out.println (sMarginIn + " table[" + s + i + "] = count=" + disIn.readInt () + " duration=" + disIn.readInt () + " (movie time scale units)"); } System.out.println ("\n"); } else if (sAtomID.equals ("stss")) { System.out.println (sMarginIn + sLine); System.out.println (sMarginIn + "Version(1) Flags(3) = 0x" + Integer.toString (disIn.readInt (), 16)); iSize = disIn.readInt (); System.out.println (sMarginIn + "Number of Entries = " + iSize); for (i = 0; i < iSize; i++) { s = ""; if (i < 100) s += " "; if (i < 10) s += " "; System.out.println (sMarginIn + " table[" + s + i + "] = sample " + disIn.readInt () + " is a key frame"); } System.out.println ("\n"); } else if (sAtomID.equals ("stsc")) { System.out.println (sMarginIn + sLine); System.out.println (sMarginIn + "Version(1) Flags(3) = 0x" + Integer.toString (disIn.readInt (), 16)); iSize = disIn.readInt (); System.out.println (sMarginIn + "Number of Entries = " + iSize); for (i = 0; i < iSize; i++) { s = ""; if (i < 100) s += " "; if (i < 10) s += " "; System.out.println (sMarginIn + " table[" + s + i + "] = 1stChunkNumMatchingThis=" + disIn.readInt () + " SamplesInChunk=" + disIn.readInt () + " DescDataRefIndexInSTSD=" + disIn.readInt ()); } System.out.println ("\n"); } else if (sAtomID.equals ("stco")) { System.out.println (sMarginIn + sLine); System.out.println (sMarginIn + "Version(1) Flags(3) = 0x" + Integer.toString (disIn.readInt (), 16)); iSize = disIn.readInt (); System.out.println (sMarginIn + "Number of Entries = " + iSize); for (i = 0; i < iSize; i++) { s = ""; if (i < 100) s += " "; if (i < 10) s += " "; System.out.println (sMarginIn + " table[" + s + i + "] = offset 0x" + Integer.toString (disIn.readInt (), 16)); } System.out.println ("\n"); } else if (sAtomID.equals ("mdat")) { disIn.skip (iLength - 8); System.out.println ("\n\n"); } else if (sAtomID.equals ("esds")) { System.out.println (); System.out.println (new Dump (disIn, iLength - 4, sMarginIn)); // 4 instead of 8 because the data is 4 bytes toolong } else { System.out.println (); System.out.println (new Dump (disIn, iLength - 8, sMarginIn)); } } catch (Throwable t) { System.out.println ("dumpAtom() error: " + t); System.exit (1); } } return (iTotalLength); } /* D U M P M O V I E */ /** Dump the previously loaded Quicktime movie. * */ public void dumpMovie (String sReportTitle) { String sMargin; DataInputStream dis; ByteArrayInputStream bais; bais = new ByteArrayInputStream (mabBuffer); dis = new DataInputStream (bais); sMargin = " "; System.out.println ("DUMP QUICKTIME MOVIE: " + sReportTitle); System.out.println (); dumpAtom (dis, mabBuffer.length, sMargin); } /* G E T A T O M D E S C R I P T I O N */ /** Return a string that describes the passed integral atom id. * */ public static String getAtomDescription (int iAtomIDIn) { return (masAtomsAndDescriptions[iAtomIDIn].substring (8)); } /* G E T A T O M F U L L D E S C R I P T I O N */ /** Return a string that includes the 4 character atom id with a * description of the atom. * */ public static String getAtomFullDescription (int iAtomIDIn) { return (masAtomsAndDescriptions[iAtomIDIn]); } /* G E T A T O M I D */ /** Get an integer that represents the passed 4 character atom id. * */ public static int getAtomID (String sAtomIDIn) { int i; for (i = 0; i < masAtomsAndDescriptions.length; i++) { if (masAtomsAndDescriptions[i].startsWith (sAtomIDIn)) return (i); } return (0); } /* I S C O N T A I N E R A T O M */ /** Returns true if the passed atom id is a container atom. * */ public static boolean isContainerAtom (String sAtomIDIn) { if (sAtomIDIn.equals ("clip") || sAtomIDIn.equals ("dinf") || sAtomIDIn.equals ("edts") || sAtomIDIn.equals ("matt") || sAtomIDIn.equals ("mdia") || sAtomIDIn.equals ("minf") || sAtomIDIn.equals ("moov") || sAtomIDIn.equals ("stbl") || sAtomIDIn.equals ("trak") || sAtomIDIn.equals ("udta")) { return (true); } return (false); } } /*===========================( End of Source )===========================*/