用 FFmpeg 制作视频滚动效果

ffmpeg -i input.mp4 -filter_complex "split[o1][o2];[o1]select=between(n\,0\,100),scroll=h=0.01[oo1];[o2]select=gt(n\,100),setpts=N/FR/TB[oo2];[oo1][oo2]concat=n=2:v=1" -map 0:a output.mp4

把输入 mp4 前 100 帧做成由右到左的滚动效果。

scroll 的速率是每帧行进的视频宽/高的百分比。0.01 即每帧位移 0.01 * width 像素,所以整个滚动效果需要 100 帧。

note:

1) 第二段 select,必须从 0 重新计算 pts,否则拼接时候效果不对;
2) 此法只适合短小视频操作,因为所有滤镜效果都缓存在内存;
3) scroll 是 FFmpeg4.3 版本新加入的滤镜效果,用前确认版本。

用 FFmpeg 实现画中画效果

ffmpeg -i input1.mp4 -stream_loop -1 -i input2.gif -filter_complex overlay=shortest=1 output.mp4

把 gif 放在 mp4 的左上角。-stream_loop -1 指示 gif 不断循环,否则 gif 会停留在最后一帧;shortest=1 指示 overlay 操作在任意一个输入读取到文件尾时结束。

note: stream_loop 是输入项参数,所以要放在要应用的输入的后面。

用 FFmpeg 制作 GIF

ffmpeg -y -ss 1:33:28 -t 22 -i input.mp4 -vf "scale=iw*0.3:ih*0.3,drawtext=x=(w-text_w)/2:y=h-40:fontsize=30:fontcolor=white:fontfile=C\\:/Windows/Fonts/STXINWEI.TTF:text='这是文字'" -r 15 output.gif

从 input.mp4 的 1:33:28 处开始截取 22 秒;输出尺寸缩小到输入的 0.3 倍;在输出图的中下部分添加文字,文字样式为白色、30像素、新魏;把输出 gif 图的帧率设为 15。

note:

1) 多个 filter 效果以,拼接,且以出现的先后顺序逐个应用到输出上。所以,drawtext 里用到的wh是缩放后的尺寸;
2) 注意fontfile值的表现方式。

用 FFmpeg 下载视频

ffmpeg -i "https://us.sinaimg.cn/0013JKJ9jx07aaEhInRC0104010094440k01.mp4?label=mp4_hd&Expires=1579700718&ssig=wkpUBmK%2B9Y&KID=unistore,video" d:\output.mp4

从 -i 标识的 url 下载视频保存到 output.mp4。

note: url 包含特殊字符(空格、& 等)时,必须用双引号包含 url 才能正确解析;输出路径同理。

用 FFmpeg 剪辑视频片段

ffmpeg -ss 300 -t 600 -i c:\input.mp4 c:\output.mp4

从 input.mp4 的 300s 处开始剪辑,时长 600s,保存到 output.mp4。

note: -ss -t 参数都可应用于输入或输出(ffmpeg -i c:\input.mp4 -ss 300 -t 600 c:\output.mp4)上,区别在于:-ss 应用于输入时有性能优势,会先跳转到时间点再进行解码;用于输出时会逐帧解码并丢弃时间点前的所有帧。

用 FFmpeg 录屏

1
ffmpeg -f gdigrab -video_size 1280x720 -offset_x 120 -offset_y 140 -show_region 1 -i desktop -c:v libx264 -preset:v ultrafast -t 10 output.mp4

从屏幕 (120,140) 像素起抓取 1280x720 尺寸的屏幕画面,时长 10 秒。-show_region 1 会在屏幕上显示一个抓取范围的矩形提示框。

note: gdigrab 只适用 Windows 系统,且只抓取画面没有声音。

FFmpeg Wiki 有关于录屏更全面的介绍。

用 FFmpeg 给 mp4 添加封面

1
ffmpeg -i input.mp4 -i cover.png -map 0 -map 1 -c copy -disposition:v:1 attached_pic output.mp4

将图片 cover.png 做为 input.mp4 的封面图。

关键是 -disposition:v:1 attached_pic 这句,即把 map 后的第二个视频流( cover.png )做为 output.mp4 的封面。

FFmpeg 编码 H264 视频码率过高问题解决方法

转码 mp4 的时候发现,输出的 H264 视频流码率高达 10M kbps+,而源码率只有约 2M kbps,这明显是不对的。明明已经通过 AVCodecContext::bit_rate 字段设定了码率却没有生效。

通过这篇 wiki,找到了答案。H264 有一套很复杂的码控规范,不能简单通过一个固定的码率数值指定输出码率——H264 基本上做不到这么精确的码控。推荐做法是启用 CRF 码控,设置合适的压缩率:

1
2
3
4
5
6
// 启用 CRF 码控
// CRF 参数值取值范围为 [0,51]。0 为无损,51 最差;23 是 libx264 默认值。
if (codec->id == AV_CODEC_ID_H264)
{
av_opt_set_int(_context, "crf", 23, AV_OPT_SEARCH_CHILDREN);
}

avcodec_open2() 之前加入上边代码块,输出视频流码率下降明显。

2020年度总结

2020 年是动荡的一年。不光是宏观的社会因素的层面上,单就我的工作内容来说,也很动荡。

2020 年学习计划大半泡了汤。年初发愿要以最高优先级对待的 StreamingCore 项目也彻底停滞。工作内容跟直播越来越无关,搞得我也没多大心思再去钻研相关技术;还总是犯懒,三天打鱼两天晒网,又喜欢东一锄头西一耙的瞎搞。

上班时…

上半年…

上半年工作内容集中在 Unity 上,开发 VR 眼镜直播客户端。收获颇丰。

阅读更多

C++17 几个新的语言特性

1. 结构化绑定声明

绑定指定名称到初始化器的子对象或元素。 通俗地讲,对形如 std::pairstd::tuple 或自定义聚合类型的实例,可以声明一组变量直接指向其成员,无需创建一个对应聚合类型的临时变量:

1
2
3
4
std::pair<int, int> point{ 0, 1 };
// some operations around point
// ...
auto [x, y] = point; // x equals to point.first; y equals to point.second
阅读更多