视频切片并行加速
背景
在实际业务中,视频处理,大都时候都挺费时的。例如:以下表格是,某中算法,在不同分辨率、帧率下的,cpu计算耗时体系(不包括:上传、下载的耗时):
分辨率 | 帧数 | 处理时长 / 视频时长 |
---|---|---|
720p | 30帧 | 2 |
720p | 60帧 | 4 |
1080p | 30帧 | 3 |
1080p | 60帧 | 6 |
2k | 30帧 | 3.5 |
2k | 60帧 | 8 |
4k | 30帧 | 7 |
4k | 60帧 | 20 |
另外,一般情况下,视频越长,所占用的cpu or gpu,也就越久。如此有以下弊端:
1、对于用户而言,耗时久,体验非常不好,有可能直接放弃了。
2、很容易造成资源负载不均,例如:有些机器比较倒霉,每次分配的都是:长视频(5min以上),有些机器比较luck,分配的大都都是:短视频(30s以内)
3、超过1h的视频,单台物理机,基本上不太可能能够处理完毕,姑且不谈cpu,内存都有可能爆满。
视频处理
这里面的视频处理,可以是:libx264转码、libx265转码、超分、ai绘画、去除水印、人像增强、去模糊、去躁点等等。
思路梳理
资源扩容
例如:某一个算法,目前部署在:8核cpu上,可逐步调大cpu 核数 + 内存大小,当然了,资源也是有限的,扩大到一定核数后,并不能100%能解决问题,另外,成本也是一个大问题。
硬件升级
假设不差钱,可以考虑上:更强型号的cpu or 更强型号的gpu,例如:大型机 or GPU:RTX
4090,可惜,有时候,就算是上了最强的CPU,在面对:长视频 + 高帧率 + 高分辨率的情况下,也有力不从心的时候。
算法优化
深入算法处理的底层原理,分析处理过程,降低算法复杂度:
1、能够并行计算的,尽量并行计算,充分压榨cpu or gpu资源。让cpu利用率常态超过50%以上,而不是偶尔能达到,其实是挺有挑战的。
2、目前很多算法 or 模型,在计算视频时,是将视频解封装到帧,然后,逐帧计算处理,是否可以再次优化呢?
并行计算
除了单进程内部开启并行计算外,其实也可以考虑:单机多进程并行计算,集群多进行并行计算,具体而言:将:长视频、高帧率、高分辨率的视频切成多个小视频,然后,集群调度,并行计算各个小视频,最后将它们的结果合并起来,从而得到原先视频的计算结果,
其整体过程如下:
1、切片:分解(Divide)将一个大视频切成多个小视频。
2、并行:集群并行调度:处理这些片段。
3、合并:将这些片段的结果合并起来,以获得整体的结果。
注意:注意:能够进行以上计算的前提条件是:片段与片段之间,无相关性,或者,可以通过某种手段,将各个片段降维到无相关性。
为啥能加速?
能够加速的原因 | 重要程度 | 说明 | 备注 |
---|---|---|---|
切 -> 并 -> 合,强依赖于:并行调度 | top 0 | 单个视频的所有切片并行计算,子任务之间并发执行,尽量不要排队等待。。并发度 = 并发执行的任务数 / 总的任务数 | |
GPU池子 与cpu池子的合理配比 | top 0 | 1、如果cpu池子中核数不够多,例如:<= 10核,那么大概率起不到加速效果。 2、如果gpu池子的卡数不够多 or 调度太慢,例如:一个算法只能调度到一张卡,那么,也起不到加速效果 |
|
切片策略:合理设置各个阶段算法参数,确保处理后的结果正常 | top 0 | 切片加速策略 | |
开启切片的条件:视频时长 | top 1 | 通用策略:如果视频时长 <= 1min,触发加速有可能会适得其反,费资源,又更慢(毕竟:切、合是有成本的)。 当然了,不同算法,这个阈值,有可能会不一样,需灵活对待。 不同分辨率 + 不同格式的视频等,是否有这一规律,目前待定,并未找到规律。 |
解决方案
如上所述,将重点探讨:切片加速的相关方案。大体过程,如下图所示:
备注:
1、上述过程要求:片与片之间,没有关联性,然后,并行处理,来提高处理速度 + 降低对硬件的需求。
2、在实际业务中,片与片之间,并非100%无关联,片段之间存在上下文的关联性。其解决思路之一:分析下关联性有什么特点,然后,将这个关联性降维到无关联性。例如:某一算法的加速流程如下图所示:
注意:以上整体流程,由:切 -> 并 -> 合,变成:切 -> 切 -> 合 -> 并 -> 合。
3、一般音频处理比较快,因此,切并合,只针对视频,不针对音频。因此,直接并行触发:音频转码。
4、如果需要在切片中处理:色偏 + 格式等问题,则需要开启切片转码,此时,建议:并行化,类似分片转码。
5、”处理”,需并行处理,这是能够提速的关键。
模块抽象
模块 | 功能定位 | 是否连db | 是否上传 or 下载 | 并发度 |
---|---|---|---|---|
总控集群 | 切片策略、算法编排、任务重试、任务取消、优先级调度等 | 是 | 否 | 高,单个pod基本上要达到300QPS以上(8核cpu,经验值) |
计算集群 | 原子化cpu、gpu计算,负责:算 | 否 | 是 | 低,单个pod一般处理:2个以内的视频 or 5个以内的图片(经验值) |
总控进程
功能 | 重要性 | 说明 | 备注 |
---|---|---|---|
切片策略 | top 0 | 描述一个视频该怎么切片,按帧切?还是按视频时长切? | |
算法编排 | top 1 | 切片、音频提取、视频合并、音视合并等各个阶段编排在一起,整体流程 | |
任务重试 | top 0 | 理论上,该任务可以重试,重新触发计算,不影响结果 | |
check bill | top 1 | 任务卡死、节点卡死时,如何触发继续流转下去?如何通知业务方? |
task、event、segment、trace
名词 | 解释 | 关系 | 说明 | 备注 |
---|---|---|---|---|
task | 任务 | 一次请求,对应一笔任务 | 一笔切片请求,对应一笔任务 | 可使用UUID生成唯一的:task_id |
event | 事件 | task 与event 是一对多的关系 | 一个dag节点,对应一个事件 | event_id = task_id + “_” + node_name |
segment | 片 | event 与 segment 是一对多的关系 | 一个视频片,对应一个event | segment_id = event_id + “_” + order |
trace | 跟踪 | trace 与 event、segment 是一对多的关系 | 一次cpu、gpu计算,对应一次trace | 可使用UUID生成唯一的:trace_id |
音频剥离
依赖算法:libfdk_aac or aac,将音频从原始视频中剥离开来,例如:ffmpeg命令如下:
1 | ffmpeg -i source.mp4 -vn -y -acodec libfdk_aac -copyts output.aac -loglevel error |
为啥要音频提取并且重新转码?
1、一般情况下,音频比较小,计算量比较小,可单独并行处理,因此,将音频流提取出来,能够:减少视频处理过程的IO + 减少:cpu、gpu计算量。
2、用户输入的视频,格式千变万化,很多视频无法直接通过:-acodec
copy。若直接将音频提取出来会发生:奇奇怪怪的错误。因此,统一将音频流转码,统一音频格式。另外,需:-copyts的保留原始音频的PTS信息。
3、有些视频天然没有音频,因此,在处理前,需判断原始视频是否有音频,若有,再触发:音频提取流程,否则:直接触发视频切片。
视频侦测:meta信息提取
1、显示“流”的全局属性:
- 显示的是流级信息,每个流(视频、音频、字幕等)只有一条记录。
- 提供整体的技术参数,例如编解码器、分辨率、码率、帧率、采样率等。
- 适用于快速查看媒体文件的基本属性和整体结构。
1 | ffprobe -v quiet -print_format json -show_format -show_streams -loglevel error {path} |
2、显示“帧”的全局信息
- 显示的是帧级信息,每一帧(视频帧、音频帧)都有详细记录。
- 包含帧的时间戳(如 pts_time)、帧类型(I、P、B 帧)、时长、关键帧标识等详细数据。
- 适用于需要分析视频细节(例如精确剪辑、帧检测等)时使用,因为它输出的数据量通常非常大。
1 | ffprobe -select_streams v -show_frames -print_format json {path} |
1、以上两条命令中的:{path}可以是本地路径,也可以是url,如果视频必须要下载到本地,则使用本地路径,否则:更建议使用url。
2、以上两条命令是对输入视频进行画像,以便决策:它是否能够进行切片加速?以及相关的切片策略?
指标 | 说明 | 备注 |
---|---|---|
码率 | 码率太低 or 码率太高,需要设置不同的码率策略 | 可行 |
帧率 | 可行 | |
分辨率 | 480p、540、720、1080、2k、4k | |
负数帧 | ||
部分帧的pts都是一模一样的 | ||
色域 | 当前视频的色域格式 | |
编码格式 | h264、h265、h266、avi等 |
视频切片
功能 | 说明 | 是否可行 | 业界是否有 |
---|---|---|---|
按照gop关键帧切 | 输入视频时长,快速分割出一坨的视频文件 | 可行 | 有 |
按帧索引切 | 将原始视频的帧解封装,然后,使用libx264 or libx265重新压缩 | 可行 | 暂无 |
视频解码成图片 | 将原始视频里的帧解码成图片,然后,直接基于图片并行处理 | 暂不可行,图片太多,并发度太大,网络带宽扛不住 | 暂无 |
当然了,视频如何切,需要考虑:底层算法,
1、有些算法,需要预留一些buffer帧进行预热,才能确保切片后的视频画质,能够不输于:不切片时的结果视频画质。
这种buffer帧策略,分为:前向重叠帧策略、后置重叠帧策略、双向重叠帧策略、无重叠帧。
2、有些算法,例如:消除某段视频里的某个物体,片与片之间存在上下文的相关性,此时,切片时,要将该物体所对应的帧序列,单独切出来,然后,合并到各个片上去,将所有片降维到:无关联性。
3、切片时,最好不要保留原始视频的PTS,也就是:切片时,将所有片的PTS都重置成0。因为:多个步骤的编解码,无法100%保留原始视频的PTS值。
4、切片时,重叠的一些帧,在后续步骤中,需去除掉。
另外:1、按照视频时长切片,参考的ffmepg命令:
1 | ffmpeg -i input.mp4 -c copy -map 0 -segment_time 10 -f segment output_%03d.mp4 |
假设需要实现:重叠帧 or 预热帧的功能,则
2、使用cv2:pip install opencv-python ffmpeg-python 按照帧索引切:参考代码如下:
1 | def slice_and_combine_video(input_video_path, output_video_path, frame_start, frame_end): |
并行处理
算法 | 片与片之间 | 是否支持切片 | 说明 | 备注 |
---|---|---|---|---|
libx264 | 不相关 | 支持 | ||
libx265 | 不相关 | 支持 | ||
去水印 | 不相关 | 支持 | ||
去字幕 | 不相关 | 支持 | ||
去某个物体 | 有点相关 | 可降维到不相关,支持 | ||
文生图 | 强相关 | 调研突破中 | ||
文生视频 | 强相关 | 调研突破中 | ||
图生视频 | 弱相关 | 支持 |
无论是哪种算法,都需要对输入视频进行解封装 + 重新编解码,因此,如果切片时有预留一些帧做buffer等操作,一般都在:并行处理中,去除这些buffer帧。
因此,底层算法,需要支持:remove_frames:[start_frames,end_frames]、[start_gop,end_gop]
视频合并
算法并行处理完毕后,能够得出一坨的算法处理后的视频片段,收集到这些片段后,将这些片段合并,即能得到一个完整的、处理后的视频。例如:参考ffmpeg命令:
1 | ffmpeg -f concat -safe 0 -i {0} -i {1} -c copy -output_ts_offset {2} -movflags faststart {3} -loglevel error |
注意:输入的各个片段的PTS,已重置过 + 算法重新编解码过,因此,需要在这边做:视频PTS对齐操作。否则,极容易导致:音画不同步的问题。
音视合并
最后一步,将音频流 + 视频流合并,使用如下:ffmepg命令,即可正常合并。
1 | ffmpeg -i {0} -i {1} -copyts -c:v copy -c:a aac -map_metadata 0 -strict experimental -movflags faststart {2} -loglevel error |
备注:
1、-c:v copy 本身不会主动增加零帧,但如果首帧 PTS 不为 0,FFmpeg 可能会调整时间戳或插入一个“零帧”以保证 PTS 归 0,尤其是在
MP4 等格式中。使用 -copyt -map_metadata 0s 选项可以保留原始时间戳,防止 PTS 归 0 造成的影响。
2、-map_metadata 0,请确保:{0}为视频,另外,也是为了将视频流的部分meta信息输出到结果视频中。
算法编排
如本文中切片加速
图片所示:整个过程,可以硬编代码写死,也可以使用dag引擎来编排,详细内容,可参考章节:任务编排
,这里不再赘述。
资源调度
包括:多云调度、cpu集群与gpu集群协调、自动扩缩容等等,这些将在章节:资源调度,重点描述,这里不再赘述。
cb体系
如本文中切片加速 包括的图片所示,由于中间各个步骤,包括了大量的:cpu or
gpu计算服务,比较容易导致:算法奔溃,卡死,导致总控进程长时间未收到回调,因此,需要总控进程触发check 任务状态,假设超过一定的时间阈值,重试
or 设置整个任务为失败。
监控指标
压缩比
压缩比 = 输出视频文件大小 / 输入视频的文件大小
成本
小文件存储成本
类别 | 说明 | 存储规格 | 生命周期 | 备注 |
---|---|---|---|---|
原视频 | 存放在桶1 | 推荐:3天内,标准存储,超出:自动降档 | 按照业务场景定,例如:3天内,自动归档 | |
结果视频 | 存放在桶2 | 推荐:21天内,标准存储,超出:自动清理 | 按照业务场景定,例如:21天,标准存储,之后自动清理 | |
中间片段 | 存放在桶3 | 单副本即可 | 按照业务场景定,建议1天后,自动清理 |
备注:
1、强烈建议:原始视频 + 结果视频 + 中间片段,存放在3个桶里,或者:至少3个文件夹里,单独根据业务场景设置生命周期规则,例如:小文件存储提供的特性,自动清理
2、上述:推荐的存储规格,只是一种建议。真实落地时,得根据实际项目的运行情况来。
性能与成本均衡
经过实测,切片能够加速,能够加速:处理时长/视频时长 ≈ 0.5左右,但是,切片成本 / 不切片成本 = 1.1,视不同算法而定。
因此,是否所有视频都开启切片?答案:否定的,得根据实际情况来定,例如:超过1min的视频,才开启切片加速。
另外,cpu集群与gpu集群,可以考虑混部,
存储集群 + 计算集群,可以考虑:单元化部署,当然了,还是遵守:存算一体原则。
问题
图片处理是否需要切片并行?
图片处理,一般比较快,如果遇到慢的问题,可通过:扩容资源的方式来处理,暂时无法进行:切片并行的策略。
当然了,图片分块后,块与块之间,都有相关性,暂时无法做到:并行化。
色偏
切片与并行算法处理,均需要考虑:色偏问题,重点是:做好色域映射。
音轨、视轨无法对齐
视频PTS对齐 + 音频PTS对齐