本帖最后由 shanji 于 2019-4-27 09:03 编辑 % i' \( u$ Y6 j; S. O L1 s9 N
5 t( _) m& I; R. g Hhttps://www.stmcu.org.cn/module/forum/thread-609701-1-1.html% _; t3 ~+ }4 P
距上次分享了个网络摄像头的示例也有一段时间了,用的裸TCP协议,这次来玩玩不同的花样,网页摄像头mjpeg-stream传输,用HTTP协议。网上搜了下,清一色的在Linux下实现的,在单片机上实现的还真没找到,为了玩起来,只能琢磨linux下的代码。
& ]) o/ A& Q( ~ 一、先把网页做出来
* P. u/ i K& `- F6 R% Q( | 网页端的实现比较简单,用img标签,例:0 ?" Y$ x: Q6 ~
<html>) Z6 L) }( O( V
<head>
^9 V; C! g# x1 |3 j </head>
2 B) _9 @5 R4 h+ L _ <body>
9 F: s9 A5 ?' p: S8 {7 S- s <img src="http://192.168.1.199:80/?stm32=mjpeg">,此处的ip指的是服务器的ip。
; W' m9 K. N* y% m# Z2 f </body>/ m: d( o( C+ J* m3 D
</html> u% L" y% s+ _8 j' l4 t
二、 服务端的代码实现
' W7 F# V* n0 Q# \# l7 f, U8 a 要在网页上看到不断刷新的图片,服务端需要发送如下的相应包( p! O7 d q. f: i! A8 Q) p
HTTP/1.1 200 OK\r\n
3 P* G! d( e& w. Z4 t, \' V0 d$ z3 U7 B5 b# a/ 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编程。 - **
# [) D' c; U1 F b7 C. Y8 m# P/ I - * @brief 开始发送流
. i- p" n* j/ J( P, i# _ - * @param client,count
8 y( o+ w# W2 ~% `* m, \ - * @retval None( {( }# w5 y) V2 r6 D$ S
- */
* q( k( l. w5 n6 {4 a - HTTP_STA HTTP_Streamer_Start(int client,u8 count)
. v E: V* I7 h+ z( R - {
) l/ J: x' l1 S4 n- j, O+ R - int frame_size=0;) P1 g% O* A9 i1 ~0 f" Z
- uint16_t haed_len=0;
: l- H+ a2 H" b2 n - sprintf(buffer, "HTTP/1.1 200 OK\r\n"\: b9 U4 {# k+ d8 v
- "Connection: Keep-Alive\r\n"\$ Z u% v; N) v8 B! V8 P" A/ }
- "Server: MJPG-Streamer/0.2\r\n"\
. V0 D. v, b* n+ | - "Cache-Control:no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n"\
$ n- V5 Z0 y4 q. U - "Pragma:no-cache\r\n"\0 o* p8 a$ k# y) y
- "Expires:WED, 23 Jan 2019 01:00:00 GMT\r\n"\* \- ?! y. i) z4 a3 w* G
- "Content-Type: multipart/x-mixed-replace;boundary=openmcu\r\n\r\n"\0 T; ^9 i& _- S. |) `( X1 I+ T
- "--openmcu\r\n"); " g, Z- n0 c- c/ o- K1 U( K9 o
-
6 ?. A# c. V) w - haed_len=strlen(buffer);
5 D1 e, x% Q& }+ u9 I3 J* j/ c - //printf("\r\n%s\r\n",buffer);; d, \# x7 b. ]+ ] f- u3 h
- if(send(client, buffer,haed_len, 0)==-1)5 H" i. c, n5 x; A, P0 u8 C
- {
& j* [+ D. r8 e' i$ a; h7 v$ \ - return HTTP_FAIL;
1 x" E! s! y+ T - }
; K' Q: D: u: S- q) x2 s - #if USE_CAMERA
& H4 t: Y8 Y: }: L+ O# g - frame_size=jpeg_data_len();
; `8 |* Q. G) ^% G0 w - if(frame_size==0) return HTTP_FAIL;. P! `" u$ n' ^5 i. V
- #else
( u! e k- n/ Q3 g' y - if(count==0)6 R; t* k4 |4 b. L6 O( @0 m
- frame_size=sizeof(cam_data);
- O3 I5 @( [6 r) k0 G" \, Z1 N - else if(count==1)
% O5 z# J+ G4 h - frame_size=sizeof(cam_data2);9 ~. B, [/ {$ l# }
- #endif - H2 y8 E. p3 Y3 E
- haed_len=strlen(buffer);
3 r# z- P2 {" d/ t( j
- M8 d3 y/ T& |1 M8 ~ w- sprintf(buffer, "Content-Type: image/jpeg\r\n"\1 S. I3 f U9 l; m0 l
- "Content-Length: %d\r\n\r\n", frame_size);$ v5 R% M8 h+ k9 K
- printf("\r\n%s\r\n",buffer);
( w; g1 l# o9 o( ~" N6 X0 t2 x - haed_len=strlen(buffer);( w/ P1 z% f! I6 g; ?6 a' \5 e
- if(send(client, buffer,haed_len, 0)==-1): f) g! F8 U( s
- {
$ v! J; m+ H+ ^' t - return HTTP_FAIL;5 n% j9 O& P( Q+ O
- }
1 ]3 g" @2 }+ Y7 n- N2 S( e" h - #if USE_CAMERA+ f' P5 K; j6 |8 P2 v$ `
- memcpy(&buffer[haed_len],(char*)ptr,frame_size);
/ z0 ]% u* d. C - #else" J) @% M2 x- }( n5 t
- if(count==0)3 l% u' B8 b& @9 Q' T
- memcpy(&buffer[haed_len],(char*)cam_data,frame_size);! a/ x& W& O, u( J4 F q# I
- else if(count==1)
( y0 p* N: u* T7 ?, X1 B5 A - memcpy(&buffer[haed_len],(char*)cam_data2,frame_size);
7 p! c. U) s1 u: t6 D - #endif / c3 H" x/ ? c& G, p/ o& E
- if(send(client, &buffer[haed_len],frame_size, 0)==-1)! G5 r4 n. N, k
- {
2 j3 ]$ R) k3 n ^1 [# N& g. R& s - return HTTP_FAIL;
/ k: h ~; C4 C/ z0 g- ~ - }
. g/ I; v( O' K) Z0 ~' r9 Y$ m: Y - #if USE_CAMERA
* K4 A2 j& F; s" T% K9 j - newframe=0; 5 X+ V; v4 [/ C. j% X. Y4 b
- cam_start();
, y- ^" k6 a' z. F6 g8 D - #endif- _# r: n( y. e2 T0 e" [3 T) D
- //lwip_close(client); ) ?. P6 n: Z; `1 s
- return HTTP_OK;
+ s: _ v4 P& f - }
复制代码
, |/ d* G* d% R
发送完第一帧图片后,循环发送前面介绍的图片数据格式,就能看到摄像头的实时画面了。 # `/ M3 }- v6 e
测试源码 |
下次可以和楼主的整合一起$ [! q$ Z" M- H% w3 b# C
将视频实时显示在屏幕上,' _+ U6 m; c. `
https://www.stmcu.org.cn/module/forum/forum.php?mod=viewthread&tid=622494&page=1#pid2473242
感谢支持下
关闭连接后发不出去了,需要重新等待客户端的连接。
那为什么send后面要close呢,这样之前的send数据也发不出去啊