From aa53cf2352416e222af0c3d54f164cbec64f0879 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Tue, 3 Apr 2018 22:08:53 +0200 Subject: [PATCH] Support H7 hardware JPEG encoder. --- src/omv/boards/OPENMV4/omv_boardconfig.h | 3 + src/omv/img/jpeg.c | 242 ++++++++++++++++++++++- src/omv/stm32fxxx_hal_msp.c | 5 + 3 files changed, 249 insertions(+), 1 deletion(-) diff --git a/src/omv/boards/OPENMV4/omv_boardconfig.h b/src/omv/boards/OPENMV4/omv_boardconfig.h index df6b42cc4..5f2884bd0 100644 --- a/src/omv/boards/OPENMV4/omv_boardconfig.h +++ b/src/omv/boards/OPENMV4/omv_boardconfig.h @@ -37,6 +37,9 @@ // RAW buffer size #define OMV_RAW_BUF_SIZE (409600) +// Enable hardware JPEG +#define OMV_HARDWARE_JPEG (1) + // If buffer size is bigger than this threshold, the quality is reduced. // This is only used for JPEG images sent to the IDE not normal compression. #define JPEG_QUALITY_THRESH (320*240*2) diff --git a/src/omv/img/jpeg.c b/src/omv/img/jpeg.c index 62c398470..28e5d65be 100644 --- a/src/omv/img/jpeg.c +++ b/src/omv/img/jpeg.c @@ -19,8 +19,247 @@ #include "fb_alloc.h" #include "ff_wrapper.h" #include "imlib.h" +#include "omv_boardconfig.h" #define TIME_JPEG (0) + +#if defined(OMV_HARDWARE_JPEG) + +#define MCU_W (8) +#define MCU_H (8) +#define JPEG_444_GS_MCU_SIZE (64) +#define JPEG_444_YCBCR_MCU_SIZE (192) +#define JPEG_422_YCBCR_MCU_SIZE (256) +#define JPEG_420_YCBCR_MCU_SIZE (384) + +typedef struct _jpeg_enc { + int img_w; + int img_h; + int img_bpp; + int mcu_row; + int mcu_size; + int out_size; + int x_offset; + int y_offset; + bool overflow; + image_t *img; + jpeg_subsample_t subsample; + union { + uint8_t *pixels8; + uint16_t *pixels16; + }; +} jpeg_enc_t; + +static uint8_t mcubuf[512]; +static jpeg_enc_t jpeg_enc; + +void bayer_blk_to_rgb565(image_t *img, int w, int h, int xoffs, int yoffs, uint16_t *rgbbuf) +{ + int r, g, b; + for (int y=yoffs; y (img->w-1) || y > (img->h-1) || x < 1 || y < 1) { + r = g = b = 0; + } else { + if ((y % 2) == 0) { // Even row + if ((x % 2) == 0) { // Even col + r = (IM_GET_RAW_PIXEL(img, x-1, y-1) + + IM_GET_RAW_PIXEL(img, x+1, y-1) + + IM_GET_RAW_PIXEL(img, x-1, y+1) + + IM_GET_RAW_PIXEL(img, x+1, y+1)) >> 2; + + g = (IM_GET_RAW_PIXEL(img, x, y-1) + + IM_GET_RAW_PIXEL(img, x, y+1) + + IM_GET_RAW_PIXEL(img, x-1, y) + + IM_GET_RAW_PIXEL(img, x+1, y)) >> 2; + + b = IM_GET_RAW_PIXEL(img, x, y); + } else { // Odd col + r = (IM_GET_RAW_PIXEL(img, x, y-1) + + IM_GET_RAW_PIXEL(img, x, y+1)) >> 1; + + b = (IM_GET_RAW_PIXEL(img, x-1, y) + + IM_GET_RAW_PIXEL(img, x+1, y)) >> 1; + + g = IM_GET_RAW_PIXEL(img, x, y); + } + } else { // Odd row + if ((x % 2) == 0) { // Even Col + r = (IM_GET_RAW_PIXEL(img, x-1, y) + + IM_GET_RAW_PIXEL(img, x+1, y)) >> 1; + + g = IM_GET_RAW_PIXEL(img, x, y); + + b = (IM_GET_RAW_PIXEL(img, x, y-1) + + IM_GET_RAW_PIXEL(img, x, y+1)) >> 1; + } else { // Odd col + r = IM_GET_RAW_PIXEL(img, x, y); + + g = (IM_GET_RAW_PIXEL(img, x, y-1) + + IM_GET_RAW_PIXEL(img, x, y+1) + + IM_GET_RAW_PIXEL(img, x-1, y) + + IM_GET_RAW_PIXEL(img, x+1, y)) >> 2; + + b = (IM_GET_RAW_PIXEL(img, x-1, y-1) + + IM_GET_RAW_PIXEL(img, x+1, y-1) + + IM_GET_RAW_PIXEL(img, x-1, y+1) + + IM_GET_RAW_PIXEL(img, x+1, y+1)) >> 2; + } + + } + r = IM_R825(r); + g = IM_G826(g); + b = IM_B825(b); + } + *rgbbuf++ = IM_RGB565(r, g, b); + } + } +} + +static uint8_t *get_mcu() +{ + uint8_t *Y0 = mcubuf; + uint8_t *CB = mcubuf + 64; + uint8_t *CR = mcubuf + 128; + + // Copy 8x8 MCUs + switch (jpeg_enc.img_bpp) { + case 1: + for (int y=jpeg_enc.y_offset; y<(jpeg_enc.y_offset + MCU_H); y++) { + for (int x=jpeg_enc.x_offset; x<(jpeg_enc.x_offset + MCU_W); x++) { + *Y0++ = jpeg_enc.pixels8[y * jpeg_enc.img_w + x]; + } + } + break; + case 2: { + for (int y=jpeg_enc.y_offset, idx=0; y<(jpeg_enc.y_offset + MCU_H); y++) { + for (int x=jpeg_enc.x_offset; x<(jpeg_enc.x_offset + MCU_W); x++, idx++) { + int ofs = y * jpeg_enc.img_w + x; + Y0[idx] = yuv_table[jpeg_enc.pixels16[ofs] * 3 + 0] - 128; + CB[idx] = yuv_table[jpeg_enc.pixels16[ofs] * 3 + 1] - 128; + CR[idx] = yuv_table[jpeg_enc.pixels16[ofs] * 3 + 2] - 128; + } + } + break; + } + case 3: { + uint16_t rgbbuf[64]; + bayer_blk_to_rgb565(jpeg_enc.img, 8, 8, jpeg_enc.x_offset, jpeg_enc.y_offset, rgbbuf); + for (int y=0, idx=0; y<8; y++) { + for (int x=0; x<8; x++, idx++) { + Y0[idx] = yuv_table[rgbbuf[idx] * 3 + 0] - 128; + CB[idx] = yuv_table[rgbbuf[idx] * 3 + 1] - 128; + CR[idx] = yuv_table[rgbbuf[idx] * 3 + 2] - 128; + } + } + break; + } + } + + jpeg_enc.x_offset += MCU_W; + if (jpeg_enc.x_offset == (jpeg_enc.mcu_row * MCU_W)) { + jpeg_enc.x_offset = 0; + jpeg_enc.y_offset += MCU_H; + } + return mcubuf; +} + +void HAL_JPEG_GetDataCallback(JPEG_HandleTypeDef *hjpeg, uint32_t NbDecodedData) +{ + HAL_JPEG_Pause(hjpeg, JPEG_PAUSE_RESUME_INPUT); + if ((hjpeg->JpegOutCount+1024) > hjpeg->OutDataLength) { + jpeg_enc.overflow = true; + HAL_JPEG_Abort(hjpeg); + return; + } + if (jpeg_enc.y_offset == jpeg_enc.img_h) { + HAL_JPEG_ConfigInputBuffer(hjpeg, NULL, 0); + } else { + HAL_JPEG_ConfigInputBuffer(hjpeg, get_mcu(), jpeg_enc.mcu_size); + } + HAL_JPEG_Resume(hjpeg, JPEG_PAUSE_RESUME_INPUT); +} + +void HAL_JPEG_DataReadyCallback (JPEG_HandleTypeDef *hjpeg, uint8_t *pDataOut, uint32_t OutDataLength) +{ + jpeg_enc.out_size = OutDataLength; +} + +void HAL_JPEG_ErrorCallback(JPEG_HandleTypeDef *hjpeg) +{ + printf("JPEG decode/encode error\n"); +} + +bool jpeg_compress(image_t *src, image_t *dst, int quality, bool realloc) +{ +#if (TIME_JPEG==1) + uint32_t start = HAL_GetTick(); +#endif + + // Init the HAL JPEG driver + JPEG_HandleTypeDef JPEG_Handle = {0}; + JPEG_Handle.Instance = JPEG; + HAL_JPEG_Init(&JPEG_Handle); + + jpeg_enc.img = src; + jpeg_enc.img_w = src->w; + jpeg_enc.img_h = src->h; + jpeg_enc.img_bpp = src->bpp; + jpeg_enc.mcu_row = src->w / MCU_W; + jpeg_enc.out_size = 0; + jpeg_enc.x_offset = 0; + jpeg_enc.y_offset = 0; + jpeg_enc.overflow = false; + jpeg_enc.pixels8 = (uint8_t *) src->pixels; + jpeg_enc.pixels16 = (uint16_t*) src->pixels; + + JPEG_ConfTypeDef JPEG_Info; + JPEG_Info.ImageWidth = src->w; + JPEG_Info.ImageHeight = src->h; + JPEG_Info.ImageQuality = quality; + + switch (src->bpp) { + case 1: + jpeg_enc.mcu_size = JPEG_444_GS_MCU_SIZE; + JPEG_Info.ColorSpace = JPEG_GRAYSCALE_COLORSPACE; + JPEG_Info.ChromaSubsampling = JPEG_444_SUBSAMPLING; + break; + case 2: + case 3: + jpeg_enc.mcu_size = JPEG_444_YCBCR_MCU_SIZE; + jpeg_enc.subsample = JPEG_SUBSAMPLE_1x1; + JPEG_Info.ColorSpace = JPEG_YCBCR_COLORSPACE; + JPEG_Info.ChromaSubsampling = JPEG_444_SUBSAMPLING; + break; + } + + if (HAL_JPEG_ConfigEncoding(&JPEG_Handle, &JPEG_Info) != HAL_OK) { + return true; + // Initialization error + //nlr_jump(mp_obj_new_exception_msg(&mp_type_RuntimeError, "JPEG config failed!!")); + } + + // NOTE: output buffer size is stored in dst->bpp + if (HAL_JPEG_Encode(&JPEG_Handle, get_mcu(), jpeg_enc.mcu_size, dst->pixels, dst->bpp, 10000) != HAL_OK) { + return true; + // Initialization error + //nlr_jump(mp_obj_new_exception_msg(&mp_type_RuntimeError, "JPEG encode failed!!")); + } + + // Set output size + dst->bpp = jpeg_enc.out_size; + +#if (TIME_JPEG==1) + printf("time: %lums\n", HAL_GetTick() - start); +#endif + + HAL_JPEG_DeInit(&JPEG_Handle); + + return jpeg_enc.overflow; +} + +#else +// Software JPEG implementation. #define FIX_0_382683433 ((int32_t) 98) #define FIX_0_541196100 ((int32_t) 139) #define FIX_0_707106781 ((int32_t) 181) @@ -516,7 +755,7 @@ static void jpeg_write_headers(jpeg_buf_t *jpeg_buf, int w, int h, int bpp, jpeg } -void bayer_blk_to_rgb565(image_t *img, int w, int h, int xoffs, int yoffs, uint16_t *rgbbuf) +static void bayer_blk_to_rgb565(image_t *img, int w, int h, int xoffs, int yoffs, uint16_t *rgbbuf) { int r, g, b; for (int y=yoffs; y