Переустановите все зависимости
Update-Package –reinstall
Аудио и видео записываются отдельно. Если микрофон и динамики записываются, звук также необходимо записывать отдельно, и в конечном итоге все потоки будут объединены.
Официальная документация
NAudio
https://github.com/naudio/NAudio
OpenCvSharp4
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
Install-Package OpenCvSharp3-AnyCPU -Version 4.0.0.20181129
При использовании OpenCvSharp4 я всегда получаю сообщение об ошибке или не могу создать видеофайл при сохранении видео. Когда я переключаюсь на OpenCvSharp3, все нормально.
Для записи аудио используется библиотека NAudio, которая может как записывать микрофон, так и записывать динамики.
Установить
Install-Package NAudio -Version 1.9.0
Хорошего решения по слиянию пока не найдено.
Большинство объединенных библиотек представляют собой пакеты FFmpeg. Сам FFmpeg относительно велик и не рекомендуется для использования, поэтому лучшей альтернативы не найдено.
Использование НАудио
Установить
Install-Package NAudio -Version 1.9.0
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
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}");
}
}
Получите динамик по умолчанию и его размер звука.
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
var defaultCaptureDevice = WasapiCapture.GetDefaultCaptureDevice();
Console.WriteLine($@"Defaultмикрофон:{defaultCaptureDevice.FriendlyName}");
var defaultLoopbackCaptureDevice = WasapiLoopbackCapture.GetDefaultLoopbackCaptureDevice();
Console.WriteLine($@"Динамик по умолчанию: {defaultLoopbackCaptureDevice.FriendlyName}");
xaml
<ProgressBar
BorderThickness="0"
Maximum="100"
Name="VolumeProgressBar" />
код
// определение
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();
}
останавливаться
// останавливаться Вызывается, когда
if (waveIn != null)
{
waveIn.StopRecording();
}
получать Список микрофонов
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.
Настроить микрофон
Установите соответствующий индекс
waveIn.DeviceNumber = 0;
Официальная документация
https://github.com/naudio/NAudio/blob/master/Docs/RecordingLevelMeter.md
// определение
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();
}
Уведомление
На получение размера звука динамика не влияет размер системного звука, поэтому, если вы хотите, чтобы реальный размер звука был слышен реальным пользователям, используйте
Собранная громкость звука
*Настройки динамика, уровень звука
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);
}
}
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;
}
}
}
Уведомление
Здесь запись вызывается непосредственно при инициализации класса. Причина в том, что если аудио и видео записываются одновременно и включаются одновременно, время запуска будет последовательным по аппаратным причинам, что приведет к появлению звука и звука. изображение не синхронизировано. Та же причина применима и к видеозаписи в следующем тексте.
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;
}
}
}
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);
}
}
[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);
}
Изменить громкость программного обеспечения но нет Изменить громкость системы
[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); //"<<"Сдвиг влево,"|" логическая операция ИЛИ
}
На данный момент нет возможности использовать код Установить аудиоустройство по умолчанию
Открыть системные настройки звука,Позвольте пользователям работать
Process.Start("mmsys.cpl");
Получить список Камер
```
## Камера экран
```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();
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;
}
}
}
}
// указатель текущей формы
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();
private VideoWriter _videoWriter;
// Создать видеокодер
_videoWriter = new VideoWriter
(
aviPath,
FourCC.XVID,
fps,
videoSize
);
//писать
_videoWriter?.Write(frame);
/// <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);
}
}
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();
}
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();
}
/// <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
);
}
/// <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;
}
}
Process.Start("mmsys.cpl");
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
Параметры, используемые в аудиорасчетах
//Частота кадров
private readonly int _frameRate;
//Аудио Частота выборки
private readonly int _audioSampleRate = 44100;
//Разрядность аудио
private readonly int _audioBits = 16;
//Аудио Количество каналов
private readonly int _audioChannels = 1;
битрейт аудио
битрейт = Частота выборки * разрядность * Количество каналов
audioBitRate = _audioSampleRate * _audioBits * _audioChannels;
размер аудиокадра
размер аудиокадра = битрейт * 1 секунда / 8 / Количество каналов / Частота кадров
audioFrameSize = audioBitRate * 1 / 8 / _audioChannels / _frameRate
= _audioSampleRate * _audioBits * _audioChannels * 1 / 8 / 2 / _frameRate
= _audioSampleRate * _audioBits * _audioChannels / 16 / _frameRate
вбитрейт * 1 секунда / 8
для1 секунды – байты.
Stopwatch sw = Stopwatch.StartNew(); // Начало времени
//тествремя код работы
SW.Стоп();
Console.WriteLine($@"sw.Elapsed.Milliсекунды:{sw.Elapsed.Milliсекунды}");