1、 爬坑学习新旅程,虚拟机搭建esp32开发环境,打印 “Hellow World”。
2、 巧用eclipes编辑器,官方教程在在Windows下搭建esp32开发环境,打印 “Hellow World”。
3、 认识基本esp32的GPIO接口,开始点亮您的第一盏 LED和中断回调实现按键功能 。
4、体会esp32的强大的定时器功能, 实现定时2s闪烁一盏LED灯。
5、接触实践esp32的pwm宽度脉冲功能, 实现呼吸效果闪烁一盏LED灯。
6、smartConfig和微信airKiss在esp32的实现,一键配网轻松快捷连接路由器。
7、利用GPIO中断做一个按键的短按和长按的回调事件,再也无须担心触发源。
8、esp32上实现本地 UDP 客户端和服务端角色,在局域网内实现通讯。
9、esp32上实现本地 TCP 客户端和服务端角色,可断线重连原路返回数据。
10、乐鑫esp32 SDK编程利用rmt驱动ws2812七彩灯,实现彩虹渐变效果。
11、入门 乐鑫esp-adf 音频框架开发,esp32造一个蓝牙耳机,实现切换歌曲,获取歌曲信息等功能。
12、开源一个微信公众号airkiss配网esp32以及局域网发现功能的工程,分享一个airkiss配网小工具。
13、esp32 内置 dns 服务器,无需外网访问域名返回指定网页。
14、esp32 sdk编程实现门户强制认证,连接esp32热点之后,自动强制弹出指定的登录界面。
15、认识本地离线语音唤醒识别框架 esp-skainet ,实现较低成本的硬件语音本地识别控制。
16、学习本地语音唤醒离线识别框架 esp-skainet ,如何修改唤醒词? 如何自定义命令词?如何做意图动作?
17、全网首发,乐鑫esp32 sdk直连京东微联·小京鱼 · IoT开放平台,实现叮咚音响语音智能控制。
18、入门京东微联·小京鱼的控制面板H5开发,读懂vue语法,做自己的控制页面。
19、重磅开源,如何在微信小程序上ble蓝牙配网esp32,blufi的那些事!
20、一篇好文,开发过程中编译esp32固件太大,无法正常启动?教你如何自定义分区表partitions.csv。
21、 esp32蓝牙配网blufi的高度封装,集成简单、使用简单、容易上手,提高开发效率!
22、讨论下程序员 “青春饭” 那些事,分享在esp32实现多种加密算法md5 |AES CBC-ECB| Sha1 | Sha256 等!
23、安信可 esp32-a1s 音频开发板移植最新 esp-adf 音频框架,小试牛刀如何实现在线文字转语音播放。
25、分享在 esp32 SDK实现冷暖光色温平滑调节的封装,轻松集成到您的项目去。
26、分享下如何在window下使用CMake编译,编译速度提高传统 make 编译一个档次。
27、windows10平台下自带的Linux安装 ESP8266/ESP32 环境,再无需额外安装虚拟机了。
28、安信可 ESP32-Cam 摄像头开发板二次开发 C SDK编程,实现MQTT远程拍照传输到私有服务器。
29、安信可 ESP32-Cam 摄像头开发板二次开发 C SDK编程,实现本地视频流监控。
上篇给大家介绍带来了如何实现拍照到私有服务器,这篇给大家带来本地视频流监控实现原理和代码;
本文章的源码免费获取:关注本人微信公众号 “徐宏blog” ,发送 210104 获取!
客户端请求HTTP格式:
GET /stream HTTP/1.1
Host: 10.10.10.114
服务器返回HTTP格式,这里是分块编码返回给客户端:
Content-Type: multipart/x-mixed-replace;boundary=123456789000000000000987654321
Transfer-Encoding: chunked
1、设置本地路由器SSID和Password,模块连接路由器;
void app_wifi_initialise(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
wifi_config_t wifi_config = {
.sta = {
.ssid = "aiot@xuhongv",
.password = "12345678",
},
};
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
}
2、开启一个web服务端,资源访问路径是 /stream;
httpd_uri_t stream = {
.uri = "/stream",
.method = HTTP_GET,
.handler = http_get_handler,
.user_ctx = "stream!"
};
httpd_handle_t server = NULL;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
// Start the httpd server
ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
if (httpd_start(&server, &config) == ESP_OK)
{
// Set URI handlers
ESP_LOGI(TAG, "Registering URI handlers");
httpd_register_uri_handler(server, &stream);
}
else
{
ESP_LOGI(TAG, "Error starting server!");
}
ESP_LOGI(TAG, "Http End");
3、数据流处理返回给客户端;
#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";
esp_err_t http_get_handler(httpd_req_t *req)
{
//获取芯片可用内存
printf("esp_get_free_heap_size : %d \n", esp_get_free_heap_size());
camera_fb_t *fb = NULL;
esp_err_t res = ESP_OK;
size_t _jpg_buf_len;
uint8_t *_jpg_buf;
char *part_buf[64];
static int64_t last_frame = 0;
if (!last_frame)
{
last_frame = esp_timer_get_time();
}
res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
if (res != ESP_OK)
{
return res;
}
while (true)
{
fb = esp_camera_fb_get();
if (!fb)
{
ESP_LOGE(TAG, "Camera capture failed");
res = ESP_FAIL;
break;
}
if (fb->format != PIXFORMAT_JPEG)
{
bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
if (!jpeg_converted)
{
ESP_LOGE(TAG, "JPEG compression failed");
esp_camera_fb_return(fb);
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->format != PIXFORMAT_JPEG)
{
free(_jpg_buf);
}
esp_camera_fb_return(fb);
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;
ESP_LOGI(TAG, "MJPG: %uKB %ums (%.1ffps)",
(uint32_t)(_jpg_buf_len / 1024),
(uint32_t)frame_time, 1000.0 / (uint32_t)frame_time);
}
last_frame = 0;
return res;
}
4、LOG日志打印,可看到在本地局域网的IP地址是:10.10.10.114,要访问地址为:10.10.10.114/stream
:
I (479) gpio: GPIO[32]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (629) camera: Detected OV2640 camera
I (639) camera: Allocating 1 frame buffers (60 KB total)
I (639) camera: Allocating 60 KB frame buffer in OnBoard RAM
I (1479) wifi:new:<9,0>, old:<1,0>, ap:<255,255>, sta:<9,0>, prof:1
I (2469) wifi:state: init -> auth (b0)
I (2479) wifi:state: auth -> assoc (0)
I (2479) wifi:state: assoc -> run (10)
I (2769) wifi:connected with aiot@xuhongv, aid = 1, channel 9, BW20, bssid = d8:c8:e9:05:c4:d8
I (2769) wifi:security type: 4, phy: bgn, rssi: -37
I (2769) wifi:pm start, type: 1
I (2839) wifi:AP's beacon interval = 102400 us, DTIM period = 1
I (3699) event: sta ip: 10.10.10.114, mask: 255.255.255.0, gw: 10.10.10.1
I (3699) example:take_picture: Http Start
I (3699) example:take_picture: Starting server on port: '80'
I (3699) example:take_picture: Registering URI handlers
I (3709) example:take_picture: Http End
5、访问效果:
本文章的源码免费获取:关注本人微信公众号 “徐宏blog” ,发送 210104 获取!
esp8266
带你飞、加群QQ
群,不喜的朋友勿喷勿加:434878850