video_replay如何捕获和回放WebRTC视频流

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 视频编码问题常常是最难解决的问题之一,video_replay工具可以帮助分析定位故障。

640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1

视频编码问题常常是最难解决的问题之一,video_replay工具可以帮助分析定位故障。视频协作平台pixip的工程师Stian Selnes撰文,详解了如何通过video_replay来捕获、分析视频的。LiveVideoStack对本文进行了摘译。


文 / Stian Selnes

译 / 刘庆超


在数据包有丢失的环境下进行视频解码不是一件容易的事。Chrome 58中引入了一种新的视频抖动缓冲区,这导致最新版的Chrome在视频显示时一直有问题。由于该问题只在某些数据包丢失时才会出现,因此调试难度很大。为此,webrtc.org提供了一个名为video_replay的工具来复现和分析这些棘手问题。


当看到Stian Selnes提交的一个版本中视频显示仍然有问题时,我将这个工具告诉了他。将视频流轻松重现后,谷歌的WebRTC视频团队很快就解决了这个bug。不过,这一过程的记录做得不是很好,所以我们请Stian重现了抓取必要数据和使用该工具进行操作的过程。Stian目前在pexip工作,他有超过10年的实时通信处理经验。他在媒体协议栈领域有非常丰富的经验,特别是在视频编解码以及其他类型的信号处理、网络协议和错误恢复能力等方面。


640?wx_fmt=png


WebRTC包含了一个非常好用但鲜为人知的工具——video_replay。事实证明,在调试视频解码问题时,这个工具非常好用。它的目的是什么呢?为了在发现异常行为之后能容易地重复捕获WebRTC呼叫,video_replay将捕获的RTP流视频作为输入文件,然后离线使用WebRTC框架来解码数据,最后在屏幕上显示输出的结果。


例如,最近我正在研究一个问题,有一个版本的Chrome显示输入的视频时突然出了上面这样的问题。最终,使用video_replay调试后,WebRTC的团队发现,Chrome中实现抖动缓冲区的部分出现了一个错误,这导致视频流在某些情况下显示会有异常。这种看似随机数据导致的错误其实是VP8解码器的内部状态引起的。

 

640?wx_fmt=png


视频编码问题常常是最难解决的问题之一。最初,我自己写了一个测试方法,每20次调用中大约复现1次这样的问题。使用这种方法重现问题是非常耗时的,效果通常也不好,最终也没有给WebRTC团队解决该问题起到什么作用。


为了可以多次重现这个问题,我设法使用wireshark捕获到一个失败的呼叫,然后使用video_replay工具来分析。这样我就有了一个每次都能重现这个罕见的问题测试用例。当一个问题具有重复性的时候,解决问题和打补丁就非常轻松啦!这是典型的双赢局面。


在这篇文章中,我将通过一个例子来演示如何使用video_replay,包括如何来捕捉一个WebRTC呼叫的RTP通信数据,识别和提取接收到的视频流,最后如何导入到video_replay中来实现在屏幕上显示捕获的视频。


捕获未加密的RTP数据


video_replay将输入的文件导入到RTP协议栈、协议包解析设备和解码器中,不过目前还没有能力解密加密呼叫使用的SRTP包。Chrome和Firefox都支持加密呼叫,但是解密WebRTC呼叫却不是一个简单的过程。尤其是SRTP进行秘钥分发时使用DTLS来保密共享,因此该秘钥难以获得。为此,最好用Chromium或Chrome Canary,因为它们有一个可以禁用SRTP加密的选项。启动浏览器时添加命令行标志–disable-webrtc-encryption即可,如果在窗口的顶部看到警告信息,说明你使用的浏览器不支持命令行标志。注意,这要求双方在通话都不能加密,否则会话将无法连接。


首先,使用Wireshark捕获数据包。在会话开始发送媒体数据之前就要打开捕获功能,这一点很重要,因为这可以将整个流都能记录下来。如果捕获的数据中丢失了流的开头,视频解码器将无法解码。


第二,打开一个选项卡,进入chrome://webrtc-internals (或者Fippo最新的webrtc-externals).。呼叫之前首先做这个,以获取所有需要的信息,特别是SDP协商信息(如果想深入分析该问题,请见webrtchacks SDP分析指导)。


