2013-11-15 23 views
12

サンプルが始まる前に、すべてのPCM wavオーディオファイルに44バイトのヘッダデータがあると仮定するのは危険です。これは一般的ですが、多くのアプリケーション(たとえばffmpeg)は、46バイトのヘッダーを持つwavを生成し、この処理を無視すると、処理中に破損して判読できないファイルが生成されます。ヘッダーの実際の長さはどのように検出できますか?WAVファイルに44または46バイトのヘッダーが含まれているかどうかを検出するにはどうすればよいですか?

明らかにこれを行う方法はありますが、私はこれを検索してほとんど議論しませんでした。そこのオーディオプロジェクトの多くは、著者のコンテキストに応じて44(または逆に46)と仮定されています。

+3

私は、データが完全にどこかで始まる多くのWAVファイルを持っています。ファイルの先頭から何百ものバイトがあります。 WAVチャンクヘッダーは実際に解析が容易で、解析しないという言い訳はありません。 –

+2

ヘッダーの解析には言い訳がありませんが、そうすることに関する誤った情報がたくさんあります。 Googleで "wav parser"を検索し、多くのトップヒットには議論のない44バイト長のコードが含まれています。 SOはもっと大きなものへのヒントしか含んでいませんでした。私は、次の欲求不満の人のためにこの問題に注意を向けようとしています。 –

+0

