ffmpeg rtsp解析

news2024/9/28 19:27:00

一、 rtsp 协议说明 

rtsp的协议层级

  • rtsp 属于应用层, 使用tcp传输,主要是传递服务器的一些信息,实现流连接。播放 暂停 销毁等控制
  •  rtp 实现音视频数据包的发送,通过RTSP等协议的SDP信息协商好了RTP数据包的发送目的和传输方式,我们就需要把音视频数据打包成RTP包,用UDP或者tcp发送给接收端了。

二、ffmpeg 中的实现

1. rtsp_read_header

其中ff_rtsp_connect连接服务器, 首先会指定下一层使用的协议是什么? 可以指定rtp over tcp 或者 rtp over udp。由这个lower_transport_mask 决定的,rt->lower_transport_mask 会有一个默认值。 通过ff_rtsp_options[] 进行设置的

   { "rtsp_transport", "RTSP transport protocols", OFFSET(lower_transport_mask), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, DEC|ENC, "rtsp_transport" }, \

默认是0 udp的形式。

2. ffurl_open

ffurl_open(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE,&s->interrupt_callback, NULL) < 0)

  • 调用到了tcp_open(), tcp去连接,tcp调用 socket() 创建tcp的fd。
  • 1 调用connect 去连接服务器,根据不同的返回值 进行不同的处理。

3. ffurl_connect

ffurl_connect(rt->rtsp_hd_out, NULL)

ff_rtsp_send_cmd(s, "OPTIONS", rt->control_uri, cmd, reply, NULL)

  • 第一步: 连接tcp,发送options这个tcp的连接主要负责服务器交互命令的传输如:option play discribe等
  • 根据传进来的url,构建tcp的地址进行连接(地址放在rt->control_uri这个变量中),并创建一个rt->rtsp_hd 的context,从这个context 中获取到 tcp_fd。第一个发送的命令是 OPTIONS, 服务器会返回可以运行的那些命令。

4.ff_rtsp_setup_input_streams

第二步:向服务器发送discribe的消息, 然后解析获取到的sdp文件,根据文件建立流,获取音视频流的信息。

发送discribe 信息  ff_rtsp_send_cmd(s, "DESCRIBE", rt->control_uri, cmd, reply, &content);

服务器回复一个sdp文件,里面包含地址,range,track等信息。

解析sdp文件

其中m开始的这一行就是流的信息。流的信息会保存到rt->rtsp_streams 中

       rtsp_st = av_mallocz(sizeof(RTSPStream));

       if (!rtsp_st)

           return;

       rtsp_st->stream_index = -1;

       dynarray_add(&rt->rtsp_streams, &rt->nb_rtsp_streams, rtsp_st);

5.ff_rtsp_make_setup_request

  • 进行rtp 和 rtcp的连接 ,连接的地址是 从url的host中获取到,比如rtsp的ip   rtsp://210.13.9.10:1554 其中port取一个随机值,并且rtp 和 rtcp 的port 只相差1。创建rtp_handle,这个ffurl_open 调用到了rtp_open 、rtp_open:分别创建两个udp的地址,rtp和rtcp的地址就是port相差1,如下,然后分别创建 s->rtcp_hd和 s->rtp_hd 这两个handle

udp_open: uri = udp://210.13.9.10?localport=13054&fifo_size=0

udp_open: uri = udp://210.13.9.10:0?localport=13055&fifo_size=0

  • 连接完成之后,发送setup的命令到服务器ff_rtsp_send_cmd(s, "SETUP", rtsp_st->control_url, cmd, reply, NULL);
  • 发送完成之后 ,做一些open context的操作,实际上是ff_rtsp_open_transport_ctx调用ff_rtp_parse_open  就是根据code_id来看 读取上来的数据是不是需要parse
  • 如果payload_type 是MP2T, ts流的情况,还需要ff_mpegts_parse_open,打开mpegts的一些 pmt pat pes的回调函数。

6. rtsp_read_play

  • 发送play的命令到服务器进行播放操作,服务器就会发送数据到客户端ff_rtsp_send_cmd(s, "PLAY", rt->control_uri, cmd, reply, NULL);

