這是接上午那篇來說的,記錄了如何將圖像文件壓縮為一個avi文件的基礎方法。
using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;
namespace org.loon.util
...{
/**//// <summary>
/// chenpeng
/// email:[email protected]
/// AVIWriter 的摘要說明。
/// </summary>
public class AVIWriter
...{
const string AVIFILE32 = "AVIFIL32";
private int _pfile = 0;
private IntPtr _ps = new IntPtr(0);
private IntPtr _psCompressed = new IntPtr(0);
private UInt32 _frameRate = 0;
private int _count = 0;
private UInt32 _width = 0;
private UInt32 _stride = 0;
private UInt32 _height = 0;
//avi標識
private UInt32 _fccType = 1935960438; // vids
private UInt32 _fccHandler = 808810089;// IV50
private Bitmap _bmp;
[DllImport(AVIFILE32)]
private static extern void AVIFileInit();
[DllImport(AVIFILE32)]
private static extern int AVIFileOpenW(ref int ptr_pfile, [MarshalAs(UnmanagedType.LPWStr)]string fileName, int flags, int dummy);
[DllImport(AVIFILE32)]
private static extern int AVIFileCreateStream(int ptr_pfile, out IntPtr ptr_ptr_avi, ref AVISTREAMINFOW ptr_streaminfo);
[DllImport(AVIFILE32)]
private static extern int AVIMakeCompressedStream(out IntPtr PPSCompressed, IntPtr aviStream, ref AVICOMPRESSOPTIONS ao, int dummy);
[DllImport(AVIFILE32)]
private static extern int AVIStreamSetFormat(IntPtr aviStream, Int32 lPos, ref BITMAPINFOHEADER lpFormat, Int32 cbFormat);
[DllImport(AVIFILE32)]
unsafe private static extern int AVISaveOptions(int hwnd, UInt32 flags,int nStreams, IntPtr* ptr_ptr_avi, AVICOMPRESSOPTIONS** ao);
[DllImport(AVIFILE32)]
private static extern int AVIStreamWrite(IntPtr aviStream, Int32 lStart,Int32 lSamples, IntPtr lpBuffer, Int32 cbBuffer, Int32 dwFlags, Int32 dummy1, Int32 dummy2);
[DllImport(AVIFILE32)]
private static extern int AVIStreamRelease(IntPtr aviStream);
[DllImport(AVIFILE32)]
private static extern int AVIFileRelease(int pfile);
[DllImport(AVIFILE32)]
private static extern void AVIFileExit();
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct AVISTREAMINFOW
...{
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 UInt32 rect_left;
public UInt32 rect_top;
public UInt32 rect_right;
public UInt32 rect_bottom;
public UInt32 dwEditCount;
public UInt32 dwFormatChangeCount;
public UInt16 szName0;
public UInt16 szName1;
public UInt16 szName2;
public UInt16 szName3;
public UInt16 szName4;
public UInt16 szName5;
public UInt16 szName6;
public UInt16 szName7;
public UInt16 szName8;
public UInt16 szName9;
public UInt16 szName10;
public UInt16 szName11;
public UInt16 szName12;
public UInt16 szName13;
public UInt16 szName14;
public UInt16 szName15;
public UInt16 szName16;
public UInt16 szName17;
public UInt16 szName18;
public UInt16 szName19;
public UInt16 szName20;
public UInt16 szName21;
public UInt16 szName22;
public UInt16 szName23;
public UInt16 szName24;
public UInt16 szName25;
public UInt16 szName26;
public UInt16 szName27;
public UInt16 szName28;
public UInt16 szName29;
public UInt16 szName30;
public UInt16 szName31;
public UInt16 szName32;
public UInt16 szName33;
public UInt16 szName34;
public UInt16 szName35;
public UInt16 szName36;
public UInt16 szName37;
public UInt16 szName38;
public UInt16 szName39;
public UInt16 szName40;
public UInt16 szName41;
public UInt16 szName42;
public UInt16 szName43;
public UInt16 szName44;
public UInt16 szName45;
public UInt16 szName46;
public UInt16 szName47;
public UInt16 szName48;
public UInt16 szName49;
public UInt16 szName50;
public UInt16 szName51;
public UInt16 szName52;
public UInt16 szName53;
public UInt16 szName54;
public UInt16 szName55;
& public UInt16 szName56;
public UInt16 szName57;
public UInt16 szName58;
public UInt16 szName59;
public UInt16 szName60;
public UInt16 szName61;
public UInt16 szName62;
public UInt16 szName63;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct AVICOMPRESSOPTIONS
...{
public UInt32 fccType;
public UInt32 fccHandler;
public UInt32 dwKeyFrameEvery;
public UInt32 dwQuality;
public UInt32 dwBytesPerSecond;
public UInt32 dwFlags;
public IntPtr lpFormat;
public UInt32 cbFormat;
public IntPtr lpParms;
public UInt32 cbParms;
public UInt32 dwInterleaveEvery;
}
[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;
}
public class AvIException : ApplicationException
...{
public AvIException(string s) : base(s) ...{ }
&n public AvIException(string s, Int32 hr)
: base(s)
...{
if (hr == AVIERR_BADPARAM)
...{
err_msg = "AVIERR_BADPARAM";
}
else
...{
err_msg = "unknown";
}
}
public string ErrMsg()
...{
return err_msg;
}
private const Int32 AVIERR_BADPARAM = -2147205018;
private string err_msg;
}
public Bitmap Create(string fileName, UInt32 frameRate, int width, int
height)
...{
_frameRate = frameRate;
_width = (UInt32)width;
_height = (UInt32)height;
_bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
//鎖定為24位位圖
BitmapData bmpDat = _bmp.LockBits(new Rectangle(0, 0, width,
height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
_stride = (UInt32)bmpDat.Stride;
_bmp.UnlockBits(bmpDat);
AVIFileInit();
int hr = AVIFileOpenW(ref _pfile, fileName, 4097, 0);
if (hr != 0)
...{
throw new AvIException("Create錯誤!");
}
CreateStream();
SetOptions();
return _bmp;
}
public void AddFrame()
...{
BitmapData bmpDat = _bmp.LockBits(
new Rectangle(0, 0, (int)_width, (int)_height),
ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
int hr = AVIStreamWrite(_psCompressed, _count, 1,
bmpDat.Scan0,
(Int32)(_stride * _height),
0,
0,
0);
if (hr != 0)
...{
throw new AvIException("AVIStreamWrite");
}
_bmp.UnlockBits(bmpDat);
_count++;
}
public void LoadFrame(Bitmap nextframe)
...{
_bmp = new Bitmap(nextframe);
}
public void Close()
...{
AVIStreamRelease(_ps);
AVIStreamRelease(_psCompressed);
AVIFileRelease(_pfile);
AVIFileExit();
}
/**//// <summary>
/// 創建流文件
/// </summary>
private void CreateStream()
...{
AVISTREAMINFOW strhdr = new AVISTREAMINFOW();
strhdr.fccType = _fccType;
strhdr.fccHandler = _fccHandler;
strhdr.dwFlags = 0;
strhdr.dwCaps = 0;
strhdr.wPriority = 0;
strhdr.wLanguage = 0;
strhdr.dwScale = 1;
strhdr.dwRate = _frameRate;
strhdr.dwStart = 0;
strhdr.dwLength = 0;
strhdr.dwInitialFrames = 0;
strhdr.dwSuggestedBufferSize = _height * _stride;
strhdr.dwQuality = 0xffffffff;
strhdr.dwSampleSize = 0;
strhdr.rect_top = 0;
strhdr.rect_left = 0;
strhdr.rect_bottom = _height;
strhdr.rect_right = _width;
strhdr.dwEditCount = 0;
strhdr.dwFormatChangeCount = 0;
strhdr.szName0 = 0;
strhdr.szName1 = 0;
int hr = AVIFileCreateStream(_pfile, out _ps, ref strhdr);
if (hr != 0)
...{
throw new AvIException("AVIFileCreateStream");
}
}
/**//// <summary>
/// 設置參數
/// </summary>
unsafe private void SetOptions()
...{
AVICOMPRESSOPTIONS opts = new AVICOMPRESSOPTIONS();
opts.fccType = _fccType;
opts.fccHandler = 0;
opts.dwKeyFrameEvery = 0;
opts.dwQuality = 0;
opts.dwFlags = 0;
opts.dwBytesPerSecond = 0;
opts.lpFormat = new IntPtr(0);
opts.cbFormat = 0;
opts.lpParms = new IntPtr(0);
opts.cbParms = 0;
opts.dwInterleaveEvery = 0;
AVICOMPRESSOPTIONS* p = &opts;
AVICOMPRESSOPTIONS** pp = &p;
IntPtr x = _ps;
IntPtr* ptr_ps = &x;
AVISaveOptions(0, 0, 1, ptr_ps, pp);
int hr = AVIMakeCompressedStream(out _psCompressed, _ps, ref
opts, 0);
if (hr != 0)
...{
throw new AvIException("AVIMakeCompressedStream");
}
BITMAPINFOHEADER bi = new BITMAPINFOHEADER();
bi.biSize = 40;
bi.biWidth = (Int32)_width;
bi.biHeight = (Int32)_height;
bi.biPlanes = 1;
bi.biBitCount = 24;
bi.biCompression = 0;
bi.biSizeImage = _stride * _height;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
hr = AVIStreamSetFormat(_psCompressed, 0, ref bi, 40);
if (hr != 0)
...{
throw new AvIException("AVIStreamSetFormat", hr);
}
}
};
}
大家可以看到,這個類基本是利用Win32 API得以實現的,下面我來演示一下如何運行此類。
手邊沒有什麼合適的圖,所以用前陣子寫的小軟件漫畫采集助手下了部《羅德斯島戰記》|||……
org.loon.util.FileUtil file=new org.loon.util.FileUtil();
org.loon.util.AVIWriter aviWriter = new org.loon.util.AVIWriter();
//ps:avi中所有圖像皆不能小於width及height
Bitmap avi_frame = aviWriter.Create("d:\mytest.avi",1, 700, 700);
//獲得指定目錄下文件列表的list
IList list=file.ListFile("D:\羅德島戰記\羅德島戰記1\");
foreach(string s in list)
...{
//獲得圖像
Bitmap cache=new Bitmap("D:\羅德島戰記\羅德島戰記1\"+s);
//由於轉化為avi後呈現相反,所以翻轉
cache.RotateFlip(RotateFlipType.Rotate180FlipX);
//載入圖像
aviWriter.LoadFrame(cache);
aviWriter.AddFrame();
}
//釋放資源
aviWriter.Close();
avi_frame.Dispose();
生成的文件屬性如下,與我們設定的參數相符:
播放畫面如下:
是不是很簡單?實際上,借助於avifile32 api,我們甚至可以改變文件壓縮格式,加入背景音樂,乃至植入病毒(咳,通常我們結合桌面截圖及avi生成還有模擬鍵盤,就可以遠程操作或者監控、記錄電腦操作……)總之,在Windows下操作avi文件是一件再簡單沒有的事情了。
有興趣的話可以這兩篇博文為基礎,將其修改為自己的字幕組工具、屏幕錄像工具、乃至遠程監控工具等。有疑問的話,可以發email到:[email protected]