三.ffmpeg 集成av1_ffmpeg av1-程序员宅基地

技术标签: 音视频  

copy from zhujiamin
一、介绍

FFmpeg4.2支持AV1、AVS2等视频编码格式,但本身并不包含解码器,需要自己集成。集成的编解码器要避开GPL开源协议(–enable-gpl),因此不能用x264、AVS2等编解码器

我在研究FFmpeg升级时,寻找能提升多媒体系统表现力的新特性,发现FFmpeg支持的基于BSD协议的dav1d解码器比较有价值,能大幅度提高AV1软解码性能,没有代码开源的风险,并且能持续迭代更新

在这里插入图片描述
AV1是由AOM(Alliance for Open Media,开放媒体联盟)制定的一个开源、免版权费的视频编码格式,目标是解决H265昂贵的专利费用和复杂的专利授权问题并成为新一代领先的免版权费的编码标准。AV1是google制定的VP9标准的继任者,也是H265强有力的竞争者

目前youtube、nextflix,以及国内的爱奇艺都在推广AV1编码视频

google从Android Q开始提供了gav1软解码器,最高支持1080P,播放高码率视频容易卡顿

FFmpeg支持libaom和libdav1d两种解码器
–enable-libaom enable AV1 video encoding/decoding via libaom [no]
–enable-libdav1d enable AV1 decoding via libdav1d [no]

在这里插入图片描述
dav1d由VideoLAN,VLC和FFmpeg联合开发,项目由AOM联盟赞助,和libaom相比,dav1d性能普遍提升100%,最高提升400%

二、编译

1.下载源码:git clone https://code.videolan.org/videolan/dav1d.git

2.dav1d用meson和ninja编译,不是常见的Makefile。安装meson(版本>=0.47)、Ninja、nasm (版本>=2.13.02) 安装参考mesonbuild.com/Quick-guide

由于公司的研发编译环境没有安装meson,我是在ubuntu虚拟机上编译的

3.交叉编译:FFmpeg配置–enable-libdav1d后,libavcodec.so会依赖libdav1d.so,meson默认用linux系统环境编译,而libavcodec.so是用ndk环境编译,会有各种依赖的系统库定义报错,因此dav1d也要用相同ndk编译,需要编写交叉编译文件,以编译arm64库为例:
在这里插入图片描述
4.执行编译命令,生成libdav1d.so

meson build --buildtype release --cross-file=cross_file_64.txt && ninja -C build
在这里插入图片描述
编译后的源码目录如图,cross_file_32.txt、cross_file_64.txt是自己写的交叉编译文件,build目录是编译生成的,libdav1d.so在build/src目录下:
在这里插入图片描述
在这里插入图片描述
由于dav1d的meson.build脚本有版本信息,因此会生成带版本号的so

在这里插入图片描述
在这里插入图片描述

三、FFmpeg集成dav1d

1.放置libdav1d.so和头文件

在FFmpeg目录创建extend/dav1d/目录存放so和头文件,头文件在dav1d源码include目录中
在这里插入图片描述
在这里插入图片描述

2.FFmpeg编译集成dav1d

FFmpeg默认通过.pc文件获取扩展项的头文件和库路径,要求编译环境安装了pkg-config,不便于共同维护

研究configure文件后,注释掉libdav1d的pkg_config检查,并通过–extra-cflags、–extra-ldflags、–extra-libs配置dav1d的头文件、库路径和库名称
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
用readelf -d libavcodec.so查看它依赖了libdav1d.so.4这个库,于是将其cp到prebuilt目录,预编译到system和vendor,并在代码中添加OMX.ffmpeg.av1.decoder
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
FFmpeg集成dav1d,在动态库依赖层面的结构如图:
在这里插入图片描述
由于dav1d解码库是集成在FFmpeg中的,只要掌握FFmpeg编译、dav1d编译、FFmpeg集成dav1d的方法即可,Android大版本升级时没有额外的适配移植工作量

3.更新FFmpeg解码API

测试dav1d解码时发现有丢帧现象,每秒最高解码15帧,打印log提示废弃的解码函数会丢帧

01-01 06:44:29.139 I 1407 12739 FFMPEG : [libdav1d @ 0xe5f10c00] The deprecated avcodec_decode_* API cannot return all the frames for this decoder. Some frames will be dropped. Update your code to the new decoding API to fix this.

需要用avcodec_send_packet和avcodec_receive_frame替代avcodec_decode_video2

看源码时,发现avcodec_decode_video2源码内部也调用了avcodec_send_packet和avcodec_receive_frame

(1)avcodec_decode_video2一个函数完成了解码的输入和输出,对于capabilities支持CODEC_CAP_DELAY的解码器,可能只输入并延迟输出,最后要填空buffer获取剩余output buffer,否则丢失最后几帧;

