esp32cam & esp_camera_fb_return(fb) & jpeg glitch

GOT666
Posts: 6
Joined: Sun Nov 27, 2022 5:04 pm

esp32cam & esp_camera_fb_return(fb) & jpeg glitch

Postby GOT666 » Sun Dec 04, 2022 2:01 pm

Hello,
Can some one explain me why I need to return fb (esp_camera_fb_return(fb) ) AFTER using the buffer?
Give me nice (as esp32cam can) jpeg:

Code: Select all

static esp_err_t stream1_handler(httpd_req_t *req) {

  esp_err_t res = ESP_OK;
  res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
  httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  httpd_resp_set_hdr(req, "X-Framerate", "60");

  while (true)  {
    fb = esp_camera_fb_get();
    if (!fb) res = ESP_FAIL;
    _jpg_buf_len = fb->len;
    _jpg_buf = fb->buf;
    _timestamp.tv_sec = fb->timestamp.tv_sec;
    _timestamp.tv_usec = fb->timestamp.tv_usec;
    res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
    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);
    res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);

    esp_camera_fb_return(fb); // NO PROBLEM
    fb = NULL;
    _jpg_buf = NULL;

    if (res != ESP_OK) break;
  }
  return res;
}

Give me crappy jpeg:

Code: Select all

static esp_err_t stream1_handler(httpd_req_t *req) {

  esp_err_t res = ESP_OK;
  res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
  httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  httpd_resp_set_hdr(req, "X-Framerate", "60");

  while (true)  {
    fb = esp_camera_fb_get();
    if (!fb) res = ESP_FAIL;
    _jpg_buf_len = fb->len;
    _jpg_buf = fb->buf;
    _timestamp.tv_sec = fb->timestamp.tv_sec;
    _timestamp.tv_usec = fb->timestamp.tv_usec;
     esp_camera_fb_return(fb); //PROBLEM
    fb = NULL;
    res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
    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);
    res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);

    _jpg_buf = NULL;

    if (res != ESP_OK) break;
  }
  return res;
}
In my project i want to use sometime the same frame twice (one for the stream and one reduce size and compare after( take 100~400ms))
I try :

Code: Select all

size_t _jpg_buf_len;
size_t _jpg_buf_1_len;
uint8_t *_jpg_buf = NULL;
uint8_t *_jpg_buf_1= NULL;

Code: Select all

    fb = esp_camera_fb_get();
    if (!fb) res = ESP_FAIL;
    _jpg_buf_len = fb->len;
    _jpg_buf = fb->buf;
    _jpg_buf_1_len = fb->len;
    _jpg_buf_1 = fb->buf;

OR

    fb = esp_camera_fb_get();
    if (!fb) res = ESP_FAIL;
    _jpg_buf_len = fb->len;
    _jpg_buf = fb->buf;
    _jpg_buf_1_len = _jpg_buf_len;
    _jpg_buf_1 = _jpg_buf;

OR

   fb = esp_camera_fb_get();
    if (!fb) res = ESP_FAIL;
    _jpg_buf_len = fb->len;
    _jpg_buf = fb->buf;
    memcpy(_jpg_buf_1, _jpg_buf , _jpg_buf_len );
In all case, when i call esp_camera_fb_return(fb) the not yet used buffer give me a hazardus glitch frame.

For the moment i use multiple camera_fb for each fonction

Code: Select all

camera_fb_t *fb = NULL;
camera_fb_t *fb_1 = NULL;
But i lose in frame rate and power.

Merci

ESP_Sprite
Posts: 9727
Joined: Thu Nov 26, 2015 4:08 am

Re: esp32cam & esp_camera_fb_return(fb) & jpeg glitch

Postby ESP_Sprite » Mon Dec 05, 2022 6:01 am

esp_camera_fb_return tells the camera driver that it's free to re-use the memory associated for anything else it wants, including writing a new picture to it, so yeah, that'll show up as corruption; while you send out the old picture, the driver is already writing a new picture there.

GOT666
Posts: 6
Joined: Sun Nov 27, 2022 5:04 pm

Re: esp32cam & esp_camera_fb_return(fb) & jpeg glitch

