流媒体课程设计报告---RTSP协议的实现

本文介绍了基于RTSP协议的流媒体传输系统设计,包括RTSP、RTP/RTCP协议的原理,以及使用Java实现视频文件推流和播放控制的过程。设计中涉及服务器和客户端的构建,详细阐述了RTP包和RTCP包的设计,以及遇到的问题和解决方案。
摘要由CSDN通过智能技术生成


前言

针对一种或多种常用流媒体传输协议如 rtsp/mms/hls 等,剖析其原理并对协议进行编程实现,同时基于该协议设计一个简单应用演示案例。本课程设计研究RTSP,RTP/RTCP协议,使用Java简单实现视频文件推流和播放控制。


一、设计内容

1、设计内容

随着互联网和智能手机的快速发展,流媒体技术在音频、视频、直播等领域广泛应用,成为网络娱乐、在线教育、远程医疗、实时会议等领域的重要组成部分。流媒体技术在现代社会中的作用越来越重要,它以“流”的形式进行数字媒体的传送,数据流具有连续性、实时性、时序性特点,它已成为在Internet上实时传输音视频的主要方式。
为了在网络上传播媒体流,流媒体技术需要解决音视频的编码、解码、存储、传输等一系列问题。在流媒体传输中存在一系列流媒体传输协议,它是一套规则和程序,管理互联网或其他网络上的音频和视频数据传输,旨在促进多媒体内容的实时传输,如现场广播、视频点播和在线游戏等。RTSP(Real Time Streaming Protocol)是一种基于TCP等协议的实时流媒体传输协议,主要用于视频监控、视频会议等实时视频传输场景,通过在希望通讯的两端建立并控制媒体会话(session),客户端通过发出命令如play、record和pause等来实时控制媒体流。本课程设计研究RTSP、RTP、RTCP等协议的运作方式,并尝试使用Java模拟实现RTSP、RTP/RTCP协议,通过网络实时传输一个可以进行控制的视频流,实现网络推流的目的。

2、设计思路

首先设计两个传输实体:传输服务器与客户端。构建两个Java Swing窗体分别作为客户端和服务器,具有必要的提示信息、操作按钮等,打开服务器后初始化状态,监听客户端的链接请求;打开客户端建立TCP连接对象,用于RTSP服务。客户端与服务器分别构建RTSP请求报文与RTSP回应报文,用于两端之间的通信。同时两端设置有报文解析,在收到对端的请求后可以根据关键字的值来映射不同的处理逻辑。
RTSP与HTTP相似,在体系结构上RTSP位于RTP和RTCP之上,且是双向的,在使用RTP进行数据传输时传送媒体数据(MJPEG),而HTTP传送HTML数据。RTSP充当多媒体服务器的网络远程控制,使实时数据如音频与视频的快进快退、中止、播放成为可能。RTSP低延迟、质量高,可扩展,有较强的控制能力和兼容性。
RTSP协议工作的三个阶段为:连接建立阶段、媒体描述阶段、媒体传输阶段。在设计时,按RTSP的工作流程设计操作逻辑:建立连接后,客户端请求服务器发送媒体描述文件(SDP文件),使服务器获取媒体流的信息。媒体描述文件包含视频的路径、名称、编码格式等信息。之后服务端向客户端回复response消息,内容有CSeq、当前会话session数据等。
RTSP连接建立之后,视频传输还需依靠RTP/RTCP协议进行数据传输与QoS传输质量保证。RTP报文由两部分组成:报头和有效载荷。在RTP会话期间,各参与者周期性地传送RTCP包;RTP和RTCP配合使用,它们能以有效的反馈和最小的开销使传输效率最佳化,因而特别适合传送网上的实时数据。设计时根据各种数据包的消息构成来构建数据构造器、解释器,并将它们放入DatagramPacket,利用DatagramSocket传送。RTP的上层视频数据为自定义的mjpeg格式的视频流,此视频的每帧数据大小、视频帧的长度已经预设好。当按下“播放”时,服务器使用Timer不断向客户端推流,客户端同样持续接收,并且使用另外定时器持续向服务器反馈通过RTCP包(PT=RR)反馈当前视频帧的接收情况,直到客户端发起新的RTSP控制请求。
客户端按下“初始化”,向服务器发送“SETUP”请求,传送视频文件名、客户端rtsp端口;按下“暂停”时,client RTSP发送“PAUSE”消息,暂停当前发送与接收;按下“播放”时,发送“PLAY”继续播放;按下“关闭”时,发送“TEARDOWN”,停止发送与接收并退出;按下“DESCRIBE”后,从服务器接收关于当前视频信息的描述回应,包括视频名、端口号、mjpeg类型号等。

