/*************************************************************************************** * * 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; }