本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/14355015.html
libswscale 源码分析系列文章:
1. FFmpeg libswscale源码分析1-API介绍
2. FFmpeg libswscale源码分析2-转码命令行与滤镜图
3. FFmpeg libswscale源码分析3-scale滤镜源码分析
4. FFmpeg libswscale源码分析4-libswscale源码分析
源码分析基于 FFmpeg 4.1 版本。
2. 转码命令行与滤镜图
本节从 ffmpeg 转码命令开始,引入一个完整的示例:hevc yuv422p10le 源软解硬编为 hevc yuv420p10le 视频。
第 2 节、第 3 节、第 4 节是由上到下分层的关系。第 2 节介绍命令行,通过命令行调用 ffmpeg 进程。第 3 节介绍 scale 滤镜,ffmpeg 进程使用了 scale 滤镜,scale 滤镜中会调用 libswscale 库。第 4 节介绍 libswscale 库。
查看 ffmpeg 中 hevc_nvenc 支持的像素格式:
代码语言:javascript复制[root@node0 ~]# ffmpeg -hide_banner -h encoder=hevc_nvenc | grep "pixel formats"
Supported pixel formats: yuv420p nv12 p010le yuv444p p016le yuv444p16le bgr0 rgb0 cuda
在如下代码 for 循环处打断点,分析滤镜图中的各个滤镜输入输出像素格式:
代码语言:javascript复制static int graph_config_links(AVFilterGraph *graph, AVClass *log_ctx)
{
AVFilterContext *filt;
int i, ret;
for (i = 0; i < graph->nb_filters; i ) {
filt = graph->filters[i];
if (!filt->nb_outputs) {
if ((ret = avfilter_config_links(filt)))
return ret;
}
}
return 0;
}
不显式指定滤镜的转码命令:
代码语言:javascript复制ffmpeg -hide_banner -y -re -i ./hevc_4k_422_10b_5994_60m_vibe.ts
-c:v hevc_nvenc -preset fast -profile:v main10 -c:a aac -f mpegts /dev/null
滤镜图如下:
代码语言:javascript复制 yuv422p10le yuv422p10le yuv444p16le yuv444p16le
[buffer] -----> [null] -----> [scale] -----> [format] -----> [buffersink]
ffmpeg 自动插入滤镜,协商滤镜格式。buffer 滤镜输出的格式是 ffmpeg hevc 解码器解码输出的图像像素格式,是 yuv422p10le。buffersink 滤镜的输入格式,是 ffmpeg 在 buffersink 滤镜前插入 format 滤镜,在执行 format 滤镜初始化时,从 hevc_nvenc 编码器支持的像素格式列表中,选定了 yuv444p16le,作为编码器的输入格式。由 scale 滤镜执行像素格式转换操作:yuv422p10le 转为 yuv444p16le。
通过滤镜指定格式 yuv420p10le:
代码语言:javascript复制ffmpeg -hide_banner -y -re -i ./hevc_4k_422_10b_5994_60m_vibe.ts -vf format=yuv420p10le
-c:v hevc_nvenc -preset fast -profile:v main10 -c:a aac -f mpegts /dev/null
滤镜图如下:
代码语言:javascript复制 yuv422p10le yuv420p10le yuv420p10le p010le p010le
[buffer] ------> [scale] ------> [format] ------> [scale] ------> [format] ------> [buffersink]
第三个滤镜 format 是我们在命令行中给出的滤镜。第五个滤镜 format 是编码器输入格式滤镜,是 ffmpeg 在滤镜图与编码器间进行像素格式协商时,在 hevc_nvenc 编码器支持的像素格式列表中,选择了 p010le 像素格式作为编码器的输入格式,并在此 format 滤镜前自动插入一个 scale 滤镜执行像素格式转换。
可以看到,一个像素格式转换,在命令行中是由一个 scale 滤镜紧跟一个 format 滤镜实现的,scale format 滤镜可由用户在命令中显式给出,ffmpeg 也会根据实际情况按需插入。
通过滤镜指定格式 p010le:
代码语言:javascript复制ffmpeg -hide_banner -y -re -i ./hevc_4k_422_10b_5994_60m_vibe.ts -vf format=p010le
-c:v hevc_nvenc -preset fast -profile:v main10 -c:a aac -f mpegts /dev/null
滤镜图如下:
代码语言:javascript复制 yuv422p10le p010le p010le p010le
[buffer] ------> [scale] ------> [format] ------> [format] ------> [buffersink]
第三个滤镜 format 是我们在命令行中给出的滤镜。第四个滤镜 format 是编码器输入格式滤镜,是 ffmpeg 在滤镜图与编码器间进行像素格式协商时,在 hevc_nvenc 编码器支持的像素格式列表中,选择了 p010le 像素格式作为编码器的输入格式。第二个滤镜 scale 执行实际的像素格式转换操作:yuv422p10le 转 p010le。