// インデックスには、データ チャンクのリストとファイル内でのその位置が含まれている。 // インデックスは、AVIOLDINDEX 構造体で構成され、各データ チャンクのエントリが含まれている。 // ファイルにインデックスが含まれる場合、AVIMAINHEADER 構造体の dwFlags メンバにある AVIF_HASINDEX フラグを設定する。 private static void WriteIdx1Chunk(RiffFile riff, List <Idx1Entry> IndexList) { const int AVIIF_KEYFRAME = 0x00000010; // 前後のフレームの情報なしにこのフレームの完全な情報を含んでいる var chunk = riff.CreateChunk("idx1"); int offset = 4; foreach (var item in IndexList) { int length = item.Length; chunk.Write(ToFourCC(item.ChunkId)); chunk.Write(item.KeyFrame? AVIIF_KEYFRAME: 0x00); chunk.Write(offset); chunk.Write(length); offset += 8 + length; // 8は多分00dcとデータサイズ if (item.Padding) { offset += 1; } } chunk.Close(); }
public AviWriter(System.IO.Stream outputAvi, string fourCC, int width, int height, float fps) { // RIFFファイルは、RIFFヘッダーとその後ろに続く 0個以上のリストとチャンクで構成されている。 // RIFFヘッダーは、'RIFF'のFOURCC、4バイトのデータサイズ、データを識別するFOURCC、データから構成されている。 // リストは、'LIST'のFOURCC、4バイトのデータサイズ、データを識別するFOURCC、データから構成されている。 // チャンクは、データを識別するFOURCC、4バイトのデータサイズ、データから構成されている。 // チャンクデータを識別するFOURCCは、2桁のストリーム番号とその後に続く2文字コード(dc=ビデオ,wb=音声,tx=字幕など)で構成されている。 // AVIファイルは、'AVI 'のFOURCCと、2つの必須のLISTチャンク('hdrl''movi')、オプションのインデックスチャンクから構成されるRIFFファイルである。 var riffFile = new RiffFile(outputAvi, "AVI "); // hdrlリストを仮のフレーム数で作成 var hdrlList = riffFile.CreateList("hdrl"); WriteHdrlList(hdrlList, fourCC, width, height, fps, 0); hdrlList.Close(); // moviリストを作成し、OnAddImageごとにデータチャンクを追加 var idx1List = new List <Idx1Entry>(); var moviList = riffFile.CreateList("movi"); this.OnAddImage += (data, keyFrame) => { var idx1 = WriteMoviList(moviList, "00dc", data); idx1.KeyFrame = keyFrame; idx1List.Add(idx1); }; // ファイルをクローズ this.OnClose += () => { // moviリストを閉じる moviList.Close(); // idx1チャンクを作成 WriteIdx1Chunk(riffFile, idx1List); // hdrlListを正しいフレーム数で上書き var offset = hdrlList.Offset; riffFile.BaseStream.Seek(offset, System.IO.SeekOrigin.Begin); // hdrlリストの先頭まで戻る riffFile.BaseStream.Seek(12, System.IO.SeekOrigin.Current); // hdrlリストのヘッダ分飛ばす WriteHdrlList(riffFile, fourCC, width, height, fps, idx1List.Count); // hdrlリストのデータを正しいフレーム数で上書き riffFile.BaseStream.Seek(0, System.IO.SeekOrigin.End); // 元の場所に戻る // ファイルをクローズ riffFile.Close(); outputAvi.Dispose(); }; }