RTSP服务器
RTSP是一个实时传输流协议,是一个应用层的协议(通常包括RTSP协议、RTP协议、RTCP协议)
- RTSP协议:负责服务器与客户端之间的请求与响应
- RTP协议:负责服务器与客户端之间传输媒体数据
- RTCP协议:负责提供有关RTP传输质量的反馈,就是确保RTP传输的质量
三者的关系:RTSP并不会发送媒体数据,只是完成服务器和客户端之间的信令交互;RTP协议负责媒体数据传输;RTCP负责RTP数据包的监视和反馈。RTP和RTCP并未规定传输层的类型,TCP/UDP;而RTSP的传输层则要求是基于TCP。
源码:https://gitee.com/Vanishi/BXC_RtspServer_study
实现一个基于UDP的RTP传输h264的RTSP服务器,并能够进行rtsp拉流播放
- 客户端播放器能够向RTSP服务器发起建立连接的请求,并且客户端在发起RTSP的Play请求以后,RTSP在回复了Play请求之后,开始源源不断的通过RTP协议向客户端推送H264视频流。
- RTP理解 (33条消息) RTP理解_屁小猪的博客-CSDN博客_rtp
- H264理解 (33条消息) H264简介_屁小猪的博客-CSDN博客_h264
- H264基础知识 (32条消息) H264基础知识入门_音视频开发老马的博客-CSDN博客_h264 压缩比
- H264的功能分为视频编码层(VCL)和网络提取层(NAL)
- H264由一个一个的NALU组成,每个NALU之间使用00 00 00 01或00 00 01分隔开,每个NALU的第一个字节都有特殊的含义。(目的:从H264文件中将一个一个的NALU提取出来,封装成RTP包)
# ffmpeg命令行解封装.mp4生成.h264视频文件
ffmpeg -i test.mp4 -codec copy -bsf: h264_mp4toannexb -f h264 test.h264
#pragma once
#pragma comment(lib, "ws2_32.lib")
#include <stdint.h>
#define RTP_VESION 2
#define RTP_PAYLOAD_TYPE_H264 96
#define RTP_PAYLOAD_TYPE_AAC 97
#define RTP_HEADER_SIZE 12
#define RTP_MAX_PKT_SIZE 1400
/*
* 0 1 2 3
* 7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |V=2|P|X| CC |M| PT | sequence number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | timestamp |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | synchronization source (SSRC) identifier |
* +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
* | contributing source (CSRC) identifiers |
* : .... :
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
struct RtpHeader
{
/* byte 0 */
uint8_t csrcLen : 4;//CSRC计数器,占4位,指示CSRC 标识符的个数。
uint8_t extension : 1;//占1位,如果X=1,则在RTP报头后跟有一个扩展报头。
uint8_t padding : 1;//填充标志,占1位,如果P=1,则在该报文的尾部填充一个或多个额外的八位组,它们不是有效载荷的一部分。
uint8_t version : 2;//RTP协议的版本号,占2位,当前协议版本号为2。
/* byte 1 */
uint8_t payloadType : 7;//有效载荷类型,占7位,用于说明RTP报文中有效载荷的类型,如GSM音频、JPEM图像等。
uint8_t marker : 1;//标记,占1位,不同的有效载荷有不同的含义,对于视频,标记一帧的结束;对于音频,标记会话的开始。
/* bytes 2,3 */
uint16_t seq;//占16位,用于标识发送者所发送的RTP报文的序列号,每发送一个报文,序列号增1。接收者通过序列号来检测报文丢失情况,重新排序报文,恢复数据。
/* bytes 4-7 */
uint32_t timestamp;//占32位,时戳反映了该RTP报文的第一个八位组的采样时刻。接收者使用时戳来计算延迟和延迟抖动,并进行同步控制。
/* bytes 8-11 */
uint32_t ssrc;//占32位,用于标识同步信源。该标识符是随机选择的,参加同一视频会议的两个同步信源不能有相同的SSRC。
/*标准的RTP Header 还可能存在 0-15个特约信源(CSRC)标识符
每个CSRC标识符占32位,可以有0~15个。每个CSRC标识了包含在该RTP报文有效载荷中的所有特约信源
*/
};
struct RtpPacket
{
struct RtpHeader rtpHeader;
uint8_t payload[0];
};
实现一个基于UDP的RTP传输音频aac的RTSP服务器,并能够进行rtsp拉流播放
- 客户端建立与RTSP服务端的连接,并且在RTSP服务端回复客户端的Play请求以后,服务端需要源源不断的读取一个本地aac音频文件,并将读取到的aac音频码流封装到RTP数据包中,再推送至客户端。
- 麦克风在录音采样后,直接获得的就是音频原始数据pcm,但pcm数据较大,所以通常需要压缩之后才能传输或保存,常见的音频压缩技术有aac,g711,mp3等
AAC音频有两种:
- ADIF - 音频数据交换格式:只有一个统一的头,必须得到所有数据后解码,适用于本地文件
- ADTS - 音视数据传输流:每一帧都有头信息,任意帧解码,适用于传输流
# ffmpeg命令行 从mp4视频文件提取aac音频文件
ffmpeg -i test.mp4 -vn -acodec aac test.aac
# ffmpeg 从aac音频文件解码为pcm音频文件
ffmpeg -i test.aac -f s16le test.pcm
# ffplay 播放.pcm音频文件
ffplay -ar 44100 -ac 2 -f s16le -i test.pcm
struct AdtsHeader {
unsigned int syncword; //12 bit 同步字 '1111 1111 1111',一个ADTS帧的开始
uint8_t id; //1 bit 0代表MPEG-4, 1代表MPEG-2。
uint8_t layer; //2 bit 必须为0
uint8_t protectionAbsent; //1 bit 1代表没有CRC,0代表有CRC
uint8_t profile; //1 bit AAC级别(MPEG-2 AAC中定义了3种profile,MPEG-4 AAC中定义了6种profile)
uint8_t samplingFreqIndex; //4 bit 采样率
uint8_t privateBit; //1bit 编码时设置为0,解码时忽略
uint8_t channelCfg; //3 bit 声道数量
uint8_t originalCopy; //1bit 编码时设置为0,解码时忽略
uint8_t home; //1 bit 编码时设置为0,解码时忽略
uint8_t copyrightIdentificationBit; //1 bit 编码时设置为0,解码时忽略
uint8_t copyrightIdentificationStart; //1 bit 编码时设置为0,解码时忽略
unsigned int aacFrameLength; //13 bit 一个ADTS帧的长度包括ADTS头和AAC原始流
unsigned int adtsBufferFullness; //11 bit 缓冲区充满度,0x7FF说明是码率可变的码流,不需要此字段。CBR可能需要此字段,不同编码器使用情况不同。这个在使用音频编码的时候需要注意。
/* number_of_raw_data_blocks_in_frame
* 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧
* 所以说number_of_raw_data_blocks_in_frame == 0
* 表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据)
*/
uint8_t numberOfRawDataBlockInFrame; //2 bit
};
实现一个基于TCP的RTP同时传输h264和aac的RTSP服务器,并能够进行rtsp拉流播放
- 客户端请求RTSP的Describe请求时,RTSP服务器返回的SDP协议,需要同时包含音频流和视频流的信息
- 客户端请求RTSP的Setup请求时,RTSP服务器不需要再对应创建RTP和RTCP的UDP连接通道,因为基于TCP的RTP传输,客户端与服务器交互时,无论是RTSP信令还是RTP数据包或者是RTCP数据包,都是使用同一个TCP连接通道。(TCP连接通道在发送RTP数据包或RTCP数据包时,需添加一些分隔字节)
- 客户端请求RTSP的Play请求时,RTSP服务器对Play请求进行回复后,源源不断的同时向客户端发送音频流和视频流的RTP数据包
# rtp通道是tcp时需要加参数,否则默认是UDP的!
ffplay -i -rtsp_transport tcp rtsp://127.0.0.1:8554