doubao_chat/apps/wifi_ipc/wifi/stream/video_rt_tcp.c

379 lines
8.9 KiB
C

#include "sys_common.h"
#include "server/rt_stream_pkg.h"
#include "lwip.h"
#include "stream_core.h"
#include "sock_api/sock_api.h"
#include "app_config.h"
static u8 inited = 0;//防止重复发送
static u32 aux_frame_cnt = 0;
extern int atoi(const char *__nptr);
struct cli_info {
struct list_head entry;
void *fd;
struct sockaddr_in addr;
};
struct video_rt_tcp_server_info {
struct list_head cli_head;
struct sockaddr_in local_addr;
void *fd;
OS_SEM sem;
u32 flag;
u8 cb_flag;
};
static struct video_rt_tcp_server_info server_info = {
.cli_head = {
.next = &server_info.cli_head,
.prev = &server_info.cli_head,
},
};
static struct cli_info *get_tcp_net_info();
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, "tcp://");
if (!tmp) {
return -1;
}
tmp += strlen("tcp://");
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 video_rt_tcp_callback(enum sock_api_msg_type type, void *p)
{
//缓存大于2帧丢帧
struct video_rt_tcp_server_info *server_info = (struct video_rt_tcp_server_info *)p;
#if 0//暂时关闭,TCP发不完整一包会引起APP花屏
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 (server_info) {
server_info->cb_flag = 1;//server_info.cb_flag = 1;
return -1;
}
}
#endif
return 0;
}
static void *video_rt_tcp_init(const char *path, const char *mode)
{
int ret = 0;
puts("video_rt_tcp_init\n");
struct rt_stream_info *r_info = calloc(1, sizeof(struct rt_stream_info));
if (r_info == NULL) {
printf("%s malloc fail\n", __FILE__);
return NULL;
}
path_analyze(r_info, path);
struct cli_info *info = get_tcp_net_info();
if (info == NULL) {
printf("%s get_tcp_net_info\n", __FILE__);
free(r_info);
return NULL;
}
sock_clr_quit(info->fd);
memcpy((void *)&r_info->addr, (void *)&info->addr, sizeof(struct sockaddr));
r_info->fd = info->fd;
return (void *)r_info;
}
static u32 video_rt_tcp_send(void *hdr, u8 *data, u32 len, u8 type)
{
struct rt_stream_info *r_info = (struct rt_stream_info *)hdr;
int ret;
char *buffer = NULL;
static u32 i = 0;
char mem[64];
u32 tmp2;
u32 tmp;
u32 start_code = 0x01000000;
struct frm_head frame_head = {0};
//缓存大于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;
}
server_info.cb_flag = 0;
memset(&frame_head, 0, sizeof(struct frm_head));
frame_head.type = type ;
frame_head.seq = (i++);
if (aux_frame_cnt < 60) { //前面1.5秒加速播放
frame_head.timestamp += 0;
aux_frame_cnt++;
} else {
frame_head.timestamp += 0;
}
frame_head.timestamp = 0;
// frame_head.timestamp = 90000 / 30;
frame_head.frm_sz = len;
ret = sock_send(r_info->fd, (char *)&frame_head, sizeof(struct frm_head), 0);
if (server_info.cb_flag) {
return len;
}
if (ret <= 0) {
return -1;
}
if (type == H264_TYPE_VIDEO) {
//防止数据源被改
memcpy(mem, data, 64);
buffer = mem;
if (*((char *)(buffer + 4)) == 0x67) {
//处理PPS帧和SPS帧 I帧
memcpy(&tmp, buffer, 4);
tmp = htonl(tmp);
memcpy(buffer, &start_code, 4);
memcpy(&tmp2, buffer + tmp + 4, 4);
tmp2 = htonl(tmp2);
memcpy(buffer + tmp + 4, &start_code, 4);
memcpy(buffer + tmp + tmp2 + 8, &start_code, 4);
//printf("tmp %d tmp2 %d\n",tmp,tmp2);
} else {
// 处理P帧
memcpy(buffer, &start_code, 4);
}
ret = sock_send(r_info->fd, mem, 64, 0);
if (server_info.cb_flag) {
return len;
}
if (ret <= 0) {
return -1;
}
ret = sock_send(r_info->fd, (char *) data + 64, len - 64, 0);
if (server_info.cb_flag) {
return len;
}
if (ret <= 0) {
return -1;
}
} else {
ret = sock_send(r_info->fd, (char *)data, len, 0);
if (server_info.cb_flag) {
return len;
}
if (ret <= 0) {
return -1;
}
}
return len;
}
/*static void video_rt_tcp_uninit(void *hdr)*/
void video_rt_tcp_uninit(void *hdr)
{
puts("video_rt_tcp_uninit\n\n\n\n\n\n");
/*aux_frame_cnt = 0;*/
/*struct rt_stream_info *r_info = (struct rt_stream_info *)hdr;*/
/*free(r_info);*/
/*puts("video_rt_tcp_uninit\n\n\n\n\n\n");*/
struct rt_stream_info *r_info = (struct rt_stream_info *)hdr;
sock_set_quit(r_info->fd);
aux_frame_cnt = 0;
if (r_info) {
free(r_info);
r_info = NULL;
}
}
REGISTER_NET_VIDEO_STREAM_SUDDEV(tcp_video_stream_sub) = {
.name = "tcp",
.open = video_rt_tcp_init,
.write = video_rt_tcp_send,
.close = video_rt_tcp_uninit,
};
int TCP_client_socket_quit(int addr)
{
struct cli_info *cli = NULL;
struct list_head *pos = &server_info.cli_head;
struct sockaddr_in *dest_addr = NULL;
list_for_each(pos, &server_info.cli_head) {
cli = list_entry(pos, struct cli_info, entry);
if (cli) {
dest_addr = &cli->addr;
if (dest_addr->sin_addr.s_addr == addr) {
sock_set_quit(cli->fd);
printf("TCP_client_socket_quit \n");
}
}
}
return 0;
}
static struct cli_info *get_tcp_net_info()
{
struct list_head *pos = NULL;
struct cli_info *cli = NULL;
struct cli_info *old_cli = NULL;
int count = 0;
os_sem_pend(&server_info.sem, 50);
list_for_each(pos, &server_info.cli_head) {
cli = list_entry(pos, struct cli_info, entry);
printf("ip:%s port:%d\n\n", inet_ntoa(cli->addr.sin_addr.s_addr), htons(cli->addr.sin_port));
count++;
}
printf("count = %d\n\n", count);
if (count > 1) {
old_cli = list_first_entry(&server_info.cli_head, struct cli_info, entry);
list_del(&old_cli->entry);
sock_set_quit(old_cli->fd);
sock_unreg(old_cli->fd);
old_cli->fd = NULL;
free(old_cli);
}
return cli;
}
static void __do_sock_accpet(void *arg)
{
socklen_t len = sizeof(server_info.local_addr);
while (1) {
struct cli_info *__cli = calloc(1, sizeof(sizeof(struct cli_info)));
if (__cli == NULL) {
printf("malloc fail\n");
while (1);
}
__cli->fd = sock_accept(server_info.fd, (struct sockaddr *)&__cli->addr, &len, video_rt_tcp_callback, &server_info);
if (server_info.flag) {
break;
}
if (__cli->fd == NULL) {
printf("some error in here\n\n");
continue;
}
printf("__do_sock_accpet add client list\n\n");
list_add_tail(&__cli->entry, &server_info.cli_head);
os_sem_post(&server_info.sem);
}
server_info.flag = 0;
sock_unreg(server_info.fd);
}
int video_rt_tcp_server_init(int port)
{
int ret = 0;
puts("video_rt_tcp_server_init\n");
memset(&server_info, 0x0, sizeof(server_info));
os_sem_create(&server_info.sem, 0);
server_info.local_addr.sin_family = AF_INET;
server_info.local_addr.sin_addr.s_addr = htonl(INADDR_ANY) ;
server_info.local_addr.sin_port = htons(port);
server_info.fd = sock_reg(AF_INET, SOCK_STREAM, 0, NULL, NULL);
if (server_info.fd == NULL) {
return -1;
}
u32 opt = 1;
if (sock_setsockopt(server_info.fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
printf("%s sock_bind fail\n", __FILE__);
return -1;
}
if (sock_bind(server_info.fd, (struct sockaddr *)&server_info.local_addr, sizeof(struct sockaddr))) {
printf("%s sock_bind fail\n", __FILE__);
return -1;
}
sock_listen(server_info.fd, 0x5);
INIT_LIST_HEAD(&server_info.cli_head);
ret = thread_fork("__do_sock_accpet", 25, 256, 0, 0, __do_sock_accpet, NULL);
if (ret != OS_NO_ERR) {
printf("%s thread fork fail\n", __FILE__);
return -1;
}
return 0;
}
void video_rt_tcp_server_uninit()
{
printf("video_rt_tcp_server_uninit\n");
server_info.flag = 1;
sock_set_quit(server_info.fd);
/*sock_unreg(server_info.fd);*/
}