周末时候看到一篇推送说 FFmpeg 升级到 5.0 版本了。
其中提到 FFmpeg 引入了 Vulkan 驱动的新滤镜,用于视频水平、垂直翻转。
看到 FFmpeg 引入了 Vulkan ,想着这是要有什么大动作啊,直接利好 Vulkan 嘛?
后来又仔细看了下 FFmpeg 的 Changelog ,原来早在 4.3 版本就已经开始支持 Vulkan 了。
那时候就已经有滤镜支持了,比如 scale_vulkan、chromaber_vulkan 等。
而且还支持在 Linux 平台上通过 Vulkan 使用 AMD 的高级媒体框架(AMF)库,可以用 GPU 来进行 H.264/HEVC 的编码。(Windows 平台用的是 DirectX 接口)
这里提一下 AMF 框架,实际上我也是第一次接触这个。
AMF 全称是 Advanced Media Framework ,翻译为高级媒体框架。它是 AMD 公司出品的,为开发人员提供对 GPU 的访问以进行多媒体处理,通过 AMF 可以进行视频编解码、转码、色彩空间转换等功能。
简单说就是提供了对自家显卡产品能力的调用,可以用它来做编解码的工作。既然 AMD 有了,那么相信 NVIDIA 也有类似的产品。
由此可见后面的趋势:渲染 API 不仅仅是用来做渲染,还是可以用做编解码的,毕竟它是可以直接用 GPU 打交道的。
所以 FFmpeg 5.0 中引入了 Vulkan 新滤镜应该也不是什么大新闻了,毕竟在 4.3 版本就已经有了支持,只是多了几个滤镜,按照开发人员的话来说,就是多了几个 shader 嘛。
接下来就看看这几个新增的 翻转shader 有何不同之处:
如果不了解 Vulkan 流程的话,建议看看 Vulkan 相关的文章,毕竟这里面概念挺多的,但很多流程还是固定的,只要抓到重点就好了。
大概的流程:Vulkan 作为 FFmpeg 中的一个滤镜,那么它肯定要接收代表解码后的 AVFrame 数据,通过将 AVFrame 数据转换为它渲染链结构的输入,经过渲染后,将渲染结果转换为 AVFrame 数据并往下进行传递。
理解上面的流程,剩下的就是去理解 Vulkan 的渲染链了。
核心代码如下:
static int process_frames(AVFilterContext *avctx, AVFrame *outframe, AVFrame *inframe)
{
// 省略起始代码
// 得到输入数据
AVVkFrame *in = (AVVkFrame *)inframe->data[0];
AVVkFrame *out = (AVVkFrame *)outframe->data[0];
const int planes = av_pix_fmt_count_planes(s->vkctx.output_format);
const VkFormat *input_formats = av_vkfmt_from_pixfmt(s->vkctx.input_format);
const VkFormat *output_formats = av_vkfmt_from_pixfmt(s->vkctx.output_format);
ff_vk_start_exec_recording(vkctx, s->exec);
cmd_buf = ff_vk_get_exec_buf(s->exec);
for (int i = 0; i < planes; i++) {
// 将输入数据绑定到 ImageView 上
RET(ff_vk_create_imageview(vkctx, s->exec,
&s->input_images[i].imageView, in->img[i],
input_formats[i],
ff_comp_identity_map));
RET(ff_vk_create_imageview(vkctx, s->exec,
&s->output_images[i].imageView, out->img[i],
output_formats[i],
ff_comp_identity_map));
s->input_images[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
s->output_images[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
}
// 绑定资源描述符
ff_vk_update_descriptor_set(vkctx, s->pl, 0);
// 设置好内存屏障
for (int i = 0; i < planes; i++) {
// 省略一大串代码
vk->CmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0,
0, NULL, 0, NULL, FF_ARRAY_ELEMS(barriers), barriers);
// 省略一大串代码
}
// 设置好 pipeline 和 资源描述符集 descriptorSet
ff_vk_bind_pipeline_exec(vkctx, s->exec, s->pl);
vk->CmdDispatch(cmd_buf, FFALIGN(s->vkctx.output_width, CGS)/CGS,
s->vkctx.output_height, 1);
ff_vk_add_exec_dep(vkctx, s->exec, inframe, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
ff_vk_add_exec_dep(vkctx, s->exec, outframe, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
// 提交到队列
err = ff_vk_submit_exec_queue(vkctx, s->exec);
if (err)
return err;
ff_vk_qf_rotate(&s->qf);
return 0;
}
以上代码要是看的费劲的话,还是只看核心的 shader 部分吧:
可以看出,做水平或者垂直翻转也只是更改了 texture 采样坐标而已,如果你会 OpenGL 的话,一样可以做出类似的 filter 。
知识星球
公众号音视频开发进阶对应的知识星球,一个编程开发领域的专业圈子,贩卖知识和技巧! ※ 入群须知:了解该星球能提供的价值和帮助,在提问时务必阐述好背景,附带相关的信息。 iOS 用户可以加我微信 ezglumes 邀请你进星球,有疑问也可以加我微信咨询。 ※ 星球内容: 基础教程: 在知识星球连载的干货教程,可以在专栏中找到,随着时间的推移,教程也会越来越多: - 音视频基础概念 - WebRTC 入门教程及源码实践 - 播放器教程及源码实践 - OpenGL 和特效开发教程 - Vulkan 入门教程 部分内容可以在博客 https://glumes.com 中检索到,后面会在星球里持续更新. 干货分享: 涵盖了移动开发和音视频工程领域的绝大部分,从项目实战角度出发,提升能力,包括但不限于以下领域: - Android/iOS 移动开发 - Camera 开发 - 短视频编辑 SDK 项目实践 - 在线直播和推流 - WebRTC 开发 - 播放器基础和提高 - OpenGL 图像渲染及特效开发 - C++ 基础和提高 - FFmpeg 使用和分析 - 干货资源和书籍分享 不止于技术方面的,各种 IT 新闻、茶余饭后、生活趣事也欢迎大家分享!!! 技术答疑解惑: 针对上述基础教程和干货分享的答疑,另外还有音视频和 IT 开发中的各种交流讨论。 - 基础知识点答疑 - 工业项目实践答疑 - 问题排查思路分析 一个 BUG 排查很久,不如来星球里提个问题,效率提升百倍。 求职和面试辅导: 一站式职场服务,每份工作都值得用心对待!!! - 面试题和面试经验分享 - 简历修改和模拟面试 - 大厂内推和信息同步 - 职场经验分享 - 职业规划和发展分析 ※ 星主和合伙人介绍 星主是公众号音视频开发进阶的作者,也是网站 https://glumes.com 的作者,曾参与过抖音、剪映等头部音视频 APP 底层 SDK 的开发。 合伙人也是在头条、快手从事音视频架构师的职位,具有多年的音视频开发经验,能力圈覆盖了音视频的绝大多数领域,资深音视频从业人员为你保驾护航。
微信公众号
扫描下面的二维码关注我的微信公众号《音视频开发进阶》,推送更多精彩内容!
添加我的微信 ezglumes 拉你入音视频与图形图像技术群一起交流学习~

原创文章,转载请注明来源: Vulkan 在 FFmpeg 中的支持