【高效视频处理】BMF 项目安装与老视频修复体验全流程及总结

一、BMF简介

BMF(Babit Multimedia Framework)是字节跳动开发的跨平台、多语言、可定制的多媒体处理框架。经过 4 年多的测试和改进,BMF 已经过量身定制,能够熟练地应对我们现实生产环境中的挑战。目前广泛应用于字节跳动的视频串流、直播转码、云剪辑和移动前/后处理场景。该框架每天处理超过 20 亿个视频。
在这里插入图片描述
官方仓库地址为:https://github.com/BabitMF/bmf?tab=readme-ov-file

二、BMF初体验

2.1、安装方式

1️⃣、pip安装
首先要确保本机已经安装了Python,然后使用pip install BabitMF安装BabitMF,安装过程中其会帮你同时安装依赖包,显示successfully安装即为成功:
在这里插入图片描述
2️⃣、源码编译安装
首先我们使用git clone命令克隆BMF源码git clone https://github.com/BabitMF/bmf bmf,克隆完成后,项目的文件结构如下:
在这里插入图片描述
使用重终端命令cd进入bmf项目目录,然后输入./build.sh开始构建,构建可能会持续5到15分钟:
在这里插入图片描述

2.2、初步体验

1️⃣、创建Graph

import bmf
graph = bmf.graph()
video = graph.decode({
     "input_path": input_video_path //输入视频的本地目录地址
})
bmf.encode(
     video['video'],
     video['audio'],
     {
         "output_path": output_path,//输出视频的本地目录地址
         "video_params": {
             "codec": "h264",
             "width": 320,
             "height": 240,
             "crf": 23,
             "preset": "very fast"
         },
         "audio_params": {
             "codec": "aac",
             "bit_rate": 128000,
             "sample_rate": 44100,
             "channels": 2
         }
     }
).run()

Graph是bmf中最基础的一个概念,使用graph.decode和encode可以对视频进行解码和编码,这里首先使用import bmf导入模块,然后使用graph = bmf.graph() 创建了一个graph对象,然后video = graph.decode({“input_path”: input_video_path}) 使用创建的图形对象对输入视频进行解码。解码后,video对象包含了解码后的视频数据和相关信息。bmf.encode(…).run() 是对解码后的视频进行编码,其中
视频参数包括:

  • “codec”: “h264” - 视频编码器为H.264。
  • “width”: 320 - 视频宽度为320像素。
  • “height”: 240 - 视频高度为240像素。
  • “crf”: 23 - 视频质量控制参数,值越低质量越高。

音频参数包括:

  • “codec”: “aac” - 音频编码器为AAC。
  • “bit_rate”: 128000 - 音频比特率为128,000 bps。
  • “sample_rate”: 44100 - 音频采样率为44.1 kHz。
  • “channels”: 2 - 音频通道数为2(立体声)。“preset”: “very fast” - 编码速度预设为"very fast"。

2️⃣、创建Pipeline
同时,BMF提供构建一个视频处理的Pipeline,通过串联不同的同步模块来实现视频处理的流程:

  1. 构建同步模块:首先调用bmf_sync.sync_module接口创建四个bmf模块(c_ffmpeg_decoder、c_ffmpeg_filter(Scale)、c_ffmpeg_filter(volume)、c_ffmpeg_encoder)。然后,它不断循环地从输入视频中读取视频流,逐帧解码,并首先将其发送到缩放过滤模块,将视频缩放到320x250的分辨率。然后,获取处理后的视频帧,发送至音量过滤模块进行一次音量调节。最后,视频被发送到编码器模块进行视频编码并保存为文件。
  2. 构建管道:调用了 bmf_sync.process 接口,直接执行同步模块的处理过程,将输入数据包提供给模块进行处理,并返回处理后的结果和任务完成的时间戳。
  3. 管道循环:不断调用 bmf_sync.process 来处理视频和音频帧。使用 decoder 模块处理输入数据。得到 frames 字典,其中包含了不同通道的视频或音频帧。如果有下一帧需要处理,分别根据通道编号(0 或 1)判断是否有帧数据,然后使用 scale 或 volume 模块进行相应的处理,最后将处理后的帧数据传递给 encoder 模块继续处理。

