Разработка рабочего стола WPF — запись аудио и видео, получение миниатюр (с использованием OpenCvSharp)
Разработка рабочего стола WPF — запись аудио и видео, получение миниатюр (с использованием OpenCvSharp)

Предисловие

Переустановите все зависимости

код Язык:javascript
копировать
Update-Package –reinstall

Аудио и видео записываются отдельно. Если микрофон и динамики записываются, звук также необходимо записывать отдельно, и в конечном итоге все потоки будут объединены.

Официальная документация

NAudio

https://github.com/naudio/NAudio

Установить

Видеотека

OpenCvSharp4

код Язык:javascript
копировать
Install-Package OpenCvSharp4 -Version 4.7.0.20230115
Install-Package OpenCvSharp4.runtime.win -Version 4.7.0.20230115
Install-Package OpenCvSharp4.Extensions -Version 4.7.0.20230115

OpenCvSharp3

код Язык:javascript
копировать
Install-Package OpenCvSharp3-AnyCPU -Version 4.0.0.20181129

При использовании OpenCvSharp4 я всегда получаю сообщение об ошибке или не могу создать видеофайл при сохранении видео. Когда я переключаюсь на OpenCvSharp3, все нормально.

аудиотека

Для записи аудио используется библиотека NAudio, которая может как записывать микрофон, так и записывать динамики.

Установить

код Язык:javascript
копировать
Install-Package NAudio -Version 1.9.0

Объединение аудио и видео Библиотека

Хорошего решения по слиянию пока не найдено.

Большинство объединенных библиотек представляют собой пакеты FFmpeg. Сам FFmpeg относительно велик и не рекомендуется для использования, поэтому лучшей альтернативы не найдено.

обработка звука

Использование НАудио

Установить

код Язык:javascript
копировать
Install-Package NAudio -Version 1.9.0

Список микрофонов

код Язык:javascript
копировать
using NAudio.Wave;
public static void GetAudioMicrophone2()
{
    for (int n = -1;
         n < WaveIn.DeviceCount;
         n++)
    {
        var caps = WaveIn.GetCapabilities(n);
        Console.WriteLine($@"{n}: {caps.ProductName}");
    }
}

Распечатайте следующим образом

-1: Microsoft Sound Mapper 0: Микрофон (Realtek(R) Audio)

Обратите внимание, что указанный выше обход начинается с -1. Когда мы получаем микрофонное устройство, мы можем переходить с 0.

Способ 2

код Язык:javascript
копировать
using NAudio.CoreAudioApi;

public static void GetAudioMicrophone2()
{
    MMDeviceEnumerator enumerator = new MMDeviceEnumerator();

    //Получаем устройство вывода аудио
    IEnumerable<MMDevice> speakDevices =
        enumerator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.Active).ToArray();
    var mmDevices = speakDevices.ToList();
    foreach (MMDevice device in mmDevices)
    {
        int volume = Convert.ToInt16(device.AudioEndpointVolume.MasterVolumeLevelScalar * 100);
        Console.WriteLine($@"{device.FriendlyName} Громкость звука:{volume}");
    }
}

Список докладчиков

Получите динамик по умолчанию и его размер звука.

код Язык:javascript
копировать
using NAudio.CoreAudioApi;

public static void GetAudioLoudspeaker2()
{
    MMDeviceEnumerator enumerator = new MMDeviceEnumerator();

    //Получаем устройство вывода аудио
    IEnumerable<MMDevice> speakDevices =
        enumerator.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active).ToArray();
    var mmDevices = speakDevices.ToList();
    foreach (MMDevice device in mmDevices)
    {
        int volume = Convert.ToInt16(device.AudioEndpointVolume.MasterVolumeLevelScalar * 100);
        Console.WriteLine($@"{device.FriendlyName} Громкость звука:{volume}");
    }
}

результат

PHL 271V8 (аудио высокой четкости NVIDIA) Размер звука: 100 Динамик/наушник (Realtek(R) Audio) Громкость звука: 29

Микрофон и динамики по умолчанию

код Язык:javascript
копировать
var defaultCaptureDevice = WasapiCapture.GetDefaultCaptureDevice();
Console.WriteLine($@"Defaultмикрофон:{defaultCaptureDevice.FriendlyName}");
var defaultLoopbackCaptureDevice = WasapiLoopbackCapture.GetDefaultLoopbackCaptureDevice();
Console.WriteLine($@"Динамик по умолчанию: {defaultLoopbackCaptureDevice.FriendlyName}");

Получите громкость микрофона в реальном времени

xaml

код Язык:javascript
копировать
<ProgressBar
             BorderThickness="0"
             Maximum="100"
             Name="VolumeProgressBar" />

код

код Язык:javascript
копировать
// определение
private WaveInEvent waveIn = null;

private void AudioMonitor()
{
  if (WaveIn.DeviceCount == 0)
  {
    return;
  }
  // Начать сбор
  waveIn = new WaveInEvent();
  //Начинаем запись и записываем данные
  waveIn.DataAvailable += (o, e1) =>
  {
    byte[] buf = e1.Buffer;
    float maxNumber = 0;
    for (int index = 0; index < buf.Length; index += 2)
    {
      short sample = (short)((buf[index + 1] << 8) | buf[index + 0]);
      float sample32 = sample / 32768f;
      sample32 = Math.Abs(sample32);

      if (sample32 > maxNumber)
      {
        maxNumber = sample32;
      }
    }

    Dispatcher.Invoke(
      () =>
      {
        VolumeProgressBar.Value = maxNumber * 100;
      });
  };

  //конец записи
  waveIn.RecordingStopped += (s, a) =>
  {
    waveIn.Dispose();
  };

  waveIn.StartRecording();
}

