C# AVI Image 轉換


AVI視頻庫 http://download.csdn.net/download/qc_id_01/9970151

Avi視頻文件的編碼有很多,這個庫只支持部分Avi文件,有些Avi文件不支持,具體哪些不支持還沒搞清楚

AviFile庫提供了

  1、從視頻流中圖片的處理

  2、視頻中音頻的處理

  3、壓縮和解壓視頻流

 

1、使用

  1、從視頻讀取圖片,還有一些參數可以通過aviStream查看到,可以把當前流信息輸出到文件 

 
            //Avi文件讀取 string filepath = @"D:\test.avi"; AviManager aviManager = new AviManager(filepath, true); VideoStream aviStream = aviManager.GetVideoStream(); //獲取和保存音頻流到文件 AudioStream audioStream = aviManager.GetWaveStream(); audioStream.ExportStream(@"D:\test.wav"); aviStream.GetFrameOpen(); //獲取視頻總幀數 int framecount = aviStream.CountFrames; //獲取第5幀的圖片 Bitmap bmp = aviStream.GetBitmap(5); //視頻速度 double rate = aviStream.FrameRate; //直接保存幀圖片到文件 //aviStream.ExportBitmap(5, @"D:\frame_05.jpg"); //保存當前流到文件 //aviStream.ExportStream(@"D:\currenttest.avi")  aviStream.GetFrameClose(); aviManager.Close();
 

   2、把圖片和音頻寫入視頻流(部分參數后面會說到,這里只是簡單的演示) 

 
            //讀取圖片文件 string[] files = Directory.GetFiles(@"D:\test\", "*.jpg"); AviManager aviManager = new AviManager(@"D:\newtest.avi", false); //添加音頻 String fileName = @"D:\audio.wav"; aviManager.AddAudioStream(fileName, 0); //讀取第一張圖片,設置每秒3幀 VideoStream aviStream = aviManager.AddVideoStream(true, 3, new Bitmap(files[0])); for (int i = 1; i < files.Length; i++) { aviStream.AddFrame(new Bitmap(files[i])); } aviManager.Close();
 

   3、從視頻截取一段保存到AviManager 

            AviManager aviManager = new AviManager(filepath, true); float startSecond = 0; float stopSecond = 10; //截取0-10s放到newManager AviManager newManager = aviManager.CopyTo(@"D:\newtest_0-10.avi", startSecond, stopSecond);

   4、對已壓縮的視頻進行解壓縮,放到另一個VideoStream中

            VideoStream newstream;
            AviManager newManager = aviStream.DecompressToNewFile(@"D:\01.avi", false, out newstream); newstream.GetFrameOpen(); Bitmap bitmap = newstream.GetBitmap(10); newstream.GetFrameClose();

    5、向視頻流中添加一張圖片幀,對於未壓縮的視頻流,我們可以直接進行添加,但是對於已經壓縮過的視頻流,添加的圖片幀不能重新進行壓縮,所以我們需要對其進行解壓縮,操作完后在進行壓縮

 
           //讀取圖片文件 string[] files = Directory.GetFiles(@"D:\test\", "*.jpg"); //打開一個已存在的視頻 AviManager aviManager = new AviManager(@"D:\test.avi", true); VideoStream avistream = aviManager.GetVideoStream(); VideoStream newstream; //解壓視頻到newstream中,最后已壓縮的形式保存 AviManager newManager = avistream.DecompressToNewFile(@"newtest.avi", true, out newstream); avistream = newManager.GetOpenStream(0); for (int i = 1; i < files.Length; i++) { avistream.AddFrame(new Bitmap(files[i])); } aviManager.Close(); //關閉和保存文件newtest.avi newManager.Close(); 
 

   6、編輯視頻流 EditableVideoStream (可以對視頻流的幀,進行cut,delete,paste等早錯)

 
            //打開一個已存在的視頻 AviManager aviManager = new AviManager(@"D:\test.avi", true); VideoStream avistream = aviManager.GetVideoStream(); EditableVideoStream editableStream = new EditableVideoStream(avistream); int start = 0; int length =10; int position = 10; //Copy IntPtr copiedData = editableStream.Copy(start, length); //Insert editableStream.Paste(copiedData, 0, position, length); //Delete IntPtr deletedData = editableStream.Cut(start, length);
 

  同時也可以把一個 VideoStream 流 Paste 到 EditableVideoStream  

            editableStream.Paste(stream, 0, position, stream.CountFrames);   

  7、對視頻流進行一些參數設置

            Avi.AVISTREAMINFO info = editableStream.StreamInfo;
            //設置播放速度:每秒 3幀 info.dwRate = 3; editableStream.SetInfo(info); 

 

