Ich möchte mit Java aus FLV-Dateien auslesen können, welcher Audio-Codec verwendet wird.
Nach etwas Sucharbeit habe ich die Dokumentation des FLV-Standards gefunden: Adobe - FLV/F4V Technology Center
Die ersten Werte welche nur 1 Byte groß sind werden soweit korrekt eingelesen, aber ich scheitere bereits beim Feld DataOffset. Es handelt sich dabei gemäß Dokumentation um einen UnsignedInteger32 (UI32) - meinem Wissen nach also 4 Byte. Um aus dem ausgelesenen Byte-Array nun einen Integer zu machen, habe ich eine passende Methode im Internet gefunden. Der Rückgabewert ist allerdings viel zu groß (über eine Mio.), laut Doku sollte er 9 sein.
Alle weiteren Felder die eingelesen werden enthalten ohnehin falsche Werte. Ich habe leider nicht die geringste Ahnung was ich falsch mache.
Hier der ganze Code:
Nach etwas Sucharbeit habe ich die Dokumentation des FLV-Standards gefunden: Adobe - FLV/F4V Technology Center
Die ersten Werte welche nur 1 Byte groß sind werden soweit korrekt eingelesen, aber ich scheitere bereits beim Feld DataOffset. Es handelt sich dabei gemäß Dokumentation um einen UnsignedInteger32 (UI32) - meinem Wissen nach also 4 Byte. Um aus dem ausgelesenen Byte-Array nun einen Integer zu machen, habe ich eine passende Methode im Internet gefunden. Der Rückgabewert ist allerdings viel zu groß (über eine Mio.), laut Doku sollte er 9 sein.
Alle weiteren Felder die eingelesen werden enthalten ohnehin falsche Werte. Ich habe leider nicht die geringste Ahnung was ich falsch mache.
Hier der ganze Code:
Code:
import java.io.*;
/**
* Reads meta data from flash videos.
*
* @author Christoph Matscheko, 2009
*/
public class MetaDataExtractor {
protected String path;
//// FLV-Header
/** File version (for example, 0x01 for FLV version 1) */
protected int Version;
/** Audio tags are present */
protected int TypeFlagsAudio;
/** Video tags are present */
protected int TypeFlagsVideo;
/** Offset in bytes from start of file to start of body (that is, size of header) */
protected int[] DataOffset = new int[4];
protected int DataOffsetInt;
//// FLV-Body
/** First tag */
protected FlvTag Tag1;
/** Size of previous tag, including its header.
* For FLV version 1, this value is 11 plus the
* DataSize of the previous tag.
*/
protected byte[] PreviousTagSize1 = new byte[4];
/** Second tag */
protected FlvTag Tag2;
/** Size of second-to-last tag */
protected byte[] PreviousTagSizeN_1 = new byte[4];
/** Last tag */
protected FlvTag TagN;
/** Size of last tag */
protected byte[] PreviousTagSizeN = new byte[4];
//// AUDIODATA
/** Format of SoundData */
protected byte[] SoundFormat = new byte[4];
public static void main( String[] args ) {
MetaDataExtractor mde = new MetaDataExtractor( "/media/daten/videos/imperial_march.flv" );
mde.printMetaData();
}
/**
* Set path to video file and read meta data.
*
* @param path Path to video file
*/
public MetaDataExtractor( String path ) {
this.path = path;
this.readMetaData();
}
/**
* Write all meta data to stdout.
*/
public void printMetaData() {
System.out.println(
"+++ FLV-HEADER +++\n" +
"UI8 Version = " + this.Version + "\n" +
"UB[1] TypeFlagsAudio = " + this.TypeFlagsAudio + "\n" +
"UB[1] TypeFlagsVideo = " + this.TypeFlagsVideo + "\n" +
"UI32 DataOffset = " + byteArrayToInt(DataOffset) + " > " + listArray( DataOffset ) + "\n"
);
/*System.out.print(
"+++ FLV-BODY +++\n" +
"FLVTAG Tag1 = "
);
printFlvTag( this.Tag1 );
System.out.print(
"UI32 PreviousTagSize1 = " + byteArrayToInt(PreviousTagSize1) + " > " + listArray(PreviousTagSize1) + "\n" +
"FLVTAG Tag2 = "
);
printFlvTag( this.Tag2 );
System.out.print(
"UI32 PreviousTagSizeN-1 = " + byteArrayToInt(PreviousTagSizeN_1) + " > " + listArray(PreviousTagSizeN_1) + "\n" +
"FLVTAG TagN = "
);
printFlvTag( this.TagN );
System.out.print(
"UI32 PreviousTagSizeN = " + byteArrayToInt(PreviousTagSizeN) + " > " + listArray(PreviousTagSizeN) + "\n" +
"\n+++ AUDIODATA +++\n" +
"UB[4] SoundFormat = " + byteArrayToInt(SoundFormat) + " > " + listArray(SoundFormat)
);*/
}
/**
* Read FLVTAG data block.
*
* @param is instance of InputStream for the video file
* @return Structure of FlvTag
* @throws IOException
*/
protected FlvTag readFlvTag( InputStream is ) throws IOException {
FlvTag ft = new FlvTag();
// TagType (UInt8)
is.read( ft.TagType );
// DataSize (UInt24)
is.read( ft.DataSize );
// Timestamp (UInt24)
is.read( ft.Timestamp );
// TimestampExtended (UInt8)
is.read( ft.TimestampExtended );
// StreamID (UInt24)
is.read( ft.StreamID );
// Data
int TagType = byteArrayToInt( ft.TagType );
if ( TagType == 8 ) {
ft.Data = "AUDIODATA";
} else if ( TagType == 9 ) {
ft.Data = "VIDEODATA";
} else if ( TagType == 18 ) {
ft.Data = "SCRIPTDATAOBJECT";
} else {
ft.Data = null;
}
return ft;
}
/**
* Parse meta data from video file.
*/
protected void readMetaData() {
try {
DataInputStream dis = new DataInputStream( new FileInputStream(this.path) );
//// FLV-Header ////
// Skip first 3 bytes ('F', 'L', 'V')
dis.skip( 3 );
// FlashVideo-Version (UI8)
this.Version = dis.readUnsignedByte();
// Skip 5 bytes (TypeFlagsReserved UB[5] - Must be 0)
dis.skip( 5 );
// TypeFlagsAudio (UI8)
this.TypeFlagsAudio = dis.readUnsignedByte();
// Skip 1 byte (TypeFlagsReserved UB[1] - Must be 0)
dis.skip( 1 );
// TypeFlagsVideo (UB[1])
this.TypeFlagsVideo = dis.readUnsignedByte();
// DataOffset (UI32)
this.DataOffset[0] = dis.readUnsignedByte();
this.DataOffset[1] = dis.readUnsignedByte();
this.DataOffset[2] = dis.readUnsignedByte();
this.DataOffset[3] = dis.readUnsignedByte();
//this.DataOffsetInt = dis.readUnsignedShort();
//// FLV-Body ////
// Skip 4 bytes (PreviousTagSize0 (UI32) - Always 0)
dis.skip( 4 );
// Tag1 (FLVTAG)
this.Tag1 = this.readFlvTag( dis );
// PreviousTagSize1 (UI32)
dis.read( PreviousTagSize1 );
// Tag2 (FLVTAG)
this.Tag2 = this.readFlvTag( dis );
// PreviousTagSizeN-1 (UI32)
dis.read( PreviousTagSizeN_1 );
// TagN (FLVTAG)
this.TagN = this.readFlvTag( dis );
// PreviousTagSizeN (UI32)
dis.read( this.PreviousTagSizeN );
//// AUDIODATA ////
// SoundFormat (UB[4])
dis.read( this.SoundFormat );
dis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch ( Exception e ) {
e.printStackTrace();
}
}
/**
* Codesnippet from http://snippets.dzone.com/posts/show/94
*
* Convert the byte array to an int.
*
* @param b The byte array
* @return The integer
*/
public static int byteArrayToInt( byte[] arr ) {
int number = 0;
for ( int i=0; i<arr.length; ++i ) {
number |= (arr[arr.length-1-i] & 0xff) << (i << arr.length-1);
}
return number;
}
public static int byteArrayToInt( int[] arr ) {
int number = 0;
for ( int i=0; i<arr.length; ++i ) {
number |= (arr[arr.length-1-i] & 0xff) << (i << arr.length-1);
}
return number;
}
/*public static int bytesToInt32( byte[] buffer ) {
return buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
}*/
/**
* Write array content into stout.
*/
public static void print_r( int[] b ) {
System.out.println( "Array(){" );
for ( int i=0; i<b.length; i++ ) {
System.out.println( "\t[" + i + "] = " + b[i] );
}
System.out.println( "}" );
}
/**
* Visualize byte array as a String.
*
* @param array array with bytes
* @return String with array data
*/
public static String listArray( byte[] array ) {
StringBuffer buf = new StringBuffer( "Array{ " );
for ( int i=0; i<array.length; i++ ) {
buf.append( "[" + i + "]=" + array[i] );
if ( i+1 < array.length )
buf.append( " " );
}
buf.append( " }" );
return buf.toString();
}
public static String listArray( int[] array ) {
StringBuffer buf = new StringBuffer( "Array{ " );
for ( int i=0; i<array.length; i++ ) {
buf.append( "[" + i + "]=" + array[i] );
if ( i+1 < array.length )
buf.append( " " );
}
buf.append( " }" );
return buf.toString();
}
/**
* Writes data from FLVTAG into stdout.
*
* @param ft FlvTag
*/
public static void printFlvTag( FlvTag ft ) {
System.out.println(
"FlvTag() {\n" +
"\tTagType = " + ft.TagType[0] + "\n" +
"\tDataSize = " + listArray( ft.DataSize ) + "\n" +
"\tTimestamp = " + listArray( ft.Timestamp ) + "\n" +
"\tTimestampExtended = " + ft.TimestampExtended[0] + "\n" +
"\tStreamID = " + listArray( ft.StreamID ) + "\n" +
"\tData = " + ft.Data + "\n}"
);
}
/**
* Structure for FLVTAG data.
*/
class FlvTag {
public byte[] TagType = new byte[1];
public byte[] DataSize = new byte[3];
public byte[] Timestamp = new byte[3];
public byte[] TimestampExtended = new byte[1];
public byte[] StreamID = new byte[3];
/** Body of the tag **/
public String Data;
}
}