Note: 此文章首发于我的个人博客zhi-hua.wang ,开放转载但需附上出处。

使用FFMPEG进行视频转码 - 日落孤城​www.zhi-hua.wang

FFMPEG 是一款开源的视频处理软件,再利用FFMPEG转码的过程中踩了很多坑,在这里列举一些常用的 FFMPEG 命令防止忘记。

以下所有的命令的输入都是《The.Mandalorian.S01E01.INTERNAL.HDR.2160p.WEB.H265-DEFLATE.mkv》这部影片,这部影片有很多特殊的地方,所以给我带来了不少困扰。它也驱使我学习了关于视频的很多知识,以下是它的一些基本参数:

视频
格式                            : HEVC
格式配置 (Profile)              : Main 10@L5@High
时长                            : 38 分 46 秒
码率                            : 15.9 Mb/s
宽度                            : 3 840 像素
高度                            : 1 608 像素
原始高度                    : 2 160 像素
帧率模式                        : 恒定帧率 (CFR)
帧率                            : 23.976 (24000/1001) FPS
色彩空间                        : YUV
色度抽样                         : 4:2:0
位深                            : 10 位
数据密度 [码率/(像素*帧率)]       : 0.108
流大小                      : 4.32 GiB (94%)
色彩范围                         : Limited
色彩原色                         : BT.2020
传输特性                         : PQ
矩阵系数                         : BT.2020 non-constant

这部影片是 4K HDR10 影片,编码方式为 HEVC,像素格式为 yuv420p10le,容器分辨率为 3840X2160,实际分辨率为3840X1608,色彩范围( color range )为TV( Limited ),色彩原色( color primaries )为 bt2020,传输特性为smpte2084( PQ ),矩阵系数(color matrix )为 bt2020nc 。为了节省篇幅,以下均以input.mkv代表这个视频源文件。而且由于配备了gtx1070显卡以及安装了最新的驱动,所有的操作都是尽量利用GPU进行硬件加速。

1. 转为720p(失败)

为了达到最好的性能,我准备使用hevc_cuvid进行解码,scale_npp进行视频缩放,hevc_nvenc进行编码。-hwaccel cuvid 告诉ffmpeg使用cuvid加速,并且把视频的数据保留在显存而不是内存上。由于版权问题ffmpeg不自带scale_npp滤镜,需要自己编译。为了方便我选择manjaro系统,直接安装AUR上的ffmpeg-full包。这个过程也很心酸,可以专门写一篇文章了,这里就不展开了。关于ffmpeg转码的文章在互联网上有很多,尤其是英伟达官网的《ffmpeg transcoding guide》建议好好读一读。

ffmpeg -hwaccel cuvid -c:v hevc_cuvid -i input.mkv -c:a copy -vf scale_npp=1280:720 -c:v hevc_nvenc -b:v 5M output.mkv

运行以上命令却报错了。原来scale_npp滤镜很娇气,无法处理10bit的视频,因此尝试失败。

2. 转为720p (format, scale_npp:48fps)

既然无法处理10bit,那我把它转成8bit呗。上format滤镜,将yuv420p10le转为yuv420p。由于format是软件滤镜,因此取消-hwaccel cuvid 。这样解码的视频会自动转存到内存。format处理好的内容使用hwupload_cuda上传到GPU,然后通过scale_npp缩放,之后通过hevc_nvenc编码。

ffmpeg -c:v hevc_cuvid -i input.mkv -c:a copy -vf "format=yuv420p,hwupload_cuda,scale_npp=1280:720" -c:v hevc_nvenc -b:v 5M output.mkv

输入以上命令,发现咋只有48fps呢?那岂不是要十几分钟?太慢了!

3. 转为720p (scale_cuda:227fps)

突然发现了scale_cuda这个宝藏,它能接受10bit输入。而且scale_cuda在ffmpeg的编译版中自带!这就好办了,赶紧敲下以下命令:

ffmpeg -hwaccel cuvid -c:v hevc_cuvid -i input.mkv -c:a copy -vf scale_cuda=1280:720 -c:v hevc_nvenc -b:v 5M output.mkv

所有任务都转到GPU上运行了,性能得到巨大提升。通过观察发现此时的瓶颈变为了GPU解码。GPU解码器的占用率高局100%,而编码器只占用了不到20%。

4. 转为720p 8bit (pix_fmt:失败)

ffmpeg -hwaccel cuvid -c:v hevc_cuvid -i input.mkv -c:a copy -vf scale_cuda=1280:720   -c:v hevc_nvenc -pix_fmt yuv420p -b:v 5M output.mkv

然而它报错:

Impossible to convert between the formats supported by the filter 'Parsed_scale_cuda_0' and the filter 'auto_scaler_0'
Error reinitializing filters!
Failed to inject frame into filter network: Function not implemented
Error while processing the decoded data for stream #0:0

5.转为720p 8bit (pix_fmt:223fps)

经过长时间的试错,发现之前的错误通过在scale_cuda滤镜后添加hwdownload,format=p010le就可以解决了,至于为啥我也不知道 。-hwaccel_output_format cuda目前可以不加,只不过会警告你以后不加就会报错了。

ffmpeg -hwaccel cuvid -hwaccel_output_format cuda  -c:v hevc_cuvid -i input.mkv -c:a copy -vf "scale_cuda=1280:720,hwdownload,format=p010le" -c:v hevc_nvenc  -pix_fmt yuv420p  -b:v 5M output.mkv

6.用resize缩放而不是scale_cuda或scale_npp (resize:225fps)

这一条与上一条没多大的区别,只是把scale_cuda改为了resize。resize这个参数是我从英伟达官网上的一篇pdf上了解到的,它说用resize性能好一些。至于好不好我不知道,我只知道resize更易读与打出来。

ffmpeg -hwaccel cuvid -hwaccel_output_format cuda  -c:v hevc_cuvid -resize 1280x720 -i input.mkv -c:a copy -vf "hwdownload,format=p010le" -c:v hevc_nvenc  -pix_fmt yuv420p  -b:v 5M output.mkv

7.固定质量模式

之前的转码都是恒定码率模式,很不科学。hevc_nvenc没有crf参数,这可咋办呢?好在找到了替代方案。通过将-rc:v 设置为vbr或者vbr_hq,从而启用VBR模式,然后设置-cq:v-qmin-qmax。这里最好把它们设置成一个数值,否则没有多大意义。这个数值接类似于crf参数。

ffmpeg -hwaccel cuvid -c:v hevc_cuvid -resize 1280x720  -i input.mkv -c:a copy  -vf "hwdownload,format=p010le"  -c:v hevc_nvenc -pix_fmt yuv420p -rc:v vbr -cq:v 20 -qmin 20 -qmax 20 output.mkv

8.颜色偏差--HDR转SDR(tonemap_opencl)

经过前面这么多的折腾,视频已经压制好了。可是越看越不对劲。为啥我压的视频看起来灰蒙蒙的呢?经过深入调查发现是由于HDR导致的。这个视频本身是HDR的,而转换过程中ffmpeg并没有保留HDR有关的元数据(这应该是个BUG),又没进行颜色的转换。所以播放器把这个HDR视频当作SDR来处理,就会导致画面发灰。解决办法有两种,一是将其转为SDR,这需要tonemap滤镜(似乎scale滤镜也可以)。另一种是保留元数据,让播放器能够正常处理。这里选择第一种。由于tonemap是运行在cpu上的,效率低,所以我改用它的硬件加速版:tonemap_opencl

http://ffmpeg.org/ffmpeg-filters.html#tonemap_005fopencl​ffmpeg.org

注意下面的命令我只在linux上测试成功过,win10会报错,我也不知道为什么。

ffmpeg -hwaccel cuvid -init_hw_device opencl=ocl -filter_hw_device ocl -extra_hw_frames 3  -c:v hevc_cuvid -resize 1280x720  -i input.mkv -c:a copy  -vf "hwupload,tonemap_opencl=tonemap=mobius:param=0.01:desat=0:r=tv:p=bt709:t=bt709:m=bt709:format=nv12,hwdownload,format=nv12"  -c:v hevc_nvenc  -rc:v vbr -cq:v 20 -qmin 20 -qmax 20 output.mkv