2、AviFile后台工作

  AviManager 管理Avi文件的stream,構造函數傳入文件名,當調用Close函數時,關閉所有打開的流和文件,並保存。

可以使用 AddVideoStream 和 AddAudioStream 把視頻里和音頻流添加到一個新的AviManager中,音頻流只支持wav文件

Create a video stream

  VideoStream 有兩個構造函數

 
            public VideoStream AddVideoStream( bool isCompressed, //display the compression dialog, create a compressed stream int frameRate, //frames per second int frameSize, //size of one frame in bytes int width, int height, PixelFormat format //format of the bitmaps  ) { VideoStream stream = new VideoStream(aviFile, isCompressed, frameRate, frameSize, width, height, format); streams.Add(stream); return stream; } public VideoStream AddVideoStream( bool isCompressed, //display the compression dialog, create a compressed stream int frameRate, //frames per second Bitmap firstFrame //get the format from this image and add it to the new stream  ) { VideoStream stream = new VideoStream(aviFile, isCompressed, frameRate, firstFrame); streams.Add(stream); return stream; }
 

  VideoStream使用格式化的數據創建新的流,調用 AVIFileCreateStream,如果 isCompressed參數為true,則調用 AVIMakeCompressedStream

 
        public VideoStream(int aviFile, bool writeCompressed, int frameRate, ...) { //store format information //... //create the stream  CreateStream(); } private void CreateStream() { //fill stream information Avi.AVISTREAMINFO strhdr = new Avi.AVISTREAMINFO(); strhdr.fccType = Avi.mmioStringToFOURCC("vids", 0); strhdr.fccHandler = Avi.mmioStringToFOURCC("CVID", 0); strhdr.dwScale = 1; strhdr.dwRate = frameRate; strhdr.dwSuggestedBufferSize = frameSize; strhdr.dwQuality = -1; //default strhdr.rcFrame.bottom = (uint)height; strhdr.rcFrame.right = (uint)width; strhdr.szName = new UInt16[64]; //create the stream int result = Avi.AVIFileCreateStream(aviFile, out aviStream, ref strhdr); if(writeCompressed) { //create a compressed stream from  CreateCompressedStream(); } } private void CreateCompressedStream() { Avi.AVICOMPRESSOPTIONS_CLASS options = new Avi.AVICOMPRESSOPTIONS_CLASS(); options.fccType = (uint)Avi.streamtypeVIDEO; options.lpParms = IntPtr.Zero; options.lpFormat = IntPtr.Zero; //display the compression options dialog Avi.AVISaveOptions(IntPtr.Zero, Avi.ICMF_CHOOSE_KEYFRAME | Avi.ICMF_CHOOSE_DATARATE, 1, ref aviStream, ref options); //get a compressed stream Avi.AVICOMPRESSOPTIONS structOptions = options.ToStruct(); int result = Avi.AVIMakeCompressedStream(out compressedStream, aviStream, ref structOptions, 0); //format the compressed stream  SetFormat(compressedStream); }
 

    其中使用 AVICOMPRESSOPTIONS_CLASS 類代替 AVICOMPRESSOPTIONS 結構體,使用類代替結構體在使用指針的時候更加容易,如果你看不懂,你可能沒在.Net使用過 AVISaveOptions 或 AVISaveV,下面看看 AVISaveOptions 的聲明

        BOOL AVISaveOptions(
                HWND hwnd,
                UINT uiFlags,
                int nStreams, PAVISTREAM * ppavi, LPAVICOMPRESSOPTIONS * plpOptions); 

    LPAVICOMPRESSOPTIONS 是一個指向  AVICOMPRESSOPTIONS 結構體指針的指針(指向指針的指針)

    在C#中,結構體是值傳遞的,如果使用ref來傳遞結構體,則傳遞的是指向結構體的指針

    而類使用的是引用,實際傳遞的是指針,地址,所以使用ref傳遞類時,實際傳遞的是指向類指針的指針(指向指針的指針),

    所以這里使用類代替結構體,下面是在C#中聲明 AVISaveOptions 和 AVICOMPRESSOPTIONS 

 
            [DllImport("avifil32.dll")] public static extern bool AVISaveOptions( IntPtr hwnd, UInt32 uiFlags, Int32 nStreams, ref IntPtr ppavi, ref AVICOMPRESSOPTIONS_CLASS plpOptions ); [StructLayout(LayoutKind.Sequential, Pack=1)] public 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 class AVICOMPRESSOPTIONS_CLASS { 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; public AVICOMPRESSOPTIONS ToStruct() { AVICOMPRESSOPTIONS returnVar = new AVICOMPRESSOPTIONS(); returnVar.fccType = this.fccType; returnVar.fccHandler = this.fccHandler; returnVar.dwKeyFrameEvery = this.dwKeyFrameEvery; returnVar.dwQuality = this.dwQuality; returnVar.dwBytesPerSecond = this.dwBytesPerSecond; returnVar.dwFlags = this.dwFlags; returnVar.lpFormat = this.lpFormat; returnVar.cbFormat = this.cbFormat; returnVar.lpParms = this.lpParms; returnVar.cbParms = this.cbParms; returnVar.dwInterleaveEvery = this.dwInterleaveEvery; return returnVar; } }
 

  在這個工作區,可以調用 AVISaveOptions ,來設置Avi文件的一些參數

  通過AddFrame函數可以用圖片填充視頻流

 
            public void AddFrame(Bitmap bmp) { bmp.RotateFlip(RotateFlipType.RotateNoneFlipY); if (countFrames == 0) { // the format of the first frame defines the format of the stream  CopyPalette(bmp.Palette); SetFormat(writeCompressed ? compressedStream : aviStream, countFrames); } //lock the memory block BitmapData bmpDat = bmp.LockBits( new Rectangle(0,0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat); //add the bitmap to the (un-)compressed stream int result = Avi.AVIStreamWrite( writeCompressed ? compressedStream : aviStream, countFrames, 1, bmpDat.Scan0, (Int32)(bmpDat.Stride * bmpDat.Height), 0, 0, 0); //unlock the memory block  bmp.UnlockBits(bmpDat); //count the frames, so that we don't have to call AVIStreamLength for every new frame countFrames++; } 
 

Add frames to an existing stream

 
        public VideoStream(int aviFile, IntPtr aviStream) { this.aviFile = aviFile; this.aviStream = aviStream; //read the stream's format Avi.BITMAPINFOHEADER bih = new Avi.BITMAPINFOHEADER(); int size = Marshal.SizeOf(bih); Avi.AVIStreamReadFormat(aviStream, 0, ref bih, ref size); Avi.AVISTREAMINFO streamInfo = GetStreamInfo(aviStream); //store the important format values this.frameRate = streamInfo.dwRate / streamInfo.dwScale; this.width = (int)streamInfo.rcFrame.right; this.height = (int)streamInfo.rcFrame.bottom; this.frameSize = bih.biSizeImage; this.countBitsPerPixel = bih.biBitCount; //get the count of frames that are already there int firstFrame = Avi.AVIStreamStart(aviStream.ToInt32()); countFrames = firstFrame + Avi.AVIStreamLength(aviStream.ToInt32()); } 
 

  如果視頻流是未壓縮的,可以直接調用AddFrame,否則,需要對其進行解壓縮,並重新壓縮到一個新的流

 
        public AviManager DecompressToNewFile(String fileName, bool recompress) { //create a new AVI file AviManager newFile = new AviManager(fileName, false); //create a video stream in the new file this.GetFrameOpen(); Bitmap frame = GetBitmap(0); VideoStream newStream = newFile.AddVideoStream(recompress, frameRate, frame); //decompress each frame and add it to the new stream for(int n=1; n<countFrames; n++) { frame = GetBitmap(n); newStream.AddFrame(frame); } this.GetFrameClose(); return newFile; }
 

 

  DecompressToNewFile 創建一個可編輯的拷貝到一個新的文件流,可以添加frames到該流

 

Separate a stream

  有時,我們可能只想要視頻的聲音,或是只要沒有聲音的視頻,我們沒有必要重新創建視頻,添加每一幀到視頻流中,可以通過使用 AviSaveV 把當前流到處到文件,AVISaveV只是所有類型的流,只是壓縮參數不一樣而已

 

 
        public override void ExportStream(String fileName) { Avi.AVICOMPRESSOPTIONS_CLASS opts = new Avi.AVICOMPRESSOPTIONS_CLASS(); //for video streams opts.fccType = (UInt32)Avi.mmioStringToFOURCC("vids", 0); opts.fccHandler = (UInt32)Avi.mmioStringToFOURCC("CVID", 0); //for audio streams //opts.fccType = (UInt32)Avi.mmioStringToFOURCC("auds", 0); //opts.fccHandler = (UInt32)Avi.mmioStringToFOURCC("CAUD", 0); //export the stream Avi.AVISaveV(fileName, 0, 0, 1, ref aviStream, ref opts); }
 

 Import sound from a Wave file

  現在,我們可以通過Bitmap來生成視頻,也可以從視頻中導出聲音,那么當我們導入wav文件的時候,底層是如何工作的呢,我們還是可以用 AVISaveV 這個方法,來組合視頻和音頻成一個文件,但這里我們有更簡單的方法,打開音頻文件作為Avi文件,然后拷貝到另一個流中

 
            public void AddAudioStream(String waveFileName) { //open the wave file AviManager audioManager = new AviManager(waveFileName, true); //get the wave sound as an audio stream... AudioStream newStream = audioManager.GetWaveStream(); //...and add it to the file  AddAudioStream(newStream); audioManager.Close(); } public void AddAudioStream(AudioStream newStream) { Avi.AVISTREAMINFO streamInfo = new Avi.AVISTREAMINFO(); Avi.PCMWAVEFORMAT streamFormat = new Avi.PCMWAVEFORMAT(); int streamLength = 0; //read header info, format and length, //and get a pointer to the wave data IntPtr waveData = newStream.GetStreamData( ref streamInfo, ref streamFormat, ref streamLength); //create new stream  IntPtr aviStream; Avi.AVIFileCreateStream(aviFile, out aviStream, ref streamInfo); //add format new stream  Avi.AVIStreamSetFormat( aviStream, 0, ref streamFormat, Marshal.SizeOf(streamFormat)); //copy the raw wave data into the new stream  Avi.AVIStreamWrite( aviStream, 0, streamLength, waveData, streamLength, Avi.AVIIF_KEYFRAME, 0, 0); Avi.AVIStreamRelease(aviStream); }
 

    截取視頻流

   public AviManager CopyTo(String newFileName, int startAtSecond, int stopAtSecond) 
        {
            AviManager newFile = new AviManager(newFileName, false);
            try 
            {
                //copy video stream
                VideoStream videoStream = GetVideoStream();

                int startFrameIndex = videoStream.FrameRate * startAtSecond;
                int stopFrameIndex = videoStream.FrameRate * stopAtSecond;

                videoStream.GetFrameOpen();
                Bitmap bmp = videoStream.GetBitmap(startFrameIndex);

                VideoStream newStream = newFile.AddVideoStream(false, videoStream.FrameRate, bmp);

                for (int n = startFrameIndex + 1; n <= stopFrameIndex; n++) 
                {
                    bmp = videoStream.GetBitmap(n);
                    newStream.AddFrame(bmp);
                }
                videoStream.GetFrameClose();

                //copy audio stream
                AudioStream waveStream = GetWaveStream();

                Avi.AVISTREAMINFO streamInfo = new Avi.AVISTREAMINFO();
                Avi.PCMWAVEFORMAT streamFormat = new Avi.PCMWAVEFORMAT();
                int streamLength = 0;
                IntPtr ptrRawData = waveStream.GetStreamData(ref streamInfo, ref streamFormat, ref streamLength);

                int startByteIndex = waveStream.CountSamplesPerSecond * startAtSecond * waveStream.CountBitsPerSample / 8;
                int stopByteIndex = waveStream.CountSamplesPerSecond * stopAtSecond * waveStream.CountBitsPerSample / 8;

                ptrRawData = new IntPtr(ptrRawData.ToInt32() + startByteIndex);

                byte[] rawData = new byte[stopByteIndex - startByteIndex];
                Marshal.Copy(ptrRawData, rawData, 0, rawData.Length);

                streamInfo.dwLength = rawData.Length;
                streamInfo.dwStart = 0;

                IntPtr unmanagedRawData = Marshal.AllocHGlobal(rawData.Length);
                Marshal.Copy(rawData, 0, unmanagedRawData, rawData.Length);

                newFile.AddAudioStream(unmanagedRawData, streamInfo, streamFormat, rawData.Length);
            } 
            catch (Exception ex) 
            {
                newFile.Close();
                throw ex;
            }
            return newFile;
        }

轉自:http://blog.csdn.net/jane_sl/article/details/8693395


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM