Example #1
0
        // インデックスには、データ チャンクのリストとファイル内でのその位置が含まれている。
        // インデックスは、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;
        }
Example #4
0
        /// <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();
            };
        }