Merge pull request #96 from kwagyeman/master

Update Gif to use fb_alloc_all.
This commit is contained in:
Ibrahim Abd Elkader 2016-03-06 17:24:50 +02:00
commit 547aa0528e
4 changed files with 58 additions and 31 deletions

View File

@ -6,13 +6,12 @@
* A super simple GIF encoder.
*
*/
#include "mp.h"
#include "ff_wrapper.h"
#include "imlib.h"
#include "fb_alloc.h"
#define BLOCK_SIZE (126) // (2^(7)) - 2
// TODO fix this, use all available FB memory
#define BUFF_SIZE (16*1024) // Multiple of (block size + 2)
#define BLOCK_SIZE (126) // (2^(7)) - 2 (DO NOT CHANGE!)
void gif_open(FIL *fp, int width, int height, bool color, bool loop)
{
@ -56,20 +55,36 @@ void gif_add_frame(FIL *fp, image_t *img, uint16_t delay)
write_word(fp, img->h);
write_data(fp, (uint8_t []) {0x00, 0x07}, 2); // 7-bits
int buf_ofs = 0;
int bytes = img->h * img->w;
uint32_t size;
uint8_t *buf = fb_alloc_all(&size);
// FatFS writes partial sectors (512-(fptr%512)) before writing the maximum contiguous sectors,
// increamenting the buffer during the process. This results in an unaligned buffer sent DMA.
// We intentionally misalign the buffer here so FatFS re-aligns it when writing the remainder.
int ff_ofs = f_tell(fp) % 4;
uint8_t *buf = fb_alloc((BUFF_SIZE+ff_ofs) * sizeof(*buf));
buf += ff_ofs;
// This should never happen unless someone forgot to free.
if (size < (sizeof(uint32_t) * 2)) { // We need atleast 8 bytes.
nlr_raise(mp_obj_new_exception_msg(&mp_type_MemoryError,
"Memory leak detected!!!"));
}
int buf_ofs = 0;
int bytes = img->h * img->w;
// When a sector boundary is encountered while writing a file and there are
// more than 512 bytes left to write FatFs will detect that it can bypass
// its internal write buffer and pass the data buffer passed to it directly
// to the disk write function. However, the disk write function needs the
// buffer to be aligned to a 4-byte boundary. FatFs doesn't know this and
// will pass an unaligned buffer if we don't fix the issue.
int fat_ofs = f_tell(fp) % 4;
buf += fat_ofs;
size -= fat_ofs;
// Since we're about to do a more than 512 byte write which will trigger
// the above issue we can fix the problem by misaligning our buffer before
// calling write so that the first partial write gets us back aligned.
for (int x=0; x<bytes; x++) {
if (x%BLOCK_SIZE==0) {
int block_size = IM_MIN(BLOCK_SIZE, bytes - x);
buf[buf_ofs++] = 1 + block_size;
if ((x%BLOCK_SIZE)==0) {
buf[buf_ofs++] = 1 + IM_MIN(BLOCK_SIZE, bytes - x);
buf[buf_ofs++] = 0x80; // clear code
}
@ -83,9 +98,13 @@ void gif_add_frame(FIL *fp, image_t *img, uint16_t delay)
buf[buf_ofs++] = (red << 5) | (green << 2) | blue;
}
if (buf_ofs==BUFF_SIZE) { // flush data
if (buf_ofs==size) { // flush data
buf_ofs = 0;
write_data(fp, buf, BUFF_SIZE);
write_data(fp, buf, size);
// Undo alignment fix. fp will be aligned from now on.
buf -= fat_ofs;
size += fat_ofs;
fat_ofs = 0;
}
}

View File

@ -63,6 +63,12 @@ static mp_obj_t py_gif_size(mp_obj_t gif_obj)
return mp_obj_new_int(f_size(&arg_gif->fp));
}
static mp_obj_t py_gif_loop(mp_obj_t gif_obj)
{
py_gif_obj_t *arg_gif = gif_obj;
return mp_obj_new_int(arg_gif->loop);
}
static mp_obj_t py_gif_add_frame(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
py_gif_obj_t *arg_gif = args[0];
@ -96,6 +102,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_width_obj, py_gif_width);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_height_obj, py_gif_height);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_format_obj, py_gif_format);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_size_obj, py_gif_size);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_loop_obj, py_gif_loop);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_gif_add_frame_obj, 2, py_gif_add_frame);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_close_obj, py_gif_close);
static const mp_map_elem_t locals_dict_table[] = {
@ -103,6 +110,7 @@ static const mp_map_elem_t locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_height), (mp_obj_t)&py_gif_height_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_format), (mp_obj_t)&py_gif_format_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_size), (mp_obj_t)&py_gif_size_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_loop), (mp_obj_t)&py_gif_loop_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_add_frame), (mp_obj_t)&py_gif_add_frame_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&py_gif_close_obj },
{ NULL, NULL },

View File

@ -1,27 +1,27 @@
import time, sensor, image, gif
# Gif recording example:
#
# You can use your OpenMV Cam to record gif files. You can either feed the
# recorder object RGB565 frames or Grayscale frames. Use photo editing software
# like GIMP to compress and optimize the Gif before uploading it to the web.
import sensor, image, time, gif
# Reset sensor
sensor.reset()
# Set sensor settings
sensor.set_contrast(1)
sensor.set_brightness(1)
sensor.set_saturation(1)
sensor.set_gainceiling(16)
sensor.set_framesize(sensor.QQVGA)
sensor.set_pixformat(sensor.GRAYSCALE)
sensor.set_pixformat(sensor.RGB565) # you can also use grayscale
for i in range(30):
img = sensor.snapshot()
# Warm up the cam
for i in range(10):
sensor.snapshot()
# FPS clock
clock = time.clock()
gif = gif.Gif("/test.gif", loop=True)
gif = gif.Gif("/test.gif", loop=True) # video setup to use current resolution
for i in range(30):
clock.tick()
img = sensor.snapshot()
gif.add_frame(img, delay=10)
gif.add_frame(img, delay=10) # centi seconds
# Print FPS.
# Note: Actual FPS is higher, the IDE slows down streaming.
print(clock.fps())

View File

@ -2,7 +2,7 @@
#
# You can use your OpenMV Cam to record mjpeg files. You can either feed the
# recorder object JPEG frames or RGB565/Grayscale frames. Once you've finished
# recording an Mjpeg file you can use VLC to play it. If you're on Ubuntu then
# recording a Mjpeg file you can use VLC to play it. If you are on Ubuntu then
# the built-in video player will work too.
import sensor, image, time, mjpeg
@ -19,7 +19,7 @@ for i in range(10):
clock = time.clock()
mjpeg = mjpeg.Mjpeg("/test.mjpeg") # video setup to use current resolution
for i in range(300):
for i in range(100):
clock.tick()
img = sensor.snapshot()
mjpeg.add_frame(img)