zoukankan      html  css  js  c++  java
  • 嵌入式-项目1-基于视频压缩的实时监控系统-2.基于Epoll的采集端程序框架设计

    第2课-基于Epoll的采集端程序框架设计

    epoll的使用流程

    (1)创建

    (2)加入事件

    (3)等待和处理

     

     

    步骤:

    1. 创建源文件

    我们的软件体系到底能不能完成,关键的事情就是加入事件(摄像头)。

    这里我们区分,主程序是第一个模块,摄像头采集系统是第二个模块,传输系统是第三个模块,配置子系统是第四个模块。每个模块对应一个原文件,我们要创建四个原文件。分别为:main.c cam.c net.c cfg.c

     

     

    1. 模型代码化

    我们创建一个include文件,用来存放我们要用到的头文件。创建头文件main.h。在这里建立结构体struct server,在cam.c中建立结构体struct cam,在net.c中建立struct tcp,在cfg.c中建立struct cfg,具体内容先不去填写。今天我们的任务就是将main.h中的内容进行完善即可。

    主程序对应着与配置子系统、采集子系统、传输子系统和epoll框架这四个内容的关系。我们就建立四个成员对应这四个关系。我们可以进行函数下放,就要下放接口。子程序同时也提供函数接口,这样就完成了函数的下放。我们看看有哪些接口:

    (1)添加事件到EPOLL

    (2)EPOLL中删除事件

    现在我们在想为什么不直接用系统带的函数epoll_ctl,还要自己写呢?因为我们用的epoll_ctl是依赖于struct epoll_event结构来的,但是这个结果里面的信息有限:

    typedef union epoll_data

    {

    void *ptr;

    int fd;

    uint32_t u32;

    uint64_4 u64;

    }epoll_data_t;

    stryct epoll_event

    {

    unint32_t events;   /*Epoll events*/

    epoll_data_t data;  /*User data variable*/

    };

    也就只有一个文件类型和一个联合(包含4项),我们要是想多保存点信息就不行了。我们可以使这个指针再加一些附加结构,这里面保存我们想要有的其他信息。我们在main函数中定义就可以。

     

    struct server

    {

    int epfd;   //指向epoll

    struct cam *cam;  //指向采集子系统

    struct tcp_srv *srv; //指向传输子系统

    struct cfg* cfg;   //指向配置子系统

    };

    1. 程序

    main.c

    #include<stdio.h>

    #include<unistd.h>

    #include<fcntl.h>

    #include<sys/epoll.h>

    #include<main.h>

    #include<stdbool.h>

    struct event_ext    //我们的附加的结构体,用来补充epoll_ctl函数

    {

    int fd;

    bool epolled;   //表示我们的时间是否已经加入到了我们监控池之中

    uint32_t events;  //事件的类型

    void (*handler)(int fd,void *arg);  //函数指针,其中有两个成员

    void *arg;  //提供给handler使用的指针

    };

    /*由于我们附加的函数的作用,我们还得需要自己手写我们对人epoll事件的添加和删除函数*/

    /*基于新的结构体而定创造函数,结构体中有的内容,这里面都该有,第一个结构*/

    struct event_ext *epoll_event_creat(int fd,uint32_t type,void (*handler)(void *arg),void *arg)

    {

    struct event_ext *e = calloc(1,sizeof(struct event_ext));  //分配空间,进行初始化

    e->fd = fd;

    e->events = type;

    e->handler = handler;

    e->arg = arg;

    return e;

    };

    //添加epoll,第二个结构

    int epoll_add_event(int epfd, struct event_ext *ev)   

     /*创建一个事件附加结构,并将参数传进来*/

    {

    struct epoll_event epv; //先创建一个结构体

    int op; //定义原本的epoll_ctl中的第二个参数

    //2. 初始化epoll_event(将附加结构挂载到epoll_event中)

    epv.data.ptr = ev;   //将附加的结构挂载原来系统带的结构体上

    epv.events =  ev->events;  //初始化数据类型,原本的epoll_event中就这两个成员

    if(ev->epolled)  //文件已经存在的时候,就是进行修改,否则进行加入

    {

    op = EPOLL_CTL_MOD; //修改的操作

    }

    else

    {

    op = EPOLL_CTL_ADD;//添加的操作

    ev->epolled = true; //第一次添加进去之后,标识就变成了真

    }

    //3. 将epoll_even加入到epoll中

    epoll_ctl(epfd,op,ev->fd,&epv);

    return 0;

    };

    //从epoll池中删除

    int epoll_del_event(int epfd, struct event_ext *ev)

    {

    epoll_ctl(epfd,EPOLL_CTL_DEL,ev->fd,NULL);

    ev->epolled = false; //删除后,标识就变成了假

    return 0;

    };

    /*定义结束这个附加的结构指针,我们才能对下面的标有“处理”的地方进行书写*/

    int main()

    {

    struct epoll_event events[512];

    int fds;

    int i;

    uint32_t event;   //用于保存事件的类型

    struct event_ext *e;  //附加结构带来的新的指针

    srv_main = calloc(1,sizeof(struct server));  //为结构体分配空间

    //1. 创建epoll

    srv_main->epfd = epoll_create(512);

    //2. 加入等事件,将这个程序进行下放-交给子系统,这之后就要设置子系统的函数接口

    srv_main->cam = cam_sys_init();

    srv_main->srv = net_sys_init();

    //3. 等待事件发生且处理

    while(1)   //不断地进行处理相应的事件

    {

    fds = epoll_wait(srv_main->epfd,events,512,1000);

    for(i=0;i<fds;i++)

    {

    event = events[i].events;   //保存事件的类型

    e = events[i].data.ptr;         //保存事件的处理方法

    if((event&EPOLLIN)&&(e->events&EPOLLIN)) /*若是读的事件,附加条件要e里面的内容类型与event里面的一致*/

    {

    //处理

    e->handler(e->fd,e->arg);

    }

    if((event&EPOLLOUT)&&(e->events&EPOLLOUT)) /*若是读的事件,附加条件要e里面的内容类型与event里面的一致*/

    {

    //处理

    e->handler(e->fd,e->arg);

    }

    if((event&EPOLLERR)&&(e->events&EPOLLERR))  /*若是读的事件,附加条件要e里面的内容类型与event里面的一致*/

    {

    //处理

    e->handler(e->fd,e->arg);

    }

    }

    }

    return -1;   //按道理来讲我们而定循环是不应该结束的,要是结束了就说明程序出错了

    }

    cam.c

    #include<main.h>

     

     

    struct cam

    {

     

    };

     

    struct cam *cam_sys_init()

    {

    //1. 初始化采集子系统

     

     

    //2. 将采集子系统中的事件加入epoll池

     

     

    return NULL;

    };

     

    net.c

    #include<main.h>

     

    struct tcp_srv

    {

     

    };

     

    struct tcp_srv *net_sys_init()

    {

    //1. 初始化传输子系统

     

     

    //2. 将传输子系统中的事件加入epoll池

     

     

    return NULL;

     

     

    };

    cfg.c

    struct cfg

    {

     

    };

     

     

     

    1. 编译

    创建一个Makefile文件,touch Makefile。通过samb服务器打开这个文件我们写下如下的文件:

    BIN = wcamsrv                                                          //输出的文件名字

    INC = -Iinclude/     /*表示需要引用的是当前文件下的include文 件,-I表示的对应的操作*/

    SRC = $(wildcard *.c)                         //表示寻找的该路径下的所有.c文件,都给SRC

    OBJ = $(patsubst %.c, %.o, $(SRC) )     /*表示输出的格式是.o的形式的,对应的三个参数,第一个参数表示所有的.c文件,第二个参数表示输出都是.o文件,第三个参数表示来自SCR变量*/

    CC = arm-linux-gcc                                                   //表示编译器的选择

    CFLAGS = $(INC) -g                                                           //编译选项

    $(BIN):$(OBJS)                                                               //编译依赖

    $(CC) -o $@ $^                                                          //编译输出

    clean:                                                                      //清除选项

    rm $(OBJS) $(BIN)                                                        

     

  • 相关阅读:
    分布式大数据高并发的web开发框架
    用户安全登录问题
    成功扩展live555支持ipv6,同时支持RTSPServer & RTSPClient
    经过两个多月的攻关,终于搞定了live555多线程并稳定压测通过
    经过两个多月的攻关,终于搞定了live555多线程并稳定压测通过
    如何使用EasyNVR+CDN突破萤石云在直播客户端数量上的限制,做到低成本高性价比的直播
    EasyNVR完美搭配腾讯云CDN/阿里云CDN进行RTMP、HLS直播加速的使用说明
    NVR硬件录像机web无插件播放方案功能实现之相关接口注意事项说明
    EasyNVR实现海康、大华NVR硬盘录像机Web无插件播放方案(支持取特定时间段视频流)
    EasyNVR无插件直播服务如何配合EasyBMS使用以及实现流媒体管理功能概述
  • 原文地址:https://www.cnblogs.com/free-1122/p/9709830.html
Copyright © 2011-2022 走看看