zoukankan      html  css  js  c++  java
  • WPF之SharpAvi视频录制(AVI)

    提供一个工具类,复制即可用,但是首先要去下载个NuGet包,直接搜索SharpAvi就OK了

      public class VideoTranscribe
        {
    
            private readonly static object lockObj = new object();
            private static VideoTranscribe instance = null;
            public static VideoTranscribe Instance
            {
                get
                {
                    lock (lockObj)
                    {
                        if (instance == null)
                        {
                            instance = new VideoTranscribe();
                        }
                    }
                    return instance;
                }
            }
    
            public VideoTranscribe()
            {
            }
    
    
            #region Settings(配置) 初始化
            private string outputFolder;//输出过滤器
            private FourCC encoder;//编码器
            private int encodingQuality;//编码质量
            private int VideoFramesPerSecond;//视频帧数
            //  private int audioSourceIndex;//音频资料索引
            //  private SupportedWaveFormat audioWaveFormat;//音频波格式
            // private bool encodeAudio;//音频编码
            // private int audioQuality;//音频质量
            /// <summary>
            /// 初始化默认值
            /// </summary>
            public void InitDefaultSettings(int Quality, int FramesPerSecond, string path)
            {
                try
                {
                    Log.Error("开始初始化录屏配置");
                    if (!System.IO.Directory.Exists(path))
                    {
                        System.IO.Directory.CreateDirectory(path);//不存在就创建目录 
                    }
                    outputFolder = path;
                    encoder = KnownFourCCs.Codecs.MotionJpeg;
                    encodingQuality = Quality;
                    VideoFramesPerSecond = FramesPerSecond;
                    // audioSourceIndex = -1;
                    // audioWaveFormat = SupportedWaveFormat.WAVE_FORMAT_44M16;
                    // encodeAudio = true;
                    // audioQuality = (Mp3AudioEncoderLame.SupportedBitRates.Length + 1) / 2;
                }
                catch (Exception ex)
                {
                    Log.Error("初始化设置异常:" + ex.Message);
                }
    
            }
            #endregion
    
            #region Recording
            private readonly Stopwatch recordingStopwatch = new Stopwatch();
            private Recorder recorder;
            private string lastFileName;
    
            /// <summary>
            /// 开始录频
            /// </summary>
            public void StartRecording(string Name)
            {
                try
                {
                    Log.Debug("开始录制视频");
                    lastFileName = System.IO.Path.Combine(outputFolder, Name + "" + DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss") + ".avi");
                    //var bitRate = Mp3AudioEncoderLame.SupportedBitRates.OrderBy(br => br).ElementAt(audioQuality);
                    recorder = new Recorder(lastFileName,encoder, encodingQuality, VideoFramesPerSecond);
                    recordingStopwatch.Start();
                }
                catch (Exception ex)
                {
                    StopRecording();
                    Log.Error("视频录制异常:" + ex.Message);
                }
            }
    
            /// <summary>
            /// 停止
            /// </summary>
            public void StopRecording()
            {
                Log.Debug("执行视频停止");
                try
                {
                    if (recorder != null)
                    {
                        recorder.Dispose();
                        recorder = null;
                    }
                }
                finally
                {
                    recordingStopwatch.Stop();
                }
            }
    
            /// <summary>
            /// 暂停
            /// </summary>
            public void SuspendRecording()
            {
                try
                {
                    Log.Debug("视频暂定");
                    if (recorder != null)
                    {
                        recorder.VideoSuspend();
                    }
    
                }
                catch (Exception ex)
                {
                    Log.Error("视频暂停异常:" + ex.Message);
                }
    
            }
            /// <summary>
            /// 继续
            /// </summary>
            public void ContinueRecording()
            {
                try
                {
                    Log.Debug("视频继续");
                    if (recorder != null)
                    {
                        recorder.VideoContinue();
                    }
    
                }
                catch (Exception ex)
                {
                    Log.Error("视频继续异常:" + ex.Message);
                }
    
            }
    
            /// <summary>
            /// 定位到avi视频上
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            public void GoToLastScreencast()
            {
                Process.Start("explorer.exe", string.Format("/select, "{0}"", lastFileName));
            }
            #endregion
    
    
    
    
        }
    internal class Recorder : IDisposable
        {
          
            Bitmap lastBitmap = new Bitmap(10, 10);
            private readonly int screenWidth;
            private readonly int screenHeight;
            private readonly AviWriter writer;
            private readonly IAviVideoStream videoStream;
            private readonly IAviAudioStream audioStream;
            private readonly WaveInEvent audioSource;
            private readonly Thread screenThread;
            private readonly ManualResetEvent stopThread = new ManualResetEvent(false);
            private readonly AutoResetEvent videoFrameWritten = new AutoResetEvent(false);
            private readonly AutoResetEvent audioBlockWritten = new AutoResetEvent(false);
            static CancellationTokenSource tokenSource = new CancellationTokenSource();
            CancellationToken token = tokenSource.Token;
            ManualResetEvent resetEvent = new ManualResetEvent(true);
            public Recorder(string fileName, FourCC codec, int quality, int VideoFramesPerSecond)
            {
                Matrix toDevice = new Matrix();
                System.Windows.Application.Current.Dispatcher.Invoke(new Action(() =>
                {
                    using (var source = new HwndSource(new HwndSourceParameters()))
                    {
                        toDevice = source.CompositionTarget.TransformToDevice;
                    }
                }));
                screenWidth = (int)Math.Round(SystemParameters.PrimaryScreenWidth * toDevice.M11);//屏幕的宽度
                screenHeight = (int)Math.Round(SystemParameters.PrimaryScreenHeight * toDevice.M22);//屏幕的高度
    
                // Create AVI writer and specify FPS  ///创建AVI写入器并指定FPS
                writer = new AviWriter(fileName)
                {
                    FramesPerSecond = VideoFramesPerSecond,
                    EmitIndex1 = true,
                };
    
                // Create video stream //创建视频
                videoStream = CreateVideoStream(codec, quality);
                // Set only name. Other properties were when creating stream, //只有名字。其他属性是在创建流时,
                // either explicitly by arguments or implicitly by the encoder used//无论是显式的参数或隐式的编码器使用
                videoStream.Name = "Screencast";
    
                //if (audioSourceIndex >= 0)
                //{
                //    var waveFormat = ToWaveFormat(audioWaveFormat);//告诉视频你的音频格式
    
                //    audioStream = CreateAudioStream(waveFormat, encodeAudio, audioBitRate);//创建音频
                //    // Set only name. Other properties were when creating stream, //只有名字。其他属性是在创建流时设置的
                //    // either explicitly by arguments or implicitly by the encoder used //无论是显式的参数或隐式的编码器使用
                //    audioStream.Name = "Voice";
    
                //    audioSource = new WaveInEvent
                //    {
                //        DeviceNumber = audioSourceIndex,
                //        WaveFormat = waveFormat,
                //        // Buffer size to store duration of 1 frame
                //        BufferMilliseconds = (int)Math.Ceiling(1000 / writer.FramesPerSecond),
                //        NumberOfBuffers = 3,
                //    };
                //    audioSource.DataAvailable += audioSource_DataAvailable;
                //}
    
                screenThread = new Thread(RecordScreen)//开一个线程去执行,录制
                {
                    Name = typeof(Recorder).Name + ".RecordScreen",
                    IsBackground = true
                };
    
                if (audioSource != null)
                {
                    videoFrameWritten.Set();
                    audioBlockWritten.Reset();
                    audioSource.StartRecording();
                }
                screenThread.Start();
            }
    
            /// <summary>
            /// 暂停
            /// </summary>
            public void VideoSuspend()
            {
                resetEvent.Reset();
            }
    
            /// <summary>
            /// 继续
            /// </summary>
            public void VideoContinue()
            {
                resetEvent.Set();
            }
            /// <summary>
            /// 创建视频流
            /// </summary>
            /// <param name="codec"></param>
            /// <param name="quality"></param>
            /// <returns></returns>
    
            private IAviVideoStream CreateVideoStream(FourCC codec, int quality)
            {
                // Select encoder type based on FOURCC of codec
                if (codec == KnownFourCCs.Codecs.Uncompressed)
                {
                    return writer.AddUncompressedVideoStream(screenWidth, screenHeight);
                }
                else if (codec == KnownFourCCs.Codecs.MotionJpeg)
                {
                    return writer.AddMotionJpegVideoStream(screenWidth, screenHeight, quality
    #if !FX45
                        // Implementation of this encoder for .NET 3.5 requires single-threaded access
                        , forceSingleThreadedAccess: true
    #endif
                        );
                }
                else
                {
                    return writer.AddMpeg4VideoStream(screenWidth, screenHeight, (double)writer.FramesPerSecond,
                        // It seems that all tested MPEG-4 VfW codecs ignore the quality affecting parameters passed through VfW API
                        // They only respect the settings from their own configuration dialogs, and Mpeg4VideoEncoder currently has no support for this
                        quality: quality,
                        codec: codec,
                        // Most of VfW codecs expect single-threaded use, so we wrap this encoder to special wrapper
                        // Thus all calls to the encoder (including its instantiation) will be invoked on a single thread although encoding (and writing) is performed asynchronously
                        forceSingleThreadedAccess: true);
                }
            }
            /// <summary>
            /// 创建音频流
            /// </summary>
            /// <param name="waveFormat"></param>
            /// <param name="encode"></param>
            /// <param name="bitRate"></param>
            /// <returns></returns>
            private IAviAudioStream CreateAudioStream(WaveFormat waveFormat, bool encode, int bitRate)
            {
                // Create encoding or simple stream based on settings
                if (encode)
                {
                    // LAME DLL path is set in App.OnStartup()
                    return writer.AddMp3AudioStream(waveFormat.Channels, waveFormat.SampleRate, bitRate);
                }
                else
                {
                    return writer.AddAudioStream(
                        channelCount: waveFormat.Channels,
                        samplesPerSecond: waveFormat.SampleRate,
                        bitsPerSample: waveFormat.BitsPerSample);
                }
            }
            /// <summary>
            /// 获取音频格式
            /// </summary>
            /// <param name="waveFormat"></param>
            /// <returns></returns>
            private static WaveFormat ToWaveFormat(SupportedWaveFormat waveFormat)
            {
                switch (waveFormat)
                {
                    case SupportedWaveFormat.WAVE_FORMAT_44M16:
                        return new WaveFormat(44100, 16, 1);
                    case SupportedWaveFormat.WAVE_FORMAT_44S16:
                        return new WaveFormat(44100, 16, 2);
                    default:
                        throw new NotSupportedException("Wave formats other than '16-bit 44.1kHz' are not currently supported.");
                }
            }
            /// <summary>
            /// 释放
            /// </summary>
            public void Dispose()
            {
                VideoContinue();
                stopThread.Set();
                screenThread.Join();
                if (audioSource != null)
                {
                    audioSource.StopRecording();
                    audioSource.DataAvailable -= audioSource_DataAvailable;
                }
    
                // Close writer: the remaining data is written to a file and file is closed
                writer.Close();
    
                stopThread.Close();
            }
            /// <summary>
            /// 录制视频
            /// </summary>
            private void RecordScreen()
            {
                var stopwatch = new Stopwatch();
    #if FX45
                Task videoWriteTask = null;
    #else
                IAsyncResult videoWriteResult = null;
    #endif
                var isFirstFrame = true;
                var shotsTaken = 0;
                var timeTillNextFrame = TimeSpan.Zero;
                stopwatch.Start();
    
                while (!stopThread.WaitOne(timeTillNextFrame))
                {
                    var buffer = GetScreenshot();
                    shotsTaken++;
    
                    // Wait for the previous frame is written //等待写入前一帧
                    if (!isFirstFrame)
                    {
    #if FX45
                        videoWriteTask.Wait();
    #else
                        videoStream.EndWriteFrame(videoWriteResult);
    #endif
                        videoFrameWritten.Set();
                    }
                    if (token.IsCancellationRequested)
                    {
                        return;
                    }
    
                    // 初始化为true时执行WaitOne不阻塞
                    resetEvent.WaitOne();
    
                    if (audioStream != null)
                    {
                        var signalled = WaitHandle.WaitAny(new WaitHandle[] { audioBlockWritten, stopThread });
                        if (signalled == 1)
                            break;
                    }
    
                    // Start asynchronous (encoding and) writing of the new frame ///开始异步(编码和)写入新帧
    #if FX45
                    videoWriteTask = videoStream.WriteFrameAsync(true, buffer, 0, buffer.Length);
    #else
                    videoWriteResult = videoStream.BeginWriteFrame(true, buffer, 0, buffer.Length, null, null);
    #endif
    
                    timeTillNextFrame = TimeSpan.FromSeconds(shotsTaken / (double)writer.FramesPerSecond - stopwatch.Elapsed.TotalSeconds);
                    if (timeTillNextFrame < TimeSpan.Zero)
                        timeTillNextFrame = TimeSpan.Zero;
    
                    isFirstFrame = false;
                }
    
                stopwatch.Stop();
    
                // Wait for the last frame is written
                if (!isFirstFrame)
                {
    #if FX45
                    videoWriteTask.Wait();
    #else
                    videoStream.EndWriteFrame(videoWriteResult);
    #endif
                }
            }
    
            private byte[] GetScreenshot()
            {
                using (Bitmap avibitmap = GetScreen())
                {
                    System.Drawing.Point mouseXY = new System.Drawing.Point();
                    mouseXY = Control.MousePosition;
                    using (Graphics mouseGraphics = Graphics.FromImage(avibitmap))
                    {
                        mouseGraphics.DrawEllipse(new System.Drawing.Pen(new SolidBrush(System.Drawing.Color.Green), 5), new Rectangle(mouseXY.X - 10, mouseXY.Y - 10, 20, 20));
                        var buffer = new byte[avibitmap.Width * avibitmap.Height * 4];
                        var bits = avibitmap.LockBits(new Rectangle(0, 0, avibitmap.Width, avibitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                        Marshal.Copy(bits.Scan0, buffer, 0, buffer.Length);
                        avibitmap.UnlockBits(bits);
                        return buffer;
                    }
                }
            }
    
            private Bitmap GetScreen()
            {
                try
                {
                    var bitmap = new Bitmap(System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width, System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height);
                    var graphics = Graphics.FromImage(bitmap);
                    graphics.CopyFromScreen(0, 0, 0, 0, System.Windows.Forms.Screen.PrimaryScreen.Bounds.Size);
                    graphics.Dispose();
                    lastBitmap.Dispose();
                    lastBitmap = bitmap;
                }
                catch
                {
                }
                return (Bitmap)lastBitmap.Clone();
            }
    
            private void audioSource_DataAvailable(object sender, WaveInEventArgs e)
            {
                var signalled = WaitHandle.WaitAny(new WaitHandle[] { videoFrameWritten, stopThread });
                if (signalled == 0)
                {
                    audioStream.WriteBlock(e.Buffer, 0, e.BytesRecorded);
                    audioBlockWritten.Set();
                }
            }
        }

    如果,发现以上工具不能用了,那么就请你直接去  https://github.com/baSSiLL/SharpAvi ,暂停的话直接用线程阻塞就成.

  • 相关阅读:
    啃掉的博文全记录
    DP五十题
    noip 真题班刷题记录及总结思考
    dfklsJj
    【2018.11.7】luogu NOIp热身赛 及刷题思考
    【trie树专题】
    【倍增专题】
    10.23
    简析 NP 问题 和P问题
    [NOIP 2010普及组 No.4] 三国游戏
  • 原文地址:https://www.cnblogs.com/ACBJTR/p/11854885.html
Copyright © 2011-2022 走看看