Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!
  • Guest, before posting your code please take these rules into consideration:
    • It is required to use our BBCode feature to display your code. While within the editor click < / > or >_ and place your code within the BB Code prompt. This helps others with finding a solution by making it easier to read and easier to copy.
    • You can also use markdown to share your code. When using markdown your code will be automatically converted to BBCode. For help with markdown check out the markdown guide.
    • Don't share a wall of code. All we want is the problem area, the code related to your issue.


    To learn more about how to use our BBCode feature, please click here.

    Thank you, Code Forum.

JavaScript Can not figure out how streaming works

noweare

Active Coder
I am trying to figure out how the browser code is controlling the streaming of images from my server .
I am fairly new to web technologies, markup languages and javascript.

I am streaming images from a camera to a browser. To start the stream the user presses a button which executes javascript code
that populates an image elements source attribute. ie "192.168.1.23:81/stream" The streaming consists of sending data
frame by frame to the browser until steaming is stopped by the user by toggling the stream button.

The camera is made up of a microcontroller board with a camera attached and functions as the server.
The server is configured to continuously send a frame of image data to the browser until the stop button is activated on the browser.

There are other buttons and checkboxes on the browser to control things on the server but those things use a fetch command to
communicate with the server. The streaming does not use "fetch" to communicate with the server. It seems the stream starts
or stops when the src attribute is populated (start) or empty ("")(stopped).

So I am wondering how streaming actually works.

Only the stream uses port 81 everything else uses port 80.


Here are some code snippets

HTML Code

Code:
<div id="stream-container" class="image-container">
    <img id="stream" src="" crossorigin>
</div>

Javascript Code
Code:
var baseHost = document.location.origin          //location origin
var streamUrl = baseHost + ':81'                       //for inside the lan only
        
const stopStream = () => {
    window.stop();                                                             //stops images from loading
    streamButton.innerHTML = 'Start Stream';      //changes text on stream button
}

const startStream = () => {
    view.src = `${streamUrl}/stream`;                      //assigns uri the source of the image frames
    streamButton.innerHTML = 'Stop Stream';             //change text on stream btn
}

//triggers streaming on server
streamButton.onclick = () => {
    const streamEnabled = streamButton.innerHTML === 'Stop Stream'   //change text on stream btn
    if (streamEnabled) {       
        stopStream();
    } else
        startStream();
}
 
Solution
I have a feeling it has to be done behind the scenes in the browser because the src is inside an image tag. I think it has to do with how the images are updated once a valid source exists, that is the only thing that makes sense.
Thinking about it, setting the src attribute of the image does send a request to the server. Normally that is just to fetch the image. In this case the "image name" is ${streamUrl}/stream, and the server interprets this as a request to start the stream server. That is probably in the code you left out.
You should be seeing that request in the debugger's Network tab.
This is very interesting to me. I am looking alternative ways to access photos and videos on my smartphone, because accessing the files from Windows Explorer is excruciatingly slow (it will probably remain so whatever method I use, but you never know).

But from these little JS snippets it is impossible for me to gauge how this works. Why setting the src attribute of some element on the browser would trigger your server to start sending (or your browser to start receiving ?) is beyond me. What does the server code look like anyway ? That is rather a black box here. You may want to provide more detailed information, full client code for a start.
 
It is very interesting to me too because I doubt very much this can all be done in the background. I will try to dig deeper into
this mystery.


But here is the server side code which is just a microcontroller with a camera as a peripheral, an esp32.

