970 lines
20 KiB
C++
970 lines
20 KiB
C++
/***************************************************************************************
|
||
*
|
||
* 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-2022, 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_tx.h"
|
||
#include "media_util.h"
|
||
#include "rtp.h"
|
||
#include "h264.h"
|
||
#include "h265.h"
|
||
#include "media_format.h"
|
||
|
||
|
||
/************************************************************************/
|
||
|
||
int gb_rtp_tcp_tx(SUA * p_sua, UA_MEDIA * p_media, uint8 * p_data, int len)
|
||
{
|
||
int offset = 0;
|
||
SOCKET fd = p_media->ua_m_fd;
|
||
|
||
if (p_sua->uaf_rtp_mux)
|
||
{
|
||
fd = p_media->mux_fd;
|
||
}
|
||
|
||
if (fd <= 0)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
while (p_sua->uaf_rtp_tx && offset < len)
|
||
{
|
||
#if __WINDOWS_OS__
|
||
int tlen = send(fd, (const char *)p_data+offset, len-offset, 0);
|
||
#else
|
||
int tlen = send(fd, (const char *)p_data+offset, len-offset, MSG_DONTWAIT);
|
||
#endif
|
||
if (tlen > 0)
|
||
{
|
||
offset += tlen;
|
||
}
|
||
else
|
||
{
|
||
int sockerr = sys_os_get_socket_error_num();
|
||
if (sockerr == EINTR || sockerr == EAGAIN)
|
||
{
|
||
usleep(1000);
|
||
continue;
|
||
}
|
||
|
||
log_print(HT_LOG_ERR, "%s, send failed, fd[%d], tlen[%d,%d], err[%d][%s]!!!\r\n",
|
||
__FUNCTION__, fd, tlen, len-offset, sockerr, sys_os_get_socket_error());
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
return offset;
|
||
}
|
||
|
||
/**
|
||
* Send rtp data by UDP socket
|
||
*
|
||
* @param p_rua rtsp user agent
|
||
* @param av_t whether video rtp data
|
||
* @param p_data rtp data
|
||
* @param len rtp data len
|
||
* @return -1 on error, or the data length has been sent
|
||
*/
|
||
int gb_rtp_udp_tx(SUA * p_sua, UA_MEDIA * p_media, uint8 * p_data, int len)
|
||
{
|
||
int offset = 0;
|
||
SOCKET fd;
|
||
struct sockaddr_in addr;
|
||
|
||
addr.sin_family = AF_INET;
|
||
addr.sin_addr.s_addr = p_sua->remote_media_ip;
|
||
addr.sin_port = htons(p_media->remote_port);
|
||
|
||
if (p_sua->uaf_multicast)
|
||
{
|
||
addr.sin_addr.s_addr = p_sua->multicast_addr;
|
||
}
|
||
|
||
fd = p_media->ua_m_fd;
|
||
|
||
if (p_sua->uaf_rtp_mux)
|
||
{
|
||
fd = p_media->mux_fd;
|
||
}
|
||
|
||
if (fd <= 0)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
while (p_sua->uaf_rtp_tx && offset < len)
|
||
{
|
||
int tlen = sendto(fd, (char *)p_data+offset, len-offset, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
|
||
if (tlen > 0)
|
||
{
|
||
offset += tlen;
|
||
}
|
||
else
|
||
{
|
||
int sockerr = sys_os_get_socket_error_num();
|
||
if (sockerr == EINTR || sockerr == EAGAIN)
|
||
{
|
||
usleep(1000);
|
||
continue;
|
||
}
|
||
|
||
log_print(HT_LOG_ERR, "%s, send failed, fd[%d], tlen[%d,%d], err[%d][%s]!!!\r\n",
|
||
__FUNCTION__, fd, tlen, len-offset, sockerr, sys_os_get_socket_error());
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
return offset;
|
||
}
|
||
|
||
int gb_rtp_video_build(SUA * p_sua, uint8 * p_data, int len, int mbit)
|
||
{
|
||
int slen = 0;
|
||
int offset = 0;
|
||
uint8 buff[40];
|
||
uint8 * p_hdr_ptr;
|
||
|
||
if (p_sua->uaf_v_tcp_rtp)
|
||
{
|
||
offset += rtp_write_uint16(buff+offset, len+12);
|
||
}
|
||
|
||
if (p_sua->uaf_rtp_mux)
|
||
{
|
||
offset += rtp_write_uint32(buff+offset, p_sua->video_rtp_media.mux_id);
|
||
}
|
||
|
||
buff[offset] = (RTP_VERSION << 6);
|
||
offset++;
|
||
|
||
buff[offset] = ((p_sua->v_rtp_info.rtp_pt) | ((mbit & 0x01) << 7));
|
||
offset++;
|
||
|
||
offset += rtp_write_uint16(buff+offset, p_sua->v_rtp_info.rtp_cnt);
|
||
|
||
offset += rtp_write_uint32(buff+offset, p_sua->v_rtp_info.rtp_ts);
|
||
|
||
offset += rtp_write_uint32(buff+offset, p_sua->v_rtp_info.rtp_ssrc);
|
||
|
||
p_hdr_ptr = p_data - offset;
|
||
memcpy(p_hdr_ptr, buff, offset);
|
||
|
||
if (p_sua->uaf_v_tcp_rtp)
|
||
{
|
||
slen = gb_rtp_tcp_tx(p_sua, &p_sua->video_rtp_media, p_hdr_ptr, offset+len);
|
||
}
|
||
else
|
||
{
|
||
slen = gb_rtp_udp_tx(p_sua, &p_sua->video_rtp_media, p_hdr_ptr, offset+len);
|
||
}
|
||
|
||
p_sua->v_rtp_info.rtp_cnt = (p_sua->v_rtp_info.rtp_cnt + 1) & 0xFFFF;
|
||
|
||
return (slen == offset+len) ? slen : -1;
|
||
}
|
||
|
||
/**
|
||
* Build video rtp packet and send (not fragment)
|
||
*
|
||
* @param p_rua rtsp user agent
|
||
* @param p_data payload data
|
||
* @param len payload data length
|
||
* @ts the packet timestamp
|
||
* @return 1 on success, -1 on error
|
||
*/
|
||
int gb_rtp_video_tx(SUA * p_sua, uint8 * p_data, int size, uint32 ts)
|
||
{
|
||
int ret = 0;
|
||
int len, max_packet_size;
|
||
uint8 * p = p_data;
|
||
|
||
max_packet_size = RTP_MAX_LEN;
|
||
|
||
p_sua->v_rtp_info.rtp_ts = ts;
|
||
|
||
while (size > 0)
|
||
{
|
||
len = max_packet_size;
|
||
if (len > size)
|
||
{
|
||
len = size;
|
||
}
|
||
|
||
ret = gb_rtp_video_build(p_sua, p, len, (len == size));
|
||
if (ret < 0)
|
||
{
|
||
break;
|
||
}
|
||
|
||
p += len;
|
||
size -= len;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* Judgment and segmentation h264 rtp data into a single package
|
||
*
|
||
* @param fu_flag fragment flag
|
||
* @param fu_s fragment start flag
|
||
* @param fu_e fragment end flag
|
||
* @param len data length
|
||
* @return the fragmention length
|
||
*/
|
||
int gb_rtp_h264_fu_split(int * fu_flag, int * fu_s, int * fu_e, int len)
|
||
{
|
||
if ((*fu_flag) == 0) // have not yet begun fragment
|
||
{
|
||
if (len <= H264_RTP_MAX_LEN) return len; // Need not be fragmented
|
||
|
||
*fu_flag = 1;
|
||
*fu_s = 1;
|
||
*fu_e = 0;
|
||
|
||
return H264_RTP_MAX_LEN;
|
||
}
|
||
else // It has begun to fragment
|
||
{
|
||
*fu_s = 0;
|
||
|
||
if (len <= H264_RTP_MAX_LEN) // End fragmentation
|
||
{
|
||
*fu_e = 1;
|
||
return len;
|
||
}
|
||
else
|
||
{
|
||
return H264_RTP_MAX_LEN;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Build and send h264 fragement rtp packet
|
||
*
|
||
* @param p_rua rtsp user agent
|
||
* @nalu_t the NALU type
|
||
* @fu_s fragement start flag
|
||
* @fu_e fragement end start
|
||
* @param p_data payload data
|
||
* @param len payload data length
|
||
* @return the rtp packet length, -1 on error
|
||
*/
|
||
int gb_rtp_h264_single_fu_build(SUA * p_sua, uint8 nalu_t, int fu_s, int fu_e, uint8 * p_data, int len)
|
||
{
|
||
int mbit = 0;
|
||
int slen;
|
||
int offset = 0;
|
||
uint8 buff[40];
|
||
uint8 * p_rtp_ptr;
|
||
|
||
if (p_sua->uaf_v_tcp_rtp)
|
||
{
|
||
offset += rtp_write_uint16(buff+offset, len+12+2);
|
||
}
|
||
|
||
if (p_sua->uaf_rtp_mux)
|
||
{
|
||
offset += rtp_write_uint32(buff+offset, p_sua->video_rtp_media.mux_id);
|
||
}
|
||
|
||
if (fu_e == 1)
|
||
{
|
||
mbit = 1;
|
||
}
|
||
else
|
||
{
|
||
mbit = 0;
|
||
}
|
||
|
||
buff[offset] = (RTP_VERSION << 6);
|
||
offset++;
|
||
|
||
buff[offset] = ((p_sua->v_rtp_info.rtp_pt) | ((mbit & 0x01) << 7));
|
||
offset++;
|
||
|
||
offset += rtp_write_uint16(buff+offset, p_sua->v_rtp_info.rtp_cnt);
|
||
|
||
offset += rtp_write_uint32(buff+offset, p_sua->v_rtp_info.rtp_ts);
|
||
|
||
offset += rtp_write_uint32(buff+offset, p_sua->v_rtp_info.rtp_ssrc);
|
||
|
||
buff[offset] = (nalu_t & 0x60) | 28;
|
||
offset++;
|
||
|
||
buff[offset] = (nalu_t & 0x1F);
|
||
|
||
if (fu_s == 1)
|
||
{
|
||
buff[offset] |= 0x80;
|
||
}
|
||
|
||
if (fu_e == 1)
|
||
{
|
||
buff[offset] |= 0x40;
|
||
}
|
||
|
||
offset++;
|
||
|
||
p_rtp_ptr = p_data - offset;
|
||
memcpy(p_rtp_ptr, buff, offset);
|
||
|
||
if (p_sua->uaf_v_tcp_rtp)
|
||
{
|
||
slen = gb_rtp_tcp_tx(p_sua, &p_sua->video_rtp_media, p_rtp_ptr, offset+len);
|
||
}
|
||
else
|
||
{
|
||
slen = gb_rtp_udp_tx(p_sua, &p_sua->video_rtp_media, p_rtp_ptr, offset+len);
|
||
}
|
||
|
||
p_sua->v_rtp_info.rtp_cnt = (p_sua->v_rtp_info.rtp_cnt + 1) & 0xFFFF;
|
||
|
||
return (slen == offset+len) ? slen : -1;
|
||
}
|
||
|
||
/**
|
||
* Send h264 rtp packet
|
||
*
|
||
* @param p_rua rtsp user agent
|
||
* @ts the packet timestamp
|
||
* @nalu_t the NALU type
|
||
* @fu_flag fragment flag
|
||
* @fu_s fragement start flag
|
||
* @fu_e fragement end start
|
||
* @param p_data payload data
|
||
* @param len payload data length
|
||
* @return the rtp packet length, -1 on error
|
||
*/
|
||
int gb_rtp_h264_tx(SUA * p_sua, uint8 nalu_t, int fu_flag, int fu_s, int fu_e, uint8 * p_data, int len)
|
||
{
|
||
int ret = 0;
|
||
|
||
if (fu_flag == 0)
|
||
{
|
||
ret = gb_rtp_video_build(p_sua, p_data, len, 1);
|
||
}
|
||
else
|
||
{
|
||
ret = gb_rtp_h264_single_fu_build(p_sua, nalu_t, fu_s, fu_e, p_data, len);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* Build h264 video rtp packet and send
|
||
*
|
||
* @param p_rua rtsp user agent
|
||
* @param p_data payload data
|
||
* @param len payload data length
|
||
* @ts the packet timestamp
|
||
* @i_flag the I-Frame flag
|
||
* @return 1 on success, -1 on error
|
||
*/
|
||
int gb_rtp_h264_video_pkt_tx(SUA * p_sua, uint8 * p_data, int len)
|
||
{
|
||
int ret = 1;
|
||
int frame_len = len;
|
||
int fu_s = 0, fu_e = 0, fu_flag = 0; // Fragement start, end flag
|
||
uint8 * p_tx_data = p_data;
|
||
uint8 nalu_t = p_tx_data[0];
|
||
int keyframe = ((nalu_t & 0x1F) == 5);
|
||
|
||
while (frame_len > 0)
|
||
{
|
||
int tlen = gb_rtp_h264_fu_split(&fu_flag, &fu_s, &fu_e, frame_len);
|
||
if (fu_flag == 1)
|
||
{
|
||
if (fu_s == 1)
|
||
{
|
||
p_tx_data++;
|
||
tlen--;
|
||
frame_len--;
|
||
}
|
||
}
|
||
|
||
// the sps and pps frame
|
||
if ((nalu_t & 0x1F) == 7 || (nalu_t & 0x1F) == 8)
|
||
{
|
||
ret = gb_rtp_h264_tx(p_sua, nalu_t, fu_flag, fu_s, fu_e, p_tx_data, tlen);
|
||
if (ret == -1)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
else if (p_sua->uaf_iframe_tx == 0 && 0 == keyframe)
|
||
{
|
||
// Non-I-frame, not yet sent I-frame, skip P frame
|
||
}
|
||
else
|
||
{
|
||
ret = gb_rtp_h264_tx(p_sua, nalu_t, fu_flag, fu_s, fu_e, p_tx_data, tlen);
|
||
if (ret == -1)
|
||
{
|
||
break;
|
||
}
|
||
|
||
p_sua->uaf_iframe_tx = 1;
|
||
}
|
||
|
||
p_tx_data += tlen;
|
||
frame_len -= tlen;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* Build h264 video rtp packet and send
|
||
*
|
||
* @param p_rua rtsp user agent
|
||
* @param p_data payload data
|
||
* @param len payload data length
|
||
* @ts the packet timestamp
|
||
* @return 1 on success, -1 on error
|
||
*/
|
||
int gb_rtp_h264_video_tx(SUA * p_sua, uint8 * p_data, int len, uint32 ts)
|
||
{
|
||
int ret = 1;
|
||
|
||
uint8 *r, *end = p_data + len;
|
||
r = avc_find_startcode(p_data, end);
|
||
|
||
p_sua->v_rtp_info.rtp_ts = ts;
|
||
|
||
while (r < end)
|
||
{
|
||
uint8 *r1;
|
||
|
||
while (!*(r++));
|
||
r1 = avc_find_startcode(r, end);
|
||
|
||
ret = gb_rtp_h264_video_pkt_tx(p_sua, r, r1 - r);
|
||
if (ret < 0)
|
||
{
|
||
break;
|
||
}
|
||
|
||
r = r1;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
int gb_rtp_h265_video_pkt_tx(SUA * p_sua, uint8 * p_data, int len, uint32 ts)
|
||
{
|
||
int frame_len = len;
|
||
uint8 * p_tx_data = p_data;
|
||
int rtp_payload_size = H265_RTP_MAX_LEN - 3;
|
||
int nal_type = (p_tx_data[0] >> 1) & 0x3F;
|
||
|
||
/* send it as one single NAL unit? */
|
||
if (frame_len <= H265_RTP_MAX_LEN)
|
||
{
|
||
gb_rtp_video_build(p_sua, p_tx_data, frame_len, 1);
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
create the HEVC payload header and transmit the buffer as fragmentation units (FU)
|
||
|
||
0 1
|
||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
|F| Type | LayerId | TID |
|
||
+-------------+-----------------+
|
||
|
||
F = 0
|
||
Type = 49 (fragmentation unit (FU))
|
||
LayerId = 0
|
||
TID = 1
|
||
*/
|
||
|
||
uint8 tbuf[2048];
|
||
uint8 * buf1 = tbuf+32;
|
||
uint8 * buf = p_tx_data;
|
||
|
||
buf1[0] = 49 << 1;
|
||
buf1[1] = 1;
|
||
|
||
/*
|
||
create the FU header
|
||
|
||
0 1 2 3 4 5 6 7
|
||
+-+-+-+-+-+-+-+-+
|
||
|S|E| FuType |
|
||
+---------------+
|
||
|
||
S = variable
|
||
E = variable
|
||
FuType = NAL unit type
|
||
*/
|
||
|
||
buf1[2] = nal_type;
|
||
/* set the S bit: mark as start fragment */
|
||
buf1[2] |= 1 << 7;
|
||
|
||
/* pass the original NAL header */
|
||
buf += 2;
|
||
frame_len -= 2;
|
||
|
||
while (frame_len > rtp_payload_size)
|
||
{
|
||
memcpy(buf1+3, buf, rtp_payload_size);
|
||
gb_rtp_video_build(p_sua, buf1, H265_RTP_MAX_LEN, 0);
|
||
|
||
buf += rtp_payload_size;
|
||
frame_len -= rtp_payload_size;
|
||
|
||
/* reset the S bit */
|
||
buf1[2] &= ~(1 << 7);
|
||
}
|
||
|
||
/* set the E bit: mark as last fragment */
|
||
buf1[2] |= 1 << 6;
|
||
/* complete and send last RTP packet */
|
||
memcpy(buf1+3, buf, frame_len);
|
||
|
||
gb_rtp_video_build(p_sua, buf1, frame_len + 3, 1);
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
int gb_rtp_h265_video_tx(SUA * p_sua, uint8 * p_data, int len, uint32 ts)
|
||
{
|
||
int ret = -1;
|
||
|
||
uint8 *r, *end = p_data + len;
|
||
r = avc_find_startcode(p_data, end);
|
||
|
||
p_sua->v_rtp_info.rtp_ts = ts;
|
||
|
||
while (r < end)
|
||
{
|
||
uint8 *r1;
|
||
|
||
while (!*(r++));
|
||
r1 = avc_find_startcode(r, end);
|
||
|
||
ret = gb_rtp_h265_video_pkt_tx(p_sua, r, r1 - r, ts);
|
||
if (ret < 0)
|
||
{
|
||
break;
|
||
}
|
||
|
||
r = r1;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
int gb_rtp_ps_video_tx(SUA * p_sua, uint8 * p_data, int len, uint32 ts)
|
||
{
|
||
int ps_cnt = 0;
|
||
int i_flag = 0;
|
||
int ps_hdr_len, remain_len = len, tx_remain, offset, tx_len;
|
||
uint8 nalu_t;
|
||
uint8 tmp_buf[512];
|
||
uint32 used_size = 0;
|
||
int vtype = 0x1b;
|
||
int atype = 0x90;
|
||
|
||
if (NULL == p_data || len < 5)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
if (VIDEO_CODEC_H264 == p_sua->media_info.v_info.codec)
|
||
{
|
||
vtype = 0x1b;
|
||
|
||
nalu_t = p_data[4] & 0x1F;
|
||
if (nalu_t == H264_NAL_SPS || nalu_t == H264_NAL_PPS || nalu_t == H264_NAL_IDR || nalu_t == H264_NAL_SEI)
|
||
{
|
||
i_flag = 1;
|
||
}
|
||
}
|
||
else if (VIDEO_CODEC_H265 == p_sua->media_info.v_info.codec)
|
||
{
|
||
vtype = 0x24;
|
||
|
||
nalu_t = (p_data[4] & 0x7E) >> 1;
|
||
if ((nalu_t >= 16 && nalu_t <= 21) || nalu_t == HEVC_NAL_VPS || nalu_t == HEVC_NAL_SPS || nalu_t == HEVC_NAL_PPS)
|
||
{
|
||
i_flag = 1;
|
||
}
|
||
}
|
||
else if (VIDEO_CODEC_MP4 == p_sua->media_info.v_info.codec)
|
||
{
|
||
vtype = 0x10;
|
||
|
||
int pos = 0;
|
||
|
||
while (pos < len - 5)
|
||
{
|
||
if (p_data[pos] == 0 && p_data[pos+1] == 0 && p_data[pos+2] == 1)
|
||
{
|
||
if (p_data[pos+3] == 0xb6)
|
||
{
|
||
if ((p_data[4] & 0xC0) == 0)
|
||
{
|
||
i_flag = 1;
|
||
}
|
||
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
pos += 4;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pos++;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (AUDIO_CODEC_G711A == p_sua->media_info.a_info.codec)
|
||
{
|
||
atype = 0x90;
|
||
}
|
||
else if (AUDIO_CODEC_G711U == p_sua->media_info.a_info.codec)
|
||
{
|
||
atype = 0x91;
|
||
}
|
||
else if (AUDIO_CODEC_G722 == p_sua->media_info.a_info.codec)
|
||
{
|
||
atype = 0x92;
|
||
}
|
||
else if (AUDIO_CODEC_AAC == p_sua->media_info.a_info.codec)
|
||
{
|
||
atype = 0x0f;
|
||
}
|
||
|
||
sys_os_mutex_enter(p_sua->pstxi_mutex);
|
||
|
||
ps_init_info(&p_sua->pstxi, vtype, atype);
|
||
|
||
while (remain_len > 0)
|
||
{
|
||
int pkt_type = (i_flag == 1) ? 3 : 1;
|
||
if (ps_cnt > 0)
|
||
{
|
||
pkt_type = 4;
|
||
}
|
||
|
||
ps_hdr_len = ps_make_header(&p_sua->pstxi, tmp_buf, remain_len, ts, pkt_type, &used_size);
|
||
|
||
tx_remain = used_size + ps_hdr_len; // ±¾´Î×éPS°üµÄ×ܳ¤¶È
|
||
offset = len - remain_len - ps_hdr_len;
|
||
memcpy(p_data + offset, tmp_buf, ps_hdr_len);
|
||
|
||
remain_len -= used_size;
|
||
|
||
while (tx_remain > 0)
|
||
{
|
||
tx_len = (tx_remain > H264_RTP_MAX_LEN) ? H264_RTP_MAX_LEN : tx_remain;
|
||
|
||
p_sua->v_rtp_info.rtp_ts = ts;
|
||
|
||
tx_remain -= tx_len;
|
||
|
||
int mark = (tx_remain > 0 || remain_len > 0) ? 0 : 1;
|
||
|
||
int ret = gb_rtp_video_build(p_sua, p_data + offset, tx_len, mark);
|
||
if (ret < 0)
|
||
{
|
||
sys_os_mutex_leave(p_sua->pstxi_mutex);
|
||
return -1;
|
||
}
|
||
|
||
p_sua->video_rtp_media.last_pkt_time = sys_os_get_uptime();
|
||
|
||
offset += tx_len;
|
||
}
|
||
|
||
ps_cnt++;
|
||
p_sua->video_rtp_media.tx_pkt_cnt++;
|
||
}
|
||
|
||
sys_os_mutex_leave(p_sua->pstxi_mutex);
|
||
|
||
return 0;
|
||
}
|
||
|
||
int gb_rtp_ps_audio_tx(SUA * p_sua, uint8 * p_data, int len, uint32 ts)
|
||
{
|
||
int ps_cnt = 0;
|
||
int ps_hdr_len, remain_len = len, tx_remain, offset, tx_len;
|
||
uint8 tmp_buf[512];
|
||
uint32 used_size = 0;
|
||
int vtype = 0x1b;
|
||
int atype = 0x90;
|
||
|
||
if (VIDEO_CODEC_H264 == p_sua->media_info.v_info.codec)
|
||
{
|
||
vtype = 0x1b;
|
||
}
|
||
else if (VIDEO_CODEC_H265 == p_sua->media_info.v_info.codec)
|
||
{
|
||
vtype = 0x24;
|
||
}
|
||
else if (VIDEO_CODEC_MP4 == p_sua->media_info.v_info.codec)
|
||
{
|
||
vtype = 0x10;
|
||
}
|
||
|
||
if (AUDIO_CODEC_G711A == p_sua->media_info.a_info.codec)
|
||
{
|
||
atype = 0x90;
|
||
}
|
||
else if (AUDIO_CODEC_G711U == p_sua->media_info.a_info.codec)
|
||
{
|
||
atype = 0x91;
|
||
}
|
||
else if (AUDIO_CODEC_G722 == p_sua->media_info.a_info.codec)
|
||
{
|
||
atype = 0x92;
|
||
}
|
||
else if (AUDIO_CODEC_AAC == p_sua->media_info.a_info.codec)
|
||
{
|
||
atype = 0x0f;
|
||
}
|
||
|
||
sys_os_mutex_enter(p_sua->pstxi_mutex);
|
||
|
||
ps_init_info(&p_sua->pstxi, vtype, atype);
|
||
|
||
while (remain_len > 0)
|
||
{
|
||
int pkt_type = 2;
|
||
if (ps_cnt > 0)
|
||
{
|
||
pkt_type = 5;
|
||
}
|
||
|
||
ps_hdr_len = ps_make_header(&p_sua->pstxi, tmp_buf, remain_len, ts, pkt_type, &used_size);
|
||
|
||
tx_remain = used_size + ps_hdr_len; // ±¾´Î×éPS°üµÄ×ܳ¤¶È
|
||
offset = len - remain_len - ps_hdr_len;
|
||
memcpy(p_data + offset, tmp_buf, ps_hdr_len);
|
||
|
||
remain_len -= used_size;
|
||
|
||
while (tx_remain > 0)
|
||
{
|
||
tx_len = (tx_remain > H264_RTP_MAX_LEN) ? H264_RTP_MAX_LEN : tx_remain;
|
||
|
||
p_sua->v_rtp_info.rtp_ts = ts;
|
||
|
||
tx_remain -= tx_len;
|
||
|
||
int mark = (tx_remain > 0 || remain_len > 0) ? 0 : 1;
|
||
|
||
int ret = gb_rtp_video_build(p_sua, p_data + offset, tx_len, mark);
|
||
if (ret < 0)
|
||
{
|
||
sys_os_mutex_leave(p_sua->pstxi_mutex);
|
||
return -1;
|
||
}
|
||
|
||
p_sua->video_rtp_media.last_pkt_time = sys_os_get_uptime();
|
||
|
||
offset += tx_len;
|
||
}
|
||
|
||
ps_cnt++;
|
||
p_sua->video_rtp_media.tx_pkt_cnt++;
|
||
}
|
||
|
||
sys_os_mutex_leave(p_sua->pstxi_mutex);
|
||
|
||
return 0;
|
||
}
|
||
|
||
int gb_rtp_ps_aac_tx(SUA * p_sua, uint8 * p_data, int len, uint32 ts)
|
||
{
|
||
if (p_data[0] != 0xFF || (p_data[1] & 0xF0) != 0xF0)
|
||
{
|
||
// add ADTS header
|
||
|
||
int profile = 2; // AAC LC
|
||
int freqIdx = 4;
|
||
|
||
switch (p_sua->media_info.a_info.samplerate)
|
||
{
|
||
case 96000:
|
||
freqIdx = 0;
|
||
break;
|
||
|
||
case 88200:
|
||
freqIdx = 1;
|
||
break;
|
||
|
||
case 64000:
|
||
freqIdx = 2;
|
||
break;
|
||
|
||
case 48000:
|
||
freqIdx = 3;
|
||
break;
|
||
|
||
case 44100:
|
||
freqIdx = 4;
|
||
break;
|
||
|
||
case 32000:
|
||
freqIdx = 5;
|
||
break;
|
||
|
||
case 24000:
|
||
freqIdx = 6;
|
||
break;
|
||
|
||
case 22050:
|
||
freqIdx = 7;
|
||
break;
|
||
|
||
case 16000:
|
||
freqIdx = 8;
|
||
break;
|
||
|
||
case 12000:
|
||
freqIdx = 9;
|
||
break;
|
||
|
||
case 11025:
|
||
freqIdx = 10;
|
||
break;
|
||
|
||
case 8000:
|
||
freqIdx = 11;
|
||
break;
|
||
|
||
case 7350:
|
||
freqIdx = 12;
|
||
break;
|
||
|
||
default:
|
||
freqIdx = 4;
|
||
break;
|
||
}
|
||
|
||
p_data -= 7;
|
||
len += 7;
|
||
|
||
p_data[0] = 0xFF;
|
||
p_data[1] = 0xF9;
|
||
p_data[2] = ((profile - 1) << 6) + (freqIdx << 2) + (p_sua->media_info.a_info.channels >> 2);
|
||
p_data[3] = ((p_sua->media_info.a_info.channels & 3) << 6) + (len >> 11);
|
||
p_data[4] = (len & 0x7FF) >> 3;
|
||
p_data[5] = ((len & 7) << 5) + 0x1F;
|
||
p_data[6] = 0xFC;
|
||
}
|
||
|
||
return gb_rtp_ps_audio_tx(p_sua, p_data, len, ts);
|
||
}
|
||
|
||
int gb_rtp_audio_build(SUA * p_sua, uint8 * p_data, int len, int mbit)
|
||
{
|
||
int slen = 0;
|
||
int offset = 0;
|
||
uint8 buff[40];
|
||
uint8 * p_hdr_ptr;
|
||
|
||
if (p_sua->uaf_a_tcp_rtp)
|
||
{
|
||
offset += rtp_write_uint16(buff+offset, len+12);
|
||
}
|
||
|
||
if (p_sua->uaf_rtp_mux)
|
||
{
|
||
offset += rtp_write_uint32(buff+offset, p_sua->audio_rtp_media.mux_id);
|
||
}
|
||
|
||
buff[offset] = (RTP_VERSION << 6);
|
||
offset++;
|
||
|
||
buff[offset] = ((p_sua->a_rtp_info.rtp_pt) | ((mbit & 0x01) << 7));
|
||
offset++;
|
||
|
||
offset += rtp_write_uint16(buff+offset, p_sua->a_rtp_info.rtp_cnt);
|
||
|
||
offset += rtp_write_uint32(buff+offset, p_sua->a_rtp_info.rtp_ts);
|
||
|
||
offset += rtp_write_uint32(buff+offset, p_sua->a_rtp_info.rtp_ssrc);
|
||
|
||
p_hdr_ptr = p_data - offset;
|
||
memcpy(p_hdr_ptr, buff, offset);
|
||
|
||
if (p_sua->uaf_a_tcp_rtp)
|
||
{
|
||
slen = gb_rtp_tcp_tx(p_sua, &p_sua->audio_rtp_media, p_hdr_ptr, offset+len);
|
||
}
|
||
else
|
||
{
|
||
slen = gb_rtp_udp_tx(p_sua, &p_sua->audio_rtp_media, p_hdr_ptr, offset+len);
|
||
}
|
||
|
||
p_sua->a_rtp_info.rtp_cnt = (p_sua->a_rtp_info.rtp_cnt + 1) & 0xFFFF;
|
||
|
||
return (slen == offset+len) ? slen : -1;
|
||
}
|
||
|
||
int gb_rtp_audio_tx(SUA * p_sua, uint8 * p_data, int size, uint32 ts)
|
||
{
|
||
int len, max_packet_size;
|
||
uint8 * p = p_data;
|
||
|
||
if (p_sua == NULL)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
p_sua->a_rtp_info.rtp_ts = ts;
|
||
|
||
max_packet_size = RTP_MAX_LEN;
|
||
|
||
while (size > 0)
|
||
{
|
||
len = max_packet_size;
|
||
if (len > size)
|
||
{
|
||
len = size;
|
||
}
|
||
|
||
gb_rtp_audio_build(p_sua, p, len, (len == size));
|
||
|
||
p += len;
|
||
size -= len;
|
||
}
|
||
|
||
p_sua->audio_rtp_media.last_pkt_time = sys_os_get_uptime();
|
||
p_sua->audio_rtp_media.tx_pkt_cnt++;
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
|