天天看点

《FFmpeg从入门到精通》读书笔记(四)

写在前面

2019.06.23

第五章 FFmpeg流媒体

第五章 FFmpeg流媒体

一、FFmpeg发布与录制RTMP流

知识点:RTMP
实时消息协议(英语:Real-Time Messaging Protocol,缩写RTMP)也称实时消息传输协议,
是最初由Macromedia为通过互联网在Flash播放器与一个服务器之间传输流媒体音频、视频
和数据而开发的一个专有协议。Macromedia后被Adobe Systems收购,该协议也已发布了不完整的规范供公众使用。
RTMP协议有许多变种:
1.默认使用TCP端口1935的纯粹(plain)协议。
2.RTMPS,通过一个TLS/SSL连接传输RTMP。
3.RTMPE,使用Adobe自有安全机制加密的RTMP。虽然实现的细节为专有,但该机制使用行业标准的密码学原函数。
4.RTMPT,用HTTP封装以穿透防火墙。RTMPT通常在TCP通信端口80和443上使用明文请求来绕过大多数的公司流量过滤。封装的会话中可能携带纯粹的RTMP、RTMPS或RTMPE数据包。
5.RTMFP, 使用UDP而非TCP的RTMP,取代RTMP Chunk Stream。Adobe Systems开发了安全的实时媒体流协议包,可以让最终用户直接地相互连接(P2P)。
虽然RTMP的主要动机是成为一个播放Flash视频的协议,但它也用于其他一些应用程序,如Adobe LiveCycle Data Services ES。
           
FFmpeg拉取RTMP的主要参数 (书 P152)

1.rtmp_app String RTMP流发布点,又称为APP

// 设置RTMP的推流发布点
ffmpeg -rtmp_app live -i rtmp://publish.chinaffmpeg.com -c copy -f flv output.flv

// 发布流
ffmpeg -re -i input.mp4 -c copy -f flv -rtmp_app live rtmp://publish.chinaffmpeg.com
           
《FFmpeg从入门到精通》读书笔记(四)
《FFmpeg从入门到精通》读书笔记(四)

Note:书中此处给出的正确返回应该是:Server error : identify stream failed. 搜索了一下我的error,找到了RTMP_ReadPacket, failed to read RTMP packet header,RTMP服务拒绝了我们的请求。接下来还是继续按照书中的步骤来整理,就假设返回的是识别失败~

出现Server error : identify stream failed的原因是尚未设置stream项导致,但是设置app是正确的。

2. rtmp_playpath String RTMP流播放的Stream地址,或者成为密钥,或者成为发布流

设置rtmp_app时可以看到提示了identity stream failed错误,通过使用rtmp_playpath参数设置来解决该错误

// 推流
ffmpeg -re -i input.mp4 -c copy -f flv -rtmp_app live -rtmp_playpath class rtmp://publish.chinaffmpeg.com

// 播放RTMP流
ffmpeg -rtmp_app live -rtmp_playpath class -i rtmp://publish.chinaffmpeg.com -c copy -f flv output.flv
           
《FFmpeg从入门到精通》读书笔记(四)

之所以能够成功地推流与拉流,是因为设置了rtmp_app与rtmp_playpath。如果认为设置这两个参数很麻烦,可以直接设置在RTMP连接中,如:

ffmpeg -i input.mp4 -c copy -f flv rtmp://publish.chinaffmpeg.com/live/class
           
《FFmpeg从入门到精通》读书笔记(四)

3.rtmp_pageurl String RTMP在Connect命令中设置的PageURL字段,其为播放时所在的Web页面URL

rtmp_swfurl String RTMP的Connect命令中设置的swfURL播放器的URL

rtmp_tcurl String RTMP的Connect命令中设置的tcURL目标发布点地址,一般形如rtmp://xxx.xxx.xxx/app

在RTMP的Connect命令中包含了很多Object,这些Object中有一个pageUrl,例如通过页面的FlashPlayer进行播放。在使用FFmpeg时,默认不会在Connect命令中携带pageUrl字段,可以使用rtmp_pageurl来设置这个字段,例如:

ffmpeg -rtmp_pageurl "http://www.chinaffmpeg.com" -i rtmp://publish.chinaffmpeg.com/live/class
           

同理,可设置swfUrl参数以及tcUrl参数

二、FFmpeg录制RTSP流

