Example #1
0
        // たとえば、ストリーム 0 にオーディオが含まれる場合、そのストリームのデータ チャンクは FOURCC '00wb' を持つ。
        // ストリーム 1 にビデオが含まれる場合、そのストリームのデータ チャンクは FOURCC '01db' または '01dc' を持つ。
        private static Idx1Entry WriteMoviList(RiffList moviList, string chunkId, byte[] data)
        {
            var chunk = moviList.CreateChunk(chunkId);

            chunk.Write(data);

            // データはワード境界に配置しなければならない
            // バイト数が奇数の場合は、1バイトのダミーデータを書き込んでワード境界にあわせる
            int  length  = data.Length;
            bool padding = false;

            if (length % 2 != 0)
            {
                chunk.WriteByte(0x00); // 1バイトのダミーを書いてワード境界にあわせる
                padding = true;
            }

            chunk.Close();

            return(new Idx1Entry(chunkId, length, padding));
        }
Example #2
0
        /// <summary>Create Hdrl</summary>
        private void WriteHdrlList(RiffList hdrlList, string fourCC, VideoFormat videoFormat, AudioFormat audioFormat, int videoFrames, int audioFrames)
        {
            // - xxxx.avi - RIFF - AVI
            //   |
            //   - LIST - hdrl         : Header List
            //   | |
            //   | |-- avih            : Main AVI Header
            //   | |
            //   | |-- LIST - strl     : Stream Header List
            //   | |   |-- strh        : Stream Header
            //   | |   +-- strf        : BITMAPINFOHEADER
            //   | |
            //   | +-- LIST - strl     : Stream Header List
            //   |     |-- strh        : Stream Header
            //   |     +-- strf        : WAVEFORMATEX
            //   |
            //   - LIST - movi
            //   | |
            //   | |-- 00dc            : stream 0 Video Chunk
            //   | |-- 01wb            : stream 1 Audio Chunk
            //   | |-- 00dc
            //   | |-- 01wb
            //   | +-- ....
            //   |
            //   + idx1
            //
            // some avi files insert JUNK chunk before 'LIST - movi' to align 2048 bytes boundary.
            // but I cant find any reason to align 2048 bytes boundary.

            if (videoFormat == null)
            {
                throw new ArgumentNullException("videoFormat");
            }

            int streams = audioFormat == null ? 1 : 2;

            // LISTチャンク'hdrl'を追加
            // 'hdrl' リストは AVI メイン ヘッダーで始まり、このメイン ヘッダーは 'avih' チャンクに含まれている。
            // メイン ヘッダーには、ファイル内のストリーム数、AVI シーケンスの幅と高さなど、AVI ファイル全体に関するグローバル情報が含まれる。
            // メイン ヘッダー チャンクは、AVIMAINHEADER 構造体で構成されている。
            {
                var chunk = hdrlList.CreateChunk("avih");
                var avih  = new AVIMAINHEADER();
                avih.dwMicroSecPerFrame    = (uint)(1 / videoFormat.FramesPerSec * 1000 * 1000);
                avih.dwMaxBytesPerSec      = 25000;  // ffmpegと同じ値に
                avih.dwFlags               = 0x0910; // ffmpegと同じ値に
                avih.dwTotalFrames         = (uint)videoFrames;
                avih.dwStreams             = (uint)streams;
                avih.dwSuggestedBufferSize = 0x100000;
                avih.dwWidth               = (uint)videoFormat.Width;
                avih.dwHeight              = (uint)videoFormat.Height;

                var data = StructureToBytes(avih);
                chunk.Write(data);
                chunk.Close();
            }

            // メイン ヘッダーの次には、1 つ以上の 'strl' リストが続く。'strl' リストは各データ ストリームごとに必要である。
            // 各 'strl' リストには、ファイル内の単一のストリームに関する情報が含まれ、ストリーム ヘッダー チャンク ('strh') とストリーム フォーマット チャンク ('strf') が必ず含まれる。
            // ストリーム ヘッダー チャンク ('strh') は、AVISTREAMHEADER 構造体で構成されている。
            // ストリーム フォーマット チャンク ('strf') は、ストリーム ヘッダー チャンクの後に続けて記述する必要がある。
            // ストリーム フォーマット チャンクは、ストリーム内のデータのフォーマットを記述する。このチャンクに含まれるデータは、ストリーム タイプによって異なる。
            // ビデオ ストリームの場合、この情報は必要に応じてパレット情報を含む BITMAPINFO 構造体である。オーディオ ストリームの場合、この情報は WAVEFORMATEX 構造体である。

            // Videoストリーム用の'strl'チャンク
            {
                var strl_list = hdrlList.CreateList("strl");
                {
                    var chunk = strl_list.CreateChunk("strh");
                    var strh  = new AVISTREAMHEADER();
                    strh.fccType               = ToFourCC("vids");
                    strh.fccHandler            = ToFourCC(fourCC);
                    strh.dwScale               = 1000 * 1000; // fps = dwRate / dwScale。秒間30フレームであることをあらわすのにdwScale=33333、dwRate=1000000という場合もあればdwScale=1、dwRate=30という場合もあります. For video streams, this is the frame rate.
                    strh.dwRate                = (int)(videoFormat.FramesPerSec * strh.dwScale);
                    strh.dwLength              = videoFrames;
                    strh.dwSuggestedBufferSize = 0x100000;
                    strh.dwQuality             = -1; // Quality is represented as a number between 0 and 10,000. If set to –1, drivers use the default quality value.

                    var data = StructureToBytes(strh);
                    chunk.Write(data);
                    chunk.Close();
                }
                {
                    var chunk = strl_list.CreateChunk("strf");
                    var strf  = new BITMAPINFOHEADER();
                    strf.biWidth       = videoFormat.Width;
                    strf.biHeight      = videoFormat.Height;
                    strf.biBitCount    = 24;
                    strf.biSizeImage   = strf.biHeight * ((3 * strf.biWidth + 3) / 4) * 4; // らしい
                    strf.biCompression = ToFourCC(fourCC);
                    strf.biSize        = System.Runtime.InteropServices.Marshal.SizeOf(strf);
                    strf.biPlanes      = 1;

                    var data = StructureToBytes(strf);
                    chunk.Write(data);
                    chunk.Close();
                }
                strl_list.Close();
            }

            // Audioストリーム用の'strl'チャンク(あれば)
            if (audioFormat != null)
            {
                var strl_list = hdrlList.CreateList("strl");
                {
                    var chunk = strl_list.CreateChunk("strh");
                    var strh  = new AVISTREAMHEADER();
                    strh.fccType               = ToFourCC("auds");
                    strh.fccHandler            = 0x00;                                                            // For audio and video streams, this specifies the codec for decoding the stream. pcmは不要。
                    strh.dwScale               = audioFormat.Channels;                                            // For audio streams, this rate corresponds to the time needed to play nBlockAlign bytes of audio, which for PCM audio is the just the sample rate.
                    strh.dwRate                = audioFormat.SamplesPerSec * strh.dwScale;                        // Dividing dwRate by dwScale gives the number of samples per second.
                    strh.dwSampleSize          = (short)(audioFormat.Channels * (audioFormat.BitsPerSample / 8)); // For audio streams, this number should be the same as the nBlockAlign member of the WAVEFORMATEX structure describing the audio.
                    strh.dwLength              = audioFrames;
                    strh.dwSuggestedBufferSize = strh.dwRate;                                                     // ?
                    strh.dwQuality             = -1;                                                              // Quality is represented as a number between 0 and 10,000. If set to –1, drivers use the default quality value.

                    var data = StructureToBytes(strh);
                    chunk.Write(data);
                    chunk.Close();
                }
                {
                    const int WAVE_FORMAT_PCM = 0x0001;
                    var       chunk           = strl_list.CreateChunk("strf");
                    var       strf            = new WAVEFORMATEX();
                    strf.nChannels       = audioFormat.Channels;
                    strf.wFormatTag      = WAVE_FORMAT_PCM;
                    strf.nSamplesPerSec  = audioFormat.SamplesPerSec;
                    strf.nBlockAlign     = (short)(audioFormat.Channels * (audioFormat.BitsPerSample / 8));
                    strf.nAvgBytesPerSec = strf.nSamplesPerSec * strf.nBlockAlign;
                    strf.wBitsPerSample  = audioFormat.BitsPerSample;
                    strf.cbSize          = 0;

                    var data = StructureToBytes(strf);
                    chunk.Write(data);
                    chunk.Close();
                }
                strl_list.Close();
            }
        }
        private void WriteHdrlList(RiffList hdrlList, string fourCC, int width, int height, float fps, int frames)
        {
            int streams = 1; // ストリーム数。音声なしの場合1。ありの場合2。

            // LISTチャンク'hdrl'を追加

            // 'hdrl' リストは AVI メイン ヘッダーで始まり、このメイン ヘッダーは 'avih' チャンクに含まれている。
            // メイン ヘッダーには、ファイル内のストリーム数、AVI シーケンスの幅と高さなど、AVI ファイル全体に関するグローバル情報が含まれる。
            // メイン ヘッダー チャンクは、AVIMAINHEADER 構造体で構成されている。

            {
                var chunk = hdrlList.CreateChunk("avih");
                var avih  = new AVIMAINHEADER();
                avih.dwMicroSecPerFrame    = (uint)(1 / (fps * 1000 * 1000));
                avih.dwMaxBytesPerSec      = 25000;  // ffmpegと同じ値に
                avih.dwFlags               = 0x0910; // ffmpegと同じ値に
                avih.dwTotalFrames         = (uint)frames;
                avih.dwStreams             = (uint)streams;
                avih.dwSuggestedBufferSize = 0x100000;
                avih.dwWidth               = (uint)width;
                avih.dwHeight              = (uint)height;

                var data = StructureToBytes(avih);
                chunk.Write(data);
                chunk.Close();
            }

            // メイン ヘッダーの次には、1 つ以上の 'strl' リストが続く。'strl' リストは各データ ストリームごとに必要である。
            // 各 'strl' リストには、ファイル内の単一のストリームに関する情報が含まれ、ストリーム ヘッダー チャンク ('strh') とストリーム フォーマット チャンク ('strf') が必ず含まれる。
            // ストリーム ヘッダー チャンク ('strh') は、AVISTREAMHEADER 構造体で構成されている。
            // ストリーム フォーマット チャンク ('strf') は、ストリーム ヘッダー チャンクの後に続けて記述する必要がある。
            // ストリーム フォーマット チャンクは、ストリーム内のデータのフォーマットを記述する。このチャンクに含まれるデータは、ストリーム タイプによって異なる。
            // ビデオ ストリームの場合、この情報は必要に応じてパレット情報を含む BITMAPINFO 構造体である。オーディオ ストリームの場合、この情報は WAVEFORMATEX 構造体である。

            // Videoストリーム用の'strl'チャンク
            var strl_list = hdrlList.CreateList("strl");

            {
                var chunk = strl_list.CreateChunk("strh");
                var strh  = new AVISTREAMHEADER();
                strh.fccType               = ToFourCC("vids");
                strh.fccHandler            = ToFourCC(fourCC);
                strh.dwScale               = 1000 * 1000; // fps = dwRate / dwScale。秒間30フレームであることをあらわすのにdwScale=333333、dwRate=1000000という場合もあればdwScale=1、dwRate=30という場合もあります
                strh.dwRate                = (int)(fps * strh.dwScale);
                strh.dwLength              = frames;
                strh.dwSuggestedBufferSize = 0x100000;
                strh.dwQuality             = -1;

                var data = StructureToBytes(strh);
                chunk.Write(data);
                chunk.Close();
            }
            {
                var chunk = strl_list.CreateChunk("strf");
                var strf  = new BITMAPINFOHEADER();
                strf.biWidth       = width;
                strf.biHeight      = height;
                strf.biBitCount    = 24;
                strf.biSizeImage   = strf.biHeight * ((3 * strf.biWidth + 3) / 4) * 4; // らしい
                strf.biCompression = ToFourCC(fourCC);
                strf.biSize        = System.Runtime.InteropServices.Marshal.SizeOf(strf);
                strf.biPlanes      = 1;

                var data = StructureToBytes(strf);
                chunk.Write(data);
                chunk.Close();
            }
            strl_list.Close();
        }