using System; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; using System.IO; namespace Plugin { public class Avi { public const int StreamtypeVIDEO = 1935960438; //mmioStringToFOURCC("vids", 0) public const int OF_SHARE_DENY_WRITE = 32; public const int BMP_MAGIC_COOKIE = 19778; //ascii string "BM" #region structure declarations [StructLayout( LayoutKind.Sequential, Pack = 1 )] public struct RECT { public UInt32 left; public UInt32 top; public UInt32 right; public UInt32 bottom; } [StructLayout( LayoutKind.Sequential, Pack = 1 )] public struct BITMAPINFOHEADER { public UInt32 biSize; public Int32 biWidth; public Int32 biHeight; public Int16 biPlanes; public Int16 biBitCount; public UInt32 biCompression; public UInt32 biSizeImage; public Int32 biXPelsPerMeter; public Int32 biYPelsPerMeter; public UInt32 biClrUsed; public UInt32 biClrImportant; } [StructLayout( LayoutKind.Sequential, Pack = 1 )] public struct AVISTREAMINFO { public UInt32 fccType; public UInt32 fccHandler; public UInt32 dwFlags; public UInt32 dwCaps; public UInt16 wPriority; public UInt16 wLanguage; public UInt32 dwScale; public UInt32 dwRate; public UInt32 dwStart; public UInt32 dwLength; public UInt32 dwInitialFrames; public UInt32 dwSuggestedBufferSize; public UInt32 dwQuality; public UInt32 dwSampleSize; public RECT rcFrame; public UInt32 dwEditCount; public UInt32 dwFormatChangeCount; [MarshalAs( UnmanagedType.ByValArray, SizeConst = 64 )] public UInt16[] szName; } [StructLayout( LayoutKind.Sequential, Pack = 1 )] public struct BITMAPFILEHEADER { public Int16 bfType; //"magic cookie" - must be "BM" public Int32 bfSize; public Int16 bfReserved1; public Int16 bfReserved2; public Int32 bfOffBits; } #endregion structure declarations #region method declarations //Initialize the AVI library [DllImport( "avifil32.dll" )] public static extern void AVIFileInit(); //Open an AVI file [DllImport( "avifil32.dll", PreserveSig = true )] public static extern int AVIFileOpen( ref int ppfile, String szFile, int uMode, int pclsidHandler ); //Get a stream from an open AVI file [DllImport( "avifil32.dll" )] public static extern int AVIFileGetStream( int pfile, out IntPtr ppavi, int fccType, int lParam ); //Get the start position of a stream [DllImport( "avifil32.dll", PreserveSig = true )] public static extern int AVIStreamStart( int pavi ); //Get the length of a stream in frames [DllImport( "avifil32.dll", PreserveSig = true )] public static extern int AVIStreamLength( int pavi ); //Get information about an open stream [DllImport( "avifil32.dll" )] public static extern int AVIStreamInfo( int pAVIStream, ref AVISTREAMINFO psi, int lSize ); //Get a pointer to a GETFRAME object (returns 0 on error) [DllImport( "avifil32.dll" )] public static extern int AVIStreamGetFrameOpen( IntPtr pAVIStream, ref BITMAPINFOHEADER bih ); /*[DllImport("avifil32.dll")] public static extern int AVIStreamGetFrameOpen( IntPtr pAVIStream, int dummy);*/ //Get a pointer to a packed DIB (returns 0 on error) [DllImport( "avifil32.dll" )] public static extern int AVIStreamGetFrame( int pGetFrameObj, int lPos ); //Create a new stream in an open AVI file [DllImport( "avifil32.dll" )] public static extern int AVIFileCreateStream( int pfile, out IntPtr ppavi, ref AVISTREAMINFO ptr_streaminfo ); //Set the format for a new stream [DllImport( "avifil32.dll" )] public static extern int AVIStreamSetFormat( IntPtr aviStream, Int32 lPos, ref BITMAPINFOHEADER lpFormat, Int32 cbFormat ); //Write a sample to a stream [DllImport( "avifil32.dll" )] public static extern int AVIStreamWrite( IntPtr aviStream, Int32 lStart, Int32 lSamples, IntPtr lpBuffer, Int32 cbBuffer, Int32 dwFlags, Int32 dummy1, Int32 dummy2 ); //Release the GETFRAME object [DllImport( "avifil32.dll" )] public static extern int AVIStreamGetFrameClose( int pGetFrameObj ); //Release an open AVI stream [DllImport( "avifil32.dll" )] public static extern int AVIStreamRelease( IntPtr aviStream ); //Release an open AVI file [DllImport( "avifil32.dll" )] public static extern int AVIFileRelease( int pfile ); //Close the AVI library [DllImport( "avifil32.dll" )] public static extern void AVIFileExit(); #endregion methos declarations #region other useful avi functions //public const int StreamtypeAUDIO = 1935963489; //mmioStringToFOURCC("auds", 0) //public const int StreamtypeMIDI = 1935960429; //mmioStringToFOURCC("mids", 0) //public const int StreamtypeTEXT = 1937012852; //mmioStringToFOURCC("txts", 0) /*[StructLayout(LayoutKind.Sequential, Pack=1)] public struct AVIFILEINFO{ public Int32 dwMaxBytesPerSecond; public Int32 dwFlags; public Int32 dwCaps; public Int32 dwStreams; public Int32 dwSuggestedBufferSize; public Int32 dwWidth; public Int32 dwHeight; public Int32 dwScale; public Int32 dwRate; public Int32 dwLength; public Int32 dwEditCount; [MarshalAs(UnmanagedType.ByValArray, SizeConst=64)] public char[] szFileType; }*/ /*[StructLayout(LayoutKind.Sequential, Pack=1)] public struct AVICOMPRESSOPTIONS { public UInt32 fccType; public UInt32 fccHandler; public UInt32 dwKeyFrameEvery; // only used with AVICOMRPESSF_KEYFRAMES public UInt32 dwQuality; public UInt32 dwBytesPerSecond; // only used with AVICOMPRESSF_DATARATE public UInt32 dwFlags; public IntPtr lpFormat; public UInt32 cbFormat; public IntPtr lpParms; public UInt32 cbParms; public UInt32 dwInterleaveEvery; }*/ /*[DllImport("avifil32.dll")] public static extern int AVIMakeCompressedStream( out IntPtr ppsCompressed, IntPtr aviStream, ref AVICOMPRESSOPTIONS ao, int dummy);*/ /*[DllImport("avifil32.dll")] public static extern int AVISaveOptions( IntPtr hWnd, int uiFlags, int nStreams, ref IntPtr ppavi, ref IntPtr ppOptions);*/ /*[DllImport("avifil32.dll")] public static extern int AVIFileInfo( int pfile, ref AVIFILEINFO pfi, int lSize);*/ /*[DllImport("winmm.dll", EntryPoint="mmioStringToFOURCCA")] public static extern int mmioStringToFOURCC(String sz, int uFlags);*/ /*[DllImport("avifil32.dll")] public static extern int AVIStreamRead( IntPtr pavi, Int32 lStart, Int32 lSamples, IntPtr lpBuffer, Int32 cbBuffer, Int32 plBytes, Int32 plSamples );*/ #endregion other useful avi functions } /// Extract bitmaps from AVI files public class AviReader { //position of the first frame, count of frames in the stream private int firstFrame = 0, countFrames = 0; //pointers private int aviFile = 0; private int getFrameObject; private IntPtr aviStream; //stream and header info private Avi.AVISTREAMINFO streamInfo; public int CountFrames { get { return countFrames; } } public UInt32 FrameRate { get { return streamInfo.dwRate / streamInfo.dwScale; } } public Size BitmapSize { get { return new Size( (int)streamInfo.rcFrame.right, (int)streamInfo.rcFrame.bottom ); } } /// Opens an AVI file and creates a GetFrame object /// Name of the AVI file public void Open( string fileName ) { //Intitialize AVI library Avi.AVIFileInit(); //Open the file int result = Avi.AVIFileOpen( ref aviFile, fileName, Avi.OF_SHARE_DENY_WRITE, 0 ); if ( result != 0 ) { throw new Exception( "Exception in AVIFileOpen: " + result.ToString() ); } //Get the video stream result = Avi.AVIFileGetStream( aviFile, out aviStream, Avi.StreamtypeVIDEO, 0 ); if ( result != 0 ) { throw new Exception( "Exception in AVIFileGetStream: " + result.ToString() ); } firstFrame = Avi.AVIStreamStart( aviStream.ToInt32() ); countFrames = Avi.AVIStreamLength( aviStream.ToInt32() ); streamInfo = new Avi.AVISTREAMINFO(); result = Avi.AVIStreamInfo( aviStream.ToInt32(), ref streamInfo, Marshal.SizeOf( streamInfo ) ); if ( result != 0 ) { throw new Exception( "Exception in AVIStreamInfo: " + result.ToString() ); } //Open frames Avi.BITMAPINFOHEADER bih = new Avi.BITMAPINFOHEADER(); bih.biBitCount = 24; bih.biClrImportant = 0; bih.biClrUsed = 0; bih.biCompression = 0; //BI_RGB; bih.biHeight = (Int32)streamInfo.rcFrame.bottom; bih.biWidth = (Int32)streamInfo.rcFrame.right; bih.biPlanes = 1; bih.biSize = (UInt32)Marshal.SizeOf( bih ); bih.biXPelsPerMeter = 0; bih.biYPelsPerMeter = 0; getFrameObject = Avi.AVIStreamGetFrameOpen( aviStream, ref bih ); //force function to return 24bit DIBS //getFrameObject = Avi.AVIStreamGetFrameOpen(aviStream, 0); //return any bitmaps if ( getFrameObject == 0 ) { throw new Exception( "Exception in AVIStreamGetFrameOpen!" ); } } /// Closes all streams, files and libraries public void Close() { if ( getFrameObject != 0 ) { Avi.AVIStreamGetFrameClose( getFrameObject ); getFrameObject = 0; } if ( aviStream != IntPtr.Zero ) { Avi.AVIStreamRelease( aviStream ); aviStream = IntPtr.Zero; } if ( aviFile != 0 ) { Avi.AVIFileRelease( aviFile ); aviFile = 0; } Avi.AVIFileExit(); } public Bitmap Export( int position ) { if ( position > countFrames ) { throw new Exception( "Invalid frame position" ); } //Decompress the frame and return a pointer to the DIB int pDib = Avi.AVIStreamGetFrame( getFrameObject, firstFrame + position ); //Copy the bitmap header into a managed struct Avi.BITMAPINFOHEADER bih = new Avi.BITMAPINFOHEADER(); bih = (Avi.BITMAPINFOHEADER)Marshal.PtrToStructure( new IntPtr( pDib ), bih.GetType() ); /*if(bih.biBitCount < 24){ throw new Exception("Not enough colors! DIB color depth is less than 24 bit."); }else */ if ( bih.biSizeImage < 1 ) { throw new Exception( "Exception in AVIStreamGetFrame: Not bitmap decompressed." ); } //Copy the image byte[] bitmapData = new byte[bih.biSizeImage]; int address = pDib + Marshal.SizeOf( bih ); for ( int offset = 0; offset < bitmapData.Length; offset++ ) { bitmapData[offset] = Marshal.ReadByte( new IntPtr( address ) ); address++; } //Copy bitmap info byte[] bitmapInfo = new byte[Marshal.SizeOf( bih )]; IntPtr ptr; ptr = Marshal.AllocHGlobal( bitmapInfo.Length ); Marshal.StructureToPtr( bih, ptr, false ); address = ptr.ToInt32(); for ( int offset = 0; offset < bitmapInfo.Length; offset++ ) { bitmapInfo[offset] = Marshal.ReadByte( new IntPtr( address ) ); address++; } //Create file header Avi.BITMAPFILEHEADER bfh = new Avi.BITMAPFILEHEADER(); bfh.bfType = Avi.BMP_MAGIC_COOKIE; bfh.bfSize = (Int32)(55 + bih.biSizeImage); //size of file as written to disk bfh.bfReserved1 = 0; bfh.bfReserved2 = 0; bfh.bfOffBits = Marshal.SizeOf( bih ) + Marshal.SizeOf( bfh ); //Create or overwrite the destination file MemoryStream fs = new MemoryStream(); //FileStream fs = new FileStream( dstFileName, System.IO.FileMode.Create ); BinaryWriter bw = new BinaryWriter( fs ); //Write header bw.Write( bfh.bfType ); bw.Write( bfh.bfSize ); bw.Write( bfh.bfReserved1 ); bw.Write( bfh.bfReserved2 ); bw.Write( bfh.bfOffBits ); //Write bitmap info bw.Write( bitmapInfo ); //Write bitmap data bw.Write( bitmapData ); bw.Close(); // fs.Close(); fs.Flush(); fs.Seek( 0, SeekOrigin.Begin ); Bitmap bmp = new Bitmap( fs ); fs.Close(); return bmp; } /// Exports a frame into a bitmap file /// Position of the frame /// Name ofthe file to store the bitmap public void ExportBitmap( int position, String dstFileName ) { if ( position > countFrames ) { throw new Exception( "Invalid frame position" ); } //Decompress the frame and return a pointer to the DIB int pDib = Avi.AVIStreamGetFrame( getFrameObject, firstFrame + position ); //Copy the bitmap header into a managed struct Avi.BITMAPINFOHEADER bih = new Avi.BITMAPINFOHEADER(); bih = (Avi.BITMAPINFOHEADER)Marshal.PtrToStructure( new IntPtr( pDib ), bih.GetType() ); /*if(bih.biBitCount < 24){ throw new Exception("Not enough colors! DIB color depth is less than 24 bit."); }else */ if ( bih.biSizeImage < 1 ) { throw new Exception( "Exception in AVIStreamGetFrame: Not bitmap decompressed." ); } //Copy the image byte[] bitmapData = new byte[bih.biSizeImage]; int address = pDib + Marshal.SizeOf( bih ); for ( int offset = 0; offset < bitmapData.Length; offset++ ) { bitmapData[offset] = Marshal.ReadByte( new IntPtr( address ) ); address++; } //Copy bitmap info byte[] bitmapInfo = new byte[Marshal.SizeOf( bih )]; IntPtr ptr; ptr = Marshal.AllocHGlobal( bitmapInfo.Length ); Marshal.StructureToPtr( bih, ptr, false ); address = ptr.ToInt32(); for ( int offset = 0; offset < bitmapInfo.Length; offset++ ) { bitmapInfo[offset] = Marshal.ReadByte( new IntPtr( address ) ); address++; } //Create file header Avi.BITMAPFILEHEADER bfh = new Avi.BITMAPFILEHEADER(); bfh.bfType = Avi.BMP_MAGIC_COOKIE; bfh.bfSize = (Int32)(55 + bih.biSizeImage); //size of file as written to disk bfh.bfReserved1 = 0; bfh.bfReserved2 = 0; bfh.bfOffBits = Marshal.SizeOf( bih ) + Marshal.SizeOf( bfh ); //Create or overwrite the destination file FileStream fs = new FileStream( dstFileName, System.IO.FileMode.Create ); BinaryWriter bw = new BinaryWriter( fs ); //Write header bw.Write( bfh.bfType ); bw.Write( bfh.bfSize ); bw.Write( bfh.bfReserved1 ); bw.Write( bfh.bfReserved2 ); bw.Write( bfh.bfOffBits ); //Write bitmap info bw.Write( bitmapInfo ); //Write bitmap data bw.Write( bitmapData ); bw.Close(); fs.Close(); } } }