MODULE AVI;
IMPORT
SYSTEM, Machine, Streams, KernelLog, AOC := Codecs;
CONST
Debug = FALSE;
DefaultReaderSize = 4096;
WriteError = 2907;
TYPE
MainAVIHeaderDesc* = OBJECT
VAR
microSecsPerFrame*: LONGINT;
maxBytesPerSec*: LONGINT;
reserved1*: LONGINT;
flags*: LONGINT;
totalFrames*: LONGINT;
initialFrames*: LONGINT;
streams*: LONGINT;
suggestedBufferSize*: LONGINT;
width*: LONGINT;
height*: LONGINT;
reserved*: ARRAY 4 OF LONGINT;
END MainAVIHeaderDesc;
AVIStreamHeader* = OBJECT
VAR
fccType*: ARRAY 4 OF CHAR;
fccHandler*: ARRAY 4 OF CHAR;
flags*: LONGINT;
priority*: LONGINT;
initialFrames*: LONGINT;
scale*: LONGINT;
rate*: LONGINT;
start*: LONGINT;
length*: LONGINT;
suggestedBufferSize*: LONGINT;
quality*: LONGINT;
sampleSize*: LONGINT;
left*: LONGINT;
top*: LONGINT;
right*: LONGINT;
bottom*: LONGINT;
streamIdentifier*: ARRAY 4 OF CHAR;
bitMapInfo*: BitMapInfo;
waveFormatEx*: WAVEFormatEx;
END AVIStreamHeader;
BitMapInfo = OBJECT
VAR
size*: LONGINT;
width*: LONGINT;
height*: LONGINT;
planes*: LONGINT;
bitCount*: LONGINT;
compression*: LONGINT;
sizeImage*: LONGINT;
xPelsPerMeter*: LONGINT;
yPelsPerMeter*: LONGINT;
clrUsed*: LONGINT;
clrImportant*: LONGINT;
END BitMapInfo;
WAVEFormatEx* = OBJECT
VAR
formatTag*: LONGINT;
channels*: LONGINT;
samplesPerSec*: LONGINT;
avgBytesPerSec*: LONGINT;
blockAlign*: LONGINT;
bitsPerSample*: LONGINT;
cbSize*: LONGINT;
END WAVEFormatEx;
AVIIndexEntry* = RECORD
ckid*: LONGINT;
flags*: LONGINT;
offset*: LONGINT;
length*: LONGINT;
tot*: LONGINT;
END;
TYPE IndexArrayPointer* = POINTER TO ARRAY OF AVIIndexEntry;
TYPE AVIStream* = OBJECT(AOC.DemuxStream)
VAR
bufAdr: LONGINT;
r : Streams.Reader;
chunkSize*: LONGINT;
streamHeader: AVIStreamHeader;
stuffByte*: LONGINT;
eof*: BOOLEAN;
PROCEDURE & Init*( r: Streams.Reader; streamHdr: AVIStreamHeader);
BEGIN
bufAdr := 0;
chunkSize := 0;
streamHeader := streamHdr;
SELF.r := r;
ASSERT(SELF.r # NIL);
stuffByte := 0;
eof := FALSE;
END Init;
PROCEDURE CanSetPos*() : BOOLEAN;
BEGIN
RETURN r.CanSetPos();
END CanSetPos;
PROCEDURE CompareCharArrays(ar1,ar2 : ARRAY OF CHAR; len: LONGINT ): BOOLEAN;
VAR
i: LONGINT;
BEGIN
IF ( len > LEN( ar1 ) ) OR ( len > LEN( ar2 ) ) THEN
RETURN FALSE
END;
FOR i := 0 TO len-1 DO
IF ar1[i] # ar2[i] THEN
RETURN FALSE
END;
END;
RETURN TRUE
END CompareCharArrays;
PROCEDURE ReadNextChunk(VAR buf: ARRAY OF CHAR);
VAR
tempBuf: ARRAY 4 OF CHAR;
len: LONGINT;
done: BOOLEAN;
BEGIN
IF Debug THEN KernelLog.String("Read next Chunk"); KernelLog.Ln; END;
done := FALSE;
eof := FALSE;
IF stuffByte > 0 THEN
r.SkipBytes( 1 );
stuffByte := 0
END;
REPEAT
r.Bytes(tempBuf, 0, 4, len );
IF r.res = Streams.Ok THEN
r.RawLInt(len);
stuffByte := len MOD 2;
IF r.res = Streams.Ok THEN
IF Debug THEN
KernelLog.String( "AVIStream: Found Chunk : " );
KernelLog.Hex( ORD( tempBuf[0] ), 0 ); KernelLog.Hex( ORD( tempBuf[1] ), 0 );
KernelLog.Hex( ORD( tempBuf[2] ), 0 ); KernelLog.Hex( ORD( tempBuf[3] ), 0 ); KernelLog.String(" ");
KernelLog.Char( tempBuf[0] ); KernelLog.Char( tempBuf[1] ); KernelLog.Char( tempBuf[2] );
KernelLog.Char( tempBuf[3] ); KernelLog.String( "@Pos: "); KernelLog.Int( r.Pos() - 8, 0 );
KernelLog.String( " SkipBytes: " ); KernelLog.Int( len, 0 ); KernelLog.Ln();
END;
IF CompareCharArrays( tempBuf, streamHeader.streamIdentifier, 4 ) THEN
IF len > 0 THEN
done := TRUE;
bufAdr := SYSTEM.ADR( buf[0] );
r.Bytes( buf, 0, len, chunkSize );
buf[len] := CHR( 0 ); buf[len+1] := CHR( 0 ); buf[len+2] := CHR( 0 ); buf[len+3] := CHR( 0 );
ASSERT( len = chunkSize );
END;
ELSE
r.SkipBytes( len + stuffByte )
END;
ELSE
eof := TRUE;
res := Streams.EOF;
KernelLog.String("ENDE");
END;
ELSE
eof := TRUE;
res := Streams.EOF;
KernelLog.String("ENDE");
END;
UNTIL ( done OR eof );
END ReadNextChunk;
PROCEDURE Resynch*(VAR buf: ARRAY OF CHAR): BOOLEAN;
BEGIN
ReadNextChunk(buf);
RETURN ~eof
END Resynch;
PROCEDURE Pos*(): LONGINT;
BEGIN
RETURN r.Pos()
END Pos;
PROCEDURE SetAVIPos*(pos: LONGINT; VAR retPos: LONGINT);
BEGIN
IF Debug THEN KernelLog.String("DemuxStream.SetAVIPos"); KernelLog.Ln; END;
r.SetPos(pos);
stuffByte := 0;
retPos := r.Pos();
Reset;
END SetAVIPos;
PROCEDURE Bytes*(VAR x: ARRAY OF CHAR; ofs, size: LONGINT; VAR len: LONGINT);
VAR
min, res: LONGINT;
BEGIN
IF Debug THEN KernelLog.String("Bytes"); KernelLog.Ln; END;
demultiplexer.GetData(streamNr, x, ofs, size, min, len, res);
END Bytes;
PROCEDURE SetPos*(pos : LONGINT);
VAR seekType, itemSize, res : LONGINT;
BEGIN
IF Debug THEN KernelLog.String("DemuxStream.SetPos"); KernelLog.Ln; END;
seekType := AOC.SeekByte;
demultiplexer.SetStreamPos(streamNr, seekType, pos, itemSize, res);
Reset;
END SetPos;
END AVIStream;
AVIDemux* = OBJECT(AOC.AVDemultiplexer)
VAR
r : Streams.Reader;
filename* : ARRAY 256 OF CHAR;
aviHeader: MainAVIHeaderDesc;
audioStreamHeader: AVIStreamHeader;
videoStreamHeader: AVIStreamHeader;
riffLength: LONGINT;
movieBeginPos: LONGINT;
indexStart: LONGINT;
videoFrames: LONGINT;
audioChunks: LONGINT;
videoIndex: IndexArrayPointer;
audioIndex: IndexArrayPointer;
audioBytes: LONGINT;
videoBufferIndex: LONGINT;
audioChunkSize: LONGINT;
audioStream: AVIStream;
videoStream: AVIStream;
videoFramePos: LONGINT;
audioFramePos: LONGINT;
PROCEDURE Open*(in : Streams.Reader; VAR res : LONGINT);
BEGIN
r := in;
res := AOC.ResFailed;
IF in IS AOC.FileInputStream THEN
in(AOC.FileInputStream).f.GetName(filename);
IF ReadHeader() THEN res := AOC.ResOk END
ELSE RETURN END;
END Open;
PROCEDURE GetAVIHeader*(): MainAVIHeaderDesc;
BEGIN
RETURN aviHeader
END GetAVIHeader;
PROCEDURE CompareCharArrays( ar1,ar2 : ARRAY OF CHAR; len: LONGINT ): BOOLEAN;
VAR
i: LONGINT;
BEGIN
IF ( len > LEN( ar1 ) ) OR ( len > LEN( ar2 ) ) THEN
RETURN FALSE
END;
FOR i := 0 TO len-1 DO
IF ar1[i] # ar2[i] THEN
RETURN FALSE
END;
END;
RETURN TRUE
END CompareCharArrays;
PROCEDURE ReadHeader*(): BOOLEAN;
VAR
buf : ARRAY 8 OF CHAR;
len: LONGINT;
done: BOOLEAN;
headerLength: LONGINT;
headerBeginPos: LONGINT;
tempHeader: AVIStreamHeader;
streamNumber: SHORTINT;
BEGIN
done := FALSE;
streamNumber := 0;
riffLength := 0;
aviHeader := NIL;
audioStreamHeader := NIL;
videoStreamHeader := NIL;
ASSERT(r # NIL);
r.Bytes( buf,0,4,len );
IF CompareCharArrays( buf, "RIFF" ,4 ) # TRUE THEN
KernelLog.String( "Not a valid .avi File!" ); KernelLog.Ln;
RETURN FALSE
END;
r.RawLInt(riffLength);
r.Bytes( buf,0,4, len );
IF CompareCharArrays( buf, "AVI ",4 ) # TRUE THEN
KernelLog.String( "Only .avi Files that contain a video stream are allowed" ); KernelLog.Ln();
RETURN FALSE
END;
REPEAT
r.Bytes( buf,0,4, len );
IF CompareCharArrays( buf, "LIST",4 ) THEN
r.RawLInt(headerLength);
headerLength := headerLength + headerLength MOD 2;
headerBeginPos := r.Pos();
r.Bytes( buf,0,4, len );
IF CompareCharArrays(buf, "hdrl",4) THEN
r.Bytes( buf,0,4, len );
IF CompareCharArrays(buf, "avih",4) THEN
aviHeader := ReadMainAVIHeader()
ELSE
SkipHeader()
END;
ELSIF CompareCharArrays( buf, "strl",4 ) THEN
r.Bytes( buf,0,4, len );
IF CompareCharArrays( buf, "strh",4 ) THEN
tempHeader := ReadAVIStreamHeader();
IF CompareCharArrays(tempHeader.fccType, "vids",4) THEN
r.SkipBytes(4);
IF videoStreamHeader = NIL THEN
videoStreamHeader := tempHeader;
videoStreamHeader.streamIdentifier[0] := "0";
videoStreamHeader.streamIdentifier[1] := CHR( ORD( '0' ) + streamNumber );
videoStreamHeader.streamIdentifier[2] := "d";
videoStreamHeader.streamIdentifier[3] := "c";
INC(streamNumber)
END;
tempHeader := NIL;
IF videoStreamHeader.bitMapInfo = NIL THEN
videoStreamHeader.bitMapInfo := ReadBitMapInfo();
videoStreamHeader.waveFormatEx := NIL
ELSE
SkipHeader()
END;
ELSIF CompareCharArrays(tempHeader.fccType, "auds",4) THEN
r.SkipBytes(4);
IF audioStreamHeader = NIL THEN
audioStreamHeader := tempHeader;
audioStreamHeader.streamIdentifier[0] := "0";
audioStreamHeader.streamIdentifier[1] := CHR( ORD('0') + streamNumber );
audioStreamHeader.streamIdentifier[2] := "w";
audioStreamHeader.streamIdentifier[3] := "b";
INC(streamNumber)
END;
tempHeader := NIL;
IF audioStreamHeader.waveFormatEx = NIL THEN
audioStreamHeader.waveFormatEx := ReadWaveFormatEx();
audioStreamHeader.bitMapInfo := NIL
ELSE
SkipHeader()
END;
ELSE
IF Debug THEN
KernelLog.String( "AVIDemux: Unknown AviStream found; " ); KernelLog.String(tempHeader.fccType);
KernelLog.Ln()
END;
END;
END;
ELSIF CompareCharArrays(buf, "movi",4) THEN
movieBeginPos := r.Pos()-4;
r.SetPos(headerLength+movieBeginPos);
r.Bytes(buf,0,4,len);
IF CompareCharArrays(buf, "idx1",4) THEN
indexStart := r.Pos()-4;
ReadIndex();
IF Debug THEN
KernelLog.String("AVIDemux: Start of movie stream found " ); KernelLog.Ln()
END;
ELSE
videoIndex := NIL;
audioIndex := NIL;
END;
r.SetPos(movieBeginPos+4);
done := TRUE;
ELSE
IF Debug THEN
KernelLog.String("AVIDemux: Unknown StreamHeader found: " ); KernelLog.String(buf); KernelLog.Ln()
END;
r.SkipBytes( headerLength - ( r.Pos() - headerBeginPos ) )
END;
ELSE
IF Debug THEN
KernelLog.String("AVIDemux: Unknown Header found: " ); KernelLog.Buffer(buf,0,4); KernelLog.Ln()
END;
SkipHeader();
END;
UNTIL done;
IF Debug THEN
DumpHeaders();
END;
RETURN TRUE
END ReadHeader;
PROCEDURE ReadIndex*;
VAR
buf : ARRAY 8 OF CHAR;
buf2 : ARRAY 8 OF CHAR;
indexLength: LONGINT;
nidx: LONGINT;
idxType: INTEGER;
i: LONGINT;
pos: LONGINT;
length: LONGINT;
len: LONGINT;
temp: LONGINT;
nai: LONGINT;
nvi: LONGINT;
tot: LONGINT;
ioff: LONGINT;
BEGIN
r.RawLInt(indexLength);
nidx := indexLength DIV 16;
idxType := 0;
i := 0;
LOOP
r.Bytes(buf, 0, 4, len);
IF CompareCharArrays(buf, videoStreamHeader.streamIdentifier, 3) THEN
i := i+1;
indexStart := r.Pos()-4;
EXIT;
END;
IF i >= nidx THEN
KernelLog.String("No Index found"); KernelLog.Ln();
EXIT;
END;
END;
r.SkipBytes(4);
r.RawLInt(pos);
r.RawLInt(length);
r.SetPos(pos);
IF CompareCharArrays(buf2, buf, 4) THEN
r.RawLInt(temp);
IF (temp = length) THEN
idxType := 1;
END;
ELSE
r.SetPos(pos + movieBeginPos);
r.Bytes(buf2, 0, 4, len);
IF CompareCharArrays(buf2, buf, 4) THEN
r.RawLInt(temp);
IF (temp = length) THEN
idxType := 2;
END;
END;
END;
IF idxType = 0 THEN
KernelLog.String("File without index: Not supported yet");
END;
IF idxType # 0 THEN
nai := 0;
nvi := 0;
r.SetPos(indexStart);
i := 0;
REPEAT
r.Bytes(buf, 0, 4, len);
IF CompareCharArrays(buf, videoStreamHeader.streamIdentifier, 3) THEN
nvi := nvi+1;
ELSE
IF audioStreamHeader # NIL THEN
IF CompareCharArrays(buf, audioStreamHeader.streamIdentifier, 4) THEN
nai := nai+1;
END;
END;
END;
r.SkipBytes(12);
i := i+1;
UNTIL (i = nidx-1);
videoFrames := nvi;
audioChunks := nai;
NEW(videoIndex, nvi);
IF (audioChunks > 0) THEN
NEW(audioIndex, nai);
END;
nvi := 0;
nai := 0;
tot := 0;
r.SetPos(indexStart);
IF (idxType = 1) THEN
ioff := 8;
ELSE
ioff := movieBeginPos;
END;
i := 0;
REPEAT
r.Bytes(buf, 0, 4, len);
IF CompareCharArrays(buf, videoStreamHeader.streamIdentifier, 3) THEN
r.RawLInt(videoIndex[nvi].flags);
r.RawLInt(videoIndex[nvi].offset);
videoIndex[nvi].offset := videoIndex[nvi].offset + ioff;
r.RawLInt(videoIndex[nvi].length);
nvi := nvi+1;
ELSE
IF CompareCharArrays(buf, audioStreamHeader.streamIdentifier, 4) THEN
r.SkipBytes(4);
r.RawLInt(audioIndex[nai].offset);
audioIndex[nai].offset := audioIndex[nai].offset + ioff;
r.RawLInt(audioIndex[nai].length);
audioIndex[nai].tot := tot;
tot := tot + audioIndex[nai].length;
nai := nai+1;
END;
END;
i := i+1;
UNTIL (i = nidx-1);
audioBytes := tot;
END;
END ReadIndex;
PROCEDURE SkipHeader*;
VAR
length: LONGINT;
BEGIN
r.RawLInt(length);
r.SkipBytes( length + length MOD 2)
END SkipHeader;
PROCEDURE ReadMainAVIHeader(): MainAVIHeaderDesc;
VAR
aviHeader: MainAVIHeaderDesc;
headerLength: LONGINT;
startPos: LONGINT;
BEGIN
NEW( aviHeader );
r.RawLInt(headerLength);
startPos := r.Pos();
r.RawLInt( aviHeader.microSecsPerFrame );
r.RawLInt( aviHeader.maxBytesPerSec );
r.RawLInt( aviHeader.reserved1 );
r.RawLInt( aviHeader.flags );
r.RawLInt( aviHeader.totalFrames );
r.RawLInt( aviHeader.initialFrames );
r.RawLInt( aviHeader.streams );
r.RawLInt( aviHeader.suggestedBufferSize );
r.RawLInt( aviHeader.width );
r.RawLInt( aviHeader.height );
r.RawLInt( aviHeader.reserved[0] );
r.RawLInt( aviHeader.reserved[1] );
r.RawLInt( aviHeader.reserved[2] );
r.RawLInt( aviHeader.reserved[3] );
IF r.Pos() - startPos < headerLength THEN
r.SkipBytes( headerLength - ( r.Pos() - startPos ) )
END;
RETURN aviHeader;
END ReadMainAVIHeader;
PROCEDURE ReadAVIStreamHeader(): AVIStreamHeader;
VAR
header: AVIStreamHeader;
headerLength: LONGINT;
startPos: LONGINT;
len: LONGINT;
temp: INTEGER;
BEGIN
NEW(header);
r.RawLInt(headerLength);
startPos := r.Pos();
r.Bytes( header.fccType,0,4, len );
r.Bytes( header.fccHandler,0,4, len );
r.RawLInt( header.flags );
r.RawLInt( header.priority );
r.RawLInt( header.initialFrames );
r.RawLInt( header.scale );
r.RawLInt( header.rate );
r.RawLInt( header.start );
r.RawLInt( header.length );
r.RawLInt( header.suggestedBufferSize );
r.RawLInt( header.quality );
r.RawLInt( header.sampleSize );
r.RawInt( temp ); header.left := temp;
r.RawInt( temp ); header.top := temp;
r.RawInt( temp ); header.right := temp;
r.RawInt( temp ); header.bottom := temp;
IF r.Pos() - startPos < headerLength THEN
r.SkipBytes( headerLength - ( r.Pos() - startPos ) )
END;
RETURN header
END ReadAVIStreamHeader;
PROCEDURE ReadBitMapInfo(): BitMapInfo;
VAR
header: BitMapInfo;
headerLength: LONGINT;
startPos: LONGINT;
temp: INTEGER;
BEGIN
NEW(header);
r.RawLInt(headerLength);
startPos := r.Pos();
r.RawLInt( header.size );
r.RawLInt( header.width );
r.RawLInt( header.height );
r.RawInt( temp ); header.planes := temp;
r.RawInt( temp ); header.bitCount := temp;
r.RawLInt( header.compression );
r.RawLInt( header.sizeImage );
r.RawLInt( header.xPelsPerMeter );
r.RawLInt( header.yPelsPerMeter );
r.RawLInt( header.clrUsed );
r.RawLInt( header.clrImportant );
IF r.Pos() - startPos < headerLength THEN
r.SkipBytes( headerLength - ( r.Pos() - startPos ) )
END;
RETURN header
END ReadBitMapInfo;
PROCEDURE ReadWaveFormatEx(): WAVEFormatEx;
VAR
header: WAVEFormatEx;
headerLength: LONGINT;
startPos: LONGINT;
temp: INTEGER;
BEGIN
NEW(header);
r.RawLInt(headerLength);
startPos := r.Pos();
r.RawInt( temp ); header.formatTag := temp;
r.RawInt( temp ); header.channels := temp;
r.RawLInt( header.samplesPerSec );
r.RawLInt( header.avgBytesPerSec );
r.RawInt( temp ); header.blockAlign := temp;
r.RawInt( temp ); header.bitsPerSample := temp;
r.RawInt( temp ); header.cbSize := temp;
IF r.Pos() - startPos < headerLength THEN
r.SkipBytes( headerLength - ( r.Pos() - startPos ) )
END;
RETURN header
END ReadWaveFormatEx;
PROCEDURE DumpHeaders*;
BEGIN
KernelLog.String("AviDemux: Dump of Avi Headers: "); KernelLog.Ln();
IF aviHeader # NIL THEN
KernelLog.String( "aviHeader.microSecsPerFrame = " ); KernelLog.Int( aviHeader.microSecsPerFrame, 0 ); KernelLog.Ln();
KernelLog.String( "aviHeader.maxBytesPerSec = " ); KernelLog.Int( aviHeader.maxBytesPerSec, 0 ); KernelLog.Ln();
KernelLog.String( "aviHeader.reserved1 = " ); KernelLog.Int( aviHeader.reserved1, 0 ); KernelLog.Ln();
KernelLog.String( "aviHeader.flags = " ); KernelLog.Int( aviHeader.flags, 0 ); KernelLog.Ln();
KernelLog.String( "aviHeader.totalFrames = " ); KernelLog.Int( aviHeader.totalFrames, 0 ); KernelLog.Ln();
KernelLog.String( "aviHeader.initialFrames = " ); KernelLog.Int( aviHeader.initialFrames, 0 ); KernelLog.Ln();
KernelLog.String( "aviHeader.streams = " ); KernelLog.Int( aviHeader.streams, 0 ); KernelLog.Ln();
KernelLog.String( "aviHeader.suggestedBufferSize = " ); KernelLog.Int( aviHeader.suggestedBufferSize, 0 ); KernelLog.Ln();
KernelLog.String( "aviHeader.width = " ); KernelLog.Int( aviHeader.width, 0 ); KernelLog.Ln();
KernelLog.String( "aviHeader.height = " ); KernelLog.Int( aviHeader.height, 0 ); KernelLog.Ln();
KernelLog.String( "aviHeader.reserved[0] = " ); KernelLog.Int( aviHeader.reserved[0],0 ); KernelLog.Ln();
KernelLog.String( "aviHeader.reserved[1] = " ); KernelLog.Int( aviHeader.reserved[1],0 ); KernelLog.Ln();
KernelLog.String( "aviHeader.reserved[2] = " ); KernelLog.Int( aviHeader.reserved[2],0 ); KernelLog.Ln();
KernelLog.String( "aviHeader.reserved[3] = " ); KernelLog.Int( aviHeader.reserved[3],0 ); KernelLog.Ln()
ELSE
KernelLog.String("AVIDemux.aviHeader = NIL"); KernelLog.Ln()
END;
IF audioStreamHeader # NIL THEN
KernelLog.String( "audioStreamHeader.fccType = " ); KernelLog.String( audioStreamHeader.fccType ); KernelLog.Ln();
KernelLog.String( "audioStreamHeader.fccHandler = " ); KernelLog.String( audioStreamHeader.fccHandler );
KernelLog.Ln();
KernelLog.String( "audioStreamHeader.flags = " ); KernelLog.Int( audioStreamHeader.flags, 0 ); KernelLog.Ln();
KernelLog.String( "audioStreamHeader.priority = " ); KernelLog.Int( audioStreamHeader.priority, 0 ); KernelLog.Ln();
KernelLog.String( "audioStreamHeader.initialFrames = " ); KernelLog.Int( audioStreamHeader.initialFrames, 0 );
KernelLog.Ln();
KernelLog.String( "audioStreamHeader.scale = " ); KernelLog.Int( audioStreamHeader.scale, 0 ); KernelLog.Ln();
KernelLog.String( "audioStreamHeader.rate = " ); KernelLog.Int( audioStreamHeader.rate, 0 ); KernelLog.Ln();
KernelLog.String( "audioStreamHeader.start = " ); KernelLog.Int( audioStreamHeader.start, 0 ); KernelLog.Ln();
KernelLog.String( "audioStreamHeader.length = " ); KernelLog.Int( audioStreamHeader.length, 0 ); KernelLog.Ln();
KernelLog.String( "audioStreamHeader.suggestedBufferSize = " );
KernelLog.Int( audioStreamHeader.suggestedBufferSize, 0 ); KernelLog.Ln();
KernelLog.String( "audioStreamHeader.quality = " ); KernelLog.Int( audioStreamHeader.quality, 0 ); KernelLog.Ln();
KernelLog.String( "audioStreamHeader.sampleSize = " ); KernelLog.Int( audioStreamHeader.sampleSize, 0 );
KernelLog.Ln();
KernelLog.String( "audioStreamHeader.left = " ); KernelLog.Int( audioStreamHeader.left, 0 ); KernelLog.Ln();
KernelLog.String( "audioStreamHeader.top = " ); KernelLog.Int( audioStreamHeader.top, 0 ); KernelLog.Ln();
KernelLog.String( "audioStreamHeader.right = " ); KernelLog.Int( audioStreamHeader.right, 0 ); KernelLog.Ln();
KernelLog.String( "audioStreamHeader.bottom = " ); KernelLog.Int( audioStreamHeader.bottom, 0 ); KernelLog.Ln();
KernelLog.String( "audioStreamHeader.streamIdentifier = " );
KernelLog.Buffer( audioStreamHeader.streamIdentifier, 0, 4 ); KernelLog.Ln()
ELSE
KernelLog.String("AVIDemux.audioStreamHeader = NIL"); KernelLog.Ln()
END;
IF videoStreamHeader # NIL THEN
KernelLog.String( "videoStreamHeader.fccType = " ); KernelLog.String( videoStreamHeader.fccType ); KernelLog.Ln();
KernelLog.String( "videoStreamHeader.fccHandler = " ); KernelLog.String( videoStreamHeader.fccHandler );
KernelLog.Ln();
KernelLog.String( "videoStreamHeader.flags = " ); KernelLog.Int( videoStreamHeader.flags, 0 ); KernelLog.Ln();
KernelLog.String( "videoStreamHeader.priority = " ); KernelLog.Int( videoStreamHeader.priority, 0 ); KernelLog.Ln();
KernelLog.String( "videoStreamHeader.initialFrames = " ); KernelLog.Int( videoStreamHeader.initialFrames, 0 );
KernelLog.Ln();
KernelLog.String( "videoStreamHeader.scale = " ); KernelLog.Int( videoStreamHeader.scale, 0 ); KernelLog.Ln();
KernelLog.String( "videoStreamHeader.rate = " ); KernelLog.Int( videoStreamHeader.rate, 0 ); KernelLog.Ln();
KernelLog.String( "videoStreamHeader.start = " ); KernelLog.Int( videoStreamHeader.start, 0 ); KernelLog.Ln();
KernelLog.String( "videoStreamHeader.length = " ); KernelLog.Int( videoStreamHeader.length, 0 ); KernelLog.Ln();
KernelLog.String( "videoStreamHeader.suggestedBufferSize = " );
KernelLog.Int( videoStreamHeader.suggestedBufferSize, 0 ); KernelLog.Ln();
KernelLog.String( "videoStreamHeader.quality = " ); KernelLog.Int( videoStreamHeader.quality, 0 ); KernelLog.Ln();
KernelLog.String( "videoStreamHeader.sampleSize = " ); KernelLog.Int( videoStreamHeader.sampleSize, 0 );
KernelLog.Ln();
KernelLog.String( "videoStreamHeader.streamIdentifier = " );
KernelLog.Buffer( videoStreamHeader.streamIdentifier, 0, 4 ); KernelLog.Ln()
ELSE
KernelLog.String("AVIDemux.videoStreamHeader = NIL"); KernelLog.Ln()
END;
IF videoStreamHeader.bitMapInfo # NIL THEN
KernelLog.String( "bitMapInfo.size = " ); KernelLog.Int( videoStreamHeader.bitMapInfo.size ,0 ); KernelLog.Ln();
KernelLog.String( "bitMapInfo.width = " ); KernelLog.Int( videoStreamHeader.bitMapInfo.width ,0 ); KernelLog.Ln();
KernelLog.String( "bitMapInfo.height = " ); KernelLog.Int( videoStreamHeader.bitMapInfo.height ,0 ); KernelLog.Ln();
KernelLog.String( "bitMapInfo.planes = " ); KernelLog.Int( videoStreamHeader.bitMapInfo.planes ,0 ); KernelLog.Ln();
KernelLog.String( "bitMapInfo.bitCount = " ); KernelLog.Int( videoStreamHeader.bitMapInfo.bitCount ,0 ); KernelLog.Ln();
KernelLog.String( "bitMapInfo.compression = " ); KernelLog.Int( videoStreamHeader.bitMapInfo.compression ,0 ); KernelLog.Ln();
KernelLog.String( "bitMapInfo.sizeImage = " ); KernelLog.Int( videoStreamHeader.bitMapInfo.sizeImage ,0 ); KernelLog.Ln();
KernelLog.String( "bitMapInfo.xPelsPerMeter = " ); KernelLog.Int( videoStreamHeader.bitMapInfo.xPelsPerMeter ,0 ); KernelLog.Ln();
KernelLog.String( "bitMapInfo.yelsPerMeter = " ); KernelLog.Int( videoStreamHeader.bitMapInfo.yPelsPerMeter ,0 ); KernelLog.Ln();
KernelLog.String( "bitMapInfo.clrUsed = " ); KernelLog.Int( videoStreamHeader.bitMapInfo.clrUsed ,0 ); KernelLog.Ln();
KernelLog.String( "bitMapInfo.clrImportant = " ); KernelLog.Int( videoStreamHeader.bitMapInfo.clrImportant ,0 ); KernelLog.Ln()
ELSE
KernelLog.String("AVIDemux.bitMapInfo = NIL"); KernelLog.Ln()
END;
IF (audioStreamHeader # NIL) & (audioStreamHeader.waveFormatEx # NIL) THEN
KernelLog.String( "waveFormat.formatTag = " ); KernelLog.Int( audioStreamHeader.waveFormatEx.formatTag ,0 ); KernelLog.Ln();
KernelLog.String( "waveFormat.channel = " ); KernelLog.Int( audioStreamHeader.waveFormatEx.channels ,0 ); KernelLog.Ln();
KernelLog.String( "waveFormat.samplesPerSec = " ); KernelLog.Int( audioStreamHeader.waveFormatEx.samplesPerSec ,0 ); KernelLog.Ln();
KernelLog.String( "waveFormat.avgBytesPerSec = " ); KernelLog.Int( audioStreamHeader.waveFormatEx.avgBytesPerSec ,0 ); KernelLog.Ln();
KernelLog.String( "waveFormat.blockAlign = " ); KernelLog.Int( audioStreamHeader.waveFormatEx.blockAlign ,0 ); KernelLog.Ln();
KernelLog.String( "waveFormat.bitsPerSample = " ); KernelLog.Int( audioStreamHeader.waveFormatEx.bitsPerSample ,0 ); KernelLog.Ln();
KernelLog.String( "waveFormat.cbSize = " ); KernelLog.Int( audioStreamHeader.waveFormatEx.cbSize ,0 ); KernelLog.Ln()
ELSE
KernelLog.String("AVIDemux.waveFormat = NIL"); KernelLog.Ln()
END;
KernelLog.Ln()
END DumpHeaders;
PROCEDURE DumpVideoIndex*;
VAR i : LONGINT;
BEGIN
KernelLog.String("AviDemux: Dump of Video-Index: "); KernelLog.Ln();
IF videoIndex = NIL THEN KernelLog.String("no index in AVI"); KernelLog.Ln; RETURN END;
FOR i := 0 TO LEN(videoIndex)-1 DO
KernelLog.String("Index: "); KernelLog.Int(i, 0);
KernelLog.String(" ckid= "); KernelLog.Int(videoIndex[i].ckid, 0);
KernelLog.String(" flags= "); KernelLog.Int(videoIndex[i].flags, 0);
KernelLog.String(" offset= "); KernelLog.Int(videoIndex[i].offset, 0);
KernelLog.String(" length= "); KernelLog.Int(videoIndex[i].length, 0);
KernelLog.String(" tot= "); KernelLog.Int(videoIndex[i].tot, 0);
IF (i > 0) THEN KernelLog.String(" deltaOFF= "); KernelLog.Int(videoIndex[i].offset - videoIndex[i-1].offset, 0); END;
KernelLog.Ln;
END
END DumpVideoIndex;
PROCEDURE DumpAudioIndex*;
VAR i : LONGINT;
BEGIN
KernelLog.String("AviDemux: Dump of Audio-Index: "); KernelLog.Ln();
IF audioIndex = NIL THEN KernelLog.String("no index in AVI"); KernelLog.Ln; RETURN END;
FOR i := 0 TO LEN(audioIndex)-1 DO
KernelLog.String("Index: "); KernelLog.Int(i, 0);
KernelLog.String(" ckid= "); KernelLog.Int(audioIndex[i].ckid, 0);
KernelLog.String(" flags= "); KernelLog.Int(audioIndex[i].flags, 0);
KernelLog.String(" offset= "); KernelLog.Int(audioIndex[i].offset, 0);
KernelLog.String(" length= "); KernelLog.Int(audioIndex[i].length, 0);
KernelLog.String(" tot= "); KernelLog.Int(audioIndex[i].tot, 0);
IF (i > 0) THEN KernelLog.String(" deltaOFF= "); KernelLog.Int(audioIndex[i].offset - audioIndex[i-1].offset, 0); END;
KernelLog.Ln;
END
END DumpAudioIndex;
PROCEDURE GetAudioStreamHeader*(): AVIStreamHeader;
BEGIN
RETURN audioStreamHeader
END GetAudioStreamHeader;
PROCEDURE GetVideoStreamHeader*():AVIStreamHeader;
BEGIN
RETURN videoStreamHeader
END GetVideoStreamHeader;
PROCEDURE GetStream*(streamNr: LONGINT): AOC.DemuxStream;
VAR
reader : Streams.Reader;
i: LONGINT;
streamInfo : AOC.AVStreamInfo;
tag : ARRAY 4 OF CHAR;
BEGIN
reader := AOC.OpenInputStream(filename);
reader.SetPos(r.Pos());
IF streamNr = 0 THEN
NEW(videoStream, reader, videoStreamHeader);
videoFramePos := 0;
streamInfo.streamType := AOC.STVideo;
FOR i := 0 TO 3 DO streamInfo.contentType[i] := videoStreamHeader.fccHandler[i] END;
IF videoIndex = NIL THEN streamInfo.seekability := {};
ELSE streamInfo.seekability := {3,4}; END;
streamInfo.length := videoFrames;
streamInfo.frames := videoFrames;
streamInfo.rate := videoStreamHeader.rate;
videoStream.streamInfo := streamInfo;
RETURN videoStream;
ELSE
NEW(audioStream, reader, audioStreamHeader);
audioFramePos := 0;
streamInfo.streamType := AOC.STAudio;
IF (audioStreamHeader.waveFormatEx # NIL) THEN
CASE audioStreamHeader.waveFormatEx.formatTag OF
1 : COPY("PCM", tag);
| 85: COPY("MP3", tag);
ELSE
END;
FOR i := 0 TO 3 DO streamInfo.contentType[i] := tag[i]; END;
END;
IF audioIndex = NIL THEN streamInfo.seekability := {};
ELSE streamInfo.seekability := {1,2}; END;
streamInfo.length := audioStreamHeader.length*GetSampleSize();
streamInfo.frames := audioChunks;
streamInfo.rate := audioStreamHeader.rate;
audioStream.streamInfo := streamInfo;
RETURN audioStream;
END;
END GetStream;
PROCEDURE GetMilliSecondsPerFrame*(): LONGINT;
BEGIN
RETURN aviHeader.microSecsPerFrame DIV 1000;
END GetMilliSecondsPerFrame;
PROCEDURE GetNofChannels*(): LONGINT;
BEGIN
RETURN audioStreamHeader.waveFormatEx.channels;
END GetNofChannels;
PROCEDURE GetSamplesPerSecond*(): LONGINT;
BEGIN
RETURN audioStreamHeader.waveFormatEx.samplesPerSec;
END GetSamplesPerSecond;
PROCEDURE GetBitsPerSample*(): LONGINT;
BEGIN
RETURN audioStreamHeader.waveFormatEx.bitsPerSample;
END GetBitsPerSample;
PROCEDURE GetVideoIndex*(): IndexArrayPointer;
BEGIN
RETURN videoIndex;
END GetVideoIndex;
PROCEDURE GetAudioIndex*(): IndexArrayPointer;
BEGIN
RETURN audioIndex;
END GetAudioIndex;
PROCEDURE GetAudioChunks*(): LONGINT;
BEGIN
RETURN audioChunks;
END GetAudioChunks;
PROCEDURE GetAudioBytes*(): LONGINT;
BEGIN
RETURN audioBytes;
END GetAudioBytes;
PROCEDURE GetVideoFrames*(): LONGINT;
BEGIN
RETURN videoFrames;
END GetVideoFrames;
PROCEDURE GetNumberOfStreams*(): LONGINT;
BEGIN
RETURN aviHeader.streams;
END GetNumberOfStreams;
PROCEDURE GetStreamInfo*(streamNr: LONGINT): AOC.AVStreamInfo;
VAR streamInfo : AOC.AVStreamInfo;
i: INTEGER;
tag : ARRAY 4 OF CHAR;
BEGIN
IF streamNr = 0 THEN
streamInfo.streamType := AOC.STVideo;
FOR i := 0 TO 3 DO
streamInfo.contentType[i] := videoStreamHeader.fccHandler[i];
END;
IF videoIndex = NIL THEN
streamInfo.seekability := {};
ELSE
streamInfo.seekability := {3,4};
END;
streamInfo.length := videoFrames;
streamInfo.frames := videoFrames;
streamInfo.rate := videoStreamHeader.rate;
ELSE
streamInfo.streamType := AOC.STAudio;
IF (audioStreamHeader.waveFormatEx # NIL) THEN
CASE audioStreamHeader.waveFormatEx.formatTag OF
1 : COPY("PCM", tag);
| 85: COPY("MP3", tag);
ELSE
END;
FOR i := 0 TO 3 DO
streamInfo.contentType[i] := tag[i];
END;
END;
IF audioIndex = NIL THEN
streamInfo.seekability := {};
ELSE
streamInfo.seekability := {1,2};
END;
streamInfo.length := audioStreamHeader.length*GetSampleSize();
streamInfo.frames := audioChunks;
streamInfo.rate := audioStreamHeader.rate;
END;
RETURN streamInfo
END GetStreamInfo;
PROCEDURE GetStreamType*(streamNr : LONGINT): LONGINT;
VAR type : LONGINT;
BEGIN
IF streamNr = 0 THEN type := AOC.STVideo;
ELSIF streamNr = 1 THEN type := AOC.STAudio;
ELSE type := AOC.STUnknown;
END;
RETURN type
END GetStreamType;
PROCEDURE GetInfo*(VAR vl, vf, vr, mspf, al, af, ar : LONGINT);
BEGIN
vl := videoFrames;
vf := videoFrames;
vr := videoStreamHeader.rate;
mspf := aviHeader.microSecsPerFrame;
IF audioStreamHeader # NIL THEN
al := audioStreamHeader.length*GetSampleSize();
af := audioChunks;
ar := audioStreamHeader.rate;
END;
END GetInfo;
PROCEDURE GetData*(streamNr: LONGINT; VAR buf: ARRAY OF CHAR; ofs, size, min: LONGINT; VAR len, res: LONGINT);
VAR
rres: BOOLEAN;
BEGIN
IF streamNr = 0 THEN
IF videoIndex # NIL THEN
IF videoFramePos < videoFrames THEN
len := videoIndex[videoFramePos].length;
IF (len > (size-4)) THEN
len := len+4;
res := AOC.ResFailed;
RETURN;
END;
rres := videoStream.Resynch(buf);
INC(videoFramePos);
IF rres THEN
videoStream.res := Streams.Ok;
res := AOC.ResOk;
ELSE
res := AOC.ResFailed;
videoStream.res := Streams.EOF;
END
ELSE
res := AOC.ResFailed;
videoStream.res := Streams.EOF;
len := 0;
END;
END;
ELSE
IF audioIndex # NIL THEN
IF audioFramePos < audioChunks THEN
len := audioIndex[audioFramePos].length;
IF (LEN(buf) < len+4) THEN
len := len+4;
res := AOC.ResFailed;
audioStream.res := Streams.EOF;
RETURN;
END;
len := audioIndex[audioFramePos].length;
rres := audioStream.Resynch(buf);
INC(audioFramePos);
IF rres THEN
audioStream.res := Streams.Ok;
res := AOC.ResOk;
ELSE
audioStream.res := Streams.EOF;
END
ELSE
res := AOC.ResFailed;
audioStream.res := Streams.EOF;
len := 0;
END;
END;
END;
END GetData;
PROCEDURE SetStreamPos*(streamNr: LONGINT; seekType: LONGINT; pos: LONGINT; VAR itemSize: LONGINT; VAR res: LONGINT);
VAR
n0, n1, n, spos: LONGINT;
BEGIN
IF Debug THEN KernelLog.String("AVIDemux.SetStreamPos: "); KernelLog.Int(pos, 0); KernelLog.Ln; END;
IF streamNr = 0 THEN
IF videoIndex # NIL THEN
IF seekType = AOC.SeekKeyFrame THEN
IF pos > itemSize THEN
IF pos >= videoStreamHeader.length-1 THEN
pos := videoStreamHeader.length-1;
ELSE
WHILE ((pos < videoFrames-1) & (videoIndex[pos].flags # 16)) DO
INC(pos);
END;
END;
ELSE
IF(pos > 0) THEN
DEC(pos);
END;
WHILE ((videoIndex[pos].flags # 16) & (pos > 0)) DO
DEC(pos);
END;
END;
END;
IF ((seekType = AOC.SeekFrame) OR (seekType = AOC.SeekKeyFrame)) THEN
IF pos < LEN(videoIndex) THEN
videoStream.SetAVIPos(videoIndex[pos].offset, itemSize);
itemSize := pos;
videoFramePos := pos;
END
ELSE
videoStream.SetAVIPos(pos, itemSize);
END;
END;
ELSE
IF audioIndex # NIL THEN
IF seekType = AOC.SeekSample THEN
IF pos < 0 THEN
pos := 0;
END;
IF pos = 0 THEN
n0 := 0;
ELSE
n0 := 0;
n1 := audioChunks;
WHILE (n0 < n1 - 1) DO
n := (n0 + n1) DIV 2;
IF (audioIndex[n].tot > pos) THEN
n1 := n;
ELSE
n0 := n;
END;
END;
END;
audioStream.SetAVIPos(audioIndex[n0].offset, itemSize);
audioFramePos := n0;
ELSIF seekType = AOC.SeekByte THEN
spos := ENTIER(pos / audioStreamHeader.rate * audioStreamHeader.waveFormatEx.samplesPerSec);
IF Debug THEN KernelLog.String("spos= "); KernelLog.Int(spos, 0); KernelLog.Ln; END;
IF spos < 0 THEN spos := 0 END;
IF spos = 0 THEN n0 := 0
ELSE
n0 := 0;
n1 := audioChunks;
WHILE (n0 < n1 - 1) DO
n := (n0 + n1) DIV 2;
IF (audioIndex[n].tot > spos) THEN
n1 := n;
ELSE
n0 := n;
END;
END;
END;
audioStream.SetAVIPos(audioIndex[n0].offset, itemSize);
audioFramePos := n0;
IF Debug THEN
KernelLog.String("audioIndex[n].tot= "); KernelLog.Int(audioIndex[n].tot, 0);
KernelLog.String("audioIndex[n0].offset= "); KernelLog.Int(audioIndex[n0].offset, 0);
KernelLog.String("audioFramePos= "); KernelLog.Int(audioFramePos, 0);
KernelLog.String("itemSize= "); KernelLog.Int(itemSize, 0); KernelLog.Ln;
END
ELSE
audioStream.SetAVIPos(pos, itemSize);
END;
END;
END;
END SetStreamPos;
PROCEDURE GetVideoWidth*(): LONGINT;
BEGIN
RETURN videoStreamHeader.bitMapInfo.width;
END GetVideoWidth;
PROCEDURE GetVideoHeight*(): LONGINT;
BEGIN
RETURN videoStreamHeader.bitMapInfo.height;
END GetVideoHeight;
PROCEDURE GetNextFrameSize*(streamNr: LONGINT): LONGINT;
BEGIN
IF streamNr = 0 THEN
IF videoFramePos < videoFrames THEN
RETURN videoIndex[videoFramePos].length;
ELSE
RETURN AOC.ResFailed;
END;
ELSE
IF audioFramePos < audioChunks THEN
RETURN audioIndex[audioFramePos].length;
ELSE
RETURN AOC.ResFailed;
END;
END;
END GetNextFrameSize;
PROCEDURE GetSampleSize*(): LONGINT;
VAR
s: LONGINT;
BEGIN
s := ((audioStreamHeader.waveFormatEx.bitsPerSample+7) DIV 8)*audioStreamHeader.waveFormatEx.channels;
IF s = 0 THEN
s := 1;
END;
RETURN s;
END GetSampleSize;
END AVIDemux;
PROCEDURE Align*(VAR index: LONGINT);
BEGIN
IF ( index MOD 8 ) # 0 THEN
index := index - ( index MOD 8 ) + 8
END;
END Align;
PROCEDURE IsAligned*(index: LONGINT): BOOLEAN;
BEGIN
IF ( index MOD 8 ) = 0 THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END;
END IsAligned;
PROCEDURE ShowBitsSlow*( n: LONGINT; VAR buf: ARRAY OF CHAR; VAR index: LONGINT): LONGINT;
VAR
ret: LONGINT;
count: LONGINT;
BEGIN
ret := 0;
count := 0;
WHILE count < n DO
ret := ret * 2;
IF ( 7 - ( index MOD 8 ) ) IN SYSTEM.VAL( SET, buf[index DIV 8] ) THEN
INC(ret)
END;
INC( index );
INC( count )
END;
index := index - count;
RETURN ret
END ShowBitsSlow;
PROCEDURE ShowBits*( n: LONGINT; VAR buf: ARRAY OF CHAR; VAR index: LONGINT): LONGINT;
VAR
nbit: LONGINT;
posInLONGINT: LONGINT;
bufa, bufb: LONGINT;
temp: LONGINT;
bufAdr: LONGINT;
BEGIN
bufAdr := SYSTEM.ADR( buf[0] );
posInLONGINT := index MOD 32;
nbit := ( posInLONGINT+ n ) - 32;
IF nbit > 0 THEN
temp := SYSTEM.LSH( index - posInLONGINT , -3 ) + bufAdr;
bufa := Machine.ChangeByteOrder( SYSTEM.GET32( temp ) );
bufb := Machine.ChangeByteOrder( SYSTEM.GET32( temp + 4 ) );
temp := SYSTEM.LSH( SYSTEM.LSH( bufa, posInLONGINT ), nbit - posInLONGINT );
RETURN SYSTEM.VAL( LONGINT, SYSTEM.VAL( SET, SYSTEM.LSH( bufb, nbit - 32 ) ) + SYSTEM.VAL( SET, temp ) )
ELSE
bufa := Machine.ChangeByteOrder( SYSTEM.GET32( SYSTEM.LSH( index - posInLONGINT, -3 ) + bufAdr ) );
RETURN SYSTEM.LSH( SYSTEM.LSH( bufa, posInLONGINT ), n - 32 )
END;
END ShowBits;
PROCEDURE ShowBitsByteAligned*(n: LONGINT; VAR buf: ARRAY OF CHAR; VAR index: LONGINT): LONGINT;
VAR
count: LONGINT;
ret: LONGINT;
BEGIN
count := 8 - ( index MOD 8 );
IF count = 8 THEN
IF ShowBits(8, buf, index) = 7FH THEN
count := 8
ELSE
count := 0
END;
END;
index := index + count;
ret := ShowBits(n, buf, index);
index := index - count;
RETURN ret
END ShowBitsByteAligned;
PROCEDURE GetBits*( n: LONGINT; VAR buf: ARRAY OF CHAR; VAR index: LONGINT): LONGINT;
VAR
ret: LONGINT;
BEGIN
ret := ShowBits(n, buf, index);
SkipBits(n, index);
RETURN ret
END GetBits;
PROCEDURE SkipBits*(n: LONGINT; VAR index: LONGINT );
BEGIN
index := index + n
END SkipBits;
PROCEDURE Factory*() : AOC.AVDemultiplexer;
VAR p: AVIDemux;
BEGIN
NEW(p);
RETURN p
END Factory;
END AVI.