1+ /*
2+ * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
3+ *
4+ * SPDX-License-Identifier: MIT
5+ */
6+
7+ #include " M5AtomS3.h"
8+ #include " camera_pins.h"
9+ #include < WiFi.h>
10+ #include " esp_camera.h"
11+
12+ #define STA_MODE
13+ // #define AP_MODE
14+
15+ const char * ssid = " yourssid" ;
16+ const char * password = " yourpasswd" ;
17+
18+ WiFiServer server (80 );
19+ camera_fb_t * fb = NULL ;
20+ uint8_t * out_jpg = NULL ;
21+ size_t out_jpg_len = 0 ;
22+
23+ static void jpegStream (WiFiClient* client);
24+
25+ static camera_config_t camera_config = {
26+ .pin_pwdn = PWDN_GPIO_NUM,
27+ .pin_reset = RESET_GPIO_NUM,
28+ .pin_xclk = XCLK_GPIO_NUM,
29+ .pin_sscb_sda = SIOD_GPIO_NUM,
30+ .pin_sscb_scl = SIOC_GPIO_NUM,
31+ .pin_d7 = Y9_GPIO_NUM,
32+ .pin_d6 = Y8_GPIO_NUM,
33+ .pin_d5 = Y7_GPIO_NUM,
34+ .pin_d4 = Y6_GPIO_NUM,
35+ .pin_d3 = Y5_GPIO_NUM,
36+ .pin_d2 = Y4_GPIO_NUM,
37+ .pin_d1 = Y3_GPIO_NUM,
38+ .pin_d0 = Y2_GPIO_NUM,
39+
40+ .pin_vsync = VSYNC_GPIO_NUM,
41+ .pin_href = HREF_GPIO_NUM,
42+ .pin_pclk = PCLK_GPIO_NUM,
43+
44+ .xclk_freq_hz = 20000000 ,
45+ .ledc_timer = LEDC_TIMER_0,
46+ .ledc_channel = LEDC_CHANNEL_0,
47+
48+ .pixel_format = PIXFORMAT_RGB565,
49+ .frame_size = FRAMESIZE_QVGA,
50+ .jpeg_quality = 0 ,
51+ .fb_count = 2 ,
52+ .fb_location = CAMERA_FB_IN_PSRAM,
53+ .grab_mode = CAMERA_GRAB_LATEST,
54+ .sccb_i2c_port = 0 ,
55+ };
56+
57+ void setup () {
58+ Serial.begin (115200 );
59+ pinMode (POWER_GPIO_NUM, OUTPUT);
60+ digitalWrite (POWER_GPIO_NUM, LOW);
61+
62+ esp_err_t err = esp_camera_init (&camera_config);
63+ if (err != ESP_OK) {
64+ Serial.println (" Camera Init Fail" );
65+ delay (1000 );
66+ esp_restart ();
67+ } else {
68+ Serial.println (" Camera Init Success" );
69+ }
70+
71+ #ifdef STA_MODE
72+
73+ WiFi.mode (WIFI_STA);
74+ WiFi.begin (ssid, password);
75+ WiFi.setSleep (false );
76+ Serial.println (" " );
77+
78+ Serial.print (" Connecting to " );
79+ Serial.println (ssid);
80+
81+ // Wait for connection
82+ while (WiFi.status () != WL_CONNECTED) {
83+ delay (500 );
84+ Serial.print (" ." );
85+ }
86+
87+ Serial.println (" " );
88+ Serial.print (" Connected to " );
89+ Serial.println (ssid);
90+ Serial.print (" IP address: " );
91+ Serial.println (WiFi.localIP ());
92+ #endif
93+
94+ #ifdef AP_MODE
95+ if (!WiFi.softAP (ssid, password)) {
96+ log_e (" Soft AP creation failed." );
97+ while (1 )
98+ ;
99+ }
100+
101+ Serial.println (" AP SSID:" );
102+ Serial.println (ssid);
103+ Serial.println (" AP PASSWORD:" );
104+ Serial.println (password);
105+
106+ IPAddress IP = WiFi.softAPIP ();
107+ Serial.print (" AP IP address: " );
108+ Serial.println (IP);
109+ #endif
110+
111+ server.begin ();
112+ }
113+
114+ void loop () {
115+ WiFiClient client = server.available (); // listen for incoming clients
116+ if (client) { // if you get a client,
117+ while (client.connected ()) { // loop while the client's connected
118+ if (client.available ()) { // if there's bytes to read from the
119+ jpegStream (&client);
120+ }
121+ }
122+ // close the connection:
123+ client.stop ();
124+ Serial.println (" Client Disconnected." );
125+ }
126+ }
127+
128+ // used to image stream
129+ #define PART_BOUNDARY " 123456789000000000000987654321"
130+ static const char * _STREAM_CONTENT_TYPE = " multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
131+ static const char * _STREAM_BOUNDARY = " \r\n --" PART_BOUNDARY " \r\n " ;
132+ static const char * _STREAM_PART = " Content-Type: image/jpeg\r\n Content-Length: %u\r\n\r\n " ;
133+
134+ static void jpegStream (WiFiClient* client) {
135+ Serial.println (" Image stream satrt" );
136+ client->println (" HTTP/1.1 200 OK" );
137+ client->printf (" Content-Type: %s\r\n " , _STREAM_CONTENT_TYPE);
138+ client->println (" Content-Disposition: inline; filename=capture.jpg" );
139+ client->println (" Access-Control-Allow-Origin: *" );
140+ client->println ();
141+ static int64_t last_frame = 0 ;
142+ if (!last_frame) {
143+ last_frame = esp_timer_get_time ();
144+ }
145+
146+ for (;;) {
147+ fb = esp_camera_fb_get ();
148+ if (fb) {
149+ frame2jpg (fb, 255 , &out_jpg, &out_jpg_len);
150+
151+ Serial.printf (" pic size: %d\n " , out_jpg_len);
152+ client->print (_STREAM_BOUNDARY);
153+ client->printf (_STREAM_PART, out_jpg_len);
154+ int32_t to_sends = out_jpg_len;
155+ int32_t now_sends = 0 ;
156+ uint8_t * out_buf = out_jpg;
157+ uint32_t packet_len = 8 * 1024 ;
158+ while (to_sends > 0 ) {
159+ now_sends = to_sends > packet_len ? packet_len : to_sends;
160+ if (client->write (out_buf, now_sends) == 0 ) {
161+ goto client_exit;
162+ }
163+ out_buf += now_sends;
164+ to_sends -= packet_len;
165+ }
166+
167+ int64_t fr_end = esp_timer_get_time ();
168+ int64_t frame_time = fr_end - last_frame;
169+ last_frame = fr_end;
170+ frame_time /= 1000 ;
171+ Serial.printf (" MJPG: %luKB %lums (%.1ffps)\r\n " , (long unsigned int )(out_jpg_len / 1024 ),
172+ (long unsigned int )frame_time, 1000.0 / (long unsigned int )frame_time);
173+
174+ if (fb) {
175+ esp_camera_fb_return (fb);
176+ fb = NULL ;
177+ }
178+ if (out_jpg) {
179+ free (out_jpg);
180+ out_jpg = NULL ;
181+ out_jpg_len = 0 ;
182+ }
183+ } else {
184+ Serial.println (" Camera capture failed" );
185+ }
186+ }
187+
188+ client_exit:
189+ if (fb) {
190+ esp_camera_fb_return (fb);
191+ fb = NULL ;
192+ }
193+ client->stop ();
194+ Serial.printf (" Image stream end\r\n " );
195+ }
0 commit comments