【问题标题】:Use of SSE instructions along side with Libavcodec将 SSE 指令与 Libavcodec 一起使用
【发布时间】:2019-05-29 18:57:24
【问题描述】:

我编写了一个简单的视频会议应用程序,它使用多个线程进行视频和音频混合。我使用 libavcodec (ffmpeg) 编解码器来混合视频。据我所知,libavcodec 使用 SSE 指令来实现高性能。对于音频混合,我使用了一个简单的混合算法,它只是添加了样本。我已经用 C++ 中的 sipmle for 循环编写了加法算法,但现在我想使用这样的 SSE 指令对其进行优化:

__m128i* d = (__m128i*) pOutBuffer;
__m128i* s = (__m128i*) pInBuffer;
for (DWORD n = (DWORD)(nSizeToMix + 7) >> 3; n != 0; --n, ++d, ++s)
{
    //Load data in SSE registers
    __m128i xmm1 = _mm_load_si128(d);
    __m128i xmm2 = _mm_load_si128(s);
    //SSE2 sum
    _mm_store_si128(d, _mm_add_epi16(xmm1, xmm2));
}

音频混合是与视频混合同时完成的一个单独的线程。当我使用 SSE 指令时,应用程序在与音频混合无关的位置突然崩溃,在视频的编码/解码中。

似乎因为 libavcodec 使用 SSE 寄存器和指令,我的代码与之冲突。有什么方法可以使用 SSE 指令而不会与 libvcodec (ffmpeg) 发生任何冲突?任何建议表示赞赏。

【问题讨论】:

  • 只有在代码、ffmpeg 或编译器中存在错误时才会崩溃。寄存器应该在线程上下文切换时保存和恢复,因此线程应该完全独立。您的崩溃听起来像是内存损坏,请尝试在启用 asan 或 valgrind 的情况下运行
  • 反对票可能是由于缺少minimal reproducible example
  • 上下文切换在操作系统中实现:wiki.osdev.org/Context_Switching。您确定您的 sse 代码没有在缓冲区范围之外访问吗?例如您的输入和输出缓冲区是否至少有16 * (nSizeToMix + 7) / 8 字节长?我们再次需要minimal reproducible example
  • 为避免回绕,您可能希望使用像 _mm_avg_epu16 这样的平均值。但这是一个无符号平均值,音频数据通常是有符号的。所以也许只是在剪辑中添加饱和度而不是包装:_mm_adds_epi16。那是有符号饱和度; epu16 也可以使用无符号饱和度。
  • @PeterCordes 你是对的。我检查了我的缓冲区。它们不够长,无法容纳 16 个字节的倍数。我通过将数组的大小更改为 16 字节的倍数解决了我的问题。

标签: c++ sse libavcodec video-conferencing


【解决方案1】:

只要您使用现代编译器(超过 10 年的版本)并且您没有在汇编中编码,上下文切换应该没问题。编译器知道其目标平台的 ABI,因此您不必知道。

如果您包含导致应用崩溃的确切代码,则最可能的原因是对齐问题。将_mm_load_si128 替换为_mm_loadu_si128,将_mm_store_si128 替换为_mm_storeu_si128,看看是否有帮助。

更新 1: 另一个可能的原因是 SSE 版本完成速度太快,这会触发并发错误。尝试添加例如Sleep( 2 ) 在循环后调用,如果视频可以正常工作,则意味着您需要修复跨线程推送或拉取数据的代码。

更新 2: 正如 Alan 指出的,数组(缓冲区)的大小可能不是 16 字节的倍数 (16 * (nSizeToMix + 7) / 8)。这肯定会导致您的应用崩溃或内存损坏。

【讨论】:

  • 我已经有一段时间没有做任何 sse 了,但据我所知,需要对齐参数的指令会立即崩溃而不是导致内存损坏?
  • 是的,通常会崩溃。未对齐的访问是 OP 代码中唯一立即可见的问题(我假设缓冲区边界很好,因为 OP 已经运行了非 SSE 版本)。
  • 即使您是手工编写 asm 或使用旧的编译器,上下文切换仍然是透明的。您无法做任何事情来使操作系统异步损坏您的 XMM 寄存器。 OP 说他们的崩溃不在混合代码中。如果对齐是问题,SIMD 加载或存储就会崩溃。
猜你喜欢
  • 2010-10-09
  • 2017-12-02
  • 2015-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-26
  • 1970-01-01
相关资源
最近更新 更多