This is the code that registers the uri and what handler to call. I am omitting some of the functionality from other
Code:
void startCameraServer() //
{
  httpd_config_t config = HTTPD_DEFAULT_CONFIG(); // default http server configuration
  config.max_uri_handlers = 16;

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

  httpd_uri_t cmd_uri =
      {
          .uri = "/control",
          .method = HTTP_GET,
          .handler = cmd_handler,
          .user_ctx = NULL
      };

  httpd_uri_t capture_uri =
      {
          .uri = "/capture",
          .method = HTTP_GET,
          .handler = capture_handler,
          .user_ctx = NULL
      };

  httpd_uri_t stream_uri = {
      .uri = "/stream",
      .method = HTTP_GET,
      .handler = stream_handler,
      .user_ctx = NULL
}
  httpd_uri_t win_uri = {
      .uri = "/resolution",
      .method = HTTP_GET,
      .handler = win_handler,
      .user_ctx = NULL
  };

  ra_filter_init(&ra_filter, 20);

  log_i("Starting web server on port: '%d'", config.server_port);

  if (httpd_start(&camera_httpd, &config) == ESP_OK)
  {
    httpd_register_uri_handler(camera_httpd, &index_uri);
    httpd_register_uri_handler(camera_httpd, &cmd_uri);
    httpd_register_uri_handler(camera_httpd, &capture_uri);
    httpd_register_uri_handler(camera_httpd, &win_uri);
  }

  config.server_port += 1;
  log_i("Starting stream server on port: '%d'", config.server_port);
  config.ctrl_port += 1;
  log_i("Starting control server on port: '%d'", config.ctrl_port);
  if (httpd_start(&stream_httpd, &config) == ESP_OK)
  {
    httpd_register_uri_handler(stream_httpd, &stream_uri);
  }
}

Here is the stream handler
Code:
static esp_err_t stream_handler(httpd_req_t *req)
{
  camera_fb_t *fb = NULL;
  struct timeval _timestamp;
  esp_err_t res = ESP_OK;
  size_t _jpg_buf_len = 0;
  uint8_t *_jpg_buf = NULL;
  char *part_buf[128];
  static int64_t last_frame = 0;
  
  res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);  // header that sets the content type of the response
  if (res != ESP_OK)
  {
    return res;
  }
  httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  httpd_resp_set_hdr(req, "X-Framerate", "60");
  last_frame = esp_timer_get_time();

  while (true)
  {
    fb = esp_camera_fb_get();
    if (!fb)
    {
      log_e("Camera capture failed");
      res = ESP_FAIL;                               
    }
    else
    {
      _timestamp.tv_sec = fb->timestamp.tv_sec;
      _timestamp.tv_usec = fb->timestamp.tv_usec;

      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)
        {
          log_e("JPEG compression failed");
          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, 128, _STREAM_PART, _jpg_buf_len, _timestamp.tv_sec, _timestamp.tv_usec);
      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)
    {
      esp_camera_fb_return(fb);
      fb = NULL;
      _jpg_buf = NULL;
    }
    else if (_jpg_buf)
    {
      free(_jpg_buf);
      _jpg_buf = NULL;
    }
    if (res != ESP_OK)
    {
      log_e("Send frame failed");
      break;                                                //here we break out of the while loop if there was an error
    }
    
    int64_t fr_end = esp_timer_get_time(); // gets time in usec since boot
    uint32_t elapsed_time = (uint32_t)fr_end - (uint32_t)last_frame;
    log_i("%u, %.1f fps)\n", elapsed_time, (float)1000000 / elapsed_time);
    last_frame = fr_end;
 
  }
  return res;
}
 
It looks like a button click starts the stream handler, which sits in a loop getting frames from the camera, compressing them, and sending them as a simple HTTP response to the client
 
This code is as clear as it can be without knowledge of the ESP's camera API. So as you wrote, it is simply writing each frame to the HTPP channel. It is still not clear to me how exactly the client JS code starts the server and stream handler. I suppose it's by posting a message to one of the other handler uri's
(control ?) but it's all a bit fuzzy.
My question now is, do you have actual problem with this or does it work but you are just wondering (like I am) how it all hangs together ? Perhaps I would understand more if you posted the complete code of both client and server. Not having an ESP, I can't of course do any experimenting. Or is there maybe some ESP emulator for Windows ?
Edit - I see there are several emulators available. I'm not sure I want to go and embark on this journey though...
 
It looks like a button click starts the stream handler, which sits in a loop getting frames from the camera, compressing them, and sending them as a simple HTTP response to the client
How does the browser communicate with the server to start streaming? I see how the server communicates with the client but not how the client communicates with the server to start/stop streaming.
 
Last edited:
This code is as clear as it can be without knowledge of the ESP's camera API. So as you wrote, it is simply writing each frame to the HTPP channel. It is still not clear to me how exactly the client JS code starts the server and stream handler. I suppose it's by posting a message to one of the other handler uri's
(control ?) but it's all a bit fuzzy.
My question now is, do you have actual problem with this or does it work but you are just wondering (like I am) how it all hangs together ? Perhaps I would understand more if you posted the complete code of both client and server. Not having an ESP, I can't of course do any experimenting. Or is there maybe some ESP emulator for Windows ?
Edit - I see there are several emulators available. I'm not sure I want to go and embark on this journey though...

