自研点直播转码核心

1. 背景

视频转码是将视频文件经过解封装、解码、滤镜处理、编码、封装从而转换为另一个视频文件的过程,B站每天都有大量的视频原片上传后经过转码系统转换为多个不同分辨率。转换后的视频在画质接近原片的前提下会拥有更低的码率,因此会提高网络传输时的流畅性并节省带宽;同时,形形色色的视频原片经过转码后会生成为较为统一、规范的编码规格,也大幅提升了播放时的设备兼容性。

目前业界使用最多的服务端视频转码框架是FFmpeg,它可以处理几乎所有格式的多媒体文件。FFmpeg的转码核心组件是实现了封装/解封装、编解码、滤镜、算法原子能力的基础库,同时,FFmpeg也提供了可以直接运行的命令行工具ffmpeg,实现了简单的转码流水线逻辑。

图片

ffmpeg7之前的串行流水线

随着转码业务的扩展,原生的ffmpeg命令行工具也暴露出了很多局限性:

  • 在多清晰度转码时,因为流水线是串行的(*FFmpeg7.0前),在音频编码、复杂滤镜场景,对点播无法最大化利用多核cpu的优势,对直播可能会让各清晰度编码互相阻塞。

  • 在直播这种长时间持续转码场景下,无法通过交互动态更新转码参数

  • 所有转码流水线控制逻辑基本都塞在了5个.c文件里,模块划分不清晰,修改/维护成本很高

  • FFmpeg版本升级时,代码迁移难度高

因此,考虑转码业务的扩展,需要进行转码核心的自研,替换ffmpeg命令行工具。

2.  自研转码核心架构

如下图所示,自研转码核心采用FFmpeg基础库作为底层的多媒体处理原子能力,对转码流水线的各模块进行了抽象,对点直播不同的业务需求,衍生出不同的子类进行处理;Controller模块是转码的核心模块,负责所有流水线的帧调度逻辑,同样对点直播做了区分。点播业务的调度逻辑相对简单,主要包含了输入流-输出流的映射关系;而直播业务包含了导播台的定时取帧逻辑,以及消息交互逻辑(转码过程中动态更换输入、输出、滤镜等),逻辑比较复杂。

图片

下图为一个两路清晰度转码对应的转码核心的模块架构图,流水线A和流水线B各视作一条Pipeline,一条Pipeline会对应一份转码产物;单个Pipeline内的单条音视频流对应的处理流程视作一条Flow;一条Flow内部的每个滤镜/编码/采样/封装操作视作一个Task。

图片

转码核心运行过程中,上层业务可以随时下发动态指令,对转码的输入、输出及整条pipeline进行增删,这个功能在直播转码中,可以大幅提高转码流的启播速度:用户断流重推后,上行节点发生变更后,业务层可以在不重启容器的情况下,通过动态指令删除转码的输入与输出,再更新为新的上行、下行节点,可以节省100%的转码拉起时间,提高推流端断流重推后的转码清晰度的覆盖。

图片

3.  模块级可控串/并行流水线

在点直播不同的场景,对转码流水线的流程控制有着不同要求,自研转码核心的每个Task类,继承了相同的基类PipelineWorker,可以自由选择以串行/并行的方式运行,并行模式的Worker会开启一个单独的线程进行帧的处理。

Task的串/并行调度策略依赖于业务需求和Task内部的并行度。

图片

3.1 直播转码

直播转码因为对实时性要求很高,转码过程滤镜、编码、输出网络IO都是可能发生阻塞的模块,如果使用串行流水线,发生卡顿的风险很大,尤其是在一入多出的场景下,多个pipeline会互相阻塞;这也是为什么FFmpeg7.0前,不适合直接用于直播转码。开启并行模式后,Task会在内部队列达到阈值后触发丢帧,尽可能保证转码流的稳定。

3.2 点播转码

点播转码场景更看重转码性能,需要根据Task特性决定采用串行/并行模式:如果Task内部实现并行度低,使用并行模式可以增加cpu利用率,发挥线上容器多核优势;如果Task内部本身并行度较高或者逻辑过于简单,使用并行模式反而会让性能因为增加线程切换产生劣化。

