前言
本文主要介紹通過udp方式實現(xiàn)rtsp拉流。
流程圖
流程說明:文章來源:http://www.zghlxwxcb.cn/news/detail-759723.html
- 相較于tcp方式“信令+數(shù)據(jù)”復用同一連接拉流,udp方式拉流“信令+數(shù)據(jù)”采用不同的連接,信令傳輸采用tcp,流數(shù)據(jù)傳輸采用udp;
- 客戶端向服務端(設備等)發(fā)起tcp請求,用于后續(xù)信令交互;
- tcp連接成功后,開始rtsp信令交互(describe、setup、play等),rtsp鏈路需要?;睿?/li>
- 客戶端選擇兩個未用的端口創(chuàng)建udp鏈路,一個用于rtp數(shù)據(jù)傳輸,一個用于rtcp數(shù)據(jù)傳輸;
- 連接成功后,服務端(設備等)發(fā)送數(shù)據(jù)至客戶端;
- 客戶端對數(shù)據(jù)解復用、解碼、播放;
設計
- 客戶端向服務端(設備等)發(fā)起tcp請求:創(chuàng)建socket、connect、設置recv超時時間
m_tcpClient = std::make_shared<ZDTcpClient>(nullptr, this);
if (!m_tcpClient.get()
|| 0 != m_tcpClient->TcpCreate()
|| 0 != m_tcpClient->TcpConnect(ip.c_str(), port)
|| 0 != m_tcpClient->TcpSetNoBlock(true)
|| 0 != m_tcpClient->TcpRecvTimeout(10))
break;
- tcp連接成功后,創(chuàng)建rtsp客戶端,開始rtsp信令交互
// 參數(shù)1(RTSP_TRANSPORT_RTP_UDP)指明使用udp方式收流
m_command = std::make_shared<CRtspCommand>(RTSP_TRANSPORT_RTP_UDP, m_tcpClient, m_func, m_user);
if (!m_command.get())
break;
// 創(chuàng)建rtsp client
if (!m_command->CreateRtspClient(m_rtspUrl, username, userpasswd))
break;
// 發(fā)送describe信令
int ret = m_command->SendDescribe();
if (0 != ret)
break;
- 創(chuàng)建udp鏈路
int CRtspCmd::HandleRtpPort(int media, const char* source, unsigned short rtp[2], char* ip, int len)
{
int ret = -1;
switch (m_transport)
{
case RTSP_TRANSPORT_RTP_UDP:
ret = sockpair_create("0.0.0.0", m_rtp[media], m_port[media]);
if (0 != ret)
{
return -1;
}
rtp[0] = m_port[media][0];
rtp[1] = m_port[media][1];
break;
default:
assert(0);
return -1;
}
return m_transport;
}
- 啟動udp收流
int CRtspUdpData::Start(int count, socket_t rtp[2], const char* peer, int peerport[2], int payload, const char* encoding)
{
// 創(chuàng)建解復用器
const struct rtp_profile_t* profile = rtp_profile_find(payload);
m_demuxer = rtp_demuxer_create(100, profile ? profile->frequency : 90000, payload, encoding, RtpPacketCB, this);
if (!m_demuxer)
return -1;
if (0 != CreatePacker_(payload, encoding))
{
rtp_demuxer_destroy(&m_demuxer);
return -1;
}
m_encoding = encoding;
m_payload = payload;
m_socket[0] = rtp[0];
m_socket[1] = rtp[1];
// 啟動數(shù)據(jù)接收線程
m_thread = std::thread(UdpDataThread, this);
return 0;
}
- 讀rtp和rtcp數(shù)據(jù)
// 讀rtp數(shù)據(jù)
int CRtspUdpData::RtpRead_(socket_t s)
{
if (!m_demuxer)
return -1;
struct sockaddr_storage ss;
socklen_t len = sizeof(ss);
int dataLen = recvfrom(s, m_rtpBuffer, sizeof(m_rtpBuffer), 0, (struct sockaddr*)&ss, &len);
if (dataLen < 12)
{
return -1;
}
// 視頻數(shù)據(jù)解復用
return rtp_demuxer_input(m_demuxer, m_rtpBuffer, dataLen);
}
// 讀rtcp數(shù)據(jù)
int CRtspUdpData::RtcpRead_(socket_t s)
{
if (!m_demuxer)
return -1;
struct sockaddr_storage ss;
socklen_t len = sizeof(ss);
int dataLen = recvfrom(s, m_rtcpBuffer, sizeof(m_rtcpBuffer), 0, (struct sockaddr*)&ss, &len);
if (dataLen < 12)
{
return -1;
}
return rtp_demuxer_input(m_demuxer, m_rtcpBuffer, dataLen);
}
效果
文章來源地址http://www.zghlxwxcb.cn/news/detail-759723.html
到了這里,關于音視頻學習(二十)——rtsp收流(udp方式)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!