1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390 |
- MODULE AVI;
- (* Procedures to read an .avi file *)
- (* Written by Thomas Trachsel, ttrachsel@web.de, 18.9.2003 *)
- (* Extended with indexfunctionality and adaptation on Codecs by Urs Müller, October 2004 *)
- (* Cleaned by PL, March 2005 *)
- IMPORT
- SYSTEM, Machine, Streams, KernelLog, AOC := Codecs;
- CONST
- Debug = FALSE;
- DefaultReaderSize = 4096;
- WriteError = 2907;
- (* Steht jetzt einmal hier, kann man vielleicht in AVIDemux reinpacken, mal schauen *)
- TYPE
- (* Structure that contains the main informations of the .avi file *)
- 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;
- (* Structure that contains the main Info of a stream in a .avi file *)
- 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;
- (* video stream specific infos *)
- 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;
- (* audio stream specific infos *)
- WAVEFormatEx* = OBJECT
- VAR
- formatTag*: LONGINT;
- channels*: LONGINT;
- samplesPerSec*: LONGINT;
- avgBytesPerSec*: LONGINT;
- blockAlign*: LONGINT;
- bitsPerSample*: LONGINT;
- cbSize*: LONGINT;
- END WAVEFormatEx;
- (* IndexChunk infos *)
- AVIIndexEntry* = RECORD
- ckid*: LONGINT;
- flags*: LONGINT;
- offset*: LONGINT;
- length*: LONGINT;
- tot*: LONGINT;
- END;
- TYPE IndexArrayPointer* = POINTER TO ARRAY OF AVIIndexEntry;
- (* Stream for reading a Stream of an .avi file *)
- TYPE AVIStream* = OBJECT(AOC.DemuxStream)
- VAR
- bufAdr: LONGINT;
- r : Streams.Reader;
- chunkSize*: LONGINT; (* Bytes in actual AVI Chunk *)
- streamHeader: AVIStreamHeader;
- stuffByte*: LONGINT;
- eof*: BOOLEAN; (* End of File *)
- (* Constructor *)
- 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;
- (* Returns TRUE if the underlying reader supports seeking. *)
- PROCEDURE CanSetPos*() : BOOLEAN;
- BEGIN
- RETURN r.CanSetPos();
- END CanSetPos;
- (* Compare two array up to len bytes *)
- 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;
- (* Seek the next chunk of our stream in the avi file and read it *)
- 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;
- (* Undocument in .avi docu; if the size of a chunk is odd, we have to skip one byte *)
- 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
- (* We found the correct chunk *)
- IF len > 0 THEN
- done := TRUE;
- bufAdr := ADDRESSOF( 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;
- (* Go to the beginnig of the next frame -> Read next chunk *)
- PROCEDURE Resynch*(VAR buf: ARRAY OF CHAR): BOOLEAN;
- BEGIN
- ReadNextChunk(buf);
- RETURN ~eof
- END Resynch;
- (* Return Pos in Avi File, relativ to the beginning of the stream data *)
- PROCEDURE Pos*(): Streams.Position;
- BEGIN
- RETURN r.Pos()
- END Pos;
- (* Set the Position of the AVIReader. If frame flag is set, position is interpreted as a framenumber *)
- 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;
- (* Set Byte Position *)
- PROCEDURE SetPos*(pos : Streams.Position);
- 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;
- (* The .avi File Demultiplexer *)
- AVIDemux* = OBJECT(AOC.AVDemultiplexer)
- VAR
- r : Streams.Reader;
- filename* : ARRAY 256 OF CHAR;
- (* We need just these 3 Headers *)
- 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 : WORD);
- 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; (* bad bad bad *)
- END Open;
- PROCEDURE GetAVIHeader*(): MainAVIHeaderDesc;
- BEGIN
- RETURN aviHeader
- END GetAVIHeader;
- (* Compare two arrays up to len bytes *)
- 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;
- (* Read .avi FIle Header *)
- 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);
- (* Check, if we have a valid avi file *)
- 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;
- (* Read AVI Headers *)
- REPEAT
- r.Bytes( buf,0,4, len );
- IF CompareCharArrays( buf, "LIST",4 ) THEN
- (* We found an additional Header *)
- (* Store Infos about header *)
- r.RawLInt(headerLength);
- headerLength := headerLength + headerLength MOD 2;
- headerBeginPos := r.Pos();
- r.Bytes( buf,0,4, len );
- (* Main AVI Header *)
- IF CompareCharArrays(buf, "hdrl",4) THEN
- r.Bytes( buf,0,4, len );
- IF CompareCharArrays(buf, "avih",4) THEN
- aviHeader := ReadMainAVIHeader()
- ELSE
- SkipHeader()
- END;
- (* Stream Header *)
- 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); (* Skip "strf" *)
- 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
- (* movie data begin, including movi Tag *)
- movieBeginPos := r.Pos()-4;
- (* this could be improved... *)
- r.SetPos(headerLength+movieBeginPos); (* headerLength); *)
- r.Bytes(buf,0,4,len);
- IF CompareCharArrays(buf, "idx1",4) THEN
- (* There is an index *)
- (* Start of Index including idx1 Tag *)
- 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
- (* Unknown Header -> Skip *)
- 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;
- (* Noch ueberlegen: BOOLEAN Rueckgabe, wenn kein Index dann False *)
- 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;
- (* Not shure, wether this is necessary - but everything works fine with it *)
- 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);
- (* Index from start of File*)
- 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;
- (* now go on according to indexType *)
- IF idxType = 0 THEN
- KernelLog.String("File without index: Not supported yet");
- (* And trap here ... *)
- END;
- (* The 0 case: no index. It is possible to generate an index b y traversing the whole file *)
- (* For now we simply declare the file as not seekable *)
- IF idxType # 0 THEN
- nai := 0;
- nvi := 0;
- r.SetPos(indexStart);
- i := 0;
- (* Count, how many entries there are (the number would also be in the header, *)
- (* but if there is no index, you have to do this anyway) *)
- 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);
- (* Vielleicht haben wir ja nur Bilder... *)
- IF (audioChunks > 0) THEN
- NEW(audioIndex, nai);
- END;
- (* So, und jetzt die Arrays fuellen *)
- 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;
- (* Skip chunk *)
- PROCEDURE SkipHeader*;
- VAR
- length: LONGINT;
- BEGIN
- r.RawLInt(length);
- r.SkipBytes( length + length MOD 2)
- END SkipHeader;
- (* Read Main AVI Header *)
- 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] );
- (* Skip Bytes if we have still available *)
- IF r.Pos() - startPos < headerLength THEN
- r.SkipBytes( headerLength - ( r.Pos() - startPos ) )
- END;
- RETURN aviHeader;
- END ReadMainAVIHeader;
- (* Read Header of this avi Stream *)
- 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;
- (* Skio Bytes if we have still available *)
- IF r.Pos() - startPos < headerLength THEN
- r.SkipBytes( headerLength - ( r.Pos() - startPos ) )
- END;
- RETURN header
- END ReadAVIStreamHeader;
- (* Read BitMapInfo Structure *)
- 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;
- (* Read WaveFormatEX Structure *)
- 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;
- (* Write Avi Headers to KernelLog *)
- 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;
- (* Write AVI video index to Kernel Log *)
- 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;
- (* Write AVI audio index to Kernel Log *)
- 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;
- (* Return AudioStreamHeader *)
- PROCEDURE GetAudioStreamHeader*(): AVIStreamHeader;
- BEGIN
- RETURN audioStreamHeader
- END GetAudioStreamHeader;
- (* Return VideoStreamHeader *)
- PROCEDURE GetVideoStreamHeader*():AVIStreamHeader;
- BEGIN
- RETURN videoStreamHeader
- END GetVideoStreamHeader;
- (* Muss noch generischer werden *)
- PROCEDURE GetStream*(streamNr: LONGINT): AOC.DemuxStream;
- VAR
- (* reader : AVIReader; *)
- (* reader: AOC.FileInputStream; *)
- reader : Streams.Reader;
- i: LONGINT;
- streamInfo : AOC.AVStreamInfo;
- tag : ARRAY 4 OF CHAR;
- BEGIN
- reader := AOC.OpenInputStream(filename); (* should be only one reader ideally... *)
- reader.SetPos(r.Pos());
- IF streamNr = 0 THEN
- NEW(videoStream, reader, videoStreamHeader);
- videoFramePos := 0;
- (* Add streamInfo to Stream *)
- 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;
- (* Add streamInfo to Stream *)
- 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;
- (* Could be optimized, as we assume videostream beeing at index 0 and that there is only one *)
- PROCEDURE GetStreamInfo*(streamNr: LONGINT): AOC.AVStreamInfo;
- VAR streamInfo : AOC.AVStreamInfo;
- i: INTEGER;
- tag : ARRAY 4 OF CHAR;
- BEGIN
- IF streamNr = 0 THEN (* Video *)
- 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 (* Audio *)
- 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;
- (* Returns Information, which can be read out from file and which is useful/needed *)
- 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
- (* res := AOC.ResFailed; *)
- 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: WORD);
- (* PROCEDURE SetStreamPos*(streamNr, pos : LONGINT; VAR res: WORD); *)
- VAR
- n0, n1, n, spos: LONGINT;
- (* seekType, itemSize : 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 * 8 * audioStreamHeader.waveFormatEx.samplesPerSec/audioStreamHeader.rate / 1000); *)
- 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;
- (* -- Helper Procedures -- *)
- (* Align stream to next Byte *)
- PROCEDURE Align*(VAR index: LONGINT);
- BEGIN
- IF ( index MOD 8 ) # 0 THEN
- index := index - ( index MOD 8 ) + 8
- END;
- END Align;
- (* True if actual position is on byte boundary *)
- PROCEDURE IsAligned*(index: LONGINT): BOOLEAN;
- BEGIN
- IF ( index MOD 8 ) = 0 THEN
- RETURN TRUE;
- ELSE
- RETURN FALSE;
- END;
- END IsAligned;
- (* Read next n Bits (max 32), without advancing in stream. Max 32 Bits are allowed *)
- (* Very slow but portable *)
- 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;
- (* Read next n Bits (max 32), without advancing in stream. Max 32 Bits are allowed *)
- (* Fast, but im not sure if it's portable *)
- 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 := ADDRESSOF( buf[0] );
- posInLONGINT := index MOD 32;
- nbit := ( posInLONGINT+ n ) - 32;
- IF nbit > 0 THEN
- (* We have to read two 32 bit values *)
- temp := LSH( index - posInLONGINT , -3 ) + bufAdr;
- bufa := Machine.ChangeByteOrder( SYSTEM.GET32( temp ) );
- bufb := Machine.ChangeByteOrder( SYSTEM.GET32( temp + 4 ) );
- temp := LSH( LSH( bufa, posInLONGINT ), nbit - posInLONGINT );
- RETURN SYSTEM.VAL( LONGINT, SYSTEM.VAL( SET, LSH( bufb, nbit - 32 ) ) + SYSTEM.VAL( SET, temp ) )
- ELSE
- (* Reading one 32 value is sufficient *)
- bufa := Machine.ChangeByteOrder( SYSTEM.GET32( LSH( index - posInLONGINT, -3 ) + bufAdr ) );
- RETURN LSH( LSH( bufa, posInLONGINT ), n - 32 )
- END;
- END ShowBits;
- (* Show n bits, byte aligned without advancing in bit stream *)
- 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 (* Spezial case: see iso spec *)
- count := 8
- ELSE
- count := 0
- END;
- END;
- index := index + count;
- ret := ShowBits(n, buf, index);
- index := index - count;
- RETURN ret
- END ShowBitsByteAligned;
- (* Read next n Bits and advance in Bit Stream. Max 32 Bits are allowed *)
- 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;
- (* Skip Next n Bits *)
- 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.
|