对于不支持CODEC_CAP_DELAY的解码器,它会阻塞式地完成一帧解码

(2)avcodec_send_packet和avcodec_receive_frame从逻辑上类似于Android MediaCodec的queueInputBuffer和dequeueOutputBuffer,分别给解码器输入和输出,形式上更加灵活,最后也要送空buffer;

实测发现大部分情况下解码工作发生在avcodec_send_packet输入buffer时,少部分情况在avcodec_receive_frame输出buffer时

更新解码API:

avcodec_decode_video2和avcodec_send_packet、avcodec_receive_frame的返回值和状态判断方式不同,且SoftFFmpegVideo继承Android OMX组件,很多状态判断工作是结合OMX的状态信息完成的,因此修改解码逻辑必须加log调试观察,充分理解解码框架的流程

SoftFFmpegVideo的主体解码流程如图,inQueue和outQueue是OMX的解码器输入输出队列
在这里插入图片描述
四、dav1d解码接口简介

FFmpeg的dav1d接口文件为libdav1d.c,解码流程如图

在这里插入图片描述
作为开源库的调用者,我们通常关注解码参数设置,先看一下参数设置内容Dav1dSettings,和默认设置参数

在这里插入图片描述
在这里插入图片描述
其中影响解码性能(速度、负载)的主要是tile线程数、帧线程数,看一下在FFmpeg中是如何赋值的

(AV1标准中tile的定义与HEVC标准中tile的定义类似:是一帧图像中能被独立解码和编码的矩形区域,尽管环路滤波时可以跨越tile的边界)

(1)定义线程数threads
在这里插入图片描述

c→thread_count:是AVCodecContext的thread_count对象,调用avcodec_open2打开编解码器时传入FFmpeg

在OPPO的SoftFFmpegVideo中,thread_count的值是0,因此会通过av_cpu_count获取手机CPU核数,再乘以1.5赋值给threads

在这里插入图片描述
将thread_count设置为0传给FFmpeg时,FFmpeg都会调用av_cpu_count设置为手机CPU核数。我在8核手机调试过thread_count,设置0或8解码速度是一样的

(2)n_tile_threads和n_frame_threads的计算
在这里插入图片描述
还有一个比较有意思的参数是apply_grain,负责获取和叠加film grain(胶片颗粒)

film grain在电视和电影内容中广泛存在,它经常是创作内容的一部分,在编码过程中需要保留下来,因为film grain的随机性,导致很难用传统的压缩算法进行压缩,AV1对film grain做了专门处理

film grain在去噪音过程中会从视频中去除掉,grain参数会通过噪音视频序列和去噪视频序列的差异中获得,这些参数会和压缩视频流一起传输到解码端,解码后,film grain会被叠加到重建视。模型和整体框架如图所示
在这里插入图片描述

参考资料:http://lazybing.github.io/blog/2018/10/17/av1-film-grain-synthesis/

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/o343196469/article/details/122419744

智能推荐

Windows系统设置每天自动备份指定文件并自动删除七天前的文件(脚本+Windows任务计划)_ms-dos七天自动删除-程序员宅基地

文章浏览阅读8.3k次,点赞8次,收藏41次。Windows系统设置每天自动备份指定文件并自动删除七天前的文件(脚本+Windows任务计划)在生活中和工作中有时候为了避免电脑宕机导致文件丢失常常会使用一些方式去备份文件,今天小编给大家介绍一个方法,用于自动备份指定文件,并删除N天前的文件。_ms-dos七天自动删除

计算机科学创新大赛,全国青少年科技创新大赛-程序员宅基地

