Page 1 of 1

Combination of live streaming and HTTP request for ESP32

Posted: Mon Mar 13, 2023 9:23 pm
by PyPat2021
Hello,
I have the problem that I already got 2 individually working codes but I don't know how to put them together.
Each of them uses the same soft-AP so I will be able to connect to the ESP32-CAM.
Code 1 creates a video-live-stream that can be seen via URL "192.168.4.2":

Code: Untitled.cpp Select all


#include "esp_camera.h"
#include <WiFi.h>
#include "esp_timer.h"
#include "img_converters.h"
#include "Arduino.h"
#include "fb_gfx.h"
#include "soc/soc.h" //disable brownout problems
#include "soc/rtc_cntl_reg.h" //disable brownout problems
#include "esp_http_server.h"

// Replace with your network credentials
const char* ssid = "ESP32-Access-Point"; //Name des Arduino-WiFi's
const char* password = "123456789"; //Passwort für das Arduino-WiFi
int max_connection = 1; //maximale Anzahl gleichzeitiger Clients im Arduino-Netzwerk

#define PART_BOUNDARY "123456789000000000000987654321"

#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27

#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22


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";

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];

res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
if(res != ESP_OK){
return res;
}

while(true){
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
res = ESP_FAIL;
} else {
if(fb->width > 400){
if(fb->format != PIXFORMAT_JPEG){
bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
esp_camera_fb_return(fb);
fb = NULL;
if(!jpeg_converted){
Serial.println("JPEG compression failed");
res = ESP_FAIL;
}
} else {
_jpg_buf_len = fb->len;
_jpg_buf = fb->buf;
}
}
}
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(res == ESP_OK){
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
}
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;
}
//Serial.printf("MJPG: %uB\n",(uint32_t)(_jpg_buf_len));
}
return res;
}

void startCameraServer(){
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.server_port = 80;

httpd_uri_t index_uri = {
.uri = "/",
.method = HTTP_GET,
.handler = stream_handler,
.user_ctx = NULL
};

//Serial.printf("Starting web server on port: '%d'\n", config.server_port);
if (httpd_start(&stream_httpd, &config) == ESP_OK) {
httpd_register_uri_handler(stream_httpd, &index_uri);
}
}

void setup() {

WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector

Serial.begin(115200);
Serial.setDebugOutput(false);

camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;

if(psramFound()){
config.frame_size = FRAMESIZE_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}

// Camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
// Wi-Fi connection
WiFi.softAP(ssid, password, max_connection);

IPAddress IP(192, 168, 4, 2); //Eine IP-Adresse für den Arduino festlegen
IPAddress NMask(255, 255, 255, 0);
WiFi.softAPConfig(IP, IP, NMask); //Configure ESP32 to apply the defined IP address from above
IPAddress local_IP = WiFi.softAPIP();

Serial.print("Camera Stream Ready! Go to: http://");
Serial.print(local_IP);

// Start streaming web server
startCameraServer();
}

void loop() {
delay(1);
}
Code 2 allows me to process HTTP-requests that I send to the ESP32.
I use this to regulate the brightness of a LED/a small laser via PWM output in 256 steps (8 bit).
for example: "192.168.4.2/LED/value127" -> sets brightness to 127/255 = about 50%

Code: Untitled.cpp Select all


// Load Wi-Fi library
#include <WiFi.h>


// Replace with your network credentials
const char* ssid = "ESP32-Access-Point"; //name for arduino WiFi
const char* password = "123456789"; //password for arduino WiFi
int max_connection = 1; //max. number of simultaneous clients

// Set web server port number to 80
WiFiServer server(80);

// Variable to store the HTTP request
String incomingrequest;


#define PIN_LED 4 //Pin 4 is flash LED
#define CHN 0 //select PWM channel
#define FRQ 1000 //select PWM frequency (Hz)
#define PWM_BIT 8 //select PWM accuracy (8-Bit is 0-255, 0 = 0% and 255 = 100%)

void setup() {
Serial.begin(115200);

ledcSetup(CHN, FRQ, PWM_BIT); //setup pwm channel
ledcAttachPin(PIN_LED, CHN); //attach the led pin to pwm channel

// Connect to Wi-Fi network with SSID and password
Serial.print("Setting AP (Access Point)…");
// Remove the password parameter, if you want the AP (Access Point) to be open
WiFi.softAP(ssid, password, max_connection);

IPAddress IP(192, 168, 4, 2); //preset arduino IP address
IPAddress NMask(255, 255, 255, 0);
WiFi.softAPConfig(IP, IP, NMask); //Configure ESP32 to apply the defined IP address from above
IPAddress local_IP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(local_IP);

server.begin();
}

void loop(){
WiFiClient client = server.available(); // Listen for incoming clients

if (client) { // If a new client connects,
Serial.println("New Client."); // print a message out in the serial port
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected()) { // loop while the client's connected
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
incomingrequest += c;
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();


// controls the LED brightness depending on the requested URL e.g. http://192.168.4.2/LED/value127 = LED brightness value 127/255
if (incomingrequest.indexOf("GET /LED/value") >= 0) {
Serial.println(incomingrequest); //http request is e.g. "GET /LED/value127 HTTP/1.1"
int urllength = incomingrequest.length(); //urllength is length value of incoming request
int endofbrightnessvalue = urllength - 9; //" HTTP/1.1" is cut, it's the last 9 digits
String brightnessvalue = incomingrequest.substring(14,endofbrightnessvalue); //brightness value "127" is between digit #14 and end of string
Serial.println("LED brightness set to" + brightnessvalue); //"brightnessvalue" = "127" in this case
ledcWrite(CHN, brightnessvalue.toInt()); //LED brightness is set to value between 0 and 255
}

// The HTTP response ends with another blank line
client.println();
// Break out of the while loop
break;
} else { // if you got a newline, then clear currentLine
currentLine = "";
}
} else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
}
}
// Clear the incomingrequest variable
incomingrequest = "";
// Close the connection
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
}

As I said before: both codes are working fine for me individually.
Now I would like to see the video live stream AND being able to control the LED brightness simultaneously.

Can anybody please help? I am quite new to this and still learning. Thank you!

Re: Combination of live streaming and HTTP request for ESP32

Posted: Tue Mar 21, 2023 12:28 pm
by corz.org
You literally just need to drop one on top of the other!

Split it into the logical sections: Initial setup (includes and then setup()) and then stuff inside loop().

Rip out all the important bits from inside the second loop() and drop them into the first loop().

There will be errors. Ensure you have full verbose output enabled, so you can see what they are. It will be obvious stuff; variables declared twice and such.

Once you get it working, go through the code and look at ways you can remove any possible duplication, or merge variables, or whatever.

This is generic advice. I haven't looked at your code though have done similar things in the past.

Re: Combination of live streaming and HTTP request for ESP32

Posted: Wed Mar 22, 2023 12:58 am
by noweare
What err msgs do you get. I would recommend start with one working then add code little by little until it breaks then fix it. Sometimes can get really confusing. Also the server serves up the html doc so that has to be correct also. Is the led flash code in the html code ?
Is the html code in a form you can read or is it compressed and stored as a binary ?