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