zoukankan      html  css  js  c++  java
  • 操作 Wave 文件(2): 判断一个文件是否是 Wave 文件


    Wave 文件的前 12 个字节可以这样描述:
    TRiff = record
      ckId    : DWORD; {'RIFF'}
      ckSize  : DWORD; {文件大小, 不包括前 8 个字节}
      fccType : DWORD; {'WAVE'}
    end;
    

    我们读出文件的前 12 个字节进行判断, 就基本可以确认它是不是 Wave 文件.

    uses MMSystem, IOUtils; {这里准备用 IOUtils.TFile.OpenRead 方便地建立文件流}
    
    procedure TForm1.FormCreate(Sender: TObject);
    var
      riff: record ckId, ckSize, fccType: DWORD; end; {可以同时定义结构并声明结构变量}
    begin
      with TFile.OpenRead('C:\WINDOWS\Media\Windows XP 启动.wav') do
      begin
        Read(riff, SizeOf(riff));
        Free;
      end;
    
      if (riff.ckId = FOURCC_RIFF) and (riff.fccType = mmioStringToFOURCC('WAVE',0)) then
        ShowMessageFmt('这是个 Wave 文件, 其大小是 %d 字节', [riff.ckSize + 8]);
    end;
    

    还是把它写成一个函数吧, 最好也别再引用 MMSystem 单元.

    {如果是 Wave 文件则返回文件大小, 不是则返回 0}
    function IsWave(FilePath: string): Integer;
      function mmioFOURCC(Chr0,Chr1,Chr2,Chr3: AnsiChar): DWORD;
      begin
        Result := DWORD(Chr0) + DWORD(Chr1) shl 8 + DWORD(Chr2) shl 16 + DWORD(Chr3) shl 24;
      end;
    var
      riff: record ckId, ckSize, fccType: DWORD; end;
    begin
      Result := 0;
      with TFileStream.Create(FilePath, fmOpenRead) do begin
        Read(riff, SizeOf(riff));
        Free;
      end;
      if (riff.ckId = mmioFOURCC('R', 'I', 'F', 'F')) and
         (riff.fccType = mmioFOURCC('W', 'A', 'V', 'E')) then
        Result := riff.ckSize + 8;
    end;
    

    依次道理, 也可以判断一个 RIFF 文件具体是什么格式.

    {返回 RIFF 文件格式的函数, 如果不是 RIFF 文件, 则返回 'noneRIFF'}
    function GetRiffType(FilePath: string): String;
      function mmioFOURCC(Chr0,Chr1,Chr2,Chr3: AnsiChar): DWORD;
      begin
        Result := DWORD(Chr0) + DWORD(Chr1) shl 8 + DWORD(Chr2) shl 16 + DWORD(Chr3) shl 24;
      end;
    var
      riff: record ckId, ckSize, fccType: DWORD; end;
    type
      TChars = array[0..3] of AnsiChar; {用于类型转换}
    begin
      Result := 'noneRIFF';
      with TFileStream.Create(FilePath, fmOpenRead) do begin
        Read(riff, SizeOf(riff));
        Free;
      end;
      if (riff.ckId = mmioFOURCC('R', 'I', 'F', 'F')) then Result := TChars(riff.fccType);
    end;
    
    //测试:
    begin
      ShowMessage(GetRiffType('C:\WINDOWS\Media\Windows XP 启动.wav')); {WAVE}
      ShowMessage(GetRiffType('C:\WINDOWS\clock.avi'));                 {AVI }
      ShowMessage(GetRiffType('C:\WINDOWS\notepad.exe'));               {noneRIFF}
    end;
    

    关于 FOURCC_RIFF、mmioFOURCC、mmioStringToFOURCC:

    RIFF 格式的文件都是有若干 "块" 来构成的, 每个块都是有 4 个字符开头(不足4个字符用空格补足);
    这连续的 4 个字节刚好是一个 32 位整数的大小, 所以常常把它们当作一个整数读出来判断.

    通过 MMSystem.mmioStringToFOURCC 就可以获取这样的整数.

    从 C/C++ 代码中经常看到: mmioFOURCC; 它并非 winmm.dll 库中的函数, 是在 C/C++ 中定义的宏.
    这里用 Delphi 模拟实现了这个函数. 其功能类似 mmioStringToFOURCC.

    MMSystem.FOURCC_RIFF 是个常量, 当需要 "RIFF" 对应的整数时直接用就是了. 举例:

    uses MMSystem;
    
    {自定义的 mmioFOURCC 函数}
    function mmioFOURCC(Chr0,Chr1,Chr2,Chr3: AnsiChar): DWORD;
    begin
      Result := DWORD(Chr0) + DWORD(Chr1) shl 8 + DWORD(Chr2) shl 16 + DWORD(Chr3) shl 24;
    end;
    
    procedure TForm1.FormCreate(Sender: TObject);
    var
      f1,f2,f3,f4: FOURCC; {FOURCC = DWORD;}
    begin
      f1 := mmioStringToFOURCC('RIFF', 0);
      f2 := mmioStringToFOURCC('Riff', MMIO_TOUPPER); {第二个参数可以把字符串转大写}
    
      f3 := mmioFOURCC('R', 'I', 'F', 'F');
    
      f4 := FOURCC_RIFF;
    
      ShowMessageFmt('%d, %d, %d, %d', [f1,f2,f3,f4]);
      {1179011410, 1179011410, 1179011410, 1179011410}
    end;
    
  • 相关阅读:
    .NET Framework 4.5 中新增的'可移植类库'功能
    使用visual sutdio右键菜单封装字段
    Visual Studio 2008的“组织using”菜单
    HTML5与HTML4的区别
    【百度地图API】如何制作公交线路的搜索?如331路
    【百度地图API】如何给自定义覆盖物添加事件
    【百度地图API】如何制作自定义样式的公交导航结果面板?
    【百度地图API】如何制作可拖拽的沿道路测距
    透过【百度地图API】分析双闭包问题
    【百度地图API】如何用圆形搜索获取中心点周围100米内全部关键点?如天安门附近所有的餐厅、加油站、宾馆、大厦等
  • 原文地址:https://www.cnblogs.com/del/p/1597315.html
Copyright © 2011-2022 走看看