知识点:RTP
实时传输协议(Real-time Transport Protocol或简写RTP)是一个网络传输协议,
它是由IETF的多媒体传输工作小组1996年在RFC 1889中公布的。
国际电信联盟ITU-T也发布了自己的RTP文档,作为H.225.0,但是后来当IETF发布了
关于它的稳定的标准RFC后就被取消了。它作为因特网标准在RFC 3550(该文档的旧版本是RFC 1889)有详细说明。
RFC 3551(STD 65,旧版本是RFC 1890)详细描述了使用最小控制的音频和视频会议。
RTP协议详细说明了在互联网上传递音频和视频的标准数据包格式。它一开始被设计为一个多播协议,
但后来被用在很多单播应用中。RTP协议常用于流媒体系统(配合RTSP协议),
视频会议和一键通(Push to Talk)系统(配合H.323或SIP),使它成为IP电话产业的技术基础。
RTP协议和RTP控制协议RTCP一起使用,而且它是创建在UDP协议上的。
           
知识点:RTSP
实时流协议(Real Time Streaming Protocol,RTSP)是一种网络应用协议,专为娱乐和通信系统的使用,
以控制流媒体服务器。该协议用于创建和控制终端之间的媒体会话。媒体服务器的客户端发布VCR命令,
例如播放,录制和暂停,以便于实时控制从服务器到客户端(视频点播)或从客户端到服务器(语音录音)的媒体流。
流数据本身的传输不是RTSP的任务。大多数RTSP服务器使用实时传输协议(RTP)和
实时控制协议(RTCP)结合媒体流传输。然而,一些供应商实现专有传输协议。
例如,RealNetworks公司的RTSP服务器软件也使用RealNetworks的专有实时数据传输(RDT)。
RTSP由RealNetworks公司,Netscape公司 [1] 和哥伦比亚大学开发,第一稿于1996年提交给IETF。
由互联网工程任务组(IETF)的多方多媒体会话控制工作组(MMUSIC WG)进行了标准化,
并于1998年发布为RFC 2326。[3] RTSP 2.0 于2016年发布为RFC 7826,作为RTSP 1.0的替代品。
RTSP 2.0基于RTSP 1.0,但不是在基本版本协商机制之外的向后兼容。
虽然在某些方面与HTTP类似,RTSP定义了控制多媒体播放控制顺序。虽然HTTP是无状态的,
但RTSP具有状态; 当需要跟踪并发会话时使用标识符。像HTTP一样,RTSP使用TCP来维护端到端连接,
而大多数RTSP控制消息由客户端发送到服务器,一些命令沿着另一个方向(即从服务器到客户端)传播。
           
RTSP参数 (书 P159)

1.rtsp_transport flag 设置RTSP的传输协议

FFmpeg默认使用的RTSP拉流方式为UDP,但丢包会导致花屏、绿屏、灰屏、马赛克等问题。使用RTSP拉流时,采用UDP方式经常会因为拉流丢包出现异常,所以在实时性与可靠性适中时,可以采用TCP方式进行拉流。

ffmpeg -rtsp_transport tcp -i rtsp://47.90.47.25/test.ts -c copy -f mp4 output.mp4
           

2.rtsp_flags flag RTSP使用标记

filter_src:只接收指定IP的流

listen:设置为被动接收模式

prefer_tcp:TCP亲和模式,如果TCP可用则首选TCP传输

3.allowed_media_types flag 设置允许接收的数据模式

默认允许的接收模式为全开启,可选项有video、audio、data、subtitle

4.user-agent String 用户客户端标识

设置该字段进行区分访问的是不是自己访问的流

ffmpeg -user-agent "DengzimingZhenNiub" -i rtsp://input:554/live/1/stream.sdp -c copy -f mp4 -y output.mp4
           

三、FFmpeg录制HTTP流

HTTP参数(书 P163)

FFmpeg的HTTP既可以作为客户端使用,也可以作为服务端使用。

1.seekable boolean 设置HTTP链接为可以seek操作

在使用FFmpeg打开直播或者点播文件时,可以通过seek操作进行播放进度移动、定位等操作

// seekable 为 0,ss制定了seek的时间位置,会处于阻塞状态
ffmpeg -ss 300 -seekable 0 -i http://bbs.chinaffmpeg.com/test/ts -c copy output.mp4

// seekable 为 1,正常执行
ffmpeg -ss 300 -seekable 1 -i http://bbs.chinaffmpeg.com/test/ts -c copy output.mp4
           

2.headers String 自定义HTTP Header数据

使用FFmpeg拉取HTTP数据时,自己设置HTTP的header,例如设置referer字段:

