-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcameraStream.cpp
More file actions
164 lines (140 loc) · 4.68 KB
/
Copy pathcameraStream.cpp
File metadata and controls
164 lines (140 loc) · 4.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include "camera_pins.h"
#ifdef CAMERA
#include <esp_http_server.h>
#include <esp_camera.h>
#include "Arduino.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#define PART_BOUNDARY "123456789000000000000987654321"
static const char *_STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char *_STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char *_STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
// Global handle for the streaming HTTP server
static httpd_handle_t stream_httpd = NULL;
static esp_err_t stream_handler(httpd_req_t *req)
{
camera_fb_t *fb = NULL;
esp_err_t res = ESP_OK;
size_t _jpg_buf_len = 0;
uint8_t *_jpg_buf = NULL;
char *part_buf[64];
// int64_t last_frame = esp_timer_get_time();
res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
if (res != ESP_OK)
{
return res;
}
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
while (true)
{
fb = esp_camera_fb_get();
if (!fb)
{
Serial.println("Camera capture failed");
res = ESP_FAIL;
}
else
{
_jpg_buf_len = fb->len;
_jpg_buf = fb->buf;
}
if (res == ESP_OK)
{
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
}
if (res == ESP_OK)
{
size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
}
if (res == ESP_OK)
{
res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
}
if (fb)
{
esp_camera_fb_return(fb);
fb = NULL;
_jpg_buf = NULL;
}
else if (_jpg_buf)
{
free(_jpg_buf);
_jpg_buf = NULL;
}
if (res != ESP_OK)
{
break;
}
// int64_t fr_end = esp_timer_get_time();
/*
int64_t frame_time = fr_end - last_frame;
last_frame = fr_end;
frame_time /= 1000;
Serial.printf("MJPG: %uB %ums (%.1ffps), free heap: %d\n",
(uint32_t)(_jpg_buf_len),
(uint32_t)frame_time, 1000.0 / (uint32_t)frame_time,
ESP.getFreeHeap());
*/
}
return res;
}
// Forward declarations
static void stream_server_task(void* pvParameters);
void startCameraStreamServer()
{
// Temporarily disable camera streaming server to avoid TCP allocation issues
Serial.println("Camera streaming server temporarily disabled due to TCP stack issues");
// We won't create the server task at all for now
/*
// Use proper synchronization for ESP-IDF httpd server
Serial.println("Setting up camera stream server...");
// Delay to ensure network stack is ready
delay(1000);
// Start in a separate task with a 1-second delay
// We'll start the actual server later
xTaskCreate(
stream_server_task, // Task function
"stream_server", // Name of task
8192, // Stack size
NULL, // Parameters
1, // Priority (1 = low)
NULL // Task handle
);
Serial.println("Camera stream server task created");
*/
}
// This task runs separately to avoid conflicts with AsyncWebServer
static void stream_server_task(void* pvParameters)
{
// Give the system time to fully initialize networking
vTaskDelay(2000 / portTICK_PERIOD_MS);
// Configure httpd server
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
// Use port 81 for streaming
config.server_port = 81;
config.ctrl_port = 32769;
// Configure for better stability
config.stack_size = 8192;
config.core_id = 0; // Run on core 0 (AsyncWebServer is likely on core 1)
Serial.printf("Starting stream server on port: %d\n", config.server_port);
// Start the server
esp_err_t ret = httpd_start(&stream_httpd, &config);
if (ret == ESP_OK) {
// Define stream URI handler
httpd_uri_t stream_uri = {
.uri = "/stream",
.method = HTTP_GET,
.handler = stream_handler,
.user_ctx = NULL
};
// Register URI handler
httpd_register_uri_handler(stream_httpd, &stream_uri);
Serial.println("Camera stream server started successfully");
} else {
Serial.printf("Camera stream server failed to start: %d\n", ret);
}
// Task can be deleted after setup
vTaskDelete(NULL);
}
#endif // CAMERA