视频切片并行加速
背景
在实际业务中,视频处理,大都时候都挺费时的。例如:以下表格是,某中算法,在不同分辨率、帧率下的,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绘画、水印去除、人像增强、去模糊、去躁点等等。
为啥只谈视频切片?
切片并行加速,是否支持以下2个场景?
1、文生视频,可否将:文本切成多段,然后,每段并发分别生成视频,最终合成一个大视频?
2、图片切片加速处理,可否将图片按块切片,然后,并发处理每一块,最终合成一个大图片?
根据实际项目上看,暂时不行,尚需深入调研分析。
1、文生视频中的:文本是有上下文相关性的,暂时无法做到:将文本降维,变成:上下文无关性。
2、图片处理,目前性能不慢,暂时没有切片加速的需求,另外,图片按块来切,貌似也是有上下文相关性。
思路梳理
资源扩容
例如:某一个算法,目前部署在:8核cpu上,假设不差钱,或者:太紧急,就继续往上调整:16核 -> 32核 -> 64核 -> 128核等等
当然了,资源也是有限的,有时候,并非每次都能通过扩容来解决。
最强硬件技术
假设不差钱,可以考虑上:更强型号的cpu or 更强型号的gpu,例如:大型机 or
银河系列超级计算机。可惜,就算是上了最强的CPU,在面对:长视频 + 高帧率 +
高分辨率的情况下,也有力不从心的时候。
并行计算策略
遇到长视频、高帧率、高分辨率的视频,处理慢时,可以考虑将视频切成多个小视频,然后,并行地处理:小视频,最后将它们的结果合并起来,从而得到原先视频的计算结果,典型的并行算法计算的策略。
1、切片:分解(Divide)将一个大视频切成多个小视频。
2、并行:并行处理这些片段。
3、合并:将这些片段的结果合并起来,以获得整体的结果
解决方案
如上所述,将重点探讨:切片加速的相关方案。大体过程,如下图所示:
备注:
1、上述过程要求:片与片之间,没有关联性,然后,并行处理,来提高处理速度 + 降低对硬件的需求。
2、在实际业务中,片与片之间,部分情况下,存在上下文的关联性。其解决思路之一:分析下关联性有什么特点,然后,将这个关联性降维到无关联性。例如:某一算法的加速流程如下图所示:
其整体流程就会由:切 -> 并 -> 合,变成:切 -> 切 -> 合 -> 并 -> 合。
3、提取音频时,直接做音频转码,也属于:旁路的并行流程。
4、切片 + 处理,需并行处理,是能够提速的关键。
模块抽象
模块 | 功能定位 | 是否连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 output.aac -loglevel error |
为啥要音频提取并且重新转码?
1、一般算法处理,都是针对视频流,很少有针对音频流的,而处理慢,主要是处理视频慢,非处理音频慢,因此,将音频流提取出来,能够:减少视频处理过程的IO +
减少:cpu、gpu计算量。
2、用户输入的视频,格式千变万化,有些视频无法直接通过:-acodec copy,直接将音频提取出来,会奇奇怪怪的错误。因此,统一将音频流转码,统一音频格式。
3、有些视频天然没有音频,因此,在处理前,需判断原始视频是否有音频,若有,再触发:音频提取流程,否则:直接触发视频切片。
视频切片
功能 | 说明 | 备注 |
---|---|---|
按视频时长切 | 按GOP关键帧快速切 | |
按帧索引切 | 将原始视频的帧解封装,然后,使用libx264 or libx265重新压缩 | 暂无 |
当然了,视频如何切,需要考虑:底层算法,
1、有些算法,需要预留一些buffer帧进行预热,才能确保切片后的视频画质,能够不输于:不切片时的结果视频画质。
这种buffer帧策略,分为:前向重叠帧策略、后置重叠帧策略、双向重叠帧策略。
2、有些算法,例如:消除某段视频里的某个物体,片与片之间存在上下文的相关性,此时,切片时,要将该物体所对应的帧序列,单独切出来,然后,合并到各个片上去,将所有片降维到:无关联性。
3、切片时,最好不要保留:PTS(后续基本用不上),也就是:切片时,将所有片的PTS都重置成0。
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]
视频合并
算法并行处理完毕后,能够得出一坨的算法处理后的视频片段,收集到这些片段后,将这些片段合并,即能得到一个完整的、处理后的视频。例如:参考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} -c:v copy -c:a copy -strict experimental -movflags faststart {2} -loglevel error |
算法编排
如本文中切片加速
图片所示:整个过程,可以硬编代码写死,也可以使用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对齐