ffmpeg -headers "referer: http://bbs.chinaffmpeg.com/index,html" -i http://play.chinaffmpeg.com/live/class.flv -c copy -f flv -y output.mp4
           
知识点:CRLF
CRLF是Carriage-Return Line-Feed的缩写,意思是回车换行,就是回车(CR, ASCII 13, \r) 换行(LF, ASCII 10, \n)。换行在有的ASCII码表也用newline(简nl)来进行表示,这里的lf是line feed的概念,意思是一样的。
           

3.user-agent String 设置HTTP请求客户端信息

在使用FFmpeg进行HTTP连接时,HTTP服务器会对连接的客户端进行记录和区分,例如使用的什么浏览器(IE、Firefox、Chrome等);

而在流媒体中,常见的User-Agent还包括Android的StageFright、iOS的QuickTime等;

而在FFmpeg进行HTTP连接时,可以使用User-Agent添加自己的特殊标识,例如:

ffmpeg -user_agent "Johnny Deng's Player" -i http://bbs.chinaffmpeg.com/1.flv
           
HTTP拉流录制
// 拉取FLV直播流录制成FLV
ffmpeg -i http://bbs.chinaffmpeg.com/live.flv -c copy -f flv output.flv
// 拉取TS直播流录制成FLV
ffmpeg -i http://bbs.chinaffmpeg.com/live.ts -c copy -f flv output.flv
// 拉取HLS直播流录制成FLV
ffmpeg -i http://bbs.chinaffmpeg.com/live.m3u8 -c copy -f flv output.flv
           

四、FFmpeg录制和发布UDP、TCP流

TCP与UDP参数(书 P166-167)

1.listen int 作为Server时监听TCP的端口

// 打开两个终端进行操作:
// 推流
ffmpeg -re -i input.mp4 -c copy -f flv tcp://127.0.0.1:1234/live/stream
// 监听流
ffmpeg -listen 1 -f flv -i tcp://127.0.0.1:1234/live/stream -c copy -f flv output.flv
           

监听的端口为1234,指定输出的格式为FLV格式

《FFmpeg从入门到精通》读书笔记(四)
《FFmpeg从入门到精通》读书笔记(四)

2.listen_timeout int 作为Server时监听TCP端口的超时时间(毫秒)

例如:设置5秒超时时间

ffmpeg -listen_timeout 5000 -listen 1 -f flv -i tcp://127.0.0.1:1234/live/stream -c copy -f flv output.flv
           

3.timeout int 获得数据超时时间(微秒)

使用TCP拉取直播流时,经常会遇到TCP服务端没有数据却不主动断开连接的情况,导致客户端持续处于连接状态不断开。通过设置timeout,例如超过20s没有数据则退出:

ffmpeg -timeout 20000000 -i tcp://127.0.0.1:1234/live/stream -c copy -f flv output.flv
           

4.send_buffer_size int 通过socker发送的buffer大小

recv_buffer_size int 通过socket读取的buffer大小

buffer设置的越小,传输就会越频繁,网络开销就会越大:

ffmpeg -re -i input.mp4 -c copy -send_buffer_size 265 -f flv tcp://127.0.0.1:1234/live/stream
           

执行后数据发送的速度会变慢,频率变高,次数变多,网络开销变大; 同时输出的帧率也会下降

5.localport int 本地端口

使用FFmpeg的UDP传输时,默认会由系统分配本地端口,使用该参数可以自己设置:

ffmpeg -re -i input.mp4 -c copy -localport 23456 -f flv udp://127.0.0.1:1234/live/stream
           

小结:FFmpeg的TCP和UDP传输常见于TCP或UDP的网络裸传输场景,例如很多编码器常见的传输方式为UDP传输MPEGTS流,使用FFmpeg进行TCP和UDP传输的参数也还在不断更新中。

五、FFmpeg推多路流

管道方式输出多路流

转码一次,输出多个封装

ffmpeg -i input -acodec aac -vcodec libx264 -f flv - | ffmpeg -f mpegts -i --c copy output1 -c copy output2 -c copy output3
           

例如:

ffmpeg -i input.mp4 -acodec aac -vcodec libx264 -f flv - | ffmpeg -f mpegts -i - -c copy -f flv rtmp://publish.chinaffmpeg.com/live/stream1 -c copy -f flv rtmp://publish.chinaffmpeg.com/live/stream2
           
《FFmpeg从入门到精通》读书笔记(四)

我自己操作的结果,返回了pipe:0: could not find codec parameters问题,在网上找到的回答时MP4不适合管道传输:

