From b94b98124e45583f3236716cd99e2a0bc30a7a3a Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Wed, 16 Jun 2021 13:48:18 +0300 Subject: [PATCH] fix grayscale mode Fixes https://github.com/espressif/esp32-camera/issues/276 --- driver/cam_hal.c | 36 ++++++++++++++++++++++++--------- target/esp32/ll_cam.c | 4 ++-- target/esp32s2/ll_cam.c | 17 +++++++++++++++- target/esp32s3/ll_cam.c | 19 +++++++++++++++-- target/private_include/ll_cam.h | 3 ++- 5 files changed, 64 insertions(+), 15 deletions(-) diff --git a/driver/cam_hal.c b/driver/cam_hal.c index bd2dcd2..7fd17c3 100644 --- a/driver/cam_hal.c +++ b/driver/cam_hal.c @@ -29,6 +29,14 @@ static int cam_verify_jpeg_soi(const uint8_t *inbuf, uint32_t length) { uint32_t sig = *((uint32_t *)inbuf) & 0xFFFFFF; if(sig != JPEG_SOI_MARKER) { + for (uint32_t i = 0; i < length; i++) { + sig = *((uint32_t *)(&inbuf[i])) & 0xFFFFFF; + if (sig == JPEG_SOI_MARKER) { + ESP_LOGW(TAG, "SOI: %d", i); + return i; + } + } + ESP_LOGW(TAG, "NO-SOI"); return -1; } return 0; @@ -42,6 +50,7 @@ static int cam_verify_jpeg_eoi(const uint8_t *inbuf, uint32_t length) uint16_t sig = *((uint16_t *)dptr); if (JPEG_EOI_MARKER == sig) { offset = dptr - inbuf; + //ESP_LOGW(TAG, "EOI: %d", length - (offset + 2)); return offset; } dptr--; @@ -117,16 +126,17 @@ static void cam_task(void *arg) case CAM_STATE_READ_BUF: { camera_fb_t * frame_buffer_event = &cam_obj->frames[frame_pos].fb; + size_t pixels_per_dma = (cam_obj->dma_half_buffer_size * cam_obj->fb_bytes_per_pixel) / (cam_obj->dma_bytes_per_item * cam_obj->in_bytes_per_pixel); if (cam_event == CAM_IN_SUC_EOF_EVENT) { if(!cam_obj->psram_mode){ - if (cam_obj->recv_size < (frame_buffer_event->len + (cam_obj->dma_half_buffer_size / cam_obj->dma_bytes_per_item))) { + if (cam_obj->fb_size < (frame_buffer_event->len + pixels_per_dma)) { ESP_LOGW(TAG, "FB-OVF"); ll_cam_stop(cam_obj); DBG_PIN_SET(0); continue; } - frame_buffer_event->len += ll_cam_memcpy( + frame_buffer_event->len += ll_cam_memcpy(cam_obj, &frame_buffer_event->buf[frame_buffer_event->len], &cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size], cam_obj->dma_half_buffer_size); @@ -135,7 +145,6 @@ static void cam_task(void *arg) if (cam_obj->jpeg_mode && cnt == 0 && cam_verify_jpeg_soi(frame_buffer_event->buf, frame_buffer_event->len) != 0) { ll_cam_stop(cam_obj); cam_obj->state = CAM_STATE_IDLE; - ESP_LOGW(TAG, "NO-SOI"); } cnt++; @@ -146,11 +155,11 @@ static void cam_task(void *arg) if (cnt || !cam_obj->jpeg_mode || cam_obj->psram_mode) { if (cam_obj->jpeg_mode) { if (!cam_obj->psram_mode) { - if (cam_obj->recv_size < (frame_buffer_event->len + (cam_obj->dma_half_buffer_size / cam_obj->dma_bytes_per_item))) { + if (cam_obj->fb_size < (frame_buffer_event->len + pixels_per_dma)) { ESP_LOGW(TAG, "FB-OVF"); cnt--; } else { - frame_buffer_event->len += ll_cam_memcpy( + frame_buffer_event->len += ll_cam_memcpy(cam_obj, &frame_buffer_event->buf[frame_buffer_event->len], &cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size], cam_obj->dma_half_buffer_size); @@ -168,9 +177,9 @@ static void cam_task(void *arg) frame_buffer_event->len = cam_obj->recv_size; } } else if (!cam_obj->jpeg_mode) { - if (frame_buffer_event->len != cam_obj->recv_size) { + if (frame_buffer_event->len != cam_obj->fb_size) { cam_obj->frames[frame_pos].en = 1; - ESP_LOGE(TAG, "FB-SIZE: %u != %u", frame_buffer_event->len, cam_obj->recv_size); + ESP_LOGE(TAG, "FB-SIZE: %u != %u", frame_buffer_event->len, cam_obj->fb_size); } } //send frame @@ -242,14 +251,18 @@ static esp_err_t cam_dma_config() CAM_CHECK(cam_obj->frames != NULL, "frames malloc failed", ESP_FAIL); uint8_t dma_align = 0; + size_t fb_size = cam_obj->fb_size; if (cam_obj->psram_mode) { dma_align = ll_cam_get_dma_align(cam_obj); + if (cam_obj->fb_size < cam_obj->recv_size) { + fb_size = cam_obj->recv_size; + } } for (int x = 0; x < cam_obj->frame_cnt; x++) { cam_obj->frames[x].dma = NULL; cam_obj->frames[x].fb_offset = 0; cam_obj->frames[x].en = 0; - cam_obj->frames[x].fb.buf = (uint8_t *)heap_caps_malloc(cam_obj->recv_size * sizeof(uint8_t) + dma_align, MALLOC_CAP_SPIRAM); + cam_obj->frames[x].fb.buf = (uint8_t *)heap_caps_malloc(fb_size * sizeof(uint8_t) + dma_align, MALLOC_CAP_SPIRAM); CAM_CHECK(cam_obj->frames[x].fb.buf != NULL, "frame buffer malloc failed", ESP_FAIL); if (cam_obj->psram_mode) { //align PSRAM buffer. TODO: save the offset so proper address can be freed later @@ -323,8 +336,10 @@ esp_err_t cam_config(const camera_config_t *config, framesize_t frame_size, uint if(cam_obj->jpeg_mode){ cam_obj->recv_size = cam_obj->width * cam_obj->height / 5; + cam_obj->fb_size = cam_obj->recv_size; } else { - cam_obj->recv_size = cam_obj->width * cam_obj->height * 2; + cam_obj->recv_size = cam_obj->width * cam_obj->height * cam_obj->in_bytes_per_pixel; + cam_obj->fb_size = cam_obj->width * cam_obj->height * cam_obj->fb_bytes_per_pixel; } ret = cam_dma_config(); @@ -431,6 +446,9 @@ camera_fb_t *cam_take(TickType_t timeout) cam_give(dma_buffer); return cam_take(timeout - (xTaskGetTickCount() - start));//recurse!!!! } + } else if(cam_obj->psram_mode && cam_obj->in_bytes_per_pixel != cam_obj->fb_bytes_per_pixel){ + //currently this is used only for YUV to GRAYSCALE + dma_buffer->len = ll_cam_memcpy(cam_obj, dma_buffer->buf, dma_buffer->buf, dma_buffer->len); } return dma_buffer; } else { diff --git a/target/esp32/ll_cam.c b/target/esp32/ll_cam.c index 4840878..92931a1 100644 --- a/target/esp32/ll_cam.c +++ b/target/esp32/ll_cam.c @@ -138,7 +138,7 @@ static size_t IRAM_ATTR ll_cam_dma_filter_grayscale_highspeed(uint8_t* dst, cons dst[1] = dma_el[2].sample1; elements += 1; } - return elements * 2; + return elements / 2; } static size_t IRAM_ATTR ll_cam_dma_filter_yuyv(uint8_t* dst, const uint8_t* src, size_t len) @@ -451,7 +451,7 @@ void ll_cam_dma_sizes(cam_obj_t *cam) static dma_filter_t dma_filter = ll_cam_dma_filter_jpeg; -size_t IRAM_ATTR ll_cam_memcpy(uint8_t *out, const uint8_t *in, size_t len) +size_t IRAM_ATTR ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, size_t len) { //DBG_PIN_SET(1); size_t r = dma_filter(out, in, len); diff --git a/target/esp32s2/ll_cam.c b/target/esp32s2/ll_cam.c index 35d8beb..682642d 100644 --- a/target/esp32s2/ll_cam.c +++ b/target/esp32s2/ll_cam.c @@ -344,8 +344,23 @@ void ll_cam_dma_sizes(cam_obj_t *cam) } } -size_t ll_cam_memcpy(uint8_t *out, const uint8_t *in, size_t len) +size_t ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, size_t len) { + // YUV to Grayscale + if (cam->in_bytes_per_pixel == 2 && cam->fb_bytes_per_pixel == 1) { + size_t end = len / 8; + for (size_t i = 0; i < end; ++i) { + out[0] = in[0]; + out[1] = in[2]; + out[2] = in[4]; + out[3] = in[6]; + out += 4; + in += 8; + } + return len / 2; + } + + // just memcpy memcpy(out, in, len); return len; } diff --git a/target/esp32s3/ll_cam.c b/target/esp32s3/ll_cam.c index 3d7eda2..b991a49 100644 --- a/target/esp32s3/ll_cam.c +++ b/target/esp32s3/ll_cam.c @@ -264,7 +264,7 @@ void ll_cam_do_vsync(cam_obj_t *cam) uint8_t ll_cam_get_dma_align(cam_obj_t *cam) { - return 64;//16 << GDMA.in[cam->dma_num].conf1.in_ext_mem_bk_size; + return 16 << GDMA.in[cam->dma_num].conf1.in_ext_mem_bk_size; } static void ll_cam_calc_rgb_dma(cam_obj_t *cam){ @@ -361,8 +361,23 @@ void ll_cam_dma_sizes(cam_obj_t *cam) } } -size_t ll_cam_memcpy(uint8_t *out, const uint8_t *in, size_t len) +size_t ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, size_t len) { + // YUV to Grayscale + if (cam->in_bytes_per_pixel == 2 && cam->fb_bytes_per_pixel == 1) { + size_t end = len / 8; + for (size_t i = 0; i < end; ++i) { + out[0] = in[0]; + out[1] = in[2]; + out[2] = in[4]; + out[3] = in[6]; + out += 4; + in += 8; + } + return len / 2; + } + + // just memcpy memcpy(out, in, len); return len; } diff --git a/target/private_include/ll_cam.h b/target/private_include/ll_cam.h index ae75919..abf0db0 100644 --- a/target/private_include/ll_cam.h +++ b/target/private_include/ll_cam.h @@ -114,6 +114,7 @@ typedef struct { uint16_t height; uint8_t in_bytes_per_pixel; uint8_t fb_bytes_per_pixel; + uint32_t fb_size; cam_state_t state; } cam_obj_t; @@ -128,7 +129,7 @@ esp_err_t ll_cam_init_isr(cam_obj_t *cam); void ll_cam_do_vsync(cam_obj_t *cam); uint8_t ll_cam_get_dma_align(cam_obj_t *cam); void ll_cam_dma_sizes(cam_obj_t *cam); -size_t ll_cam_memcpy(uint8_t *out, const uint8_t *in, size_t len); +size_t ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, size_t len); esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_t xclk_freq_hz, uint8_t sensor_pid); // implemented in cam_hal