Combination of live streaming and HTTP request for ESP32

PyPat2021
Posts: 4
Joined: Sun Jun 12, 2022 12:27 pm

Combination of live streaming and HTTP request for ESP32

Postby PyPat2021 » Mon Mar 13, 2023 9:23 pm

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":
  1. #include "esp_camera.h"
  2. #include <WiFi.h>
  3. #include "esp_timer.h"
  4. #include "img_converters.h"
  5. #include "Arduino.h"
  6. #include "fb_gfx.h"
  7. #include "soc/soc.h" //disable brownout problems
  8. #include "soc/rtc_cntl_reg.h"  //disable brownout problems
  9. #include "esp_http_server.h"
  10.  
  11. // Replace with your network credentials
  12. const char* ssid     = "ESP32-Access-Point"; //Name des Arduino-WiFi's
  13. const char* password = "123456789"; //Passwort für das Arduino-WiFi
  14. int max_connection = 1; //maximale Anzahl gleichzeitiger Clients im Arduino-Netzwerk
  15.  
  16. #define PART_BOUNDARY "123456789000000000000987654321"
  17.  
  18. #define PWDN_GPIO_NUM     32
  19. #define RESET_GPIO_NUM    -1
  20. #define XCLK_GPIO_NUM      0
  21. #define SIOD_GPIO_NUM     26
  22. #define SIOC_GPIO_NUM     27
  23.  
  24. #define Y9_GPIO_NUM       35
  25. #define Y8_GPIO_NUM       34
  26. #define Y7_GPIO_NUM       39
  27. #define Y6_GPIO_NUM       36
  28. #define Y5_GPIO_NUM       21
  29. #define Y4_GPIO_NUM       19
  30. #define Y3_GPIO_NUM       18
  31. #define Y2_GPIO_NUM        5
  32. #define VSYNC_GPIO_NUM    25
  33. #define HREF_GPIO_NUM     23
  34. #define PCLK_GPIO_NUM     22
  35.  
  36.  
  37. static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
  38. static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
  39. static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
  40.  
  41. httpd_handle_t stream_httpd = NULL;
  42.  
  43. static esp_err_t stream_handler(httpd_req_t *req){
  44.   camera_fb_t * fb = NULL;
  45.   esp_err_t res = ESP_OK;
  46.   size_t _jpg_buf_len = 0;
  47.   uint8_t * _jpg_buf = NULL;
  48.   char * part_buf[64];
  49.  
  50.   res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
  51.   if(res != ESP_OK){
  52.     return res;
  53.   }
  54.  
  55.   while(true){
  56.     fb = esp_camera_fb_get();
  57.     if (!fb) {
  58.       Serial.println("Camera capture failed");
  59.       res = ESP_FAIL;
  60.     } else {
  61.       if(fb->width > 400){
  62.         if(fb->format != PIXFORMAT_JPEG){
  63.           bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
  64.           esp_camera_fb_return(fb);
  65.           fb = NULL;
  66.           if(!jpeg_converted){
  67.             Serial.println("JPEG compression failed");
  68.             res = ESP_FAIL;
  69.           }
  70.         } else {
  71.           _jpg_buf_len = fb->len;
  72.           _jpg_buf = fb->buf;
  73.         }
  74.       }
  75.     }
  76.     if(res == ESP_OK){
  77.       size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
  78.       res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
  79.     }
  80.     if(res == ESP_OK){
  81.       res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
  82.     }
  83.     if(res == ESP_OK){
  84.       res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
  85.     }
  86.     if(fb){
  87.       esp_camera_fb_return(fb);
  88.       fb = NULL;
  89.       _jpg_buf = NULL;
  90.     } else if(_jpg_buf){
  91.       free(_jpg_buf);
  92.       _jpg_buf = NULL;
  93.     }
  94.     if(res != ESP_OK){
  95.       break;
  96.     }
  97.     //Serial.printf("MJPG: %uB\n",(uint32_t)(_jpg_buf_len));
  98.   }
  99.   return res;
  100. }
  101.  
  102. void startCameraServer(){
  103.   httpd_config_t config = HTTPD_DEFAULT_CONFIG();
  104.   config.server_port = 80;
  105.  
  106.   httpd_uri_t index_uri = {
  107.     .uri       = "/",
  108.     .method    = HTTP_GET,
  109.     .handler   = stream_handler,
  110.     .user_ctx  = NULL
  111.   };
  112.  
  113.   //Serial.printf("Starting web server on port: '%d'\n", config.server_port);
  114.   if (httpd_start(&stream_httpd, &config) == ESP_OK) {
  115.     httpd_register_uri_handler(stream_httpd, &index_uri);
  116.   }
  117. }
  118.  
  119. void setup() {
  120.  
  121.   WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
  122.  
  123.   Serial.begin(115200);
  124.   Serial.setDebugOutput(false);
  125.  
  126.   camera_config_t config;
  127.   config.ledc_channel = LEDC_CHANNEL_0;
  128.   config.ledc_timer = LEDC_TIMER_0;
  129.   config.pin_d0 = Y2_GPIO_NUM;
  130.   config.pin_d1 = Y3_GPIO_NUM;
  131.   config.pin_d2 = Y4_GPIO_NUM;
  132.   config.pin_d3 = Y5_GPIO_NUM;
  133.   config.pin_d4 = Y6_GPIO_NUM;
  134.   config.pin_d5 = Y7_GPIO_NUM;
  135.   config.pin_d6 = Y8_GPIO_NUM;
  136.   config.pin_d7 = Y9_GPIO_NUM;
  137.   config.pin_xclk = XCLK_GPIO_NUM;
  138.   config.pin_pclk = PCLK_GPIO_NUM;
  139.   config.pin_vsync = VSYNC_GPIO_NUM;
  140.   config.pin_href = HREF_GPIO_NUM;
  141.   config.pin_sscb_sda = SIOD_GPIO_NUM;
  142.   config.pin_sscb_scl = SIOC_GPIO_NUM;
  143.   config.pin_pwdn = PWDN_GPIO_NUM;
  144.   config.pin_reset = RESET_GPIO_NUM;
  145.   config.xclk_freq_hz = 20000000;
  146.   config.pixel_format = PIXFORMAT_JPEG;
  147.  
  148.   if(psramFound()){
  149.     config.frame_size = FRAMESIZE_UXGA;
  150.     config.jpeg_quality = 10;
  151.     config.fb_count = 2;
  152.   } else {
  153.     config.frame_size = FRAMESIZE_SVGA;
  154.     config.jpeg_quality = 12;
  155.     config.fb_count = 1;
  156.   }
  157.  
  158.   // Camera init
  159.   esp_err_t err = esp_camera_init(&config);
  160.   if (err != ESP_OK) {
  161.     Serial.printf("Camera init failed with error 0x%x", err);
  162.     return;
  163.   }
  164.   // Wi-Fi connection
  165.   WiFi.softAP(ssid, password, max_connection);
  166.  
  167.   IPAddress IP(192, 168, 4, 2); //Eine IP-Adresse für den Arduino festlegen
  168.     IPAddress NMask(255, 255, 255, 0);
  169.   WiFi.softAPConfig(IP, IP, NMask); //Configure ESP32 to apply the defined IP address from above
  170.   IPAddress local_IP = WiFi.softAPIP();
  171.  
  172.   Serial.print("Camera Stream Ready! Go to: http://");
  173.   Serial.print(local_IP);
  174.  
  175.   // Start streaming web server
  176.   startCameraServer();
  177. }
  178.  
  179. void loop() {
  180. delay(1);
  181. }
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%
  1. // Load Wi-Fi library
  2. #include <WiFi.h>
  3.  
  4.  
  5. // Replace with your network credentials
  6. const char* ssid     = "ESP32-Access-Point"; //name for arduino WiFi
  7. const char* password = "123456789"; //password for arduino WiFi
  8. int max_connection = 1; //max. number of simultaneous clients
  9.  
  10. // Set web server port number to 80
  11. WiFiServer server(80);
  12.  
  13. // Variable to store the HTTP request
  14. String incomingrequest;
  15.  
  16.  
  17. #define PIN_LED   4   //Pin 4 is flash LED
  18. #define CHN       0   //select PWM channel
  19. #define FRQ       1000  //select PWM frequency (Hz)
  20. #define PWM_BIT   8     //select PWM accuracy (8-Bit is 0-255, 0 = 0% and 255 = 100%)
  21.  
  22. void setup() {
  23.   Serial.begin(115200);
  24.  
  25.   ledcSetup(CHN, FRQ, PWM_BIT); //setup pwm channel
  26.   ledcAttachPin(PIN_LED, CHN);  //attach the led pin to pwm channel
  27.  
  28.   // Connect to Wi-Fi network with SSID and password
  29.   Serial.print("Setting AP (Access Point)…");
  30.   // Remove the password parameter, if you want the AP (Access Point) to be open
  31.   WiFi.softAP(ssid, password, max_connection);
  32.  
  33.   IPAddress IP(192, 168, 4, 2); //preset arduino IP address
  34.     IPAddress NMask(255, 255, 255, 0);
  35.   WiFi.softAPConfig(IP, IP, NMask); //Configure ESP32 to apply the defined IP address from above
  36.   IPAddress local_IP = WiFi.softAPIP();
  37.   Serial.print("AP IP address: ");
  38.   Serial.println(local_IP);
  39.  
  40.   server.begin();
  41. }
  42.  
  43. void loop(){
  44.   WiFiClient client = server.available();   // Listen for incoming clients
  45.  
  46.   if (client) {                             // If a new client connects,
  47.     Serial.println("New Client.");          // print a message out in the serial port
  48.     String currentLine = "";                // make a String to hold incoming data from the client
  49.     while (client.connected()) {            // loop while the client's connected
  50.       if (client.available()) {             // if there's bytes to read from the client,
  51.         char c = client.read();             // read a byte, then
  52.         Serial.write(c);                    // print it out the serial monitor
  53.         incomingrequest += c;
  54.         if (c == '\n') {                    // if the byte is a newline character
  55.           // if the current line is blank, you got two newline characters in a row.
  56.           // that's the end of the client HTTP request, so send a response:
  57.           if (currentLine.length() == 0) {
  58.             // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
  59.             // and a content-type so the client knows what's coming, then a blank line:
  60.             client.println("HTTP/1.1 200 OK");
  61.             client.println("Content-type:text/html");
  62.             client.println("Connection: close");
  63.             client.println();
  64.            
  65.            
  66.             // controls the LED brightness depending on the requested URL e.g. http://192.168.4.2/LED/value127 = LED brightness value 127/255
  67.             if (incomingrequest.indexOf("GET /LED/value") >= 0) {
  68.               Serial.println(incomingrequest); //http request is e.g. "GET /LED/value127 HTTP/1.1"
  69.               int urllength = incomingrequest.length(); //urllength is length value of incoming request
  70.               int endofbrightnessvalue = urllength - 9; //" HTTP/1.1" is cut, it's the last 9 digits
  71.               String brightnessvalue = incomingrequest.substring(14,endofbrightnessvalue); //brightness value "127" is between digit #14 and end of string
  72.               Serial.println("LED brightness set to" + brightnessvalue); //"brightnessvalue" = "127" in this case
  73.               ledcWrite(CHN, brightnessvalue.toInt()); //LED brightness is set to value between 0 and 255
  74.             }  
  75.            
  76.             // The HTTP response ends with another blank line
  77.             client.println();
  78.             // Break out of the while loop
  79.             break;
  80.           } else { // if you got a newline, then clear currentLine
  81.             currentLine = "";
  82.           }
  83.         } else if (c != '\r') {  // if you got anything else but a carriage return character,
  84.           currentLine += c;      // add it to the end of the currentLine
  85.         }
  86.       }
  87.     }
  88.     // Clear the incomingrequest variable
  89.     incomingrequest = "";
  90.     // Close the connection
  91.     client.stop();
  92.     Serial.println("Client disconnected.");
  93.     Serial.println("");
  94.   }
  95. }

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!

User avatar
corz.org
Posts: 80
Joined: Fri Feb 03, 2023 10:44 pm
Location: Aberdeen
Contact:

Re: Combination of live streaming and HTTP request for ESP32

Postby corz.org » Tue Mar 21, 2023 12:28 pm

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.

noweare
Posts: 74
Joined: Tue Jul 02, 2019 11:35 am

Re: Combination of live streaming and HTTP request for ESP32

Postby noweare » Wed Mar 22, 2023 12:58 am

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 ?

Who is online

Users browsing this forum: No registered users and 58 guests