...retrieve information from an AVI file?

Author: Based project of YAAI updated by Jiri Betunak
Homepage: http://yaai.sourceforge.net/

Category: Multimedia

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.

 

printed from
www.swissdelphicenter.ch
developers knowledge base