您的位置:首页 > 其它

分析一个通用的rtsp server实现过程发送模块

2017-08-07 20:59 561 查看
      这里主要介绍rtsp之后的发送流程,rtsp到达play之后,通过判断参数是play之后,可以启动一个线程

来发送已经打包好的ts流,于是需要将ts流打包rtp包,

正常从网上信息可以看出:RTP with payload type 33 (MPEG2 TS): The RTP timestamp 表示RTP packet的TRANSMISSION time。(来自RFC 2250)

同时,从这里可以了解到:
http://blog.csdn.net/xiaojun111111/article/details/52208370
TS流是有许多的TS Packet组成的,每个TS Packet的长度固定为188 bytes,每个packet都是以sync_byte:0x47开头。

MTU(Maximum Transmission Unit): 最大传输单元。是指一种通信协议的某一层上面所能通过的最大数据包大小(以字节为单位)。最大传输单元这个参数通常与通信接口有关(网络接口卡、串口等)。例如:以太网无法接收大于1500
字节的数据包。

协议分析 :每一个RTP数据报都由头部(Header)和负载(Payload)两个部分组成,其中头部前 12 个字节的含义是固定的,而负载则可以是音频或者视频数据。

于是定义:

#define  TS_PACKET_SIZE 188
#define  MTU (7 * TS_PACKET_SIZE)  //1316 + 12 < 1500
#define  TS_PAYLOAD_TYPE 33


然后定义rtp包的头部

typedef struct
{
/**//* byte 0 */
unsigned char csrc_len : 4;        /**//* expect 0 */
unsigned char extension : 1;        /**//* expect 1, see RTP_OP below */
unsigned char padding : 1;        /**//* expect 0 */
unsigned char version : 2;        /**//* expect 2 */
/**//* byte 1 */
unsigned char payload : 7;        /**//* RTP_PAYLOAD_RTSP */
unsigned char marker : 1;        /**//* expect 1 */
/**//* bytes 2, 3 */
unsigned short seq_no;
/**//* bytes 4-7 */
unsigned  long timestamp;
/**//* bytes 8-11 */
unsigned long ssrc;            /**//* stream number is used here. */
} RTP_HEADER_TS;


这里的socket中的send函数里面的port和ip是通过前面的rtsp setup阶段确定,并通过设置接口add_dest_socket_info传递到这里,如下:

RTP_MP3_SOCKET_INFO* psocketinfo = new  RTP_MP3_SOCKET_INFO;
psocketinfo->rtp_socket_port = destport;
psocketinfo->rtp_socket_ip = destip;
m_RTP_SOCKET_INFO_MAP[psessionhandle] = psocketinfo;
m_socketinfo_update_flag = true;


于是,发送的时候,直接获取就ok了,如下:

RTP_SOCKET_INFO_List_MP3::iterator iter = m_RTP_SOCKET_INFO_List.begin();
for ( ; iter != m_RTP_SOCKET_INFO_List.end(); iter++ )
{
RTP_MP3_SOCKET_INFO& mp3socketinfo = ( *iter );
struct sockaddr_in destsockaddr;
destsockaddr.sin_family = AF_INET;
destsockaddr.sin_addr.s_addr = inet_addr( mp3socketinfo.rtp_socket_ip.c_str() );
destsockaddr.sin_port = htons( mp3socketinfo.rtp_socket_port );
int ret = sendto( socket, sendbuf, totalsendcountbytes, 0, ( struct sockaddr* )&destsockaddr, sizeof( destsockaddr ) );
if ( ret < 0 )
{
printf( "\n  mp3 frame send error ! \n " );
}
}


当然上面是mp3的例子,ts流也可以借鉴这个方式来同样构造一套,用来发送就ok了。

我们通过后面采集的数据,写入到buffer数据里面,然后此时发送线程,就需要从buffer里面来读取数据了,
参考这里的文章http://www.codeforge.com/read/96791/RtpPacket.cpp__html

可以发现,需要构造rtp packet将前面的header填充,于是这样写:

//1.构造rtp报文
rtp_hdr = ( RTP_HEADER_TS * )&rtpbuf[0];//存的数据
rtp_hdr->payload = TS_PAYLOAD_TYPE;  //负载类型号,
rtp_hdr->version = 2;  //版本号,此版本固定为2
rtp_hdr->ssrc = htonl( tsssrc );
rtp_hdr->marker = 0;


于是接下来就需要将前面的buffer数据发送到client端了,

可以简单的见下面的逻辑,如下:

//传入的ts buffer的长度
unsigned int framelen = pbuffer->length ;
//  每一个RTP包中都有前12个字节定长的头字段
int rtpheadersize = 12;

    对于buffer的长度小于len的情况,采取一个rtp包发送就ok了,序列号需要递增,和ping一样,用来标志一个包,

然后直接通过rtp的send函数发送,这里的socket结构体没有耦合好,建议最好将这里的send函数直接用base 库里面

的sokcet类的继承类udp来实现,这里就比较合理!

if(MTU >= framelen){ //小于mtu的情况
//设置rtp M位
rtp_hdr->marker = 0;
rtp_hdr->seq_no = htons((*seq_num)++); //序列号,每发送一个RTP包增1
memcpy(rtpbuf + rtpheadersize, pbuffer->buffer, framelen);
int bytes = 0;
bytes = framelen + rtpheadersize;
sendPacketToClients(socket, rtpbuf, bytes);

}


那么对于buffer的长度大于len的情况,需要分段发送了,

int k = 0, l = 0;
k = framelen / MTU; //需要k个MTU字节的RTP包
l = framelen % MTU; //最后一个RTP包需要装载的字节数


首先统计多少个mtu的个数,和最后的个数,很容易算出来的,

当然如果是mtu的整数倍的话,需要单独拿出来,作为一个特例存在,

if(0 == l){

k = k -1;   //k大于等于1
l = MTU;
}


于是可以进行while循环操作了,count用来计数,

如下:

int count =0; //用于指示当前发送的是第几个分片RTP包


接下来,处理的步骤如下:前面k个mtu包发送,最后一个单独发送,于是可以写成下面的代码:

while(t <= k){
rtp_hdr->seq_no = htons((*seq_num)++);  //序列号,每发送一个RTP包增1
if(t < k){ //发送一个需要分片的buffer的第一个分片
memset(rtpbuf + rtpheadersize, 0, 1500 - rtpheadersize);
memcpy(rtpbuf + rtpheadersize, pbuffer->buffer + t * MTU, MTU);
int bytes = 0;
bytes = MTU + rtpheadersize;
sendPacketToClients(socket, rtpbuf, bytes);
}else if(t == k){
memset(sendbuf + rtpheadersize, 0, 1500 -  rtpheadersize);
memcpy(sendbuf + rtpheadersize, pbuffer->buffer + t * MTU, l);
int bytes = 0;
bytes = l + rtpheadersize;
sendPacketToClients(socket, rtpbuf, bytes);
}

t++;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