WPF 绘图效率的问题 如何速度快而且又避免卡顿

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF 绘图效率的问题 如何速度快而且又避免卡顿相关的知识,希望对你有一定的参考价值。

参考技术A 1、内存容量不足,应用程序抢占内存空间会导致死机。可腾讯电脑管家卸载不要的软件
2、应用程序内存空间分配错误会导致死机。
3、内存质量不佳,应用程序写入内存的数据无法读取会导致死机。
4、多个应用程序在内存地址分配时发生冲突也会导致死机。
5、系统感染了毒,病毒大量在内存中复制导致应用程序可用内存不足从而产生应用程序内存分配冲突而导致死机用腾讯电脑管家彻底查杀病毒。

如何避免 DirectSound 中的失真和卡顿?

【中文标题】如何避免 DirectSound 中的失真和卡顿?【英文标题】:How can I avoid distortion and stuttering in DirectSound? 【发布时间】:2015-01-20 06:54:43 【问题描述】:

我有一个使用 C 语言编写的 DirectSound 应用程序,在 Windows 7 上运行。该应用程序只是捕获一些声音帧,然后播放它们。为了对捕获结果进行完整性检查,我将 PCM 数据写入一个文件,我可以使用 aplay 在 Linux 中播放该文件。

不幸的是,声音断断续续,有时包含口吃(并且在 Linux 中播放速度不正确)。奇怪的是,如果 PCM 数据在捕获时没有在播放缓冲区中播放,则在播放捕获文件时观察到的失真量会更少。

这是我的 WAVEFORMATEX 的初始化:

memset(&wfx, 0, sizeof(WAVEFORMATEX)); 
wfx.cbSize = 0;
wfx.wFormatTag = WAVE_FORMAT_PCM; 
wfx.nChannels = 1; 
wfx.nSamplesPerSec = sampleRate; 
wfx.wBitsPerSample = sampleBitWidth;
wfx.nBlockAlign = (wfx.nChannels * wfx.wBitsPerSample) / 8; 
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign code here

sampleRate 为 8000,sampleBitWidth 为 16。

我使用相同的结构创建了一个捕获和播放缓冲区,捕获缓冲区有 3 个通知位置。我开始捕捉:

lpDsCaptureBuffer->Start(DSCBSTART_LOOPING);

然后我启动一个播放线程,该线程在与通知点关联的事件上调用 WaitForMultipleObjects。收到通知后,我重置所有事件,并将 1 或 2 块捕获缓冲区复制到本地缓冲区,然后将它们传递给播放例程:

void playFromBuff(LPVOID captureBuff,DWORD captureLen) 
  LPVOID playBuff;
  DWORD playLen;
  HRESULT hr;

  hr = lpDsPlaybackBuffer->Lock(0L,captureLen,&playBuff,&playLen,NULL,0L,0L);

  memcpy(playBuff,captureBuff,playLen);
  hr = lpDsPlaybackBuffer->Unlock(playBuff,playLen,NULL,0L);
  hr = lpDsPlaybackBuffer->SetCurrentPosition(0L);
  hr = lpDsPlaybackBuffer->Play(0L,0L,0L);

(省略了一些错误检查)。

请注意,播放缓冲区没有通知位置。每次从捕获缓冲区中获取块时,我都会从位置 0 开始锁定播放缓冲区。

由 WaitForMultipleObjects 保护的捕获代码如下所示:

    lpDsCaptureBuffer->GetCurrentPosition(NULL,&readPos);

    hr = lpDsCaptureBuffer->Lock(...,...,&captureBuff1,&captureLen1,&captureBuff2,&captureLen2,0L);

其中省略号包含涉及当前和先前看到的读取位置的计算。我忽略了那些可能错误的计算——我怀疑这就是问题所在。

我的通知位置是 1024 的倍数。但报告的读取位置是 1500、2500 和 3500。所以如果我看到读取位置为 1500,这是否意味着我可以从字节 0 读取到 1500。当接下来我看到 2500,这是否意味着我应该从 1501 读取到 2500?为什么这些阅读位置与我的通知位置不完全对应?这里的正确算法是什么?

我尝试了一种更简单的替代方法,即在捕获缓冲区已满时停止捕获,而无需其他通知位置。但这意味着,我认为,允许一些声音逃脱捕获。

【问题讨论】:

【参考方案1】:

我的通知位置是 1024 的倍数。但报告的读取位置是 1500、2500 和 3500。所以如果我看到读取位置为 1500,这是否意味着我可以从字节 0 读取到 1500。当接下来我看到 2500,这是否意味着我应该从 1501 读取到 2500?为什么这些阅读位置与我的通知位置不完全对应?这里的正确算法是什么?

DirectSound API 现在是其他“真实”音频捕获 API 之上的兼容层。这意味着内部音频捕获会填充一些缓冲区(尤其是 500 的倍数),然后将填充的缓冲区传递给 DirectSound 捕获,然后再将它们报告给您。这就解释了为什么您会看到读取位置是 500 的倍数,因为 DirectSound 本身就可以通过这种方式获得数据。

由于您对获取捕获的数据感兴趣,因此您的假设是正确的,即您主要对读取位置感兴趣。您收到通知,并且知道可以安全读取的偏移量。由于捕获 API 是分层的,因此会涉及一些延迟,因为层需要在彼此之间传递大量数据,然后才能将它们提供给您。

【讨论】:

我重新计算了我的捕获缓冲区计算,所以现在,当我将捕获数据保存到一个文件时,在使用 Linux aplay 播放时声音是完美的——如果我不使用Windows 中的播放缓冲区。不知何故,在单独的缓冲区中播放数据的行为会影响捕获的内容。 一些提示:您应该能够使用调试器找到一些东西并跟踪调用和操作的顺序。也许您的线程同步会使您以某种方式丢失某些循环。出于调试目的,您需要从超长捕获缓冲区开始,以确保您没有上溢、下溢等问题。一旦在这个简单的场景中进行了调整,您就可以将其更改为接近您最终想要的。 我将一个 WAV 文件加载到缓冲区中,并尝试以 2 种方式播放它。首先,我尝试了老式的调用 sndPlaySound,听起来不错。接下来,我尝试使用我的 DirectSound 播放缓冲区。尽管音高和速度合适,但它听起来波涛汹涌且失真。会不会是因为仿真层效果不好? 我是这样看的:如果您有一个标准/外部方法可以流畅地播放捕获的数据,那么捕获本身就可以了。如果捕获受到并发播放的影响,那么我会研究导致捕获延迟的线程问题和死锁。如果只是播放有问题,那么那里应该有一个错误。请注意,在回放时,您再次处理分层 API,您必须提前准备好数据并远离缓冲数据(20-30-50 毫秒),否则数据在实际回放时到达较晚,您会听到断断续续的声音。 请参阅相关 Q What is the smallest audio buffer needed to produce Tone sound without distotions with WaveOUT API 以获取另一个旧 API,这同样适用于 DirectSound 播放 - 数据预加载时间最短,并且做得少于此时间会导致由于迟到而播放静音片段数据到达。

以上是关于WPF 绘图效率的问题 如何速度快而且又避免卡顿的主要内容,如果未能解决你的问题,请参考以下文章

如何解决wpf中绘图的卡顿

mysql提高查询速度

WPF三维立体效果3D

Android——APP性能如何优化

如何提高电脑运行速度

性能测试基本知识