DELPHI获取flash文件的影片时长,原始尺寸,帧数等信息

2018-10-30

感谢“温柔刀客”的努力,找到一篇不错的Flash编程文章,也感谢文章的作者,解决了我一个困惑了很久的问题,呵呵~~~

unit uFlash;

interface

uses
  windows, SysUtils, Classes, Zlib;

type
  TBitWidth = Integer;
  TSWFRect = packed record
   Xmin: Integer;    // in twips
   Xmax: Integer;    // in twips
   Ymin: Integer;    // in twips
   Ymax: Integer;    // in twips
  end;

  TSWFColor = packed record
   R : Byte;
   G : Byte;
   B : Byte;
   RGB : string;
  end;

  TSWFHeader = packed record
   Signature: array[0..2] of char;
   Version: byte;
   FileLength: cardinal;
   FrameSize: TSWFRect;
   FrameRate: byte;
   FrameRateRemainder: byte;
   FrameCount: cardinal;
   BkColor : TSWFColor;
  end;

  TTagHandle   = record
   ID   : Integer;
   Length   : Integer;
   HandleLength   : Integer;
  end;
 
function GetSwfFileHeader(const FileName: string; var Header: TSWFHeader): boolean;

implementation

function ReadNBits(const Buffer; Position: longint; Count: TBitWidth): longint;
var
  I, B: longint;
begin
  Result := 0;
  B := 1 shl (Count - 1);
  for I := Position to Position + Count - 1 do
  begin
   if (PByteArray(@Buffer)^[I div 8] and (128 shr (I mod 8))) <> 0 then
   Result := Result or B;
   B := B shr 1;
  end;
end;

function ReadTagHandle(const Buffer; Position : Longint): TTagHandle;
var
  v : Smallint;
begin
  v :=   PSmallint(@PByteArray(@Buffer)^[Position])^;
  Result.ID :=   v shr 6;
  v :=   v shl 10;
  Result.Length :=   v shr 10;
  if Result.Length = $FFFFFF then
  begin
   //长tag
   Result.HandleLength :=   6;
   Result.Length :=   PInteger(@PByteArray(@Buffer)^[Position + 2])^;
  end
  else
   Result.HandleLength :=   2;
end;

function GetSwfFileHeader(const FileName: string; var Header: TSWFHeader): boolean;
const
  BuffSize = 64;
var
  Buffer: PByteArray;
  NBitsField: byte;
  Poz: longword;
  FileStream: TFileStream;
  MemStream: TMemoryStream;
  ZStream: TDecompressionStream;
  Tag : TTagHandle;
begin
  Result := False;
  if not FileExists(FileName) then
   Exit;
  FileStream := TFileStream.Create(FileName, fmOpenRead);
  try
   FileStream.Position := 0;
   if FileStream.Size > 22 then
   begin
   GetMem(Buffer, BuffSize);
   try
   FileStream.Read(Header, 8);
   if (Header.Signature = 'CWS') and (Header.Version >= 6) then
   begin
   Result := True;
   MemStream := TMemoryStream.Create;
   try
   MemStream.CopyFrom(FileStream, FileStream.Size - 8);
   MemStream.Position := 0;
   ZStream := TDecompressionStream.Create(MemStream);
   try
   ZStream.Read(Buffer^, BuffSize);
   finally
   ZStream.Free;
   end;
   finally
   MemStream.Free;
   end;
   end
   else
   begin
   FileStream.Read(Buffer^, BuffSize);
   Result := Header.Signature = 'FWS';
   end;

   if Result then
   with Header do
   begin
   Poz := 0;
   NBitsField := TBitWidth(ReadNBits(Buffer^, Poz, 5));
   Inc(Poz, 5);
   FrameSize.Xmin := Integer(ReadNBits(Buffer^, Poz, NBitsField));
   Inc(Poz, NBitsField);
   FrameSize.Xmax := Integer(ReadNBits(Buffer^, Poz, NBitsField));
   Inc(Poz, NBitsField);
   FrameSize.Ymin := Integer(ReadNBits(Buffer^, Poz, NBitsField));
   Inc(Poz, NBitsField);
   FrameSize.Ymax := Integer(ReadNBits(Buffer^, Poz, NBitsField));
   Inc(Poz, NBitsField);
   NBitsField := Poz mod 8;
   Poz := Poz div 8;
   if (NBitsField > 0) then
   Inc(Poz);
   FrameRateRemainder := Buffer^[Poz];    // 8.[8]
   FrameRate := Buffer^[Poz + 1];
   FrameCount := Buffer^[Poz + 2] or (Buffer^[Poz + 3] shl 8);
   Inc(Poz, 4);
   Tag :=   ReadTagHandle(Buffer^, poz);
   while Tag.ID <> 9 do
   begin
   Inc(Poz, Tag.Length + Tag.HandleLength);
   Tag :=   ReadTagHandle(Buffer^, Poz);
   end;
   BkColor.R := Buffer^[Poz + 2];
   BkColor.G := Buffer^[Poz + 3];
   BkColor.B := Buffer^[Poz + 4];
   BkColor.RGB :=   StringReplace(
   Format('%2x%2x%2x', [BkColor.R, BkColor.G, BkColor.B]),
   ' ', '0', [rfReplaceAll]);
   end;

   finally
   FreeMem(Buffer);
   end;
   end;
  finally
   FileStream.Free;
  end;
end;

end.

=====================

一个运行实例:

procedure TForm1.Button4Click(Sender: TObject);
var
   Head: TSWFHeader;
   Xmin, Ymin, XMax,YMax:integer;
begin
   M.Clear;
   if not FIleExists(Edit1.Text) then exit;
   if not GetSwfFileHeader(Edit1.Text, Head)
   then SHowmessage('读取出错');

   //注意需要 div 20 才得到真正的像素大小
   //XMin:=Head.FrameSize.Xmin div 20;
   XMax:=Head.FrameSize.Xmax div 20;
   //YMin:=Head.FrameSize.Ymin div 20;
   YMax:=Head.FrameSize.Ymax div 20;
   //M.Lines.Add(inttostr(XMin));

   M.Lines.Add('当前影片的长是:'+inttostr(XMax));
   //M.Lines.Add(inttostr(YMin));
   M.Lines.Add('当前影片的宽是:'+inttostr(YMax));
end;


阅读13