RIFF(Resource Interchange File Format)はMicrosoft社の作ったファイルフォーマットで、チャンクの概念を使って画像や音声など、様々なデータを1つのファイルに格納します。RIFFファイルを使う代表的な例としてWAVファイルやAVIファイルがあります。 RIFFは汎用メタファイル形式とも呼ばれるように、コーデックのようなデータ自身のフォーマットは規定しません。RIFFはファイル上のデータの置き方(どのチャンクに何が入っていて、チャンクがどのように配置されるかを示す方法)のみを規定します、データ自身の具体的なフォーマットはWAVやAVI等のそれぞれのファイルフォーマットによって規定されます。
RIFFのチャンクRIFFではデータ全体をいくつかのまとまったデータに分割し、分割されたデータごとにファイル上に配置していきます。分割されたデータブロックのそれぞれをRIFFではチャンク(chunk)と呼んでいます。AVIファイルの場合、通常、動画データはフレームごとに1つのチャンクとして分割されます。音声は1フレームの期間ごとに1つのチャンクに分けられることもあります。デジカメ等、PCに比べると能力の乏しい環境ではフレーム画像とフレーム期間中の音声のチャンクに分割した方が作りやすいこともあります。ただし、どの単位でデータ全体をチャンクに分割するかはRIFFフォーマットでは規定しません。
RIFFファイルはチャンクに分割されたデータをファイル上に配置して、後から(再生するときに)元のデータに復元できるような仕組みを提供します。階層構造を持つことができ、RIFFファイルはチャンクの(階層構造を持つ)集合体として表現されます。
チャンクは以下のような構造を持ちます。
フィールド | オフセット [byte] | サイズ [byte] | 説明 |
---|---|---|---|
ID | 0 | 4 | チャンクを識別するための4文字のコード(FourCC) |
Size | 4 | 4 | このチャンクのデータサイズ |
Data | 8 | n | このチャンクのデータ本体 |
IDは1~4文字の英数字で、3文字以下の場合は右側を空白文字で埋める必要があります。たとえば仮に'AVI'というIDのチャンクがあるとすれば、これは間違いで'AVI 'のように空白を追加する必要があります。このようなコード化はRIFF以外でも用いられ、FourCCコードと呼ばれています。FourCCコードは定数をマクロ定義する場合に比べて、データそのものを読むことで意味を理解しやすいという利点があります。
IDはファイル上では左側の文字が下位アドレスに置かれます。たとえば'RIFF'というIDのチャンクについて見てみます。すべてのRIFFファイルはこのチャンクをチャンク構造のルートに持ちます。AVIやWAVファイルの先頭をダンプすると次のように表示されるはずです。
Address 00 01 02 03 00000000 52 49 46 4C ... RIFF..
ファイルの先頭に'R'、それから順に'I', 'F', 'F'が置かれています。
Sizeはこのチャンクのデータ(Dataフィールド)のバイト数を示し、リトルエンディアンで記録されます。Dataフィールドのサイズであってこのチャンク全体のサイズではありません。したがって、このチャンクの先頭アドレスとSizeフィールドから(同じ階層の)次のチャンクのアドレスを計算するには、「チャンクの先頭アドレス」 + 「Sizeフィールド値」 + 8 のようにIDとSizeフィールド分の8バイトを加算する必要があります。
次はあるAVIファイルのダンプの一部です。
000022C8 : id = 5453494C (L,I,S,T), size = 00000018 (24), type = 4F464E49 (I,N,F,O) 000022D4 : id = 54465349 (I,S,F,T), size = 0000000C (12), type = 6676614C (L,a,v,f) 000022E8 : id = 4B4E554A (J,U,N,K), size = 000003F8 (1016), type = 00000000 ( , , , )
アドレス0x000022C8の'LIST'チャンクはサブチャンクを持っていますが、同じ階層の次のチャンクは0x000022E8にあります。このアドレスは 0x000022C8 + 0x00000018 + 8 = 0x000022E8 によって計算することができます。
Dataフィールド内(チャンクデータ)のデータの構造は、それぞれのチャンクタイプによって異なります。この構造にRIFFは関与しません。
チャンクのヘッダ(Sizeフィールド)で示されるサイズと実際のチャンクのサイズが異なる場合があります。AVIやWAVではチャンクサイズが奇数のとき、(ヘッダに示すサイズは奇数のままで)チャンクの後にゼロのバイトを付加する事で、実際にチャンクサイズを偶数に整列させています。AVIやWAVに関するドキュメントでは実際のサイズを偶数化することが規定されていますが、これがRIFFの仕様であるかははっきりしません。 Windows Platform SDKのmmioAscendでRIFFを作る場合、奇数サイズのチャンクの後に自動的に値ゼロのバイトが追加されるようなので、ほとんどのRIFFがチャンクサイズを偶数化されると考えても問題ないと思われます。
チャンクIDが'RIFF'(RIFFチャンク)または'LIST'(LISTチャンク)のチャンクはその内部にさらにチャンクを含むことができます。チャンクを含むチャンクを「親(parent)チャンク)」、他のチャンクに含るチャンクを、「サブ(sub)チャンク」と呼びます。RIFFファイルはチャンクの階層構造のルートに'RIFF'チャンクを持ち、それ以外のチャンクはRIFFチャンクのサブチャンクとして配置されます。
RIFFチャンクは全てのRIFFファイルに含まれ、RIFFファイル内の最初のチャンクは、RIFFチャンクでなければなりません。RIFFファイル内のその他のチャンクはすべて、このRIFFチャンクのサブチャンクとなります。RIFFチャンクのDataフィールドの先頭4バイトはFormTypeフィールド(FourCCコード)として用いられます。これはそのRIFFファイルが何のデータを含んでいるかを示します。たとえば、AVIファイルのFormTypeフィールドは'AVI '、WAVファイルでは'WAVE'となります。RIFFの仕様はFormTypeフィールドの値を定義しません。
RIFFチャンクはRIFFのチャンクの階層のルートに位置しなければならないという点を除いて、構造や仕組みはLISTチャンクと同じです。LISTチャンクと同じようにサブチャンクを持つことができます。
以下はあるAVIファイルの先頭をダンプした結果です。
Offset Data 00000000 52 49 46 46 .. chunk ID 'RIFF' 00000004 4C 6D 70 00 .. chunk Size 0x00706D4C (7368012) byte chunk data 00000008 41 56 49 20 .. FormType 'AVI '
LISTチャンクは、いくつかのサブチャンクを持つチャンクです(サブチャンクを持つことができるのはRIFFチャンクとLISTチャンクだけです)。
LISTチャンクにも、RIFFチャンクと同じようにDataフィールドの先頭の4バイトがFormTypeフィールド(FourCCコード)として用いられます。FormTypeフィールドはこのLISTチャンクにどのようなサブチャンクが含まれるかを示します。たとえばAVIファイルでビデオとオーディオはformType 'movi'で示されるLISTチャンクに'01wb'や'00dc'のIDを持つサブチャンクとして格納されます。01wbがオーディオデータ、00dcがビデオデータを含みます('01'や'00'の部分は実装に依存して異なるかもしれません)。以下は実際のAVIファイルの'movi' LISTチャンクをツールを使ってダンプした結果です。
000026E8 : id = 5453494C (L,I,S,T), size = 00701EAC (7347884), type = 69766F6D (m,o,v,i) 000026F4 : id = 62773130 (0,1,w,b), size = 0000AC30 (44080) 0000D32C : id = 63643030 (0,0,d,c), size = 00007177 (29047) ..
000026E8 + 8 バイトから始まるLISTチャンクのDataフィールドの先頭はFormType 'movi'が置かれ、それにて'01wb'チャンクと'00dc'チャンクが続きます。この例では'01wb'チャンクも'00dc'チャンクも(LISTチャンクでもRIFFチャンクでもないので)サブチャンクを持ちませんがLISTチャンクのサブチャンクとしてLISTチャンクを持つこともできます。