二、设计过程

1、RTP包设计

参考资料,定义RTP的封装格式,如图1所示
在这里插入图片描述

图1 RTP首部格式
//rtp首部长度:12 bytes
static int HEADER_SIZE = 12;
//构成RTP头的字段
public int Version;//版本号,2
public int Padding;//填充位,0
public int Extension;//扩展位,0
public int CC;//csrc计数器,0(贡献源列表)
public int Marker;//标记位,0
public int PayloadType;//载荷类型,26(mjpeg)
public int SequenceNumber;//序列号
public int TimeStamp;//时间戳
public int Ssrc;//同步标识符,自定义
public byte[] header;//头部数据
public int payload_size; //rtp 载荷长度
public byte[] payload;//载荷数据
相关数据获取到则存储在全局变量中,在需要时使用构造器构建RTP包。

2、RTCP包设计

RTCP有5种分组类型,分别为发送端报告、接收端报告、原点描述、结束传输、特定应用。本次设计将一个rtcp分组封装在一个udp包中,分组类型只采用接收端报告(Reciever Report)封装,用作客户端向服务器报告接收情况。PT=RR=201类型的RTCP包格式如下图所示。
在这里插入图片描述

图2 RTCP(Receive Report类型)包格式
final static int HEADER_SIZE = 8;
final static int BODY_SIZE = 24;
public int Version; // 版本号 2
public int Padding; // 数据包的填充 0
public int RC; // 1
public int PayloadType; // Receiver Report 201
public int length; // 总长度 32 bytes, 8 + 24
public int Ssrc; // 同步标识符
public float fractionLost; //发送方丢失的RTP数据包占当前已发送的比例
public int cumLost; //发送方丢失的RTP数据包的总数
public int highSeqNb; // 收到的最高序列号
public int jitter; //未使用
public int LSR; //未使用
public int DLSR; //未使用
public byte[] header; //首部bytes
public byte[] body; //数据bytes
暂时只设计RR包类型,在客户端以固定间隔收集当前收到的视频数据情况,发回服务器,以达到反馈当前会话质量的目的。

3、服务器设计

服务器GUI界面如图3所示。
在这里插入图片描述

图3 服务器
服务器完成的功能有:建立RTSP的TCP连接、建立用于RTP/RTCP传输的UDP连接、接收客户端的RTSP请求并作出回应、控制视频流的发送,暂停与停止、调整发送质量等。
1)回应请求
使用单独线程循环执行的部分。在parseRequest()中使用BufferedReader.readLine();读取从客户端发来的每一行数据,提取关键字(SETUP、PLAY、PAUSE、DESCRIBE、TEARDOWN),并将状态信息更新;sendResponse() 函数用来发送普通的RTSP响应,sendDescribe()用来发送SDP格式的DESCRIBE响应字符串。
2)发送视频帧
使用Timer定时器间隔一定的时间持续发送数据。时间间隔在类的成员变量中定义,这也是视频流发送的速度,影响播放器接收视频流的速度,影响视频播放速度。接口中的方法实现后,首先调用int image_length = video.getNextFrame(buf);获得当前视频帧的下一帧数据buf和下一帧的数据量大小image_length(字节)。此时每帧视频信息数据量过大,需要进行图片压缩,调用imgTranslator.setCompressionQuality(0.5f); 调整图像质量,重新获得新的image_length和buf;之后将一帧图片打包成RTP数据包,再封装成字节数组的形式,拼接好头部信息,装入一个UDP套接字,发给客户端。此时一次发送任务完成,服务器将循环进行发送帧,直到视频结束。
3)图片压缩
使用Java Image I/O API包执行常见的图像io操作。定义ImageTranslator类,调用api中writer.getDefaultWriteParam().setCompressionQuality()相关方法,设定JPEG格式,设定压缩质量;调用ImageIO.read()与writer.write()方法写入调整后的图片数据。

4、客户端设计

客户端UI如图所示。
在这里插入图片描述

