// インデックスには、データ チャンクのリストとファイル内でのその位置が含まれている。 // インデックスは、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(AVIIF_KEYFRAME); 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, 1); 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(); }; }
public RiffBase(System.IO.Stream output, string fourCC) { this.FourCC = fourCC; this.Offset = output.Position; Writer = new System.IO.BinaryWriter(output); Writer.Write(RiffFile.ToFourCC(fourCC)); this.SizeOffset = output.Position; uint dummy_size = 0; Writer.Write(dummy_size); this.DataOffset = output.Position; }
/// <summary>Create with video and audio stream.</summary> public AviWriter(System.IO.Stream outputAvi, string fourCC, VideoFormat videoFormat, AudioFormat audioFormat) { // 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リストをとりあえずフレーム数=0で作成(あとで上書き) var hdrlList = riffFile.CreateList("hdrl"); WriteHdrlList(hdrlList, fourCC, videoFormat, audioFormat, 0, 0); hdrlList.Close(); // moviリストを作成し、AddImage/AddAudioごとにデータチャンクを追加 var idx1List = new List <Idx1Entry>(); var moviList = riffFile.CreateList("movi"); this.AddImage += (data) => { if (videoFormat == null) { throw new InvalidOperationException("no video stream."); } var idx1 = WriteMoviList(moviList, "00dc", data); idx1List.Add(idx1); }; this.AddAudio += (data) => { if (audioFormat == null) { throw new InvalidOperationException("no audio stream."); } var idx1 = WriteMoviList(moviList, "01wb", data); idx1List.Add(idx1); }; // ファイルをクローズ this.Close += () => { // moviリストを閉じる moviList.Close(); // idx1チャンクを作成 WriteIdx1Chunk(riffFile, idx1List); var videoFrames = idx1List.Where(x => x.ChunkId == "00dc").Count(); var audioFrames = idx1List.Where(x => x.ChunkId == "01wb").Count(); // 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, videoFormat, audioFormat, videoFrames, audioFrames); // hdrlリストのデータを正しいフレーム数で上書き riffFile.BaseStream.Seek(0, System.IO.SeekOrigin.End); // 元の場所に戻る // ファイルをクローズ riffFile.Close(); outputAvi.Dispose(); }; }