c# 如何从 nvlc 捕获音频并提高 Accord.Audio.NewFrameEventArgs
c# how to capture audio from nvlc and raise Accord.Audio.NewFrameEventArgs
我正在使用 c# 开发用于记录来自 IP 摄像机的视频流的应用程序。
我正在使用 Accord.Video.FFMPEG.VideoFileWriter
和 nVLC C# 包装器。
我有一个 class 使用 nVLC 从流中捕获音频,它应该实现 IAudioSource
接口,所以我使用 CustomAudioRendere
来捕获声音数据,然后引发事件 NewFrame 包含信号对象。
问题是将信号保存到视频文件时,从 RTSP
流录制时声音很可怕(离散),但从本地麦克风(从笔记本电脑)录制时质量很好。
这是引发事件的代码:
public void Start()
{
_mFactory = new MediaPlayerFactory();
_mPlayer = _mFactory.CreatePlayer<IAudioPlayer>();
_mMedia = _mFactory.CreateMedia<IMedia>(Source);
_mPlayer.Open(_mMedia);
var fc = new Func<SoundFormat, SoundFormat>(SoundFormatCallback);
_mPlayer.CustomAudioRenderer.SetFormatCallback(fc);
var ac = new AudioCallbacks { SoundCallback = SoundCallback };
_mPlayer.CustomAudioRenderer.SetCallbacks(ac);
_mPlayer.Play();
}
private void SoundCallback(Sound newSound)
{
var data = new byte[newSound.SamplesSize];
Marshal.Copy(newSound.SamplesData, data, 0, (int)newSound.SamplesSize);
NewFrame(this, new Accord.Audio.NewFrameEventArgs(new Signal(data,Channels, data.Length, SampleRate, Format)));
}
private SoundFormat SoundFormatCallback(SoundFormat arg)
{
Channels = arg.Channels;
SampleRate = arg.Rate;
BitPerSample = arg.BitsPerSample;
return arg;
}
下面是捕获事件的代码:
private void source_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
Signal sig = eventArgs.Signal;
duration += eventArgs.Signal.Duration;
if (videoFileWrite == null)
{
videoFileWrite = new VideoFileWriter();
videoFileWrite.AudioBitRate = sig.NumberOfSamples*sig.NumberOfChannels*sig.SampleSize;
videoFileWrite.SampleRate = sig.SampleRate;
videoFileWrite.FrameSize = sig.NumberOfSamples/sig.NumberOfFrames;
videoFileWrite.Open("d:\output.mp4");
}
if (isStartRecord)
{
DoneWriting = false;
using (MemoryStream ms = new MemoryStream())
{
encoder = new WaveEncoder(ms);
encoder.Encode(eventArgs.Signal);
ms.Seek(0, SeekOrigin.Begin);
decoder = new WaveDecoder(ms);
Signal s = decoder.Decode();
videoFileWrite.WriteAudioFrame(s);
encoder.Close();
decoder.Close();
}
DoneWriting = true;
}
}
我通过仅从 SoundCallback void 中的 Sound 对象 "newSound" 获取一个通道解决了这个问题,然后从该字节数组创建一个信号并引发事件 "NewFrame"。
这一解决方案背后的主要思想是,当音频流包含多个通道时,SoundCallback void 中 Sound 对象中的 SampleData 属性 包含所有通道的字节数组,格式如下:
让我们假设两个字节样本的一个通道的声音数据是 A1A2B1B2C1C2...等,因此 SampleData 将用于两个通道:
A1A2A1A2B1B2B1B2C1C2C1C2.....等等
希望对您有所帮助。
我正在使用 c# 开发用于记录来自 IP 摄像机的视频流的应用程序。
我正在使用 Accord.Video.FFMPEG.VideoFileWriter
和 nVLC C# 包装器。
我有一个 class 使用 nVLC 从流中捕获音频,它应该实现 IAudioSource
接口,所以我使用 CustomAudioRendere
来捕获声音数据,然后引发事件 NewFrame 包含信号对象。
问题是将信号保存到视频文件时,从 RTSP
流录制时声音很可怕(离散),但从本地麦克风(从笔记本电脑)录制时质量很好。
这是引发事件的代码:
public void Start()
{
_mFactory = new MediaPlayerFactory();
_mPlayer = _mFactory.CreatePlayer<IAudioPlayer>();
_mMedia = _mFactory.CreateMedia<IMedia>(Source);
_mPlayer.Open(_mMedia);
var fc = new Func<SoundFormat, SoundFormat>(SoundFormatCallback);
_mPlayer.CustomAudioRenderer.SetFormatCallback(fc);
var ac = new AudioCallbacks { SoundCallback = SoundCallback };
_mPlayer.CustomAudioRenderer.SetCallbacks(ac);
_mPlayer.Play();
}
private void SoundCallback(Sound newSound)
{
var data = new byte[newSound.SamplesSize];
Marshal.Copy(newSound.SamplesData, data, 0, (int)newSound.SamplesSize);
NewFrame(this, new Accord.Audio.NewFrameEventArgs(new Signal(data,Channels, data.Length, SampleRate, Format)));
}
private SoundFormat SoundFormatCallback(SoundFormat arg)
{
Channels = arg.Channels;
SampleRate = arg.Rate;
BitPerSample = arg.BitsPerSample;
return arg;
}
下面是捕获事件的代码:
private void source_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
Signal sig = eventArgs.Signal;
duration += eventArgs.Signal.Duration;
if (videoFileWrite == null)
{
videoFileWrite = new VideoFileWriter();
videoFileWrite.AudioBitRate = sig.NumberOfSamples*sig.NumberOfChannels*sig.SampleSize;
videoFileWrite.SampleRate = sig.SampleRate;
videoFileWrite.FrameSize = sig.NumberOfSamples/sig.NumberOfFrames;
videoFileWrite.Open("d:\output.mp4");
}
if (isStartRecord)
{
DoneWriting = false;
using (MemoryStream ms = new MemoryStream())
{
encoder = new WaveEncoder(ms);
encoder.Encode(eventArgs.Signal);
ms.Seek(0, SeekOrigin.Begin);
decoder = new WaveDecoder(ms);
Signal s = decoder.Decode();
videoFileWrite.WriteAudioFrame(s);
encoder.Close();
decoder.Close();
}
DoneWriting = true;
}
}
我通过仅从 SoundCallback void 中的 Sound 对象 "newSound" 获取一个通道解决了这个问题,然后从该字节数组创建一个信号并引发事件 "NewFrame"。 这一解决方案背后的主要思想是,当音频流包含多个通道时,SoundCallback void 中 Sound 对象中的 SampleData 属性 包含所有通道的字节数组,格式如下: 让我们假设两个字节样本的一个通道的声音数据是 A1A2B1B2C1C2...等,因此 SampleData 将用于两个通道: A1A2A1A2B1B2B1B2C1C2C1C2.....等等
希望对您有所帮助。