libavcodec/swscale 的输出损坏,具体取决于分辨率

2024-03-20

我正在编写一个视频会议软件,我有一个 H.264 流,使用 libavcoded 解码为 IYUV,然后在无窗口模式下使用 VMR9 渲染到窗口中。我使用 DirectShow 图形来执行此操作。

为了避免不必要的 RGB 和反转换(请参阅link https://stackoverflow.com/questions/23567621/does-vmr9-support-native-yuv-rendering),我使用 libswscale 将 IYUV 视频转换为 YUY2,然后将其传递到 VMR9。

我注意到视频分辨率为 848x480 时,输出视频会损坏,因此我进一步调查并发现,对于某些分辨率,视频总是会损坏。为了将 libswscale 排除在阐述之外,我添加了对 IYUV+padding 到 IYUV 转换的支持,并且它适用于所有分辨率。

尽管如此,我还是愿意避免缓慢的 IYUV,因此我实现了对 NV12(使用 libswscale)和 YV12(手动,本质上与 IYUV 相同)的支持。在两台不同的计算机上进行一些测试后,我得出了奇怪的结果。

resolution  YUY2    NV12    IYUV    YV12
PC 1 (my laptop)                
640x360     ok      broken  ok      broken
848x480     broken  broken  ok      broken
960x540     broken  broken  ok      broken
1024x576    ok      ok      ok      ok
1280x720    ok      ok      ok      broken
1920x1080   ok      broken  ok      broken

PC 2                
640x360     ok      ok      ok      ok
848x480     ok      broken  ok      broken
960x540     ok      ok      ok      ok
1024x576    ok      ok      ok      ok
1280x720    ok      broken  ok      ok
1920x1080   ok      ok      ok      ok

为了排除VMR9故障,我用EVR代替它,但结果相同。

I know that padding is needed for memory alignment, and that the size of padding depends on CPU used (libavcodec doc https://ffmpeg.org/doxygen/trunk/structAVFrame.html#aa52bfc6605f6a3059a0c3226cc0f6567), that may explain difference between two computers(first has Intel i7-3820QM, the second Intel Core 2 Quad Q6600). I suppose it has something to do with padding, because images are corrupted in certain way. You can see my blue t-shirt in lower part of image. You can see my blue t-shirt in lower part of image, and my face in the upper one.

接下来是转换的代码。 NV12 和 YUY2 转换使用 libswscale 执行,而 IYUV 和 YV12 则手动执行。

int pixels = _outputFrame->width * _outputFrame->height;
if (_outputFormat == "YUY2") {
    int stride = _outputFrame->width * 2;
    sws_scale(_convertCtx, _outputFrame->data, _outputFrame->linesize, 0, _outputFrame->height, &out, &stride);
}
else if (_outputFormat == "NV12") {
    int stride[] = { _outputFrame->width, _outputFrame->width };
    uint8_t * dst[] = { out, out + pixels };
    sws_scale(_convertCtx, _outputFrame->data, _outputFrame->linesize, 0, _outputFrame->height, dst, stride);
}
else if (_outputFormat == "IYUV") { // clean ffmpeg padding
    for (int i = 0; i < _outputFrame->height; i++) // copy Y
        memcpy(out + i * _outputFrame->width, _outputFrame->data[0] + i * _outputFrame->linesize[0] , _outputFrame->width);
    for (int i = 0; i < _outputFrame->height / 2; i++) // copy U
        memcpy(out + pixels + i * _outputFrame->width / 2, _outputFrame->data[1] + i * _outputFrame->linesize[1] , _outputFrame->width / 2);            
    for (int i = 0; i < _outputFrame->height / 2; i++) // copy V
        memcpy(out + pixels + pixels/4 + i * _outputFrame->width / 2, _outputFrame->data[2] + i * _outputFrame->linesize[2] , _outputFrame->width / 2);
} 
else if (_outputFormat == "YV12") { // like IYUV, but U is inverted with V plane
    for (int i = 0; i < _outputFrame->height; i++) // copy Y
        memcpy(out + i * _outputFrame->width, _outputFrame->data[0] + i * _outputFrame->linesize[0], _outputFrame->width);
    for (int i = 0; i < _outputFrame->height / 2; i++) // copy V
        memcpy(out + pixels + i * _outputFrame->width / 2, _outputFrame->data[2] + i * _outputFrame->linesize[2], _outputFrame->width / 2);
    for (int i = 0; i < _outputFrame->height / 2; i++) // copy U
        memcpy(out + pixels + pixels / 4 + i * _outputFrame->width / 2, _outputFrame->data[1] + i * _outputFrame->linesize[1], _outputFrame->width / 2);
}

out是一个输出缓冲区。_outputFrame是libavcodec输出的AVFrame。_convertCtx初始化如下。

if (_outputFormat == "YUY2")
    _convertCtx = sws_getContext(_width, _height, AV_PIX_FMT_YUV420P,
                                 _width, _height, AV_PIX_FMT_YUYV422, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
else if (_outputFormat == "NV12")
    _convertCtx = sws_getContext(_width, _height, AV_PIX_FMT_YUV420P,
                                 _width, _height, AV_PIX_FMT_NV12, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);

问题:

  1. 手动转换是否正确?
  2. 我的假设正确吗?
  3. 前面两个答案都是肯定的,问题出在哪里?尤其是...
  4. 为什么它只显示某些分辨率而不显示其他分辨率?
  5. 我可以提供哪些额外信息?

None

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

libavcodec/swscale 的输出损坏,具体取决于分辨率 的相关文章

  • C++:创建一个由用户输入大小的数组

    我想知道我们是否可以创建一个具有用户指定大小的数组 Ex int a cout lt lt Enter desired size of the array cin gt gt a int array a 上面的程序将不起作用 因为数组大小必
  • 如何让 CMake 为目标安装 PDB 文件

    如何让 CMake 安装调试 Visual Studio 生成的 DLL 文件和 EXE 文件所需的配套 PDB 文件 我已经挣扎了一段时间 试图找到这个问题的一个好的答案 我现在认为我找到了一个 使用安装文件命令
  • 改变 RGB 颜色的色调

    我正在尝试编写一个函数来改变 RGB 颜色的色调 具体来说 我在 iOS 应用程序中使用它 但数学是通用的 下图显示了 R G 和 B 值如何随色调变化 看起来 编写一个函数来改变色调似乎应该是一个相对简单的事情 而不需要对不同的颜色格式进
  • 我是否必须使用我的数据库训练 Viola-Jones 算法才能获得准确的结果?

    我尝试提取面部数据库的面部特征 但我认识到 Viola Jones 算法在两种情况下效果不佳 当我尝试单独检测眼睛时 当我尝试检测嘴巴时 运作不佳 检测图像的不同部分 例如眼睛或嘴巴 或者有时会检测到其中几个 这是不可能的情况 我使用的图像
  • c++1y 模式下的 Clang >= 3.3 无法解析 标头

    我有一个项目可以在 g 4 8 1 和 c 11 模式下 clang gt 3 3 下正确编译和运行 然而 当我切换到实验时 std c 1y模式下 clang 3 3 但不是 g 在
  • 如何将文本框中删除的字符替换为0

    在winforms中 如何用零替换删除的字符 例如 文本框中为 12 45 如果我们删除小数点后 它应该变成12 00 同样的方法删除前面的000 45 默认值应为 000 00 Use a 蒙版文本框 http msdn microsof
  • ReportViewer“缺少 URL 参数:名称”

    在一个网络应用程序中 我正在处理 ReportViewer 时不断出现错误 缺少 URL 参数 名称 我找到了原因 但没有找到解决方案 导致报告查看器出现异常的 url Reserved ReportViewerWebControl axd
  • 字符串中unicode字符的正则表达式

    我正在使用 C 进行一些 OCR 工作 并提取了我需要使用的文本 现在我需要使用正则表达式解析一行 string checkNum string routingNum string accountNum Regex regEx new Re
  • 如何将整个流读入 std::string ?

    我正在尝试将整个流 多行 读入字符串中 我正在使用这段代码 它有效 但它冒犯了我的风格感 当然有更简单的方法吗 也许使用字符串流 void Obj loadFromStream std istream stream std string s
  • 树结构的序列化/反序列化

    我试图找出保存 序列化 并稍后打开 反序列化 树结构的最佳方法 我的结构由具有不同属性的各种对象类型组成 但每个对象类型都继承自基本抽象 Node 类 每个节点都有唯一的 ID GUID 并且有一个 AddSuperNode Node nd
  • 最好的 C++ 编译器是哪个? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何在 Datagridview 中为图像列提供超链接

    如何在winforms中超链接到DataGridViewImageColumn OP 评论中的代码示例 DataGridView dgv new DataGridView dgv Name dgv i dgv DataSource dsMa
  • 让 AutoMapper 自动映射前缀属性

    我希望 AutoMapper 自动映射成员 如下所示 class Model public int ModelId get set class ModelDto public int Id get set 在这里 我会做一个 CreateM
  • C memcpy 二维数组

    我正在尝试使用将一个二维数组复制到另一个memcpy 我的代码 include
  • 为什么 `boost::any` 比 `void*` 更好?

    有什么先天优势boost any and boost any cast提供超过使用void and dynamic cast 优点是boost any比类型安全得多void E g int i 5 void p i static cast
  • 同时重新排序和旋转图像的高效方法

    为了快速加载 jpeg 我为turbojpeg 实现了一个 mex wrapper 以有效地将 大 jpeg 读入 MATLAB 对于 4000x3000px 的图像 实际解码只需要大约 120 毫秒 而不是 5 毫秒 然而 像素顺序是 R
  • 在C中更改函数内的数组

    我正在学习 C 并且很困惑为什么在 main 中创建的数组不会在函数内部更改 我假设传递的数组是一个指针 并且更改指针应该更改数组 对吧 有人可以解释这种情况下发生了什么吗 谢谢你的帮助 int main int i length 10 i
  • C# 中 WinForm TextBox 中数字的按键事件

    我想限制用户在文本框中仅输入数字 我在按键事件中添加此代码 private void txtPartID KeyPress object sender KeyPressEventArgs e if e KeyChar gt 0 e KeyC
  • 如何将 MouseDown 事件放入样式中?

    这有效 XAML
  • win32 内容已更改,但除非移动窗口,否则不会显示更新

    我的 win32 GUI 内容每秒都会更改 但除非手动移动窗口 否则不会显示更新 我尝试每秒弹出一个消息框来触发窗口刷新 它成功了 因此 这证明我的内容确实发生了变化 但窗口没有更新 我希望刷新窗口而不是每次都弹出消息框 有没有这样的窗口功

随机推荐