doubao_chat/apps/wifi_camera/wifi/stream/video_rt_udp.c

340 lines
9.0 KiB
C

#include "sys_common.h"
#include "system/spinlock.h"
#include "os/os_api.h"
#include "server/rt_stream_pkg.h"
#include "app_config.h"
#include "lwip.h"
#include "lwip/sockets.h"
#include "sock_api/sock_api.h"
#include "os/os_api.h"
#include "stream_core.h"
/*
UDP端口:2224
UDP 每片数据包 格式:
|1byte 类型 | 1byte 保留 | 2byte payload长度 | 4byte 序号 | 4byte 帧大小 | 4byte 偏移 | 4byte 时间戳 | payload |
*/
#define UDP_SEND_BUF_SIZE (5*1472)
#define MAX_PAYLOAD (1472-sizeof(struct frm_head))//最后4字节属于h264流的
static u32 video_timestramp = 0;
static u32 audio_timestramp = 0;
static u32 seq = 1;
static u32 aux_frame_cnt = 0;
static u32 old_times = 0;
static u32 new_times = 0;
static struct rt_stream_info *rt_info = NULL;
extern int atoi(const char *__nptr);
extern int net_video_rec_get_list_vframe(void);
extern int net_video_buff_set_frame_cnt(void);
static int path_analyze(struct rt_stream_info *info, const *path)
{
char *tmp = NULL;
char *tmp2 = NULL;
char ip[15] = {0};
u16 port = 0;
tmp = strstr(path, "udp://");
if (!tmp) {
return -1;
}
tmp += strlen("udp://");
tmp2 = strchr(tmp, ':');
printf("tmp=%s len=%d\n", tmp, tmp2 - tmp);
strncpy(ip, tmp, tmp2 - tmp);
port = atoi(tmp2 + 1);
printf("remote ip:%s port:%d\n", ip, port);
info->addr.sin_family = AF_INET;
info->addr.sin_addr.s_addr = inet_addr(ip);
info->addr.sin_port = htons(port);
return 0;
}
static int net_rt_pkg_udp_callback(enum sock_api_msg_type type, void *p)
{
//缓存大于2帧丢帧
struct rt_stream_info *info = (struct rt_stream_info *)p;
int vcnt = net_video_rec_get_list_vframe();
int set_cnt = net_video_buff_set_frame_cnt();
if (vcnt > set_cnt && set_cnt > 0) {
if (info) {
info->cb_flag = 1;
}
return -1;
}
return 0;
}
static void *get_sock_handler(int (*cb_func)(enum sock_api_msg_type type, void *priv), void *priv)
{
void *fd = NULL;
if (0) { //条件链表
//add P2P code
} else {
fd = sock_reg(AF_INET, SOCK_DGRAM, 0, cb_func, priv);
if (fd == NULL) {
printf("%s %d->Error in socket()\n", __func__, __LINE__);
return NULL;
}
u32 millsec = 100;
sock_setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (const void *)&millsec, sizeof(millsec));
return fd;
}
}
struct rt_stream_info *net_rt_vpkg_open(const char *path, const char *mode)
{
int flags = 0;
int err;
struct rt_stream_info *info = (struct rt_stream_info *)calloc(1, sizeof(struct rt_stream_info));
if (info == NULL) {
printf("%s %d->Error in malloc()\n", __func__, __LINE__);
return NULL;
}
info->udp_send_buf = (char *)malloc(UDP_SEND_BUF_SIZE);
if (info->udp_send_buf == NULL) {
printf("%s %d->Error in malloc()\n", __func__, __LINE__);
free(info);
return NULL;
}
if (path_analyze(info, path)) {
printf("%s %d->Error in path_analyze\n", __func__, __LINE__);
free(info);
return NULL;
}
info->fd = get_sock_handler(net_rt_pkg_udp_callback, info);
if (!info->fd) {
printf("%s %d->Error get_sock_handler\n", __func__, __LINE__);
free(info);
return NULL;
}
rt_info = info;
return info;
err1:
free(info->udp_send_buf);
free(info);
return NULL;
}
int net_rt_vpkg_write(struct rt_stream_info *info, char *buffer, size_t len, struct sockaddr *addr, int addrlen)
{
/* struct sockaddr_in * addr2 = (struct sockaddr_in *)addr; */
return sock_sendto(info->fd, buffer, len, 0, addr, addrlen);
}
int net_rt_vpkg_close(struct rt_stream_info *info)
{
video_timestramp = 0;
audio_timestramp = 0;
aux_frame_cnt = 0;
//os_sem_del(&mutex,OS_DEL_ALWAYS);
if (info->fd) {
sock_unreg(info->fd);
}
if (info->udp_send_buf) {
free(info->udp_send_buf);
}
free(info);
rt_info = NULL;
return 0;
}
int UDP_client_socket_unreg(int addr)
{
if (rt_info) {
printf("UDP_client_socket_quit , addr 0x%x , 0x%x\n", rt_info->addr.sin_addr.s_addr, addr);
if (rt_info->addr.sin_addr.s_addr == addr) {
video_timestramp = 0;
audio_timestramp = 0;
aux_frame_cnt = 0;
sock_set_quit(rt_info->fd);
sock_unreg(rt_info->fd);
rt_info->fd = NULL;
rt_info = NULL;
return 0;
}
}
return -1;
}
#ifdef CONFIG_UVC_VIDEO2_ENABLE
static u32(*uvc_send_data_cb)(void *priv, void *data, u32 len);
void set_udp_uvc_rt_cb(u32(*cb)(void *priv, void *data, u32 len))
{
uvc_send_data_cb = cb;
}
#endif
int net_rt_send_frame(struct rt_stream_info *info, char *buffer, size_t len, u8 type)
{
u16 payload_len = 0;
u32 total_udp_send = 0;
struct frm_head frame_head = {0};
u32 change_data = 0x01000000;
u32 tmp, tmp2, tmp3;
int ret;
u32 remain_len = len;
#if TCFG_LCD_USB_SHOW_COLLEAGUE
if (type == H264_TYPE_VIDEO || type == JPEG_TYPE_VIDEO) {
if (uvc_send_data_cb) {
uvc_send_data_cb(NULL, buffer, len);
} else {
if (type == H264_TYPE_VIDEO || type == JPEG_TYPE_VIDEO) {
putchar('V');
} else {
putchar('A');
}
}
}
#endif
if (info == NULL || info->udp_send_buf == NULL || info->fd == NULL) {
printf("use net_rt_stream_open_pkg\n");
return -1;
}
//缓存大于2帧丢帧
int vcnt = net_video_rec_get_list_vframe();
int set_cnt = net_video_buff_set_frame_cnt();
if (vcnt > set_cnt && set_cnt > 0) {
return len;
}
info->cb_flag = 0;
frame_head.offset = 0;
frame_head.frm_sz = len;
frame_head.type &= ~LAST_FREG_MAKER;
frame_head.type |= type;
/*
static u32 last_ms;
static u32 freq_num;
u32 now_ms;
freq_num++;
now_ms = timer_get_ms();
if (last_ms && now_ms > last_ms && (now_ms - last_ms) / 1000) { //1000ms
last_ms = now_ms - (now_ms - last_ms) % 1000;
printf("\n ===== send num : %d =======\n", freq_num);
freq_num = 0;
} else if (now_ms <= last_ms || !last_ms) {
last_ms = now_ms;
}
*/
if (frame_head.type == H264_TYPE_VIDEO || frame_head.type == JPEG_TYPE_VIDEO) {
//video_timestramp += 90000 / VIDEO_FRQ_30HZ;
new_times = timer_get_ms();
if (aux_frame_cnt < 60) {
video_timestramp = 0;
} else {
video_timestramp += 0;//(new_times - old_times) * 100;
}
/* printf("p=%d\n",new_times-old_times); */
old_times = new_times;
frame_head.timestamp = video_timestramp;
} else {
audio_timestramp = 501;
frame_head.timestamp = audio_timestramp;
}
frame_head.timestamp = 0;
frame_head.seq = seq++;
while (remain_len) {
if (remain_len < MAX_PAYLOAD) {
payload_len = remain_len;
frame_head.type |= LAST_FREG_MAKER;
} else {
payload_len = MAX_PAYLOAD;
}
frame_head.payload_size = payload_len;
memcpy(info->udp_send_buf + total_udp_send, &frame_head, sizeof(struct frm_head));
total_udp_send += sizeof(struct frm_head);
memcpy(info->udp_send_buf + total_udp_send, buffer + frame_head.offset, payload_len);
if (frame_head.offset == 0 &&
frame_head.type == H264_TYPE_VIDEO) {
if (*((char *)(info->udp_send_buf + total_udp_send + 4)) == 0x67) {
//处理PPS帧和SPS帧 I帧
memcpy(&tmp, info->udp_send_buf + total_udp_send, 4);
tmp = htonl(tmp);
memcpy(info->udp_send_buf + total_udp_send, &change_data, 4);
memcpy(&tmp2, info->udp_send_buf + total_udp_send + tmp + 4, 4);
tmp2 = htonl(tmp2);
memcpy(info->udp_send_buf + total_udp_send + tmp + 4, &change_data, 4);
memcpy(info->udp_send_buf + total_udp_send + tmp + tmp2 + 8, &change_data, 4);
} else {
// 处理P帧
memcpy(info->udp_send_buf + total_udp_send, &change_data, 4);
}
}
total_udp_send += payload_len;
if ((total_udp_send == UDP_SEND_BUF_SIZE) || (payload_len < MAX_PAYLOAD)) {
if ((ret = net_rt_vpkg_write(info, info->udp_send_buf, total_udp_send, (struct sockaddr *)&info->addr, sizeof(struct sockaddr_in))) != total_udp_send) {
if (info->cb_flag) {
return len;
}
/* printf("ret:%d total_udp_send:%d\n", ret, total_udp_send); */
puts("rt_stream_sent error!\n");
return -1;
}
total_udp_send = 0;
}
remain_len -= payload_len;
frame_head.offset += payload_len;
}
return len;
}
REGISTER_NET_VIDEO_STREAM_SUDDEV(udp_video_stream_sub) = {
.name = "udp",
.open = net_rt_vpkg_open,
.write = net_rt_send_frame,
.close = net_rt_vpkg_close,
};