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 )===========================*/