4.  动态自适应转码

在直播转码场景,由于采用了flv封装格式+rtmp协议,直播源流可能在推流过程中随时改变分辨率、帧率等规格,这需要转码核心具备转码参数动态自适应的能力。

4.1 分辨率自适应

随着直播多人连麦业务的铺开,线上有越来越多的变分辨率直播流,flv格式可以通过刷新sequence header任意更新编码规格,而转码在感知到分辨率变化后,需要滤镜、编码、封装模块联动来保证转码流分辨率的正常刷新:

图片

下图为不同宽高比的输入流,经过转码缩放(scale)滤镜后的宽高参数变化逻辑,采用了维持原始宽高比的zoom缩放:

图片

滤镜组的参数自适应是一个难处理的点,因为滤镜种类繁多,参数和输入宽高的对应关系也不同,比如缩放滤镜scale只有目标宽高两个参数,只和输入帧的宽高比有关;而滤镜叠加有水印宽高、叠加坐标参数,计算起来就更复杂。因此我们复用了ffmpeg的表达式功能,业务层可以用占位符、已定义输入变量、表达式来使滤镜参数动态适应输入规格,而转码核心也只需要维护一套参数自适应规则即可覆盖几乎所有滤镜。

4.2 帧率自适应

大多数PC开播工具在推流时都会保持帧率固定,但是对移动端开播的用户,开播工具可能会根据网络情况在某个范围动态调整帧率,变化的帧率对帧采样逻辑提出了挑战。

目前视频帧采样算法有CFR(固定帧率)和VFR(变帧率)两种,针对直播变帧率场景,直播转码选择用VFR代替常用的CFR采样。主要是因为CFR算法在当前场景不够灵活,暴露出一些问题:

  • 当使用固定的60/30fps规格进行CFR采样时,如果输入是50/25这种无法被60/30整除的帧率,会导致不均匀拷贝/丢帧,产生卡的感觉(见下图)

  • 当使用输入流的初始帧率和目标帧率的最小值进行CFR采样时,如果源流中途帧率升高,会导致不应该丢弃的帧被丢弃,也会让播放相对于源流变卡了;如果源流中途帧率降低,会产生多余的拷贝帧,造成编码资源及码率的浪费。

图片

图片

使用VFR采样,当源流帧率大于设定帧率时,也会出现采样不均匀的情况(见上二图),为此,我们增加了VFR-HALF采样方式,会在源流fps满足一定条件时命中。如果当源流帧率为50而目标帧率是30的情况下,会将实际目标帧率调整为25(二采一),以保证采样画面的均匀,这也是youtube点播采用的方法。

5.  码流附加信息管理

码流附加信息主要是指码流中独立于帧压缩数据之外的数据,在avc编码中指sei信息。目前B站点直播业务均会依赖sei信息的处理能力。直播答题、跨年晚会的指尖游戏都是通过sei信息实现的,点播的HDR视频,也会用到sei中的调色信息。

ffmpeg命令行工具对sei信息的处理一直比较保守,在ffmpeg5以前,ffmpeg会在解码时直接丢弃sei信息;ffmpeg5以后,ffmpeg会将解码后的sei信息保存在frame结构里,虽然有sei信息写入的能力,但写入能力全部由对应的编码器来完成。

ffmpeg的sei处理逻辑因为强行绑定了编码器的内部实现,在当前自研+gpu+异构转码混合使用的场景下,无法覆盖所有的编码器且无法保证所有编码器写入方式的一致性。自研转码内核调整了sei的写入时机,在编码后增加了bsf滤镜统一处理所有avc/hevc/av1 sei的写入,在视频帧采样时也会根据业务配置,判断丢弃/合并弃帧的sei信息。

图片

在直播转码中,我们也会使用sei记录转码流生产的整个生命周期。通过播端拿到的对应sei信息,可以准确分析出码流从推流端直播姬开始到用户链路上的各生产节点的延迟和其他核心指标,为指标优化提供数据支持。

