⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 riffdump.dpr

📁 Voice Commnucation Components for Delphi
💻 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 + -