останавливаться

код Язык:javascript
копировать
// останавливаться Вызывается, когда
if (waveIn != null)
{
    waveIn.StopRecording();
}

получать Список микрофонов

код Язык:javascript
копировать
for (int n = -1; n < WaveIn.DeviceCount; n++)
{
    var caps = WaveIn.GetCapabilities(n);
    Console.WriteLine($"{n}: {caps.ProductName}");
}

Распечатайте следующим образом

-1: Microsoft Sound Mapper 0: Микрофон (Realtek(R) Audio)

Обратите внимание, что указанный выше обход начинается с -1. Когда мы получаем микрофонное устройство, мы можем переходить с 0.

Настроить микрофон

Установите соответствующий индекс

код Язык:javascript
копировать
waveIn.DeviceNumber = 0;

Официальная документация

https://github.com/naudio/NAudio/blob/master/Docs/RecordingLevelMeter.md

Получите громкость динамика в реальном времени

код Язык:javascript
копировать
// определение
private WasapiLoopbackCapture capture = null; //new WasapiLoopbackCapture();

// Начать сбор
capture = new WasapiLoopbackCapture();

capture.DataAvailable += (s, e1) =>
{
    byte[] buf = e1.Buffer;
    float maxNumber = 0;
    for (int index = 0; index < buf.Length; index += 2)
    {
        short sample = (short)((buf[index + 1] << 8) | buf[index + 0]);
        float sample32 = sample / 32768f;
        sample32 = Math.Abs(sample32);

        if (sample32 > maxNumber)
        {
            maxNumber = sample32;
        }
    }

    Console.WriteLine("maxNumber" + maxNumber);
};
//конец записи
capture.RecordingStopped += (s, a) =>
{
    capture.Dispose();
};
capture.StartRecording();

if(capture!=null){
    capture.StopRecording();
}

Уведомление

На получение размера звука динамика не влияет размер системного звука, поэтому, если вы хотите, чтобы реальный размер звука был слышен реальным пользователям, используйте Собранная громкость звука*Настройки динамика, уровень звука

Установить громкость динамика

код Язык:javascript
копировать
private void SetCurrentSpeakerVolume(int volume)
{
    var enumerator = new MMDeviceEnumerator();
    IEnumerable<MMDevice> speakDevices = enumerator.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active).ToArray();
    if (speakDevices.Count() > 0)
    {
        MMDevice mMDevice = speakDevices.ToList()[0];
        mMDevice.AudioEndpointVolume.MasterVolumeLevelScalar = volume / 100.0f;
        Console.WriteLine("Набор динамиков:" + mMDevice.FriendlyName);
        Console.WriteLine("Установлена ​​громкость звука динамика:" + volume);
    }
}

Записывающий микрофон и динамики

Записывающий микрофон

код Язык:javascript
копировать
using System;
using System.IO;
using System.Threading;

using NAudio.Wave;

namespace ZUtils
{
    public class ZRecordMicrophoneHelper
    {
        public enum RecordState
        {
            Stop = 0,
            Start = 1,
            Pause = 2
        }


        private RecordState _state;

        //Записывающий голос микрофона
        private readonly WaveInEvent _waveIn; //new WaveInEvent();

        private Action<string> _stopAction;


        //Объект для создания аудиофайла

        public ZRecordMicrophoneHelper(string filePath)
        {
            WaveFileWriter writer;

            var audioFile = filePath;
            _state = RecordState.Pause;
            try
            {
                _waveIn = new WaveInEvent();
                writer = new WaveFileWriter(audioFile, _waveIn.WaveFormat);
                //Начинаем запись и записываем данные
                _waveIn.DataAvailable += (s, a) =>
                {
                    if (_state == RecordState.Start)
                    {
                        writer.Write(a.Buffer, 0, a.BytesRecorded);
                    }
                };

                //конец записи
                _waveIn.RecordingStopped += (s, a) =>
                {
                    writer.Dispose();
                    writer = null;
                    _waveIn.Dispose();
                    _stopAction?.Invoke(audioFile);
                };

                _waveIn.StartRecording();
            }
            catch (Exception)
            {
                // ignored
            }
        }

        /// <summary>
        /// Начать запись
        /// </summary>
        public void StartRecordAudio()
        {
            _state = RecordState.Start;
        }

        /// <summary>
        /// Завершить запись
        /// </summary>
        public void StopRecordAudio(Action<string> stopAction)
        {
            _stopAction = stopAction;
            _state = RecordState.Stop;
            _waveIn.StopRecording();
        }

        /// <summary>
        /// Пауза записи
        /// </summary>
        public void PauseRecordAudio()
        {
            _state = RecordState.Pause;
        }

        /// <summary>
        /// Возобновить запись
        /// </summary>
        public void ResumeRecordAudio()
        {
            _state = RecordState.Start;
        }

