/// <summary> /// 指定したAVI_CONTAINER構造体にAVIファイルの情報を格納すると共に, /// ファイルにヘッダー情報を書き込みます. /// </summary> /// <param name="file">書き込み対象のファイル</param> /// <param name="frameRate">AVIファイルのフレームレート</param> // string file, uint scale, uint rate, int width, int height, IntPtr hwnd public bool Open(string file, uint scale, uint rate, int width, int height, IntPtr hwnd) { m_width = width; m_height = height; this.m_stream = new BinaryWriter(new FileStream(file, FileMode.Create, FileAccess.Write)); float fps = (float)rate / (float)scale; this.m_main_header.dwMicroSecPerFrame = (uint)(1.0e6 / fps);// ! 1秒は10^6μ秒 this.m_main_header.dwReserved1 = 0; this.m_main_header.dwFlags = 2064; this.m_main_header.dwInitialFrames = 0; this.m_main_header.dwStreams = 0; this.m_main_header.dwScale = scale; this.m_main_header.dwRate = rate; this.m_main_header.dwStart = 0; this.m_main_header.dwLength = 0; this.m_rate = rate; this.m_scale = scale; //this.noOfFrame = 0; Util.fwrite("RIFF", this.m_stream); Util.WriteDWORD(0, this.m_stream); Util.fwrite("AVI ", this.m_stream); Util.fwrite("LIST", this.m_stream); Util.WriteDWORD(0x9cc, this.m_stream); Util.fwrite("hdrl", this.m_stream); m_current_chunk = 0; m_position_in_chunk = 0L; m_std_index = new AVISTDINDEX(0L); m_super_index = new AVISUPERINDEX(0); m_riff_position = 0x4; return(true); }
public const int BMP_MAGIC_COOKIE = 19778; //ascii string "BM" /*// <summary> * /// 指定されたBITMAP型変数の情報ヘッダーをファイルに書き込みます. * /// </summary> * /// <param name="bmp"></param> * /// <param name="fp"></param> * public static void bmpWriteInfoHeader( BITMAPINFOHEADER infoHeader, BinaryWriter stream ) { * //type(INFO_HEADER), intent(in) :: infoHeader * //type(FILE), intent(inout) :: fp * Util.WriteDWORD( (uint)infoHeader.biSize, stream ); * Util.WriteDWORD( (uint)infoHeader.biWidth, stream ); * Util.WriteDWORD( (uint)infoHeader.biHeight, stream ); * Util.WriteWORD( (ushort)infoHeader.biPlanes, stream ); * Util.WriteWORD( (ushort)(infoHeader.biBitCount), stream ); * Util.WriteDWORD( (uint)infoHeader.biCompression, stream ); * Util.WriteDWORD( (uint)infoHeader.biSizeImage, stream ); * Util.WriteDWORD( (uint)infoHeader.biXPelsPerMeter, stream ); * Util.WriteDWORD( (uint)infoHeader.biYPelsPerMeter, stream ); * Util.WriteDWORD( (uint)infoHeader.biClrUsed, stream ); * Util.WriteDWORD( (uint)infoHeader.biClrImportant, stream ); * }*/ /// <summary> /// ファイルにAVIStreamHeader構造体の値を書き込みます /// </summary> public static void aviWriteStreamHeader(AVIStreamHeader streamHeader, MainAVIHeader mainHeader, BinaryWriter stream) { //type(AVI_CONTAINER), intent(inout) :: avi Util.fwrite("strh", stream); Util.WriteDWORD(56, stream); // call bmpQWordWrite( 56, avi%fp ) !// AVIStreamHeaderのサイズ //fwrite( streamHeader.fccType, fp );// i = fwrite( avi%streamHeader%fccType, 1, 4, avi%fp ) Util.WriteDWORD((uint)streamHeader.fccType, stream); //fwrite( streamHeader.fccHandler, fp );// i = fwrite( streamHeader.fccHandler, 1, 4, fp ); Util.WriteDWORD((uint)streamHeader.fccHandler, stream); //WriteDWORD( 0, fp ); Util.WriteDWORD(streamHeader.dwFlags, stream); //WriteDWORD( streamHeader.dwReserved1, fp ); Util.WriteWORD(0, stream); //wPriority Util.WriteWORD(0, stream); //wLanghage Util.WriteDWORD(streamHeader.dwInitialFrames, stream); Util.WriteDWORD(streamHeader.dwScale, stream); Util.WriteDWORD(streamHeader.dwRate, stream); Util.WriteDWORD(streamHeader.dwStart, stream); Util.WriteDWORD(streamHeader.dwLength, stream); Util.WriteDWORD(streamHeader.dwSuggestedBufferSize, stream); Util.WriteDWORD(streamHeader.dwQuality, stream); Util.WriteDWORD(streamHeader.dwSampleSize, stream); Util.WriteWORD(0, stream); //left Util.WriteWORD(0, stream); //top Util.WriteWORD((ushort)mainHeader.dwWidth, stream); //right Util.WriteWORD((ushort)mainHeader.dwHeight, stream); //bottom }
public void Write(BinaryWriter fp) { Util.fwrite(fcc, fp); Util.WriteDWORD((uint)cb, fp); Util.WriteWORD(wLongsPerEntry, fp); Util.WriteBYTE(bIndexSubType, fp); Util.WriteBYTE(bIndexType, fp); Util.WriteDWORD((uint)nEntriesInUse, fp); Util.fwrite(dwChunkId, fp); Util.WriteQWORD((ulong)qwBaseOffset, fp); Util.WriteDWORD((uint)dwReserved3, fp); foreach (_avistdindex_entry entry in aIndex) { Util.WriteDWORD((uint)entry.dwOffset, fp); Util.WriteDWORD((uint)entry.dwSize, fp); } }
public void Write(BinaryWriter fp) { Util.fwrite(fcc, fp); Util.WriteDWORD((uint)cb, fp); //ここほんとは(int)cb Util.WriteWORD(wLongsPerEntry, fp); Util.WriteBYTE(bIndexSubType, fp); Util.WriteBYTE(bIndexType, fp); Util.WriteDWORD((uint)nEntriesInUse, fp); Util.fwrite(dwChunkId, fp); Util.WriteDWORD((uint)dwReserved1, fp); Util.WriteDWORD((uint)dwReserved2, fp); Util.WriteDWORD((uint)dwReserved3, fp); foreach (_avisuperindex_entry entry in aIndex) { Util.WriteQWORD((ulong)entry.qwOffset, fp); Util.WriteDWORD((uint)entry.dwSize, fp); Util.WriteDWORD((uint)entry.dwDuration, fp); } }
/// <summary> /// ファイルにMainAviHeader構造体の値を書き込みます /// </summary> public static void aviWriteMainHeader(MainAVIHeader mainHeader, BinaryWriter stream) { //type(AVI_CONTAINER), intent(inout) :: avi Util.fwrite("avih", stream); // i = fwrite( 'avih', 1, 4, avi%fp ) Util.WriteDWORD(56, stream); // MainAVIHeaderのサイズ Util.WriteDWORD(mainHeader.dwMicroSecPerFrame, stream); Util.WriteDWORD(0 /*this.mainHeader.dwMaxBytesPerSec*/, stream); Util.WriteDWORD(mainHeader.dwReserved1, stream); Util.WriteDWORD(mainHeader.dwFlags, stream); Util.WriteDWORD(mainHeader.dwTotalFrames, stream); Util.WriteDWORD(mainHeader.dwInitialFrames, stream); Util.WriteDWORD(mainHeader.dwStreams, stream); Util.WriteDWORD(0 /*this.mainHeader.dwSuggestedBufferSize*/, stream); Util.WriteDWORD(mainHeader.dwWidth, stream); Util.WriteDWORD(mainHeader.dwHeight, stream); Util.WriteDWORD(mainHeader.dwScale, stream); Util.WriteDWORD(mainHeader.dwRate, stream); Util.WriteDWORD(mainHeader.dwStart, stream); Util.WriteDWORD(mainHeader.dwLength, stream); }//end subroutine
/// <summary> /// aviファイルにフレームを1つ追加します. /// </summary> /// <param name="bmp"></param> public void AddFrame(Bitmap bmp) { int i, width, height, lineSize; if (bmp.Width != m_width || bmp.Height != m_height) { throw new Exception("bitmap size mismatch"); } // BitmapDataからビットマップデータと、BITMPAINFOHEADERを取り出す BitmapData bmpDat = bmp.LockBits( new Rectangle(0, 0, (int)bmp.Width, (int)bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); int address = bmpDat.Scan0.ToInt32(); byte[] bitmapData = new byte[bmpDat.Stride * bmpDat.Height]; Marshal.Copy(new IntPtr(address), bitmapData, 0, bitmapData.Length); if (m_is_first) //then { m_is_first = false; this.m_main_header.dwWidth = (uint)m_width; this.m_main_header.dwHeight = (uint)m_height; this.m_main_header.dwMaxBytesPerSec = (uint)(bmpDat.Stride * bmpDat.Height * this.frameRate); // bmp%infoHeader%SizeImage * avi%frameRate this.m_main_header.dwStreams = 1; this.m_main_header.dwSuggestedBufferSize = (uint)(bmpDat.Stride * bmpDat.Height); // bmp.infoHeader%SizeImage m_linesize = bmpDat.Stride; this.m_stream_header.fccType = Util.mmioFOURCC("vids"); this.m_stream_header.fccHandler = 0; this.m_stream_header.dwFlags = 0; this.m_stream_header.dwReserved1 = 0; this.m_stream_header.dwInitialFrames = 0; this.m_stream_header.dwScale = m_scale; this.m_stream_header.dwRate = m_rate; this.m_stream_header.dwStart = 0; this.m_stream_header.dwSuggestedBufferSize = this.m_main_header.dwSuggestedBufferSize; this.m_stream_header.dwQuality = 0; this.m_stream_header.dwSampleSize = 0; Util.aviWriteMainHeader(m_main_header, m_stream); Util.fwrite("LIST", this.m_stream); // i = fwrite( 'LIST', 1, 4, avi%fp ) Util.WriteDWORD(0x874, this.m_stream); // call bmpQWordWrite( 130, avi%fp ) Util.fwrite("strl", this.m_stream); // i = fwrite( 'strl', 1, 4, avi%fp ) Util.aviWriteStreamHeader(m_stream_header, m_main_header, m_stream); // avi ) Util.fwrite("strf", this.m_stream); // i = fwrite( 'strf', 1, 4, avi%fp ) Util.WriteDWORD(0x28, this.m_stream); //call bmpQWordWrite( 40, avi%fp ) !// infoHeaderのサイズ BITMAPINFOHEADER bih = new BITMAPINFOHEADER(); bih.biSize = (uint)(Marshal.SizeOf(bih)); bih.biWidth = bmpDat.Width; bih.biHeight = bmpDat.Height; bih.biPlanes = 1; bih.biBitCount = 24; bih.biCompression = 0;//BI_RGB bih.biSizeImage = (uint)(bmpDat.Stride * bmpDat.Height); bih.biXPelsPerMeter = 0; bih.biYPelsPerMeter = 0; bih.biClrUsed = 0; bih.biClrImportant = 0; bih.Write(m_stream); /*fwrite( "strn", this.fp ); * WriteDWORD( 6, this.fp ); * fwrite( "VIDEO", this.fp ); * WriteBYTE( 0, this.fp );*/ Util.fwrite("indx", this.m_stream); //fcc Util.WriteDWORD(0x7f8, this.m_stream); // cb Util.WriteWORD((byte)0x4, this.m_stream); // wLongsPerEntry Util.WriteBYTE(0x0, this.m_stream); // bIndexSubType Util.WriteBYTE(Util.AVI_INDEX_OF_INDEXES, this.m_stream); // bIndexType Util.WriteDWORD(0x0, this.m_stream); // nEntriesInUse Util.fwrite("00db", this.m_stream); // dwChunkId Util.WriteDWORD(0x0, this.m_stream); Util.WriteDWORD(0x0, this.m_stream); Util.WriteDWORD(0x0, this.m_stream); for (int ii = 1; ii <= 126; ii++) { Util.WriteQWORD(0x0, this.m_stream); Util.WriteDWORD(0x0, this.m_stream); Util.WriteDWORD(0x0, this.m_stream); } Util.fwrite("LIST", this.m_stream); Util.WriteDWORD(0x104, m_stream); Util.fwrite("odml", this.m_stream); Util.fwrite("dmlh", m_stream); Util.WriteDWORD(0xf8, m_stream); Util.WriteDWORD(0x0, m_stream); //ここ後で更新するべき for (int ii = 1; ii <= 61; ii++) { Util.WriteDWORD(0x0, m_stream); } Util.fwrite("JUNK", this.m_stream); // i = fwrite( 'JUNK', 1, 4, avi%fp ) Util.WriteDWORD(0x60c, m_stream); Util.WriteDWORD(0, m_stream); //"This"が将来登録されたらやばいので Util.fwrite("This file was generated by RawAvi@LipSync", this.m_stream); //WriteDWORD( 1503, this.fp );// call bmpQWordWrite( 1802, avi%fp ) for (i = 1; i <= 1503; i++) //do i = 1, 1802 { this.m_stream.Write((byte)0); // call fputc( 0, avi%fp ) }//end do m_junk_length = 0xff4; Util.fwrite("LIST", this.m_stream); // i = fwrite( 'LIST', 1, 4, avi%fp ) m_movi_position = m_stream.BaseStream.Position; Util.WriteDWORD(0, this.m_stream); // call bmpQWordWrite( 0, avi%fp ) !// ******************ココの数字は一番最後に書き換える必要あり2040~2043あとdwTotalFrames(48~51)も Util.fwrite("movi", this.m_stream); // i = fwrite( 'movi', 1, 4, avi%fp ) m_next_framedata_position = m_stream.BaseStream.Position; m_std_index.SetBaseOffset((ulong)m_next_framedata_position); m_super_index.nEntriesInUse++; }//end if if (m_next_framedata_position != m_stream.BaseStream.Position) { m_stream.BaseStream.Seek(m_next_framedata_position, SeekOrigin.Begin); } long chunk_size = m_next_framedata_position - m_riff_position; #if DEBUG // MessageBox.Show( "chunk_size=" + chunk_size ); #endif if ((m_current_chunk == 0 && chunk_size > m_split_sreshold) || (m_current_chunk > 0 && chunk_size > SRESHOLD)) { // AVIXリストへの書き込みに移行 UpdateIndex(); m_stream.BaseStream.Seek(m_avix_position, SeekOrigin.Begin); Util.fwrite("RIFF", m_stream); m_riff_position = m_stream.BaseStream.Position; #if DEBUG // fp.Flush(); // MessageBox.Show( "m_riff_position=" + m_riff_position ); #endif Util.WriteDWORD(0, m_stream); Util.fwrite("AVIX", m_stream); long current = m_stream.BaseStream.Position; if ((current + 12) % 0x800 != 0) { long additional = (current + 20) % 0x800; additional = 0x800 - ((current + 20) % 0x800); m_junk_length = (int)additional + 20; Util.fwrite("JUNK", m_stream); Util.WriteDWORD((uint)additional, m_stream); for (long ii = 0; ii < additional; ii++) { Util.WriteBYTE((byte)0, m_stream); } } else { m_junk_length = 0; } m_junk_length = 0; Util.fwrite("LIST", m_stream); m_movi_position = m_stream.BaseStream.Position; Util.WriteDWORD(0, m_stream); //後で更新するべき Util.fwrite("movi", m_stream); m_next_framedata_position = m_stream.BaseStream.Position; m_std_index.aIndex.Clear(); m_std_index.SetBaseOffset((ulong)m_next_framedata_position); m_current_chunk++; m_super_index.nEntriesInUse++; } // フレームを書き込む処理 width = (int)this.m_main_header.dwWidth; height = (int)this.m_main_header.dwHeight; if (width != bmpDat.Width) //then //aviAddFrame = -1 { return; }//end if if (height != bmpDat.Height) //then //aviAddframe = -1 { return; }//end if lineSize = bmpDat.Stride;// int( (width * 24 + 31) / 32 ) * 4 m_std_index.AddIndex((uint)((ulong)m_stream.BaseStream.Position - m_std_index.qwBaseOffset) + 8, (uint)(lineSize * height)); Util.fwrite("00db", this.m_stream); // i = fwrite( '00db', 1, 4, avi%fp ) Util.WriteDWORD(m_main_header.dwSuggestedBufferSize, m_stream); // call bmpQWordWrite( avi%mainHeader%dwSuggestedBufferSize, avi%fp ) m_stream.Write(bitmapData); m_next_framedata_position = m_stream.BaseStream.Position; _avisuperindex_entry entry = m_super_index.aIndex[m_current_chunk]; entry.dwDuration++; m_super_index.aIndex[m_current_chunk] = entry; // avi%noOfFrame = avi%noOfFrame + 1 this.m_stream.Flush(); // aviAddFrame = fflush( avi%fp ) bmp.UnlockBits(bmpDat); }// end function
/*[Obsolete] * public void Open( string file, float frameRate ) { * uint scale, rate; * AviWriter.CalcScaleAndRate( (decimal)frameRate, out scale, out rate ); * Open( file, scale, rate ); * }*/ //todo: AVIMainHeader.dwTotalFramesに、ファイル全体のフレーム数を入れる(仕様違反) //todo: AVIStreamHeader.dwLengthに、ファイル全体のフレーム数を入れる(仕様違反) /// <summary> /// 全てのインデックスを更新し、ファイルが(動画ファイルとして)使用できる状態にします /// この関数を読んだあとでも,さらにaviAddFrame関数を使うことでフレームを追加することが出来ます. /// </summary> public void UpdateIndex() { _avisuperindex_entry entry = m_super_index.aIndex[m_current_chunk]; entry.qwOffset = (ulong)m_stream.BaseStream.Position; entry.dwSize = m_std_index.cb; m_super_index.aIndex[m_current_chunk] = entry; if (m_stream.BaseStream.Position != m_next_framedata_position) { m_stream.BaseStream.Seek(m_next_framedata_position, SeekOrigin.Begin); } m_std_index.Write(m_stream); int frames = (int)m_super_index.aIndex[m_current_chunk].dwDuration; m_avix_position = m_stream.BaseStream.Position; if (m_current_chunk == 0) { uint i, step, number; step = this.m_main_header.dwSuggestedBufferSize + 8; Util.fwrite("idx1", this.m_stream); Util.WriteDWORD((uint)(16 * frames), this.m_stream); for (i = 1; i <= frames; i++) { Util.fwrite("00db", this.m_stream); Util.WriteDWORD(Util.AVIF_HASINDEX, this.m_stream); Util.WriteDWORD((uint)(4 + (i - 1) * step), this.m_stream); Util.WriteDWORD(this.m_main_header.dwSuggestedBufferSize, this.m_stream); }// end do m_avix_position = m_stream.BaseStream.Position; number = (uint)frames; //avi_writeIsolate( this.fp, number, 48 ); // AVIMainHeader.dwTotalFrames m_stream.Seek(48, SeekOrigin.Begin); Util.WriteDWORD(number, m_stream); //avi_writeIsolate( this.fp, number, 140 ); // AVIStreamHeader.dwLength m_stream.Seek(140, SeekOrigin.Begin); Util.WriteDWORD(number, m_stream); //odml dlmhのdwTotalFrames m_stream.Seek(0x8e8, SeekOrigin.Begin); Util.WriteDWORD((uint)frames, m_stream); // LIST****moviの****の数値を計算 number = 4; //"movi" number += (uint)(frames * (m_linesize * m_main_header.dwHeight + 8)); //フレーム数*(フレームのサイズ+"00db"+00dbチャンクのサイズ) number += 4 + 4 + (uint)m_std_index.cb; //ix00のサイズ //number += 4 + 4 + 16 * frames;//idx1のサイズ //avi_writeIsolate( this.fp, number, 2040 ); // LIST****movi の ****部分 m_stream.BaseStream.Seek(m_movi_position, SeekOrigin.Begin); Util.WriteDWORD(number, m_stream); //number = 4096 + (this.mainHeader.dwSuggestedBufferSize + 24) * this.noOfFrame; //avi_writeIsolate( this.fp, number, 4 ); // RIFF****AVI の ****部分 number = (uint)m_junk_length /* 0xff4*/; //JUNKの終わりまでのサイズ。これは固定 number += 4; //"movi" number += (uint)(frames * (m_linesize * m_main_header.dwHeight + 8)); //00db...の合計サイズ number += 4 + 4 + (uint)m_std_index.cb; number += (uint)(4 + 4 + 16 * frames); //idx1のサイズ m_stream.BaseStream.Seek(m_riff_position, SeekOrigin.Begin); Util.WriteDWORD(number, m_stream); UpdateIndexOfIndex(); } else { // LIST****moviの****を更新 int number = 4; number += (int)(frames * (m_linesize * m_main_header.dwHeight + 8)); number += 8 + (int)m_std_index.cb; m_stream.BaseStream.Seek(m_movi_position, SeekOrigin.Begin); Util.WriteDWORD((uint)number, m_stream); // odml dlmhのdwTotalFrames uint frames2 = 0; for (int j = 0; j <= m_current_chunk; j++) { frames2 += (uint)m_super_index.aIndex[j].dwDuration; } m_stream.BaseStream.Seek(0x8e8, SeekOrigin.Begin); Util.WriteDWORD(frames2, m_stream); //avi_writeIsolate( this.fp, number, 48 ); // AVIMainHeader.dwTotalFrames m_stream.Seek(48, SeekOrigin.Begin); Util.WriteDWORD(frames2, m_stream); //avi_writeIsolate( this.fp, number, 140 ); // AVIStreamHeader.dwLength m_stream.Seek(140, SeekOrigin.Begin); Util.WriteDWORD(frames2, m_stream); //RIFF****AVIXの****を更新 long num2 = m_junk_length + number; m_stream.BaseStream.Seek(m_riff_position, SeekOrigin.Begin); Util.WriteDWORD((uint)num2, m_stream); UpdateIndexOfIndex(); } }
/// <summary> /// aviファイルにフレームを1つ追加します. /// </summary> /// <param name="bmp"></param> public unsafe void AddFrame(Bitmap bmp) { int width, height, lineSize; BitmapData bmpDat; if (m_is_transparent) { bmpDat = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); } else { bmpDat = bmp.LockBits(new Rectangle(0, 0, (int)bmp.Width, (int)bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); } if (m_next_framedata_position != m_stream.BaseStream.Position) { m_stream.BaseStream.Seek(m_next_framedata_position, SeekOrigin.Begin); } long chunk_size = m_next_framedata_position - m_riff_position; if ((m_current_chunk == 0 && chunk_size > m_split_sreshold) || (m_current_chunk > 0 && chunk_size > _THRESHOLD)) { // AVIXリストへの書き込みに移行 UpdateIndex(); m_stream.BaseStream.Seek(m_avix_position, SeekOrigin.Begin); Util.fwrite("RIFF", m_stream); m_riff_position = m_stream.BaseStream.Position; Util.WriteDWORD(0, m_stream); Util.fwrite("AVIX", m_stream); long current = m_stream.BaseStream.Position; if ((current + 12) % 0x800 != 0) { long additional = (current + 20) % 0x800; additional = 0x800 - ((current + 20) % 0x800); m_junk_length = (int)additional + 20; Util.fwrite("JUNK", m_stream); Util.WriteDWORD((uint)additional, m_stream); for (long ii = 0; ii < additional; ii++) { Util.WriteBYTE((byte)0, m_stream); } } else { m_junk_length = 0; } m_junk_length = 0; Util.fwrite("LIST", m_stream); m_movi_position = m_stream.BaseStream.Position; Util.WriteDWORD(0, m_stream);//後で更新するべき Util.fwrite("movi", m_stream); m_next_framedata_position = m_stream.BaseStream.Position; m_std_index.aIndex.Clear(); m_std_index.SetBaseOffset((ulong)m_next_framedata_position); m_current_chunk++; m_super_index.nEntriesInUse++; } // フレームを書き込む処理 width = (int)m_main_header.dwWidth; height = (int)m_main_header.dwHeight; if (width != bmpDat.Width) { return; } if (height != bmpDat.Height) { return; } lineSize = bmpDat.Stride; if (m_compressed) { int is_key_frame = 0; int size = bmpDat.Stride * bmpDat.Height; try { IntPtr dat = VCM.ICSeqCompressFrame(m_compvar, 0, bmpDat.Scan0, &is_key_frame, &size); if (!dat.Equals(IntPtr.Zero)) { byte[] ndat = new byte[size]; Marshal.Copy(dat, ndat, 0, size); m_std_index.AddIndex((uint)((ulong)m_stream.BaseStream.Position - m_std_index.qwBaseOffset) + 8, (uint)size); Util.fwrite("00db", m_stream); Util.WriteDWORD((uint)size, m_stream); m_stream.Write(ndat, 0, size); m_this_movi_size += size; } } catch { } } else { m_std_index.AddIndex((uint)((ulong)m_stream.BaseStream.Position - m_std_index.qwBaseOffset) + 8, (uint)(lineSize * height)); Util.fwrite("00db", m_stream); int address = bmpDat.Scan0.ToInt32(); byte[] bitmapData = new byte[bmpDat.Stride * bmpDat.Height]; Marshal.Copy(new IntPtr(address), bitmapData, 0, bitmapData.Length); Util.WriteDWORD(m_main_header.dwSuggestedBufferSize, m_stream); m_stream.Write(bitmapData); m_this_movi_size += bitmapData.Length; } m_next_framedata_position = m_stream.BaseStream.Position; _avisuperindex_entry entry = m_super_index.aIndex[m_current_chunk]; entry.dwDuration++; m_super_index.aIndex[m_current_chunk] = entry; m_stream.Flush(); bmp.UnlockBits(bmpDat); }
/// <summary> /// 指定したAVI_CONTAINER構造体にAVIファイルの情報を格納すると共に, /// ファイルにヘッダー情報を書き込みます. /// </summary> /// <param name="file">書き込み対象のファイル</param> /// <param name="scale"></param> /// <param name="rate"></param> /// <param name="compressed"></param> public unsafe bool Open(string file, uint scale, uint rate, int width, int height, bool compressed, bool transparent, IntPtr hWnd) { #if DEBUG Console.WriteLine("AviWriterEx.Open(string,uint,uint,bool,IntPtr)"); #endif m_stream = new BinaryWriter(new FileStream(file, FileMode.Create, FileAccess.Write)); float fps = (float)rate / (float)scale; m_main_header.dwMicroSecPerFrame = (uint)(1.0e6 / fps);// ! 1秒は10^6μ秒 m_main_header.dwReserved1 = 0; m_main_header.dwFlags = 2064; m_main_header.dwInitialFrames = 0; m_main_header.dwStreams = 0; m_main_header.dwScale = scale; m_main_header.dwRate = rate; m_main_header.dwStart = 0; m_main_header.dwLength = 0; m_rate = rate; m_scale = scale; Util.fwrite("RIFF", m_stream); Util.WriteDWORD(0, m_stream); Util.fwrite("AVI ", m_stream); Util.fwrite("LIST", m_stream); Util.WriteDWORD(0x9cc, m_stream); Util.fwrite("hdrl", m_stream); m_current_chunk = 0; m_position_in_chunk = 0L; m_std_index = new AVISTDINDEX(0L); m_super_index = new AVISUPERINDEX(0); m_riff_position = 0x4; m_compressed = compressed; m_is_transparent = transparent; m_stream_fcc_handler = 0; m_hwnd = hWnd; m_file = file; m_opened = true; if (m_is_first) { int stride = 0; using (Bitmap b = new Bitmap(width, height, m_is_transparent ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb)) { BitmapData bd = b.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, b.PixelFormat); stride = bd.Stride; b.UnlockBits(bd); } m_is_first = false; m_main_header.dwWidth = (uint)width; m_main_header.dwHeight = (uint)height; m_main_header.dwMaxBytesPerSec = (uint)(stride * height * frameRate); m_main_header.dwStreams = 1; m_main_header.dwSuggestedBufferSize = (uint)(stride * height); m_linesize = stride; m_stream_header.fccType = Util.mmioFOURCC("vids"); m_stream_header.fccHandler = 0; m_stream_header.dwFlags = 0; m_stream_header.dwReserved1 = 0; m_stream_header.dwInitialFrames = 0; m_stream_header.dwScale = m_scale; m_stream_header.dwRate = m_rate; m_stream_header.dwStart = 0; m_stream_header.dwSuggestedBufferSize = m_main_header.dwSuggestedBufferSize; m_stream_header.dwQuality = 0; m_stream_header.dwSampleSize = 0; Util.aviWriteMainHeader(m_main_header, m_stream); Util.fwrite("LIST", m_stream); Util.WriteDWORD(0x874, m_stream); Util.fwrite("strl", m_stream); Util.aviWriteStreamHeader(m_stream_header, m_main_header, m_stream); Util.fwrite("strf", m_stream); BITMAPINFOHEADER bih = new BITMAPINFOHEADER(); //(BITMAPINFOHEADER)Marshal.PtrToStructure( Marshal.AllocHGlobal( sizeof( BITMAPINFOHEADER ) ), typeof( BITMAPINFOHEADER ) ); bih.biSize = (uint)(Marshal.SizeOf(bih)); bih.biWidth = width; bih.biHeight = height; bih.biPlanes = 1; bih.biBitCount = m_is_transparent ? (short)32 : (short)24; bih.biCompression = 0;//BI_RGB bih.biSizeImage = (uint)(stride * height); bih.biXPelsPerMeter = 0; bih.biYPelsPerMeter = 0; bih.biClrUsed = 0; bih.biClrImportant = 0; if (m_compressed) { m_p_compvar = Marshal.AllocHGlobal(sizeof(COMPVARS)); m_compvar = (COMPVARS *)m_p_compvar.ToPointer(); byte[] buf = new byte[sizeof(COMPVARS)]; for (int i = 0; i < buf.Length; i++) { buf[i] = 0x0; } Marshal.Copy(buf, 0, m_p_compvar, buf.Length); m_compvar->cbSize = sizeof(COMPVARS); int ret = VCM.ICCompressorChoose(m_hwnd, 0, IntPtr.Zero, IntPtr.Zero, m_compvar, "Select Video Compressor"); if (ret == 0) { m_opened = false; Marshal.FreeHGlobal(m_p_compvar); m_stream.Close(); return(false); } if (m_compvar->hic != 0) { m_p_bitmapinfo_in = Marshal.AllocHGlobal(sizeof(BITMAPINFO)); m_bitmapinfo_in = (BITMAPINFO *)m_p_bitmapinfo_in.ToPointer(); buf = new byte[sizeof(BITMAPINFO)]; for (int i = 0; i < buf.Length; i++) { buf[i] = 0x0; } Marshal.Copy(buf, 0, m_p_bitmapinfo_in, buf.Length); m_bitmapinfo_in->bmiHeader = bih; uint dwSize = VCM.ICCompressGetFormatSize(m_compvar->hic, m_bitmapinfo_in); #if DEBUG Console.WriteLine("m_compvar->hic=" + m_compvar->hic); Console.WriteLine("ICCompressGetFormatSize=" + dwSize); #endif m_p_bitmapinfo_out = Marshal.AllocHGlobal((int)dwSize); m_bitmapinfo_out = (BITMAPINFO *)m_p_bitmapinfo_out.ToPointer(); buf = new byte[dwSize]; for (int i = 0; i < buf.Length; i++) { buf[i] = 0x0; } Marshal.Copy(buf, 0, m_p_bitmapinfo_out, buf.Length); VCM.ICCompressGetFormat(m_compvar->hic, m_bitmapinfo_in, m_bitmapinfo_out); m_bih_compression = m_bitmapinfo_out->bmiHeader.biCompression; #if DEBUG Console.WriteLine("AddFrame(Bitmap)"); Console.WriteLine(" biout.biSize=" + m_bitmapinfo_out->bmiHeader.biSize); #endif VCM.ICSeqCompressFrameStart(m_compvar, m_bitmapinfo_in); bih = m_bitmapinfo_out->bmiHeader; Util.WriteDWORD(bih.biSize, m_stream);// infoHeaderのサイズ m_bitmapinfo_out->Write(m_stream); } else { m_compressed = false; Util.WriteDWORD(bih.biSize, m_stream);// infoHeaderのサイズ bih.Write(m_stream); } } else { Util.WriteDWORD(bih.biSize, m_stream);// infoHeaderのサイズ bih.Write(m_stream); } m_super_index_position = m_stream.BaseStream.Position; Util.fwrite("indx", m_stream); //fcc Util.WriteDWORD(0x7f8, m_stream); // cb Util.WriteWORD((byte)0x4, m_stream); // wLongsPerEntry Util.WriteBYTE(0x0, m_stream); // bIndexSubType Util.WriteBYTE(Util.AVI_INDEX_OF_INDEXES, m_stream); // bIndexType Util.WriteDWORD(0x0, m_stream); // nEntriesInUse Util.fwrite("00db", m_stream); // dwChunkId Util.WriteDWORD(0x0, m_stream); Util.WriteDWORD(0x0, m_stream); Util.WriteDWORD(0x0, m_stream); for (int ii = 1; ii <= 126; ii++) { Util.WriteQWORD(0x0, m_stream); Util.WriteDWORD(0x0, m_stream); Util.WriteDWORD(0x0, m_stream); } Util.fwrite("LIST", m_stream); Util.WriteDWORD(0x104, m_stream); Util.fwrite("odml", m_stream); Util.fwrite("dmlh", m_stream); Util.WriteDWORD(0xf8, m_stream); Util.WriteDWORD(0x0, m_stream);//ここ後で更新するべき for (int ii = 1; ii <= 61; ii++) { Util.WriteDWORD(0x0, m_stream); } Util.fwrite("JUNK", m_stream); Util.WriteDWORD(0x60c, m_stream); Util.WriteDWORD(0, m_stream);//"This"が将来登録されたらやばいので string msg = "This file was generated by [email protected];VfwBugCompatible=" + VfwBugCompatible; const int tlen = 1544; int remain = tlen - msg.Length; Util.fwrite(msg, m_stream); for (int i = 1; i <= remain; i++) { m_stream.Write((byte)0); } m_junk_length = 0xff4; Util.fwrite("LIST", m_stream); m_movi_position = m_stream.BaseStream.Position; Util.WriteDWORD(0, m_stream);// call bmpQWordWrite( 0, avi%fp ) !// ******************ココの数字は一番最後に書き換える必要あり2040~2043あとdwTotalFrames(48~51)も Util.fwrite("movi", m_stream); m_next_framedata_position = m_stream.BaseStream.Position; m_std_index.SetBaseOffset((ulong)m_next_framedata_position); m_super_index.nEntriesInUse++; } return(true); }