本帖最后由 shanji 于 2019-4-27 09:03 编辑 " Z$ R# Z: @' F* J2 G9 H" `5 P
. q" |+ P6 g! O8 j2 X
https://www.stmcu.org.cn/module/forum/thread-609701-1-1.html
' S3 O4 G9 m/ ]4 l4 _距上次分享了个网络摄像头的示例也有一段时间了,用的裸TCP协议,这次来玩玩不同的花样,网页摄像头mjpeg-stream传输,用HTTP协议。网上搜了下,清一色的在Linux下实现的,在单片机上实现的还真没找到,为了玩起来,只能琢磨linux下的代码。, Z% O O* x6 u6 L% f3 j: Y1 ]
一、先把网页做出来
V( \! E. l# a* F) f 网页端的实现比较简单,用img标签,例:
+ R& C3 [9 p& H, X$ B2 A<html>
" D6 m/ A, A9 R- c <head>0 |5 U2 C/ o L% C4 |9 N8 z
</head>3 v' O: X3 T3 f' U
<body>5 r! C& w# k# f x7 ]# u
<img src="http://192.168.1.199:80/?stm32=mjpeg">,此处的ip指的是服务器的ip。
( Y& J: F% `# u </body>( Q# B1 A7 C3 [3 i5 z3 O
</html>1 M( s8 g Z3 W/ v0 X* p
二、 服务端的代码实现
0 [/ r4 k( w: k5 e1 f 要在网页上看到不断刷新的图片,服务端需要发送如下的相应包
e9 l& k* ~& g1 Y: } HTTP/1.1 200 OK\r\n
" w7 m4 w2 ?% [; l% f' k0 g
/ g- t4 Z' ?' ? 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 r. f8 m' d: a. v: c# A# H. U
- * @brief 开始发送流
6 D3 D& m- i4 Y, v - * @param client,count' ]# H( |& W+ C. R4 B f5 ?
- * @retval None
. l* O* N9 N' e - */
' ~$ O! X/ D) U/ H2 ^4 _ - HTTP_STA HTTP_Streamer_Start(int client,u8 count)
, `7 B3 A' V& Y9 H g: P8 b - {
$ h9 T) L/ y; N, x. O - int frame_size=0;
8 r/ y. y6 ?$ [. _ - uint16_t haed_len=0;
/ a( F5 |7 _/ b9 P# L - sprintf(buffer, "HTTP/1.1 200 OK\r\n"\
( F; Y' l+ L# r% x - "Connection: Keep-Alive\r\n"\3 l$ E, q8 w8 ?! K
- "Server: MJPG-Streamer/0.2\r\n"\
- z) r' }7 {7 A- F- k. u, L - "Cache-Control:no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n"\8 P5 S0 m8 u6 E, J
- "Pragma:no-cache\r\n"\
! E4 a3 N( g$ Z: x - "Expires:WED, 23 Jan 2019 01:00:00 GMT\r\n"\: s+ b* a0 w: G$ {
- "Content-Type: multipart/x-mixed-replace;boundary=openmcu\r\n\r\n"\
( V- w! O" S" n - "--openmcu\r\n");
" |2 @" u1 _ {# @2 t: b, A; ` - - o+ O% u. c: T3 U* F8 }) D
- haed_len=strlen(buffer); N' e9 R& j0 s% c
- //printf("\r\n%s\r\n",buffer);
5 A7 x1 a% @4 T) \5 f, M0 S( | - if(send(client, buffer,haed_len, 0)==-1)% {# Z: r! r7 ]* c' ?* F& x
- {
. C# h, Y) z6 R - return HTTP_FAIL;
+ c. Y; m8 `. M2 l! c. M/ ~0 ] - }
[3 ^5 @: T! J. ~! v - #if USE_CAMERA
) y& @+ F! u. I- k - frame_size=jpeg_data_len();
* k# C, E( J" ?1 p X' r - if(frame_size==0) return HTTP_FAIL;
1 X8 l( B6 L6 H - #else' h0 z+ Q! p/ t
- if(count==0)8 S0 C# h D9 t" `4 X2 _' Y
- frame_size=sizeof(cam_data);
: b4 ~! b f1 [( _4 N$ l+ {( G! \ - else if(count==1)
. d: I. k) a, s0 f9 n* M3 j% `8 W - frame_size=sizeof(cam_data2);
: f, R4 Q4 b" L7 v1 b; r$ M9 P - #endif # y, L; O0 q7 V
- haed_len=strlen(buffer);
* b5 c( b: D2 N& y; @1 \! z - 8 X$ Z; g. } u
- sprintf(buffer, "Content-Type: image/jpeg\r\n"\+ B: }) Z: d* R% f1 `! y, T
- "Content-Length: %d\r\n\r\n", frame_size);0 q* k4 X H0 o3 O& Y# ?
- printf("\r\n%s\r\n",buffer);5 g1 I f( j# }+ L3 [; v. R
- haed_len=strlen(buffer);
2 V$ U( I6 b& T. v1 q9 d& S - if(send(client, buffer,haed_len, 0)==-1)
4 ^7 B( }4 V" I* Q - {
! `0 Y3 N3 p! ~1 l& U9 ]8 h - return HTTP_FAIL;
% _$ [$ z' [4 k - }
; Q# f) x, p/ {! \ g - #if USE_CAMERA' r- G& U9 P' w0 a% e
- memcpy(&buffer[haed_len],(char*)ptr,frame_size);
+ x |/ a n. s0 Z; t$ P" {. W - #else* w8 {% c' S- x; H$ D
- if(count==0)5 i) R+ m2 L5 ~0 Y6 P' b
- memcpy(&buffer[haed_len],(char*)cam_data,frame_size);7 T9 S/ D: K6 h4 D1 f# L
- else if(count==1)
" \# J0 z9 o% e! \; {' d; H3 b5 N - memcpy(&buffer[haed_len],(char*)cam_data2,frame_size);9 r, t r* ^4 Z
- #endif
9 i4 q% k8 j$ V6 f - if(send(client, &buffer[haed_len],frame_size, 0)==-1)
9 v! z' O5 e# L( j - {
3 f! W( F3 t; t1 q8 v( t$ C - return HTTP_FAIL;
3 X* z/ `) g1 h9 @* l9 z - }
+ A$ j- q3 F: M, u& L2 I3 Y - #if USE_CAMERA! p" m& H9 I, t& S1 ]' j" _! e: L
- newframe=0; 0 {( V5 k0 ^0 L4 n: N
- cam_start();
, b- [: @6 r- k& H" o; t - #endif7 o+ P3 Z$ D( _/ S5 a
- //lwip_close(client);
7 n3 l B0 U+ x- z - return HTTP_OK;
, G+ l% t7 _' l' ~$ e; V7 y - }
复制代码
A e, e2 u6 F
发送完第一帧图片后,循环发送前面介绍的图片数据格式,就能看到摄像头的实时画面了。 & j: H( c7 s0 y; K) b' Z
测试源码 |
下次可以和楼主的整合一起
将视频实时显示在屏幕上,
https://www.stmcu.org.cn/module/forum/forum.php?mod=viewthread&tid=622494&page=1#pid2473242
感谢支持下( C: o7 ^9 z. f5 e6 J
关闭连接后发不出去了,需要重新等待客户端的连接。
那为什么send后面要close呢,这样之前的send数据也发不出去啊