私は、音楽音響研究所(スタンフォード)のウェブサイトの[WAVE PCM soundfile format](https://ccrma.stanford.edu/courses/422/projects/WaveFormat/)この種のものにとって有用なリソースとなります。 – Sheridan

答えて

8

トリックは、ヘッダーの16バイト目から始まる4バイト整数である「Subchunk1Size」を調べることです。通常の44バイトのwavでは、この整数は16 [10、0、0、0]になります。 46バイトのヘッダーの場合、余分な拡張メタデータ(まれな?)がある場合、この整数は18 [12、0、0、0]またはそれ以上になります。

余分なデータ自体(存在する場合)は、だから、ヘッダ長を検出するためのシンプルなC#のプログラムは次のようになりますバイトで36

を開始します:

static void Main(string[] args) 
{ 
    byte[] bytes = new byte[4]; 
    FileStream fileStream = new FileStream(args[0], FileMode.Open, FileAccess.Read); 
    fileStream.Seek(16, 0); 
    fileStream.Read(bytes, 0, 4); 
    fileStream.Close(); 
    int Subchunk1Size = BitConverter.ToInt32(bytes, 0); 

    if (Subchunk1Size < 16) 
     Console.WriteLine("This is not a valid wav file"); 
    else 
     switch (Subchunk1Size) 
     { 
      case 16: 
       Console.WriteLine("44-byte header"); 
       break; 
      case 18: 
       Console.WriteLine("46-byte header"); 
       break; 
      default: 
       Console.WriteLine("Header contains extra data and is larger than 46 bytes"); 
       break; 
     } 
} 
+0

これは私を混乱させる....ありがとう! – kaitian521

22

あなたはすべてをチェックする必要があります実際のサイズを確認するためのヘッダーデータ。 Broadcast Wave Formatファイルにはさらに大きな拡張サブチャンクが含まれます。 Pro ToolsのWAVファイルとAIFFファイルには、文書化されていない拡張チャンクとオーディオ後のデータがあります。サンプルデータの開始位置と終了位置を確認するには、データチャンク(WAVファイルの場合は 'data'、AIFFの場合は 'SSND')を実際に探す必要があります。レビューとして

、すべてのWAVサブチャンクは、次の形式に準拠:

 
Subchunk Descriptor (4 bytes) 
    Subchunk Size (4 byte integer, little endian) 
    Subchunk Data (size is Subchunk Size) 

これは、プロセスが非常に簡単です。あなたが探しているものでない場合は、ディスクリプタを読み、データサイズを読み、次のものにスキップします。それを行うための単純なJavaルーチンは、次のようになります。ここで注目すべき

 
found 'RIFF' descriptor 
found 'bext' descriptor 
found 'fmt ' descriptor 
found 'minf' descriptor 
found 'elm1' descriptor 
found 'data' descriptor 
found 'regn' descriptor 
found 'ovwf' descriptor 
found 'umid' descriptor 
end of file 

、両方の「FMT」と「データ」は、合法的に表示されます。ここでは例えば

// 
// Quick note for people who don't know Java well: 
// 'in.read(...)' returns -1 when the stream reaches 
// the end of the file, so 'if (in.read(...) < 0)' 
// is checking for the end of file. 
// 
public static void printWaveDescriptors(File file) 
     throws IOException { 
    try (FileInputStream in = new FileInputStream(file)) { 
     byte[] bytes = new byte[4]; 

     // read first 4 bytes 
     // should be RIFF descriptor 
     if (in.read(bytes) < 0) { 
      return; 
     } 

     printDescriptor(bytes); 

     // first subchunk will always be at byte 12 
     // there is no other dependable constant 
     in.skip(8); 

     for (;;) { 
      // read each chunk descriptor 
      if (in.read(bytes) < 0) { 
       break; 
      } 

      printDescriptor(bytes); 

      // read chunk length 
      if (in.read(bytes) < 0) { 
       break; 
      } 

      // skip the length of this chunk 
      // next bytes should be another descriptor or EOF 
      in.skip(
        (bytes[0] & 0xFF) 
       | (bytes[1] & 0xFF) << 8 
       | (bytes[2] & 0xFF) << 16 
       | (bytes[3] & 0xFF) << 24 
      ); 
     } 

     System.out.println("end of file"); 
    } 
} 

private static void printDescriptor(byte[] bytes) 
     throws IOException { 
    String desc = new String(bytes, "US-ASCII"); 
    System.out.println("found '" + desc + "' descriptor"); 
} 

は私が持っていたランダムなWAVファイルでありますMicrosoft's RIFF specificationはサブチャンクがどのような順序でも出現できると述べているため、他のチャンクの間に配置します。私が知っているいくつかの主要なオーディオシステムでさえ、これは間違っていて、それを説明していません。

特定のチャンクを探したい場合は、探しているものが見つかるまで、各ディスクリプタをチェックしてファイルをループします。

+0

Radiodef、あなたのコメントのおかげで! 以前はビットシフトを使用していませんでしたが、Webで実用的な使用例を見つけることはできません。この表現がビットシフトがここで使われる理由を説明してください。 (bytes[0] & 0xFF) | (bytes[1] & 0xFF) << 8 | (bytes[2] & 0xFF) << 16 | (bytes[3] & 0xFF) << 24 ありがとうございます! –

+0

@RomanM 4バイトを32ビット整数に変換します。例えば、32ビットの整数「00000000000000001000000010000001」(10進数32897)は、「00000000」、「00000000」、「10000000」および「10000001」の4バイトに分割することができます。ビットシフトを行うコードでは、各バイトを配置してビット単位のORで結合することによって、バイト単位で32ビットの整数を作成します。 '&0xFF'部分はJava固有のもので、[ここで説明します](https://stackoverflow.com/q/11380062/2891664)。 – Radiodef

+0

ありがとうございます! –

2

Radiodefの優れた返信に加えて、わかりやすい3つの点を追加したいと思います。

  1. WAVファイルの唯一のルールは、FMTチャンクがDATAチャンクの前に来ることです。それとは別に、あなたは冒頭で、DATAチャンクの前に、そしてその後に、あなたが知らないチャンクを見つけるでしょう。次のチャンクを見つけるために前方にスキップする各チャンクのヘッダーを読み取る必要があります。

  2. FMTチャンクは一般に16バイトと18バイトのバリエーションで検出されますが、実際には18バイト以上も許容されます。 FMTチャンクのヘッダーサイズフィールドが16より大きい場合、バイト17と18もそこに余分なバイト数を指定するため、両方がゼロの場合、16バイトのFMTチャンクと同じ18バイトのFMTチャンクになります。 FMTチャンクの最初の16バイトだけを読み込み、それらを解析して、それ以上は無視しても安全です。 これはなぜ問題なのですか? Windows XPのMedia Playerは16ビットのWAVファイルを再生することができましたが、FMTチャンクが拡張(18バイト以上)バージョンの場合にのみ24ビットのWAVファイルが再生できました。 「Windowsは私の24ビットWAVファイルを再生しない」という苦情が多かったのですが、18バイトのFMTチャンクがあれば、それは... MicrosoftはWindows 7の初期段階でいつか修正しました。 16バイトのFMTファイルで24ビットが正常に動作するようになりました。

  3. (新しく追加)奇数サイズのチャンクサイズが頻繁に発生します。 24ビットのモノファイルが作成されたときに主に見られます。仕様からは明らかではありませんが、チャンクサイズは実際のデータ長(奇数)を指定し、チャンクの後と次のチャンクの開始前にパッドバイト(ゼロ)が追加されます。したがって、チャンクは常に偶数の境界から始まりますが、チャンクサイズ自体は実際の奇数値として格納されます。

関連する問題