7. rtsp_read_packet

  • 调用 ff_rtsp_fetch_packet,udp的情况 udp_read_packet 实际是调用的是ret = ffurl_read(rtsp_st->rtp_handle, buf, buf_size); 这个调用的是rtp_read。
  • 这里分别从两个fd那边来获取数据  一个是rtcp_fd, 一个rtp_fd.读到底层buf之后 调用ff_rtp_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len);
  • 如果是ts的话,那么会调用tsparse 先parse一下 在调用codec的parse parse 一下 然后返回。

三、rtsp_read_packet 序号处理

  • 读取数据流程: 正常没有丢包和乱序的情况下,从udp_read 中读取一包出来,读取的方式是采用poll等待, fd 有两个一个是rtp实际上下面一层是rtpproto.c  调用的rtp_read_packet, 没有调用udp_read. 在rtp_read_packet里面就直接调用系统的recvfrom 从之前的open的fd 中读取数据回来。
  • 这个数据经过解析回到上面一层也就是rtsp。 这里面就有对序号不连续的情况进程处理。一个是rtcp,有数据可以读的话 就里面读上来, 然后这边读上来的包立马就进行parser,parse的时候如果这一包 还没有销毁玩 要继续调用parse。
  • 第一包 或者 解析到的seq 是连续的,那就直接调用parse
  • seq不连续,比如1 3这样,那么把3给存储起来 放到queue里面。同时更新wait_end 为queue里面第一包放进去的时间+能够延迟最长的时间默认为100ms。

   queue是一个队列,第一个元素是最早放进来的,后面的依次放到后面。 这边又分为两种情况

  1. 读超时, 也就是2这个数据一直没读到,后面读的是3,4,5,6,7这样,那么就最多读取100ms、超过了就返回超时(这个时候出现log max delay reache )。然后强制调用ff_rtp_parse_packet(rtsp_st->transport_priv, pkt, NULL, 0)。通过倒数第二个参数NULL控制会从queue的队列里面读数据 进行parsre(这个时候出现log RTP: missed)然后返回。

  2. 读到了2这个数据,那么判断序号seq 和 queue的seq就相差1 也就是seq为2 ,queue第一个元素是3.直接将2parse。parse出来之后,有一个while循环会把queue里面的数据全部parse掉。parse掉之后才会继续读取数据。同时将wait_end 重置为0,也就是说恢复到没有包丢掉的情况。

  3. 如果是直接rtp地址,就少了rtsp的处理。就看rtpproto.c里面的处理 直接就是rtp_read_header 建立udp或者tcp的连接,得到一个fd,然后从这个fd读数据。如果是直接udp的地址,同样少了rtp的处理, 直接就看udp.c的处理。

 四、rtsp丢包原因分析

   分析方法:rtsp丢包可能发生在传输的每个环节,一般来说最大的可能是服务器端发送的时候某些包没有发送 或者 网络环境导致发送的包丢失  或者客户端应用程序导致底层收的包没有及时处理。通常通过分段的网络抓包可以确认包是在哪个阶段丢的

  • 问题:用tcpdump抓包看是不丢包的,但是从udp read上来的数据 解析成rtp包是丢失的,也就是rtp的序号是不连续的,即使是加大乱序buffer 到很大也是没有效果的。 udp 包乱序了基本上后面就再也读不上来了。

 

  • 首先tcpdump工作在哪一个层次,tcpdump工作在IP层。 tcpdump出来的是正确的,就说明网络层是正常。 只有应用层去接收数据的时候丢掉了。分析 是不是读数据不及时, 看读数据的线程,cache 满的时候 是有一个sleep的操作。 也就是当上层cache 很多的时候,会减慢读取数据的线程。通过分析 丢包基本上都是发生在读数据线程sleep很久的时候。数据cache多的时候,不去减慢读数据,也就是不去做sleep 操作。 相当于有一个线程一直在及时的把数据从socket读上来。这个时候看是正常的。 那么就说明之前是cache 导致socket的数据堆积 变慢了。
  • 如果从客户端网络抓包看是不丢包,但应用却丢包,那么基本上是应用处理接收到的网络包程序有问题。udp是无连接,客户端没有及时接收那么缓冲去满的话就会丢弃,但这些数据服务端是实际都发送成功 并且被IP层接收了。

五、相关调试命令