tonemap_opencl的这些参数中,tonemap指定了使用的算法,可选值为nonecliplineargammareinhardhablemobius。param是用来微调这些算法的。具体的内容看ffmpeg的文档。这里最重要的是将p、t以及m都设置为了bt709。所以这个滤镜会完成以下转换:色彩原色: bt2020->bt709、传输特性:smpte2084->bt709、矩阵系数:bt2020nc->bt709 (HDR有多种不同标准,smpte2084对应的是HDR10。 经过HDR->SDR的转换,颜色终于变得正常了,不过仔细看肯定和原片有差距。可以根据画面的特色选用不同的算法和参数来进行调整,以保证画面的准确度。

9. 颜色偏差--添加HDR元数据(失败)

上一节我们将HDR转为了SDR,画面的准确度有些许丢失。那该怎么办呢?之前说到还有一种方法,那就是保留元数据。我尝试过用MKVToolNix将色彩原色、传输特性以及矩阵系数分别设置为9、16和9。然后这个视频在linux上播放正常了,但是在windows上还是灰的。我真的是很无语!!!

YouTubeHDR/hdr_metadata​github.com

我在github上还找到了另外一个项目,叫做nv_hevc_hdr_patcher。但是这个项目看起来挺不好用的,我懒得折腾,所以HDR元数据添加宣告失败(怎么可能这么轻易放弃,下一节会用其它工具搞定这个问题(如果我还会继续写的话(会吗?)))

SK-Hardwired/nv_hevc_hdr_patcher​github.com

总结

使用FFMPEG,在尽量利用硬件加速的情况下完成了视频的压制。直接转码时会丧失HDR元数据,导致发灰(见下图中间一栏)。通过tonemap可以将HDR转为SDR视频,画面的颜色得到较为准确的还原,但还是有轻微的差别。最终也没能够完成HDR元数据的添加。

原片
直接压片,元数据丢失导致发灰
tonemap转为SDR后颜色恢复

ffmpeg rtmp 花屏_使用FFMPEG进行视频转码相关推荐

  1. ffmpeg rtmp 花屏_音视频系列6:ffmpeg多线程拉流

    本文与csdn博客同步:https://blog.csdn.net/Hanghang_/article/details/105302384,欢迎关注,点赞,评论. 前言 本篇博客是音视频系列的续集与改 ...

  2. ffmpeg 切片花屏_利用ffmpeg解码H264,花屏,该如何解决

    利用ffmpeg解码H264,花屏 UINT CMP4File::VideoCap_Thread_Fun(void* pParam) { CMP4File  *pMP4File=(CMP4File*) ...

  3. ffmpeg rtmp 花屏_iphone6splus花屏闪屏,iphone6sp换屏价格

    人们之所以会购买iPhone,大多数用户是因为它有非常高清的屏幕.一个高清的屏幕,不仅对大家的视力损害小,而且会有一个非常好的使用体验.但是手机一旦出现屏幕跳屏.花屏竖条的情况,会极大的影响人们对手机 ...

  4. ffmpeg rtmp 花屏_FFmpeg视频抽帧那些事

    视频文件是多媒体数据中比较常见的一种,也是入门门槛比较高的一个领域.视频数据相关的领域任务包括视频物体检测.视频物体追踪.视频分类.视频检索和视频摘要抽取等. 视频数据与图像数据非常类似,都是由像素点 ...

  5. ffmpeg rtmp 花屏_FFmpeg代码架构

    FFmpeg模块分类 打开FFmpeg源码,会发现有一系列libavxxx的模块,这些模块很好地划分了代码的结构和分工. libavformat,format,格式封装 libavcodec,code ...

  6. ffmpeg rtmp 花屏_FFmpeg - 如何编码封装透明通道视频

    最近项目在做一个功能,需要把动态的视频添加到静态图片上面,使得图片看起来有一层会动态变化的前景.本次项目涉及安卓和 iOS 两个不同平台.由于使用常规的方法不能够做出想要的效果,我特意去学习了视频制作 ...

  7. ffmpeg命令 抓屏_使用FFmpeg从视频中截图的命令 | 学步园

    截取一张352x240尺寸大小的,格式为jpg的图片: ffmpeg -i test.asf -y -f image2 -t 0.001 -s 352x240 a.jpg 把视频的前30帧转换成一个A ...

  8. 最简单的基于FFmpeg的移动端样例:IOS 视频转码器

    ===================================================== 最简单的基于FFmpeg的移动端样例系列文章列表: 最简单的基于FFmpeg的移动端样例:A ...

  9. 各种RTMP直播流播放权限_音视频_数据花屏_问题检测与分析工具EasyRTMPClient

    之前的一篇博客<网络摄像机IPCamera RTSP直播播放网络/权限/音视频数据/花屏问题检测与分析助手EasyRTSPClient>,我们介绍了RTSP流的检测和分析工具EasyRTS ...

最新文章

  1. Windows和Linux的编译理解
  2. java之==和equals区别
  3. C - 数据结构实验之排序三:bucket sort(水题)
  4. 干掉 Swagger,试试这个!
  5. linux默认归档目录,Linux系统管理(第4章:目录和文件管理二)
  6. ISCSI 1-由零开始
  7. 浅谈javascript数值类型转换
  8. 【连载】Django入门到实战(一)
  9. JavaSE Collections类 , Iterator迭代器 , 增强for循环
  10. Linux嵌入式开发_修改镜像文件输出路径
  11. 白板推导系列Pytorch-朴素贝叶斯
  12. UVM_COOKBOOK学习【Testbench Architecture】
  13. 面向初学者的 40 多个 Python 项目——开始编写 Python 代码的简单想法
  14. 游戏建模:21个人脑壳雕刻小小技巧,非常有用!
  15. 一、Jmeter总结
  16. 【U3D入门小白教程——案例篇】之一:球吃豆
  17. VDO-SLAM: A Visual Dynamic Object-aware SLAM System论文笔记
  18. 美多商场之图形验证码
  19. HAL 编程问题手记
  20. MATLAB 文件未关联解决方法

热门文章

  1. [学习笔记]后缀数组
  2. ping网站服务器,ping命令的作用,ping真能检测出服务器的快慢吗??
  3. JS下载PDF、图片时直接下载而不是预览
  4. 爱奇艺推荐系统架构与实践
  5. Appium----基于Ubuntu系统安装个人版免费的Android模拟器Genymotion模拟器
  6. cadence allegro 之如何隐藏/显示单个DRC
  7. 解决Windows运行游戏提示缺少steam_api.dll的问题
  8. CentOS 7安装并启动Google浏览器
  9. 文件管理(操作系统)
  10. echarts自定义地图总结(VUE)