0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux下基于HTTP网页视频监控

嵌入式技术 来源:嵌入式技术 作者:嵌入式技术 2022-08-31 08:56 次阅读

Linux下基于HTTP网页视频监控

1.HTTP简介

超文本传输协议(Hyper Text Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII形式给出;而消息内容则具有一个类似MIME的格式。这个简单模型是早期Web成功的有功之臣,因为它使开发和部署非常地直截了当。
HTTP的发展是由蒂姆·伯纳斯-李于1989年在欧洲核子研究组织(CERN)所发起。HTTP的标准制定由万维网协会(World Wide Web Consortium,W3C)和互联网工程任务组(Internet Engineering Task Force,IETF)进行协调,最终发布了一系列的RFC,其中最著名的是1999年6月公布的 RFC 2616,定义了HTTP协议中现今广泛使用的一个版本——HTTP 1.1。
HTTP 是一个基于 TCP/IP 通信协议来传递数据( HTML 文件, 图片文件, 查询结果等)。工作于客户端-服务端架构上,默认端口号为 80,但是你也可以改为 8080或其它端口号。HTTP协议永远都是客户端发起请求,服务器回送响应。

poYBAGMOGAqAbe4DAAJliuWhVAc526.png#pic_center

 HTTP是基于客户/服务器模式,且面向连接的。
客户与服务器之间的HTTP连接是一种一次性连接,它限制每次连接只处理一个请求,当服务器返回本次请求的应答后便立即关闭连接,下次请求再重新建立连接。当然HTTP也可以设置为长连接,在HTTP / 1.1中,引入了保持活动机制,其中连接可以重用于多个请求。这样的持久性连接可以明显减少请求延迟,因为在发送第一个请求之后,客户端不需要重新协商TCP 3-Way-Handshake连接。

HTTP是一种无状态协议,即服务器不保留与客户交易时的任何状态。这就大大减轻了服务器记忆负担,从而保持较快的响应速度。但也意味着如果后续处理需要前面的信息则必须重传。

2.HTTP报文格式

HTTP报文是面向文本的,报文中的每一个字段都是一些ASCII码串,每个字段的长度是不确定的。

HTTP有两种报文:请求报文和响应报文。

HTTP的请求报文由四部分组成:请求行(request line)、请求头部(header)、空行和请求数据(request data)

pYYBAGMOGAqAA6trAABD1X2gBK4308.png#pic_center

  HTTP 响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。

poYBAGMOGAuAVwodAAIebXO9tLs922.png#pic_center

3.HTTP请求方式

HTTP/1.1协议中共定义了八种方法(有时也叫“动作”),来表明Request-URL指定的资源不同的操作方式
其中:

HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。

HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法
4.HTTP状态码

当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含 HTTP 状态码的信息头( server header)用以响应浏览器的请求。

HTTP 状态码的英文为 HTTP Status Code。

下面是常见的 HTTP 状态码:

200 - 请求成功

301 - 资源(网页等)被永久转移到其它 URL

404 - 请求的资源(网页等)不存在

500 - 内部服务器错误

5.搭建HTTP服务器

HTTP 协议底层是 TCP 协议, HTTP 本身属于上层协议, 协议格式都是以文本格式响应。 浏览器在访问 HTTP服务器时,会发送请求报文, HTTP 服务器解析请求报文,根据解析结果,给浏览器进行回应。

浏览器第一次访问 HTTP 服务器时,会请求空路径, HTTP 服务器第一次回发的报文数据应该是 html 文件。浏览器收到 html 文件之后,再根据 html 文件描述符的内容与服务器进行后续交互。后续服务端需要根据浏览器请求响应对应数据即可。

5.1 搭建HTTP服务器响应浏览器图片请求

  • html文件

1.bmp
  • http服务器

  服务器采用多线程方式处理客户端请求,http是属于短连接状态,每次连接只处理一个请求,当服务器返回本次请求的应答后便立即关闭连接,下次请求再重新建立连接。

#include 
#include           /* See NOTES */
#include 
#include 
#include  /* superset of previous */
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define HTTP_PORT 8080   //HTTP服务器端口号
/*
服务端响应客户端请求

"HTTP/1.1 200 OK\r\n"
"Content-type:image/jpeg\r\n"
"Content-Length:1234\r\n"
"\r\n"

形参:c_fd  --客户端套接字
      type  --文件类型
	  file  --要发送的文件
返回值:0成功,其它失败
*/
int Http_SendData(int c_fd,const char *type,const char *file)
{
	int fd=open(file,O_RDONLY);//打开文件
	if(fd<0)return -1;//打开文件失败
	struct stat statbuf;
	fstat(fd,&statbuf);
	if(statbuf.st_size<=0)
	{
		close(fd);
		return -2;
	}
	char buff[1024]={0};
	snprintf(buff,sizeof(buff),"HTTP/1.1 200 OK\r\n"
								"Content-type:%s\r\n"
								"Content-Length:%ld\r\n"
								"\r\n",type,statbuf.st_size);
	if(write(c_fd,buff,strlen(buff))!=strlen(buff))
	{
		close(fd);
		return -3;//发送数据头失败
	}
	/*发送文件内容*/
	int size;
	while(1)
	{
		size=read(fd,buff,sizeof(buff));
		if(write(c_fd,buff,size)!=size)break;//发送失败
		if(size!=sizeof(buff))break;//发送完成
	}
	close(fd);
	return 0;
}
/*线程工作函数*/
void *pth_work(void *arg)
{
	int c_fd=*(int *)arg;
	free(arg);
	char buff[1024]={0};
	int size;
	size=read(c_fd,buff,sizeof(buff)-1);
	if(size<=0)
	{
		close(c_fd);
		pthread_exit(NULL);
	}
	buff[size]='\0';
	printf("buff=%s\n",buff);
	if(strstr(buff,"GET / HTTP/1.1"))//请求网页文件
	{
		Http_SendData(c_fd,"text/html","./html/image.html");
	}
	else if(strstr(buff,"GET /1.bmp HTTP/1.1"))
	{
		Http_SendData(c_fd,"application/x-bmp","./html/1.bmp");
	}
	else if(strstr(buff,"GET /favicon.ico HTTP/1.1"))
	{
		Http_SendData(c_fd,"image/x-icon","./html/wmp.ico");
	}
	close(c_fd);
	pthread_exit(NULL);
}
int main()
{
	 int sockfd=socket(AF_INET,SOCK_STREAM,0);
	 if(sockfd==-1)
	 {
		 printf("创建网络套接字失败\n");
		 return 0;
	 }
	/*允许绑定已使用的端口号*/
	int on = 1;
	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
	/*绑定端口号*/
	struct sockaddr_in s_addr=
	{
		.sin_family=AF_INET,//IPV4
		.sin_port=htons(HTTP_PORT),
		.sin_addr.s_addr=INADDR_ANY
	};
	if(bind(sockfd,(const struct sockaddr *)&s_addr,sizeof(s_addr)))
	{
		printf("绑定端口号失败\n");
		return 0;
	}
	/*设置监听数量*/
	listen(sockfd,100);
	/*等待客户端连接*/
	struct sockaddr_in c_addr;
	socklen_t len=sizeof(c_addr);
	int c_fd;
	pthread_t pthid;
	int *p=NULL;
	while(1)
	{
		c_fd=accept(sockfd,(struct sockaddr *)&c_addr,&len);
		if(c_fd==-1)
		{
			printf("客户端连接失败\n");
			continue;
		}
		printf("%d连接成功,%s:%d\n",c_fd,inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port));
		p=malloc(4);
		*p=c_fd;
		pthread_create(&pthid,NULL,pth_work,p);
		pthread_detach(pthid);//设置为分离属性
	}
}
pYYBAGMOGAyARmEDAA53cfGwqMI658.png#pic_center