最后,就是呼叫了。我们以appr.tc为例,但适用于任何使用WebRTC的呼叫。打开第二标签进入https://appr.tc/?IPv6 = false。由于目前video_replay尚没有IPv6相关的解决方案,因此在这个例子中,我将其禁用,希望该问题能很快解决。


现在,加入一个直播室。当第二个参与者加入同一个房间时,RTP将开始流动。不管谁先加入,除非chrome://webrtc-internals看起来有异常。下面的截图是在拨号进入现有房间时拍摄的。


收集信息


为了从接收到的流中成功获得RTP包,并能顺利使用video_replay播放,我们需要收集一些关于RTP流的细节信息。有几种方法可以做到这一点,我坚信最重要的是下面这几个:


  • Video codec 视频编码

  • RTP SSRC  RTP SSRC

  • RTP payload types RTP 载荷类型

  • IP address and port  IP地址和端口


使用webrtc-internals来收集统计信息 


首先,扩大接收到的视频流的统计表,给一个类似于ssrc_4075734755_recv这样的命名。统计表可能不止一个,一般第二个是音频流,还可能有一对以_send为后缀的表,里面是发送流的等效统计信息。视频流接收的统计表可以根据_recv后缀和mediaType=video来识别出来。分别记下ssrc、googCodecName 和transportId属性,例如4075734755、VP9和channel-audio-1。


你可能会问为什么的视频流和音频通道有相同的transportid?这表示使用了BUNDLE来使音频和视频共享通道。如果BUNDLE没有协商和使用,音频和视频将使用单独的通道。

 

640?wx_fmt=png


下一步,我们将查看协商的SDP以获得RTP有效载荷类型(PT)。除了PT使用的视频编解码器,我们还必须找到RED的PT标记,这个PT是WebRTC用来封装的视频包的。SDP描述了视频客户端的接收能力,因此为了找到接收到的有效负载类型,我们必须查看浏览器向另一个参与者提供的SDP类型。


这可以通过扩展的setlocaldescription API调用找到,找到M =video的部分和后面每个支持的编解码器的PT的rtpmap定义。由于我们的视频编解码器的VP9,我们会关注的属性是a=rtpmap:98 / 90000和a= rtpmap:102 red/9000,这告诉我们,VP9和RED的有效载荷类型分别为98和102。

 

640?wx_fmt=png


如果你正在寻找发送流而不是接收的信息,你应该看看其他参与者通过setRemoteDescription的扩展字段标记了什么。事实上,载荷字段的类型应该是对称的,所以无论你看setlocaldescription或setremotedescription无关紧要,但在实时视频通信的世界,没人什么都知道,所以最好是都看一下。


为了在Wireshark中快速确定正确的RTP流,需要知道IP地址和使用端口。远程或本地地址并不重要,只要使用适当的wireshark过滤就行。对于这个示例,我们将使用本地地址,因为我们希望提取所接收的流,所以它是数据包的目的地。在chrome://webrtc-internals 的Conn-audio  和 Conn-video部分包含了连接的统计信息。处于活跃状态的用粗体突出显示,根据上一步提到的transportid我们就可以知道要看视频还是音频通道。


为了在我们的例子中找到本地地址,我们需要扩大conn-audio-1-0,并且注意googlocaladdress,其值为10.47.4.245:52740。


640?wx_fmt=png


Wireshark中的RTP标记


现在,为了在我们的呼叫中方便地识别和提取所接收的视频流,我们已经收集了所有必要的信息。Wireshark可能会将捕获的RTP数据包简单地以UDP数据包来显示。我们想告诉Wireshark这些是RTP包,所以我们可以将其导出为rtpdump格式。


首先,使用地址和端口显示过滤器,例如ip.dst = = 10.47.4.245和udp.dstport = = 52740。然后,右击一个数据包,选择解码为,然后选择RTP。


其次,选择菜单电话→RTP →RTP流,列出列表中的所有RTP流。我们接收到的视频流中的SSRC连同其他流的一起列出来,选择并导出为rtpdump格式。(video_replay还支持PCAP格式,但由于其对各种链路层的支持非常有限,我一般推荐使用rtpdump。)最后我们有一个文件只包含接收的视频数据包,可以将其导入到video_replay中。


