mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Support H7 hardware JPEG encoder.
This commit is contained in:
parent
6877b3afe6
commit
aa53cf2352
@ -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)
|
||||
|
||||
@ -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<yoffs+h; y++) {
|
||||
for (int x=xoffs; x<xoffs+w; x++) {
|
||||
if (x > (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<yoffs+h; y++) {
|
||||
@ -1042,6 +1281,7 @@ bool jpeg_compress(image_t *src, image_t *dst, int quality, bool realloc)
|
||||
jpeg_overflow:
|
||||
return jpeg_buf.overflow;
|
||||
}
|
||||
#endif //defined OMV_HARDWARE_JPEG
|
||||
|
||||
// This function inits the geometry values of an image.
|
||||
void jpeg_read_geometry(FIL *fp, image_t *img, const char *path)
|
||||
|
||||
@ -106,6 +106,11 @@ void HAL_MspInit(void)
|
||||
__HAL_RCC_MDMA_CLK_ENABLE();
|
||||
#endif
|
||||
|
||||
#if defined(OMV_HARDWARE_JPEG)
|
||||
// Enable JPEG clock
|
||||
__HAL_RCC_JPGDECEN_CLK_ENABLE();
|
||||
#endif
|
||||
|
||||
/* Configure DCMI GPIO */
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user