文章浏览阅读761次。全国青少年科技创新大赛China Adolescents Science & Technology Innovation Contest翰林青创赛战绩2020年计算机(选送全国)一等奖 1名计算机二等奖 1名化学二等奖 1名三等奖若干2019年数学一等奖 1名二等奖 1名三等奖若干项目介绍全国青少年科技创新大赛(China Adolescents Science & Tech..._青少年科技创新大赛计算机科学与信息技术

STM32CUBEMX学习笔记——陶晶驰串口屏中断接收数据_陶晶瓷串口屏怎么接收-程序员宅基地

文章浏览阅读2.4k次,点赞4次,收藏26次。网上很多串口屏的开发都是基于标准库开发的,我本人接触到的开发模式是CUBEMX,两种开发环境导致很多资料之间有点割裂,因此我将自己之前学习标准库的开发方式利用CUBEMX实现的方法写在这,防止自己忘记。开发环境还是之前做的项目,以一个按钮为例通过这个按钮学习串口屏的通讯 。b4和b6还需要按下一秒后连续改变h1和n1的数值,因此顺便回顾一下如何实现:b4的按下事件中加入定时器,如果连续1000ms就进入使能:tm2.tim=1000tm2.en=1使能后就在定时器模块中:t_陶晶瓷串口屏怎么接收

web前端培训分享JavaScript学习笔记分支结构_if(ture)前端-程序员宅基地

文章浏览阅读169次。web前端培训分享JavaScript学习笔记分支结构,我们的 js 代码都是顺序执行的(从上到下)逻辑分支就是根据我们设定好的条件来决定要不要执行某些代码IF 条件分支结构if 语句· 通过一个 if 语句来决定代码执行与否a· 语法: if (条件) { 要执行的代码 }· 通过 () 里面的条件是否成立来决定 {} 里面的代码是否执行// 条件为 true 的时候执行 {} 里面的代码if (true) {alert(‘因为条件是 true,我会执行’)}// 条件为 false 的_if(ture)前端

Java ExecutorService四种线程池的例子与说明_java executorservice 多线程 例子-程序员宅基地

文章浏览阅读160次。一、为什么使用线程池使用new Thread执行多个线程有如下一些问题: 每次new Thread新建对象性能差。 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。 缺乏更多功能,如定时执行、定期执行、线程中断。相比new Thread,Java提供的四种线程池的好处在于: 重用存在的线程,减少对象创建、消亡的..._java executorservice 多线程 例子

高级映射(一):一对一、一对多,多对多查询总结_购物车和商品是一对多还是多对多-程序员宅基地

文章浏览阅读2w次,点赞2次,收藏18次。多表之间的数据交互其实一对一和一对多映射,在前面的配置中已经接触到,我没在日志里直接说明,是因为想要在之后写一篇总结日志(就是本篇),总结这些高级映射的配置。例如一对一查询在关联的嵌套结果集查询中就涉及到,一对多查询则在这个基础上再加上一个或多个嵌套结果集,它们可以是一个实体类,或者是一个集合。多对多查询稍微有点复杂,举个例子来说,一个商城管理系统中,一名顾客在一个购物清单中可以有多件商品,而..._购物车和商品是一对多还是多对多

随便推点

STL --- 四、算法 Algorithms_c++ algorithms-程序员宅基地

STL中的算法提供了丰富的功能,包括常用算法介绍和时间、空间复杂度的选择。在编写程序时需根据具体问题选择适当的算法,满足时间或空间需求。

【计算机网络学习笔记04】网络体系架构与网络协议_网络体系以及网络协议的定义和内容。-程序员宅基地

文章浏览阅读1.4w次。【计算机网络学习笔记04】网络体系架构与网络协议一、网络协议的概念和要素网络协议是计算机网络相互通信的对等层实体之间,用来交换信息时必须遵守的规则或约定的集合。这些为网络数据交换而制定的通信规则、约定与标准被统称为网络协议,简称协议。网络协议主要由三个基本要素组成,分别是语法、语义和时序。语法:用于定义数据和控制信息的结构或格式。语义:用于解释数据或控制信息的具体含义。时序(同步):用于对事件实现顺序的详细说明。二、计算机网络体系结构计算机网络各层、层中协议以及层间接口的集合(即网络层次_网络体系以及网络协议的定义和内容。

【测试】echo发送和接收TCP/UDP数据包|shell 发送TCP/UDP数据包_shell脚本接收udp-程序员宅基地

文章浏览阅读7.6k次,点赞2次,收藏14次。目录通过/dev/tcp、/dev/udpshell给tcp或udp服务发送16进制报文指令通过/dev/tcp、/dev/udp(https://blog.csdn.net/u010039418/article/details/86251470)通过/dev/tcp、/dev/udp可以直接在shell脚本中发起tcp、udp连接,方便又高效,平时用于测试啥的还是挺方便的。直接发送格式 /dev/udp/ip/port比如要向本地10001端口发送数据,可以使用ec._shell脚本接收udp

Pytorch学习笔记09——多分类问题_pytorch normalize mean, std-程序员宅基地

文章浏览阅读639次,点赞2次,收藏5次。pytorch多分类问题_pytorch normalize mean, std

学习open62541 --- [15] 使用建模工具UaModeler-程序员宅基地

文章浏览阅读1.2w次,点赞120次,收藏55次。讲述如何使用建模工具UaModeler_uamodeler

Linux里的防火墙:netfilter简介与Iptables的使用(上)_netfilter (policy drop)-程序员宅基地

文章浏览阅读3.6k次。什么是防火墙?防火墙可以是像360,金山,卡巴斯基等软件,也可以是硬件,我们来用OSI七层模型来划分的话。那么分为:1. 三层防火墙:它只负责检查数据从进入到第三层,还有从第三层流出,是否符合它规定的条件,如果是,那么就放行,反之就拦截。2.七成防火墙:它_netfilter (policy drop)