5.2 搭建HTTP服务器实现摄像头网页监控

  要实现网页摄像头监控,就是服务端采集摄像头数据,通过一帧一帧图片流方式响应客户端,因此客户端和服务器直接需要建立长连接,保持活动机制。

  • 长连接响应格式
//建立长连接格式
	"HTTP/1.0 200 OK\r\n"
	"Server: wbyq\r\n"
	"Content-Type:multipart/x-mixed-replace;boundary=boundarydonotcross\r\n"
	"\r\n"
	"--boundarydonotcross\r\n"
while(1)
{
	//(1)响应报文头
		"Content-type:image/jpeg\r\n"
		"Content-Length:666\r\n"
		"\r\n"
		write(“向浏览器发送报文头数据”);
	//(2)发送主体数据
		write(“向浏览器发送报图像主体数据”);
	//(3)发送间隔字符串
		"\r\n"
		"--boundarydonotcross\r\n"
		write(“间隔字符串数据”);
}
  • 服务端处理流程
poYBAGMOGA2ALK7HAAHe8T6Aujw636.png#pic_center
  • 摄像头图像采集参考:https://blog.csdn.net/weixin_44453694/article/details/126488841
  • 摄像头采集图像线程
       摄像头采集线程负责采集图像数据,当采集到一帧图像数据后通过广播唤醒所有的http客户端处理线程。