Postby GOT666 » Mon Dec 05, 2022 10:00 am

ESP_Sprite wrote:
Mon Dec 05, 2022 6:01 am
esp_camera_fb_return tells the camera driver that it's free to re-use the memory associated for anything else it wants, including writing a new picture to it, so yeah, that'll show up as corruption; while you send out the old picture, the driver is already writing a new picture there.
Thanks
But i not sure to hunderstend:

Code: Select all

    camera_fb_t *fb = NULL;
    fb = esp_camera_fb_get();
    _jpg_buf_len = fb->len;
    _jpg_buf = fb->buf;
    esp_camera_fb_return(fb);
    fb = NULL;
Where ( or in what?) should i have to copy the frame buffer to keep it ?

ESP_Sprite
Posts: 9727
Joined: Thu Nov 26, 2015 4:08 am

Re: esp32cam & esp_camera_fb_return(fb) & jpeg glitch

Postby ESP_Sprite » Tue Dec 06, 2022 4:19 am

Code: Select all

_jpg_buf = fb->buf
This sets a _jpg_buf to a *pointer* to the framebuffer memory; the memory itself still is located in fb (and as such gets corrupted after you return it). You would have to memcpy() this data into a buffer of your own instead.

GOT666
Posts: 6
Joined: Sun Nov 27, 2022 5:04 pm

Re: esp32cam & esp_camera_fb_return(fb) & jpeg glitch

Postby GOT666 » Tue Dec 06, 2022 10:25 am

ESP_Sprite wrote:
Tue Dec 06, 2022 4:19 am
the memory itself still is located in fb
Ho...
I should copy the frame buffer in a pointer that i copy in another pointer.
Why i don't think about it ...

My new test code:

Code: Select all

 size_t buf_buf_len;
 uint8_t *buf_buf = NULL;

static esp_err_t stream3_handler(httpd_req_t *req) {
  size_t _jpg_buf_len;
  uint8_t *_jpg_buf = NULL;
  esp_err_t res = ESP_OK;
  res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
  httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  httpd_resp_set_hdr(req, "X-Framerate", "60");

  while (true)  {
    unsigned long debut = millis();
    fb = esp_camera_fb_get();
    if (!fb) res = ESP_FAIL;
    _jpg_buf_len = fb->len;
    _jpg_buf = fb->buf;
//    if(poursuite){    }
    buf_buf_len = _jpg_buf_len;
    buf_buf = (uint8_t*)malloc(buf_buf_len);
    unsigned long debut_memcpy = micros();
    memcpy( buf_buf, _jpg_buf, _jpg_buf_len);
    unsigned long fin_memcpy = micros();
    Serial.println((String)"the_memcpy: " + (fin_memcpy-debut_memcpy) + (String)" us");
    _timestamp.tv_sec = fb->timestamp.tv_sec;
    _timestamp.tv_usec = fb->timestamp.tv_usec;
    _jpg_buf = NULL;
    esp_camera_fb_return(fb);
    fb = NULL;
    res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
    size_t hlen = snprintf((char *)part_buf, 128, _STREAM_PART, buf_buf_len, _timestamp.tv_sec, _timestamp.tv_usec);
    res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
    res = httpd_resp_send_chunk(req, (const char *)buf_buf, buf_buf_len);

    free(buf_buf);
    buf_buf = NULL;
    unsigned long fin = millis();
    Serial.println((String)"the_while: " + (fin-debut) + (String)" ms");
    if (res != ESP_OK){
      _jpg_buf = NULL;
      esp_camera_fb_return(fb);
      fb = NULL;
      free(buf_buf);
      buf_buf = NULL;
      break;
    }
  }
  return res;
}
1600 * 1200 :
-> the_while: 286 ms
-> the_memcpy: 15060 us

800 * 600
-> the_while: 77 ms
-> the_memcpy: 3043 us

Now I hunderstend and can use my copied frame in other task .

My problem was :

Code: Select all

_jpg_buf = fb->buf;
The solution is :

Code: Select all

memcpy( buf_buf, _jpg_buf, _jpg_buf_len);
Merci beaucoup !

Who is online

Users browsing this forum: No registered users and 65 guests