C#将图像文件压缩为AVI文件播放

来源:互联网 发布:知乎 花たん 编辑:程序博客网 时间:2024/05/16 08:41
继续上一篇blog

using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;

namespace org.loon.util
{
    
/// <summary>
    
/// AVIWriter 的摘要说明,chenpeng,Email:ceponline@yahoo.com.cn。
    
/// </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) { }
            
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(00, width,
                height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            _stride 
= (UInt32)bmpDat.Stride;
            _bmp.UnlockBits(bmpDat);
            AVIFileInit();
            
int hr = AVIFileOpenW(ref _pfile, fileName, 40970);
            
if (hr != 0)
            
{
                
throw new AviException("Create错误!");
            }


            CreateStream();
            SetOptions();

            
return _bmp;
        }


        
public void AddFrame()
        
{

            BitmapData bmpDat 
= _bmp.LockBits(
                
new Rectangle(00, (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(
001, 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, 0ref bi, 40);
            
if (hr != 0)
            
{
                
throw new AviException("AVIStreamSetFormat", hr);
            }

        }

    

    
    }
;

}


运行:

    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",1700700);
            
//获得指定目录下文件列表的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到:ceponline@yahoo.com.cn