《FFmpeg从入门到精通》读书笔记(四)
tee封装格式输出多路流
ffmpeg -re -i input.mp4 -acodec aac -vcodec libx264 -map 0 -f tee "[f=flv]rtmp://publish.chinaffmpeg.com/live/stream1 | [f=flv]rtmp://publish.chinaffmpeg.com/live/stream2"
           
《FFmpeg从入门到精通》读书笔记(四)
tee协议输出多路流

tee封装格式的简化写法,直接使用tee协议输出多路流:

ffmpeg -re -i input.mp4 -acodec aac -vcodec libx264 -f flv "tee:rtmp://publish.chinaffmpeg.com/live/stream1|rtmp://publish.chinaffmpeg.com/live/stream2"
           

六、FFmpeg生成HDS流

知识点:HDS
HTTP Dynamic Streaming通过对来自RTMP端的“流”进行包装处理,转化成HTTP“流”提供给客户端解析,
用户再也不用下载整个文件,同时又能使用HTTP协议进行快速观看视频。
           

HDS相关(一)之 HTTP Dynamic Streaming 学习笔记(原理篇)

《FFmpeg从入门到精通》读书笔记(四)
HDS参数(书 P177)

1.window_size int 设置HDS文件列表的最大文件数

设置HDS为直播模式时,需要实时更新列表,通过该参数控制文件列表窗口大小; 默认不控制列表窗口大小。

ffmpeg -i input -c copy -f hds -window_size 4 output
           

2.extra_window_size int 设置HDS文件里表之外的文件保留数

控制列表之外的残留文件数目

ffmpeg -i input -c copy -f hds -window_size 4 -extra_window_size 1 output
           

3.min_frag_duration int 设置切片文件市场(微秒)

remove_at_exit boolean 生成HDS文件退出时删除所有列表及文件

七、FFmpeg生成DASH流

知识点:DASH
基于HTTP的动态自适应流(英语:Dynamic Adaptive Streaming over HTTP,缩写DASH,
也称MPEG-DASH)是一种自适应比特率流技术,使高质量流媒体可以通过传统的HTTP
网络服务器以互联网传递。类似苹果公司的HTTP Live Streaming(HLS)方案,MPEG-DASH
会将内容分解成一系列小型的基于HTTP的文件片段,每个片段包含很短长度的可播放内容,
而内容总长度可能长达数小时(例如电影或体育赛事直播)。内容将被制成多种比特率的
备选片段,以提供多种比特率的版本供选用。当内容被MPEG-DASH客户端回放时,
客户端将根据当前网络条件自动选择下载和播放哪一个备选方案。
客户端将选择可及时下载的最高比特率片段进行播放,从而避免播放卡顿或重新缓冲事件。
也因如此,MPEG-DASH客户端可以无缝适应不断变化的网络条件并提供高质量的播放体验,
拥有更少的卡顿与重新缓冲发生率。
MPEG-DASH是首个基于HTTP的自适应比特率流解决方案,它也是一项国际标准。
MPEG-DASH不应该与传输协议混淆——MPEG-DASH使用TCP传输协议。
MPEG-DASH使用现有的HTTP网络服务器基础设施。它允许如互联网电视、电视机顶盒、
台式计算机、智能手机、平板电脑等设备消费通过互联网传送的多媒体内容(如视频、电视、广播等),
并可应对变动的互联网接收条件。自适应流解决方案的标准化是为向市场提供信心,
使该解决方案可以用于通用部署,抗衡类似但更专有的解决方案,如微软Smooth Streaming与Adobe的HDS。
不同于HLS、HDS和Smooth Streaming,DASH不关心编解码器,因此它可以接受任何编码格式编码的内容,如H.265、H.264、VP9等。
           
DASH参数(书 P180)

1.window_size int 索引文件中文件的条目数

extra_window_size int 索引文件之外的切片文件保留数

ffmpeg -re -i input.mp4 -c:v copy -acodec copy -f dash -window_size 4 -extra_window_size 5 index.mpd
           
《FFmpeg从入门到精通》读书笔记(四)
《FFmpeg从入门到精通》读书笔记(四)

2.single_file boolean 设置切片为单文件模式

FFmpeg支持生成DASH时将切片列表中的文件写入到一个文件

ffmpeg -re -i input.mp4 -c:v copy -acodec copy -f dash -window_size 4 -extra_window_size 5 -single_file 1 index.mpd
           
《FFmpeg从入门到精通》读书笔记(四)
《FFmpeg从入门到精通》读书笔记(四)