BabitMF(Babit Multimedia Framework,BMF),作为一个通用的多媒体处理框架,能够提供简单易用的跨语言接口、灵活的调度和可扩展性,以及以模块化的方式动态扩展、管理和复用视频处理的原子能力。BMF 以 graph/pipeline 的形式构建多媒体处理链路,或通过直接调用各个处理能力实现项目集成,帮助多媒体用户在各类生产环境中方便、高效地实施项目。BMF 的使用场景涵盖视频转码、视频帧提取、视频增强、视频分析、视频帧插入、视频编辑、视频会议以及 VR 等。目前,BMF 每天处理的视频数以亿计。在此过程中,BMF 框架的功能多样性、易用性、兼容性和稳定性得到了充分的打磨。
链接:https://github.com/BabitMF/bmf
上图是 BMF 的概要架构图,包括一整套的生态体系,主要由三部分组成:
- 应用层:顶层为用户提供多语言的 API 包括 Python、Go、C++,方便用户根据不同的项目需求进行开发集成。
- 框架层:中间层包括框架的 graph/pipeline 调度,跨数据类型跨设备的数据流转 Backend,以及常用的跨设备 reformat、color space conversion、tensor 算子等 SDK。
- 模块层:包含具有各种原子能力的模块,提供多语言模块开发机制。用户可以根据自身需求将算法/处理实现为 Python、Go、C++ 语言的任意一种。
BMF的安装部署指南
安装方式选择————》》》
- pip 安装: 使用Python的包管理工具pip进行安装。这是最简单的安装方式之一。
- Docker 安装: 利用Docker容器进行BMF的安装,提供了一种轻量、可移植的部署方案。
- 预编译二进制文件: 使用预编译的二进制文件,适用于各种操作系统。
- 源代码构建: 从源代码编译安装,适用于需要定制化配置的情况。
依赖————》》》
- 常规依赖: 安装系统所需的所有package,可以使用apt、yum或brew进行安装。
- Python依赖: 如果您使用Python API或通过预编译安装包调用Python模块,需要安装Python,要求版本在Mac ARM为3.9以上,Linux和Windows为3.7以上。
- FFmpeg依赖: BMF目前支持4.2 - 5.1版本的FFmpeg,您可以使用系统的package管理器安装。对于ubuntu、debian、CentOS:8和macOS,可以直接使用系统提供的安装方式。
安装步骤————》》
- pip 安装: 使用**
pip install BMF
**进行安装,确保您的Python版本满足要求。 - Docker 安装: 利用Docker容器,您可以使用Docker Hub上的BMF镜像,通过**
docker pull
**获取镜像并运行容器。 - 预编译二进制文件: 下载适用于您操作系统的预编译二进制文件,并按照说明进行安装。
- 源代码构建: 从BMF的源代码中构建安装,首先获取源代码,然后按照README或安装指南进行编译和安装。
下载 Python 源代码
bashCopy codecd /opt
wget https://www.python.org/ftp/python/3.9.13/Python-3.9.13.tgz
tar xvf Python-3.9.13.tgz
cd Python-3.9.13
这将下载 Python 3.9.13 版本的源代码并解压缩到指定目录。
配置编译选项
在进入 Python 源代码目录后,执行以下命令来配置编译选项:
bashCopy codesudo ./configure --enable-optimizations
这将根据您的系统和需求配置 Python 编译选项。**--enable-optimizations
**选项会在编译过程中应用一些优化。
编译
配置完成后,使用以下命令进行编译:
bashCopy codesudo make altinstall
这将启动编译过程。请注意,使用 make altinstall
而不是 make install
,是为了避免与系统默认的 Python 版本发生冲突。altinstall
将安装 Python 到一个版本特定的目录,而不是默认的 /usr/local/bin
目录。
验证安装
编译完成后,可以使用以下命令验证 Python 是否成功安装:
bashCopy codepython3.9.13 --version
这应该输出 Python 3.9.13 的版本信息,证明编译安装成功。
设置环境变量
如果您希望新编译的 Python 版本成为系统默认的 Python 版本,可以考虑设置相应的环境变量。例如,在 .bashrc
或 .zshrc
文件中添加以下行:
bashCopy codeexport PATH="/opt/Python-3.9.13/bin:$PATH"
BMF的基本使用
转码
使用 BMF 以及如何使用 FFmpeg 兼容选项来实现所需的功能。使用BMF 在转码时需要 FFmpeg 4.x 或 5.x,通过 apt 检查版本,如果版本符合要求,通过 apt 安装 ffmpeg,否则,就需要从源码编译ffmpeg。
! apt show ffmpeg | grep "^Package:|^Version:"
! apt install -y ffmpeg
! git clone https://github.com/BabitMF/bmf bmf
! ./bmf/scripts/build_ffmpeg.sh nasm yasm x264 x265
BMF的安装:
! pip3 install BabitMF
下载我们将使用的视频文件:
! gdown --fuzzy https://drive.google.com/file/d/1l8bDSrWn6643aDhyaocVStXdoUbVC3o2/view?usp=sharing -O big_bunny_10s_30fps.mp4
! ffprobe big_bunny_10s_30fps.mp4
然后进行视频转码:
import bmf
input_video_path = "./big_bunny_10s_30fps.mp4"
output_path = "./remux_output.m3u8"
# create graph
graph = bmf.graph()
# decode
video = graph.decode({
"input_path": input_video_path,
"video_codec": "copy",
"audio_codec": "copy"
})
(
bmf.encode(
video['video'],
video['audio'],
{
"output_path": output_path,
"format": "hls",
"mux_params": {
"hls_list_size": "0",
"hls_time": "2",
"hls_segment_filename": "./file%03d.ts"
}
}
).run()
)
AI推理
此演示展示了如何将最先进的 AI 算法集成到 BMF 视频处理管道中。著名的开源着色算法 DeOldify 被包装成一个 BMF pyhton 模块。最终效果如下图所示,左侧是原始视频,右侧是彩色视频。
环境设置,下载预训练权重,pip 安装 BMF 包,BMF框架利用FFmpeg视频解码器和编码器作为视频解码和编码的内置模块。在使用 BMF 之前,用户必须安装受支持的 FFmpeg 库。
!git clone https://github.com/eefengwei/DeOldify.git DeOldify
!pip3 install -r ./DeOldify/requirements-colab.txt
!mkdir -p ./DeOldify/models
!wget -c https://data.deepai.org/deoldify/ColorizeVideo_gen.pth -O ./DeOldify/models/ColorizeVideo_gen.pth
!pip install BabitMF-GPU
!sudo apt install ffmpeg
!dpkg -l | grep -i ffmpeg
!pip install wurlitzer
%load_ext wurlitzer
import sys
sys.path.insert(0, '/content/DeOldify')
print(sys.path)
%%file py_deoldify_module.py
import bmf
import numpy as np
from bmf import ProcessResult, Packet, Timestamp, VideoFrame
import PIL
import bmf.hml.hmp as mp
from deoldify import device
from deoldify.device_id import DeviceId
import torch
from deoldify.visualize import *
import warnings
debug = False
class py_deoldify_module(bmf.Module):
def __init__(self, node, option=None):
print(f'py_deoldify_module init ...')
self.node_ = node
self.option_ = option
print(option)
warnings.filterwarnings("ignore", category=UserWarning, message=".*?Your .*? set is empty.*?")
#NOTE: This must be the first call in order to work properly!
#choices: CPU, GPU0...GPU7
device.set(device=DeviceId.GPU0)
if not torch.cuda.is_available():
print('warning: GPU is not available, the computation is going to be very slow...')
weight_path=Path('/content/DeOldify')
if option and 'model_path' in option.keys():
model_path = option['model_path']
if not model_path:
print(f'model_path={model_path}')
weight_path=Path(model_path)
self.colorizer = get_stable_video_colorizer(weight_path)
self.idx = 0
print(f'py_deoldify_module init successfully...')
def process(self, task):
# iterate through all input queues to the module
idx = self.idx
for (input_id, input_queue) in task.get_inputs().items():
# get output queue
output_queue = task.get_outputs()[input_id]
while not input_queue.empty():
# get the earliest packet from queue
packet = input_queue.get()
# handle EOF
if packet.timestamp == Timestamp.EOF:
output_queue.put(Packet.generate_eof_packet())
task.timestamp = Timestamp.DONE
# process packet if not empty
if packet.timestamp != Timestamp.UNSET and packet.is_(VideoFrame):
vf = packet.get(VideoFrame)
rgb = mp.PixelInfo(mp.kPF_RGB24)
np_vf = vf.reformat(rgb).frame().plane(0).numpy()
# numpy to PIL
image = Image.fromarray(np_vf.astype('uint8'), 'RGB')
colored_image = self.colorizer.colorize_single_frame_from_image(image)
if not colored_image:
print(f'Fail to process the input image with idx = {idx}')
continue
if debug:
input_name = f'video/bmf_raw/frame_{idx}.png'
print(f'input_name = {input_name}')
image.save(input_name)
output_name = f'video/bmf_out/frame_{idx}.png'
print(f'output_name = {output_name}')
colored_image.save(output_name)
self.idx = idx + 1
out_frame_np = np.array(colored_image)
rgb = mp.PixelInfo(mp.kPF_RGB24)
frame = mp.Frame(mp.from_numpy(out_frame_np), rgb)
out_frame = VideoFrame(frame)
out_frame.pts = vf.pts
out_frame.time_base = vf.time_base
pkt = Packet(out_frame)
pkt.timestamp = out_frame.pts
output_queue.put(pkt)
return ProcessResult.OK
使用体验
总体来说,使用起来还是十分丝滑的。
- 多媒体处理全面涵盖:BMF 提供了丰富的多媒体处理功能,涵盖了视频、音频和图像的各个方面。从简单的转码到复杂的编辑管道,再到人工智能推理,BMF 提供了全面而完善的解决方案,使其成为一个多才多艺的多媒体处理框架。
- 模块化设计:BMF 的模块化设计让用户能够轻松地构建复杂的处理管道。通过组合不同的模块,用户可以实现各种定制化的处理流程,从而满足不同项目的需求。这种模块化的设计也促进了代码的可重用性,提高了开发效率。
- 多语言支持:BMF 支持多语言编程,包括 Python、Go、C++ 等,使得开发者可以根据自己的偏好和项目需求选择适合的编程语言。这种灵活性有助于提高团队的协作效率,同时也扩大了 BMF 的用户群体。
THE end
BMF 作为一款多媒体处理框架,在其全面的功能和灵活的设计中体现了强大的潜力。尽管在使用过程中遇到了一些挑战,但其优点仍然让我对这个框架抱有信心。通过不断的学习和实践,我相信 BMF 将为多媒体领域的开发者提供更多可能性。
infoQ社区链接:https://xie.infoq.cn/article/ce636a7697e0aa6f53db17bc2