        /// <summary>
        /// Устройство доступно?
        /// </summary>
        /// <returns></returns>
        public static bool IsDeviceGood()
        {
            string tempPath = Path.GetTempPath();

            WaveInEvent mWaveIn;
            WaveFileWriter mWriter = null;
            try
            {
                string mAudioFile = Path.Combine(tempPath, "_microphone.mp3");

                mWaveIn = new WaveInEvent();
                mWriter = new WaveFileWriter(mAudioFile, mWaveIn.WaveFormat);
                //Начинаем запись и записываем данные
                var writer = mWriter;
                mWaveIn.DataAvailable += (s, a) =>
                {
                    writer.Write(a.Buffer, 0, a.BytesRecorded);
                };

                //конец записи
                mWaveIn.RecordingStopped += (s, a) =>
                {
                    writer.Dispose();

                    mWriter = null;
                    mWaveIn.Dispose();

                    if (File.Exists(mAudioFile))
                    {
                        File.Delete(mAudioFile);
                    }
                };

                mWaveIn.StartRecording();

                ThreadPool.QueueUserWorkItem(o =>
                {
                    Thread.Sleep(200);
                    mWaveIn.StopRecording();
                });
            }
            catch (Exception)
            {
                if (mWriter != null)
                {
                    mWriter.Dispose();
                    mWriter = null;
                }

                return false;
            }

            return true;
        }
    }
}

Уведомление

Здесь запись вызывается непосредственно при инициализации класса. Причина в том, что если аудио и видео записываются одновременно и включаются одновременно, время запуска будет последовательным по аппаратным причинам, что приведет к появлению звука и звука. изображение не синхронизировано. Та же причина применима и к видеозаписи в следующем тексте.

Запись динамиков

код Язык:javascript
копировать
using System;
using System.IO;
using System.Threading;

using NAudio.Wave;

namespace ZUtils
{
    public class ZRecordLoudspeakerHelper
    {
        public enum RecordState
        {
            Stop = 0,
            Start = 1,
            Pause = 2
        }

        private RecordState _state;

        //Запись голос динамиков
        private readonly WasapiLoopbackCapture _capture; 

        private Action<string> _stopAction;

        public ZRecordLoudspeakerHelper(string filePath)
        {
            WaveFileWriter writer;

            var audioFile = filePath;
            _state = RecordState.Pause;
            try
            {
                _capture = new WasapiLoopbackCapture();
                writer = new WaveFileWriter(audioFile, _capture.WaveFormat);

                _capture.DataAvailable += (s, a) =>
                {
                    if (_state == RecordState.Start)
                    {
                        writer.Write(a.Buffer, 0, a.BytesRecorded);
                    }
                };
                //конец записи
                _capture.RecordingStopped += (s, a) =>
                {
                    writer.Dispose();
                    writer = null;
                    _capture.Dispose();
                    _stopAction?.Invoke(audioFile);
                };
                _capture.StartRecording();
            }
            catch (Exception)
            {
                // ignored
            }
        }

        /// <summary>
        /// Начать запись
        /// </summary>
        public void StartRecordAudio()
        {
            _state = RecordState.Start;
        }

        /// <summary>
        /// Завершить запись
        /// </summary>
        public void StopRecordAudio(Action<string> stopAction)
        {
            _stopAction = stopAction;
            _state = RecordState.Stop;
            _capture.StopRecording();
        }

        /// <summary>
        /// Пауза записи
        /// </summary>
        public void PauseRecordAudio()
        {
            _state = RecordState.Pause;
        }

        /// <summary>
        /// Возобновить запись
        /// </summary>
        public void ResumeRecordAudio()
        {
            _state = RecordState.Start;
        }

        /// <summary>
        /// Устройство доступно?
        /// </summary>
        /// <returns></returns>
        public static bool IsDeviceGood()
        {
            string tempPath = Path.GetTempPath();

            WaveFileWriter mWriter = null;
            WasapiLoopbackCapture mCapture;
            try
            {
                string mAudioFile = Path.Combine(tempPath, "_loudspeaker.mp3");
                mCapture = new WasapiLoopbackCapture();
                mWriter = new WaveFileWriter(mAudioFile, mCapture.WaveFormat);

                var writer = mWriter;
                mCapture.DataAvailable += (s, a) =>
                {
                    writer.Write(a.Buffer, 0, a.BytesRecorded);
                };
                //конец записи
                mCapture.RecordingStopped += (s, a) =>
                {
                    writer.Dispose();

                    mWriter = null;
                    mCapture.Dispose();

                    if (File.Exists(mAudioFile))
                    {
                        File.Delete(mAudioFile);
                    }
                };
                mCapture.StartRecording();
                ThreadPool.QueueUserWorkItem(o =>
                {
                    Thread.Sleep(200);
                    mCapture.StopRecording();
                });
            }
            catch (Exception)
            {
                if (mWriter != null)
                {
                    mWriter.Dispose();
                    mWriter = null;
                }
                return false;
            }

            return true;
        }
    }
}

микширование звука

код Язык:javascript
копировать
public static void MixAudio
(
    string microphonePath,
    string loudspeakerPath,
    string outPath
)
{
    using (var reader1 = new AudioFileReader(microphonePath))
    using (var reader2 = new AudioFileReader(loudspeakerPath))
    {
        reader1.Volume = 1.0f;
        reader2.Volume = 0.6f;
        var mixer = new MixingSampleProvider
        (
            new[]
            {
                reader1,
                reader2
            }
        );
        WaveFileWriter.CreateWaveFile16(outPath, mixer);
    }
}

Получение статуса аудио

Изменить громкость системы

код Язык:javascript
копировать
[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, UInt32 dwFlags, UInt32 dwExtraInfo);
 
[DllImport("user32.dll")]
static extern Byte MapVirtualKey(UInt32 uCode, UInt32 uMapType);
 
private const byte VK_VOLUME_MUTE = 0xAD;
private const byte VK_VOLUME_DOWN = 0xAE;
private const byte VK_VOLUME_UP = 0xAF;
private const UInt32 KEYEVENTF_EXTENDEDKEY = 0x0001;
private const UInt32 KEYEVENTF_KEYUP = 0x0002;
 