图 4 客户端
客户端实现的功能包括:流媒体视频接收、视频显示、发送视频播放控制请求等。
1)发送控制请求
客户端设置有5个按钮,分别对应RTSP请求的INIT、PLAY、PAUSE、TEARDOWN、DESCRIBE。客户端启动后,根据已给定的RTSP server端口与域名、视频文件名进行初始化,建立链接对象与输入输出流对象。点击按钮调用接口方法…ButtonListener(),完成功能。初始化按钮首先被点击,之后其他按钮才可以被激活;点击“描述”,可以测试DESCRIBE请求,可以看到从服务器返回的响应的标准输出。
2)显示视频帧
视频帧通过循环进行的定时器处理程序处理并显示。构建一个DatagramPacket来接收来自UDP套接字的数据,成功获取到比特流后进行解读,得到真正的每一帧JPEG图像。获取时使用Java Toolkit工具包中的createImage方法,此方法以指定的偏移量和长度解码存储在指定字节数组中的jpeg图像。之后参考资料,将显示的可能为乱序输入的图片通过FrameSynchronizer的方法调整顺序(序列号同步),并将其绑定在iconLabel中。完成图片显示过程。
5、自定义MJPEG视频编码
将原始MP4视频文件重新编码以便用于流媒体传输。具体思路为:逐帧提取或间隔截取视频帧,将提取到的视频帧转化为一系列jpg格式图片;计算jpg图片字节数。将图片字节数和jpg格式的字节流按顺序写入MJPEG文件,直到写完所有的已提取的视频帧。由于图片字节数不超过5位数,将每位数字译成ASCII码,用5个字节按大端序写入在jpg字节流前面。使用python完成,相关的python代码如下:

import cv2
# 将num转化为5位int数组
def get_digits(num):
    try:
        num = int(num)
        if num < 0 or num >= 100000:
            raise ValueError("数字过大或过小")
        num_str = str(num).zfill(5)
        digit = [d for d in num_str]
        return digit
    except ValueError as e:
        print(f"{e}")
        return None
# 定义调整后的视频分辨率
width = 384
height = 288
# 转换完成后一共c帧
c = 0
input_file = "gerenjianjie.mp4"
output_file = "gerenjianjie.mjpeg"
cap = cv2.VideoCapture(input_file)
with open(output_file, "wb") as f:
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        # 重新调整每一帧的大小
        frame = cv2.resize(frame, (width, height))
        retval, buffer = cv2.imencode('.jpg', frame)
        len1 = len(buffer)
        print("大小:", len1)
        digits = get_digits(len1)
        # 写入大小
        for i in range(5):
            b = bytes([ord(digits[i])])
            f.write(b)
        # 写入每帧图像
        f.write(buffer.tobytes())
        c = c + 1
cap.release()
print("视频一共:", c, "帧")

6、问题与解决方案

1)对于流媒体RTSP、RTP等协议的字段构成、连接方式认识模糊,对于各个字段的含义了解不是很深入。
上网搜集资料,查找关于RTSP等协议的RFC文档,参考课堂资料,逐步分析,设计协议中的每一个字段,以及它们的构造器、解析器,暂时舍弃了未用到的字段。
2)对于如何将每帧图像从比特流中解析出来没有好的思路。
通过网络了解到可以使用toolkit.createImage(payload, 0, payload_length)获取图像;为了防止序列号错乱,设置类FrameSynchronizer,内有相关方法可以根据帧的序列号进行同步。
3)接收图像时每帧数据量过大,出现缓存溢出的情况,UDP包数据量过大。
RTP 的包长度必须要小于 MTU(最大传输单元,Maximum Transmission Unit)。IP协议中 MTU 的最大长度为 1500 字节,RTP 有效载荷的长度不得超过 1460 字节。暂时强制压缩图片数据量使每帧图片大小合适。

三、总结

通过本次课程设计,我实现了一个基于RTSP的流媒体传输协议的演示案例,有了很多收获与感悟。首先,我尝试深入了解RTSP、RTP/RTCP协议的原理和特点,包括协议中的基本概念、协议的各种命令和响应、RTP包的格式和处理等,从而对流媒体传输有了更加深入的理解;同时,通过协议的编程实现,我体会到了协议中的各种细节和要点,也更好地掌握了协议的使用方法和应用场景,从而应对实际应用中的问题。本次课设也让我掌握了许多流媒体开发的相关知识,为我后续学习和开发提供了较好的参考。
课程设计中也存在一些问题。首先,还没有对协议的各种细节和特点有深入的理解,忽略了一些细节,媒体的传输只对重新编码的特定视频起作用;在设计中,需要分别设计客户端与服务器,两端之间的交互问题没有很好的处理;未实现RTCP协议的功能,未获取发送信息包数目、丢失信息包数目等信息;未注意到RTP包的大小限制,导致消息大小超过MTU出现异常;未实现播放进度控制等。
在设计过程中,我发现了自己的薄弱和不足之处,也认识到了持续学习的重要性。只有通过不断学习和实践,才能保持自己在学习和生活之中的竞争力和创造性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值