void *Camera_work(void *arg)
{
	int fd=video_info.video_fd;//摄摄像头描述符
	printf("摄像头采集线程,fd=%d\n",fd);
	struct v4l2_buffer v4l2buf;
	memset(&v4l2buf,0,sizeof(v4l2buf));//初始化结构体
	v4l2buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//视频捕获格式
	v4l2buf.memory=V4L2_MEMORY_MMAP;//内存映射
	int rgb_size=video_info.image_w*video_info.image_h*3;//rgb数据大小
	char *rgb_buffer=malloc(rgb_size);
	char *jpg_buffer=malloc(rgb_size);
	char *buff[]={rgb_buffer,jpg_buffer};
	int jpeg_buffer_size;
	pthread_cleanup_push(pth_clean,(void *)buff);
	while(1)
	{
		/*从采集队列中取出图像数据*/
		if(ioctl(fd,VIDIOC_DQBUF,&v4l2buf))break;//取数据失败
		//printf("v4l2buff[%d]=%p\n",v4l2buf.index,video_info.video_buff[v4l2buf.index]);
		//将yuv转换为rgb
		yuv_to_rgb(video_info.video_buff[v4l2buf.index],rgb_buffer,video_info.image_w,video_info.image_h);
		//将rgb数据转换为jpg数据格式
		jpeg_buffer_size=rgb_to_jpeg(video_info.image_w,video_info.image_h,rgb_size,rgb_buffer,jpg_buffer, 80); 
	
		/*将数据拷贝给其它线程*/
		pthread_mutex_lock(&mutex);
		jpg_size=jpeg_buffer_size;
		memcpy(jpeg_image_buffer,jpg_buffer,jpeg_buffer_size);
		pthread_cond_broadcast(&cond);//广播唤醒所有线程
		pthread_mutex_unlock(&mutex);

		/*将缓冲区添加回采集队列中*/
		if(ioctl(fd,VIDIOC_QBUF,&v4l2buf))break;//添加到采集队列失败
	}	
	pthread_cleanup_pop(1);
}
  • http客户端处理线程
      http客户端线程负责处理浏览器请求,当摄像头线程采集到一帧数据后,http客户端线程将数据下发给浏览器。
void *pth_work(void *arg)
{
	int c_fd=*(int *)arg;
	free(arg);
	char buff[1024]={0};
	int size;
	size=read(c_fd,buff,sizeof(buff)-1);
	if(size<=0)
	{
		close(c_fd);
		pthread_exit(NULL);
	}
	buff[size]='\0';
	printf("buff=%s\n",buff);
	if(strstr(buff,"GET / HTTP/1.1"))//请求网页文件
	{
		Http_SendData(c_fd,"text/html","./html/image.html");
	}
	else if(strstr(buff,"GET /1.jpg HTTP/1.1"))
	{
		Http_Content(c_fd);
	}
	else if(strstr(buff,"GET /favicon.ico HTTP/1.1"))
	{
		Http_SendData(c_fd,"image/x-icon","./html/wmp.ico");
	}
	close(c_fd);
	pthread_exit(NULL);
}
  • http建立长连接
      通过使用建立长连接的方式实现摄像头网页视频监控,以图片流的方式完成画面监控。
