本帖最后由 shanji 于 2019-4-27 09:03 编辑
0 k) ^: M$ G0 A: u/ j1 [' b& ]* p9 r
https://www.stmcu.org.cn/module/forum/thread-609701-1-1.html/ K: n1 q0 D/ l4 G+ S( a! d8 w+ }
距上次分享了个网络摄像头的示例也有一段时间了,用的裸TCP协议,这次来玩玩不同的花样,网页摄像头mjpeg-stream传输,用HTTP协议。网上搜了下,清一色的在Linux下实现的,在单片机上实现的还真没找到,为了玩起来,只能琢磨linux下的代码。
6 D! `/ ~, \ u6 H 一、先把网页做出来
: D/ H- K+ L2 z& l4 ^( Y- s' D i 网页端的实现比较简单,用img标签,例:
; v2 m& C- }* O5 |# m<html>
5 b5 J j; L8 J+ M3 {) N <head>& }+ B0 |' B, t2 ?- L _5 ~
</head>1 V4 i; x" v4 C( b8 M
<body>
. V, a) O" D, d- i; n <img src="http://192.168.1.199:80/?stm32=mjpeg">,此处的ip指的是服务器的ip。% L( Y5 p$ M- m( C r! `
</body>& G: L+ ?4 p& w, O' Q
</html>
: w+ [# ]8 n# B+ A. u- c K 二、 服务端的代码实现7 f; c: n0 g W1 y+ j j" X
要在网页上看到不断刷新的图片,服务端需要发送如下的相应包9 I- L; E! K! e0 G
HTTP/1.1 200 OK\r\n
- l+ I! ^) Q! w$ N/ t
/ J O6 S M, s) W3 t! }& V 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编程。 - **! A7 o$ ?! H1 D+ p5 ?
- * @brief 开始发送流
/ E' o( @1 T5 ~4 j - * @param client,count0 ~6 ~! K. C6 s
- * @retval None
! k" p D1 ^' Y/ e! X: d - */
; M+ v4 P# m+ p0 T( m# d4 { - HTTP_STA HTTP_Streamer_Start(int client,u8 count)0 v2 x: ? [5 j. {
- { ( D# u4 ]& s$ O6 G% @4 @& K# L
- int frame_size=0;, z2 Y5 t) `! Y* P4 ?
- uint16_t haed_len=0;
7 v+ B5 M8 q1 w8 h7 D1 Z" i - sprintf(buffer, "HTTP/1.1 200 OK\r\n"\
, G3 Q( W; l- L - "Connection: Keep-Alive\r\n"\0 [" }! b3 X3 P) P5 J0 l3 @, r
- "Server: MJPG-Streamer/0.2\r\n"\
: ~, a) G4 D/ I p% m. i4 M - "Cache-Control:no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n"\
% m6 p* I: v* d- t: K& ] - "Pragma:no-cache\r\n"\4 y, I* ?6 Z3 `# R) R- _
- "Expires:WED, 23 Jan 2019 01:00:00 GMT\r\n"\- A. r. c. V& {
- "Content-Type: multipart/x-mixed-replace;boundary=openmcu\r\n\r\n"\5 c( t) u% n2 @. y) ~
- "--openmcu\r\n"); + w7 x$ W" A" u1 j# a
- 7 W+ a# y! M# `, @7 h
- haed_len=strlen(buffer);( W( p f% u1 b3 z- j
- //printf("\r\n%s\r\n",buffer);
# \) r7 Q: e+ ^8 P4 k: F - if(send(client, buffer,haed_len, 0)==-1)" u6 {0 B, Z" s) @6 h
- {
- j6 ?1 d2 y- e) ] - return HTTP_FAIL;
b- Q# r, _% u9 p - }, n W9 K2 N: M" m
- #if USE_CAMERA: T# L# c! C8 k8 N9 d& y+ x0 {0 U
- frame_size=jpeg_data_len(); 1 W4 q! q/ x( `3 g- c8 D% [
- if(frame_size==0) return HTTP_FAIL;
! @' D" E; z: z2 r* C0 Y$ s - #else
) v* @9 u5 h1 [ - if(count==0)' }8 C2 ^ ], c5 {4 F) p" w, B
- frame_size=sizeof(cam_data);" g6 D3 K7 {$ B; J4 s6 j
- else if(count==1)
: g% ]$ ~$ A( |$ [ - frame_size=sizeof(cam_data2);) }8 l' K7 C# [, ]4 s' ^& v
- #endif J; \3 O8 v/ ^
- haed_len=strlen(buffer);
6 x/ |6 U" d& d. e$ s- U6 t* M' g
. Q2 V: {( W, j/ u$ u- sprintf(buffer, "Content-Type: image/jpeg\r\n"\
$ @! q' \3 U1 n$ I( k - "Content-Length: %d\r\n\r\n", frame_size);
! V8 @# Y; ?& {" f' i1 g - printf("\r\n%s\r\n",buffer);
" `) @" @. @; r% O: q) a8 ] - haed_len=strlen(buffer);
3 l7 h: d, H" f" ]. n5 p - if(send(client, buffer,haed_len, 0)==-1)
- c" X7 h) ~ D" P! i3 P; G - {( ^# z3 E. X; d7 B3 i
- return HTTP_FAIL;
6 G( ^% z( l* F2 B1 q - }- ~! \. H$ C0 E/ S1 }
- #if USE_CAMERA: B2 u& A9 G$ S& t- ]% J% F; o8 v7 q
- memcpy(&buffer[haed_len],(char*)ptr,frame_size);- y9 p$ U: C' D+ E( Y: K" N% S2 l
- #else
L$ ]5 v# e9 L( L+ j0 X - if(count==0)
6 ?0 p+ O V+ {' A8 K U! T- ^ - memcpy(&buffer[haed_len],(char*)cam_data,frame_size);
i0 d- n% c3 ]% w$ s8 y5 W! c - else if(count==1)
1 t& r3 C0 a; W, o) G6 ?' X( F - memcpy(&buffer[haed_len],(char*)cam_data2,frame_size);0 z- V/ D! u6 ?
- #endif
, S2 S6 n/ R U! h* G - if(send(client, &buffer[haed_len],frame_size, 0)==-1). E8 p# v. p: E. R
- {! i4 P& @ z$ H" y! J5 d; x8 j2 n
- return HTTP_FAIL;
1 N1 D6 F* G/ O8 T! U - }
- q& [4 b6 O8 g b8 [/ b4 ~ - #if USE_CAMERA
5 T. F# A$ G% `' f8 \/ H# g - newframe=0;
5 }' x: z8 e2 ]! @3 T4 B - cam_start(); Q2 V6 S i% N# V+ r8 _
- #endif
3 ?% g# L1 p% F- S - //lwip_close(client);
2 v I8 k: G3 W; d- z - return HTTP_OK;& J- V+ I: a' q) C2 M) `
- }
复制代码
9 |: E) e* _; \5 n! E" I& T' R- r+ D
发送完第一帧图片后,循环发送前面介绍的图片数据格式,就能看到摄像头的实时画面了。 8 ?4 M( S" M* U: R1 X1 g
测试源码 |
下次可以和楼主的整合一起
将视频实时显示在屏幕上,
https://www.stmcu.org.cn/module/forum/forum.php?mod=viewthread&tid=622494&page=1#pid24732426 L/ i) `& f$ W6 d$ E, G- K e3 n
4 C, @) [& x7 ]# ]
感谢支持下
关闭连接后发不出去了,需要重新等待客户端的连接。
那为什么send后面要close呢,这样之前的send数据也发不出去啊