Bạn có USB webcam muốn stream lên web mà không cần PC chạy 24/7? ESP32-P4 với USB 2.0 HS có thể làm bridge: nhận video từ USB cam và stream qua WebRTC — cần điện 5V là đủ.
Tại Sao ESP32-P4 Làm Được?
ESP32-S3 có USB nhưng chỉ USB 1.1 Full Speed (12Mbps) — không đủ bandwidth cho video 720p. ESP32-P4 có USB 2.0 High Speed (480Mbps) — đủ để đọc UVC webcam ở 720p@30fps.
UVC (USB Video Class) là chuẩn plug-and-play cho webcam — hầu hết USB camera đều hỗ trợ, không cần driver riêng.
Danh Sách Linh Kiện
| Linh Kiện | Ghi Chú |
|---|---|
| ESP32-P4 EV Board | Bắt buộc (USB 2.0 HS) |
| USB Webcam | Hỗ trợ UVC, MJPEG output, 720p |
| USB OTG adapter | Micro-USB / USB-C OTG |
| Nguồn 5V 2A | Cấp riêng cho ESP32 và camera |
Camera Tương Thích Test Được
- Logitech C270 (640×480@30fps, MJPEG)
- Logitech C920 (1080p@30fps, H.264)
- Microsoft LifeCam HD-3000 (720p@30fps)
- Camera clone no-brand từ Shopee (hầu hết UVC MJPEG 640×480)
Cấu Trúc Code
esp-webrtc-solution có demo sẵn solutions/usbcamerabridge/. Cấu trúc chính:
usb_camera_bridge/
├── main/
│ ├── app_main.c ← Entry point
│ ├── uvc_camera.c ← UVC driver wrapper
│ └── webrtc_bridge.c ← Kết nối UVC → WebRTC
└── CMakeLists.txt
Code: UVC Camera Init
#include "usb/usb_host.h"
#include "usb/uvc_host.h"
static uvc_host_stream_hdl_t g_uvc_stream;
// Callback nhận frame từ USB camera
static bool uvc_frame_callback(const uvc_host_frame_t *frame, void *user_data) {
if (frame->data_len == 0) return true;
// Gửi frame vào WebRTC pipeline
esp_webrtc_handle_t webrtc = (esp_webrtc_handle_t)user_data;
esp_webrtc_video_frame_t vf = {
.data = frame->data,
.data_len = frame->data_len,
.pts = esp_timer_get_time() / 1000, // ms
.codec = ESP_WEBRTC_VIDEO_CODEC_MJPEG, // UVC thường output MJPEG
};
esp_webrtc_push_video_frame(webrtc, &vf);
return true;
}
static void init_uvc_camera(esp_webrtc_handle_t webrtc) {
// Khởi tạo USB Host
usb_host_config_t host_cfg = {
.skip_phy_setup = false,
.intr_flags = ESP_INTR_FLAG_LEVEL1,
};
usb_host_install(&host_cfg);
// Cấu hình UVC stream
const uvc_host_stream_config_t stream_cfg = {
.event_cb = NULL,
.frame_cb = uvc_frame_callback,
.frame_cb_arg = webrtc,
.vs_format = {
.h_res = 640,
.v_res = 480,
.fps = 30,
.format = UVC_VS_FORMAT_MJPEG,
},
};
uvc_host_stream_open(&stream_cfg, portMAX_DELAY, &g_uvc_stream);
uvc_host_stream_start(g_uvc_stream);
}
MJPEG → H.264 Transcoding (Tùy Chọn)
Nếu camera chỉ output MJPEG (phổ biến), ESP32-P4 có thể transcode sang H.264 bằng hardware:
// ESP-Capture có MJPEG → H.264 transcoder sử dụng HW
esp_capture_transcode_cfg_t transcode_cfg = {
.input_codec = CAPTURE_CODEC_MJPEG,
.output_codec = CAPTURE_CODEC_H264,
.width = 640,
.height = 480,
.fps = 30,
.bitrate = 500000, // 500kbps
};
esp_capture_add_transcoder(cap, &transcode_cfg);
Transcoding tốn thêm ~10% CPU nhưng giảm 5× bandwidth so với MJPEG raw.
Main App
void app_main(void) {
// Wi-Fi
wifi_init_sta(CONFIG_WIFI_SSID, CONFIG_WIFI_PASS);
wifi_wait_connected();
// WebRTC không cần esp_capture — push frame thủ công từ UVC callback
esp_webrtc_cfg_t cfg = {
.signaling = {
.type = ESP_WEBRTC_SIGNALING_WHIP,
.whip_url = CONFIG_WHIP_URL,
},
.video_codec = ESP_WEBRTC_VIDEO_CODEC_H264,
.audio_codec = ESP_WEBRTC_AUDIO_CODEC_G711A, // Dùng G.711 nhẹ nếu không có mic tốt
.manual_video_push = true, // Bật chế độ push thủ công
};
esp_webrtc_handle_t webrtc;
esp_webrtc_init(&cfg, &webrtc);
esp_webrtc_start(webrtc);
// Khởi tạo UVC camera, pass webrtc handle vào callback
init_uvc_camera(webrtc);
ESP_LOGI("bridge", "USB Camera Bridge running");
// Main loop
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
📷 [Hình minh hoạ: Ảnh: USB webcam cắm vào ESP32-P4 EV Board qua OTG adapter, stream lên browser]
Latency So Sánh
| Pipeline | Latency |
|---|---|
| Camera USB → ESP32 UVC | ~33ms (1 frame @30fps) |
| MJPEG → H.264 transcode | ~15ms |
| WebRTC encode + transmit | ~50ms |
| Tổng (LAN) | ~100ms |
| Tổng (WAN) | ~150–250ms |
Xử Lý Camera Ngắt Kết Nối
USB camera có thể ngắt đột ngột (tháo, lỗi). Thêm reconnect logic:
static void uvc_event_cb(const uvc_host_driver_event_data_t *event, void *arg) {
if (event->type == UVC_HOST_DRIVER_EVENT_DEVICE_DISCONNECTED) {
ESP_LOGW("bridge", "USB Camera disconnected, waiting for reconnect...");
g_uvc_stream = NULL;
// WebRTC vẫn chạy nhưng không có video
esp_webrtc_pause_video(g_webrtc);
} else if (event->type == UVC_HOST_DEVICE_CONNECTED) {
ESP_LOGI("bridge", "USB Camera reconnected");
init_uvc_camera(g_webrtc);
esp_webrtc_resume_video(g_webrtc);
}
}
Ứng Dụng Thực Tế
- Camera an ninh cũ lên stream: biến USB cam cũ thành IP camera không cần NVR
- Streaming từ microscope USB: kết nối microscope kỹ thuật số vào WebRTC stream
- Kiosk camera: tablet hoặc ESP32-P4 + USB cam làm camera kiosk
- Kiểm soát từ xa máy móc: camera USB gắn ở máy CNC stream về dashboard
Bài tiếp theo: Tích Hợp OpenAI Realtime API — ESP32 Nói Chuyện Với GPT-4o


