本帖最后由 shanji 于 2019-4-27 09:03 编辑
/ Q' @4 m* ~& S0 [, ?# Y) Q
1 M, ~ b4 ~( @1 A9 k1 ?https://www.stmcu.org.cn/module/forum/thread-609701-1-1.html% k! U( d2 N6 }$ n
距上次分享了个网络摄像头的示例也有一段时间了,用的裸TCP协议,这次来玩玩不同的花样,网页摄像头mjpeg-stream传输,用HTTP协议。网上搜了下,清一色的在Linux下实现的,在单片机上实现的还真没找到,为了玩起来,只能琢磨linux下的代码。2 S% t& L0 j3 d3 Q
一、先把网页做出来
* l# x: E. ^' W) q: U5 A 网页端的实现比较简单,用img标签,例:
" b/ N/ S! M) T; A3 L<html>
( T; S& [% Z3 H4 f) c$ p/ d <head>2 t; ~& v9 l1 \4 g) t
</head>
2 c/ p' d- F E; I) B, Z1 J <body>, C' {( V& _4 ~ k( y; o& T
<img src="http://192.168.1.199:80/?stm32=mjpeg">,此处的ip指的是服务器的ip。/ G+ _, d- {) l) D! q' @
</body>( b$ m( A* |7 l7 j1 Z
</html>! }; R0 P( B! ?, |5 }; d
二、 服务端的代码实现; n9 q, O0 a }: ~5 R
要在网页上看到不断刷新的图片,服务端需要发送如下的相应包
h6 X7 p5 @) P& k T1 U HTTP/1.1 200 OK\r\n
) z! x* N$ c ^9 d1 e, q) y2 ], C
Content-Type: multipart/x-mixed-replace;boundary=xxxxxxxx\r\n\r\n //boundary后面的字段可自行定义 关于multipart/x-mixed-replace和boundary网上有很多专业解释,我就不copy了,知道怎么用它就对了。 要发送图片时的数据包格式是 --xxxxxxxx\r\n Content-Type: img/jpeg\r\n Content-Length: 2048\r\n\r\n //此帧图片的大小 循环发送这样的数据包给网页,网页上就能看到不断刷新的画面了 有了上面的基础,就可以开始码代码。 关键代码: 程序中使用了RT-Therad RTOS,用socket编程。 - **+ e+ N5 W& M3 `( i1 U3 n
- * @brief 开始发送流# s; v- N- H- t8 C l5 O
- * @param client,count
7 n/ ]( o6 q0 q$ O - * @retval None
) H ]! d( D$ L3 [& k% F - */# M# N6 L! c- O# h' z/ G1 F1 R
- HTTP_STA HTTP_Streamer_Start(int client,u8 count)
5 U$ N# z) F9 j- |6 r, u' `) P { - {
1 A* Q# j6 Z- S, i; B: ? - int frame_size=0;) Z6 u1 f1 |. x) l' e+ z
- uint16_t haed_len=0;
5 Y/ G3 @) i* Q. i1 r; D* f. ^ - sprintf(buffer, "HTTP/1.1 200 OK\r\n"\
6 @& e" r: @5 U3 f9 u - "Connection: Keep-Alive\r\n"\
5 [) o% L& O8 z& o, x - "Server: MJPG-Streamer/0.2\r\n"\5 E( ?6 w/ W, z8 x
- "Cache-Control:no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n"\
* E( t. z: _4 o' {7 j) G - "Pragma:no-cache\r\n"\% `/ a/ j3 X( ?
- "Expires:WED, 23 Jan 2019 01:00:00 GMT\r\n"\
4 T8 Q& O) I& h+ K - "Content-Type: multipart/x-mixed-replace;boundary=openmcu\r\n\r\n"\& Q" I% G! Z4 d( `/ T+ Q
- "--openmcu\r\n");
; { k: N0 E% m -
! B, U" ?) Y: n' \6 y8 A) Z" x - haed_len=strlen(buffer);
, {7 T9 a& R6 Y - //printf("\r\n%s\r\n",buffer);
; W" w7 p3 W2 T; Z9 R0 [ - if(send(client, buffer,haed_len, 0)==-1)
, h4 ]0 ?1 @* r, n# } - {
, w7 B! V! X3 t, o. V - return HTTP_FAIL;$ I8 ]2 G1 @; G& s& v
- }
' \5 n$ l) R4 y6 \: l - #if USE_CAMERA/ n% M7 g5 s! X+ ]0 b
- frame_size=jpeg_data_len();
6 j3 u0 X! d4 C; V5 M$ g2 x" V; } - if(frame_size==0) return HTTP_FAIL;
0 k. ]" \( p) s6 j/ b - #else# Y3 k- u4 _( F$ O! h
- if(count==0)
) \) q4 |. |: K: ?8 G3 [* n& Q - frame_size=sizeof(cam_data);
2 o7 M! V& V: G$ K5 } - else if(count==1)7 g: a1 O/ [4 x, ^! t' V- O+ g# b
- frame_size=sizeof(cam_data2);
/ n% M0 E8 l/ y/ M2 V - #endif 3 \( \( ~9 ~/ u( b2 Z
- haed_len=strlen(buffer);
' \8 z/ T" W9 @) }- Q2 \. p, b
& X3 k4 f0 [ v; S! E/ B- sprintf(buffer, "Content-Type: image/jpeg\r\n"\
* g% S+ ? m2 M/ U* _2 T" {6 z - "Content-Length: %d\r\n\r\n", frame_size);% V& p" z- b+ ^4 z' T5 R
- printf("\r\n%s\r\n",buffer);
& Y$ ]. F" P: R" x# e - haed_len=strlen(buffer);7 n; B4 J" \# `2 r# X0 h6 f
- if(send(client, buffer,haed_len, 0)==-1)
% m+ b' Y4 A5 M- F* k8 A0 U - {
& C% U9 y8 q7 v; v8 E( c - return HTTP_FAIL;
- F K. c4 D3 U9 C3 h - }
3 _: U% `9 }! K5 @$ a - #if USE_CAMERA2 F# [0 m6 I4 D: c' S# [0 A* I" s
- memcpy(&buffer[haed_len],(char*)ptr,frame_size);
4 Q2 @1 r `% i5 G6 T - #else2 y- B# n% n @1 f
- if(count==0)
u& j0 s7 _6 e: R5 S* L - memcpy(&buffer[haed_len],(char*)cam_data,frame_size);& i7 I4 z4 e: m0 _; a" H* |/ |# w
- else if(count==1)7 x7 L1 l6 Z: e" O
- memcpy(&buffer[haed_len],(char*)cam_data2,frame_size);$ d% J$ w, T5 b6 X" W! T z
- #endif ! a0 N* Q$ f2 S3 {6 H
- if(send(client, &buffer[haed_len],frame_size, 0)==-1); c/ U9 ?& S" p1 m& b5 y) L
- {) G5 `, `$ O$ N8 f8 f& }: @# [' J
- return HTTP_FAIL; c! S" l! d( C& d$ D
- }
9 U2 d8 s( X" x( J' _) Z+ h: h% H - #if USE_CAMERA
( ?# o0 o. q! ~4 l' b2 e - newframe=0;
- f6 W6 O9 u v1 J& N4 ]& u" I g - cam_start();
, T4 i/ z7 a. T7 h - #endif3 }0 Z( o0 I* t# N9 Q
- //lwip_close(client);
( ?$ L+ b) V& v. v6 l, ] - return HTTP_OK; m/ q& H5 Q# C$ t5 U% I7 g' |
- }
复制代码
1 y- t( P! T( e b- |( O) m# O
发送完第一帧图片后,循环发送前面介绍的图片数据格式,就能看到摄像头的实时画面了。
% e+ M! [+ X+ a3 L! W测试源码 |
下次可以和楼主的整合一起
将视频实时显示在屏幕上,
https://www.stmcu.org.cn/module/forum/forum.php?mod=viewthread&tid=622494&page=1#pid24732422 L: a/ F" E5 f9 x4 X
感谢支持下, N4 T3 n# d$ ^% N
关闭连接后发不出去了,需要重新等待客户端的连接。
那为什么send后面要close呢,这样之前的send数据也发不出去啊