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(); }; }
/// <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(); }; }