640?wx_fmt=png640?wx_fmt=png


建立WebRTC 和 video_replay


使用之前,需要从WebRTC源码生成video_replay。如何设置环境、获取代码和编译等一般性的说明可以从https://webrtc.org/native-code/development中查到。注意,为了能生成video_replay工具,在编译时需要将其明确指定为一个目标。总之,在确定必要的软件已经安装了之后,下面的命令可以获得代码和生成video_replay:


 
  

1mkdir webrtc-checkout
2cd webrtc-checkout/
3fetch --nohooks webrtc
4gclient sync
5cd src
6gn gen out/Default
7ninja -C out/Default video_replay


使用video_replay重放捕捉信息


最后重播捕获的流,并希望之前它是如何在appr.tc中的状态可以准确地显示出来。我们的示例做到这一点的最小命令行是:


1out/Default/video_replay -input_file received-video.rtpdump -codec VP9 -media_payload_type 98 -red_payload_type 102 -ssrc 4075734755

(注意:媒体payload_type参数之前命名为payload)


根据之前的说明, 命令行的参数也非常容易理解。


video_replay参数


如果你的目标是重现WebRTC出现问题后的bug,对于某些问题,将rtpdump连同命令行参数一起进行重放将有巨大的帮助。如果你想多做一些自己的video_replay调试,有几个命令行选项可能会很有用。


让我们看看当前的帮助文本并解释不同选项的作用。编写这一文件时,../../webrtc/video/replay.cc的标记有如下:


 
  

1-abs_send_time_id (RTP extension ID for abs-send-time) type: int32 default: -1
2-codec (Video codec) type: string default: "VP8"
3-decoder_bitstream_filename (Decoder bitstream output file) type: string default: ""
4-fec_payload_type (ULPFEC payload type) type: int32 default: -1
5-input_file (input file) type: string default: ""
6-out_base (Basename (excluding .yuv) for raw output) type: string default: ""
7-payload_type (Payload type) type: int32 default: 123
8-payload_type_rtx (RTX payload type) type: int32 default: 98
9-red_payload_type (RED payload type) type: int32 default: -1
10-ssrc (Incoming SSRC) type: uint64 default: 12648429
11-ssrc_rtx (Incoming RTX SSRC) type: uint64 default: 195939069
12-transmission_offset_id (RTP extension ID for transmission-offset) type: int32 default: -1


下面是关于它们的更多解释:


640?wx_fmt=png


快捷方法


当你熟悉上面的过程时,你可以使用一些快捷方式来提高效率。首先,你可以使用Wireshark中查看RTP视频包而不必使用chrome://webrtc-internals。大多数视频包通常超过1000字节,而音频数据包一般也就几百字节。将解码的视频数据包使用RTP协议在Wireshark中处理,可以同时显示SSRC和有效载荷类型。Wireshark不能自动确定是RED有没有用,但是可以从经验中猜到,因为有效载荷类型一般不会在通话之间改变。


其次,如果你的video_replay支持pcap,你可以将原有pcap直接导入video_replay中。由于忽略了所有未知的数据包,命令行输出可能会有很多错误,但它可以解码并显示指定的流。


WebRTCon 2018 8折报名


WebRTCon希望与行业专家一同分享、探讨当下技术热点、行业最佳应用实践。如果你拥有音视频领域独当一面的能力,欢迎申请成为讲师,分享你的实践和洞察,请联系 speaker@livevideostack.com。更多详情扫描下图二维码

640?wx_fmt=jpeg