其核心代码如下:

import bmf
from bmf import bmf_sync, Packet
input_video_path = "./big_bunny_10s_30fps.mp4"
output_path = "./video.mp4"

def bmf.builder.bmf_sync.sync_module (
   name, 
   option, 
   input_streams, 
   output_streams 
)
def bmf.builder.bmf_sync.process (
  module, 
  pkts_dict 
)   

# create sync modules
decoder = bmf_sync.sync_module("c_ffmpeg_decoder", {"input_path": input_video_path}, [], [0, 1])
scale = bmf_sync.sync_module("c_ffmpeg_filter", {
    "name": "scale",
    "para": "320, 250"
}, [0], [0])
volume = bmf_sync.sync_module("c_ffmpeg_filter", {
    "name": "volume",
    "para": "volume=3"
}, [0], [0])
encoder = bmf_sync.sync_module("c_ffmpeg_encoder", {
    "output_path": output_path
}, [0, 1], [])

while True:
    frames, _ = bmf_sync.process(decoder, None)
    has_next = False
    for key in frames:
        if len(frames[key]) > 0:
            has_next = True
            break
    if not has_next:
        bmf_sync.send_eof(encoder)
        break
    if 0 in frames.keys() and len(frames[0]) > 0:
        frames, _ = bmf_sync.process(scale, {0: frames[0]})
        bmf_sync.process(encoder, {0: frames[0]})
    if 1 in frames.keys() and len(frames[1]) > 0:
        frames, _ = bmf_sync.process(volume, {0: frames[1]})
        bmf_sync.process(encoder, {1: frames[0]})

2.3、老视频修复体验

熟悉了基础的BMF操作后,我们可以体验一下BMF修复老视频的demo,官方为我们提供了一个写好的colab的notebook:https://colab.research.google.com/github/BabitMF/bmf/blob/master/bmf/demo/colorization_python/deoldify_demo_colab.ipynb

点击进入链接,连接到Colab的资源,申请T4资源,申请成功后如下所示:
在这里插入图片描述

然后点击代码执行程序-全部运行:
在这里插入图片描述
运行流程首先会克隆老视频修复的git仓库,然后安装对应的依赖和工具:
在这里插入图片描述
其通过构建一个 BMF 模块,使用 DeOldify 算法对黑白视频进行颜色化处理。核心代码如下:

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

模型构建好之后,在2-2这里,可以修改相关的参数,其中:input_video_path是输入视频路径,output_video_path是输出彩色视频路径。model_weight_path是在步骤1-3中下载模型权重的路径(仅体验的话不用管这个参数)。
在这里插入图片描述
等待片刻后,就能输出对应的老视频修复结果了:
在这里插入图片描述

三、BMF体验总结

3.1、优点

通过以上实践体验,总的来讲,BMF通过提供简洁易用的跨语言接口、灵活的调度和扩展性,以 graph/pipeline 的方式构建高性能的多媒体处理链路,以模块化的方式动态扩展、管理和复用视频处理,非常适合运用在视频转码、视频抽帧、视频增强、视频分析、视频插帧、视频编辑、视频会议、VR 等领域,其具有:

1、跨平台兼容性:BMF广泛支持多个操作系统,包括Linux、Windows和Mac OS,并且经过优化以适应x86和ARM CPU架构,确保在不同平台上的高效运行。

2、多语言支持:BMF提供Python、Go和C++ API,为开发人员提供了使用首选编程语言进行开发的灵活性,使项目更易于使用。

