前言
mjpg-streamer是一个开源的视频流媒体服务器软件,能够利用Linux系统的视频设备驱动以及JPEG编码库,将摄像头捕获的视频帧实时转换为MJPEG格式的数据流,并通过HTTP协议对外提供服务。它支持多种视频输入源,并能通过网络将视频流推送给支持HTTP协议的客户端。
因此摄像头数据向网页的推流,我们采用 mjpg-streamer 来实现。具体的移植步骤可参考以下内容:mjpg-streamer移植到IMX6ULL
本次实验使用的USB摄像头是罗技C270,如要采用其他摄像头,则应采用支持UVC且支持MJPEG输出的摄像头。
摄像头推流到网页
要实现推流,我们需要知道推流的端口地址,mjpg默认是8080端口,因此我们访问http://192.168.1.50:8080/?action=stream即可获取推流图像。
在网页端需要指明图片的路径,HTML部分代码如下:
实现的最终效果如下图所示:
摄像头抓拍
在 /boa 目录下创建 history 文件夹,用于存放抓拍图片。用户点击监控界面的“拍照”按钮后,将触发 capture.cgi 程序执行。该程序以当前系统时间作为文件名,将抓拍的图像存储至 /boa/history/ 目录中。
抓拍图像直接调用 mjpg-streamer 自带的快照接口即可获取,无需额外开发采集逻辑:
http://127.0.0.1:8080/?action=snapshot
capture.cgi 的程序实现如下:
// ==================== capture.cgi ====================#include<stdio.h>#include<stdlib.h>#include<string.h>#include<time.h>#include<unistd.h>#defineCAPTURE_DIR"/boa/history/"intmain(void){charfilename[64];charfullpath[128];charcmd[256];time_tnow;structtm*tm_info;// 1. 生成文件名(按时间命名)time(&now);tm_info=localtime(&now);strftime(filename,sizeof(filename),"capture_%Y%m%d_%H%M%S.jpg",tm_info);// 2. 完整存储路径snprintf(fullpath,sizeof(fullpath),"%s%s",CAPTURE_DIR,filename);// 3. 从 mjpg-streamer 获取快照并保存snprintf(cmd,sizeof(cmd),"wget -q -O %s http://127.0.0.1:8080/?action=snapshot",fullpath);system(cmd);snprintf(cmd,sizeof(cmd),"chmod 644 %s",fullpath);// 赋予权限system(cmd);// 4. 返回 JSON 响应printf("Content-Type: application/json\r\n");printf("Access-Control-Allow-Origin: *\r\n");printf("\r\n");// 5. 检查是否保存成功if(access(fullpath,F_OK)==0){printf("{\"success\": true, \"filename\": \"%s\"}\n",filename);}else{printf("{\"success\": false, \"message\": \"抓拍失败\"}\n");}return0;}历史记录页面通过 list_images.cgi 读取 /boa/history/ 目录下的图片文件,并将文件信息封装为 JSON 格式返回给前端。前端 history.html 获取该 JSON 数据后解析渲染,即可展示历史抓拍图片列表。
以下是list_images.c的程序:
// ==================== list_images.cgi ====================#include<stdio.h>#include<stdlib.h>#include<string.h>#include<dirent.h>#include<sys/stat.h>#include<time.h>#defineCAPTURE_DIR"/boa/history/"intmain(void){DIR*dir;structdirent*entry;structstatfile_stat;charfullpath[256];intfirst=1;printf("Content-Type: application/json\r\n");printf("Access-Control-Allow-Origin: *\r\n");printf("\r\n");printf("{ \"images\": [");dir=opendir(CAPTURE_DIR);if(dir!=NULL){while((entry=readdir(dir))!=NULL){// 只处理 .jpg 文件if(strstr(entry->d_name,".jpg")==NULL)continue;snprintf(fullpath,sizeof(fullpath),"%s%s",CAPTURE_DIR,entry->d_name);stat(fullpath,&file_stat);// 格式化时间(加 8 小时修正时区)chartime_str[64];time_tadjusted_time=file_stat.st_mtime+28800;// +8小时structtm*tm_info=localtime(&adjusted_time);strftime(time_str,sizeof(time_str),"%Y-%m-%d %H:%M:%S",tm_info);if(!first)printf(",");printf("{");printf("\"filename\":\"%s\",",entry->d_name);printf("\"time\":\"%s\"",time_str);printf("}");first=0;}closedir(dir);}printf("] }\n");return0;}