本帖最后由 shanji 于 2019-4-27 09:03 编辑 8 r8 n+ N! b: X( L* h
1 q) |) P7 z- p/ G' Y# f+ m' Hhttps://www.stmcu.org.cn/module/forum/thread-609701-1-1.html
3 `& O" I* X% F4 [+ ]距上次分享了个网络摄像头的示例也有一段时间了,用的裸TCP协议,这次来玩玩不同的花样,网页摄像头mjpeg-stream传输,用HTTP协议。网上搜了下,清一色的在Linux下实现的,在单片机上实现的还真没找到,为了玩起来,只能琢磨linux下的代码。
& w: G7 J( C3 r" P( i9 ?) q! I7 ~0 _ 一、先把网页做出来
, P1 M* z1 W0 w. o- b. @ 网页端的实现比较简单,用img标签,例:
' K: \* _, G, N3 q# c$ w8 y<html> c& p; k I; A. a- y o
<head>
" Y1 g0 V6 I3 w- B$ f" q) m6 @ </head>& }& @, U, J7 N! F
<body>3 C ~5 e, f2 J, |5 u+ y" f
<img src="http://192.168.1.199:80/?stm32=mjpeg">,此处的ip指的是服务器的ip。
4 M: s- B' H9 j. l a# W </body>
7 w# T$ q3 T9 ^: J% M</html>0 p2 |+ r( V$ m- [6 O' K. C" G5 s
二、 服务端的代码实现
, [9 |: S3 ?. ^ 要在网页上看到不断刷新的图片,服务端需要发送如下的相应包1 K) Y6 h$ o5 q3 f
HTTP/1.1 200 OK\r\n
! a8 _1 B, B" S' x8 h6 ~1 K
) p) K, }7 k, k 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编程。 - **2 ?7 ~0 \9 c; n
- * @brief 开始发送流
- L) p; {8 u2 ^4 `9 S- e# Y4 F/ ? - * @param client,count# _% X3 p6 B- @: ~9 {7 Z, T
- * @retval None
/ p, Z! j5 c: N" {* ^; ?: ] - */2 o, @ _- j/ ~" e
- HTTP_STA HTTP_Streamer_Start(int client,u8 count)7 D" ]7 t+ D# X2 Y6 a
- { 4 U, u& s* ]0 h" w2 ~2 `: ]) ]) F# y
- int frame_size=0;
+ q' e4 N3 x+ s `" q - uint16_t haed_len=0;
7 x/ M4 Z- ~. Y- W9 X k - sprintf(buffer, "HTTP/1.1 200 OK\r\n"\' e/ J& y J) z4 Z1 _: f0 M) O
- "Connection: Keep-Alive\r\n"\
* Z% c% `) A: |" O& f M - "Server: MJPG-Streamer/0.2\r\n"\
m* G! O4 |: n1 p' } - "Cache-Control:no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n"\0 T' W* T% x D+ n
- "Pragma:no-cache\r\n"\8 @) E: o( m0 ~! e1 T1 t
- "Expires:WED, 23 Jan 2019 01:00:00 GMT\r\n"\
# U2 ^2 t8 R- O7 Q- }6 s2 T D - "Content-Type: multipart/x-mixed-replace;boundary=openmcu\r\n\r\n"\
; P, X6 l t/ |" ~; u% s - "--openmcu\r\n");
. M8 t; L; h5 s -
2 m& _; @6 L; f2 F' m6 Y - haed_len=strlen(buffer);% S# v, w1 Z' `* G; c4 f' m) L
- //printf("\r\n%s\r\n",buffer);' g6 W7 D+ h- L! b
- if(send(client, buffer,haed_len, 0)==-1)
$ f4 z1 w3 v0 k - {
% K2 v1 L# L7 G, u3 {: F i - return HTTP_FAIL;. {0 G- i; f+ F
- }. S9 b( z6 Z/ ~* w& K/ R; p( }& z. F. h2 c
- #if USE_CAMERA
& n7 S. `- X V0 C - frame_size=jpeg_data_len();
1 H. t. P5 G3 m- C- v! k$ T - if(frame_size==0) return HTTP_FAIL;* ~0 j- t# m+ S- S# l$ _
- #else
" X$ R- g1 Q5 L c' L }, T4 n0 N$ i - if(count==0)" m( l3 m1 C, c) h
- frame_size=sizeof(cam_data);
/ d2 Y8 [; G( ^8 o - else if(count==1)5 r3 S/ b0 t8 A O8 ]
- frame_size=sizeof(cam_data2);. k, `; Z' S6 L. u Q4 `; U
- #endif 6 H/ L u* q- x$ U4 ~5 \
- haed_len=strlen(buffer);
% P$ z+ P/ ~* p( S/ x5 H
" A" M& a4 R' C% t1 z- sprintf(buffer, "Content-Type: image/jpeg\r\n"\" d' Z: Z H6 k
- "Content-Length: %d\r\n\r\n", frame_size);, g6 z+ t0 J5 X
- printf("\r\n%s\r\n",buffer);
2 u' n- A! t/ ?( L h# H. d6 J4 r - haed_len=strlen(buffer);# `3 J* y5 { Q G: ^5 [7 t
- if(send(client, buffer,haed_len, 0)==-1) L* M/ F/ n/ ?+ j3 W9 F8 A
- {8 W* d& j. [! ]% B4 ~
- return HTTP_FAIL;3 P) h* [6 y5 [ d* S) P/ N9 P+ t
- }
5 |' O, {. h% t7 C' r1 z0 x* ?+ k" n: V - #if USE_CAMERA
! b X% {$ ?4 M2 H - memcpy(&buffer[haed_len],(char*)ptr,frame_size);
" W& ?5 N, J3 s - #else
, {5 x9 \2 C j6 j* c! T0 e - if(count==0)
4 O/ k3 ]5 Z, g: o _% T$ N: ? - memcpy(&buffer[haed_len],(char*)cam_data,frame_size);
6 O9 J8 s! r+ i- v) `! l - else if(count==1)
( ~5 r, O3 l! q; \- [5 L% F - memcpy(&buffer[haed_len],(char*)cam_data2,frame_size);/ Y5 |: ?, p9 p9 {' p
- #endif
7 i% K' S1 Z9 \* ?8 j3 J$ F0 B# n - if(send(client, &buffer[haed_len],frame_size, 0)==-1)
- u, H) w; d4 N2 l+ U2 ~) u - {
* S$ l6 h" `0 V( h8 V# W0 a - return HTTP_FAIL;
+ H7 {) h( ]- T2 |* \ - }
' [/ I' y, z. B - #if USE_CAMERA
/ X7 }7 R2 h$ Z T: U - newframe=0;
; p6 T/ b( N+ }+ f' G4 k - cam_start();
" e9 E- a' x( U, Q' q( H - #endif( O+ V" A5 i+ c7 r5 l A: J1 s
- //lwip_close(client); / d, O# |! N" @- D6 r+ m
- return HTTP_OK;
3 N2 T! n0 o1 R! D. w- n7 c5 \0 N - }
复制代码( @; H" ~ K. ~: J8 _+ W7 [
发送完第一帧图片后,循环发送前面介绍的图片数据格式,就能看到摄像头的实时画面了。
$ c: e/ P! O! o! T) ?% @; { W$ l测试源码 |
下次可以和楼主的整合一起7 t* s( ]$ w1 c. s
将视频实时显示在屏幕上,
https://www.stmcu.org.cn/module/forum/forum.php?mod=viewthread&tid=622494&page=1#pid2473242
1 V" {' e$ I( `- |
感谢支持下; ]9 i- g- E" `) W: {/ j
关闭连接后发不出去了,需要重新等待客户端的连接。
那为什么send后面要close呢,这样之前的send数据也发不出去啊