diff --git a/src/Makefile b/src/Makefile index 1f3bc4d30..3caae149f 100755 --- a/src/Makefile +++ b/src/Makefile @@ -123,6 +123,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/, \ fb_alloc.o \ umm_malloc.o \ ff_wrapper.o \ + framebuffer.o \ array.o \ usbdbg.o \ sccb.o \ diff --git a/src/omv/Makefile b/src/omv/Makefile index fdfeafd23..a8b56732d 100644 --- a/src/omv/Makefile +++ b/src/omv/Makefile @@ -5,6 +5,7 @@ SRCS += $(addprefix , \ fb_alloc.c \ umm_malloc.c \ ff_wrapper.c \ + framebuffer.c \ array.c \ usbdbg.c \ sccb.c \ diff --git a/src/omv/framebuffer.c b/src/omv/framebuffer.c new file mode 100644 index 000000000..199cd94fa --- /dev/null +++ b/src/omv/framebuffer.c @@ -0,0 +1,75 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Framebuffer stuff. + * + */ +#include "imlib.h" +#include "omv_boardconfig.h" +#include "framebuffer.h" +// 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 (160*120*2) + +extern char _fb_base; +framebuffer_t *fb = (framebuffer_t *) &_fb_base; + +extern char _jpeg_buf; +jpegbuffer_t *jpeg_fb = (jpegbuffer_t *) &_jpeg_buf; + +void copy_fb_to_jpeg_fb() +{ + static int overflow_count = 0; + + if ((fb->bpp > 3) && JPEG_FB()->enabled) { + // Lock FB + if (mutex_try_lock(&JPEG_FB()->lock, MUTEX_TID_OMV)) { + if(OMV_JPEG_BUF_SIZE < fb->bpp) { + // image won't fit. so don't copy. + JPEG_FB()->w = 0; JPEG_FB()->h = 0; JPEG_FB()->size = 0; + } else { + memcpy(JPEG_FB()->pixels, fb->pixels, fb->bpp); + JPEG_FB()->w = fb->w; JPEG_FB()->h = fb->h; JPEG_FB()->size = fb->bpp; + } + + // Unlock the framebuffer mutex + mutex_unlock(&JPEG_FB()->lock, MUTEX_TID_OMV); + } + } else if ((fb->bpp > 0) && JPEG_FB()->enabled) { + // Lock FB + if (mutex_try_lock(&JPEG_FB()->lock, MUTEX_TID_OMV)) { + // Set JPEG src and dst images. + image_t src = {.w=fb->w, .h=fb->h, .bpp=fb->bpp, .pixels=fb->pixels}; + image_t dst = {.w=fb->w, .h=fb->h, .bpp=OMV_JPEG_BUF_SIZE, .pixels=JPEG_FB()->pixels}; + + // Note: lower quality saves USB bandwidth and results in a faster IDE FPS. + bool overflow = jpeg_compress(&src, &dst, JPEG_FB()->quality, false); + if (overflow == true) { + // JPEG buffer overflowed, reduce JPEG quality for the next frame + // and skip the current frame. The IDE doesn't receive this frame. + if (JPEG_FB()->quality > 1) { + // Keep this quality for the next n frames + overflow_count = 60; + JPEG_FB()->quality = IM_MAX(1, (JPEG_FB()->quality/2)); + } + JPEG_FB()->w = 0; JPEG_FB()->h = 0; JPEG_FB()->size = 0; + } else { + if (overflow_count) { + overflow_count--; + } + // No buffer overflow, increase quality up to max quality based on frame size + if (overflow_count == 0 && + JPEG_FB()->quality < ((MAIN_FB_SIZE() > JPEG_QUALITY_THRESH) ? 35:60)) { + JPEG_FB()->quality++; + } + // Set FB from JPEG image + JPEG_FB()->w = dst.w; JPEG_FB()->h = dst.h; JPEG_FB()->size = dst.bpp; + } + + // Unlock the framebuffer mutex + mutex_unlock(&JPEG_FB()->lock, MUTEX_TID_OMV); + } + } +} diff --git a/src/omv/framebuffer.h b/src/omv/framebuffer.h index 335a81905..736fe713d 100644 --- a/src/omv/framebuffer.h +++ b/src/omv/framebuffer.h @@ -3,30 +3,32 @@ * Copyright (c) 2013/2014 Ibrahim Abdelkader * This work is licensed under the MIT license, see the file LICENSE for details. * - * Framebuffer pointer. + * Framebuffer stuff. * */ #ifndef __FRAMEBUFFER_H__ #define __FRAMEBUFFER_H__ +#include #include "mutex.h" -extern char _fb_base; -static struct framebuffer { + +typedef struct framebuffer { int w,h; int bpp; uint8_t pixels[]; -// Note all instances of fb point to the same memory address. -}*__attribute__ ((__unused__)) fb = (struct framebuffer *) &_fb_base; +} framebuffer_t; -extern char _jpeg_buf; -static struct jpegbuffer { +extern framebuffer_t *fb; + +typedef struct jpegbuffer { int w,h; int size; int enabled; int quality; mutex_t lock; uint8_t pixels[]; -// Note all instances of jepg_fb point to the same memory address. -}*__attribute__ ((__unused__)) jpeg_fb = (struct jpegbuffer *) &_jpeg_buf; +} jpegbuffer_t; + +extern jpegbuffer_t *jpeg_fb; // Use these macros to get a pointer to main or JPEG framebuffer. #define MAIN_FB() (fb) @@ -36,4 +38,8 @@ static struct jpegbuffer { // Use this macro to get a pointer to the free SRAM area located after the framebuffer. #define FB_PIXELS() (MAIN_FB()->pixels+MAIN_FB_SIZE()) + +// Transfers the frame buffer to the jpeg frame buffer if not locked. +void copy_fb_to_jpeg_fb(); + #endif /* __FRAMEBUFFER_H__ */ diff --git a/src/omv/sensor.c b/src/omv/sensor.c index 44be8db1c..a72175f09 100644 --- a/src/omv/sensor.c +++ b/src/omv/sensor.c @@ -26,9 +26,6 @@ #define REG_MIDL 0x1D #define MAX_XFER_SIZE (0xFFFC) -// 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 (160*120*2) sensor_t sensor; TIM_HandleTypeDef TIMHandle; @@ -699,7 +696,6 @@ static void sensor_check_bufsize() // overwrite image pixels before they are compressed. int sensor_snapshot(image_t *image, line_filter_t line_filter_func, void *line_filter_args) { - static int overflow_count = 0; uint32_t addr, length, tick_start; // Set line filter @@ -712,55 +708,7 @@ int sensor_snapshot(image_t *image, line_filter_t line_filter_func, void *line_f // Compress the framebuffer for the IDE preview, only if it's not the first frame, // the framebuffer is enabled and the image sensor does not support JPEG encoding. // Note: This doesn't run unless the IDE is connected and the framebuffer is enabled. - if ((fb->bpp > 3) && JPEG_FB()->enabled && sensor.pixformat != PIXFORMAT_JPEG) { - // Lock FB - if (mutex_try_lock(&JPEG_FB()->lock, MUTEX_TID_OMV)) { - if(OMV_JPEG_BUF_SIZE < fb->bpp) { - // image won't fit. so don't copy. - JPEG_FB()->w = 0; JPEG_FB()->h = 0; JPEG_FB()->size = 0; - } else { - memcpy(JPEG_FB()->pixels, fb->pixels, fb->bpp); - JPEG_FB()->w = fb->w; JPEG_FB()->h = fb->h; JPEG_FB()->size = fb->bpp; - } - - // Unlock the framebuffer mutex - mutex_unlock(&JPEG_FB()->lock, MUTEX_TID_OMV); - } - } else if ((fb->bpp > 0) && JPEG_FB()->enabled && sensor.pixformat != PIXFORMAT_JPEG) { - // Lock FB - if (mutex_try_lock(&JPEG_FB()->lock, MUTEX_TID_OMV)) { - // Set JPEG src and dst images. - image_t src = {.w=fb->w, .h=fb->h, .bpp=fb->bpp, .pixels=fb->pixels}; - image_t dst = {.w=fb->w, .h=fb->h, .bpp=OMV_JPEG_BUF_SIZE, .pixels=JPEG_FB()->pixels}; - - // Note: lower quality saves USB bandwidth and results in a faster IDE FPS. - bool overflow = jpeg_compress(&src, &dst, JPEG_FB()->quality, false); - if (overflow == true) { - // JPEG buffer overflowed, reduce JPEG quality for the next frame - // and skip the current frame. The IDE doesn't receive this frame. - if (JPEG_FB()->quality > 1) { - // Keep this quality for the next n frames - overflow_count = 60; - JPEG_FB()->quality = IM_MAX(1, (JPEG_FB()->quality/2)); - } - JPEG_FB()->w = 0; JPEG_FB()->h = 0; JPEG_FB()->size = 0; - } else { - if (overflow_count) { - overflow_count--; - } - // No buffer overflow, increase quality up to max quality based on frame size - if (overflow_count == 0 && - JPEG_FB()->quality < ((MAIN_FB_SIZE() > JPEG_QUALITY_THRESH) ? 35:60)) { - JPEG_FB()->quality++; - } - // Set FB from JPEG image - JPEG_FB()->w = dst.w; JPEG_FB()->h = dst.h; JPEG_FB()->size = dst.bpp; - } - - // Unlock the framebuffer mutex - mutex_unlock(&JPEG_FB()->lock, MUTEX_TID_OMV); - } - } + if (sensor.pixformat != PIXFORMAT_JPEG) copy_fb_to_jpeg_fb(); // Setup the size and address of the transfer switch (sensor.pixformat) {