mirror of
https://git.femboyfinancial.jp/james/lipsync.git
synced 2024-11-22 18:52:02 -08:00
484 lines
18 KiB
C#
484 lines
18 KiB
C#
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
|
|
|
|
}
|
|
|
|
/// <summary>Extract bitmaps from AVI files</summary>
|
|
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 );
|
|
}
|
|
}
|
|
|
|
/// <summary>Opens an AVI file and creates a GetFrame object</summary>
|
|
/// <param name="fileName">Name of the AVI file</param>
|
|
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!" );
|
|
}
|
|
}
|
|
|
|
/// <summary>Closes all streams, files and libraries</summary>
|
|
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;
|
|
}
|
|
|
|
|
|
/// <summary>Exports a frame into a bitmap file</summary>
|
|
/// <param name="position">Position of the frame</param>
|
|
/// <param name="dstFileName">Name ofthe file to store the bitmap</param>
|
|
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();
|
|
}
|
|
}
|
|
|
|
}
|