/*
HTTP长连接处理客户端请求
"HTTP/1.0 200 OK\r\n"
"Server: wbyq\r\n"
"Content-Type:multipart/x-mixed-replace;boundary=boundarydonotcross\r\n"
"\r\n"
"--boundarydonotcross\r\n"
*/
int Http_Content(int c_fd)
{
	char buff[1024]={0};
	/*建立长连接*/
	snprintf(buff,sizeof(buff),"HTTP/1.0 200 OK\r\n"
								"Server: wbyq\r\n"
								"Content-Type:multipart/x-mixed-replace;boundary=boundarydonotcross\r\n"
								"\r\n"
								"--boundarydonotcross\r\n");
	if(write(c_fd,buff,strlen(buff))!=strlen(buff))return -1;//发送报文头失败
	int jpe_image_size;//保存jpeg图像大小
	char *image_jpeg=malloc(video_info.image_w*video_info.image_h*3);//保存jpeg图像数据
	while(1)
	{
		/*
			(1)响应报文头
			"Content-type:image/jpeg\r\n"
			"Content-Length:666\r\n"
			"\r\n"
		*/
		pthread_mutex_lock(&mutex);//互斥锁上锁
		pthread_cond_wait(&cond,&mutex);//等待条件变量产生
		jpe_image_size=jpg_size;
		memcpy(image_jpeg,jpeg_image_buffer,jpe_image_size);
		pthread_mutex_unlock(&mutex);//互斥锁上锁
		snprintf(buff,sizeof(buff),	"Content-type:image/jpeg\r\n"
									"Content-Length:%d\r\n"
									"\r\n",jpe_image_size);
		if(write(c_fd,buff,strlen(buff))!=strlen(buff))
		{
			free(image_jpeg);//释放空间
			return -2;//响应报文头失败
		}
		/*发送jpg图像数据*/
		if(write(c_fd,image_jpeg,jpe_image_size)!=jpe_image_size)
		{
			free(image_jpeg);//释放空间
			return -3;//发送图像数据失败
		}
		/*
			(3)发送间隔字符串
			"\r\n"
			"--boundarydonotcross\r\n"
		*/
		strcpy(buff,"\r\n--boundarydonotcross\r\n");
		if(write(c_fd,buff,strlen(buff))!=strlen(buff))
		{
			free(image_jpeg);//释放空间
			break;//发送间隔符失败
		}		
	}	
	return -4;//发送图像数据失败
}
  • 运行效果
pYYBAGMOGA2ABsxxAAJjuk8OkfQ981.png#pic_center

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 视频监控
    +关注

    关注

    17

    文章

    1706

    浏览量

    64887
  • Linux
    +关注

    关注

    87

    文章

    11216

    浏览量

    208807
  • HTTP
    +关注

    关注

    0

    文章

    501

    浏览量

    31013
收藏 人收藏

    评论

    相关推荐

    基于ARM的视频监控系统的设计

    提出一种基于ARM 嵌入式开发平台视频监控的实现方案。通过V4L2 在Linux 构建视频图像采集和显示,然后使用servfox 和spc
    发表于 11-05 01:56 2875次阅读
    基于ARM的<b class='flag-5'>视频</b><b class='flag-5'>监控</b>系统的设计

    基于HTTP网页服务器和UDP上位机的MJPG码流传输

    本文采用的硬件板卡为飞凌嵌入式OKMX8MP-C开发板,系统版本Linux5.4.70+Qt5.15.0,主要介绍基于HTTP网页服务器和UDP上位机的MJPG码流传输。
    发表于 06-09 11:27 1737次阅读

    基于嵌入式Linux的网络视频监控系统研究

    基于嵌入式Linux的网络视频监控系统研究
    发表于 08-20 09:37

    【实战项目一:嵌入式视频监控系统】【初学必学】

    网页视频监控系统实战项目(驱动移植部分一)2.【创科之龙】嵌入式网页视频监控系统实战项目(驱动移
    发表于 07-19 18:18

    Linux组态,快速实现监控系统

    `基于紫金桥跨平台跨平台实时数据库,可Linux系统快速实现一个监控系统。1、组态流程和传统windows组态差不多,所以上手很快。2、不仅软件支持跨平台,工程也支持跨平台,windows
    发表于 12-23 15:46

    网页视频播放器代码

    网页视频播放器代码
    发表于 01-10 11:23 102次下载
    <b class='flag-5'>网页</b><b class='flag-5'>视频</b>播放器代码

    基于嵌入式Linux视频的网络监控系统设计

    基于嵌入式Linux视频的网络监控系统设计 摘要:介绍了一种采用Browser/Server结构、在视频服务器上内置一个嵌入式Web服务器、基于嵌入式
    发表于 10-13 14:39 715次阅读
    基于嵌入式<b class='flag-5'>Linux</b><b class='flag-5'>视频</b>的网络<b class='flag-5'>监控</b>系统设计

    FMC视频监控业务与技术

    简述FMC中与视频监控联系比较密切的几种技术,对FMC视频监控业务的发展趋势进行预测,并对FMC
    发表于 10-10 16:33 30次下载
    FMC<b class='flag-5'>下</b>的<b class='flag-5'>视频</b><b class='flag-5'>监控</b>业务与技术

    ARM_Linux实现无线视频监控系统

    ARM_Linux实现无线视频监控系统资料
    发表于 11-18 16:35 3次下载

    基于ARM和Linux的嵌入式远程视频监控系统的设计

    基于ARM和Linux的嵌入式远程视频监控系统的设计(嵌入式开发板如何刷程序)-本文根据大楼电梯视频监控系统的要求,提出了一种基于嵌入式技术
    发表于 07-30 12:56 7次下载
    基于ARM和<b class='flag-5'>Linux</b>的嵌入式远程<b class='flag-5'>视频</b><b class='flag-5'>监控</b>系统的设计

    基于嵌入式Linux视频监控系统毕业论文

    基于嵌入式Linux视频监控系统毕业论文(培训嵌入式开发软件)-基于嵌入式Linux视频监控系统
    发表于 07-30 13:46 28次下载
    基于嵌入式<b class='flag-5'>Linux</b><b class='flag-5'>视频</b><b class='flag-5'>监控</b>系统毕业论文

    基于HTTP网页服务器和UDP上位机的MJPG码流传输

    本文采用的硬件板卡为飞凌嵌入式OKMX8MP-C开发板,系统版本Linux5.4.70+Qt5.15.0,主要介绍基于HTTP网页服务器和UDP上位机的MJPG码流传输。
    发表于 01-23 12:05 759次阅读

    Linux编程_网页视频监控项目

    介绍LinuxHTTP服务器搭建,完成网页图片显示,网页视频显示。
    的头像 发表于 09-17 15:45 1116次阅读
    <b class='flag-5'>Linux</b>编程_<b class='flag-5'>网页</b><b class='flag-5'>视频</b><b class='flag-5'>监控</b>项目

    发烧友实测 | i.MX8MP 基于HTTP网页服务器和UDP上位机的MJPG码流传输(mjpg-steamer)

    作者|donatello1996来源|电子发烧友题图|飞凌嵌入式本文采用的硬件板卡为飞凌嵌入式OKMX8MP-C开发板,系统版本Linux5.4.70+Qt5.15.0,主要介绍基于HTTP网页
    的头像 发表于 01-10 16:30 924次阅读
    发烧友实测 | i.MX8MP 基于<b class='flag-5'>HTTP</b><b class='flag-5'>网页</b>服务器和UDP上位机的MJPG码流传输(mjpg-steamer)

    基于飞凌嵌入式OK113i网页视频监控项目

    通过OK113i飞凌嵌入式开发板,采用USB设备头,通过V4L2框架实现视频图像采集。创建摄像头图像采集线程,搭建HTTP服务器,固定端口号为8080,建立HTTP长连接,实现网页
    的头像 发表于 01-08 22:57 1029次阅读
    基于飞凌嵌入式OK113i<b class='flag-5'>网页</b><b class='flag-5'>视频</b><b class='flag-5'>监控</b>项目