# include <WiFi.h>
# include <esp_http_server.h>
# include <esp_camera.h>
// カメラに接続するときのSSID(周りの人とかぶらないものにすること)
# define CAMERA_SSID "my_camera"
// 1: 上下反転する, 0: しない
# define FLIP 1
// 区切り用のランダム文字列(変更不要)
# define BOUNDARY_KEY "123456789000000000000987654321"
void setup() {
// シリアル通信開始
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println("power on");
// WiFi アクセスポイントモード設定
Serial.println("WiFi ap mode");
WiFi.mode(WIFI_MODE_AP);
WiFi.softAP(CAMERA_SSID);
Serial.println("Please Connect SSID " CAMERA_SSID " and Browse http://192.168.4.1/");
// カメラ接続
Serial.println("camera begin");
camera_config_t config = {
.pin_pwdn = -1,
.pin_reset = 15,
.pin_xclk = 27,
.pin_sscb_sda = 22,
.pin_sscb_scl = 23,
.pin_d7 = 19,
.pin_d6 = 36,
.pin_d5 = 18,
.pin_d4 = 39,
.pin_d3 = 5,
.pin_d2 = 34,
.pin_d1 = 35,
.pin_d0 = 32,
.pin_vsync = 25,
.pin_href = 26,
.pin_pclk = 21,
.xclk_freq_hz = 20000000, // 20MHz
.ledc_timer = LEDC_TIMER_0, // 0番のタイマー使用
.ledc_channel = LEDC_CHANNEL_0, // 0番のチャネル使用
.pixel_format = PIXFORMAT_JPEG, // JPEG
.frame_size = FRAMESIZE_VGA, // 解像度
.jpeg_quality = 12, // JPGE画質(小さいほど高画質)
.fb_count = 1 // フレームバッファ数(2つあれば2倍で処理できる?)
};
esp_err_t result = esp_camera_init(&config);
if (result != ESP_OK) {
Serial.printf("esp_camera_init error 0x%x\n", result);
return;
}
// 上下反転設定
sensor_t * sensor = esp_camera_sensor_get();
sensor->set_vflip(sensor, FLIP);
// HTTP Server 開始
Serial.println("httpd begin");
httpd_handle_t httpd = NULL;
httpd_config_t httpd_config = HTTPD_DEFAULT_CONFIG();
Serial.printf("lisen port %d\n", httpd_config.server_port);
result = httpd_start(&httpd, &httpd_config);
if (result != ESP_OK) {
Serial.printf("httpd_start error 0x%x\n", result);
return;
}
// 映像送信処理登録
httpd_uri_t stream = {
.uri = "/",
.method = HTTP_GET,
.handler = [](httpd_req_t *request) {
Serial.println("GET /");
// レスポンスの種類を指定
esp_err_t result = httpd_resp_set_type(request, "multipart/x-mixed-replace;boundary=" BOUNDARY_KEY);
if (result != ESP_OK) {
Serial.printf("httpd_resp_set_type(multipart) error 0x%x\n", result);
}
// 繰り返し画像を送信(動画のように見える)
while (result == ESP_OK) {
//撮影
struct Shot {
// カメラフレーム
camera_fb_t* frame;
// カメラ画像取得
Shot() : frame(esp_camera_fb_get()) {
if (!ok()) {
Serial.println("esp_camera_fb_get failed");
}
}
// 取得成功かどうか
inline bool ok() {
return frame != NULL;
}
// バイナリデータ
inline uint8_t* data() {
return frame->buf;
}
// バイト数
inline size_t size() {
return frame->len;
}
// リソース開放
~Shot() {
if (frame != NULL) {
esp_camera_fb_return(frame);
}
}
} shot;
if (!shot.ok()) break;
// ヘッダ部分の送信
char buffer[64];
size_t length = snprintf(buffer, sizeof(buffer), "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n", shot.size());
result = httpd_resp_send_chunk(request, buffer, length);
if (result != ESP_OK) {
Serial.printf("httpd_resp_send_chunk(header) error 0x%x\n", result);
continue;
}
// JPEGの送信
result = httpd_resp_send_chunk(request, (char*)shot.data(), shot.size());
if (result != ESP_OK) {
Serial.printf("httpd_resp_send_chunk(image) error 0x%x\n", result);
continue;
}
// 区切り送信
result = httpd_resp_send_chunk(request, "\r\n--" BOUNDARY_KEY "\r\n", -1);
if (result != ESP_OK) {
Serial.printf("httpd_resp_send_chunk(boundary) error 0x%x\n", result);
continue;
}
}
if (result != ESP_OK) {
Serial.printf("stream_handler error 0x%x\n", result);
return httpd_resp_send_500(request);
}
return httpd_resp_send(request, NULL, 0);
},
.user_ctx = NULL
};
result = httpd_register_uri_handler(httpd, &stream);
if (result != ESP_OK) {
Serial.printf("httpd_register_uri_handler(stream) error 0x%x\n", result);
return;
}
}
void loop() {
}
More than 5 years have passed since last update.
M5Cameraに直接接続して映像を見る
Posted at
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme