|
|
Getting info from SWF-file |
|
A little theory
Any SWF-file consists of 2 main parts: Header and Body. So reading of
header is enough to get info about the movie. Header record is described
by the following structure:
TSWFHeader = packed record
Signature: array [0..2] of char;
Version: byte;
FileLength: cardinal;
FrameSize: TSWFRect;
FrameRate: byte;
FrameRateRemainder: byte;
FrameCount: cardinal;
end;
TSWFRect = packed record Xmin: integer; // in twips Xmax: integer; // in twips Ymin: integer; // in twips Ymax: integer; // in twips end;
Header reading is complicated by two features:
1. Size of header record is not a fixed value because of the bit-packing
techniques used for Rect record storing. Rect structure: Nbits, Xmin,
Xmax, Ymin, Ymax. The unsigned Nbits field occupies the first five bits
and indicates how long the next four signed fields are.
2. In compressed format a part of header is stored in the packed part
of the file. Has been uncompressed using the open standard ZLIB. The data
format used by the ZLIB library is described by Request for Comments (RFCs)
documents 1950 to 1952.
Function GetSwfFileHeader
function GetSwfFileHeader(const FileName:
String; var Header: TSWFHeader): boolean;
Function returns true if the file is read successfully.
Rect record fields are in twips (1 px = 20 twips). Frame rate consists
of 2 parts: FrameRate is integer and FrameRateRemainder is fractional.
The complete value is calculated from
FrameRate + FrameRateRemainder / 256.
How it works:
1. Reading first 8 bytes. This is non compressed part of header.
2. Signature comparing. Unpacking in case compressed format.
3. Reading the Rect bit structure and other data.
Function GetSwfFileHeader(const FileName:
string; var Header: TSWFHeader): boolean;
const
BuffSize = 25;
var
Buffer: PByteArray;
NBitsField: byte;
Poz: longword;
FileStream: TFileStream;
MemStream: TMemoryStream;
ZStream: TDecompressionStream;
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);
end;
finally
FreeMem(Buffer);
end;
end;
finally
FileStream.Free;
end;
end;
The full source is SwfFileInfo.pas.
to top |