本帖最后由 shanji 于 2019-4-27 09:03 编辑
5 R3 v( I/ u7 G/ X
& t$ J7 d% a) ^, x* j7 ?) }1 @https://www.stmcu.org.cn/module/forum/thread-609701-1-1.html
9 b! [/ }% F1 `" F r# ~4 d- i距上次分享了个网络摄像头的示例也有一段时间了,用的裸TCP协议,这次来玩玩不同的花样,网页摄像头mjpeg-stream传输,用HTTP协议。网上搜了下,清一色的在Linux下实现的,在单片机上实现的还真没找到,为了玩起来,只能琢磨linux下的代码。' l$ ~- G- h% {% c. B
一、先把网页做出来
o! w3 C* H3 v4 e0 E 网页端的实现比较简单,用img标签,例:' r4 n! F$ W8 [% y
<html>9 h* N, @8 D& |$ C7 I# u
<head>/ P2 V+ P( o, x5 l* m& B" v
</head>
: ]* u4 y& d. F6 |0 v <body>
1 b' H( N8 _) o1 c" m <img src="http://192.168.1.199:80/?stm32=mjpeg">,此处的ip指的是服务器的ip。
- @# Z$ `1 s% u </body>
1 J) @( v; V1 C0 Q4 x* F: f; J</html># f8 K! }$ C( Z' L8 K2 F
二、 服务端的代码实现0 o2 b# j* V* y0 Q
要在网页上看到不断刷新的图片,服务端需要发送如下的相应包1 G9 O, i4 N, b' R' H( Q: j& E
HTTP/1.1 200 OK\r\n8 f) d. w0 Q" y7 k- ?, A
# f# p9 L; Y W* g; g 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编程。 - **7 t$ o8 ?2 h- h5 u9 ^* n+ P
- * @brief 开始发送流$ H$ r& Q) u6 I6 N( t
- * @param client,count2 \9 f! R U1 o) G. l- E* e
- * @retval None
% D0 U- a4 s7 u z4 I - */0 e5 b7 y' ^! S. H" `3 w+ z
- HTTP_STA HTTP_Streamer_Start(int client,u8 count)
1 d0 ?2 g: M3 e# F - {
; d: e0 i% [3 h" Z, j# C - int frame_size=0;, k2 g! G/ }3 g8 w8 h0 Q
- uint16_t haed_len=0;
/ d1 z9 w' ^; ~8 d! x - sprintf(buffer, "HTTP/1.1 200 OK\r\n"\
( ~. `, M: J6 T* P" V) v - "Connection: Keep-Alive\r\n"\
" e! O6 i1 P/ Q! F6 {2 d1 P - "Server: MJPG-Streamer/0.2\r\n"\
4 K# T, Z$ S7 `/ l3 q - "Cache-Control:no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n"\ i& t1 p9 w8 X7 K1 r6 L1 E3 M
- "Pragma:no-cache\r\n"\, M; C* i" g' e
- "Expires:WED, 23 Jan 2019 01:00:00 GMT\r\n"\: m: p1 ?4 d& i5 m! u
- "Content-Type: multipart/x-mixed-replace;boundary=openmcu\r\n\r\n"\5 u, R& C: J" X7 b/ q* q* I
- "--openmcu\r\n");
5 f3 q- b4 `* N ^6 Z7 ] -
* Z2 |8 Q* Z1 m h& I+ y - haed_len=strlen(buffer);' a' y: a; r+ S
- //printf("\r\n%s\r\n",buffer);+ {% s! d8 ~9 R
- if(send(client, buffer,haed_len, 0)==-1)
1 L. q" H- _( Q) q7 D - {
: n( l4 ~. E% c5 n. f: K - return HTTP_FAIL;
; k) x2 D, A. a# C8 O3 A - }
$ Z9 o! s% p! V t$ j0 J2 M - #if USE_CAMERA/ D! J I( K2 s; f, K9 D
- frame_size=jpeg_data_len(); % r: W8 `/ X: C
- if(frame_size==0) return HTTP_FAIL;2 l; u& x% w5 i0 D/ H+ c
- #else
4 f% J0 C2 p4 }" | - if(count==0)
2 T+ B* M' u* d5 Y3 Z - frame_size=sizeof(cam_data);
+ t# W. k1 f. g O' G8 o - else if(count==1)
6 N! o! n- E1 Z$ a6 G$ D6 c - frame_size=sizeof(cam_data2);- T6 i5 _' B' q
- #endif
; u2 @9 Q( V) _) A) _4 U - haed_len=strlen(buffer);
& U3 X5 b" |3 V* e - # O5 W. b% n( R# Q( P( t; S5 W N
- sprintf(buffer, "Content-Type: image/jpeg\r\n"\
' z6 o& }+ c: o, ?* e - "Content-Length: %d\r\n\r\n", frame_size);2 E9 G9 M6 g$ m6 Z
- printf("\r\n%s\r\n",buffer);
- o4 g* e9 {9 E. p' m - haed_len=strlen(buffer);6 R3 Q8 d* \ [9 @; w! K
- if(send(client, buffer,haed_len, 0)==-1)
0 w$ r2 m6 L0 Q - {
0 D* [; G% [% b; _ - return HTTP_FAIL;4 F0 ~( {8 Q% ~4 I+ |9 G8 P" l
- }
- ~& |4 ] V& T) l0 O - #if USE_CAMERA0 N( S& y8 T* g; q" |. L; k
- memcpy(&buffer[haed_len],(char*)ptr,frame_size);/ k: w' I6 c: a |, u9 c2 ^5 T" T' \
- #else" s% C2 A6 f7 y* o5 P
- if(count==0)
! ^. ?/ ^2 t3 X4 @# T% n - memcpy(&buffer[haed_len],(char*)cam_data,frame_size);8 g* I4 O Z* N5 e! y: b. X# ?
- else if(count==1)2 q2 L4 ]8 c* d% P4 O7 a
- memcpy(&buffer[haed_len],(char*)cam_data2,frame_size); C4 B t. Y* W& d
- #endif
7 T R0 F2 r. W) A I; v/ C - if(send(client, &buffer[haed_len],frame_size, 0)==-1)6 l$ f" e0 S; T3 U" x
- {
9 J3 w4 r: x' ~6 ] - return HTTP_FAIL;
7 Y$ t3 L- ^9 W- ~' i - }
( ^$ p S+ g6 {# V# \' X+ j7 B - #if USE_CAMERA+ N: O/ c. i+ X! Z: u2 R
- newframe=0;
7 U4 J6 h6 { S# `. d) \: d2 b) Z - cam_start(); + f: ^6 V, }8 Y E2 q; c' y- t
- #endif
9 s/ w( Q1 _ a% V1 k, M y - //lwip_close(client);
# B$ K2 z4 c8 n3 Z* V% l/ W - return HTTP_OK;, O8 Z& e# L/ o |( R" E. Q
- }
复制代码
; s' J0 D/ d* ? @" t
发送完第一帧图片后,循环发送前面介绍的图片数据格式,就能看到摄像头的实时画面了。 / O( s: [1 H7 O& f/ j% @& G* L
测试源码 |
下次可以和楼主的整合一起3 U% p( Z! H3 T
将视频实时显示在屏幕上,
https://www.stmcu.org.cn/module/forum/forum.php?mod=viewthread&tid=622494&page=1#pid2473242) T% m* g1 i) g3 Y$ ]6 ?6 L
感谢支持下
关闭连接后发不出去了,需要重新等待客户端的连接。
那为什么send后面要close呢,这样之前的send数据也发不出去啊