The system works perfectly. I am getting around 24 frames/sec on 640 x 480 resolution. It is a lot of code to go through especially if you can not duplicate it. Plus it would be a lot of time on your part.

I used the developer tools to step through the browser code and it doesn't go any further than just changing the src attribute and magically the stream starts. I don't hit the set point again until I hit the button to stop the stream and hit it again to start. Using dev tools when I do anything that is assigned port 80 uses the fetch command.

I have a feeling it has to be done behind the scenes in the browser because the src is inside an image tag. I think it has to do with how the images are updated once a valid source exists, that is the only thing that makes sense.
 
I have a feeling it has to be done behind the scenes in the browser because the src is inside an image tag. I think it has to do with how the images are updated once a valid source exists, that is the only thing that makes sense.
Thinking about it, setting the src attribute of the image does send a request to the server. Normally that is just to fetch the image. In this case the "image name" is ${streamUrl}/stream, and the server interprets this as a request to start the stream server. That is probably in the code you left out.
You should be seeing that request in the debugger's Network tab.
 
Solution
Thinking about it, setting the src attribute of the image does send a request to the server. Normally that is just to fetch the image. In this case the "image name" is ${streamUrl}/stream, and the server interprets this as a request to start the stream server. That is probably in the code you left out.
You should be seeing that request in the debugger's Network tab.
I wish it was in the code I left out then I could mark this thread "problem solved" I would of seen that code get executed using the debugger. The server is getting a request but I don't know how that's being done.


Here is all the html,css and js. Only elements with class ="default-action" use fetch to communicate with the server.

Code:
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>ESP32 CAMERA</title>
    <style>
        body {
            font-family: Arial, Helvetica, sans-serif;
            background: black;
            color: white;
            /*border:2px solid white;*/
        }

        .main {
            margin: 30px;
        }

        .container {
            display: flex;
            flex-wrap: wrap;
            width: 75%;
            align-items: center;
             border: 2px solid green;
              justify-content: space-between;
              padding: 5px;
        }

        button {
            height: 40px;
            width: 120px;
            font-size: 14px;
            background-color: rgba(255, 255, 255, 0.56);
            border: 2px solid green;
            /*padding:20px;*/
            margin: 5px;
        }

        #framesize:hover,
        button:hover {
            background-color: white;
            cursor: pointer;
        }

        #framesize {
            padding: 8px;
            font-size: 14px;
            background-color: rgba(255, 255, 255, 0.56);
        }

        a:link {
            font-family: Arial, Helvetica, sans-serif;
            text-decoration: none;
            padding: 11px 32px;
            background-color: rgba(255, 255, 255, 0.56);
            font-size: 14px;
            cursor: pointer;
            margin-left: 4px;
            border: 2px solid green;
        }

        a:hover {
            background-color: white;
        }


        #stream {
            margin-top: 15px;
            border: 3px solid blue;
        }
       
    </style>
</head>

