📄 riffdump.dpr
字号:
(*
----------------------------------------------
riffDump.pas
Voice Communicator components version 2.5
RIFF dump demo application
----------------------------------------------
This source code cannot be used without
proper permission granted to you as a private
person or an entity by the Lake of Soft, Ltd
Visit http://lakeofsoft.com/ for details.
Copyright (c) 2001, 2005 Lake of Soft, Ltd
All rights reserved
----------------------------------------------
created by:
Lake, 21 Apr 2002
modified by:
Lake, Apr-Nov 2002
Lake, Jun 2003
Lake, Oct 2005
----------------------------------------------
*)
{$APPTYPE CONSOLE}
{$I unaDef.inc}
program
riffDump;
uses
Windows, unaTypes, MMSystem,
{$IFDEF VCX_DEMO}
Math, SysUtils, // some functions are not exported from pre-compiled unaUtils.dcu
{$ENDIF}
unaUtils, unaClasses, unaMsAcmAPI, unaRIFF;
// from AviFmt.h
(*
Main AVI File Header
*)
const
// flags for use in <dwFlags> in AVIFileHdr
AVIF_HASINDEX = $00000010;
AVIF_MUSTUSEINDEX = $00000020;
AVIF_ISINTERLEAVED = $00000100;
AVIF_TRUSTCKTYPE = $00000800;
AVIF_WASCAPTUREFILE = $00010000;
AVIF_COPYRIGHTED = $00020000;
(* The AVI File Header LIST chunk should be padded to this size *)
AVI_HEADERSIZE = 2048; // size of AVI header list
type
// avih / size = $38
PMainAVIHeader = ^MainAVIHeader;
MainAVIHeader = 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;
// #define streamtypeVIDEO FCC('vids')
// #define streamtypeAUDIO FCC('auds')
// #define streamtypeMIDI FCC('mids')
// #define streamtypeTEXT FCC('txts')
// for avistreamheader.dwFlags
// #define AVISF_DISABLED 0x00000001
// #define AVISF_VIDEO_PALCHANGES 0x00010000
pavistreamheader = ^avistreamheader;
avistreamheader = packed record
fccType: fourCC; // stream type codes
fccHandler: fourCC;
dwFlags: DWORD;
wPriority: WORD;
wLanguage: WORD;
dwInitialFrames: DWORD;
dwScale: DWORD;
dwRate: DWORD; // dwRatedwScale is stream tick rate in ticks/sec
dwStart: DWORD;
dwLength: DWORD;
dwSuggestedBufferSize: DWORD;
dwQuality: DWORD;
dwSampleSize: DWORD;
//struct {
left: shortInt;
top: shortInt;
right: shortInt;
bottom: shortInt;
//} rcFrame;
end;
t_timeRec = record
case integer of
1: (r_time: unsigned);
2: (r_ms: byte;
r_sec: byte;
r_min: word;
)
end;
pCDDA_header = ^tCDDA_header;
tCDDA_header = record
r_formatTag: word;
r_trackNum: word;
r_serial: unsigned;
r_startPos_sec: unsigned;
r_length_sec: unsigned;
r_startPos_time: t_timeRec;
r_length_time: t_timeRec;
end;
var
numBytes: unsigned;
rootSign: string;
// -- --
function int2Hex(value: unsigned; size: unsigned = 8): string;
begin
result := adjust(int2Str(value, 16), size, '0');
end;
function time2str(const time: t_timeRec): string;
begin
result := adjust(int2str(time.r_min, 10), 3, '0') + ':' +
adjust(int2str(time.r_sec, 10), 2, '0') + ':' +
adjust(int2str(time.r_ms, 10), 2, '0');
end;
// -- --
procedure displayChunkHeader(const pad: string; chunk: unaRIFFChunk);
var
str: string;
cddaHdr: pCDDA_header;
waveHdr: PWAVEFORMATEX;
waveTagDetails: ACMFORMATTAGDETAILS;
aviMainHdr: PMainAVIHeader;
aviStreamHdr: pavistreamheader;
begin
// WAVE format header
if (chunk.isID('fmt ') and ($10 <= chunk.header.r_size)) then begin
if ('CDDA' = rootSign) then begin
cddaHdr := pointer(chunk.data);
//
fillChar(waveTagDetails, sizeOf(waveTagDetails), #0);
waveTagDetails.cbStruct := sizeOf(waveTagDetails);
waveTagDetails.dwFormatTag := cddaHdr.r_formatTag;
if (0 = acm_FormatTagDetails(0, waveTagDetails, ACM_FORMATTAGDETAILSF_FORMATTAG)) then
str := ' (' + waveTagDetails.szFormatTag + ')'
else
str := ' (Unknown format tag)';
//
infoMessage(pad + ' Format tag : ' + int2Str(cddaHdr.r_formatTag) + str);
infoMessage(pad + ' Track # : ' + int2Str(cddaHdr.r_trackNum));
infoMessage(pad + ' Serial (?) : 0x' + int2Str(cddaHdr.r_serial, 16));
infoMessage(pad + ' Starting pos : ' + int2Str(cddaHdr.r_startPos_sec));
infoMessage(pad + ' Length : ' + int2Str(cddaHdr.r_length_sec));
infoMessage(pad + ' Starting time : ' + time2Str(cddaHdr.r_startPos_time));
infoMessage(pad + ' Length : ' + time2Str(cddaHdr.r_length_time));
end
else
if ('WAVE' = rootSign) then begin
waveHdr := pointer(chunk.data);
//
fillChar(waveTagDetails, sizeOf(waveTagDetails), #0);
waveTagDetails.cbStruct := sizeOf(waveTagDetails);
waveTagDetails.dwFormatTag := waveHdr.wFormatTag;
if (0 = acm_FormatTagDetails(0, waveTagDetails, ACM_FORMATTAGDETAILSF_FORMATTAG)) then
str := ' (' + waveTagDetails.szFormatTag + ')'
else
str := ' (Unknown format tag)';
//
infoMessage(pad + ' Format tag : ' + int2Str(waveHdr.wFormatTag) + str);
infoMessage(pad + ' Number of channels : ' + int2Str(waveHdr.nChannels));
infoMessage(pad + ' Samples per second : ' + int2Str(waveHdr.nSamplesPerSec));
infoMessage(pad + ' Bits per sample : ' + int2Str(waveHdr.wBitsPerSample));
infoMessage(pad + ' Av. bytes per sec. : ' + int2Str(waveHdr.nAvgBytesPerSec));
infoMessage(pad + ' Block align : ' + int2Str(waveHdr.nBlockAlign));
if ((sizeOf(waveHdr^) <= chunk.header.r_size) and (WAVE_FORMAT_PCM <> waveHdr.wFormatTag)) then
infoMessage(pad + ' Extra data size : ' + int2Str(waveHdr.cbSize));
end;
end;
// WAVE uncompressed size header
if (chunk.isID('fact') and (4 <= chunk.header.r_size)) then
infoMessage(pad + ' Uncompressed stream size : 0x' + int2Hex(punsigned(chunk.data)^));
// AVI main header
if (chunk.isID('avih') and (sizeOf(aviMainHdr^) <= chunk.header.r_size)) then begin
aviMainHdr := pointer(chunk.data);
infoMessage(pad + ' Number of microsec. between frames : ' + int2Str(aviMainHdr.dwMicroSecPerFrame));
infoMessage(pad + ' Approximate maximum data rate : ' + int2Str(aviMainHdr.dwMaxBytesPerSec));
infoMessage(pad + ' Pad to multiples of this size : ' + int2Str(aviMainHdr.dwPaddingGranularity));
infoMessage(pad + ' The ever-present flags : ' + int2Hex(aviMainHdr.dwFlags));
infoMessage(pad + ' Total number of frames of data : ' + int2Str(aviMainHdr.dwTotalFrames));
infoMessage(pad + ' Initial frame for interleaved files : ' + int2Str(aviMainHdr.dwInitialFrames));
infoMessage(pad + ' Number of streams in the file : ' + int2Str(aviMainHdr.dwStreams));
infoMessage(pad + ' Suggested buffer size for reading : ' + int2Str(aviMainHdr.dwSuggestedBufferSize));
infoMessage(pad + ' Width of the AVI file in pixels : ' + int2Str(aviMainHdr.dwWidth));
infoMessage(pad + ' Height of the AVI file in pixels : ' + int2Str(aviMainHdr.dwHeight));
end;
// AVI stream header
if (chunk.isID('strh') and (sizeOf(aviStreamHdr^) <= chunk.header.r_size)) then begin
aviStreamHdr := pointer(chunk.data);
infoMessage(pad + ' Type of the data in the stream : ' + aviStreamHdr.fccType);
infoMessage(pad + ' Specific stream data handler : ' + aviStreamHdr.fccHandler);
infoMessage(pad + ' Flags for the data stream : ' + int2Hex(aviStreamHdr.dwFlags));
infoMessage(pad + ' Priority of a stream type : ' + int2Str(aviStreamHdr.wPriority));
infoMessage(pad + ' Language of a stream : ' + int2Str(aviStreamHdr.wLanguage));
infoMessage(pad + ' Audio data is skewed ahead by : ' + int2Str(aviStreamHdr.dwInitialFrames));
infoMessage(pad + ' Time scale for this stream : ' + int2Str(aviStreamHdr.dwScale));
infoMessage(pad + ' Stream tick rate in ticks/sec : ' + int2Str(aviStreamHdr.dwRate));
infoMessage(pad + ' Starting time of the AVI file : ' + int2Str(aviStreamHdr.dwStart));
infoMessage(pad + ' Length of this stream : ' + int2Str(aviStreamHdr.dwLength));
infoMessage(pad + ' Suggested buffer size for reading : ' + int2Str(aviStreamHdr.dwSuggestedBufferSize));
infoMessage(pad + ' Quality of the data in the stream : ' + choice(unsigned(-1) = aviStreamHdr.dwQuality, 'default', int2Str(aviStreamHdr.dwQuality)));
infoMessage(pad + ' Size of a single sample of data : ' + int2Str(aviStreamHdr.dwSampleSize));
infoMessage(pad + ' Destination rectangle for stream : ' +
'(Left=' + int2Str(aviStreamHdr.left) + '; Top=' + int2Str(aviStreamHdr.top) + ') - ' +
'(Right=' + int2Str(aviStreamHdr.right) + '; Bottom=' + int2Str(aviStreamHdr.bottom) + ')');
end;
end;
// -- --
procedure displaySubChunks(chunk: unaRIFFChunk; step: unsigned);
var
i: unsigned;
m: unsigned;
size: unsigned;
pad: string;
str: string;
num: byte;
b: byte;
ascii: string;
ofs: unsigned;
begin
if (nil <> chunk) then begin
pad := padChar(' ', step);
infoMessage(int2Hex(chunk.offset) + ': ' + pad + chunk.header.r_id + ' [0x' + int2Hex(chunk.header.r_size, 7) + '/0x' + int2Hex(chunk.maxSize - 8, 7) + '] ' + choice(chunk.isContainer, chunk.header.r_type, ''));
if (chunk.isContainer) then begin
i := 0;
size := 0;
//
if (0 = step) then begin
setLength(rootSign, 4);
move(chunk.data^, rootSign[1], 4);
end;
//
while (i < chunk.getSubChunkCount) do begin
displaySubChunks(chunk[i], step + 2);
inc(size, chunk[i].header.r_size);
inc(i);
end;
infoMessage(int2Hex(chunk.offset + chunk.header.r_size) + ': ' + pad + chunk.header.r_id + ' total size: 0x' + int2Hex(size));
end
else begin
// display know file headers
displayChunkHeader(pad, chunk);
//
ofs := 0;
m := min(numBytes, chunk.header.r_size);
if (0 < m) then begin
i := 0;
str := ' ' + int2Hex(chunk.offset + 8) + '/' + int2Hex(ofs) + ': ';
ascii := '';
num := 0;
//
while (i < m) do begin
b := byte(chunk.data[i]);
str := str + int2Hex(b, 2) + ' ';
ascii := ascii + choice((b < 32) or (b > 127), '.', char(b));
inc(i);
inc(num);
if (8 = num) then
str := str + '| ';
if (15 < num) then begin
str := str + ' ' + ascii;
if (i < m) then
str := str + #13#10 + ' ' + int2Hex(chunk.offset + 8 + i) + '/' + int2Hex(ofs + i) + ': ';
ascii := '';
num := 0;
end;
end;
//
if (0 <> num) then
str := str + padChar(' ', unsigned(16 - num) * 3 + choice(8 > num, unsigned(2), 0)) + ' ' + ascii;
//
infoMessage(str);
end;
end;
end;
end;
// -- main --
var
riff: unaRIFile;
name: string;
sw: string;
begin
infoMessage(' ');
infoMessage('RIFF dump, version 1.2 Copyright (c) 2002-2005 Lake of Soft, Ltd');
//
if (0 < paramCount) then begin
// file name
name := paramStr(1);
infoMessage(' ');
// handle /D switch
if (1 < paramCount) then begin
sw := upperCase(trim(paramStr(2)));
if ((1 < length(sw)) and ('D' = sw[2])) then begin
sw := copy(sw, 3, length(sw));
numBytes := str2IntUnsigned(sw, 64);
infoMessage('Number of bytes in the dump was set to ' + int2Str(numBytes));
end;
end
else
numBytes := 0;
// create unaRIFile
infoMessage('Parsing [' + name + '], please wait..'#13#10);
//
if (fileExists(name)) then begin
riff := unaRIFile.create(name);
// display riff chunks
if (riff.isValid) then begin
infoMessage('<begin>');
infoMessage(' ');
displaySubChunks(riff.rootChunk, 0);
infoMessage(' ');
infoMessage('<end>');
end
else
infoMessage('Input file does not appear to be a valid RIFF file.');
// release file
freeAndNil(riff);
end
else
infoMessage('Unable to open input file.');
end
else begin
infoMessage(' ');
infoMessage(' syntax: riffDump [riff_file [/D[NN]]]');
infoMessage(' ');
infoMessage(' riff_file'#9'- input RIFF file');
infoMessage(' /D[NN]'#9#9'- turn dump mode ON');
infoMessage( #9#9' NN - number of bytes to dump (default is 64)');
infoMessage(' ');
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -