Files
ANSCORE/MediaClient/rtsp/rtsp_rcua.cpp

1075 lines
25 KiB
C++
Raw Normal View History

2026-03-28 16:54:11 +11:00
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#include "sys_inc.h"
#include "rtp.h"
#include "word_analyse.h"
#include "rtsp_parse.h"
#include "rtsp_rcua.h"
#include "rfc_md5.h"
#include "base64.h"
#include "rtsp_util.h"
#include "http_cln.h"
#ifdef OVER_WEBSOCKET
#include "rtsp_ws.h"
#endif
/***********************************************************************/
void rcua_build_auth_line(RCUA * p_rua, HRTSP_MSG * tx_msg, const char * p_method)
{
if (0 == p_rua->need_auth)
{
return;
}
HD_AUTH_INFO * p_auth = &p_rua->auth_info;
if (p_rua->auth_mode == 1) // digest
{
int offset;
int buflen;
char buff[500] = {'\0'};
http_calc_auth_digest(p_auth, p_method);
offset = 0;
buflen = sizeof(buff);
offset += snprintf(buff+offset, buflen-offset,
"Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", "
"uri=\"%s\", response=\"%s\"",
p_auth->auth_name, p_auth->auth_realm, p_auth->auth_nonce,
p_auth->auth_uri, p_auth->auth_response);
if (p_auth->auth_opaque_flag)
{
offset += snprintf(buff+offset, buflen-offset,
", opaque=\"%s\"", p_auth->auth_opaque);
}
if (p_auth->auth_qop[0] != '\0')
{
offset += snprintf(buff+offset, buflen-offset,
", qop=\"%s\", cnonce=\"%s\", nc=%s",
p_auth->auth_qop, p_auth->auth_cnonce, p_auth->auth_ncstr);
}
if (p_auth->auth_algorithm[0] != '\0')
{
offset += snprintf(buff+offset, buflen-offset,
", algorithm=%s", p_auth->auth_algorithm);
}
rtsp_add_tx_msg_line(tx_msg, "Authorization", "%s", buff);
}
else if (p_rua->auth_mode == 0) // basic
{
char buff[512] = {'\0'};
char basic[512] = {'\0'};
snprintf(buff, sizeof(buff), "%s:%s", p_auth->auth_name, p_auth->auth_pwd);
base64_encode((uint8 *)buff, (int)strlen(buff), basic, sizeof(basic));
rtsp_add_tx_msg_line(tx_msg, "Authorization", "Basic %s", basic);
}
}
HRTSP_MSG * rcua_build_options(RCUA * p_rua)
{
HRTSP_MSG * tx_msg = rtsp_get_msg_buf();
if (tx_msg == NULL)
{
log_print(HT_LOG_ERR, "%s, rtsp_get_msg_buf return NULL!!!\r\n", __FUNCTION__);
return NULL;
}
tx_msg->msg_type = 0;
tx_msg->msg_sub_type = RTSP_MT_OPTIONS;
rtsp_add_tx_msg_fline(tx_msg, "OPTIONS", "%s RTSP/1.0", p_rua->uri);
rtsp_add_tx_msg_line(tx_msg, "CSeq", "%u", p_rua->cseq);
rcua_build_auth_line(p_rua, tx_msg, "OPTIONS");
if (p_rua->sid[0] != '\0')
{
rtsp_add_tx_msg_line(tx_msg, "Session", "%s", p_rua->sid);
}
rtsp_add_tx_msg_line(tx_msg, "User-Agent", p_rua->user_agent);
return tx_msg;
}
HRTSP_MSG * rcua_build_describe(RCUA * p_rua)
{
HRTSP_MSG * tx_msg = rtsp_get_msg_buf();
if (tx_msg == NULL)
{
log_print(HT_LOG_ERR, "%s, rtsp_get_msg_buf return NULL!!!\r\n", __FUNCTION__);
return NULL;
}
tx_msg->msg_type = 0;
tx_msg->msg_sub_type = RTSP_MT_DESCRIBE;
rtsp_add_tx_msg_fline(tx_msg, "DESCRIBE", "%s RTSP/1.0", p_rua->uri);
rtsp_add_tx_msg_line(tx_msg, "CSeq", "%u", p_rua->cseq);
rcua_build_auth_line(p_rua, tx_msg, "DESCRIBE");
rtsp_add_tx_msg_line(tx_msg, "Accept", "application/sdp");
rtsp_add_tx_msg_line(tx_msg, "User-Agent", p_rua->user_agent);
#ifdef BACKCHANNEL
if (p_rua->backchannel)
{
rtsp_add_tx_msg_line(tx_msg, "Require", "www.onvif.org/ver20/backchannel");
}
#endif
return tx_msg;
}
void rcua_build_setup_fline(HRTSP_MSG * tx_msg, const char * ctl, const char * uri)
{
if (strncmp(ctl, "rtsp://", 7) == 0)
{
rtsp_add_tx_msg_fline(tx_msg, "SETUP", "%s RTSP/1.0", ctl);
}
else
{
int len = (int)strlen(uri);
if (uri[len-1] == '/')
{
rtsp_add_tx_msg_fline(tx_msg, "SETUP", "%s%s RTSP/1.0", uri, ctl);
}
else
{
rtsp_add_tx_msg_fline(tx_msg, "SETUP", "%s/%s RTSP/1.0", uri, ctl);
}
}
}
HRTSP_MSG * rcua_build_setup(RCUA * p_rua, int av_t)
{
HRTSP_MSG * tx_msg = rtsp_get_msg_buf();
if (tx_msg == NULL)
{
log_print(HT_LOG_ERR, "%s, rtsp_get_msg_buf return NULL!!!\r\n", __FUNCTION__);
return NULL;
}
tx_msg->msg_type = 0;
tx_msg->msg_sub_type = RTSP_MT_SETUP;
rcua_build_setup_fline(tx_msg, p_rua->channels[av_t].ctl, p_rua->uri);
rtsp_add_tx_msg_line(tx_msg, "CSeq", "%u", p_rua->cseq);
if (p_rua->sid[0] != '\0')
{
rtsp_add_tx_msg_line(tx_msg, "Session", "%s", p_rua->sid);
}
rcua_build_auth_line(p_rua, tx_msg, "SETUP");
if (p_rua->rtp_tcp) // TCP
{
rtsp_add_tx_msg_line(tx_msg, "Transport", "RTP/AVP/TCP;unicast;interleaved=%u-%u",
p_rua->channels[av_t].interleaved, p_rua->channels[av_t].interleaved+1);
}
else if (p_rua->rtp_mcast) // rtp multicast
{
rtsp_add_tx_msg_line(tx_msg, "Transport", "RTP/AVP;multicast;port=%u-%u",
p_rua->channels[av_t].r_port, p_rua->channels[av_t].r_port+1);
}
else
{
rtsp_add_tx_msg_line(tx_msg, "Transport", "RTP/AVP;unicast;client_port=%u-%u",
p_rua->channels[av_t].l_port, p_rua->channels[av_t].l_port+1);
}
rtsp_add_tx_msg_line(tx_msg, "User-Agent", p_rua->user_agent);
#ifdef BACKCHANNEL
if (av_t == AV_TYPE_BACKCHANNEL) // backchannel
{
rtsp_add_tx_msg_line(tx_msg, "Require", "www.onvif.org/ver20/backchannel");
}
#endif
#ifdef REPLAY
if (p_rua->replay)
{
rtsp_add_tx_msg_line(tx_msg, "Require", "onvif-replay");
}
#endif
return tx_msg;
}
HRTSP_MSG * rcua_build_play(RCUA * p_rua)
{
HRTSP_MSG * tx_msg = rtsp_get_msg_buf();
if (tx_msg == NULL)
{
log_print(HT_LOG_ERR, "%s, rtsp_get_msg_buf return NULL!!!\r\n", __FUNCTION__);
return NULL;
}
tx_msg->msg_type = 0;
tx_msg->msg_sub_type = RTSP_MT_PLAY;
rtsp_add_tx_msg_fline(tx_msg, "PLAY", "%s RTSP/1.0", p_rua->uri);
rtsp_add_tx_msg_line(tx_msg, "CSeq", "%u", p_rua->cseq);
rcua_build_auth_line(p_rua, tx_msg, "PLAY");
rtsp_add_tx_msg_line(tx_msg, "Session", "%s", p_rua->sid);
rtsp_add_tx_msg_line(tx_msg, "Range", "npt=%0.3f-", p_rua->seek_pos/1000.0);
rtsp_add_tx_msg_line(tx_msg, "User-Agent", p_rua->user_agent);
#ifdef BACKCHANNEL
if (p_rua->backchannel) // backchannel
{
rtsp_add_tx_msg_line(tx_msg, "Require", "www.onvif.org/ver20/backchannel");
}
#endif
#ifdef REPLAY
if (p_rua->replay)
{
rtsp_add_tx_msg_line(tx_msg, "Require", "onvif-replay");
if (p_rua->scale_flag)
{
rtsp_add_tx_msg_line(tx_msg, "Scale", "%8.2f", p_rua->scale / 100.0);
}
if (p_rua->rate_control_flag)
{
rtsp_add_tx_msg_line(tx_msg, "Rate-Control", "%s", p_rua->rate_control ? "yes" : "no");
}
if (p_rua->immediate_flag && p_rua->immediate)
{
rtsp_add_tx_msg_line(tx_msg, "Immediate", "yes");
}
if (p_rua->frame_flag)
{
if (1 == p_rua->frame)
{
rtsp_add_tx_msg_line(tx_msg, "Frames", "predicted");
}
else if (2 == p_rua->frame)
{
if (p_rua->frame_interval_flag && p_rua->frame_interval)
{
rtsp_add_tx_msg_line(tx_msg, "Frames", "intra/%d", p_rua->frame_interval);
}
else
{
rtsp_add_tx_msg_line(tx_msg, "Frames", "intra");
}
}
}
if (p_rua->range_flag && p_rua->replay_start > 0)
{
char range[256] = {'\0'};
char start[32] = {'\0'}, end[32] = {'\0'};
struct tm *t1;
t1 = gmtime(&p_rua->replay_start);
snprintf(start, sizeof(start)-1, "%04d%02d%02dT%02d%02d%02dZ",
t1->tm_year+1900, t1->tm_mon+1, t1->tm_mday,
t1->tm_hour, t1->tm_min, t1->tm_sec);
if (p_rua->replay_end > 0)
{
t1 = gmtime(&p_rua->replay_end);
snprintf(end, sizeof(end)-1, "%04d%02d%02dT%02d%02d%02dZ",
t1->tm_year+1900, t1->tm_mon+1, t1->tm_mday,
t1->tm_hour, t1->tm_min, t1->tm_sec);
snprintf(range, sizeof(range)-1, "clock=%s-%s", start, end);
}
else
{
snprintf(range, sizeof(range)-1, "clock=%s-", start);
}
rtsp_add_tx_msg_line(tx_msg, "Range", range);
}
}
#endif
return tx_msg;
}
HRTSP_MSG * rcua_build_pause(RCUA * p_rua)
{
HRTSP_MSG * tx_msg = rtsp_get_msg_buf();
if (tx_msg == NULL)
{
log_print(HT_LOG_ERR, "%s::rtsp_get_msg_buf return NULL!!!\r\n", __FUNCTION__);
return NULL;
}
tx_msg->msg_type = 0;
tx_msg->msg_sub_type = RTSP_MT_PAUSE;
rtsp_add_tx_msg_fline(tx_msg, "PAUSE", "%s RTSP/1.0", p_rua->uri);
rtsp_add_tx_msg_line(tx_msg, "CSeq", "%u", p_rua->cseq);
rcua_build_auth_line(p_rua, tx_msg, "PAUSE");
rtsp_add_tx_msg_line(tx_msg, "Session", "%s", p_rua->sid);
rtsp_add_tx_msg_line(tx_msg, "User-Agent", p_rua->user_agent);
return tx_msg;
}
HRTSP_MSG * rcua_build_get_parameter(RCUA * p_rua)
{
HRTSP_MSG * tx_msg = rtsp_get_msg_buf();
if (tx_msg == NULL)
{
log_print(HT_LOG_ERR, "%s, rtsp_get_msg_buf return NULL!!!\r\n", __FUNCTION__);
return NULL;
}
tx_msg->msg_type = 0;
tx_msg->msg_sub_type = RTSP_MT_GET_PARAMETER;
rtsp_add_tx_msg_fline(tx_msg, "GET_PARAMETER", "%s RTSP/1.0", p_rua->uri);
rtsp_add_tx_msg_line(tx_msg, "CSeq", "%u", p_rua->cseq);
rcua_build_auth_line(p_rua, tx_msg, "GET_PARAMETER");
rtsp_add_tx_msg_line(tx_msg, "Session", "%s", p_rua->sid);
rtsp_add_tx_msg_line(tx_msg, "User-Agent", p_rua->user_agent);
return tx_msg;
}
HRTSP_MSG * rcua_build_teardown(RCUA * p_rua)
{
HRTSP_MSG * tx_msg = rtsp_get_msg_buf();
if (tx_msg == NULL)
{
log_print(HT_LOG_ERR, "%s, rtsp_get_msg_buf return NULL!!!\r\n", __FUNCTION__);
return NULL;
}
tx_msg->msg_type = 0;
tx_msg->msg_sub_type = RTSP_MT_TEARDOWN;
rtsp_add_tx_msg_fline(tx_msg, "TEARDOWN", "%s RTSP/1.0", p_rua->uri);
rtsp_add_tx_msg_line(tx_msg, "CSeq", "%u", p_rua->cseq);
rcua_build_auth_line(p_rua, tx_msg, "TEARDOWN");
rtsp_add_tx_msg_line(tx_msg, "Session", "%s", p_rua->sid);
rtsp_add_tx_msg_line(tx_msg, "User-Agent", p_rua->user_agent);
#ifdef BACKCHANNEL
if (p_rua->backchannel) // backchannel
{
rtsp_add_tx_msg_line(tx_msg, "Require", "www.onvif.org/ver20/backchannel");
}
#endif
return tx_msg;
}
BOOL rcua_get_media_info(RCUA * p_rua, HRTSP_MSG * rx_msg)
{
if (rx_msg == NULL || p_rua == NULL)
{
return FALSE;
}
if (!rtsp_msg_with_sdp(rx_msg))
{
return FALSE;
}
rtsp_get_remote_cap(rx_msg, "video", &(p_rua->channels[AV_VIDEO_CH].cap_count),
p_rua->channels[AV_VIDEO_CH].cap, &p_rua->channels[AV_VIDEO_CH].r_port);
rtsp_get_remote_cap_desc(rx_msg, "video", p_rua->channels[AV_VIDEO_CH].cap_desc);
#ifdef BACKCHANNEL
if (p_rua->backchannel)
{
rtsp_get_remote_cap(rx_msg, "audio", &(p_rua->channels[AV_AUDIO_CH].cap_count),
p_rua->channels[AV_AUDIO_CH].cap, &p_rua->channels[AV_AUDIO_CH].r_port, "recvonly");
rtsp_get_remote_cap_desc(rx_msg, "audio", p_rua->channels[AV_AUDIO_CH].cap_desc, "recvonly");
rtsp_get_remote_cap(rx_msg, "audio", &(p_rua->channels[AV_BACK_CH].cap_count),
p_rua->channels[AV_BACK_CH].cap, &p_rua->channels[AV_BACK_CH].r_port, "sendonly");
rtsp_get_remote_cap_desc(rx_msg, "audio", p_rua->channels[AV_BACK_CH].cap_desc, "sendonly");
}
else
#endif
{
rtsp_get_remote_cap(rx_msg, "audio", &(p_rua->channels[AV_AUDIO_CH].cap_count),
p_rua->channels[AV_AUDIO_CH].cap, &p_rua->channels[AV_AUDIO_CH].r_port);
rtsp_get_remote_cap_desc(rx_msg, "audio", p_rua->channels[AV_AUDIO_CH].cap_desc);
}
#ifdef METADATA
rtsp_get_remote_cap(rx_msg, "application", &(p_rua->channels[AV_METADATA_CH].cap_count),
p_rua->channels[AV_METADATA_CH].cap, &p_rua->channels[AV_METADATA_CH].r_port);
rtsp_get_remote_cap_desc(rx_msg, "application", p_rua->channels[AV_METADATA_CH].cap_desc);
#endif
return TRUE;
}
void rcua_send_rtsp_msg(RCUA * p_rua, HRTSP_MSG * tx_msg)
{
int slen;
char * tx_buf;
int offset = 0;
int buf_len;
char rtsp_tx_buffer[2048+RTSP_SND_RESV_SIZE];
SOCKET fd = -1;
if (tx_msg == NULL)
{
return;
}
#ifdef OVER_HTTP
if (p_rua->over_http)
{
fd = p_rua->rtsp_send.cfd;
}
else
#endif
#ifdef OVER_WEBSOCKET
if (p_rua->over_ws)
{
fd = p_rua->ws_http.cfd;
}
else
#endif
fd = p_rua->fd;
if (fd <= 0)
{
return;
}
tx_buf = rtsp_tx_buffer + RTSP_SND_RESV_SIZE;
buf_len = sizeof(rtsp_tx_buffer) - RTSP_SND_RESV_SIZE;
offset += snprintf(tx_buf+offset, buf_len-offset, "%s %s\r\n", tx_msg->first_line.header, tx_msg->first_line.value_string);
HDRV * pHdrV = (HDRV *)pps_lookup_start(&(tx_msg->rtsp_ctx));
while (pHdrV != NULL)
{
offset += snprintf(tx_buf+offset, buf_len-offset, "%s: %s\r\n", pHdrV->header, pHdrV->value_string);
pHdrV = (HDRV *)pps_lookup_next(&(tx_msg->rtsp_ctx), pHdrV);
}
pps_lookup_end(&(tx_msg->rtsp_ctx));
offset += snprintf(tx_buf+offset, buf_len-offset, "\r\n");
if (tx_msg->sdp_ctx.node_num != 0)
{
pHdrV = (HDRV *)pps_lookup_start(&(tx_msg->sdp_ctx));
while (pHdrV != NULL)
{
if (pHdrV->header[0] != '\0')
{
offset += snprintf(tx_buf+offset, buf_len-offset, "%s=%s\r\n", pHdrV->header, pHdrV->value_string);
}
else
{
offset += snprintf(tx_buf+offset, buf_len-offset, "%s\r\n", pHdrV->value_string);
}
pHdrV = (HDRV *)pps_lookup_next(&(tx_msg->sdp_ctx), pHdrV);
}
pps_lookup_end(&(tx_msg->sdp_ctx));
}
log_print(HT_LOG_DBG, "TX >> %s\r\n", tx_buf);
#ifdef OVER_HTTP
if (p_rua->over_http)
{
char tx_buf_base64[4096];
base64_encode((uint8 *)tx_buf, offset, tx_buf_base64, sizeof(tx_buf_base64));
tx_buf = tx_buf_base64;
offset = strlen(tx_buf_base64);
slen = http_cln_tx(&p_rua->rtsp_send, tx_buf, offset);
}
else
#endif
#ifdef OVER_WEBSOCKET
if (p_rua->over_ws)
{
int extra = rtsp_ws_encode_data((uint8 *)tx_buf, offset, 0x82, 1);
tx_buf -= extra;
offset += extra;
slen = http_cln_tx(&p_rua->ws_http, tx_buf, offset);
}
else
#endif
{
slen = send(fd, tx_buf, offset, 0);
}
if (slen != offset)
{
log_print(HT_LOG_ERR, "%s, slen=%d, offset=%d, send message failed!!!\r\n",
__FUNCTION__, slen, offset);
}
}
BOOL rcua_get_sdp_video_desc(RCUA * p_rua, const char * key, int * pt, char * p_sdp, int max_len)
{
int payload_type = 0, i;
int rtpmap_len = (int)strlen("a=rtpmap:");
char key_str[64] = {'\0'};
strncpy(key_str, key, sizeof(key_str)-1);
for (i=0; i<MAX_AVN; i++)
{
char * ptr = p_rua->channels[AV_VIDEO_CH].cap_desc[i];
if (memcmp(ptr, "a=rtpmap:", rtpmap_len) == 0)
{
char pt_buf[16];
char code_buf[64] = {'\0'};
int next_offset = 0;
ptr += rtpmap_len;
if (GetLineWord(ptr, 0, (int)strlen(ptr), pt_buf, sizeof(pt_buf), &next_offset, WORD_TYPE_NUM) == FALSE)
{
return FALSE;
}
GetLineWord(ptr, next_offset, (int)strlen(ptr)-next_offset, code_buf, sizeof(code_buf), &next_offset, WORD_TYPE_STRING);
if (memcmp(uppercase(code_buf), uppercase(key_str), strlen(key_str)) == 0)
{
payload_type = atoi(pt_buf);
break;
}
}
}
if (payload_type <= 0)
{
return FALSE;
}
if (pt)
{
*pt = payload_type;
}
if (p_sdp == NULL)
{
return TRUE;
}
p_sdp[0] = '\0';
char fmtp_buf[32];
int fmtp_len = snprintf(fmtp_buf, sizeof(fmtp_buf), "a=fmtp:%d", payload_type);
for (i=0; i<MAX_AVN; i++)
{
char * ptr = p_rua->channels[AV_VIDEO_CH].cap_desc[i];
if (memcmp(ptr, fmtp_buf, fmtp_len) == 0)
{
ptr += rtpmap_len+1;
strncpy(p_sdp, ptr, max_len);
break;
}
}
return TRUE;
}
BOOL rcua_get_sdp_audio_desc(RCUA * p_rua, const char * key, int * pt, char * p_sdp, int max_len)
{
int payload_type = 0, i;
int rtpmap_len = (int)strlen("a=rtpmap:");
char key_str[64] = {'\0'};
strncpy(key_str, key, sizeof(key_str)-1);
for (i=0; i<MAX_AVN; i++)
{
char * ptr = p_rua->channels[AV_AUDIO_CH].cap_desc[i];
if (memcmp(ptr, "a=rtpmap:", rtpmap_len) == 0)
{
char pt_buf[16];
char code_buf[64] = {'\0'};
int next_offset = 0;
ptr += rtpmap_len;
if (GetLineWord(ptr, 0, (int)strlen(ptr), pt_buf, sizeof(pt_buf), &next_offset, WORD_TYPE_NUM) == FALSE)
{
return FALSE;
}
GetLineWord(ptr, next_offset, (int)strlen(ptr)-next_offset, code_buf, sizeof(code_buf), &next_offset, WORD_TYPE_STRING);
if (memcmp(uppercase(code_buf), uppercase(key_str), strlen(key_str)) == 0)
{
payload_type = atoi(pt_buf);
break;
}
}
}
if (payload_type <= 0)
{
return FALSE;
}
if (pt)
{
*pt = payload_type;
}
if (p_sdp == NULL)
{
return TRUE;
}
p_sdp[0] = '\0';
char fmtp_buf[32];
int fmtp_len = snprintf(fmtp_buf, sizeof(fmtp_buf), "a=fmtp:%d", payload_type);
for (i=0; i<MAX_AVN; i++)
{
char * ptr = p_rua->channels[AV_AUDIO_CH].cap_desc[i];
if (memcmp(ptr, fmtp_buf, fmtp_len) == 0)
{
ptr += rtpmap_len+1;
strncpy(p_sdp, ptr, max_len);
break;
}
}
return TRUE;
}
BOOL rcua_get_sdp_h264_desc(RCUA * p_rua, int * pt, char * p_sdp, int max_len)
{
return rcua_get_sdp_video_desc(p_rua, "H264/90000", pt, p_sdp, max_len);
}
BOOL rcua_get_sdp_h264_params(RCUA * p_rua, int * pt, char * p_sps_pps, int max_len)
{
BOOL ret = FALSE;
char sdp[1024] = {'\0'};
if (rcua_get_sdp_h264_desc(p_rua, pt, sdp, sizeof(sdp)) == FALSE)
{
return FALSE;
}
char * p_substr = strstr(sdp, "sprop-parameter-sets=");
if (p_substr != NULL)
{
p_substr += strlen("sprop-parameter-sets=");
char * p_tmp = p_substr;
while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0')
{
p_tmp++;
}
int sps_base64_len = (int)(p_tmp - p_substr);
if (sps_base64_len < max_len)
{
memcpy(p_sps_pps, p_substr, sps_base64_len);
p_sps_pps[sps_base64_len] = '\0';
ret = TRUE;
}
}
return ret;
}
BOOL rcua_get_sdp_h265_desc(RCUA * p_rua, int * pt, char * p_sdp, int max_len)
{
return rcua_get_sdp_video_desc(p_rua, "H265/90000", pt, p_sdp, max_len);
}
BOOL rcua_get_sdp_h265_params(RCUA * p_rua, int * pt, BOOL * donfield, char * p_vps, int vps_len, char * p_sps, int sps_len, char * p_pps, int pps_len)
{
char sdp[1024] = {'\0'};
if (rcua_get_sdp_h265_desc(p_rua, pt, sdp, sizeof(sdp)) == FALSE)
{
return FALSE;
}
char * p_substr = strstr(sdp, "sprop-depack-buf-nalus=");
if (p_substr != NULL)
{
p_substr += strlen("sprop-depack-buf-nalus=");
char * p_tmp = p_substr;
while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0')
{
p_tmp++;
}
int len = (int)(p_tmp - p_substr);
if (len > 0)
{
if (donfield)
{
*donfield = (atoi(p_substr) > 0 ? TRUE : FALSE);
}
}
else
{
return FALSE;
}
}
p_substr = strstr(sdp, "sprop-vps=");
if (p_substr != NULL)
{
p_substr += strlen("sprop-vps=");
char * p_tmp = p_substr;
while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0')
{
p_tmp++;
}
int len = (int)(p_tmp - p_substr);
if (len < vps_len)
{
memcpy(p_vps, p_substr, len);
p_vps[len] = '\0';
}
else
{
return FALSE;
}
}
p_substr = strstr(sdp, "sprop-sps=");
if (p_substr != NULL)
{
p_substr += strlen("sprop-sps=");
char * p_tmp = p_substr;
while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0')
{
p_tmp++;
}
int len = (int)(p_tmp - p_substr);
if (len < sps_len)
{
memcpy(p_sps, p_substr, len);
p_sps[len] = '\0';
}
else
{
return FALSE;
}
}
p_substr = strstr(sdp, "sprop-pps=");
if (p_substr != NULL)
{
p_substr += strlen("sprop-pps=");
char * p_tmp = p_substr;
while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0')
{
p_tmp++;
}
int len = (int)(p_tmp - p_substr);
if (len < pps_len)
{
memcpy(p_pps, p_substr, len);
p_pps[len] = '\0';
}
else
{
return FALSE;
}
}
return TRUE;
}
BOOL rcua_get_sdp_mp4_desc(RCUA * p_rua, int * pt, char * p_sdp, int max_len)
{
return rcua_get_sdp_video_desc(p_rua, "MP4V-ES/90000", pt, p_sdp, max_len);
}
BOOL rcua_get_sdp_mp4_params(RCUA * p_rua, int * pt, char * p_cfg, int max_len)
{
BOOL ret = FALSE;
char sdp[1024] = {'\0'};
if (rcua_get_sdp_mp4_desc(p_rua, pt, sdp, sizeof(sdp)) == FALSE)
{
return FALSE;
}
char * p_substr = strstr(sdp, "config=");
if (p_substr != NULL)
{
p_substr += strlen("config=");
char * p_tmp = p_substr;
while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0')
{
p_tmp++;
}
int cfg_len = (int)(p_tmp - p_substr);
if (cfg_len < max_len)
{
memcpy(p_cfg, p_substr, cfg_len);
p_cfg[cfg_len] = '\0';
ret = TRUE;
}
else
{
ret = FALSE;
}
}
return ret;
}
BOOL rcua_get_sdp_aac_desc(RCUA * p_rua, int * pt, char * p_sdp, int max_len)
{
return rcua_get_sdp_audio_desc(p_rua, "MPEG4-GENERIC", pt, p_sdp, max_len);
}
BOOL rcua_get_sdp_aac_params(RCUA * p_rua, int *pt, int *sizelength, int *indexlength, int *indexdeltalength, char * p_cfg, int max_len)
{
char sdp[1024] = {'\0'};
if (rcua_get_sdp_aac_desc(p_rua, pt, sdp, sizeof(sdp)) == FALSE)
{
return FALSE;
}
char * p_substr = strstr(sdp, "config=");
if (p_substr != NULL)
{
p_substr += strlen("config=");
char * p_tmp = p_substr;
while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0')
{
p_tmp++;
}
int len = (int)(p_tmp - p_substr);
if (len < max_len)
{
memcpy(p_cfg, p_substr, len);
p_cfg[len] = '\0';
}
else
{
return FALSE;
}
}
p_substr = strstr(sdp, "sizelength=");
if (p_substr != NULL)
{
p_substr += strlen("sizelength=");
char * p_tmp = p_substr;
while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0')
{
p_tmp++;
}
int len = (int)(p_tmp - p_substr);
if (len > 0)
{
*sizelength = atoi(p_substr);
}
}
p_substr = strstr(sdp, "indexlength=");
if (p_substr != NULL)
{
p_substr += strlen("indexlength=");
char * p_tmp = p_substr;
while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0')
{
p_tmp++;
}
int len = (int)(p_tmp - p_substr);
if (len > 0)
{
*indexlength = atoi(p_substr);
}
}
p_substr = strstr(sdp, "indexdeltalength=");
if (p_substr != NULL)
{
p_substr += strlen("indexdeltalength=");
char * p_tmp = p_substr;
while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0')
{
p_tmp++;
}
int len = (int)(p_tmp - p_substr);
if (len > 0)
{
*indexdeltalength = atoi(p_substr);
}
}
return TRUE;
}
SOCKET rcua_init_udp_connection(uint16 port)
{
struct sockaddr_in addr;
SOCKET fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd <= 0)
{
log_print(HT_LOG_ERR, "%s, socket SOCK_DGRAM error!\n", __FUNCTION__);
return -1;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
int len = 1024*1024;
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&len, sizeof(int)))
{
log_print(HT_LOG_WARN, "%s, setsockopt SO_RCVBUF error!\r\n", __FUNCTION__);
}
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
log_print(HT_LOG_ERR, "%s, Bind udp socket fail, port = %d, error = %s\r\n",
__FUNCTION__, port, sys_os_get_socket_error());
closesocket(fd);
return -1;
}
return fd;
}
SOCKET rcua_init_mc_connection(uint16 port, char * destination)
{
struct sockaddr_in addr;
struct ip_mreq mcast;
SOCKET fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd <= 0)
{
log_print(HT_LOG_ERR, "%s, socket SOCK_DGRAM error!\n", __FUNCTION__);
return -1;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = get_default_if_ip();
addr.sin_port = htons(port);
/* reuse socket addr */
int opt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)))
{
log_print(HT_LOG_WARN, "%s, setsockopt SO_REUSEADDR error!\r\n", __FUNCTION__);
}
int len = 1024*1024;
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&len, sizeof(int)))
{
log_print(HT_LOG_WARN, "%s, setsockopt SO_RCVBUF error!\r\n", __FUNCTION__);
}
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
log_print(HT_LOG_ERR, "%s, Bind udp socket fail, port = %d, error = %s\r\n",
__FUNCTION__, port, sys_os_get_socket_error());
closesocket(fd);
return -1;
}
int ttl = 255;
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, sizeof(ttl));
mcast.imr_multiaddr.s_addr = inet_addr(destination);
mcast.imr_interface.s_addr = addr.sin_addr.s_addr;
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mcast, sizeof(mcast)) < 0)
{
log_print(HT_LOG_ERR, "%s, setsockopt IP_ADD_MEMBERSHIP error!%s\r\n",
__FUNCTION__, sys_os_get_socket_error());
closesocket(fd);
return -1;
}
return fd;
}