当前位置: > 华清远见教育科技集团 > 嵌入式学习 > 讲师博文 > 视频服务器(三)
视频服务器(三)
时间:2016-12-13作者:华清远见

CYG视频服务器之代码解释

1.和浏览器交互的线程

void *client_thread(void *arg)
        {
            request_t request = {0};
            char buf[1024] = {0};
            client_t *pclient = (client_t *)arg;
            //接受浏览器发过来的请求
            if(recv(pclient->connect_fd,buf,sizeof(buf) -1,0) < 0)
            {
                perror("Fail to recv");
                pthread_exit(NULL);
            }

            //分析请求
            if(analysis_http_request(buf,&request) < 0){
                pthread_exit(NULL);
            }

            //应答浏览器
            switch(request.type)
            {
                case A_FILE:
                send_file(pclient->connect_fd,request.parm,pclient->www_dir);
                break;

                case A_SNAPSHOT:
                send_snapshot(pclient->connect_fd);
                break;

                case A_STREAM:
                send_stream(pclient->connect_fd);
                break;
            }
            close(pclient->connect_fd);
            free(pclient->www_dir);
            printf("free pclient->www_dir ok.\n");
            free(pclient);
            printf("free pclient ok.\n");
            free(request.parm);
            printf("free request.parm ok.\n");
            return NULL;
        }

2.接受客户端发送的请求

int accept_http_request(int sockfd,char *buf)
        {
            fd_set fds;
            int ret;
            int n = 0,offset = 0;
            struct timeval tv = {5,0};
            while(1)
            {
                FD_ZERO(&fds);
                FD_SET(sockfd,&fds);
                if((ret = select(sockfd + 1,&fds,NULL,NULL,&tv)) <= 0)
                {
                    if(ret < 0){
                        perror("Fail to select");
                        return -1;
                    }
                    break;
                }

                if((n = recv(sockfd,buf + offset,BUFFER_SIZE - offset,0)) < 0)
                {
                    perror("Fail to recv");
                    return -1;
                }
                #if 0
                printf("***********************************\n");
                printf("%s\n",buf);
                printf("***********************************\n");
                #endif
                offset += n;
                if(offset >= sizeof(buf) - 1)
                break;
            }
            return 0;
        }

3.分析请求的内容

int analysis_http_request(char *buf,request_t *req)
        {
            int len = 0;
            char *p = NULL;

            /* determine what to deliver */
            if ( strstr(buf, "GET /?action=snapshot") != NULL ) {
                req->type = A_SNAPSHOT;
                return 0;
            }else if ( strstr(buf, "GET /?action=stream") != NULL ) {
                req->type = A_STREAM;
                return 0;
            }else{

                if((p = strstr(buf,"GET /")) == NULL)
                {
                    printf("Http request error.\n");
                    //send error to client
                    return -1;
                }
                p += strlen("GET /");
                Len=MIN(MAX(strspn(p, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._-1234567890"), 0), 100);
                req->parm = (char *)malloc(len + 1);
                memset(req->parm,0,len+1);
                memcpy(req->parm,p,len);
                printf("req->parm : %s.\n",req->parm);
                req->type = A_FILE;
            }

            return 0;
        }

4.发送一副静态图片

void send_snapshot(int sockfd)
        {
            int length;
            char *frame;
            char buf[BUFFER_SIZE];

            pthread_mutex_lock(&global.update_lock);

            pthread_cond_wait(&global.update_cond,&global.update_lock);

            //获得视频数据
            length = global.length;
            frame = (char *)malloc(global.length);
            memcpy(frame,global.start,global.length);

            pthread_mutex_unlock(&global.update_lock);

            //添加http头
            memset(buf,0,sizeof(buf));
            sprintf(buf, "HTTP/1.0 200 OK\r\n" \
                        "Content-type: image/jpeg\r\n" \
                        STD_HEADER \
                        "\r\n");

            //发送http头
            if(send(sockfd,buf,strlen(buf),0) < 0)
            {
                free(frame);
                return;
            }

            //发送视频数据
            if(send(sockfd,frame,length,0) < 0)
            {
                free(frame);
                return;
            }

            free(frame);

            return;
        }

5.发送视频流

void send_stream(int sockfd)
        {
            int length;
            char *frame;
            char buf[BUFFER_SIZE];

            printf("send_stream\n");

            sprintf(buf, "HTTP/1.1 200 OK\r\n" \
                        STD_HEADER \
                        "Content-Type: multipart/x-mixed-replace;boundary=" BOUNDARY "\r\n" \
                        "\r\n" \
                        "--" BOUNDARY "\r\n");

            //send to http head
            if(send(sockfd,buf,strlen(buf),0) < 0)
            {
                perror("fail to send http head");
                return;
            }

            printf("send http head ok\n");

            while(!global.stop)
            {
                pthread_mutex_lock(&global.update_lock);
                pthread_cond_wait(&global.update_cond,&global.update_lock);

                //获得视频数据
                length = global.length;
                frame = (char *)malloc(global.length);
                memcpy(frame,global.start,global.length);

                pthread_mutex_unlock(&global.update_lock);

                /* print the individual mimetype and the length
                * sending the content-length fixes random stream disruption observed
                * with firefox
                */
                sprintf(buf, "Content-Type: image/jpeg\r\n" \
                "Content-Length: %d\r\n" \
                "\r\n",length);
                //sending intermdiate header
                if(send(sockfd,buf,strlen(buf),0) < 0)
                {
                    perror("Fail to send intermdiate header");
                    return;
                }

                printf("send intermdiate header.\n");

                //sending camera frame
                if(send(sockfd,frame,length,0) < 0)
                {
                    perror("Fail to send camera frame");
                    return;
                }

                sprintf(buf, "\r\n--" BOUNDARY "\r\n");
                if ( send(sockfd, buf, strlen(buf),0) < 0 ) break;

                free(frame);
            }

            return;
        }

6.发送普通文件

void send_file(int sockfd,char *pathfile,char *www_dir)
        {
            int n,fd,i;
            char buf[1024] = {0};
            char *extension, *mimetype=NULL;

            if(pathfile == NULL || strlen(pathfile) == 0)
            pathfile = "index.html";

            /* find file-extension */
            if ( (extension = strstr(pathfile, ".")) == NULL ) {
                // send_error(fd, 400, "No file extension found");
                return;
            }

            /* determine mime-type */
            for ( i=0; i < LENGTH_OF(mimetypes); i++ ) {
                if ( strcmp(mimetypes[i].dot_extension, extension) == 0 ) {
                    mimetype = (char *)mimetypes[i].mimetype;
                    break;
                }
            }

            /* in case of unknown mimetype or extension leave */
            if ( mimetype == NULL ) {
                // send_error(fd, 404, "MIME-TYPE not known");
                return;
            }

            //打开文件
            sprintf(buf,"%s/%s",www_dir,pathfile);
            if((fd = open(buf,O_RDONLY)) < 0)
            {
                fprintf(stderr,"Fail to open %s : %s.\n",buf,strerror(errno));
                //send error to webbrowser
                return;
            }

            // printf("pathfile : %s.\n",buf);

            //添加http头
            memset(buf,0,sizeof(buf));
            sprintf(buf, "HTTP/1.0 200 OK\r\n" \
                        "Content-type: %s\r\n" \
                        STD_HEADER \
                        "\r\n",mimetype);

            n = strlen(buf);

            //发送http头信息和网页
            do{
                send(sockfd,buf,n,0);
            }while(n = read(fd,buf,sizeof(buf)));
            return;

发表评论
评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)