本帖最后由 shanji 于 2019-4-27 09:03 编辑
R) H) ?$ l# q: z( |; M+ K( u o0 U+ G& |, p
https://www.stmcu.org.cn/module/forum/thread-609701-1-1.html
* ~4 ~. M% B R# z" a0 w距上次分享了个网络摄像头的示例也有一段时间了,用的裸TCP协议,这次来玩玩不同的花样,网页摄像头mjpeg-stream传输,用HTTP协议。网上搜了下,清一色的在Linux下实现的,在单片机上实现的还真没找到,为了玩起来,只能琢磨linux下的代码。( `; Q* b; A8 a, a
一、先把网页做出来
' r0 y6 L9 P# d! |! R x* W 网页端的实现比较简单,用img标签,例:6 y, ^: I' }7 }: O4 b! T! I
<html>4 a8 X% G& ]0 S, ~
<head>2 G! F ~* |' z; a
</head>
% q6 p% E# S' n5 q- }5 ~1 v <body>) \2 \( H' R& \, X4 `1 P# ^
<img src="http://192.168.1.199:80/?stm32=mjpeg">,此处的ip指的是服务器的ip。/ n- m: f6 k9 A4 C) |# `" G& F( Z
</body>! {! g/ D U$ E
</html>
( V% ]/ L _$ w% z 二、 服务端的代码实现1 _/ I; U9 g$ b) O6 C- P5 l8 F
要在网页上看到不断刷新的图片,服务端需要发送如下的相应包8 y! D3 u6 K3 @$ b
HTTP/1.1 200 OK\r\n, J X) P9 g8 ^5 @ J2 b# ?7 d3 p
& i: T+ Z9 P; T1 L: [* S
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编程。 - **
- E1 f8 `! p% o: v' u# h t( e - * @brief 开始发送流* c' O- e6 G* B: X
- * @param client,count7 h1 D+ t% f f5 r. f* z
- * @retval None! b; F' a7 f; b- ^' y5 a3 F& P
- */
! P) R% Y) q% t% z% w - HTTP_STA HTTP_Streamer_Start(int client,u8 count)9 G2 f6 q9 f, v: W, j: _; X
- { : H" K+ n1 G% C5 c
- int frame_size=0;+ V# U; G! |$ w6 s3 h
- uint16_t haed_len=0;/ h. o6 o0 }! x$ E- @# u
- sprintf(buffer, "HTTP/1.1 200 OK\r\n"\0 _# r& B6 _8 H' q% y4 g! H
- "Connection: Keep-Alive\r\n"\$ ~# B6 ]. ?: v! Y
- "Server: MJPG-Streamer/0.2\r\n"\+ I" K6 K- y8 o
- "Cache-Control:no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n"\
- Q, V1 A/ p6 r, P% Z - "Pragma:no-cache\r\n"\& @' _) U$ r( O8 B' K& d9 ^
- "Expires:WED, 23 Jan 2019 01:00:00 GMT\r\n"\
4 {1 q# B4 ?3 V - "Content-Type: multipart/x-mixed-replace;boundary=openmcu\r\n\r\n"\7 o/ Q3 I7 g, h+ l/ y, Y
- "--openmcu\r\n");
; \1 @0 b4 Y) o2 S" [/ O9 ]) o - 0 E& S9 y+ n6 N% P( u$ x. y, G
- haed_len=strlen(buffer);
: F' y- p" p. Z2 {* m - //printf("\r\n%s\r\n",buffer);7 o7 f% ?1 l: n* `2 ~/ k% A. D
- if(send(client, buffer,haed_len, 0)==-1)( A z2 h$ b+ y
- {) Z- Z1 L- [) } d) `; ?
- return HTTP_FAIL;) i3 z) H; R6 I
- }, ~& _. x2 P3 Z% e; `- d
- #if USE_CAMERA* [# g' \8 }. y) ~( X6 ^5 J
- frame_size=jpeg_data_len();
( }& y% s. ]2 z4 h9 ?& V4 I - if(frame_size==0) return HTTP_FAIL;% S: G: Z: d& L E3 @7 O( G
- #else
1 i' Q4 ^& L1 @& M - if(count==0)- t' B2 ?7 l6 j
- frame_size=sizeof(cam_data);
B# h8 K5 d: Q - else if(count==1)8 U7 l2 {2 b2 t: a
- frame_size=sizeof(cam_data2);
) [0 y( }# S. ~. A' _ - #endif G+ k3 b. l, l
- haed_len=strlen(buffer);; s; p, ?& x9 e, W ] n
- , Z% x8 S# j. X; c9 L4 \- B x2 R
- sprintf(buffer, "Content-Type: image/jpeg\r\n"\" D$ N l' s( A. X
- "Content-Length: %d\r\n\r\n", frame_size);& T* m$ \! |6 S @5 k
- printf("\r\n%s\r\n",buffer);( p4 h+ J: E4 Y1 Q1 m0 t
- haed_len=strlen(buffer);3 f1 o* l9 O! D( t6 C
- if(send(client, buffer,haed_len, 0)==-1)
1 D8 z3 I; [0 C) I: }0 w7 k" n - {
+ W) E) t! G/ L, K: h2 j4 l5 }5 { - return HTTP_FAIL;& N6 G- s% x2 F. h7 {
- }
$ q, Z5 C0 t ~2 G3 S - #if USE_CAMERA
2 Y( E3 ]1 v t3 h$ _ - memcpy(&buffer[haed_len],(char*)ptr,frame_size);
' Z* a) }3 F: d/ H7 U# T: M5 b6 g - #else
' q5 c8 {7 L+ D- x( p/ ] @+ | - if(count==0)
* u: {: O/ [' Z+ T( o - memcpy(&buffer[haed_len],(char*)cam_data,frame_size);1 P/ C9 c+ a, h# p
- else if(count==1)1 z$ C( _# ^" X! L& m
- memcpy(&buffer[haed_len],(char*)cam_data2,frame_size);) Q, |. }, I4 \. X" Q$ @5 J
- #endif
) b5 e& ]+ r' Y |3 g - if(send(client, &buffer[haed_len],frame_size, 0)==-1)5 W6 l5 X4 C+ U o$ j
- {
8 l& `6 H2 Q3 ?6 o* e - return HTTP_FAIL; c; @: X) U, c
- }( J0 c: ~, T! Z4 G, ^
- #if USE_CAMERA
* f. W0 @' B3 F$ b! u; r5 z - newframe=0; " Y' d. x2 N7 [( k) I
- cam_start();
# m4 f& p" r: `$ o% Z - #endif
( o4 c+ q7 I, Y D" ? - //lwip_close(client);
/ w4 M! M6 l; N- J& p! d! J; g" B8 q$ ] - return HTTP_OK;
9 a4 d% e' ^$ o - }
复制代码1 v4 A; X4 x' V# i, p
发送完第一帧图片后,循环发送前面介绍的图片数据格式,就能看到摄像头的实时画面了。 ( `9 U' D |8 G1 `- R
测试源码 |
下次可以和楼主的整合一起
将视频实时显示在屏幕上,. e P1 x- d2 w7 k; H& I/ z# p
https://www.stmcu.org.cn/module/forum/forum.php?mod=viewthread&tid=622494&page=1#pid2473242
感谢支持下
关闭连接后发不出去了,需要重新等待客户端的连接。
那为什么send后面要close呢,这样之前的send数据也发不出去啊