ifconfig etho1 看是不是有丢包

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/546366.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UNIX网络编程卷一 学习笔记 第十四章 高级I/O函数

有3种方式可在涉及套接字的IO操作上设置超时方法&#xff1a; 1.调用alarm&#xff0c;它在指定超时期满时产生SIGALRM信号。此方法涉及信号处理&#xff0c;而信号处理在不同的实现上存在差异&#xff0c;且此方法可能干扰进程中已经执行过的alarm调用&#xff0c;可能使之前已…

【LLM系列之Tokenizer】如何科学地训练一个LLM分词器

1 背景与基础 1.1 为什么需要分词 对于人而言&#xff0c;在我们学会阅读之前&#xff0c;仍然可以理解语言。比如当你开始上学时&#xff0c;即使你不知道名词和动词之间的区别&#xff0c;但是你已经可以和你的同学交谈了&#xff0c;比如“我喜欢吃香蕉”&#xff0c;孩子…

vmware ubuntu突然无法联网的一种解决方案

记录一下vmware突然无法联网的一种解决方案。此法未必适用所有无法联网情形。Good Luck then. 今天使用vmware的ubuntu 18.04时&#xff0c;突然无法联网。Firefox在访问百度时显示“The proxy server is refusing connections”&#xff0c;随即检查了浏览器的proxy设置&#…

详解Jetpack Compose中的状态管理与使用

前言 引用一段官方描述&#xff0c;如下 由于 Compose 是声明式工具集&#xff0c;因此更新它的唯一方法是通过新参数调用同一可组合项。这些参数是界面状态的表现形式。每当状态更新时&#xff0c;都会发生重组。因此&#xff0c;TextField 不会像在基于 XML 的命令式视图中那…

头歌计算机组成原理实验—运算器设计(9)第9关:原码一位乘法器设计

第9关&#xff1a;原码一位乘法器设计 实验目的 学生掌握原码一位乘法运算的基本原理&#xff0c;熟练掌握 Logisim 寄存器电路的使用&#xff0c;能在 Logisim 平台中设计实现一个 8*8位的无符号数乘法器。 视频讲解 ####实验内容 在 alu.circ 文件中的原码一位乘法器子电…

分布式消息中间件RocketMQ概述

RocketMQ 概述 MQ概述 MQ简介 ​ MQ&#xff0c;Message Queue&#xff0c;是一种提供消息队列服务的中间件&#xff0c;也称为消息中间件&#xff0c;是一套提供了消息生产、存储、消费全过程API的软件系统。消息即数据。一般消息的体量不会很大。 MQ用途 在网络上上可以查…

React学习笔记五-props

此文章是本人在学习React的时候&#xff0c;写下的学习笔记&#xff0c;在此纪录和分享。此为第五篇&#xff0c;主要介绍react中的props。 目录 1.props的基本使用 2.props的批量传递 2.1展开运算符的复习 2.1.1数组中的展开运算符 2.1.2函数中的展开运算符 2.1.3构造字面…

部署图的画法

部署图画法 1.部署图 1.1含义 部署图是把软件制品装配到计算机节点以及配置软件环境的工作 软件部署包含环境部署和软件制品部署 1.2软件部署 软件部署通过部署图对软件进行建模 1.3部署图 部署图常见的有制品 节点 设备 运行环境和部署规范 1.4部署图关系 在UML&…

UnityVR--Managers--对象池2

目录 前言 基本结构 对象池代码 对象池管理器代码 使用 总结 前言 经过上一篇对象池1的了解&#xff0c;已经做到了使用Unity自带的ObjectPool进行内存优化。本篇自己构建一个对象池管理器&#xff08;Manager&#xff09;&#xff0c;实现对象池的创建、删除、加载资源…

机器视觉工程师很苦吗?年轻人不怕苦,就怕学不到东西,机器视觉销售>项目经理>视觉>电气>机械>老板

年轻人不怕苦&#xff0c;就怕学不到东西。 对于年轻人来说&#xff0c;需要规划&#xff0c;更需要发展。如果学不到东西&#xff0c;就会限制其发展&#xff0c;最重要的体现就是限制待遇上限。 一个非标自动化公司出差的频次&#xff08;各个公司略有差别&#xff0c;大多…