6.  总结与展望

自研转码核心的开发初衷是覆盖ffmpeg命令行难以实现的业务场景,而随着业务需求越来越多元,自研转码核心的应用场景也越来越多。自2020年首次应用于直播导播台业务,自研转码核心已经覆盖了导播台业务、直播转码业务,目前正在逐步覆盖点播转码。

后续我们会继续聚焦在提升用户体验以及提升转码系统效率这两个目标上面:

  • 之前我们已经和公司的AI、画质团队合作,完成了AI直播字幕、游戏赛事看板等功能的开发,后续我们也会接入AI相关更多的新功能、玩法到点直播转码中。

  • 自研转码核心在点播流式转码的灰度过程中,已经展现出了比较明显的性能提升;后续我们会更细粒度地优化流水线串并行策略,将机器资源利用到极致。

-End-

作者丨DogHunter

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3266808.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

未来的智能农业:智能合约如何提升农业生产效率和可持续性

随着全球人口的增长和资源的有限性,农业生产面临着越来越大的挑战。如何在提高生产效率的同时保障可持续发展成为全球农业发展的关键问题。智能合约作为一种基于区块链技术的自动化执行合约,正在逐渐应用于农业领域,为农业生产带来了新的机遇…

Leetcode刷题-----移动零283复写零问题1089

目录 1.问题介绍 1.1题目要求 1.2思路分析 1.3想法实现 2.复写零问题 2.1问题分析 2.2思路分析 2.3想法实现 1.问题介绍 1.1题目要求 把这个数组里面为0的元素挪动到这个数组的后面,其他的非零元素的相对位置保持不变; 1.2思路分析 这个里面&a…

甄选范文“论软件测试中缺陷管理及其应用”软考高级论文,系统架构设计师论文

论文真题 软件缺陷指的是计算机软件或程序中存在的某种破坏正常运行能力的问题、错误,或者隐藏的功能缺陷。缺陷的存在会导致软件产品在某种程度上不能满足用户的需要。在目前的软件开发过程中,缺陷是不可避免的。软件测试是发现缺陷的主要手段,其核心目标就是尽可能多地找…

场外期权如何报价?名义本金是什么?

今天带你了解场外期权如何报价?名义本金是什么?投资者首先需要挑选自己想要进行期权交易的沪深上市公司股票。选出股票后,需要将股票信息、预期的操作时间(如期限)、看涨或看跌的选择以及预计的交易金额等信息报给场外…

Cisco OSPF LSA 类型详解指南

注:机翻,未校对。 OSPF LSA Types: The Ultimate Guide OSPF LSA Types – OSPF LSA 类型 – OSPF uses LSAs or Link state Advertisements to share information of each network and populate the LSDB (Link State Database). The LSAs are used by…

ppt模板如何制作?5个工具让你事半功倍

让我瞧瞧是谁还在为寻找PPT模板而发愁? 其实这可不是什么难题~身为职场高效打工人的我,今天便特地为大家整理了5大ppt模板ai生成神器~想知道都有哪些选择吗?接着往下看你便清楚啦! ✮迅捷PPT ☺使用场景:商业演示、教…

dsp c6657 SYS/BIOS学习笔记

