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.
|
||||
for i in range(200):
|
||||
clock.tick()
|
||||
m.add_frame(sensor.snapshot())
|
||||
m.write(sensor.snapshot())
|
||||
print(clock.fps())
|
||||
|
||||
m.close(clock.fps())
|
||||
m.close()
|
||||
led.off()
|
||||
|
||||
raise (Exception("Please reset the camera to see the new file."))
|
||||
|
||||
@ -60,9 +60,9 @@ while True:
|
||||
clock = time.clock() # Tracks FPS.
|
||||
for i in range(200):
|
||||
clock.tick()
|
||||
m.add_frame(sensor.snapshot())
|
||||
m.write(sensor.snapshot())
|
||||
print(clock.fps())
|
||||
|
||||
m.close(clock.fps())
|
||||
m.close()
|
||||
led.off()
|
||||
print("Restarting...")
|
||||
|
||||
@ -56,9 +56,9 @@ while True:
|
||||
clock = time.clock() # Tracks FPS.
|
||||
for i in range(200):
|
||||
clock.tick()
|
||||
m.add_frame(sensor.snapshot())
|
||||
m.write(sensor.snapshot())
|
||||
print(clock.fps())
|
||||
|
||||
m.close(clock.fps())
|
||||
m.close()
|
||||
led.off()
|
||||
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,
|
||||
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);
|
||||
void mjpeg_sync(FIL *fp, uint32_t *frames, uint32_t *bytes, float fps);
|
||||
void mjpeg_close(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, uint32_t us_avg);
|
||||
|
||||
/* Point functions */
|
||||
point_t *point_alloc(int16_t x, int16_t y);
|
||||
|
||||
@ -22,6 +22,8 @@
|
||||
#define LENGTH_1_OFFSET (35 * 4)
|
||||
#define MOVI_OFFSET (54 * 4)
|
||||
|
||||
#define TIME_SCALE (1000)
|
||||
|
||||
void mjpeg_open(FIL *fp, int width, int height) {
|
||||
file_write(fp, "RIFF", 4); // FOURCC fcc; - 0
|
||||
file_write_long(fp, 0); // DWORD cb; size - updated on close - 1
|
||||
@ -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, width); // DWORD dwWidth; - 16
|
||||
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 dwStart; - 20
|
||||
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 wLanguage; - 30.5
|
||||
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 dwStart; - 34
|
||||
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) {
|
||||
float xscale = width / ((float) roi->w);
|
||||
float yscale = height / ((float) roi->h);
|
||||
// MAX == KeepAspectRationByExpanding - MIN == KeepAspectRatio
|
||||
// MAX == KeepAspectRatioByExpanding - MIN == KeepAspectRatio
|
||||
float scale = IM_MIN(xscale, yscale);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
// 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
|
||||
file_seek(fp, SIZE_OFFSET);
|
||||
file_write_long(fp, 216 + (*frames * 8) + *bytes);
|
||||
file_write_long(fp, 216 + datasize);
|
||||
// Needed
|
||||
file_seek(fp, MICROS_OFFSET);
|
||||
file_write_long(fp, (!fast_roundf(fps)) ? 0 :
|
||||
fast_roundf(1000000 / fps));
|
||||
file_write_long(fp, (!(*frames)) ? 0 :
|
||||
fast_roundf((((*frames * 8) + *bytes) * fps) / *frames));
|
||||
file_write_long(fp, us_avg);
|
||||
file_write_long(fp, IM_DIV((((uint64_t) datasize) * us_avg), frames));
|
||||
// Needed
|
||||
file_seek(fp, FRAMES_OFFSET);
|
||||
file_write_long(fp, *frames);
|
||||
file_write_long(fp, frames);
|
||||
// Probably not needed but writing it just in case.
|
||||
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.
|
||||
file_seek(fp, LENGTH_0_OFFSET);
|
||||
file_write_long(fp, (!fast_roundf(fps)) ? 0 :
|
||||
fast_roundf((*frames * 1000) / fps));
|
||||
file_write_long(fp, length);
|
||||
// Probably not needed but writing it just in case.
|
||||
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.
|
||||
file_seek(fp, LENGTH_1_OFFSET);
|
||||
file_write_long(fp, (!fast_roundf(fps)) ? 0 :
|
||||
fast_roundf((*frames * 1000) / fps));
|
||||
file_write_long(fp, length);
|
||||
// Needed
|
||||
file_seek(fp, MOVI_OFFSET);
|
||||
file_write_long(fp, 4 + (*frames * 8) + *bytes);
|
||||
file_write_long(fp, 4 + datasize);
|
||||
file_sync(fp);
|
||||
file_seek(fp, position);
|
||||
}
|
||||
|
||||
void mjpeg_close(FIL *fp, uint32_t *frames, uint32_t *bytes, float fps) {
|
||||
mjpeg_sync(fp, frames, bytes, fps);
|
||||
void mjpeg_close(FIL *fp, uint32_t frames, uint32_t bytes, uint32_t us_avg) {
|
||||
mjpeg_sync(fp, frames, bytes, us_avg);
|
||||
file_close(fp);
|
||||
}
|
||||
|
||||
|
||||
@ -30,6 +30,8 @@ typedef struct py_mjpeg_obj {
|
||||
mp_obj_base_t base;
|
||||
uint32_t frames;
|
||||
uint32_t bytes;
|
||||
uint32_t us_old;
|
||||
uint32_t us_avg;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
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,
|
||||
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;
|
||||
}
|
||||
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);
|
||||
if (self->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;
|
||||
}
|
||||
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);
|
||||
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;
|
||||
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) {
|
||||
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);
|
||||
|
||||
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->frames = 0;
|
||||
mjpeg->bytes = 0;
|
||||
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->closed = false;
|
||||
|
||||
file_open(&mjpeg->fp, path, false, FA_WRITE | FA_CREATE_ALWAYS);
|
||||
mjpeg_open(&mjpeg->fp, mjpeg->width, mjpeg->height);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user