目录
打赏
0
0
0
0
41
分享
相关文章
同一路RTSP|RTMP流如何同时回调YUV和RGB数据实现渲染和算法分析
我们播放RTSP|RTMP流,如果需要同时做渲染和算法分析的话,特别是渲染在上层实现(比如Unity),算法是python这种情况,拉两路流,更耗费带宽和性能,拉一路流,同时回调YUV和RGB数据也可以,但是更灵活的是本文提到的按需转算法期望的RGB数据,然后做算法处理
iOS平台RTMP|RTSP播放器如何实时回调YUV数据
我们在做RTMP、RTSP播放器的时候,有开发者需要自己处理拉取到的YUV数据,做二次分析之用,为此,我们做了以下的设计:InitPlayer之后,再调用SmartPlayerStart()接口之前,设置yuv数据回调即可。
104 6
Android平台如何实现多路低延迟RTSP|RTMP播放?
本文档详细介绍了大牛直播SDK在Android平台上实现RTSP与RTMP流媒体播放及录像功能的技术细节。早在2015年,SDK的第一版就已经支持了多实例播放,并且通过简单的实例封装就能轻松实现。文档中提供了代码示例,展示了如何开启播放、停止播放以及开始和停止录像等功能。此外,SDK还提供了丰富的配置选项,例如设置录像目录、文件大小限制、转码选项等。总结部分列出了该SDK的关键特性,包括但不限于高稳定性和低延迟的播放能力、多实例支持、事件回调、硬解码支持、网络状态监控以及复杂的网络环境处理等。这些功能使得SDK能够应对各种应用场景,特别是在对延迟和稳定性有极高要求的情况下表现优异。
152 5
低延迟播放超高分辨率(4K+)帧率(50帧+)RTSP|RTMP流技术探讨和实现
为满足安检等场景需求,需支持4K+分辨率与50帧以上的高帧率视频流播放。实现这一目标的关键步骤包括:确保视频源支持高帧率输出、选用高性能RTSP/RTMP播放器以处理高负载视频解码、采用硬件解码以降低CPU负担、保证充足的网络带宽以维持流畅播放并控制延迟、合理配置播放器缓冲策略以适应网络波动、进行性能监控与调试以优化播放效果,以及确保播放器在多平台上的良好兼容性和表现。例如,大牛直播SDK的SmartPlayer在不同平台上实现了稳定且低延迟(150-300ms)的播放体验,支持多种视频和音频格式及多种功能,如多实例播放、事件回调、视频快照等。
229 1
探讨TCP传输视频流并利用FFmpeg进行播放的过程
探讨TCP传输视频流并利用FFmpeg进行播放的过程
843 0
深入理解FFmpeg音视频编程:处理封装、解码、播放 队列与回放策略
深入理解FFmpeg音视频编程:处理封装、解码、播放 队列与回放策略
419 0
海康摄像头开发笔记(一):连接防爆摄像头、配置摄像头网段、设置rtsp码流、播放rtsp流、获取rtsp流、调优rtsp流播放延迟以及录像存储
Hik防爆摄像头录像,因为防爆摄像头会有对应的APP软件,与普通的网络摄像头和球机不一样,默认认为它不可以通过web网页配置,所以弄了个来实测确认。经测试实际上也是可以通过web网页配置(与网络摄像头基本是一致的,在码流方面可能会有些不一样),然后提取rtsp流的,界面与球机无异,只是没有球机的云台控制功能,但是界面上也是有的。
海康摄像头开发笔记(一):连接防爆摄像头、配置摄像头网段、设置rtsp码流、播放rtsp流、获取rtsp流、调优rtsp流播放延迟以及录像存储
如何实现RTMP或RTSP播放端回调YUV/RGB数据?
今天某乎收到个问题推荐,如何实现RTSP回调YUV数据,用于二次处理? 正好前些年我们做RTSP和RTMP直播播放的时候,实现过相关的需求,本文就以Android为例,大概说说具体实现吧。
141 1
Unity实现Camera和Audio数据的低延迟RTMP推送技术探讨
关于Unity实现RTMP直播推送技术方案,之前零散的写过几篇介绍,得到了好多开发者的关注。以Android平台为例,目前视频这块,我们demo实现的是Camera数据的采集,然后编码投递到底层,如果设备没有性能瓶颈,可达到高帧率(60帧)均匀的RTMP推送效果。
121 0
如何在Unity3d平台下低延迟播放RTMP或RTSP流
随着VR类、工业仿真、智慧城市等场景的快速发展,开发者对Unity3d低延迟的直播需求量越来越大,前两年,大牛直播SDK发布了Windows平台、Android平台和iOS平台的Unity3d RTMP和RTSP的播放,好多公司用起来体验都非常好,以下介绍大概实现流程。
319 0