将HI3518E当作服务器,用RTSP打包H264数据可以在局域网内采用rtsp观看。
main.c源码:
int main(void)
{
int s32MainFd,temp;
struct timespec ts = { 2, 0 };
pthread_t id;
//分配环形缓冲区,总共32个,每个大小为size
ringmalloc(1280*720);
printf("RTSP server START\n");
//设置服务器信息全局变量,设置内容保存在stPrefs结构体
PrefsInit();
printf("listen for client connecting...\n");
signal(SIGINT, IntHandl);
//创建、设置、绑定、监听套接字,并将套接字设为非阻塞模式
s32MainFd = tcp_listen(SERVER_RTSP_PORT_DEFAULT);
/*创建线程schedule_do:nanosleep(&ts, NULL)让出CPU,超时时间33333纳秒=33微秒到重新获得CPU。获得CPU时,在stop_schedule=0的情况下,循环
ringgetringget(&ringinfo)来取得3518里的H264数据然后用sched[i].play_action=RtpSend函数发送出去*/
if (ScheduleInit() == ERR_FATAL)
{
fprintf(stderr,"Fatal: Can't start scheduler %s, %i \nServer is aborting.\n", __FILE__, __LINE__);
return 0;
}
//设置rtp端口值,前面tcp_listen参数是RTSP端口,与RTP端口不同
RTP_port_pool_init(RTP_DEFAULT_PORT);
//SAMPLE_VENC_1080P_CLASSIC与H264编码差不多,只不过不是保存在文件里,而是通过网络直接发送
//出去,里面有个线程去处理视频流,读视频流时也会休眠
// 4个线程:1.main:负责切换所有线程,nanosleep让出cpu,超时唤醒
// 2.schedule_do:服务器取视频数据发 送线程,nanosleep让出cpu,超时唤醒
// 3.SAMPLE_VENC_1080P_CLASSIC:h264编码线程,sleep(1)让出CPU,但超时唤醒又死循环sleep(1),基本上可以不考虑这个线程
// 4.SAMPLE_COMM_VENC_GetVencStreamProc:读取3518的H264数据并保存到环形缓冲区线程,select休眠,有数据或超时唤醒
pthread_create(&id,NULL,SAMPLE_VENC_1080P_CLASSIC,NULL);
while (!g_s32Quit)
{
nanosleep(&ts, NULL);//超时时间为ts,NULL表示不记录剩余时间
EventLoop(s32MainFd);//这个s32MainFd是由上面的tcp_listen创建且是无阻塞模式
}
sleep(2);
ringfree();
printf("The Server quit!\n");
return 0;
}
先从大框架解释一下,HI3518E编码产生数据,然后又通过RTSP将数据打包发送出去,很符合生产者消费者模式,所以我们定义了一个环形缓冲区ringmalloc(1280*720);PrefsInit()规定了RTSP的端口为554端口,tcp_listen()按linux网络编程流程函数创建、绑定了套接字然后监听端口,而且还设置了套接字是无阻塞模式。
纵观整个程序,总共4个线程,main主线程:nanosleep(&ts, NULL)让出CPU,超时时间2秒唤醒,不断在EventLoop()函数里进行检查是否有RTSP连接请求,清理断开的连接和会话,用多路IO复用select函数来查询是否有RTSP包生成,调用select休眠,有RTSP数据或超时100ms唤醒.有RTSP包时,读取接收到的包和客户端IP地址,并将这些内容保存到rtsp结构体里,然后根据rtsp结构体内容进行解析通信。
schedule_do线程:nanosleep(&ts, NULL)让出CPU,超时时间33333纳秒=33微秒到重新获得CPU。获得CPU时,在stop_schedule=0的情况下,循环ringgetringget(&ringinfo)来取得3518里的H264数据然后用sched[i].play_action=RtpSend函数发送出去。
SAMPLE_VENC_1080P_CLASSIC线程:sleep(1)让出CPU,但超时唤醒又循环sleep(1),基本上可以不考虑这个线程。HI3518E对H264编码前作一些初始化的准备工作,主要工作内容见前面博客:海思3518E H264编码然后创建线程SAMPLE_COMM_VENC_GetVencStreamProc。
SAMPLE_COMM_VENC_GetVencStreamProc线程:select休眠,有数据或超时唤醒。Hi3518E进行H264编码并将编码数据存到ringinfo里。