本帖最后由 shanji 于 2019-4-27 09:03 编辑
' f1 X2 t9 r+ N/ x' T, N
" S# H& i6 p+ g# G* U4 hhttps://www.stmcu.org.cn/module/forum/thread-609701-1-1.html
! m9 j) |( Y+ k" _3 }距上次分享了个网络摄像头的示例也有一段时间了,用的裸TCP协议,这次来玩玩不同的花样,网页摄像头mjpeg-stream传输,用HTTP协议。网上搜了下,清一色的在Linux下实现的,在单片机上实现的还真没找到,为了玩起来,只能琢磨linux下的代码。
$ i/ ^' G7 Y8 I% l+ U( I/ E 一、先把网页做出来/ h' }0 g9 M! z- a; w X4 p
网页端的实现比较简单,用img标签,例:% m% i$ }; @; z0 e0 g4 H8 t
<html>$ i0 u- j- g/ Q$ W2 T6 g% @
<head>
7 z/ p& ~ Q% b </head>
5 C/ n3 r6 `& p/ m9 V% I' [ <body>
. A% b8 f6 n$ K; G+ N- _( G <img src="http://192.168.1.199:80/?stm32=mjpeg">,此处的ip指的是服务器的ip。
: E3 e5 d. _4 V6 x( q& ?2 H: d </body>
) ~ f! W9 }, l" V, l. B; ^</html>$ ?( n: L; [3 Q
二、 服务端的代码实现
; U3 \0 l/ T8 n" n- A# p; F 要在网页上看到不断刷新的图片,服务端需要发送如下的相应包* i& S8 J' }, }1 Y* u
HTTP/1.1 200 OK\r\n2 S/ C# r% `' `: H7 r- B6 e6 V! V
/ e& o. @7 W* ^! u1 b
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编程。 - **
/ c: ?; v0 V) e: v$ {* m3 F- I& k' x - * @brief 开始发送流' R! a6 ?5 v& \6 e3 l
- * @param client,count
+ `8 I5 a4 u1 n - * @retval None, [( T9 i3 J. z, r* [
- */' v$ B, |* G5 E9 @( A! I6 q+ P
- HTTP_STA HTTP_Streamer_Start(int client,u8 count)5 a1 d: t: X1 R* [2 I$ s
- { " k f- Z# ]& S4 ]
- int frame_size=0;
b: M9 w I& C, G - uint16_t haed_len=0;
0 p" T! Z0 o3 Q* ^6 ~. Y - sprintf(buffer, "HTTP/1.1 200 OK\r\n"\
+ x3 @8 a9 T6 R9 ]9 v0 H* H+ I8 O - "Connection: Keep-Alive\r\n"\
9 A' ~9 |& d4 b - "Server: MJPG-Streamer/0.2\r\n"\
% ~) J# I$ X% ~( G4 P9 |3 f0 J0 D - "Cache-Control:no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n"\
7 T1 T M1 `! I0 w9 f$ @ - "Pragma:no-cache\r\n"\
5 ^- n& F8 }! f8 @4 v - "Expires:WED, 23 Jan 2019 01:00:00 GMT\r\n"\: \! _5 r7 y1 Z
- "Content-Type: multipart/x-mixed-replace;boundary=openmcu\r\n\r\n"\3 }+ W' p7 a; Q" b/ a" p4 }1 x
- "--openmcu\r\n"); 5 T- _! I c) s
- " s! K# W) t$ q* X7 i4 {
- haed_len=strlen(buffer);
! a) A. |7 ~4 E( _ - //printf("\r\n%s\r\n",buffer);* k5 R- i. D# h4 V. Z8 W% C* i
- if(send(client, buffer,haed_len, 0)==-1)6 g5 D, ~; n, w
- {7 A0 r6 z( p8 F1 s
- return HTTP_FAIL;
! [ @0 F4 K5 q. {5 _2 C! H- _ - }
0 ^2 q5 \. O8 W6 e) @2 r7 } - #if USE_CAMERA' T% F- N9 R. _9 X
- frame_size=jpeg_data_len();
0 y/ P E8 q0 W$ l! n0 Q - if(frame_size==0) return HTTP_FAIL;
1 {: R, l5 }) t1 g - #else
, I+ C& S, R9 V" C6 A - if(count==0)" R9 A' {5 D9 d7 c# i; z) R7 C5 e
- frame_size=sizeof(cam_data);% ]/ t1 q4 D: i6 g8 N$ d+ u8 e
- else if(count==1)
c }, Y' t7 Z" Z - frame_size=sizeof(cam_data2);
$ H7 z5 ~9 o6 \/ e! }6 q$ r/ z - #endif 3 v9 C$ G8 m0 Q# b
- haed_len=strlen(buffer);7 O& S+ b" o/ G g
/ ~) x/ W# e2 @; D- sprintf(buffer, "Content-Type: image/jpeg\r\n"\7 o! { C+ c. T' E8 z5 e
- "Content-Length: %d\r\n\r\n", frame_size);
. D% P! Y# g4 h( I6 h - printf("\r\n%s\r\n",buffer);
; n! b: C7 G: I0 f - haed_len=strlen(buffer);
- L1 F. j8 m% Q5 J" Y - if(send(client, buffer,haed_len, 0)==-1)
4 l& W" m o4 z( |+ ^/ {% D w - {9 }8 e; T! k+ k( Q7 A/ O
- return HTTP_FAIL;% ]% ?: D3 f# o9 _* m
- }
" P' t! f. s# e+ j - #if USE_CAMERA
. k! P3 Y+ n2 C! R; [ - memcpy(&buffer[haed_len],(char*)ptr,frame_size);. y( v9 q. x! {" y
- #else" Z, \0 Z% C m d: s
- if(count==0)& }- A# r* B: h% ] i9 A. E
- memcpy(&buffer[haed_len],(char*)cam_data,frame_size);
( e# v& [) A8 x9 |6 { - else if(count==1)
* \% T& z! |$ e. m4 }) w3 y8 d - memcpy(&buffer[haed_len],(char*)cam_data2,frame_size);
$ {; j$ }5 a. T3 V& m* z - #endif
3 ^2 F8 W+ F) } X* c, [6 i - if(send(client, &buffer[haed_len],frame_size, 0)==-1)
% N# R4 Z4 `4 A5 t' r0 `8 A$ V# ] - {
% k! T/ c) A y - return HTTP_FAIL;2 v& J; d! l* @
- }
- h6 M- R: V4 M; n3 a - #if USE_CAMERA
6 L, ?$ B! M/ S/ n+ O- w - newframe=0; ; y( ~6 e& z Q# @' ~. \% }$ J/ k2 @. F1 R
- cam_start();
- D I( l. D8 M. _+ u3 A# g - #endif
& g9 G" X! V5 {+ K - //lwip_close(client); : r6 z8 v5 s1 ~; D) M4 i8 U( X
- return HTTP_OK;
2 b7 a$ u/ Q' c& z1 l3 { - }
复制代码+ ?7 z) y8 R w8 K' [
发送完第一帧图片后,循环发送前面介绍的图片数据格式,就能看到摄像头的实时画面了。
( M a& L% y i6 W8 m1 V# j测试源码 |
下次可以和楼主的整合一起
将视频实时显示在屏幕上,
https://www.stmcu.org.cn/module/forum/forum.php?mod=viewthread&tid=622494&page=1#pid2473242
- e: [" g7 {/ i5 E+ M# t6 q
感谢支持下
关闭连接后发不出去了,需要重新等待客户端的连接。
那为什么send后面要close呢,这样之前的send数据也发不出去啊