#!/bin/bash
# Author: twily.info 2025
#
# to load wifi camera as usb video class (uvc) like
# /dev/video0
#
# (download arduino appimage and make executaable;
# https://www.arduino.cc/en/software/ )
#
# (to flash to esp, short IO0 to GND while it is starting
# hold the short until Uploading begins ~ is a timing thing)
#
# install stuff~ FDTI and v4l2
# $ sudo apt install cp2102 v4l2loopback-dkms
# $ sudo apt install ffmpeg
# $ sudo apt install gstreamer1.0-tools gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-libav
# $ sudo apt install gstreamer1.0-plugins-good
#
# crontab (remove sudo's and setup on root):
# reboot screen -dmS esp32cam /home/amalie/scripts/esp32-cam-ffmpeg-gst-uvc.sh
#
# ----
# specific to eps32-cam camerawebserver
# load up arduino ide (available on linux)
#
# add preferances additional url;
#
# https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
#
# create clean example of camerawebserver (templates);
#
# setup wifi ssid and password to connect
#
# add under stream_handler to customize defaults;
#
# // Force VGA resolution
# sensor_t *s = esp_camera_sensor_get();
# s->set_framesize(s, FRAMESIZE_VGA);
# s->set_brightness(s, 1); // -2 to 2 (0 = default)
# s->set_contrast(s, -1); // -2 to 2 (0 = default)
# s->set_saturation(s, 1); // -2 to 2 (0 = default)
# s->set_whitebal(s, 1); // 1 = enable auto white balance, 0 = disable
# s->set_awb_gain(s, 1); // 1 = enable AWB gain, 0 = disable
# s->set_wb_mode(s, 0); // 0 = auto, 1 = sunny, 2 = cloudy, 3 = office, 4 = home
#
# optimizatioon code limit frametime for network load;
# while (true) {
# fb = esp_camera_fb_get();
# if (!fb) {
# log_e("Camera capture failed");
# res = ESP_FAIL;
# break;
# }
# size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, fb->len);
# res = httpd_send(req, (const char *)part_buf, hlen);
# if (res == ESP_OK) {
# res = httpd_send(req, (const char *)fb->buf, fb->len);
# }
# if (res == ESP_OK) {
# res = httpd_send(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
# }
# esp_camera_fb_return(fb);
# if (res != ESP_OK) break;
# vTaskDelay(66 / portTICK_PERIOD_MS); // ~15fps
# }
#
# (Common resolution options:
# FRAMESIZE_QQVGA (160x120)
# FRAMESIZE_QCIF (176x144)
# FRAMESIZE_DCIF (352x288)
# FRAMESIZE_QVGA (320x240) [defaault]
# FRAMESIZE_CIF (352x288)
# FRAMESIZE_VGA (640x480)
# FRAMESIZE_XGA (1024x768)
# FRAMESIZE_UXGA (1600x1200) )
# ----
IP="10.0.0.91"
PORT="81"
while true; do
sudo modprobe -r v4l2loopback # Clear if needed
sudo modprobe v4l2loopback devices=1 video_nr=0 exclusive_caps=1
# use ffmpeg or gstreamer:
#ffmpeg -reconnect 1 -reconnect_at_eof 1 -reconnect_streamed 1 -reconnect_delay_max 5 -timeout 30000000 -fflags nobuffer -analyzeduration 0 -probesize 32 -re -i http://$IP:$PORT/stream -f v4l2 -pix_fmt yuv420p /dev/video0
gst-launch-1.0 souphttpsrc location=http://$IP:$PORT/stream is-live=true timeout=0 retries=-1 ! multipartdemux ! jpegdec ! videobalance brightness=0.1 contrast=0.8 saturation=1.2 ! videoconvert ! videorate ! video/x-raw,format=YUY2,width=640,height=480,framerate=15/1 ! v4l2sink device=/dev/video0 sync=false
# debug
#gst-launch-1.0 souphttpsrc location="http://$IP:$PORT/stream" ! multipartdemux ! jpegdec ! videobalance brightness=0.1 contrast=0.8 saturation=1.2 ! videoconvert ! autovideosink
sleep 5 # Pause before retry
done
# debug
#sudo lsof /dev/video0
# debug
#v4l2loopback-ctl /dev/video0
# debug
#vlc v4l2:///dev/video0
Top