<body>
    <section class="main">
        <label style=color:yellow>OV2640 CAMERA</label>
        <br>
        <br>
        <div class='container'>

            <div id="content">
                <!---label id="mylabel">Resolution</label -->
                <select id="framesize" class="default-action">
                    <option value="9">SVGA(800x600)</option>
                    <option value="8">VGA(640x480)</option>
                    <option value="7" selected>HVGA(480x320)</option> <!-- default -->
                    <option value="5">QVGA(320x240)</option>
                    <option value="4">240x240</option>
                </select>
            </div>

            <div>
                <label for="hmirror">H-Mirror</label>
                <div class="switch">
                    <input id="hmirror" type="checkbox" class="default-action" checked="checked">
                    <!--label class="slider" for="hmirror"></label> !--dont know what this is-->
                </div>
            </div>

            <div>
                <label for="vflip">V-Flip</label>
                <div class="switch">
                    <input id="vflip" type="checkbox" class="default-action" checked="checked">
                </div>
            </div>

            <div>
                <label for="panServo">Pan</label>
                <!--div class="range-min">250</div--->
                <input type="range" id="panServo" min="250" max="400" value="250" class="default-action">
                <!--div ="range-max">400</div-->
            </div>

            <div>
                <label for="tiltServo">Tilt</label>
                <!--div class="range-min">225</div-->
                <input type="range" id="tiltServo" min="225" max="370" value="225" class="default-action">
                <!--div class="range-max">370</div-->
            </div>

            <nav>
                <button id="get-still">Get Still</button>
                <button id="toggle-stream">Start Stream</button>
                <button id="light" type="button" value="0">light On</button>
                <!--button id="save-button">Save Still</button-->
                <a style="color:black" id="save-still" href="#" download="capture.jpg">Save Still</a>
            </nav>

            <div>
                <p id="status">-</p>
            </div>
        </div> <!-- container -->

        <div id="stream-container" class="image-container">
            <!--img id="stream" src="snowman.jpg" height="500px" width="400px"-->
            <img id="stream" loading="lazy" crossorigin>
        </div>

    </section>
    <script>

        var baseHost = document.location.origin        //location origin is esp32 (192.168.1.7)
        var streamUrl = baseHost + ':81'                     //for internal use only
      
        window.console.log(streamUrl); 
        window.console.log(baseHost); 
      
        const view = document.getElementById('stream');
        const viewContainer = document.getElementById('stream-container');
        const stillButton = document.getElementById('get-still');
        const streamButton = document.getElementById('toggle-stream');
        const saveButton = document.getElementById('save-still');
        const lightButton = document.getElementById('light');
        const statusMsg = document.getElementById('status');

        console.log(window.frames[0]
        );

        const stopStream = () => {
            //window.stop();
            view.src = ``;                                          //stops images from loading
            streamButton.innerHTML = 'Start Stream';      //changes text on stream btn
        }

        const startStream = () => {
            view.src = `${streamUrl}/stream`;                      //assigns url to view.src, the source of the frame
            streamButton.innerHTML = 'Stop Stream';             //change text on stream btn
        }

        //run when an element with class="default-action" is changed, stream does not have a class of default-action
        document.querySelectorAll('.default-action')
            .forEach(el => {
                el.onchange = () => updateConfig(el);
            })

        function updateConfig(el) {
            console.log("updateConfig");   //this is used
            console.log(el);               //log which element is being configured
            console.log(el.type);
            console.log(el.value);
            let value;
            switch (el.type) {
                case 'checkbox':
                    value = el.checked ? 1 : 0;
                    break;
                case 'range':
                case 'select-one':
                    value = el.value;
                    break;
                case 'button':
                    value = el.value;
                    break;
                default:
                    return;
            }

            /* builds query to be send to esp32 */
            const query = `${baseHost}/control?var=${el.id}&val=${value}`;
            console.log(query);
            fetch(query)
                .then(response => {
                         if (el.id == 'motor')
                        statusMsg.innerHTML = 'Motor Error';
                })

        }//updateConfig


        // Attach actions to buttons
        stillButton.onclick = () => {
            stopStream();
            view.src = `${baseHost}/capture?_cb=${Date.now()}`;

        }

        //triggers streaming from esp32
        streamButton.onclick = () => {
            const streamEnabled = streamButton.innerHTML === 'Stop Stream'   //change text on stream btn
            //console.log('stream btn click')
            if (streamEnabled) {       //call appropriate function
                stopStream();
            } else
                startStream();
        }

        const framesize = document.getElementById('framesize');

        framesize.onchange = () => {
            updateConfig(framesize);
            console.log('frame-onchange');
        }


        lightButton.onclick = () => {
            if (lightButton.innerHTML == 'light On') {
                lightButton.innerHTML = 'light Off';
                lightButton.value = '1';
            } else {
                lightButton.innerHTML = 'light On';
                lightButton.value = '0';
            }
            updateConfig(lightButton);
        }

        saveButton.onclick = () => {
            var canvas = document.createElement("canvas");
            canvas.width = view.width;
            canvas.height = view.height;
            document.body.appendChild(canvas);
            var context = canvas.getContext('2d');
            context.drawImage(view, 0, 0);
            try {
                var dataURL = canvas.toDataURL('image/jpeg');
                saveButton.href = dataURL;
                var d = new Date();
                  saveButton.download = d.getFullYear() + ("0" + (d.getMonth() + 1)).slice(-2) + ("0" + d.getDate()).slice(-2) + ("0" + d.getHours()).slice(-2) + ("0" + d.getMinutes()).slice(-2) + ("0" + d.getSeconds()).slice(-2) + ".jpg";
            } catch (e) {
                console.error(e);
            }
            canvas.parentNode.removeChild(canvas);
        }

  </script>
</body>
</html>

    </script>

</body>

</html>
 
I wish it was in the code I left out then I could mark this thread "problem solved" I would of seen that code get executed using the debugger. The server is getting a request but I don't know how that's being done.
I'm not sure how you can see server-side code being executed using "the debugger". Which debugger would that be ? Does the ESP have its own debugger ? It seems to be running some dialect of C/C++, which is alien to the browser.

As to how the server is getting the request, see image. When you click the 'Start' button, the browser sends a GET request for the stream URL. Obviously in my case that triggers an error, but that is not the point here. There just isn't anything more to be seen in the browser's debugger.

Somewhere in the server the request will be picked up and translated into the appropriate action. But you won't see that in your code, I realize now. Because the action to start the stream handler is implicit, and handle by the ESP's web server :

C-like:
httpd_uri_t stream_uri = {
      .uri = "/stream",
      .method = HTTP_GET,
      .handler = stream_handler,
      .user_ctx = NULL
}

I guess this could be the missing piece of the puzzle ?

1712388870600.png
 
I was talking about using the debugger in dev tools on the browser to see how the get request gets initialed. You thought maybe the
answer was in the code i left out. I thought you meant browser code I did not include in my post.

Like you said the get request is done in the background by the browser when the src attribute of the image element is populated. I didn't know that until I used Network tab in dev tools (F12] where I can see the requests and the response.

In the stream handler code on the server (esp32) the "Stream Content type" header = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY" is part of the response to the stream request from the browser.

That header tells the browser that it will pushing images to the browser without having the browser ask for the next image. Each image frame is sent with a "stream boundary" letting the browser know that it is a new image, along with other headers. It is also referred to as "server push"

This happens until widow.stop() command (javascript) or image src attribute (html) is populated with an empty string ("").

Hopefully how the browser works will become more clear to me as I use web technologies with devices that can connect to the web.

You are correct about how the esp32 works. The server has to be set up, handlers appoints to the proper uri's etc... Headers have to be correct for what ever your doing etc... I will need to work on what headers are needed for different requests, responses. A lot to figure out as I learn this stuff.

Post Script
I found this on wikipedia
" Another mechanism is related to a special MIME type called multipart/x-mixed-replace , Web browsers interpret this as a document that changes whenever the server pushes a new version to the client.It is still supported by Firefox, Opera, Safari, today, but it is ignored by Internet Explorer and is only partially supported by Chrome.It can be applied to HTML documents, and also for streaming images in webcam applications.
 
Last edited:
Seems to be all clear now, does it not ? If so, you can mark the issue solved.
Now could you tell me more about the configuration ? You using localhost:80 and 81 makes me think you are using an ESP emulator on your local machine, am I right ? And how exactly does the ESP or emulator connect to the camera ? This is of particular interest to me because accessing my smartphone's Camera folder from Windows Explorer is like watching paint dry, and so is using the C# library I use to do this programmatically. Not sure if it's Samsung or Microsoft to blame, but either way it sucks so I'll consider any alternative ( darn, why do I need to keep all photos and videos of my grandchildren 🙄 )
 
Seems to be all clear now, does it not ? If so, you can mark the issue solved.
Now could you tell me more about the configuration ? You using localhost:80 and 81 makes me think you are using an ESP emulator on your local machine, am I right ? And how exactly does the ESP or emulator connect to the camera ? This is of particular interest to me because accessing my smartphone's Camera folder from Windows Explorer is like watching paint dry, and so is using the C# library I use to do this programmatically. Not sure if it's Samsung or Microsoft to blame, but either way it sucks so I'll consider any alternative ( darn, why do I need to keep all photos and videos of my grandchildren 🙄 )
Clear enough to move on I think : ). That was kind of a rabbit hole . Thanks for your help. You are very knowledgeable so it has been nice to meet you.

Not using an emulator. The esp32 is part of my LAN once it connects to wifi and is issued an ip address by my router. I've attached the pinout of the esp32. The pins that the camera uses are in blue (CAM_*). I can connect the camera to the web by using software called "Caddy" it allows me to access the camera from outside my LAN securly.

I am still developing some projects around the camera but I needed to take a break and learn some html, css and js, since connectivity over the web will be pretty cool and I like to make my projects look good.

Thanks for your help and let me know what projects you are working on. I am impressed by the cool graphics project you did. I like that stuff.
 

Attachments

  • ESP32_Pinout.png
    ESP32_Pinout.png
    241.3 KB · Views: 2
Last edited:
Clear enough to move on I think : ). That was kind of a rabbit hole . Thanks for your help. You are very knowledgeable so it has been nice to meet you.

Not using an emulator. The esp32 is part of my LAN once it connects to wifi and is issued an ip address by my router. I've attached the pinout of the esp32. The pins that the camera uses are in blue (CAM_*). I can connect the camera to the web by using software called "Caddy" it allows me to access the camera from outside my LAN securly.

I am still developing some projects around the camera but I needed to take a break and learn some html, css and js, since connectivity over the web will be pretty cool and I like to make my projects look good.

Thanks for your help and let me know what projects you are working on. I am impressed by the cool graphics project you did. I like that stuff.
Glad I could help a bit. Still puzzled that you use localhost ports 80 and 81. Usually these are used by your local webserver such as IIS or Apache. I would have thought that your ESP would have its own IP address. Anyway, looking at that pinout which goes right over my head, I decided right away not to bother with microcontrollers. I'm strictly a software guy 😊
 
Glad I could help a bit. Still puzzled that you use localhost ports 80 and 81. Usually these are used by your local webserver such as IIS or Apache. I would have thought that your ESP would have its own IP address. Anyway, looking at that pinout which goes right over my head, I decided right away not to bother with microcontrollers. I'm strictly a software guy 😊
I'm not using localhost. The microcontroller is on my LAN with an address of 192.168.86.30 I'm sure you would pick up microcontrollers pretty quickly. They have a lot more resources (ram, flash) now such that you can program them in python and even javascript.
 
I'm not using localhost. The microcontroller is on my LAN with an address of 192.168.86.30 I'm sure you would pick up microcontrollers pretty quickly. They have a lot more resources (ram, flash) now such that you can program them in python and even javascript.
Oh ok. These lines
JavaScript:
var baseHost = document.location.origin        //location origin is esp32 (192.168.1.7)
        var streamUrl = baseHost + ':81'                     //for internal use only
lead me to suspect localhost, especially because the IP address is only mentioned in the comment.
But of course document.location does not imply localhost. Silly me.

So how exactly does the camera connect to the ESP ? The pinout does not explain that to me. I'd expect a camera to connect via USB, Bluetooth or LAN.
 
Oh ok. These lines
JavaScript:
var baseHost = document.location.origin        //location origin is esp32 (192.168.1.7)
        var streamUrl = baseHost + ':81'                     //for internal use only
lead me to suspect localhost, especially because the IP address is only mentioned in the comment.
But of course document.location does not imply localhost. Silly me.

So how exactly does the camera connect to the ESP ? The pinout does not explain that to me. I'd expect a camera to connect via USB, Bluetooth or LAN.
The camera itself connects through a connector built on the esp32 board, so it is hard wired. So you could think of the whole thing as the "camera" . Then you would connect to it via wifi to a LAN I guess one could connect via BT but I have not. There are example programs that streams frames to a website. That is what I started with for my project.

At this point I think you could probably find examples written in python for the camera. Definitely examples in C. I heard it is capable of doing some machine vision but I think that's pushing it. There are a few different versions of the camera board with different sizes, with
or without sd card, usb or no usb etc ...

Link -> Freenove Esp32 camera
 
The camera is an Ov2640, 2 Mega Pixel sensor. It is really a camera sensor module, not a full blown complete stand alone camera. I think that's what you are thinking, like a webcam or security camera. The camera module plugs into the esp32 board. The esp32 provides the software that sets up the camera by writing to its registers to configure it and control it, The camera module spits out the frame data which is then stored in the esp32 memory . So once a frame is complete it can be displayed by sending it to a webpage or written or written to a display. Sounds scary but the example code makes
it a lot easier. Hope that helps. I am not that good at explaining things as you can see, : )
 

New Threads

Buy us a coffee!

Back
Top Bottom