3、高效数据处理:BMF提供了无缝的数据格式转换,涵盖了流行框架(FFmpeg/Numpy/PyTorch/OpenCV/TensorRT)。这包括硬件设备(CPU/GPU)之间的转换,以及色彩空间和像素格式的高效转换,为项目提供高度灵活性和效率。

3.2、缺点

1、ARM GPU支持受限:官方暂不支持ARM GPU架构。
2、文档较少:目前仅有官方文档和极少数论坛文章可供参考。
3、社区活跃度不足:目前社区相对不够活跃,遇到问题时可能难以获得及时的帮助和反馈。

最后

💖 个人简介:人工智能领域研究生,目前主攻文本生成图像(text to image)方向

📝 个人主页:中杯可乐多加冰

🔥 限时免费订阅:文本生成图像T2I专栏

🎉 支持我:点赞👍+收藏⭐️+留言📝

另外,我们已经建立了研学交流群,如果你也是大模型、T2I方面的爱好者或研究者可以私信我加入。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C# windows服务程序开机自启动exe程序

我们使用传统的Process.Start(".exe")启动进程会遇到无法打开UI界面的问题,尤其是我们需要进行开启自启动程序设置时出现诸多问题,于是我们就想到采用windows服务开机自启动来创建启动一个新的exe程序,并且是显式运行。 首先是打开…

对接第三方接口鉴权(Spring Boot+Aop+注解实现Api接口签名验证)

前言 一个web系统,从接口的使用范围也可以分为对内和对外两种,对内的接口主要限于一些我们内部系统的调用,多是通过内网进行调用,往往不用考虑太复杂的鉴权操作。但是,对于对外的接口,我们就不得不重视这个…

Java字符串对象池的作用是什么?

Java字符串对象池的作用是什么? 在 Java 中,字符串池(String Pool)是字符串常量的存储区域,它位于堆区域中。字符串池的作用是提高字符串的重用性,减少内存消耗。 字符串池的位置: 在堆中&…

Qt6入门教程 3:创建Hello World项目

一.新建一个项目 程序员的职业生涯都是从一声问候开始的,我们的第一个Qt项目也是HelloWorld 首先要说明的是,IDE不一定要用Qt Creator,用Visual Studio、VSCode、CLion也可以搭建Qt开发环境,它们都相应的插件来支持Qt开发。当然这…

气动凝结水回收机组 浮球机械泵回收机组工作原理动画讲解介绍

​ 1:气动凝结水回收浮球机械泵介绍 气动凝结水回收是一种利用气动力转换产生负压的装置,可以将废气中的水分分离出来并回收利用。这种装置主要包含两个关键部件:气水分离器和气动运动控制阀。 气水分离器负责将进入回收装置的废气中的水分…

transforms图像增强(二)

一、图像变换 1、transforms.Pad transforms.Pad是一个用于对图像边缘进行填充的数据转换操作。 参数: padding:设置填充大小。可以是单个整数,表示在上下左右四个方向上均填充相同数量的像素;也可以是一个包含两个整数的元组…

粉丝投稿:从写下第1个脚本到年薪20W,我的自动化测试心路历程

我希望我的故事能够激励现在的软件测试人,尤其是还坚持在做“点点点”的测试人。 你可能会有疑问:“我也能做到这一点的可能性有多大?”因此,我会尽量把自己做决定和思考的过程讲得更具体一些,并尽量体现更多细节。 每…

印象笔记02: 笔记本管理系统和空间使用

印象笔记02: 笔记本管理系统和空间使用 印象笔记新建笔记是一件非常容易的事情。笔记多了,就是归纳到笔记本里。 印象笔记一共有三层的笔记结构:最高层级是笔记本组,其次是笔记本,最后是一个个的笔记。合理的分类能够…

SpringCloud系列篇:核心组件之注册中心组件

🥳🥳Welcome Huihuis Code World ! !🥳🥳 接下来看看由辉辉所写的关于SpringCloud的相关操作吧 目录 🥳🥳Welcome Huihuis Code World ! !🥳🥳 一.注册中心组件是什么 二.注册中心…