/// <summary>
/// Изменить громкость размер системы, увеличение
/// </summary>
public void VolumeUp()
{
    keybd_event(VK_VOLUME_UP, MapVirtualKey(VK_VOLUME_UP, 0), KEYEVENTF_EXTENDEDKEY, 0);
    keybd_event(VK_VOLUME_UP, MapVirtualKey(VK_VOLUME_UP, 0), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
 
/// <summary>
/// Изменить громкость размер системы, уменьшить
/// </summary>
public void VolumeDown()
{
    keybd_event(VK_VOLUME_DOWN, MapVirtualKey(VK_VOLUME_DOWN, 0), KEYEVENTF_EXTENDEDKEY, 0);
    keybd_event(VK_VOLUME_DOWN, MapVirtualKey(VK_VOLUME_DOWN, 0), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
 
/// <summary>
/// Изменить громкость размер системы, немой
/// </summary>
public void Mute()
{
    keybd_event(VK_VOLUME_MUTE, MapVirtualKey(VK_VOLUME_MUTE, 0), KEYEVENTF_EXTENDEDKEY, 0);
    keybd_event(VK_VOLUME_MUTE, MapVirtualKey(VK_VOLUME_MUTE, 0), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}

Изменить громкость программного обеспечения

Изменить громкость программного обеспечения но нет Изменить громкость системы

код Язык:javascript
копировать
[DllImport("Winmm.dll")]
private static extern int waveOutSetVolume(int hwo, System.UInt32 pdwVolume);

[DllImport("Winmm.dll")]
private static extern uint waveOutGetVolume(int hwo, out System.UInt32 pdwVolume);  

private int volumeMinScope = 0;
private int volumeMaxScope = 100;
private int volumeSize = 100;

/// <summary>
/// Регулятор громкости, но не Изменить громкость системынастраивать
/// </summary>
public int VolumeSize
{
    get { return volumeSize; }
    set { volumeSize = value; }
}

public void SetCurrentVolume()
{
    if (volumeSize < 0)
    {
        volumeSize = 0;
    }

    if (volumeSize > 100)
    {
        volumeSize = 100;
    }

    //Сначала сопоставляем значение трекбара с диапазоном 0x0000~0xFFFF
    System.UInt32 Value = (System.UInt32)((double)0xffff * (double)volumeSize / (double)(volumeMaxScope - volumeMinScope));


    //Ограничиваем диапазон значений значения
    if (Value < 0)
    {
        Value = 0;
    }

    if (Value > 0xffff)
    {
        Value = 0xffff;
    }

    System.UInt32 left = (System.UInt32)Value;//Громкость левого канала
    System.UInt32 right = (System.UInt32)Значение;//Правильно
    waveOutSetVolume(0, left << 16 | right); //"<<"Сдвиг влево,"|" логическая операция ИЛИ
}

Установить аудиоустройство по умолчанию

На данный момент нет возможности использовать код Установить аудиоустройство по умолчанию

Открыть системные настройки звука,Позвольте пользователям работать

код Язык:javascript
копировать
Process.Start("mmsys.cpl");

Камера

Камерасписок

Получить список Камер

код Язык:javascript
копировать
```



## Камера экран

```csharp
строка docPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var FouderPath = Path.Combine(docPath, "Video");
if (!Directory.Exists(fouderPath))
{
    Directory.CreateDirectory(fouderPath);
}
string mp4Path = Path.Combine(fouderPath, "out.avi");

// Параметры определения видео и аудио
double fps = 20;
Size videoSize = new Size(640, 480);

// видеозапись
VideoCapture videoCapture = new VideoCapture(CaptureDevice.DShow, 0);
videoCapture.FrameWidth = videoSize.Width;
videoCapture.FrameHeight = videoSize.Height;
videoCapture.Fps = fps;
videoCapture.Open(0);

// Создать видеокодер
_videoWriter = new VideoWriter
(
    mp4Path,
    FourCC.XVID,
    fps,
    videoSize
);
new Thread
(
    () =>
    {
        while (true)
        {
            using (var frame = new Mat())
            {
                while (true)
                {
                    if (!videoCapture.Read(frame))
                        return;
                    if (frame.Width != 640)
                    	return;
                    lock (this)
                    {
                        _videoWriter?.Write(frame);
                    }
                    Dispatcher.Invoke
                    (
                        () =>
                        {
                            var bitmap = BitmapConverter.ToBitmap(frame);
                            BitmapImage bitmapImage = new BitmapImage();
                            using (MemoryStream memory = new MemoryStream())
                            {
                                bitmap.Save(memory, ImageFormat.Png);
                                memory.Position = 0;
                                bitmapImage.BeginInit();
                                bitmapImage.StreamSource = memory;
                                bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                                bitmapImage.EndInit();
                            }
                            this.MyImg.Source = bitmapImage;
                            bitmap.Dispose();
                        }
                    );
                }
            }
        }
    }
).Start();

видеозапись

Запись на рабочий стол

Инструменты

код Язык:javascript
копировать
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
using System.Windows.Forms;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using Size = OpenCvSharp.Size;

// ReSharper disable MemberCanBePrivate.Local

namespace z_recorder_opencv.Uitls
{
    public class ZRecordVideoHelper
    {
        public enum RecordState
        {
            Stop = 0,
            Start = 1,
            Pause = 2
        }

        private RecordState _state;
        private int _fps;


        private readonly VideoWriter _videoWriter; //написание видео

        public ZRecordVideoHelper(string filePath, int fps = 5)
        {
            _fps = fps;
            _state = RecordState.Pause;
            Size videoSize = new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
            try
            {
                // Открыт для записи
                lock (this)
                {
                    _videoWriter = new VideoWriter
                    (
                        filePath,
                        FourCC.XVID,
                        fps,
                        videoSize
                    );
                }
            }
            catch (Exception)
            {
                // ignored
            }
        }

        /// <summary>
        /// Начать запись
        /// </summary>
        public bool StartRecordVideo()
        {
            _state = RecordState.Start;

            int frameSpace = 1000 / _fps;
            new Thread
            (
                () =>
                {
                    var dateTime = DateTime.Now;
                    while (true)
                    {
                        var miniSec = DateTime.Now.Subtract(dateTime).Milliseconds;
                        if (miniSec < frameSpace)
                        {
                            break;
                        }

                        if (_state == RecordState.Start)
                        {
                            lock (this)
                            {
                                dateTime = DateTime.Now;
                                using (var screen = GetScreen())
                                {
                                    using (var frame = screen.ToMat())
                                    {
                                        _videoWriter?.Write(frame);
                                    }
                                }
                            }
                        }
                    }
                }
            ).Start();
            return true;
        }


        /// <summary>
        /// Завершить запись
        /// </summary>
        public void StopRecordVideo()
        {
            _state = RecordState.Stop;


            // заканчиваем запись
            lock (this)
            {
                _videoWriter.Release();
                _videoWriter.Dispose();
            }
        }

        /// <summary>
        /// Пауза записи
        /// </summary>
        public void PauseRecordVideo()
        {
            _state = RecordState.Pause;
        }

        /// <summary>
        /// Возобновить запись
        /// </summary>
        public void ResumeRecordVideo()
        {
            _state = RecordState.Start;
        }


        private const PixelFormat FORMAT = PixelFormat.Format24bppRgb;

        public static Bitmap GetScreen()
        {
            Bitmap screenshot = new Bitmap
            (
                Screen.PrimaryScreen.Bounds.Width,
                Screen.PrimaryScreen.Bounds.Height,
                FORMAT
            );
            using (Graphics gfx = Graphics.FromImage(screenshot))
            {
                gfx.CopyFromScreen
                (
                    Screen.PrimaryScreen.Bounds.X,
                    Screen.PrimaryScreen.Bounds.Y,
                    0,
                    0,
                    Screen.PrimaryScreen.Bounds.Size,
                    CopyPixelOperation.SourceCopy
                );

                // Нарисовать значок курсора
                // Создайте красную кисть
                Brush brush = new SolidBrush(Color.LimeGreen);
                gfx.FillEllipse
                (
                    brush,
                    Cursor.Position.X - 10,
                    Cursor.Position.Y - 10,
                    20,
                    20
                );
                return screenshot;
            }
        }
    }
}

Метод вызова

код Язык:javascript
копировать
// указатель текущей формы
IntPtr winHandle = new WindowInteropHelper(this).Handle;
var curScreen = Screen.FromHandle(winHandle);
int RecordWidth = curScreen.Bounds.Width;
int RecordHeight = curScreen.Bounds.Height;

//Запись на рабочий стол
ZRecordVideoHelper helper3 = null;
helper3 = new ZRecordVideoHelper(TempVideoPathName, RecordWidth, RecordHeight);
helper3.StartRecordVideo();

//Пауза записи
helper3.PauseRecordVideo();

//Возобновить запись
helper3.ResumeRecordVideo();

//Завершить запись
helper3.StopRecordVideo();

написание видео

код Язык:javascript
копировать
private VideoWriter _videoWriter;
// Создать видеокодер
_videoWriter = new VideoWriter
(
    aviPath,
    FourCC.XVID,
    fps,
    videoSize
);

//писать
_videoWriter?.Write(frame);

Чтение потока на рабочем столе

код Язык:javascript
копировать

Запись компонентов

код Язык:javascript
копировать
/// <summary>
/// сохранить изображение
/// </summary>
/// <param name="ui">Нужны скриншотыUIконтроль</param>
/// <param name="filePathName">Адрес сохранения изображения имя 1.png</param>
/// <param name="ImgWidth">Высокий уровень после преобразования</param>
/// <param name="ImgHeight">Высокий уровень после преобразования</param>
public static void SaveUI(FrameworkElement ui, string filePathName, int ImgWidth, int ImgHeight)
{
    Console.WriteLine("Путь к снимку экрана:" + filePathName);
    try
    {
        RenderTargetBitmap bmp = new RenderTargetBitmap(
            (int)ui.ActualWidth,
            (int)ui.ActualHeight,
            1 / 96, 1 / 96,
            PixelFormats.Default
        );
        bmp.Render(ui);
        BitmapEncoder encoder = new PngBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(bmp));
        if (ImgWidth > 0)
        {
            MemoryStream memoryStream = new MemoryStream();
            encoder.Save(memoryStream);
            Bitmap bit = new Bitmap(memoryStream, true);
            Bitmap Img = new Bitmap(bit, ImgWidth, ImgHeight);
            Img.Save(filePathName);
            Img.Dispose();
            bit.Dispose();
            memoryStream.Dispose();
        }
        else
        {
            using (var stream = new FileStream(filePathName, FileMode.Create))
            {
                encoder.Save(stream);
            }
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
}

public static void SaveUI2(FrameworkElement frameworkElement, string filePathName)
{
    System.IO.FileStream fs = new System.IO.FileStream(filePathName, System.IO.FileMode.Create);
    RenderTargetBitmap bmp = new RenderTargetBitmap((int)frameworkElement.ActualWidth, (int)frameworkElement.ActualHeight, 1 / 96, 1 / 96, PixelFormats.Default);
    bmp.Render(frameworkElement);
    BitmapEncoder encoder = new PngBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(bmp));
    encoder.Save(fs);
    fs.Close();
}

public static Bitmap SaveUI2Bitmap(FrameworkElement frameworkElement, int width, int height)
{
    using (MemoryStream outStream = new MemoryStream())
    {
        RenderTargetBitmap bmp = new RenderTargetBitmap(
            (int)frameworkElement.ActualWidth,
            (int)frameworkElement.ActualHeight,
            1 / 96, 
            1 / 96,
            PixelFormats.Default
        );
        bmp.Render(frameworkElement);
        BitmapEncoder enc = new PngBitmapEncoder();
        enc.Frames.Add(BitmapFrame.Create(bmp));
        enc.Save(outStream);

        System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(outStream);
        return new Bitmap(bitmap, width, height);
    }
}

Запись камеры

Интервал кадров управления записью

код Язык:javascript
копировать
private WaveFileWriter _audioWriter;
private VideoWriter _videoWriter;

private async void CameraRecord()
{
    string docPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    var fouderPath = Path.Combine(docPath, "Video");
    if (!Directory.Exists(fouderPath))
    {
        Directory.CreateDirectory(fouderPath);
    }
    string aviPath = Path.Combine(fouderPath, "in_video.avi");

    // Параметры определения видео и аудио
    double fps = 24;
    Size videoSize = new Size(640, 480);

    // видеозапись
    VideoCapture videoCapture = new VideoCapture(CaptureDevice.DShow, 0);
    videoCapture.FrameWidth = videoSize.Width;
    videoCapture.FrameHeight = videoSize.Height;
    videoCapture.Fps = fps;
    videoCapture.Open(0);

    // Создать видеокодер
    _videoWriter = new VideoWriter
    (
        aviPath,
        FourCC.XVID,
        fps,
        videoSize
    );
    int frameSpace = (int)(1000 / fps);
    new Thread
    (
        () =>
        {
            var dateTime = DateTime.Now;
            while (true)
            {
                using (var frame = new Mat())
                {
                    while (true)
                    {
                        var miniSec = DateTime.Now.Subtract(dateTime).Milliseconds;
                        if (miniSec < frameSpace)
                        {
                            break;
                        }

                        if (!videoCapture.Read(frame))
                        {
                            return;
                        }

                        if (frame.Width != 640)
                        {
                            return;
                        }
                        lock (this)
                        {
                            dateTime = DateTime.Now;
                            _videoWriter?.Write(frame);
                        }
                        Dispatcher.Invoke
                        (
                            () =>
                            {
                                var bitmap = BitmapConverter.ToBitmap(frame);
                                BitmapImage bitmapImage = new BitmapImage();
                                using (MemoryStream memory = new MemoryStream())
                                {
                                    bitmap.Save(memory, ImageFormat.Png);
                                    memory.Position = 0;
                                    bitmapImage.BeginInit();
                                    bitmapImage.StreamSource = memory;
                                    bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                                    bitmapImage.EndInit();
                                }
                                this.MyImg.Source = bitmapImage;
                                bitmap.Dispose();
                            }
                        );
                    }
                }
            }
        }
    ).Start();

    //Аудиозапись
    string wavPath = Path.Combine(fouderPath, "in_audio.wav");
    WaveFormat audioFormat = new WaveFormat
    (
        44100,
        16,
        2
    );

    // Создать аудиомагнитофон
    _audioWriter = new WaveFileWriter(wavPath, audioFormat);

    // Создать аудиозахватчик
    WaveInEvent audioCapture = new WaveInEvent();
    audioCapture.WaveFormat = audioFormat;
    audioCapture.DataAvailable += (sender, e) => _audioWriter.Write
    (
        e.Buffer,
        0,e.BytesRecorded
    );
    audioCapture.StartRecording();
    await Task.Delay(20 * 1000);
    // останавливаться Записывать Аудиоивидео    videoCapture.Release();
    _videoWriter.Release();
    await Task.Delay(1 * 1000);
    string picPath = Path.Combine(fouderPath, "test.jpg");
    ZOpencvUtils.GetVideoPic(aviPath, picPath);
    var duration = ZOpencvUtils.GetDuration(aviPath);
    Console.WriteLine($@"duration:{duration}");
    audioCapture.StopRecording();
    _audioWriter.Close();
    _audioWriter.Dispose();
}

Раздельная съемка и запись кадров

код Язык:javascript
копировать
private WaveFileWriter _audioWriter;
private VideoWriter _videoWriter;
private readonly Queue<Mat> _videoQueue = new Queue<Mat>();
private RecordState _recordState;

enum RecordState
{
    Stop,
    Recording
}

private async void CameraRecord()
{
    string docPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    var fouderPath = Path.Combine(docPath, "Video");
    if (!Directory.Exists(fouderPath))
    {
        Directory.CreateDirectory(fouderPath);
    }
    string aviPath = Path.Combine(fouderPath, "in_video.avi");

    // Параметры определения видео и аудио
    double fps = 30;
    Size videoSize = new Size(640, 480);

    // видеозапись
    VideoCapture videoCapture = new VideoCapture(CaptureDevice.DShow, 0);
    videoCapture.FrameWidth = videoSize.Width;
    videoCapture.FrameHeight = videoSize.Height;
    videoCapture.Fps = fps;
    videoCapture.Open(0);

    // Создать видеокодер
    _videoWriter = new VideoWriter
    (
        aviPath,
        FourCC.XVID,
        fps,
        videoSize
    );
    int frameSpace = (int)(1000 / fps);
    _recordState = RecordState.Recording;
    new Thread
    (
        () =>
        {
            var dateTime = DateTime.Now;
            while (true)
            {
                using (var frame = new Mat())
                {
                    while (_recordState == RecordState.Recording)
                    {
                        var miniSec = DateTime.Now.Subtract(dateTime).Milliseconds;
                        if (miniSec < frameSpace)
                        {
                            break;
                        }
                        if (!videoCapture.Read(frame))
                        {
                            return;
                        }
                        if (frame.Width == 0)
                        {
                            return;
                        }
                        lock (this)
                        {
                            dateTime = DateTime.Now;
                            _videoQueue.Enqueue(frame);
                        }
                        Dispatcher.Invoke
                        (
                            () =>
                            {
                                var bitmap = BitmapConverter.ToBitmap(frame);
                                BitmapImage bitmapImage = new BitmapImage();
                                using (MemoryStream memory = new MemoryStream())
                                {
                                    bitmap.Save(memory, ImageFormat.Png);
                                    memory.Position = 0;
                                    bitmapImage.BeginInit();
                                    bitmapImage.StreamSource = memory;
                                    bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                                    bitmapImage.EndInit();
                                }
                                this.MyImg.Source = bitmapImage;
                                bitmap.Dispose();
                            }
                        );
                    }
                }
            }
        }
    ).Start();
    new Thread
    (
        () =>
        {
            while (_recordState == RecordState.Recording)
            {
                if (_videoQueue.Count > 0)
                {
                    var frame = _videoQueue.Dequeue();
                    _videoWriter?.Write(frame);
                }
            }
        }
    ).Start();

    //Аудиозапись
    string wavPath = Path.Combine(fouderPath, "in_audio.wav");
    WaveFormat audioFormat = new WaveFormat
    (
        44100,
        16,
        2
    );

    // Создать аудиомагнитофон
    _audioWriter = new WaveFileWriter(wavPath, audioFormat);

    // Создать аудиозахватчик
    WaveInEvent audioCapture = new WaveInEvent();
    audioCapture.WaveFormat = audioFormat;
    audioCapture.DataAvailable += (sender, e) =>
    {
        if (_recordState == RecordState.Recording)
        {
            _audioWriter.Write
            (
                e.Buffer,
                0,e.BytesRecorded
            );
        }
    };
    audioCapture.StartRecording();
    await Task.Delay(20 * 1000);
    _recordState = RecordState.Stop;
    // останавливаться Записывать Аудиоивидео    videoCapture.Release();
    _videoWriter.Release();
    await Task.Delay(1 * 1000);
    string picPath = Path.Combine(fouderPath, "out_thumbnail.jpg");
    ZOpencvUtils.GetVideoPic(aviPath, picPath);
    var duration = ZOpencvUtils.GetDuration(aviPath);
    Console.WriteLine($@"duration:{duration}");
    audioCapture.StopRecording();
    _audioWriter.Close();
    _audioWriter.Dispose();
}

Объединение аудио и видео

код Язык:javascript
копировать

Создать миниатюры

код Язык:javascript
копировать
/// <summary>
/// Создать миниатюры
/// </summary>
/// <param name="mp4Path"></param>
/// <param name="picPath"></param>
public static void GetVideoPic(string mp4Path, string picPath)
{
    using (var video = new VideoCapture())
    {
        Mat image = new Mat();
        video.Open(mp4Path);
        while (video.Read(image))
        {
            using (var bitmap = BitmapConverter.ToBitmap(image))
            {
                SaveAsJpeg
                (
                    bitmap,
                    picPath,
                    90
                );
            }
            break;
        }
    }
}

// Сохранить в формате jpeg, качество — качество изображения (0–100).
public static void SaveAsJpeg
(
    Bitmap bitmap,
    string fileName,
    int quality
)
{
    var jpegEncoder = ImageCodecInfo.GetImageEncoders().First(codec => codec.FormatID == ImageFormat.Jpeg.Guid);
    var encoderParameters = new EncoderParameters(1);
    encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality);
    bitmap.Save
    (
        fileName,
        jpegEncoder,
        encoderParameters
    );
}

Получить продолжительность видео

код Язык:javascript
копировать
/// <summary>
/// Получить продолжительность видео
/// </summary>
/// <param name="mp4Path"></param>
/// <returns></returns>
public static int GetDuration(string mp4Path)
{
    try
    {
        using (var video = new VideoCapture())
        {
            video.Open(mp4Path);
            return (int)(video.FrameCount / video.Fps);
        }
    }
    catch (Exception)
    {
        return 0;
    }
}

Открыть системные настройки звука

код Язык:javascript
копировать
Process.Start("mmsys.cpl");

Позвонить в местную игру

код Язык:javascript
копировать
Process pro = new Process
{
  StartInfo = new ProcessStartInfo(videoPath)
};
pro.Start();

Расчет параметров звука

Формула между частотой дискретизации и скоростью передачи данных (скоростью кода) выглядит следующим образом:

Битрейт = Частота дискретизации × Глубина выборки × Количество каналов AudioBitRate = SampleRate × биты × каналы

Среди них частота дискретизации представляет собой количество выборок, собираемых в секунду, в Гц (герцах); глубина выборки представляет собой количество битов, занимаемых каждым значением выборки, обычно 16 или 24 бита; количество каналов представляет собой количество каналов; аудиосигнала. Обычно моно или стерео.

Например, для фрагмента стереомузыки с частотой дискретизации 44100 Гц, глубиной дискретизации 16 бит и номером канала 2, его битрейт равен:

Скорость передачи данных = 44100 × 16 × 2 = 1411200 бит/с = 1,41 Мбит/с.

Частота дискретизации — 44100 Гц, глубина выборки — 16 бит, количество каналов — 1, тогда битрейт:

Скорость передачи данных = 44100 × 16 × 1 = 705600 бит/с.

потому что

1 byte = 8 bits

Таким образом, байт, сгенерированный за 1 с в приведенном выше примере, равен

1411200 / 8 = 176400

Параметры, используемые в аудиорасчетах

код Язык:javascript
копировать
//Частота кадров
private readonly int _frameRate;

//Аудио Частота выборки
private readonly int _audioSampleRate = 44100;

//Разрядность аудио
private readonly int _audioBits = 16;

//Аудио Количество каналов
private readonly int _audioChannels = 1;

битрейт аудио

код Язык:javascript
копировать
битрейт = Частота выборки * разрядность * Количество каналов
audioBitRate = _audioSampleRate * _audioBits * _audioChannels;

размер аудиокадра

код Язык:javascript
копировать
размер аудиокадра = битрейт * 1 секунда / 8 / Количество каналов / Частота кадров
audioFrameSize = audioBitRate * 1 / 8 / _audioChannels / _frameRate 
    = _audioSampleRate * _audioBits * _audioChannels * 1 / 8 / 2 / _frameRate
    = _audioSampleRate * _audioBits * _audioChannels / 16 / _frameRate

вбитрейт * 1 секунда / 8для1 секунды – байты.

время работы

код Язык:javascript
копировать
Stopwatch sw = Stopwatch.StartNew(); // Начало времени
//тествремя код работы
SW.Стоп();
Console.WriteLine($@"sw.Elapsed.Milliсекунды:{sw.Elapsed.Milliсекунды}");
boy illustration
Учебное пособие по Jetpack Compose для начинающих, базовые элементы управления и макет
boy illustration
Код js веб-страницы, фон частицы, код спецэффектов
boy illustration
【новый! Суперподробное】Полное руководство по свойствам компонентов Figma.
boy illustration
🎉Обязательно к прочтению новичкам: полное руководство по написанию мини-программ WeChat с использованием программного обеспечения Cursor.
boy illustration
[Забавный проект Docker] VoceChat — еще одно приложение для мгновенного чата (IM)! Может быть встроен в любую веб-страницу!
boy illustration
Как реализовать переход по странице в HTML (html переходит на указанную страницу)
boy illustration
Как решить проблему зависания и низкой скорости при установке зависимостей с помощью npm. Существуют ли доступные источники npm, которые могут решить эту проблему?
boy illustration
Серия From Zero to Fun: Uni-App WeChat Payment Practice WeChat авторизует вход в систему и украшает страницу заказа, создает интерфейс заказа и инициирует запрос заказа
boy illustration
Серия uni-app: uni.navigateЧтобы передать скачок значения
boy illustration
Апплет WeChat настраивает верхнюю панель навигации и адаптируется к различным моделям.
boy illustration
JS-время конвертации
boy illustration
Обеспечьте бесперебойную работу ChromeDriver 125: советы по решению проблемы chromedriver.exe не найдены
boy illustration
Поле комментария, щелчок мышью, специальные эффекты, js-код
boy illustration
Объект массива перемещения объекта JS
boy illustration
Как открыть разрешение на позиционирование апплета WeChat_Как использовать WeChat для определения местонахождения друзей
boy illustration
Я даю вам два набора из 18 простых в использовании фонов холста Power BI, так что вам больше не придется возиться с цветами!
boy illustration
Получить текущее время в js_Как динамически отображать дату и время в js
boy illustration
Вам необходимо изучить сочетания клавиш vsCode для форматирования и организации кода, чтобы вам больше не приходилось настраивать формат вручную.
boy illustration
У ChatGPT большое обновление. Всего за 45 минут пресс-конференция показывает, что OpenAI сделал еще один шаг вперед.
boy illustration
Copilot облачной разработки — упрощение разработки
boy illustration
Микросборка xChatGPT с низким кодом, создание апплета чат-бота с искусственным интеллектом за пять шагов
boy illustration
CUDA Out of Memory: идеальное решение проблемы нехватки памяти CUDA
boy illustration
Анализ кластеризации отдельных ячеек, который должен освоить каждый&MarkerгенетическийВизуализация
boy illustration
vLLM: мощный инструмент для ускорения вывода ИИ
boy illustration
CodeGeeX: мощный инструмент генерации кода искусственного интеллекта, который можно использовать бесплатно в дополнение к второму пилоту.
boy illustration
Машинное обучение Реальный бой LightGBM + настройка параметров случайного поиска: точность 96,67%
boy illustration
Бесшовная интеграция, мгновенный интеллект [1]: платформа больших моделей Dify-LLM, интеграция без кодирования и встраивание в сторонние системы, более 42 тысяч звезд, чтобы стать свидетелями эксклюзивных интеллектуальных решений.
boy illustration
LM Studio для создания локальных больших моделей
boy illustration
Как определить количество слоев и нейронов скрытых слоев нейронной сети?
boy illustration
[Отслеживание целей] Подробное объяснение ByteTrack и детали кода