Files

981 lines
40 KiB
C
Executable File

/*
* Copyright (c) XCAM. All rights reserved.
*/
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include "livestream_comm.h"
#include "xcam_livestream_rtsp_server.h"
#include "livestream_mbuffer.h"
#include "livestream_rtp_session.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
/* audio specific header len is 4, see rfc2550*/
static const xcam_u32 g_audio_specific_header_len = 4;
/* increase 128 bytes when current rtp packet buf is over full */
static const xcam_u32 g_rtp_packet_buf_step_len = 128;
#define RTP_VERSION 2
#define RTP_DEFAULT_SSRC 41030
#define RTP_TRANS_TIMEVAL_SEC (5)
#define RTP_TRANS_TIMEVAL_USEC (0)
#define RTP_TRANS_STREAM_VIDEO (0)
#define RTP_TRANS_STREAM_AUDIO (1)
#define RTP_TRANS_STREAM_DATA (2)
#define RTP_TRANS_STREAM_MAX (3)
static xcam_void rtp_packet_hdr(xcam_char* pack_addr, xcam_u32 timestamp, xcam_u32 marker,
rtp_payload_type payload_type, xcam_u32 ssrc, xcam_u16 last_sn)
{
rtp_pack_hdr* rtp_hdr = NULL;
rtp_hdr = (rtp_pack_hdr*)pack_addr;
RTP_HDR_SET_VERSION(rtp_hdr, RTP_VERSION);
RTP_HDR_SET_P(rtp_hdr, 0); /*no padding*/
RTP_HDR_SET_X(rtp_hdr, 0); /*no extension*/
RTP_HDR_SET_CC(rtp_hdr, 0); /*0 CSRC*/
RTP_HDR_SET_M(rtp_hdr, marker);
RTP_HDR_SET_PT(rtp_hdr, payload_type);
RTP_HDR_SET_SEQNO(rtp_hdr, htons(last_sn));
RTP_HDR_SET_TS(rtp_hdr, htonl(timestamp));
RTP_HDR_SET_SSRC(rtp_hdr, htonl(ssrc));
return;
}
static xcam_s32 rtp_send_to_sockfd(xcam_s32 write_sock, const xcam_char* buffer,
xcam_u32 data_len, const struct sockaddr_in* peer_sock_addr)
{
const xcam_char* buffer_pos = NULL;
struct timeval timeout_val;
xcam_u32 rem_size = 0;
xcam_s32 err_num = 0;
xcam_s32 size = 0;
xcam_s32 ret = 0;
fd_set write_fds;
memset(&timeout_val, 0, sizeof(struct timeval));
rem_size = data_len;
buffer_pos = buffer;
while (rem_size > 0) {
FD_ZERO(&write_fds);
FD_SET(write_sock, &write_fds);
timeout_val.tv_sec = RTP_TRANS_TIMEVAL_SEC;
timeout_val.tv_usec = RTP_TRANS_TIMEVAL_USEC;
/*judge if it can send */
ret = select(write_sock + 1, NULL, &write_fds, NULL, &timeout_val);
/*select found over time or error happend*/
if (0 == ret) {
err_num = errno;
LOG_LIVESTREAM_ERROR("send media rtp data timeout,errno=%d,%s\n",
errno, strerror(err_num));
return XCAM_FAILURE;
} else if (0 > ret) {
if (EINTR == errno || EAGAIN == errno) {
LOG_LIVESTREAM_ERROR("select error: %s\n", strerror(errno));
continue;
}
err_num = errno;
LOG_LIVESTREAM_ERROR("send media rtp data, select error: %s", strerror(err_num));
return XCAM_FAILURE;
}
if (!FD_ISSET(write_sock, &write_fds)) {
err_num = errno;
LOG_LIVESTREAM_ERROR("send media rtp data error: write fd not in fdset! error:%s\n",
strerror(err_num));
return XCAM_FAILURE;
}
/*select ok and fd isset ok*/
if (peer_sock_addr == NULL) {
size = send(write_sock, buffer_pos, rem_size, MSG_DONTWAIT);
} else {
size = sendto(write_sock, buffer_pos, rem_size, 0,
(struct sockaddr*)peer_sock_addr, sizeof(struct sockaddr));
}
if (size < 0) {
/*if it is not eagain error, means can not send*/
if (errno != EINTR && errno != EAGAIN) {
err_num = errno;
LOG_LIVESTREAM_ERROR("send media data(%u Byte) error: %s\n", data_len, strerror(err_num));
return XCAM_FAILURE;
}
/*it is eagain error, means can try again*/
continue;
}
rem_size -= size;
buffer_pos += size;
}
return XCAM_SUCCESS;
}
static xcam_void rtp_rtsp_itlv_packet(xcam_char* ptr_pack_addr, xcam_s32 channel,
xcam_u32 pack_len, xcam_u32 timestamp, xcam_u32 marker,
rtp_payload_type payload_type, xcam_u32 ssrc, xcam_u16 last_sn)
{
rtsp_itleaved_hdr* ptr_rtsp_itlv_hdr = XCAM_NULL;
ptr_rtsp_itlv_hdr = (rtsp_itleaved_hdr*)ptr_pack_addr;
ptr_rtsp_itlv_hdr->daollar = '$';
ptr_rtsp_itlv_hdr->chn_id = channel;
/* rtsp payload len represent the later packet lengthpacket len = rtp head + data len */
ptr_rtsp_itlv_hdr->payload_len = htons((xcam_u16)(pack_len - sizeof(rtsp_itleaved_hdr) + sizeof(rtp_pack_hdr)));
/* packet rtp packet */
rtp_packet_hdr((xcam_char*)(&(ptr_rtsp_itlv_hdr->rtp_head)), timestamp, marker, payload_type, ssrc, last_sn);
return;
}
/*
FU-A
FU indicator
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
FU header
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R| Type |
+---------------+
Type Packet Type name
---------------------------------------------------------
0 undefined -
1-23 NAL unit Single NAL unit packet per H.264
24 STAP-A Single-time aggregation packet
25 STAP-B Single-time aggregation packet
26 MTAP16 Multi-time aggregation packet
27 MTAP24 Multi-time aggregation packet
28 FU-A Fragmentation unit
29 FU-B Fragmentation unit
30-31 undefined -
*/
static xcam_s32 rtp_fu_package_header(xcam_char* ptr_header, xcam_u8* ptr_message,
xcam_u8 start, xcam_u8 end)
{
xcam_s32 head_len = 0;
xcam_u8 nal_type;
xcam_u8 nri;
if (XCAM_NULL == ptr_header || XCAM_NULL == ptr_message) {
LOG_LIVESTREAM_ERROR("ptr_header=%p ptr_message=%p\n", ptr_header, ptr_message);
fflush(stdout);
return XCAM_FAILURE;
}
if ((1 == start && 1 == end) || start > 1 || end > 1) {
LOG_LIVESTREAM_ERROR("start=%d, end=%d\n", start, end);
fflush(stdout);
return XCAM_FAILURE;
}
if ((*ptr_message != 0 || *(ptr_message + 1) != 0 || *(ptr_message + 2) != 0 || *(ptr_message + 3) != 1)
&& (*ptr_message != 0 || *(ptr_message + 1) != 0 || *(ptr_message + 2) != 1)) {
LOG_LIVESTREAM_ERROR("this package is not have NALU!\n");
fflush(stdout);
return XCAM_FAILURE;
}
if (*ptr_message == 0 && *(ptr_message + 1) == 0 && *(ptr_message + 2) == 0 && *(ptr_message + 3) == 1) {
head_len = 4;
} else if (*ptr_message == 0 && *(ptr_message + 1) == 0 && *(ptr_message + 2) == 1) {
head_len = 3;
} else {
fflush(stdout);
return XCAM_FAILURE;
}
nri = (ptr_message[head_len] & 0x60) >> 5;
nal_type = ptr_message[head_len] & 0x1F;
*ptr_header = 0;
*ptr_header = nri << 5 | 0x1c;/*NAL is 0x1c=28means FUA*/
*(ptr_header + 1) = 0;
*(ptr_header + 1) = start << 7 | end << 6 | nal_type;
return XCAM_SUCCESS;
}
static xcam_s32 rtp_session_start_tcp_itlv(livestream_rtp_session* rtp_session)
{
if ( RTP_SESSION_STATE_READY == rtp_session->session_state ) {
rtp_session->session_state = RTP_SESSION_STATE_PLAY;
} else if ( RTP_SESSION_STATE_PLAY == rtp_session->session_state) {
/*do nothing*/
} else {
LOG_LIVESTREAM_ERROR("start video error: video is in not ready state.\n");
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
static xcam_s32 rtp_session_start_udp(livestream_rtp_session* rtp_session)
{
xcam_s32 temp_sock = 0;
if (RTP_SESSION_STATE_READY == rtp_session->session_state) {
/*send rtp socket*/
temp_sock = livestream_comm_open_udp_socket(rtp_session->server_rtp_port);
if (-1 == temp_sock) {
LOG_LIVESTREAM_ERROR("error:get socket from port%d.\n", rtp_session->server_rtp_port);
return XCAM_FAILURE;
}
rtp_session->rtp_send_sock = temp_sock;
livestream_comm_get_peer_sockaddr(rtp_session->client_ip, rtp_session->client_rtp_port, &(rtp_session->client_sockaddr));
rtp_session->session_state = RTP_SESSION_STATE_PLAY;
} else if ( RTP_SESSION_STATE_PLAY == rtp_session->session_state) {
/*do nothing*/
} else {
LOG_LIVESTREAM_ERROR("start video error: video is in not ready state.\n");
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_update_seq_num(livestream_rtp_session* rtp_session, xcam_u32 seq_num)
{
/*check the appointed task exit or not*/
if (XCAM_NULL == rtp_session) {
LOG_LIVESTREAM_ERROR("get RTP rtp_session NULL.\n");
return XCAM_FAILURE;
}
rtp_session->seq_num = seq_num;
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_get_packet_and_send_param(livestream_rtp_session* rtp_session, xcam_s32* ptr_write_sock,
struct sockaddr_in* ptr_peer_sockaddr, xcam_u32* ptr_last_sn,
rtp_pack_type* ptr_pack_type, xcam_u32* ptr_ssrc)
{
xcam_s32 ret = 0;
rtp_trans_mode trans_mode = RTP_TRANS_BUTT;
trans_mode = rtp_session->media_trans_mode;
/*1 get packet type*/
/*if stream waiting packet is video and vidieo is in playing state,
stream can be packeted*/
/*packet the stream according to different packet type */
*ptr_pack_type = rtp_session->pack_type;
*ptr_ssrc = rtp_session->ssrc;
if (RTP_TRANS_TCP_ITLV == trans_mode) {
*ptr_write_sock = rtp_session->rtp_send_sock;
*ptr_last_sn = rtp_session->seq_num;
} else if (RTP_TRANS_UDP == trans_mode) { /*the branch must be udp transport*/
*ptr_write_sock = rtp_session->rtp_send_sock;
memcpy(ptr_peer_sockaddr, &(rtp_session->client_sockaddr), sizeof(struct sockaddr_in));
*ptr_last_sn = rtp_session->seq_num;
} else if (RTP_TRANS_BROADCAST == trans_mode) {
*ptr_write_sock = rtp_session->rtp_send_sock;
memcpy(ptr_peer_sockaddr, &(rtp_session->client_sockaddr), sizeof(struct sockaddr_in));
*ptr_last_sn = rtp_session->seq_num;
} else {
LOG_LIVESTREAM_ERROR("unsupport trans type in send trans_mode:%d.\n", trans_mode);
return ret;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_send_data_in_rtsp_itlv(livestream_rtp_session* rtp_session, const xcam_u8* data_addr,
xcam_u32 data_len, xcam_u32 ts, rtp_payload_type rtp_type, xcam_u32* seq_num, xcam_u32 ssrc,
xcam_s32 write_sock, struct sockaddr_in* peer_sockaddr, xcam_s32 packet_len)
{
xcam_char* tmp_pack_buf = rtp_session->pack_buffer;
const xcam_u8* pack_data_addr = data_addr;
xcam_u32 pack_payload_len = packet_len;
xcam_u32 current_seq_num = *seq_num;
xcam_u32 rtp_send_len = 0;
xcam_u32 package_len = 0;
xcam_u32 send_len = 0;
xcam_s32 channel = 0;
xcam_u8 marker = 0;
xcam_s32 ret = 0;
if (pack_data_addr == XCAM_NULL) {
LOG_LIVESTREAM_ERROR("param pack_data_addr is null\n");
return XCAM_FAILURE;
}
if (rtp_type == RTP_PT_H264) {
/*juege the slice data head length*/
xcam_u32 slice_head_len = 0;
/*H264 slice data header length*/
if ((0x00 == (xcam_u8)data_addr[0]) && (0x00 == (xcam_u8)data_addr[1])) {
if ((0x00 == (xcam_u8)data_addr[2]) && (0x01 == (xcam_u8)data_addr[3])) {
slice_head_len = 5;
}
if (0x01 == (xcam_u8)data_addr[2]) {
slice_head_len = 4;
}
} else {
LOG_LIVESTREAM_INFO("Unknow H264 Nalu Head:%x %x %x %x %x \n",
data_addr[0], data_addr[1], data_addr[2], data_addr[3], data_addr[4]);
slice_head_len = 5;
}
channel = rtp_session->itlv_client_media_chnid;
/*when the frame data length is less than the packetsize 1500*/
if (data_len - (slice_head_len - 1) + sizeof(rtsp_itleaved_hdr) <= pack_payload_len) {
send_len = data_len - (slice_head_len - 1);
rtp_send_len = send_len + sizeof( rtsp_itleaved_hdr );
/*payload data should cut the 4 bytes head :00 00 00 01*/
memcpy(tmp_pack_buf + sizeof(rtsp_itleaved_hdr),
pack_data_addr + slice_head_len - 1, send_len);
/*form the rtp itlv head */
if (0x65 == (xcam_u8)data_addr[slice_head_len - 1] || 0x61 == (xcam_u8)data_addr[slice_head_len - 1]) {
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, 1, rtp_type, ssrc, current_seq_num++);
} else {
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, 0, rtp_type, ssrc, current_seq_num++);
}
/*send the rtp packet */
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else { /*when the frame data length is larger than the packetsize 1500 */
/*need to cut the frame into several rtp packets*/
while (package_len < data_len) {
if (pack_payload_len >= sizeof(rtsp_itleaved_hdr) + 2 + data_len - package_len) {
send_len = data_len - package_len;
marker = 1;
} else {
send_len = pack_payload_len - sizeof(rtsp_itleaved_hdr) - 2;
marker = 0;
}
rtp_send_len = send_len + sizeof( rtsp_itleaved_hdr ) + 2;
if (package_len == 0) { /*the first package*/
package_len += slice_head_len;
pack_data_addr += slice_head_len;
ret = rtp_fu_package_header(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) , (xcam_u8*)data_addr, 1, 0);
} else if ((package_len + send_len) < data_len) { /*in the middle packages*/
ret = rtp_fu_package_header(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ), (xcam_u8*)data_addr, 0, 0);
marker = 0;
} else { /*the last package*/
ret = rtp_fu_package_header(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ), (xcam_u8*)data_addr, 0, 1);
marker = 1;
}
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP FU Head pack error %d\n", ret);
return XCAM_FAILURE;
}
/*copy the data */
memcpy(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) + 2,
pack_data_addr, send_len);
/*form rtp itlv head*/
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, marker, rtp_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
pack_data_addr += send_len; /*update the ptr to the frame data*/
package_len += send_len; /*update the send data length*/
}
}
} else if (RTP_PT_H265 == rtp_type) {
/*juege the slice data head length*/
xcam_u32 slice_head_len = 0;
/*H265 slice data header length*/
if ((0x00 == (xcam_u8)data_addr[0]) && (0x00 == (xcam_u8)data_addr[1])) {
if ((0x00 == (xcam_u8)data_addr[2]) && (0x01 == (xcam_u8)data_addr[3])) {
slice_head_len = 5;
}
if (0x01 == (xcam_u8)data_addr[2]) {
slice_head_len = 4;
}
} else {
LOG_LIVESTREAM_INFO("Unknow H264 Nalu Head:%x %x %x %x %x \n",
data_addr[0], data_addr[1], data_addr[2], data_addr[3], data_addr[4]);
slice_head_len = 5;
}
int nal_type = (data_addr[slice_head_len - 1] >> 1) & 0x3F;
channel = rtp_session->itlv_client_media_chnid;
/*when the frame data length is less than the packetsize 1500 */
if (data_len - (slice_head_len - 1) + sizeof(rtsp_itleaved_hdr) <= pack_payload_len) {
send_len = data_len - (slice_head_len - 1);
rtp_send_len = send_len + sizeof( rtsp_itleaved_hdr );
/*payload data should cut the 4 bytes head :00 00 00 01*/
memcpy(tmp_pack_buf + sizeof(rtsp_itleaved_hdr),
pack_data_addr + slice_head_len - 1, send_len);
if (0x26 == (xcam_u8)data_addr[slice_head_len - 1] || 0x02 == (xcam_u8)data_addr[slice_head_len - 1]) {
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, 1, rtp_type, ssrc, current_seq_num++);
} else {
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, 0, rtp_type, ssrc, current_seq_num++);
}
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else { /*when the frame data length is larger than the packetsize 1500 */
tmp_pack_buf[sizeof(rtsp_itleaved_hdr)] = 49 << 1;
tmp_pack_buf[sizeof(rtsp_itleaved_hdr) + 1] = 1;
tmp_pack_buf[sizeof(rtsp_itleaved_hdr) + 2] = nal_type;
/*need to cut the frame into several rtp packets*/
while (package_len < data_len) {
if (pack_payload_len >= sizeof(rtsp_itleaved_hdr) + 3 + data_len - package_len) {
send_len = data_len - package_len;
marker = 1;
} else {
send_len = pack_payload_len - sizeof(rtsp_itleaved_hdr) - 3;
marker = 0;
}
rtp_send_len = send_len + sizeof( rtsp_itleaved_hdr ) + 3;
if (package_len == 0) { /*the first package*/
package_len += slice_head_len + 1;
pack_data_addr += slice_head_len + 1;
tmp_pack_buf[sizeof(rtsp_itleaved_hdr) + 2] |= 1 << 7;
} else if ((package_len + send_len) < data_len) { /* in the middle packages*/
marker = 0;
tmp_pack_buf[sizeof(rtsp_itleaved_hdr) + 2] &= ~(1 << 7);
} else { /*the last package*/
marker = 1;
tmp_pack_buf[sizeof(rtsp_itleaved_hdr) + 2] &= ~(1 << 7);
tmp_pack_buf[sizeof(rtsp_itleaved_hdr) + 2] |= 1 << 6;
}
memcpy(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) + 3, pack_data_addr, send_len);
/*form rtp itlv head*/
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, marker, rtp_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
pack_data_addr += send_len; /*update the ptr to the frame data*/
package_len += send_len; /*update the send data length*/
}
}
} else if (RTP_PT_PCMA == rtp_type || RTP_PT_PCMU == rtp_type || RTP_PT_G726 == rtp_type) {
/*audio do not cut into packets*/
if (data_len >= (pack_payload_len - sizeof( rtsp_itleaved_hdr ))) {
if (rtp_session->pack_buffer) {
free(rtp_session->pack_buffer);
rtp_session->pack_buffer = XCAM_NULL;
}
rtp_session->pack_buffer = (xcam_char*)malloc((data_len + 128));
if (XCAM_NULL == rtp_session->pack_buffer) {
LOG_LIVESTREAM_ERROR("dynamic alloc fail!\n");
return XCAM_FAILURE;
}
tmp_pack_buf = rtp_session->pack_buffer;
}
channel = rtp_session->itlv_client_media_chnid;
send_len = data_len;
rtp_send_len = send_len + sizeof(rtsp_itleaved_hdr);
memcpy(tmp_pack_buf + sizeof(rtsp_itleaved_hdr), pack_data_addr, send_len);
/*form the rtp head*/
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, 0, rtp_type, ssrc, current_seq_num++);
/*send the audio data*/
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP audio send error\n");
return ret;
}
} else if (RTP_PT_AAC == rtp_type) {
if ((data_len - 7) >= (pack_payload_len - sizeof( rtsp_itleaved_hdr ) - 4)) {
if (rtp_session->pack_buffer) {
free(rtp_session->pack_buffer);
rtp_session->pack_buffer = XCAM_NULL;
}
rtp_session->pack_buffer = (xcam_char*)malloc((data_len + 128));
if (XCAM_NULL == rtp_session->pack_buffer) {
LOG_LIVESTREAM_ERROR("dynamic alloc fail!\n");
return XCAM_FAILURE;
}
tmp_pack_buf = rtp_session->pack_buffer;
}
channel = rtp_session->itlv_client_media_chnid;
/*payload data should cut the first 7 bytes ADTS header */
send_len = data_len - 7 + 4;
rtp_send_len = send_len + sizeof( rtsp_itleaved_hdr );
/*add 4 bytes au header*/
*(tmp_pack_buf + sizeof( rtsp_itleaved_hdr )) = 0x00;
*(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) + 1) = 0x10;
*(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) + 2) = ((data_len - 7) & 0x1fe0) >> 5;
*(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) + 3) = ((data_len - 7) & 0x1f) << 3;
memcpy(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) + 4,
pack_data_addr + 7, data_len - 7);
/*add rtp head */
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, 1, rtp_type, ssrc, current_seq_num++);
/*send the data */
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else if (rtp_type == RTP_PT_MPA) {
if (data_len >= (pack_payload_len - sizeof(rtsp_itleaved_hdr) - g_audio_specific_header_len)) {
if (rtp_session->pack_buffer) {
free(rtp_session->pack_buffer);
rtp_session->pack_buffer = XCAM_NULL;
}
rtp_session->pack_buffer = (xcam_char*)malloc((data_len + g_rtp_packet_buf_step_len));
if (rtp_session->pack_buffer == XCAM_NULL) {
LOG_LIVESTREAM_ERROR("dynamic alloc fail!\n");
return XCAM_FAILURE;
}
tmp_pack_buf = rtp_session->pack_buffer;
}
send_len = data_len + g_audio_specific_header_len;
rtp_send_len = send_len + sizeof( rtsp_itleaved_hdr );
xcam_u32 *audioSpecHeader = (xcam_u32 *)(tmp_pack_buf + sizeof(rtsp_itleaved_hdr));
*audioSpecHeader = 0;/* MBZ is reserved, and frag offset is 0, so audio specific header is 0 */
memcpy(tmp_pack_buf + sizeof(rtsp_itleaved_hdr) + g_audio_specific_header_len,
pack_data_addr, data_len);
marker = 1; /* mpa maker should be 1, see rfc2550 */
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, marker, rtp_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else {
/*media type do not support*/
LOG_LIVESTREAM_ERROR("unsupport stream type:%d\n", rtp_type);
return XCAM_FAILURE;
}
*seq_num = current_seq_num; /*update the seq when send several packet inside*/
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_send_data_in_rtp(livestream_rtp_session* session, const xcam_u8* data_addr,
xcam_u32 data_len, xcam_u32 ts, rtp_payload_type package_type, xcam_u32* seq_num,
xcam_u32 ssrc, xcam_s32 write_sock, const struct sockaddr_in* peer_sockaddr, xcam_s32 packet_len)
{
xcam_char* tmp_pack_buf = session->pack_buffer;
const xcam_u8* pack_data_addr = data_addr;
xcam_u32 pack_payload_len = packet_len;
xcam_u32 current_seq_num = *seq_num;
xcam_u32 package_len = 0;
xcam_u32 rtp_send_len = 0;
xcam_u32 send_len = 0;
xcam_u8 marker = 0;
xcam_s32 ret = 0;
if (RTP_PT_H264 == package_type) {
xcam_u32 slice_head_len = 0;
/*H264 head length */
if ((0x00 == (xcam_u8)data_addr[0]) && (0x00 == (xcam_u8)data_addr[1])) {
if ((0x00 == (xcam_u8)data_addr[2]) && (0x01 == (xcam_u8)data_addr[3])) {
slice_head_len = 5;
}
if (0x01 == (xcam_u8)data_addr[2]) {
slice_head_len = 4;
}
} else {
LOG_LIVESTREAM_INFO("Unknow H264 Nalu Head:%x %x %x %x %x \n",
data_addr[0], data_addr[1], data_addr[2], data_addr[3], data_addr[4]);
slice_head_len = 5;
}
/*datalen less than packet length*/
if (data_len - (slice_head_len - 1) + sizeof(rtp_pack_hdr) <= pack_payload_len) {
send_len = data_len - (slice_head_len - 1);
rtp_send_len = send_len + sizeof( rtp_pack_hdr );
/*payload data cut the first 4 bytres head ::00 00 00 01*/
memcpy(tmp_pack_buf + sizeof( rtp_pack_hdr ),
pack_data_addr + slice_head_len - 1, send_len);
/*add rtp head*/
if (0x65 == (xcam_u8)data_addr[slice_head_len - 1] || 0x61 == (xcam_u8)data_addr[slice_head_len - 1]) {
rtp_packet_hdr(tmp_pack_buf, ts, 1, package_type, ssrc, current_seq_num++);
} else {
rtp_packet_hdr(tmp_pack_buf, ts, 0, package_type, ssrc, current_seq_num++);
}
/*send the data */
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else { /*when the frame data is larger than packet length*/
while (package_len < data_len) {
if (pack_payload_len >= sizeof(rtp_pack_hdr) + 2 + data_len - package_len) {
send_len = data_len - package_len;
marker = 1;
} else {
send_len = pack_payload_len - sizeof(rtp_pack_hdr) - 2;
marker = 0;
}
rtp_send_len = send_len + sizeof( rtp_pack_hdr ) + 2;
if (package_len == 0) { /*the first package*/
package_len += slice_head_len;
pack_data_addr += slice_head_len;
ret = rtp_fu_package_header(tmp_pack_buf + sizeof( rtp_pack_hdr ) , (xcam_u8*)data_addr, 1, 0);
} else if ((pack_payload_len == rtp_send_len) && ((package_len + send_len) < data_len)) { // in the middle packages
ret = rtp_fu_package_header(tmp_pack_buf + sizeof( rtp_pack_hdr ), (xcam_u8*)data_addr, 0, 0);
marker = 0;
} else { /*the last package*/
ret = rtp_fu_package_header(tmp_pack_buf + sizeof( rtp_pack_hdr ), (xcam_u8*)data_addr, 0, 1);
marker = 1;
}
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP FU Head pack error %d\n", ret);
return XCAM_FAILURE;
}
/*cp the data*/
memcpy(tmp_pack_buf + sizeof( rtp_pack_hdr ) + 2, pack_data_addr, send_len);
/*add the rtp head*/
rtp_packet_hdr(tmp_pack_buf, ts, marker, package_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
pack_data_addr += send_len;
package_len += send_len;
}
}
} else if (RTP_PT_H265 == package_type) {
xcam_u32 slice_head_len = 0;
/*H265 slice head length*/
if ((0x00 == (xcam_u8)data_addr[0]) && (0x00 == (xcam_u8)data_addr[1])) {
if ((0x00 == (xcam_u8)data_addr[2]) && (0x01 == (xcam_u8)data_addr[3])) {
slice_head_len = 5;
}
if (0x01 == (xcam_u8)data_addr[2]) {
slice_head_len = 4;
}
} else {
LOG_LIVESTREAM_INFO("Unknow H265 Nalu Head:%x %x %x %x %x \n",
data_addr[0], data_addr[1], data_addr[2], data_addr[3], data_addr[4]);
slice_head_len = 5;
}
xcam_s32 nal_type = (data_addr[slice_head_len - 1] >> 1) & 0x3F;
/*frame date less than the packet length*/
if (data_len - (slice_head_len - 1) + sizeof(rtp_pack_hdr) <= pack_payload_len) {
send_len = data_len - (slice_head_len - 1);
rtp_send_len = send_len + sizeof( rtp_pack_hdr );
/*payload should cut the first 4 bytes head :00 00 00 01*/
memcpy(tmp_pack_buf + sizeof( rtp_pack_hdr ),
pack_data_addr + slice_head_len - 1, send_len);
/*rtpͷ*/
if (0x26 == (xcam_u8)data_addr[slice_head_len - 1] || 0x02 == (xcam_u8)data_addr[slice_head_len - 1]) {
rtp_packet_hdr(tmp_pack_buf, ts, 1, package_type, ssrc, current_seq_num++);
} else {
rtp_packet_hdr(tmp_pack_buf, ts, 0, package_type, ssrc, current_seq_num++);
}
/*send the data */
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else { /*when the frame date is larger than packet length*/
tmp_pack_buf[sizeof(rtp_pack_hdr)] = 49 << 1;
tmp_pack_buf[sizeof(rtp_pack_hdr) + 1] = 1;
tmp_pack_buf[sizeof(rtp_pack_hdr) + 2] = nal_type;
while (package_len < data_len) {
if (pack_payload_len >= sizeof(rtp_pack_hdr) + 3 + data_len - package_len) {
send_len = data_len - package_len;
marker = 1;
} else {
send_len = pack_payload_len - sizeof(rtp_pack_hdr) - 3;
marker = 0;
}
rtp_send_len = send_len + sizeof( rtp_pack_hdr ) + 3;
if (package_len == 0) { /*the first package*/
package_len += slice_head_len + 1;
pack_data_addr += slice_head_len + 1;
tmp_pack_buf[sizeof(rtp_pack_hdr) + 2] |= 1 << 7;
} else if ((pack_payload_len == rtp_send_len) && ((package_len + send_len) < data_len)) { // in the middle packages
marker = 0;
tmp_pack_buf[sizeof(rtp_pack_hdr) + 2] &= ~(1 << 7);
} else { /*the last package*/
marker = 1;
tmp_pack_buf[sizeof(rtp_pack_hdr) + 2] &= ~(1 << 7);
tmp_pack_buf[sizeof(rtp_pack_hdr) + 2] |= 1 << 6;
}
/*copy the data */
memcpy(tmp_pack_buf + sizeof( rtp_pack_hdr ) + 3,
pack_data_addr, send_len);
/*add the rtp head */
rtp_packet_hdr(tmp_pack_buf, ts, marker, package_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
pack_data_addr += send_len;
package_len += send_len;
}
}
} else if (RTP_PT_PCMA == package_type || RTP_PT_PCMU == package_type || RTP_PT_G726 == package_type) {
/*audio not cut */
if (data_len >= (pack_payload_len - sizeof( rtp_pack_hdr ))) {
if (session->pack_buffer) {
free(session->pack_buffer );
session->pack_buffer = XCAM_NULL;
}
session->pack_buffer = (xcam_char*)malloc((data_len + 128));
if (XCAM_NULL == session->pack_buffer) {
LOG_LIVESTREAM_ERROR("dynamic alloc fail!\n");
return XCAM_FAILURE;
}
tmp_pack_buf = session->pack_buffer;
}
send_len = data_len;
rtp_send_len = send_len + sizeof(rtp_pack_hdr);
memcpy(tmp_pack_buf + sizeof( rtp_pack_hdr ), pack_data_addr, send_len);
rtp_packet_hdr(tmp_pack_buf, ts, 0, package_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else if (RTP_PT_AAC == package_type) {
if ((data_len - 7) >= (pack_payload_len - sizeof(rtp_pack_hdr) - 4)) {
if (session->pack_buffer) {
free(session->pack_buffer);
session->pack_buffer = XCAM_NULL;
}
session->pack_buffer = (xcam_char*)malloc( (data_len + 128));
if (XCAM_NULL == session->pack_buffer) {
LOG_LIVESTREAM_ERROR("dynamic alloc fail!\n");
return XCAM_FAILURE;
}
tmp_pack_buf = session->pack_buffer;
}
/*payload cut the first 7 BYTES ADTS head*/
send_len = data_len - 7 + 4;
rtp_send_len = send_len + sizeof( rtp_pack_hdr );
if (tmp_pack_buf == XCAM_NULL) {
return XCAM_FAILURE;
}
/*add 4 bytes au header*/
*(tmp_pack_buf + sizeof( rtp_pack_hdr )) = 0x00;
*(tmp_pack_buf + sizeof( rtp_pack_hdr ) + 1) = 0x10;
*(tmp_pack_buf + sizeof( rtp_pack_hdr ) + 2) = ((data_len - 7) & 0x1fe0) >> 5;
*(tmp_pack_buf + sizeof( rtp_pack_hdr ) + 3) = ((data_len - 7) & 0x1f) << 3;
memcpy(tmp_pack_buf + sizeof( rtp_pack_hdr ) + 4, pack_data_addr + 7, data_len - 7);
/*add rtp head */
rtp_packet_hdr(tmp_pack_buf, ts, 1, package_type, ssrc, current_seq_num++);
/*send the data */
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else if (package_type == RTP_PT_MPA) {
if (data_len >= (pack_payload_len - sizeof(rtp_pack_hdr) - g_audio_specific_header_len)) {
if (session->pack_buffer) {
free(session->pack_buffer);
session->pack_buffer = XCAM_NULL;
}
session->pack_buffer = (xcam_char*)malloc((data_len + g_rtp_packet_buf_step_len));
if (session->pack_buffer == XCAM_NULL) {
LOG_LIVESTREAM_ERROR("dynamic alloc fail!\n");
return XCAM_FAILURE;
}
tmp_pack_buf = session->pack_buffer;
}
send_len = data_len + g_audio_specific_header_len;
rtp_send_len = send_len + sizeof( rtp_pack_hdr );
xcam_u32 *audioSpecHeader = (xcam_u32 *)(tmp_pack_buf + sizeof(rtp_pack_hdr));
*audioSpecHeader = 0;/* MBZ is reserved, and frag offset is 0, so audio specific header is 0 */
memcpy(tmp_pack_buf + sizeof(rtp_pack_hdr) + g_audio_specific_header_len,
pack_data_addr, data_len);
marker = 1; /* mpa maker should be 1, see rfc2550 */
rtp_packet_hdr(tmp_pack_buf, ts, marker, package_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else {
/*not support type */
LOG_LIVESTREAM_ERROR("unsupport stream type:%d\n", package_type);
return XCAM_FAILURE;
}
*seq_num = current_seq_num; /*update the seq num */
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_start(livestream_rtp_session* rtp_session)
{
xcam_s32 s32Ret = XCAM_SUCCESS;
if (XCAM_NULL == rtp_session) {
return XCAM_FAILURE;
}
/*if it is tcp trans type */
if (RTP_TRANS_TCP_ITLV == rtp_session->media_trans_mode) {
/*do not need create the socke while tcp_itlv cause the data trans sock is the same with session sock*/
s32Ret = rtp_session_start_tcp_itlv(rtp_session);
if (XCAM_SUCCESS != s32Ret) {
LOG_LIVESTREAM_ERROR("start task rtp_session_start_tcp_itlv fail %d.\n", s32Ret);
return s32Ret;
}
} else if (RTP_TRANS_UDP == rtp_session->media_trans_mode) {
/*if it is udp trans type, record corresponding info*/
s32Ret = rtp_session_start_udp(rtp_session);
if (XCAM_SUCCESS != s32Ret) {
LOG_LIVESTREAM_ERROR("start task rtp_session_start_udp fail %d.\n", s32Ret);
return s32Ret;
}
} else if (RTP_TRANS_TCP == rtp_session->media_trans_mode) {
/*if it is tcp trans type, record corresponding info*/
/*to do :add the part for tcp trans*/
LOG_LIVESTREAM_ERROR("start rtpSession error: not support tcp trans now.\n");
return XCAM_FAILURE;
} else {
LOG_LIVESTREAM_ERROR("start rtpSession error: unrecognized trans now.\n");
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_stop(livestream_rtp_session* rtp_session)
{
if (XCAM_NULL == rtp_session) {
LOG_LIVESTREAM_ERROR("Stop rtpSession error.\n");
return XCAM_FAILURE;
}
/*set all meida state as init*/
rtp_session->session_state = RTP_SESSION_STATE_STOP;
/*if it is tcp trans type*/
if (RTP_TRANS_TCP_ITLV == rtp_session->media_trans_mode) {
/*do nothing*/
} else if (RTP_TRANS_UDP == rtp_session->media_trans_mode) {
/*if it is udp trans type, record corresponding info*/
livestream_comm_close_socket(&rtp_session->rtp_send_sock);
} else if (RTP_TRANS_BROADCAST == rtp_session->media_trans_mode) {
/*if it is broadcast trans type, record corresponding info*/
livestream_comm_close_socket(&rtp_session->rtp_send_sock);
} else {
LOG_LIVESTREAM_ERROR(
"top trans task error: not unrecognized trans type %d.\n", rtp_session->media_trans_mode);
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_create(livestream_rtp_session** pptr_session, xcam_s32 packet_len)
{
livestream_rtp_session* ptr_rtp_session = XCAM_NULL;
if (packet_len <= 0) {
LOG_LIVESTREAM_ERROR("ptr_rtp_session packlen less than 0\n");
return XCAM_FAILURE;
}
ptr_rtp_session = (livestream_rtp_session*)malloc(sizeof(livestream_rtp_session));
if (!ptr_rtp_session) {
LOG_LIVESTREAM_ERROR("dynamic alloc for ptr_rtp_session failed\n");
return XCAM_FAILURE;
}
memset(ptr_rtp_session, 0x00, sizeof(livestream_rtp_session));
ptr_rtp_session->pack_buffer = (xcam_char*)malloc(packet_len);
if (!ptr_rtp_session->pack_buffer) {
LOG_LIVESTREAM_ERROR("dynamic alloc for pack_buffer failed\n");
free(ptr_rtp_session);
ptr_rtp_session = XCAM_NULL;
return XCAM_FAILURE;
}
memset(ptr_rtp_session->pack_buffer, 0x00, packet_len);
*pptr_session = ptr_rtp_session;
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_destroy(livestream_rtp_session* rtp_session)
{
if (XCAM_NULL == rtp_session) {
LOG_LIVESTREAM_ERROR("param rtp_session is null !\n");
return XCAM_FAILURE;
}
if (rtp_session->pack_buffer) {
free(rtp_session->pack_buffer);
rtp_session->pack_buffer = XCAM_NULL;
}
free(rtp_session);
rtp_session = XCAM_NULL;
return XCAM_SUCCESS;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */