C# AVI Image 转换
阅读原文时间:2023年07月15日阅读:1

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,则调用&nbsp;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&nbsp;类代替&nbsp;``AVICOMPRESSOPTIONS 结构体,使用类代替结构体在使用指针的时候更加容易,如果你看不懂,你可能没在.Net使用过&nbsp;`AVISaveOptions`&nbsp;或&nbsp;`AVISaveV`,下面看看&nbsp;AVISaveOptions 的声明 ``

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

    LPAVICOMPRESSOPTIONS 是一个指向  AVICOMPRESSOPTIONS 结构体指针的指针(指向指针的指针)

在C#中,结构体是值传递的,如果使用ref来传递结构体,则传递的是指向结构体的指针

    而类使用的是引用,实际传递的是指针,地址,所以使用ref传递类时,实际传递的是指向类指针的指针(指向指针的指针),

    所以这里使用类代替结构体,下面是在C#中声明 AVISaveOptions 和&nbsp;`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 + ; 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 = ;  
            IntPtr ptrRawData = waveStream.GetStreamData(ref streamInfo, ref streamFormat, ref streamLength);

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

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

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

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

            IntPtr unmanagedRawData = Marshal.AllocHGlobal(rawData.Length);  
            Marshal.Copy(rawData, , 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

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器