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 参数_使用FFMPEG进行视频转码相关推荐

  1. ffmpeg学习(13)音视频转码(2)使用filter

    ffmpeg学习(10)音视频文件muxer(1)封装格式转换 中介绍了媒体文件的封装格式转换,ffmpeg学习(11)音视频文件muxer(2)多输入混流 中介绍了音视频的混流,本文介绍基于ffmp ...

  2. ffmpeg命令_使用ffmpeg命令为多个短视频修改视频备注说明

    今天主要给大家讲一下使用视频剪辑高手中的ffmpeg命令为多个短视频修改备注说明的详细步骤,有需要和感兴趣的宝贝们可以跟随小编一起来试试. 收集视频 将需要剪辑的短视频保存到同一文件夹上 进入软件 双 ...

  3. python调用ffmpeg合并_用ffmpeg命令处理mp4剪切与合并

    1. 剪切: ./ffmpeg -ss 00:00:06 -t 00:00:12 -i input.mp4 -vcodec copy -acodec copy output.mp4 意思是从截取从6秒 ...

  4. SpringBoot 实现大文件视频转码(转码基于FFMPEG实现)

    最近项目需要将用户上传的视频如果不是MP4格式,需要全部转码为MP4格式的,这里我通过FFMPeg进行大文件视频转码的实现. 一.安装FFMPeg 首先我们需要在机器上安装FFMPeg用于我们的视频转 ...

  5. ffmpeg webm 提取_ffmpeg简单使用教程 转码、压制、提取、截取、合并、录屏等

    1.查看帮助文档 ffmpeg是一个开源的音视频转码工具 本文是自己学习ffmpeg使用方式的一个笔记 将ffmpeg命令行工具加入环境变量之后,输入ffmpeg -h打印帮助文档 PS C:\Use ...

  6. 七彩cms云转码_七彩CMS视频转码 2019云转码彻底开源系统版本号

    源代码详细介绍 自然环境规定:nginx 1.16.2,php7.2,mariadb10.3 视頻情况一直是"已经等候转换格式",这个是因为ffmpeg沒有管理权限.视频转码要采用 ...

  7. 抖音短视频源码中视频排序模块热门列表解决方案

    我们都知道,在短视频APP中会有推荐列表,不同短视频APP的推荐机制是不同的,有聚集流量的"中心化"推荐方式,也有对新手友好的"去中心化"推荐机制. 中心化推荐 ...

  8. ffmpeg 硬件解码rtsp流_树莓派使用硬件加速视频转码

    现在随着智能设备普及以及宽带的升级,越来越的的视频素材在不断的产生.无论是我们自己拍摄的视频,还是从网上收集来的电影.电视剧,并不是全部都值得我们保存最高清的版本.打个比方,比如你下载了一个 1080 ...

  9. ffmpeg rtmp 花屏_使用FFMPEG进行视频转码

    Note: 此文章首发于我的个人博客zhi-hua.wang ,开放转载但需附上出处. 使用FFMPEG进行视频转码 - 日落孤城​www.zhi-hua.wang FFMPEG 是一款开源的视频处理 ...

最新文章

  1. Kaggle HousePrice : LB 0.11666(排名前15%), 用搭积木的方式(一,原理)
  2. [转]关于安卓与ios的推送系统,我说说自己的看法。
  3. 重置mysql密码的命令
  4. 【Qt】2D绘图之涂鸦板
  5. 买铅笔(洛谷-P1909)
  6. 【bzoj2929】[Poi1999]洞穴攀行 网络流最大流
  7. groovy 使用java类_深入学习java中的Groovy 和 Scala 类
  8. css3 rem的用法
  9. python实现通讯录的增删改查_python实现数据库增删改查
  10. 7月5日服务器临时维护更新公告,封印战记7月5日更新什么? 7月5日临时更新维护公告...
  11. 目前M院M师的教学乱象
  12. delphi mysql类_Delphi MySQL数据库操作类
  13. rhino编程语言c井,Rhino插件开发:RhinoScript脚本教程(4):VBScript基础
  14. CAPL基础知识学习
  15. 教你同时分析DPD多个单号的物流信息
  16. Ionic之自定义icon大小
  17. 计算机学院刘岗,中科院金属所刘岗研究员访问城市环境研究所
  18. Python 爬虫下载图片两种方法
  19. 普通工程师和高级工程师的差别在哪里?如何快速突破?
  20. 植物大战僵尸(6):查找植物叠加种植CALL

热门文章

  1. 重力传感器 测重力代码_“重力瀑布”如何帮助您教授孩子的密码学基础知识...
  2. Python实现定时任务,定时采集数据,定时执行脚本程序都可以
  3. 用python偷偷给班级群女同学的颜值进行排名,排最后的大姐说开学要打爆我
  4. LAB Color Space
  5. Pytorch《DCGAN模型》
  6. [机器学习-实践]支持向量机(SVM)从例子代码中学习
  7. 计算 期望与方差(mean and Variance)在 Tensorflow 与 Numpy 对比
  8. 0 full gc时cpu idle_Go语言中如何观察GC
  9. iris数据集_sklearn日志(二)训练集和测试集划分
  10. 混合模型简介与高斯混合模型