FFmpeg是一个开源免费跨平台的视频和音频流方案,它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多codec都是从头开发的。FFmpeg在Linux平台下开发,但它同样也可以在其它操作系统环境中编译运行。
本篇除了会涉及到音频相关参数,但不会有音频相关操作或者详细解析,主要是针对图片与视频本身进行命令总结,不过在此之前,我想总结一下图片和视频的一些相关介绍。
说到图片自然最常见的是RGB,关于RGB,它的色彩模式是工业界的一种颜色标准,是通过对红®、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色,而在我们保存图片下的格式png、jpg等默认都是以RGB进行存储,一般没有提供YUV格式的图片保存,那么什么是YUV呢?简单来说,YUV 和我们熟悉的 RGB 差不多,都是颜色编码方式,只不过它们的三个字母代表的意义与 RGB 不同,YUV 的 “Y” 表示明亮度(Luminance或Luma),也就是灰度值;而 ”U” 和 ”V” 表示的则是色度(Chrominance或Chroma),描述影像色彩及饱和度,用于指定像素的颜色。
常见的YUV的采样有YUV444,YUV422,YUV420:
更详细的定义可以参阅以下链接,介绍得很详细以及还有ffmpeg源码解读。
如何理解 YUV ?
所以我们可以知道了YUV格式,而RGB和YUV格式在ffmpeg里的转换命令如下,具体源码部分怎么转的可以看上面的链接:
ffmpeg -i picture4.jpg -s 1080x720 -pix_fmt yuv420p picture4.yuv
ffplay -f rawvideo -video_size 1080x720 picture4.yuv
ffmpeg的语法格式以及大致的一些基本参数为:
ffmpeg [[options][`-i’ input_file]]… {[options] output_file}…
参数 | 说明 |
---|---|
-vcodec codec | 强制使用codec编解码方式(‘copy’ to copy stream) |
-newvideo | 在现在的视频流后面加入新的视频流 |
-s 320x240 | 指定分辨率 |
-ac <数值> | 设定声道数,1就是单声道,2就是立体声 |
-ar <采样率> | 设定声音采样率,PSP只认24000 |
-vol <百分比> | 设定音量 |
-y | 覆盖输出文件 |
-b < bitrate> | 指定压缩比特 |
-r fps | 设置帧频 缺省25 |
-bitexact | 仅使用位精确算法 用于编解码测试 |
-bufsize size | 设置码率控制缓冲区大小 |
-maxrate / -minrate < bitrate> | 设置最大 / 最小视频码率容忍度 |
知道了语法,这里还有一些常用的设置或者图片命令,这里记录一下:
# 把darkdoor.[001-100].jpg序列帧和001.mp3音频文件利用mpeg4编码方式合成视频文件darkdoor.avi:
$ ffmpeg -i 001.mp3 -i darkdoor.%3d.jpg -s 1024x768 -author skypp -vcodec mpeg4 darkdoor.avi
# 要查看你的ffmpeg支持哪些格式,可以用如下命令:
$ ffmpeg -formats | less
# 还可以把视频文件导出成jpg序列帧:
$ ffmpeg -i bc-cinematic-en.avi example.%d.jpg
# 输出 YUV420P 原始数据
$ ffmpeg -i test.mp4 test.yuv
# 从视频前10s中提取图像,1s提取一帧
$ ffmpeg -i test.mp4 -t 10 -r 1 -f image2 pic-%03d.jpeg
# 截取一张352x240尺寸大小的,格式为jpg的图片
$ ffmpeg -i test.asf -y -f image2 -t 0.001 -s 352x240 a.jpg
# 把视频的前30帧转换成一个Animated Gif
$ ffmpeg -i test.asf -vframes 30 -y -f gif a.gif
# 截取指定时间的缩微图,-ss后跟的时间单位为秒
$ ffmpeg -i test.avi -y -f image2 -ss 8 -t 0.001 -s 350x240 test.jpg
由于rtmp和rtsp没有研究多久,我这里主要引用一篇大佬文章:
一、什么是RTSP
RTSP(Real Time Streaming Protocol)实时流传输协议。是 TCP/IP 协议体系中的一个应用层协议,RTSP在体系结构上位于RTP和RTCP之上,它使用TCP或UDP完成数据传输如下图1所示。
二、RTSP、RTP、RTCP之间关系
RTSP发起/终结流媒体、RTP传输流媒体数据、RTCP对RTP进行控制、同步。如图2所示
三、RTSP交互过程
RTSP分为服务器与客户端,RTSP协议定义了服务器-客户端之间的接口,主要有OPTIONS,DESCRIBE,SETUP,PLAY,TEARDOWN,RECOED,ANNOUNCE。RTSP并不包括具体数据的传输,该功能一般由RTP与RTCP协议来实现,并可以通过TCP或UDP两种底层传输方式进行。
RTSP协议–图文解释
另外mark一篇写得很详细的关于rtsp流整个协议的组成结构博文:
EasyDarwin开源社区流媒体视频课程:流媒体传输控制协议(RTSP RTP SDP)详解之RTSP
直播协议 | 优势 | 劣势 |
---|---|---|
RTP /RTCP | RTP 实行有序传送,RTP中的序列号允许接收方重组发送方的包序列,同时序列号也能用于决定适当的包位置,如在视频解码中,就不需要顺序解码。RTCP的主要功能是为RTP所提供的服务质量提供反馈,例如:RTP传输字节数,传输分组数,丢失分组数,单向和双向网络延迟等。网络应用程序可以利用RTCP所提供的信息来提高服务质量,比如限制流量或改用压缩比小的编解码器 | RTP载荷的最大尺寸为1460字 节。以H264 为例,如果一帧数据大于1460,则需要分片打包,然后到接收端再拆包,组合成一帧数据,进行解码播放。 |
RTSP:(Real Time Streaming Protocol)实时流协议 | RTSP 是一种双向实时数据传输协议,它允许客户端向服务器端发送请求,如回放、快进、倒退等操作。而且,RTSP 可基于RTP 来传送数据,还可以选择 TCP、UDP、组播 UDP 等通道来发送数据,具有很好的扩展性 | 1.服务端实现复杂。2.代理服务器弱:数量少,优化少3. 无路由器防火墙穿透。4. 管流分离:需要1-3个通道 |
RTMP协议(Real Time Messaging Protocol)实时消息传输协议 | RTMP是Adobe Systems公司为Flash播放器和服务器之间音频、视频和数据传输开发的开放协议。该协议基于TCP,RTMP是一种设计用来进行实时数据通信的网络协议,主要用来在Flash/AIR平台和支持RTMP协议的流媒体/交互服务器之间进行音视频和数据通信。1.速度快,误码率低,延迟低 。2.RTMP 是专为流媒体服务而生,协议在制定的时候就考虑到很多底层的优化3.消息块的传输能够提供更加稳定的直播环境,在硬件上要求会更高,但是却能够缓解http的繁琐的传输介质 | 1.不支持Html5传播、浏览器推送 2.基于TCP协议,虽然开发难度大,推广度还不够,对于开发人员来说门槛比较高 3.硬件要求相较于HLS较高。 4. 协议复杂:开发者写起来累,效率也不行。5.Cache麻烦:流协议做缓存不方便。 |
HTTP-FLV协议 | FLV协议由Adobe公司主推,即将音视频数据封装成 FLV,然后通过 HTTP 协议传输给客户端,格式极其简单,只是在大块的视频帧和音视频头部加入一些标记头信息,在延迟表现和大规模并发方面都很成熟。但是在手机浏览器上的支持非常有限,但是用作手机端APP直播协议却异常合适。 | 1.需要http长连接 2.h5中需要使用插件。3.需要flash技术支持,不支持多音频流,多视频流,不便于拖动 |
HLS协议 | HLS协议苹果推出,将视频分成5-10秒的视频小分片,然后用m3u8索引表进行管理,由于客户端下载到的视频都是5-10秒的完整数据,故视频的流畅性很好,但也同样引入了很大的延迟(HLS的一般延迟在10-30s左右)。实际上还是纯“文本协议”相比于FLV,HLS在iPhone和大部分android手机浏览器上的支持非常给力。HLS协议客户端支持简单, 只需要支持 HTTP 请求即可, HTTP 协议无状态, 只需要按顺序下载媒体片段即可,而且网络兼容性好, HTTP 数据包也可以方便地通过防火墙或者代理服务器。但是相比RTMP 这类长连接协议, 用到互动直播场景延时较高。 | 相比 RTMP 这类长连接协议, 延时较高, 难以用到直播场景。对于点播服务来说, 由于 TS 切片通常较小, 海量碎片在文件分发, 一致性缓存, 存储等方面都有较大挑战,小文件碎片化严重 |
具体的关于rtsp和rtmp的区别我觉得还是得去看看底层,目前以我的理解,rtsp和rtmp虽然实现都比较复杂,但在我的实验里面,rtsp比rtmp误错率高,误码率没仔细观察过,但应该也会高一点,难道因为它是管流分离的,需要1-3个通道,而rtmp只需要一个?或者我用的是rtmp-Nginx和srs,根据GitHub中大牛直播SDK,它们都是RTMP的服务器,而RTSP的是Darwin Stream Server,但我的问题是出现在解码,在同等情况下,多路RTSP的掉线情况永远比多路RTMP的测试高,这个也是我纠结了一两天无果,最后多加了一层rtsp转rtmp的逻辑而没有再对rtsp进行直接解码,然后问题得到缓解,如果有大佬知道为什么,可以私信我或者在评论区回复。
在上面关于ffmpeg图片相关的操作下的参数表格这里做得并不全面,只是列了一些常用的,更多的以及解释可以看看wiki会有所收获:
https://zh.wikipedia.org/wiki/FFmpeg
ffmpeg -re -i test.mp4 -vcodec libx264 -acodec aac -f flv rtmp://localhost:1935/live/fff01
这里能推srs是因为我在本地搭建了srs服务器,关于搭建可以看我之前的博文,这里不再介绍,另外加了-vcodec libx264其实就已经在转码了,ffmpeg默认是flv,如果要获取到mp4的支持,需要安装libx264,这个也在srs搭建那篇博文有写。
下面引用一些常用的命令,mp4和avi相关:
# 分离视频流 / 音频流
ffmpeg -i input_file -vcodec copy -an output_file_video
ffmpeg -i input_file -acodec copy -vn output_file_audio
# 视频解复用
ffmpeg –i test.mp4 –vcodec copy –an –f m4v test.264ffmpeg –i test.avi –vcodec copy –an –f m4v test.264
# 转码为码流原始文件
ffmpeg –i test.mp4 –vcodec h264 –s 352*278 –an –f m4v test.264
ffmpeg –i test.mp4 –vcodec h264 –bf 0 –g 25 –s 352*278 –an –f m4v test.264
# 转码为封装文件
ffmpeg –i test.avi -vcodec mpeg4 –vtag xvid –qsame test_xvid.avi
# 视频录制
ffmpeg –i rtsp://localhost:1935/test –vcodec copy out.avi
# mp4视频转flv
ffmpeg -i test.mp4 -acodec copy -vcodec copy -f flv test.flv
ts相关:
# H264视频转ts视频流
ffmpeg -i test.h264 -vcodec copy -f mpegts test.ts
# ts视频转mp4
ffmpeg -i test.ts -acodec copy -vcodec copy -f mp4 test.mp4
# udp视频流的推送
ffmpeg -re -i 1.ts -c copy -f mpegts udp://192.168.0.106:1234
# 切割ts分片
ffmpeg -i input.mp4 -c:v libx264 -c:a aac -strict -2 -f hls -hls_list_size 6 -hls_time 5 output1.m3u8
YUV相关:
# YUV序列播放
ffplay -f rawvideo -video_size 1920x1080 input.yuv
# YUV序列转AVI
ffmpeg –s w*h –pix_fmt yuv420p –i input.yuv –vcodec mpeg4 output.avi
# 从第0帧开始截取30帧
ffmpeg -s widthxheight -i input.yuv -c:v rawvideo -filter:v select="gt(n\, -1)" -vframes 30 out30.yuv
# 或者 0 - 30
ffmpeg -s widthxheight -i input.yuv -c:v rawvideo -filter:v select="between(n\, 0\, 29)" out30.yuv
ffmpeg 推流端可以通过一些控制参数来降低推流的延迟,主要优化方向是提高编码的效率、减少缓冲大小,当然有时候要牺牲一些代码质量和带宽。 关于ffmpeg 的转码延时测试与设置优化,总结了一些优化措施可以参考一下:
前面的我没有尝试,后面几个参数,我之前是查到一篇关于-preset参数的实验,最后说是加-preset ultrafast和-tune zerolatency能达到速度延迟在0.2 ~ 0.6间,经过我实验确实有效,在多进程下能提高ffmpeg的消费情况。
关于ffmpeg中使用GPU,因为目前是两大主流显卡:AMD和NVIDIA,我这里主要用的NVIDIA的,然后它的官网中是有关于自家支持ffmpeg使用的NVENC和h264:
它主要是和CPU下的libx264对比:
Preset | NVENC | libx264 |
High Quality | -c:v h264_nvenc -preset medium -b:v BITRATE -bufsize BITRATE*2 -profile:v high -bf 3 -b_ref_mode 2 -temporal-aq 1 -rc-lookahead 20 -vsync 0 | -c:v libx264 -preset medium -b:v BITRATE -bufsize BITRATE*2 -profile:v high -tune psnr -vsync 0 -threads 4 |
Low Latency Fast | -c:v h264_nvenc -preset llhp -rc cbr_ld_hq -b:v BITRATE -bufsize BITRATE/FRATE -profile:v high -g 999999 -vsync 0 | -c:v libx264 -preset fast -b:v BITRATE -bufsize BITRATE/FRATE -profile:v high -g 999999 -x264opts no-sliced-threads:nal-hrd=cbr -tune zerolatency -threads 4 -vsync 0 |
Turing H.264 Video Encoding Speed and Quality
可以从Performance and Quality Results 质量检测结果中发现h264的各种性能都高于x264,但我个人实际体验过程中发现并没有多少优越性,画质上差不多,可能x264还要快一点?。。(狗头),其实里面线段还是很接近的,这里只能说仁者见仁智者见智,这个问题引用知乎的讨论帖:
GPU转码效果为什么不如纯CPU?
而关于GPU下的使用命令,可以看看wiki,它详细的描述了ffmpeg对GPU的可靠性还有一系列参数对接:
https://trac.ffmpeg.org/wiki/HWAccelIntro
只要能编译成功,命令同样很简单,我之前的文章也写过编译以及测试,这里引用几个上面链接中的命令:
# Sample decode using CUDA:
ffmpeg -hwaccel cuda -i input output
# Sample decode using CUVID:
ffmpeg -c:v h264_cuvid -i input output
# Full hardware transcode with NVDEC and NVENC:
ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input -c:v h264_nvenc -preset slow output
# If ffmpeg was compiled with support for libnpp, it can be used to insert a GPU based scaler into the chain:
ffmpeg -hwaccel_device 0 -hwaccel cuda -i input -vf scale_npp=-1:720 -c:v h264_nvenc -preset slow output.mkv