1 SYS/BIOS简介 SYS/BIOS是一种用于TI的DSP平台的嵌入式操作系统(RTOS)。 2 任务 2.1 任务调度 SYS/BIOS任务线程有0-31个优先级(默认0-15,优先级0被空闲线程使用,任务最低优先级为1,最高优先级为15&am…

《MySQL DBA 修炼之道》第五章 查询优化

《MySQL DBA 修炼之道》原文是在第六章 查询优化,博主觉得比较重要,所以想提前整理为一篇博文。 查询优化是研发人员比较关注也是疑问最多的领域。 基础知识 1. 查询优化的常用策略 一般的常用策略 优化数据访问、重写SQL、重新设计表、添加索引 4种…

【鸿蒙开发】鸿蒙ArkUI自定义组件如何封装一个好用的Toast/Loading/ProgressHUD组件

1. HUD 在移动端 App 开发中,Toast 、 Loading 和 Progress 是十分常用的UI控件,如果不做特殊要求,一般可以直接使用系统 API 提供的方法,但如果想要定制化 UI,就需要自定义实现了。 在 HarmonyOS 中,Toa…

Leetcode—769. 最多能完成排序的块【中等】

2024每日刷题&#xff08;149&#xff09; Leetcode—769. 最多能完成排序的块 实现代码 class Solution { public:int maxChunksToSorted(vector<int>& arr) {int ans 0;int mx INT_MIN;for(int i 0; i < arr.size(); i) {mx max(arr[i], mx);if(mx i) {a…

单GPU训练一天,Transformer在100位数字加法上就达能到99%准确率

乘法和排序也有效。 自 2017 年被提出以来&#xff0c;Transformer 已成为 AI 大模型的主流架构&#xff0c;一直稳站 C 位。 但所有研究者都不得不承认的是&#xff0c;Transformer 在算数任务中表现非常糟糕&#xff0c;尤其是加法&#xff0c;这一缺陷在很大程度上源于 Tra…

python毕业设计选题求职招聘系统-可视化大屏

✌网站介绍&#xff1a;✌10年项目辅导经验、专注于计算机技术领域学生项目实战辅导。 ✌服务范围&#xff1a;Java(SpringBoo/SSM)、Python、PHP、Nodejs、爬虫、数据可视化、小程序、安卓app、大数据等设计与开发。 ✌服务内容&#xff1a;免费功能设计、免费提供开题答辩P…

虚拟机配置RabbitMQ集群教程

RabbitMQ是常用的一款消息中间件&#xff0c;那么如何在我们虚拟机中创建其集群呢&#xff1f;跟着博主这篇文章让你一步到位 本篇搭建的是三台机器为一个集群&#xff01;假设大家虚拟机都为初始化状态&#xff0c;从0开始&#xff08;注意集群搭建需要CentOS8以上环境&#x…

Linux:基础

一、安装 二、 一些组件 2.1 git管理 集中式版本控制系统:版本库是集中存放在中央服务器的,需要时要先从中央服务器取得最新的版本进行修改,修改后再推送给中央服务器。集中式版本控制系统最大的毛病就是必须联网才能工作,网速慢的话影响太大。 分布式版本控制系统:分布…

Redis的使用场景——热点数据缓存

热点数据缓存 Redis的使用场景——热点数据的缓存 1.1 什么是缓存 为了把一些经常访问的数据&#xff0c;放入缓存中以减少对数据库的访问效率&#xff0c;从而减少数据库的压力&#xff0c;提高程序的性能。【在内存中存储】 1.2 缓存的原理 查询缓存中是否存在对应的数据如…

学习记录day19——数据结构 查找算法

概念 在给定数据元素的某个值&#xff0c;在查找表中确定一个其关键字等于给定值的数据元素的操作&#xff0c;叫做查找 查找的分类 顺序查找:将待查找数据&#xff0c;进行全部遍历一遍&#xff0c;直到找到要查找的元素 折半查找:每次都去除一半的查找范围的查找方式&#x…

Easy es问题总结

官网教程&#xff1a;https://www.easy-es.cn/pages/ac41f0/#settings 一 测试项目 1 pom <dependencies><!-- 排除springboot中内置的es依赖,以防和easy-es中的依赖冲突--><dependency><groupId>org.springframework.boot</groupId><artifa…

JavaScript 将网址 www. 抹去

简单好用 https://andi.cn/page/621609.html

【OpenCV C++20 学习笔记】序列化——XML和YAML文件处理

序列化——XML和YAML文件处理 序列化和反序列化代码实现XML/YAML文件的打开和关闭写入或读取文本和数字写入或读取OpenCV数据写入或读取数组以及map读取和写入自定义数据类型 输出结果 序列化和反序列化 如果希望永久保存某些对象&#xff0c;而不是每次运行程序的时候重新创建…