062:cesium设置泛光折线材质(material-6)

第062个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中设置泛光折线材质,请参考源代码,了解PolylineGlowMaterialProperty的应用。 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共89行)相关API参考:专…

蓝桥:前端开发笔面必刷题——Day2 数组(三)

文章目录 &#x1f4cb;前言&#x1f3af;两数之和 II&#x1f4da;题目内容✅解答 &#x1f3af;移除元素&#x1f4da;题目内容✅解答 &#x1f3af;有序数组的平方&#x1f4da;题目内容✅解答 &#x1f3af;三数之和&#x1f4da;题目内容✅解答 &#x1f4dd;最后 &#x…

Cloud Studio 内核升级之持续优化

前言 Cloud Studio 是基于浏览器的集成式开发环境&#xff08;IDE&#xff09;&#xff0c;为开发者提供了一个永不间断的云端工作站。用户在使用 Cloud Studio 时无需安装&#xff0c;随时随地打开浏览器就能使用。云端开发体验与本地几乎一样&#xff0c;上手门槛更低&#…

Xcode 14.3 和 iOS 16.4 为 SwiftUI 带来了哪些新功能?

0. 概览 今年年初&#xff0c;Apple 推出了最新的 Xcode 14.3 以及对应的 iOS 16.4 。 与此同时&#xff0c;它们对目前最新的 SwiftUI 4.0 也添加了一些新功能&#xff1a; sheet 弹窗后部视图&#xff08;Interact with a view Behind a sheet&#xff09;可交互&#xff…

头歌计算机组成原理实验—运算器设计(7) 第7关:6位有符号补码阵列乘法器

第7关&#xff1a;6位有符号补码阵列乘法器 实验目的 帮助学生掌握补码阵列乘法器的实现原理。 视频讲解 实验内容 在 Logisim 中打开 alu.circ 文件&#xff0c;在6位补码阵列乘法器中利用5位阵列乘法器以及求补器等部件实现补码阵列乘法器&#xff0c;实验框架如图所示&a…

Linux - Shell 权限 权限管理 权限修改 权限身份的认证 目录的权限 粘滞位

shell命令以及运行原理 我们来输入指令的本质就是 输入字符串。 而指令的本质&#xff0c;就是编译好的文件和脚本&#xff0c;而只要是文件&#xff0c;就会在系统的特定路径下存放。 我们使用所有的指令最终都要在 OS &#xff08;操作系统&#xff09;内部运行&#xff0c;…

〖Python网络爬虫实战㉖〗- Selenium库和ChromeDriver驱动的安装

订阅&#xff1a;新手可以订阅我的其他专栏。免费阶段订阅量1000 python项目实战 Python编程基础教程系列&#xff08;零基础小白搬砖逆袭) 说明&#xff1a;本专栏持续更新中&#xff0c;目前专栏免费订阅&#xff0c;在转为付费专栏前订阅本专栏的&#xff0c;可以免费订阅付…

【C++】内存泄漏 智能指针

目录 一、什么是内存泄漏二、如何检测内存泄漏1、内存占用变化排查法2、valgrind定位法3、mtrace定位法 三、智能指针分类及作用1、unique_ptr2、shared_ptr3、weak_ptr 一、什么是内存泄漏 在实际的 C 开发中&#xff0c;我们经常会遇到诸如程序运行中突然崩溃、程序运行所用…

关于 HTTPS 的加密流程

目录 HTTP 与 HTTPS 的区别加密方式HTTPS 基本工作过程1. 仅使用对称密钥2. 引入非对称密钥对 key 进行加密3. 引入证书, 破解中间人攻击 HTTP 与 HTTPS 的区别 其实 HTTPS 与 HTTP 一样都是应用层协议, HTTPS 只是在 HTTP 的基础上再加上了一个加密层. 为啥要对 HTTP 进行加密…

bugku---misc

一.telnet 下载后是一个压缩包 条件反射&#xff0c;先丢在wireshark中看一下&#xff0c; 直接搜flag&#xff0c;就 出来了 Data: flag{d316759c281bf925d600be698a4973d5} 二.简单取证1 之前只做过取证大赛的&#xff0c;但是这个没有啥思路&#xff0c;看了一下需要工具m…