Mega Code Archive

 
Categories / Delphi / Files
 

Retrieve information from an AVI file

Title: retrieve information from an AVI file? Unit AVIinfo; Interface Uses Classes, Consts, SysUtils, Windows, Math; Type FOURCC = DWORD; PropertyStrings = (prAviInfo = 2, prFileName, prFileSize, prStreams, prVideoStream, prCompression, prVidBitrate, prResolution, prColorDepth, prRunningTime, prFrameRate, prMsPerFrame, prFrames, prKeyFrames, prAudioStream, prWaveType, prAudBitrate, prSamplerate, prBitDepth, prChannels, prAudioDelay); TagInfo = Record Name: String; // Name of the tag Position, Size: Int64; // Position to Size of this ta int64 End; TMainAVIHeader = Packed Record dwMicroSecPerFrame: DWORD; // frame display rate (or 0L) dwMaxBytesPerSec: DWORD; // max. transfer rate dwPaddingGranularity: DWORD; // pad to multiples of this // size; normally 2K. dwFlags: DWORD; // the ever-present flags dwTotalFrames: DWORD; // # frames in file dwInitialFrames: DWORD; dwStreams: DWORD; dwSuggestedBufferSize: DWORD; dwWidth: DWORD; dwHeight: DWORD; dwReserved: Array[0..3] Of DWORD; End; TAVIStreamHeader = Packed Record fccType: FOURCC; fccHandler: FOURCC; dwFlags: DWORD; // Contains AVITF_* flags wPriority: WORD; wLanguage: WORD; dwInitialFrames: DWORD; dwScale: DWORD; dwRate: DWORD; // dwRate / dwScale == samples/second dwStart: DWORD; dwLength: DWORD; // In units above... dwSuggestedBufferSize: DWORD; dwQuality: DWORD; dwSampleSize: DWORD; rcFrame: TRECT; End; WAVEFORMATEX = Packed Record wFormatTag: Word; { format type } nChannels: Word; { number of channels (i.e. mono, stereo, etc.) } nSamplesPerSec: DWORD; { sample rate } nAvgBytesPerSec: DWORD; { for buffer estimation } nBlockAlign: Word; { block size of data } wBitsPerSample: Word; cbSize: Word; End; TAuthorInfo = Record Artist, Comment, Copyright, Name, Product, Source, Subject, DisplayName, Genre, Language, Software: String; End; TBackup = Record AviH: TMainAVIHeader; VidSH: TAVIStreamHeader; AudSH: TAVIStreamHeader; End; EAviInfoError = Class(Exception); TAviStreamInfo = Class(TObject) Private fAviHeader: TMainAviHeader; fVideoStreamHeader: TAviStreamHeader; fVideoStreamFormat: BitmapInfoHeader; fAudioStreamHeader: TAviStreamHeader; fAudioStreamFormat: WaveformatEx; fHasVideo: Boolean; fHasAudio: Boolean; fFrameRate: Double; fRunningTime: Double; fAuthorInfo: TAuthorInfo; fKeyFrames: DWord; fVideoBitrate: Double; fAudioBitrate: Double; fSize: Int64; fAudioDelay: Double; fChanged: Boolean; PropertyStringList: TStringList; Protected TagList: Record Count, Idx1Pos, MoviPos, InfoPos, VidsPos, AudsPos, AvihPos: Byte; Tags: Array[0..40] Of TagInfo; End; Backup: TBackup; AviStream: TStream; Procedure CreateTagList(AStream: TStream); Procedure ParseTagList(AStream: TStream); Procedure CalcKeyFrames(AStream: TStream); Procedure FillPropertyString; Procedure FillPropertyStringNoDescription; Function TimeToShortString(myTime: Double): String; Procedure SetAuthorInfo(Value: TAuthorInfo); Virtual; Procedure SetFrameRate(Value: Double); Virtual; Procedure SetAudioDelay(Value: Double); Virtual; // CheckAVI should make sure before altering the AVI that it's the same // file/stream that was used with LoadAVI // Implement it if you need to use TAviStreamInfo, // currently it always returns false. Function CheckAVI(AStream: TStream): Boolean; Public Constructor Create; Destructor Destroy; Override; // procedure LoadAVI(AStream: TStream); Procedure LoadAVI(AStream: TStream; Description: Boolean); Procedure UndoChanges; Procedure SaveToFile(aFilename: TFileName); Procedure SaveToStream(AStream: TStream); Function PropertyString(pr: PropertyStrings): String; Property AviHeader: TMainAviHeader Read fAviHeader; Property VideoStreamHeader: TAviStreamHeader Read fVideoStreamHeader; Property VideoStreamFormat: BitmapInfoHeader Read fVideoStreamFormat; Property AudioStreamHeader: TAviStreamHeader Read fAudioStreamHeader; Property AudioStreamFormat: WaveFormatEx Read fAudioStreamFormat; Property HasVideo: Boolean Read fHasVideo; Property HasAudio: Boolean Read fHasAudio; Property FrameRate: Double Read fFrameRate Write SetFrameRate; Property RunningTime: Double Read fRunningTime; Property KeyFrames: DWord Read fKeyFrames; Property VideoBitrate: Double Read fVideoBitrate; Property AudioBitrate: Double Read fAudioBitrate; Property AudioDelay: Double Read fAudioDelay Write SetAudioDelay; Property AuthorInfo: TAuthorInfo Read fAuthorInfo Write SetAuthorInfo; Property Size: Int64 Read fSize; Property Changed: Boolean Read fChanged; Published End; TAviFileInfo = Class(TAviStreamInfo) Private Protected fAviFile: TFileName; Function CheckAVI(Const Filename: String): Boolean; Procedure SetAuthorInfo(Value: TAuthorInfo); Override; Procedure SetFrameRate(Value: Double); Override; Procedure SetAudioDelay(Value: Double); Override; Public Procedure UndoChanges; Property AviFile: TFileName Read fAviFile; Procedure LoadAVI(Const FileName: TFilename; Description: Boolean); // procedure LoadAVI(const FileName: TFileName); End; Function fcc2String(fcc: FourCC): String; Function Wavetype2String(WaveType: Word): String; Function CodecIdent2String(fcc: FourCC): String; Implementation // ********************************** // ** USEFUL MAKROS // ********************************** Function fcc2String(fcc: FourCC): String; Var Buffer: Array[0..3] Of Char; Begin Move(fcc, Buffer, SizeOf(Buffer)); Result := Buffer; End; Function GetStringFromResource(Name: String): String; Begin With TResourceStream.Create(HInstance, Name, RT_RCDATA) Do Try SetLength(Result, Size); Read(Result[1], Size); Finally Free; End; End; Function Wavetype2String(WaveType: Word): String; Var StrLst: TStringList; I, P: Integer; S: String; Begin StrLst := TStringList.Create; Try StrLst.Text := GetStringFromResource('AudioCodecs'); For i := 0 To StrLst.Count - 1 Do Begin S := StrLst[i]; // TStrings.NameValueSeperator property isn't there on D6 or lower, // So i just use '=' here (as this is the default). // P := AnsiPos(StrLst.NameValueSeparator, S); P := AnsiPos('=', S); If P 0 Then Begin If WaveType = StrToInt(Copy(S, 1, P - 1)) Then Begin // Again, ValueFromIndex doesn't seem to be there on D6 or lower. // Result:=StrLst.ValueFromIndex[i]; Result := StrLst.Values[StrLst.Names[i]]; Exit; End; End; End; Finally StrLst.Free; End; End; Function CodecIdent2String(fcc: FourCC): String; Var Codec: String; S: TStringList; Begin Result := ''; Codec := Fcc2String(Fcc); S := TStringList.Create; Try S.Text := GetStringFromResource('VideoCodecs'); Result := S.Values[Codec]; Finally S.Free; End; If Result = '' Then Result := 'Unknown'; End; { TAviFileInfo } Function TAviFileInfo.CheckAVI(Const Filename: String): Boolean; Begin Result := (Filename = fAviFile); End; Procedure TAviFileInfo.LoadAVI(Const FileName: TFilename; Description: Boolean); Var tempStream: TFileStream; Begin fAviFile := FileName; tempStream := TFileStream.Create(Filename, fmOpenRead Or fmShareDenyWrite); Try Inherited LoadAVI(tempStream, Description); Finally tempstream.Free; End; PropertyStringList[ord(prFileName)] := StringReplace(PropertyStringList[ord(prFileName)], 'None [Loaded from Stream]', ExtractFileName(FileName), []); End; Procedure TAviFileInfo.SetAudioDelay(Value: Double); Var tempStream: TFileStream; Begin tempStream := TFileStream.Create(fAviFile, fmOpenReadWrite Or fmShareDenyWrite); Try AviStream := tempStream; Inherited SetAudioDelay(Value); Finally tempstream.Free; End; End; Procedure TAviFileInfo.SetAuthorInfo(Value: TAuthorInfo); Var tempStream: TFileStream; Begin tempStream := TFileStream.Create(fAviFile, fmOpenReadWrite Or fmShareDenyWrite); Try AviStream := tempStream; Inherited SetAuthorInfo(Value); Finally tempstream.Free; End; End; Procedure TAviFileInfo.SetFrameRate(Value: Double); Var tempStream: TFileStream; Begin tempStream := TFileStream.Create(fAviFile, fmOpenReadWrite Or fmShareDenyWrite); Try AviStream := tempStream; Inherited SetFrameRate(Value); Finally tempstream.Free; End; End; Procedure TAviFileInfo.UndoChanges; Var tempStream: TFileStream; Begin tempStream := TFileStream.Create(fAviFile, fmOpenReadWrite Or fmShareExclusive); Try AviStream := tempStream; Inherited UndoChanges; Finally tempstream.Free; End; End; { TAviStreamInfo } Procedure TAviStreamInfo.UndoChanges; Begin // AStream.Seek(0,soBeginning); // AStream.Write(BackupHdr,sizeof(BackupHdr)); AviStream.Seek(TagList.Tags[TagList.AudsPos].Position + 4, soBeginning); AviStream.WriteBuffer(BackUp.AudSH, SizeOf(BackUp.AudSH)); AviStream.Seek(TagList.Tags[TagList.VidsPos].Position + 4, soBeginning); AviStream.WriteBuffer(BackUp.VidSH, SizeOf(BackUp.VidSH)); AviStream.Seek(TagList.Tags[TagList.AvihPos].Position + 16, soBeginning); AviStream.WriteBuffer(BackUp.AviH, SizeOf(BackUp.AviH)); End; Procedure TAviStreamInfo.LoadAVI(AStream: TStream; Description: Boolean); Begin fSize := AStream.Size; fChanged := false; AviStream := AStream; CreateTagList(AStream); // Fill the array TagList // It contains the positions of the // tags in the file. ParseTagList(AStream); // Interpret the TagList and fill // the public properties with the info CalcKeyFrames(AStream); If Description Then FillPropertyString Else FillPropertyStringNoDescription; End; Procedure TAviStreamInfo.CreateTagList(AStream: TStream); Var Code: String; ChunkSize: DWord; StreamSize, ChunkPos: Int64; Buffer: Array[0..3] Of Char; Begin StreamSize := Astream.Size; // Astream.Size is a // property - Slower AStream.Seek(0, soBeginning); TagList.Count := 0; While Astream.Position Do Begin AStream.Read(Buffer, Sizeof(Buffer)); ChunkPos := Astream.Position; Code := AnsiUpperCase(Buffer); {-GENRE,,} If (Code = 'INFO') Or (Code = 'AVIH') Or (Code = 'IART') Or (Code = 'ICMT') Or (Code = 'ICOP') Or (Code = 'INAM') Or (Code = 'IPRD') Or (Code = 'ISBJ') Or (Code = 'ISRC') Or (Code = 'STRF') Or (Code = 'DISP') Or (Code = 'STRH') Or (Code = 'STRD') Or (Code = 'MOVI') Or (Code = 'IDX1') Or (Code = 'JUNK') Or (Code = 'PRMI') Or (Code = 'LIST') Or (Code = 'IGNR') Or (Code = 'ILNG') Or (Code = 'ISFT') Then Begin AStream.Read(ChunkSize, Sizeof(ChunkSize)); If Code = 'MOVI' Then Begin AStream.Seek(-12, soCurrent); AStream.Read(ChunkSize, Sizeof(ChunkSize)); AStream.Seek(ChunkSize, soCurrent); End; If Code = 'INFO' Then Begin AStream.Seek(-12, soCurrent); AStream.Read(ChunkSize, Sizeof(ChunkSize)); AStream.Seek(4, soCurrent); End; If (Code = 'JUNK') Or (Code = 'DISP') Or (Code = 'IDX1') Then AStream.Seek(ChunkSize, soCurrent); TagList.Tags[TagList.Count].Name := Code; TagList.Tags[TagList.Count].Position := ChunkPos; TagList.Tags[TagList.Count].Size := ChunkSize; Inc(TagList.Count); End Else Begin AStream.Seek(-3, soCurrent); End; End; End; Procedure TAviStreamInfo.ParseTagList(AStream: TStream); Function ReadAuthorInfo(AStream: TStream; i: Byte): AnsiString; Var BigBuffer: Array[0..2147] Of Char; //2147 InfoSize: LongInt; s, sc: String; ii: Integer; Begin AStream.Seek(TagList.Tags[i].Position, soBeginning); InfoSize := AStream.Read(BigBuffer, Min(TagList.Tags[i].Size + 3, Sizeof(BigBuffer))); s := ''; For ii := 1 To InfoSize - 1 Do Begin sc := BigBuffer[ii]; If sc #0 Then s := s + sc; End; Result := s; //Copy(s, 0, InfoSize); End; Var i: byte; Code: String; StreamHeader: TAviStreamHeader; Begin For i := 0 To TagList.Count Do Begin If TagList.Tags[i].Name = 'AVIH' Then Begin AStream.Seek(TagList.Tags[i].Position + 4, soBeginning); AStream.Read(fAviHeader, Sizeof(fAviHeader)); End; If TagList.tags[i].Name = 'STRH' Then Begin AStream.Seek(TagList.Tags[i].Position + 4, soBeginning); AStream.Read(StreamHeader, SizeOf(StreamHeader)); Code := AnsiUpperCase(fcc2String(StreamHeader.fccType)); If code = 'VIDS' Then Begin fHasVideo := true; TagList.VidsPos := i; fVideoStreamHeader := StreamHeader; fFrameRate := StreamHeader.dwRate / StreamHeader.dwScale; fRunningTime := AviHeader.dwTotalFrames / FrameRate; AStream.Read(fVideoStreamFormat, Sizeof(fVideoStreamFormat)); End; If code = 'AUDS' Then Begin fHasAudio := true; TagList.AudsPos := i; fAudioStreamHeader := StreamHeader; AStream.Read(fAudioStreamFormat, Sizeof(fAudioStreamFormat)); End; End; // Ende STRH If TagList.tags[i].Name = 'IART' Then //director fAuthorInfo.Artist := ReadAuthorInfo(AStream, i); If TagList.tags[i].Name = 'ICMT' Then fAuthorInfo.Comment := ReadAuthorInfo(AStream, i); If TagList.tags[i].Name = 'ICOP' Then //CPYRIGHT fAuthorInfo.Copyright := ReadAuthorInfo(AStream, i); If TagList.tags[i].Name = 'INAM' Then //title fAuthorInfo.Name := ReadAuthorInfo(AStream, i); If TagList.tags[i].Name = 'IPRD' Then //product fAuthorInfo.Product := ReadAuthorInfo(AStream, i); If TagList.tags[i].Name = 'ISRC' Then fAuthorInfo.Source := ReadAuthorInfo(AStream, i); If TagList.tags[i].Name = 'ISBJ' Then //SUBJECT fAuthorInfo.Subject := ReadAuthorInfo(AStream, i); If TagList.tags[i].Name = 'DISP' Then fAuthorInfo.DisplayName := ReadAuthorInfo(AStream, i); {________} If TagList.tags[i].Name = 'IGNR' Then //genre fAuthorInfo.Genre := ReadAuthorInfo(AStream, i); If TagList.tags[i].Name = 'ILNG' Then //lang fAuthorInfo.Language := ReadAuthorInfo(AStream, i); If TagList.tags[i].Name = 'ISFT' Then //software fAuthorInfo.Software := ReadAuthorInfo(AStream, i); {________} If TagList.Tags[i].Name = 'IDX1' Then TagList.Idx1Pos := i; If TagList.Tags[i].Name = 'INFO' Then TagList.InfoPos := i; If TagList.Tags[i].Name = 'MOVI' Then TagList.MoviPos := i; End; fAudioDelay := (AudioStreamHeader.dwStart * AudioStreamHeader.dwScale / AudioStreamHeader.dwRate) - (VideoStreamHeader.dwStart / FrameRate); // Backup Everything BackUp.AviH := AviHeader; Backup.VidSH := VideoStreamHeader; Backup.AudSH := AudioStreamHeader; End; Constructor TAviStreamInfo.Create; Begin fHasVideo := false; fHasAudio := false; fChanged := false; PropertyStringList := TStringList.Create; End; Procedure TAviStreamInfo.CalcKeyFrames(AStream: TStream); Var Idx1End, BytesRead: Int64; Keyfr: LongInt; Buffer: Array[1..2048] Of byte; i: word; VidStreamSize, AudStreamSize: Dword; Begin KeyFr := 0; VidStreamSize := 0; AudStreamSize := 0; AStream.Seek(TagList.Tags[TagList.Idx1Pos].Position + 4, soBeginning); Idx1End := TagList.Tags[TagList.Idx1Pos].Size + TagList.Tags[TagList.Idx1Pos].Position + 4; While AStream.Position Do Begin // Sorry for this terrible type of code, but // reading big chunks is considerably faster // than getting small chunks. BytesRead := AStream.Read(Buffer, Sizeof(Buffer)) Div 16 - 1; For i := 0 To BytesRead Do Begin // 00 is normally the video stream If (Buffer[1 + 16 * i] = Ord('0')) And (Buffer[2 + 16 * i] = Ord('0')) Then Begin // keyframe flag set? If ((Buffer[5 + 16 * i] And $10) 0) Then Begin Inc(Keyfr); End; VidStreamSize := VidStreamSize + Buffer[13 + i * 16] + Buffer[14 + i * 16] * $100 + Buffer[15 + i * 16] * $10000 + Buffer[16 + i * 16] * $1000000; End; // 01 is the audio stream If (Buffer[1 + 16 * i] = Ord('0')) And (Buffer[2 + 16 * i] = Ord('1')) Then AudStreamSize := AudStreamSize + Buffer[13 + i * 16] + Buffer[14 + i * 16] * $100 + Buffer[15 + i * 16] * $10000 + Buffer[16 + i * 16] * $1000000; End; End; fKeyframes := KeyFr; fVideoBitrate := VidStreamSize * FrameRate / (125 * AviHeader.dwTotalFrames); fAudioBitrate := AudStreamSize * FrameRate / (125 * AviHeader.dwTotalFrames); End; Function TAviStreamInfo.CheckAVI(AStream: TStream): Boolean; Begin // Donno what to do here, perhaps compare the first 8 Kb with BackupHdr. // Just a dummy function for CheckAVI in TAviFileInfo. // If you want to use TAviStreamInfo implement this function! Result := false; End; Procedure TAviStreamInfo.SetAuthorInfo(Value: TAuthorInfo); Begin // yet to implement End; Procedure TAviStreamInfo.SetFrameRate(Value: Double); Begin // Check here if AviStream is still valid If Value Then Raise EAviInfoError.Create('Framerate can''t set the framerate to a negative value. (' + FloatToStr(Value) + ')'); fChanged := true; fVideoStreamHeader.dwScale := 10000; fVideoStreamHeader.dwRate := Round(Value * fVideoStreamHeader.dwScale); fAviHeader.dwMicroSecPerFrame := Round(fVideoStreamHeader.dwScale / fVideoStreamHeader.dwRate * 1000000); AviStream.Seek(TagList.Tags[TagList.VidsPos].Position + 4, soBeginning); AviStream.WriteBuffer(fVideoStreamHeader, SizeOf(fVideoStreamHeader)); AviStream.Seek(TagList.Tags[TagList.AvihPos].Position + 16, soBeginning); AviStream.WriteBuffer(fAviHeader, SizeOf(fAviHeader)); fFrameRate := Value; End; Procedure TAviStreamInfo.SetAudioDelay(Value: Double); Begin fChanged := true; If Value = 0 Then Begin // The following is something as an "Audio Framerate": // AudioStreamHeader.dwRate/AudioStreamHeader.dwScale fAudioStreamHeader.dwStart := Round(Value * AudioStreamHeader.dwRate / AudioStreamHeader.dwScale); fVideoStreamHeader.dwStart := 0; End; If Value Then Begin fAudioStreamHeader.dwStart := 0; fVideoStreamHeader.dwStart := -Round(Value * FrameRate); End; AviStream.Seek(TagList.Tags[TagList.AudsPos].Position + 4, soBeginning); AviStream.WriteBuffer(fAudioStreamHeader, SizeOf(fAudioStreamHeader)); AviStream.Seek(TagList.Tags[TagList.VidsPos].Position + 4, soBeginning); AviStream.WriteBuffer(fVideoStreamHeader, SizeOf(fVideoStreamHeader)); fAudioDelay := Value; End; {____________________________________________} Procedure TAviStreamInfo.FillPropertyStringNoDescription; Begin PropertyStringList.Clear; PropertyStringList.Add('Yet Another Avi Info (YAAI) Output File'); PropertyStringList.Add('visit http://yaai.sourceforge.net/ for more information'); PropertyStringList.Add('AVI Information'); PropertyStringList.Add(' None [Loaded from Stream]'); PropertyStringList.Add(IntToStr(Size) + ' Bytes (' + Floattostrf(Size / 1048576, ffFixed, 15, 2) + ' MB)'); PropertyStringList.Add(IntToStr(AviHeader.dwStreams)); If HasVideo Then Begin PropertyStringList.Add('Video Stream'); PropertyStringList.Add(fcc2String(VideoStreamHeader.fccHandler) + ' - ' + CodecIdent2String(VideostreamHeader.fccHandler)); PropertyStringList.Add(FloatToStrF(VideoBitrate, ffFixed, 15, 2) + ' kbit/s'); PropertyStringList.Add(IntToStr(AviHeader.dwWidth) + 'x' + IntToStr(AviHeader.dwHeight)); PropertyStringList.Add(IntToStr(VideoStreamFormat.biBitCount) + ' bits'); PropertyStringList.Add(FloatToStrF(RunningTime, ffFixed, 15, 2) + ' s (' + TimeToShortString(RunningTime) + ')'); // 86400 = Seconds / Day PropertyStringList.Add(FloatToStrF(FrameRate, ffFixed, 15, 4) + ' fps'); PropertyStringList.Add( IntToStr(AviHeader.dwMicroSecPerFrame) + ' ms'); PropertyStringList.Add( IntToStr(AviHeader.dwTotalFrames)); PropertyStringList.Add(IntToStr(KeyFrames) + ' (Every ' + IntToStr(AviHeader.dwTotalFrames Div Keyframes) + ')'); End Else Begin PropertyStringList.Add('No Video Stream Found!'); PropertyStringList.Add('-'); PropertyStringList.Add('-'); PropertyStringList.Add('-'); PropertyStringList.Add('-'); PropertyStringList.Add('-'); PropertyStringList.Add('-'); PropertyStringList.Add('-'); PropertyStringList.Add('-'); PropertyStringList.Add('-'); End; If HasAudio Then Begin PropertyStringList.Add('Audio Stream'); PropertyStringList.Add( IntToStr(AudioStreamFormat.wFormatTag) + ' - ' + WaveType2String(AudioStreamFormat.wFormatTag)); PropertyStringList.Add(FloatToStrF(AudioBitrate, ffFixed, 15, 2) + ' kbit/s'); PropertyStringList.Add(IntToStr(AudioStreamFormat.nSamplesPerSec) + ' Hz'); PropertyStringList.Add(IntToStr(AudioStreamFormat.wBitsPerSample) + ' Bits'); PropertyStringList.Add(IntToStr(AudioStreamFormat.nChannels)); PropertyStringList.Add(FloatToStrF(AudioDelay, ffFixed, 15, 2) + ' s'); End Else Begin PropertyStringList.Add('No Audio Stream Found!'); PropertyStringList.Add('-'); PropertyStringList.Add('-'); PropertyStringList.Add('-'); PropertyStringList.Add('-'); PropertyStringList.Add('-'); PropertyStringList.Add('-'); End; PropertyStringList.Add('Author Details'); PropertyStringList.Add(AuthorInfo.Artist); PropertyStringList.Add(AuthorInfo.Comment); PropertyStringList.Add(AuthorInfo.Copyright); PropertyStringList.Add(AuthorInfo.Name); PropertyStringList.Add(AuthorInfo.Product); PropertyStringList.Add(AuthorInfo.Source); PropertyStringList.Add(AuthorInfo.Subject); PropertyStringList.Add(AuthorInfo.DisplayName); PropertyStringList.Add(AuthorInfo.Genre); PropertyStringList.Add(AuthorInfo.Language); PropertyStringList.Add(AuthorInfo.Software); End; Procedure TAviStreamInfo.FillPropertyString; Begin PropertyStringList.Clear; PropertyStringList.Add('Yet Another Avi Info (YAAI) Output File'); PropertyStringList.Add('visit http://yaai.sourceforge.net/ for more information'); PropertyStringList.Add('AVI Information'); PropertyStringList.Add(' Filename: None [Loaded from Stream]'); PropertyStringList.Add(' Filesize: ' + IntToStr(Size) + ' Bytes (' + Floattostrf(Size / 1048576, ffFixed, 15, 2) + ' MB)'); PropertyStringList.Add(' Streams (i.e. Video, Audio): ' + IntToStr(AviHeader.dwStreams)); If HasVideo Then Begin PropertyStringList.Add('Video Stream'); PropertyStringList.Add(' Compression: ' + fcc2String(VideoStreamHeader.fccHandler) + ' - ' + CodecIdent2String(VideostreamHeader.fccHandler)); PropertyStringList.Add(' Avg. Bitrate: ' + FloatToStrF(VideoBitrate, ffFixed, 15, 2) + ' kbit/s'); PropertyStringList.Add(' Resolution: ' + IntToStr(AviHeader.dwWidth) + 'x' + IntToStr(AviHeader.dwHeight)); PropertyStringList.Add(' Color Depth: ' + IntToStr(VideoStreamFormat.biBitCount) + ' bits'); PropertyStringList.Add(' Running Time: ' + FloatToStrF(RunningTime, ffFixed, 15, 2) + ' s (' + TimeToShortString(RunningTime) + ')'); PropertyStringList.Add(' Framerate: ' + FloatToStrF(FrameRate, ffFixed, 15, 4) + ' fps'); PropertyStringList.Add(' Microseconds Per Frame: ' + IntToStr(AviHeader.dwMicroSecPerFrame) + ' ms'); PropertyStringList.Add(' Frames: ' + IntToStr(AviHeader.dwTotalFrames)); PropertyStringList.Add(' Keyframes: ' + IntToStr(KeyFrames) + ' (Every ' + IntToStr(AviHeader.dwTotalFrames Div Keyframes) + ')'); End Else Begin PropertyStringList.Add('No Video Stream Found!'); PropertyStringList.Add(' Compression: -'); PropertyStringList.Add(' Avg. Bitrate: -'); PropertyStringList.Add(' Resolution: -'); PropertyStringList.Add(' Color Depth: -'); PropertyStringList.Add(' Running Time: -'); PropertyStringList.Add(' Framerate: -'); PropertyStringList.Add(' Microseconds Per Frame: -'); PropertyStringList.Add(' Frames: -'); PropertyStringList.Add(' Keyframes: -'); End; If HasAudio Then Begin PropertyStringList.Add('Audio Stream'); PropertyStringList.Add(' Wave Type: ' + IntToStr(AudioStreamFormat.wFormatTag) + ' - ' + WaveType2String(AudioStreamFormat.wFormatTag)); PropertyStringList.Add(' Avg. Bitrate: ' + FloatToStrF(AudioBitrate, ffFixed, 15, 2) + ' kbit/s'); PropertyStringList.Add(' Sample Rate: ' + IntToStr(AudioStreamFormat.nSamplesPerSec) + ' Hz'); PropertyStringList.Add(' Bit Depth: ' + IntToStr(AudioStreamFormat.wBitsPerSample) + ' Bits'); PropertyStringList.Add(' Channels: ' + IntToStr(AudioStreamFormat.nChannels)); PropertyStringList.Add(' Audio Delay: ' + FloatToStrF(AudioDelay, ffFixed, 15, 2) + ' s'); End Else Begin PropertyStringList.Add('No Audio Stream Found!'); PropertyStringList.Add(' Wave Type: -'); PropertyStringList.Add(' Avg. Bitrate: -'); PropertyStringList.Add(' Sample Rate: -'); PropertyStringList.Add(' Bit Depth: -'); PropertyStringList.Add(' Channels: -'); PropertyStringList.Add(' Audio Delay: -'); End; PropertyStringList.Add('Author Details'); PropertyStringList.Add(' Artist: ' + AuthorInfo.Artist); PropertyStringList.Add(' Comment: ' + AuthorInfo.Comment); PropertyStringList.Add(' Copyright: ' + AuthorInfo.Copyright); PropertyStringList.Add(' Name: ' + AuthorInfo.Name); PropertyStringList.Add(' Product: ' + AuthorInfo.Product); PropertyStringList.Add(' Source: ' + AuthorInfo.Source); PropertyStringList.Add(' Subject: ' + AuthorInfo.Subject); PropertyStringList.Add(' Display Name: ' + AuthorInfo.DisplayName); PropertyStringList.Add(' Genre: ' + AuthorInfo.Genre); PropertyStringList.Add(' Language: ' + AuthorInfo.Language); PropertyStringList.Add(' Software: ' + AuthorInfo.Software); End; Destructor TAviStreamInfo.Destroy; Begin If PropertyStringList Nil Then PropertyStringList.Free; Inherited Destroy; End; Function TAviStreamInfo.PropertyString(pr: PropertyStrings): String; Begin Result := trim(PropertyStringList[ord(pr)]); End; Procedure TAviStreamInfo.SaveToFile(aFilename: TFileName); Begin PropertyStringList.SaveToFile(aFilename); End; Procedure TAviStreamInfo.SaveToStream(AStream: TStream); Begin PropertyStringList.SaveToStream(aStream); End; Function TAviStreamInfo.TimeToShortString(myTime: Double): String; Var i: Dword; Begin i := Trunc(myTime); Result := IntToStr(i Mod 60) + 's'; If i = 60 Then Begin i := i Div 60; Result := IntToStr(i Mod 60) + 'm ' + Result; If i = 60 Then Begin i := i Div 60; Result := IntToStr(i Mod 60) + 'h ' + Result; End; End; End; End.