Support H7 hardware JPEG encoder.

This commit is contained in:
iabdalkader 2018-04-03 22:08:53 +02:00
parent 6877b3afe6
commit aa53cf2352
3 changed files with 249 additions and 1 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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;