一键转换,创新无限:将HTML轻松转化为PDF!

在数字时代,HTML与PDF已成为信息传递的两大主流格式。然而,在这两者之间转换常常让人感到困扰。现在,有了我们的创新工具,您只需轻点一下,即可一键将HTML转化为PDF! 首先,我们要进入首助编辑高…

(Python + Selenium4)Web自动化测试自学Day2之动手尝试

目录 文章声明⭐⭐⭐让我们开始今天的学习吧!小试牛刀关于select标签关于弹窗只有一个点击按钮的弹窗需要确认的弹窗用户可以输入的弹窗 文章声明⭐⭐⭐ 该文章为我(有编程语言基础,非编程小白)的 Python Selenium4 Web自动化测试…

HttpRunner自动化测试工具之获取响应数据extract提取值到变量

获取响应数据 extract: 提取 注:extract 应与request保持同一层级 1、响应行,响应头;通过 extract 提取响应的数据并存储到变量中,如下图: 注:变量名的前面要有 - # 获取响应数据: 响应行(…

【年终总结系列 2023】成长与收获:回顾过去、展望未来,加油2024!

转眼间加入CSDN已经六年多了,初加入CSDN时,我兴致勃勃地投入到写作中,分享了一些CTF的解题思路和方法,取得了不错的反响。但随着工作忙碌和生活压力的增加,我在CTF方面的写作频率逐渐减少,也很长时间没有更…

Linux离线安装MySQL(rpm)

目录 下载安装包安装MySQL检测安装结果服务启停MySQL用户设置 下载安装包 下载地址:https://downloads.mysql.com/archives/community/ 下载全量包如:(mysql-8.1.0-1.el7.x86_64.rpm-bundle.tar) 解压:tar -xzvf mysql-8.1.0-1.el7.x86_64.…

国家高等教育智慧教育平台

文章目录 1. 网站地址2. 网站简介3. 网站集合的资源与依托平台彩蛋环节a. 考试酷b. 公益学术平台 足不出户,就能免费学习2.7万门大学课程。包含国家精品课程,部分课程由国家级名师 / 院士 授课。 1. 网站地址 国家高等教育智慧教育平台网址:…

架构的本质是什么?

最近总是有小伙伴问我,如何成长为一名优秀的架构师,我也不知道该如何去回答,但是我想聊一下架构的本质。 架构不是互联网行业独有的 架构及对应的架构师职位并不是互联网行业独有的,只要存在组织的地方就存在架构。 比如一个木…

【C++】vector

文章目录 1. vector 的介绍2. vector 的使用2.1 vector 的定义2.2 vector iterator 的使用2.3 vector 的空间增长问题2.3 vector 增删查改 1. vector 的介绍 vector的文档介绍 vector是表示可变大小数组的序列容器。就像数组一样,vector也采用连续的存储空间来存储…

程序员必知!责任链模式的实战应用与案例分析

责任链模式让多个对象依次处理请求,降低发送者和接收者的耦合度,以在线购物为例,用户提交订单需经多步验证,通过责任链模式,验证器按顺序处理请求,先用户身份,再支付方式,最后配送地…

【LMM 011】MiniGPT-5:通过 Generative Vokens 进行交错视觉语言生成的多模态大模型

论文标题:MiniGPT-5: Interleaved Vision-and-Language Generation via Generative Vokens 论文作者:Kaizhi Zheng* , Xuehai He* , Xin Eric Wang 作者单位:University of California, Santa Cruz 论文原文:https://arxiv.org/ab…

java的面向对象编程(oop)概述及案例

前言: 学到了面向对象编程,整理下相关知识点。打牢基础,daydayup! 面向对象基础概述 1,什么是面向对象,面向对象的思考逻辑是什么? 面向对象就是把任何事物都看成一个又一个对象。思考逻辑为万物皆对象&am…