mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Merge pull request #2043 from kwagyeman/kwabena/mjpeg_fps_internal
modules/py_mjpeg: Calculate MJPEG FPS internally.
This commit is contained in:
commit
0d00e62b03
@ -29,10 +29,10 @@ m = mjpeg.Mjpeg("example.mjpeg")
|
|||||||
clock = time.clock() # Create a clock object to track the FPS.
|
clock = time.clock() # Create a clock object to track the FPS.
|
||||||
for i in range(200):
|
for i in range(200):
|
||||||
clock.tick()
|
clock.tick()
|
||||||
m.add_frame(sensor.snapshot())
|
m.write(sensor.snapshot())
|
||||||
print(clock.fps())
|
print(clock.fps())
|
||||||
|
|
||||||
m.close(clock.fps())
|
m.close()
|
||||||
led.off()
|
led.off()
|
||||||
|
|
||||||
raise (Exception("Please reset the camera to see the new file."))
|
raise (Exception("Please reset the camera to see the new file."))
|
||||||
|
|||||||
@ -60,9 +60,9 @@ while True:
|
|||||||
clock = time.clock() # Tracks FPS.
|
clock = time.clock() # Tracks FPS.
|
||||||
for i in range(200):
|
for i in range(200):
|
||||||
clock.tick()
|
clock.tick()
|
||||||
m.add_frame(sensor.snapshot())
|
m.write(sensor.snapshot())
|
||||||
print(clock.fps())
|
print(clock.fps())
|
||||||
|
|
||||||
m.close(clock.fps())
|
m.close()
|
||||||
led.off()
|
led.off()
|
||||||
print("Restarting...")
|
print("Restarting...")
|
||||||
|
|||||||
@ -56,9 +56,9 @@ while True:
|
|||||||
clock = time.clock() # Tracks FPS.
|
clock = time.clock() # Tracks FPS.
|
||||||
for i in range(200):
|
for i in range(200):
|
||||||
clock.tick()
|
clock.tick()
|
||||||
m.add_frame(sensor.snapshot())
|
m.write(sensor.snapshot())
|
||||||
print(clock.fps())
|
print(clock.fps())
|
||||||
|
|
||||||
m.close(clock.fps())
|
m.close()
|
||||||
led.off()
|
led.off()
|
||||||
print("Restarting...")
|
print("Restarting...")
|
||||||
|
|||||||
@ -1182,8 +1182,8 @@ void mjpeg_open(FIL *fp, int width, int height);
|
|||||||
void mjpeg_write(FIL *fp, int width, int height, uint32_t *frames, uint32_t *bytes,
|
void mjpeg_write(FIL *fp, int width, int height, uint32_t *frames, uint32_t *bytes,
|
||||||
image_t *img, int quality, rectangle_t *roi, int rgb_channel, int alpha,
|
image_t *img, int quality, rectangle_t *roi, int rgb_channel, int alpha,
|
||||||
const uint16_t *color_palette, const uint8_t *alpha_palette, image_hint_t hint);
|
const uint16_t *color_palette, const uint8_t *alpha_palette, image_hint_t hint);
|
||||||
void mjpeg_sync(FIL *fp, uint32_t *frames, uint32_t *bytes, float fps);
|
void mjpeg_sync(FIL *fp, uint32_t frames, uint32_t bytes, uint32_t us_avg);
|
||||||
void mjpeg_close(FIL *fp, uint32_t *frames, uint32_t *bytes, float fps);
|
void mjpeg_close(FIL *fp, uint32_t frames, uint32_t bytes, uint32_t us_avg);
|
||||||
|
|
||||||
/* Point functions */
|
/* Point functions */
|
||||||
point_t *point_alloc(int16_t x, int16_t y);
|
point_t *point_alloc(int16_t x, int16_t y);
|
||||||
|
|||||||
@ -13,14 +13,16 @@
|
|||||||
|
|
||||||
#include "file_utils.h"
|
#include "file_utils.h"
|
||||||
|
|
||||||
#define SIZE_OFFSET (1 * 4)
|
#define SIZE_OFFSET (1 * 4)
|
||||||
#define MICROS_OFFSET (8 * 4)
|
#define MICROS_OFFSET (8 * 4)
|
||||||
#define FRAMES_OFFSET (12 * 4)
|
#define FRAMES_OFFSET (12 * 4)
|
||||||
#define RATE_0_OFFSET (19 * 4)
|
#define RATE_0_OFFSET (19 * 4)
|
||||||
#define LENGTH_0_OFFSET (21 * 4)
|
#define LENGTH_0_OFFSET (21 * 4)
|
||||||
#define RATE_1_OFFSET (33 * 4)
|
#define RATE_1_OFFSET (33 * 4)
|
||||||
#define LENGTH_1_OFFSET (35 * 4)
|
#define LENGTH_1_OFFSET (35 * 4)
|
||||||
#define MOVI_OFFSET (54 * 4)
|
#define MOVI_OFFSET (54 * 4)
|
||||||
|
|
||||||
|
#define TIME_SCALE (1000)
|
||||||
|
|
||||||
void mjpeg_open(FIL *fp, int width, int height) {
|
void mjpeg_open(FIL *fp, int width, int height) {
|
||||||
file_write(fp, "RIFF", 4); // FOURCC fcc; - 0
|
file_write(fp, "RIFF", 4); // FOURCC fcc; - 0
|
||||||
@ -43,7 +45,7 @@ void mjpeg_open(FIL *fp, int width, int height) {
|
|||||||
file_write_long(fp, 0); // DWORD dwSuggestedBufferSize; - 15
|
file_write_long(fp, 0); // DWORD dwSuggestedBufferSize; - 15
|
||||||
file_write_long(fp, width); // DWORD dwWidth; - 16
|
file_write_long(fp, width); // DWORD dwWidth; - 16
|
||||||
file_write_long(fp, height); // DWORD dwHeight; - 17
|
file_write_long(fp, height); // DWORD dwHeight; - 17
|
||||||
file_write_long(fp, 1000); // DWORD dwScale; - 18
|
file_write_long(fp, TIME_SCALE); // DWORD dwScale; - 18
|
||||||
file_write_long(fp, 0); // DWORD dwRate; rate - updated on close - 19
|
file_write_long(fp, 0); // DWORD dwRate; rate - updated on close - 19
|
||||||
file_write_long(fp, 0); // DWORD dwStart; - 20
|
file_write_long(fp, 0); // DWORD dwStart; - 20
|
||||||
file_write_long(fp, 0); // DWORD dwLength; length - updated on close - 21
|
file_write_long(fp, 0); // DWORD dwLength; length - updated on close - 21
|
||||||
@ -60,7 +62,7 @@ void mjpeg_open(FIL *fp, int width, int height) {
|
|||||||
file_write_short(fp, 0); // WORD wPriority; - 30
|
file_write_short(fp, 0); // WORD wPriority; - 30
|
||||||
file_write_short(fp, 0); // WORD wLanguage; - 30.5
|
file_write_short(fp, 0); // WORD wLanguage; - 30.5
|
||||||
file_write_long(fp, 0); // DWORD dwInitialFrames; - 31
|
file_write_long(fp, 0); // DWORD dwInitialFrames; - 31
|
||||||
file_write_long(fp, 1000); // DWORD dwScale; - 32
|
file_write_long(fp, TIME_SCALE); // DWORD dwScale; - 32
|
||||||
file_write_long(fp, 0); // DWORD dwRate; rate - updated on close - 33
|
file_write_long(fp, 0); // DWORD dwRate; rate - updated on close - 33
|
||||||
file_write_long(fp, 0); // DWORD dwStart; - 34
|
file_write_long(fp, 0); // DWORD dwStart; - 34
|
||||||
file_write_long(fp, 0); // DWORD dwLength; length - updated on close - 35
|
file_write_long(fp, 0); // DWORD dwLength; length - updated on close - 35
|
||||||
@ -96,7 +98,7 @@ void mjpeg_write(FIL *fp, int width, int height, uint32_t *frames, uint32_t *byt
|
|||||||
const uint16_t *color_palette, const uint8_t *alpha_palette, image_hint_t hint) {
|
const uint16_t *color_palette, const uint8_t *alpha_palette, image_hint_t hint) {
|
||||||
float xscale = width / ((float) roi->w);
|
float xscale = width / ((float) roi->w);
|
||||||
float yscale = height / ((float) roi->h);
|
float yscale = height / ((float) roi->h);
|
||||||
// MAX == KeepAspectRationByExpanding - MIN == KeepAspectRatio
|
// MAX == KeepAspectRatioByExpanding - MIN == KeepAspectRatio
|
||||||
float scale = IM_MIN(xscale, yscale);
|
float scale = IM_MIN(xscale, yscale);
|
||||||
|
|
||||||
image_t dst_img = {
|
image_t dst_img = {
|
||||||
@ -196,43 +198,45 @@ void mjpeg_write(FIL *fp, int width, int height, uint32_t *frames, uint32_t *byt
|
|||||||
fb_alloc_free_till_mark();
|
fb_alloc_free_till_mark();
|
||||||
}
|
}
|
||||||
|
|
||||||
void mjpeg_sync(FIL *fp, uint32_t *frames, uint32_t *bytes, float fps) {
|
void mjpeg_sync(FIL *fp, uint32_t frames, uint32_t bytes, uint32_t us_avg) {
|
||||||
uint32_t position = f_tell(fp);
|
uint32_t position = f_tell(fp);
|
||||||
|
// size of all mjpeg headers and jpegs.
|
||||||
|
uint32_t datasize = (frames * 8) + bytes;
|
||||||
|
// frames_per_second == rate / scale
|
||||||
|
uint32_t rate = IM_DIV((1000000 * TIME_SCALE), us_avg);
|
||||||
|
// video length == frames / frames_per_second
|
||||||
|
uint32_t length = IM_DIV((((uint64_t) frames) * TIME_SCALE), rate);
|
||||||
// Needed
|
// Needed
|
||||||
file_seek(fp, SIZE_OFFSET);
|
file_seek(fp, SIZE_OFFSET);
|
||||||
file_write_long(fp, 216 + (*frames * 8) + *bytes);
|
file_write_long(fp, 216 + datasize);
|
||||||
// Needed
|
// Needed
|
||||||
file_seek(fp, MICROS_OFFSET);
|
file_seek(fp, MICROS_OFFSET);
|
||||||
file_write_long(fp, (!fast_roundf(fps)) ? 0 :
|
file_write_long(fp, us_avg);
|
||||||
fast_roundf(1000000 / fps));
|
file_write_long(fp, IM_DIV((((uint64_t) datasize) * us_avg), frames));
|
||||||
file_write_long(fp, (!(*frames)) ? 0 :
|
|
||||||
fast_roundf((((*frames * 8) + *bytes) * fps) / *frames));
|
|
||||||
// Needed
|
// Needed
|
||||||
file_seek(fp, FRAMES_OFFSET);
|
file_seek(fp, FRAMES_OFFSET);
|
||||||
file_write_long(fp, *frames);
|
file_write_long(fp, frames);
|
||||||
// Probably not needed but writing it just in case.
|
// Probably not needed but writing it just in case.
|
||||||
file_seek(fp, RATE_0_OFFSET);
|
file_seek(fp, RATE_0_OFFSET);
|
||||||
file_write_long(fp, fast_roundf(fps * 1000));
|
file_write_long(fp, rate);
|
||||||
// Probably not needed but writing it just in case.
|
// Probably not needed but writing it just in case.
|
||||||
file_seek(fp, LENGTH_0_OFFSET);
|
file_seek(fp, LENGTH_0_OFFSET);
|
||||||
file_write_long(fp, (!fast_roundf(fps)) ? 0 :
|
file_write_long(fp, length);
|
||||||
fast_roundf((*frames * 1000) / fps));
|
|
||||||
// Probably not needed but writing it just in case.
|
// Probably not needed but writing it just in case.
|
||||||
file_seek(fp, RATE_1_OFFSET);
|
file_seek(fp, RATE_1_OFFSET);
|
||||||
file_write_long(fp, fast_roundf(fps * 1000));
|
file_write_long(fp, rate);
|
||||||
// Probably not needed but writing it just in case.
|
// Probably not needed but writing it just in case.
|
||||||
file_seek(fp, LENGTH_1_OFFSET);
|
file_seek(fp, LENGTH_1_OFFSET);
|
||||||
file_write_long(fp, (!fast_roundf(fps)) ? 0 :
|
file_write_long(fp, length);
|
||||||
fast_roundf((*frames * 1000) / fps));
|
|
||||||
// Needed
|
// Needed
|
||||||
file_seek(fp, MOVI_OFFSET);
|
file_seek(fp, MOVI_OFFSET);
|
||||||
file_write_long(fp, 4 + (*frames * 8) + *bytes);
|
file_write_long(fp, 4 + datasize);
|
||||||
file_sync(fp);
|
file_sync(fp);
|
||||||
file_seek(fp, position);
|
file_seek(fp, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mjpeg_close(FIL *fp, uint32_t *frames, uint32_t *bytes, float fps) {
|
void mjpeg_close(FIL *fp, uint32_t frames, uint32_t bytes, uint32_t us_avg) {
|
||||||
mjpeg_sync(fp, frames, bytes, fps);
|
mjpeg_sync(fp, frames, bytes, us_avg);
|
||||||
file_close(fp);
|
file_close(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -30,6 +30,8 @@ typedef struct py_mjpeg_obj {
|
|||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
uint32_t frames;
|
uint32_t frames;
|
||||||
uint32_t bytes;
|
uint32_t bytes;
|
||||||
|
uint32_t us_old;
|
||||||
|
uint32_t us_avg;
|
||||||
uint32_t width;
|
uint32_t width;
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
bool closed;
|
bool closed;
|
||||||
@ -120,29 +122,44 @@ STATIC mp_obj_t py_mjpeg_write(uint n_args, const mp_obj_t *pos_args, mp_map_t *
|
|||||||
image, args[ARG_quality].u_int, &roi, args[ARG_channel].u_int,
|
image, args[ARG_quality].u_int, &roi, args[ARG_channel].u_int,
|
||||||
args[ARG_alpha].u_int, color_palette, alpha_palette, args[ARG_hint].u_int);
|
args[ARG_alpha].u_int, color_palette, alpha_palette, args[ARG_hint].u_int);
|
||||||
|
|
||||||
|
uint32_t ticks = mp_hal_ticks_us();
|
||||||
|
|
||||||
|
if (self->frames > 1) {
|
||||||
|
uint32_t ticks_diff = mp_hal_ticks_us() - self->us_old;
|
||||||
|
|
||||||
|
if (self->frames <= 2) {
|
||||||
|
self->us_avg = ticks_diff;
|
||||||
|
} else {
|
||||||
|
uint64_t cumulative_average_n = ((uint64_t) self->us_avg) * (self->frames - 1);
|
||||||
|
self->us_avg = (cumulative_average_n + ticks_diff) / self->frames;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self->us_old = ticks;
|
||||||
|
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_mjpeg_write_obj, 2, py_mjpeg_write);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_mjpeg_write_obj, 2, py_mjpeg_write);
|
||||||
|
|
||||||
STATIC mp_obj_t py_mjpeg_sync(mp_obj_t self_in, mp_obj_t fps_obj) {
|
STATIC mp_obj_t py_mjpeg_sync(mp_obj_t self_in) {
|
||||||
py_mjpeg_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
py_mjpeg_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
if (self->closed) {
|
if (self->closed) {
|
||||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("MJPEG stream is closed"));
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("MJPEG stream is closed"));
|
||||||
}
|
}
|
||||||
mjpeg_sync(&self->fp, &self->frames, &self->bytes, mp_obj_get_float(fps_obj));
|
mjpeg_sync(&self->fp, self->frames, self->bytes, self->us_avg);
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_mjpeg_sync_obj, py_mjpeg_sync);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_mjpeg_sync_obj, py_mjpeg_sync);
|
||||||
|
|
||||||
STATIC mp_obj_t py_mjpeg_close(mp_obj_t self_in, mp_obj_t fps_obj) {
|
STATIC mp_obj_t py_mjpeg_close(mp_obj_t self_in) {
|
||||||
py_mjpeg_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
py_mjpeg_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
if (!self->closed) {
|
if (!self->closed) {
|
||||||
mjpeg_close(&self->fp, &self->frames, &self->bytes, mp_obj_get_float(fps_obj));
|
mjpeg_close(&self->fp, self->frames, self->bytes, self->us_avg);
|
||||||
}
|
}
|
||||||
self->closed = true;
|
self->closed = true;
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_mjpeg_close_obj, py_mjpeg_close);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_mjpeg_close_obj, py_mjpeg_close);
|
||||||
|
|
||||||
STATIC mp_obj_t py_mjpeg_open(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
STATIC mp_obj_t py_mjpeg_open(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
enum { ARG_width, ARG_height };
|
enum { ARG_width, ARG_height };
|
||||||
@ -157,12 +174,10 @@ STATIC mp_obj_t py_mjpeg_open(uint n_args, const mp_obj_t *pos_args, mp_map_t *k
|
|||||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
|
|
||||||
py_mjpeg_obj_t *mjpeg = m_new_obj_with_finaliser(py_mjpeg_obj_t);
|
py_mjpeg_obj_t *mjpeg = m_new_obj_with_finaliser(py_mjpeg_obj_t);
|
||||||
|
memset(mjpeg, 0, sizeof(py_mjpeg_obj_t));
|
||||||
mjpeg->base.type = &py_mjpeg_type;
|
mjpeg->base.type = &py_mjpeg_type;
|
||||||
mjpeg->frames = 0;
|
|
||||||
mjpeg->bytes = 0;
|
|
||||||
mjpeg->width = (args[ARG_width].u_int == -1) ? framebuffer_get_width() : args[ARG_width].u_int;
|
mjpeg->width = (args[ARG_width].u_int == -1) ? framebuffer_get_width() : args[ARG_width].u_int;
|
||||||
mjpeg->height = (args[ARG_height].u_int == -1) ? framebuffer_get_height() : args[ARG_height].u_int;
|
mjpeg->height = (args[ARG_height].u_int == -1) ? framebuffer_get_height() : args[ARG_height].u_int;
|
||||||
mjpeg->closed = false;
|
|
||||||
|
|
||||||
file_open(&mjpeg->fp, path, false, FA_WRITE | FA_CREATE_ALWAYS);
|
file_open(&mjpeg->fp, path, false, FA_WRITE | FA_CREATE_ALWAYS);
|
||||||
mjpeg_open(&mjpeg->fp, mjpeg->width, mjpeg->height);
|
mjpeg_open(&mjpeg->fp, mjpeg->width, mjpeg->height);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user