Multimedia Delphi

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 < StreamSize - 4 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 < Idx1End 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 <= 0 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 < 0 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.