Zooming, preview stall warnings, HQ still resolutions.

V 4.3.2
Zoom in to a percent of the camera sensor.  Selected zooms are saved
as part of a Preset Settings.  A large zoom can help with camera focusing.

Show stall warning on preview when GPU jpeg encoder does not keep up
converting the preview images and frames are dropped.  This problem showed
up with the HQ camera on Pi 4 where video_fps needs to lowered to around
20 to avoid stalls.  I don't see the problem on Pi 2 with HQ camera or
with V1 or v2 cameras, so maybe a later firmware version will help.

Put in HQ still resolutions and now still resolution options shown depend
on camera resolution detected.

Checking archive diskfree failed to remove stills.

Changed how to track through the preview jpeg encoder which preview frame
to use for thumbs.

Added greyworld
This commit is contained in:
Bill Wilson 2020-06-08 17:45:34 -05:00
parent 08ed7926e5
commit 994384dae9
13 changed files with 400 additions and 139 deletions

Binary file not shown.

View File

@ -1,6 +1,6 @@
/* PiKrellCam
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
| Copyright (C) 2015-2020 Bill Wilson billw@gkrellm.net
|
| PiKrellCam is free software: you can redistribute it and/or modify it
| under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/* PiKrellCam
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
| Copyright (C) 2015-2020 Bill Wilson billw@gkrellm.net
|
| PiKrellCam is free software: you can redistribute it and/or modify it
| under the terms of the GNU General Public License as published by
@ -125,7 +125,8 @@ ParameterTable awb_mode_table[] =
{ MMAL_PARAM_AWBMODE_FLUORESCENT, "flourescent" },
{ MMAL_PARAM_AWBMODE_INCANDESCENT, "incandescent" },
{ MMAL_PARAM_AWBMODE_FLASH, "flash" },
{ MMAL_PARAM_AWBMODE_HORIZON, "horizon" }
{ MMAL_PARAM_AWBMODE_HORIZON, "horizon" },
{ MMAL_PARAM_AWBMODE_GREYWORLD, "greyworld" }
};
#define AWB_MODE_TABLE_SIZE \
@ -214,6 +215,9 @@ ParameterTable parameter_table[] =
{ MMAL_PARAMETER_VIDEO_STABILISATION, "video_stabilisation" }, /* bool */
{ MMAL_PARAMETER_ENABLE_RAW_CAPTURE, "raw_capture" }, /* bool */
#if 0
{ MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS, "draw_focus_box" }, /* bool */
#endif
};
@ -358,6 +362,8 @@ flip_control_set(char *option, char *setting)
return status;
}
static boolean force_crop;
MMAL_STATUS_T
crop_control_set(char *option, char *setting)
{
@ -368,9 +374,31 @@ crop_control_set(char *option, char *setting)
if (sscanf(setting, "%d %d %d %d", &crop.rect.x, &crop.rect.y,
&crop.rect.width, &crop.rect.height) == 4)
status = mmal_port_parameter_set(camera.control_port, &crop.hdr);
if (option)
force_crop = TRUE; /* crop command from FIFO, so force restoring */
/* zoom_percent from preset changes */
return status;
}
void
zoom_percent(int percent)
{
int origin, width;
char buf[128];
if ( percent < 10 || percent > 100
|| (percent == pikrellcam.zoom_percent_prev && !force_crop)
)
return;
force_crop = FALSE;
width = 65536 * percent / 100;
origin = 65536 / 2 - width / 2;
snprintf(buf, sizeof(buf), "%d %d %d %d", origin, origin, width, width);
pikrellcam.zoom_motion_holdoff = 5;
crop_control_set(NULL, buf);
pikrellcam.zoom_percent_prev = percent;
}
MMAL_STATUS_T
color_effect_set(char *option, char *setting)
{
@ -404,6 +432,7 @@ static CameraParameter camera_parameters[] =
{ "video_stabilisation", "false", boolean_control_set, &pikrellcam.video_stabilisation },
{ "raw_capture", "false", boolean_control_set, &pikrellcam.raw_capture },
// { "draw_focus_box", "false", boolean_control_set, &pikrellcam.draw_focus_box },
{ "rotation", "0", rotation_control_set, &pikrellcam.rotation },
{ "exposure_mode", "auto", exposure_mode_set, &pikrellcam.exposure_mode },
@ -750,6 +779,10 @@ static Config config[] =
"#",
"motion_show_counts", "off", FALSE, {.value = &pikrellcam.motion_show_counts}, config_value_bool_set },
{ "# If on, show a warning if the preview mjpeg encoder stalls.\n"
"#",
"preview_stall_warning", "on", FALSE, {.value = &pikrellcam.preview_stall_warning}, config_value_bool_set },
{ "# Minimum width and height in pixels for the substitution width and height\n"
"# variables for motion detect areas in the preview jpeg.\n"
"# This minimum helps with possible frame skew for smaller relatively\n"
@ -1158,7 +1191,7 @@ static Config config[] =
{ "# Annotate text background color. Set to \"none\" for no background.\n"
"# Otherwise, set to a hex rgb value, eg \"000000\" for black or \"808080\" for gray.\n"
"#",
"annotate_text_background_color", "none", FALSE, {.string = &pikrellcam.annotate_text_background_color }, config_string_set },
"annotate_text_background_color", "808080", FALSE, {.string = &pikrellcam.annotate_text_background_color }, config_string_set },
{ "# Annotate text brightness. Range: integer from 0 - 255\n"
"# Text cannot be set to a color, only to a brightness..\n"
@ -1279,7 +1312,7 @@ config_load(char *config_file)
if ((f = fopen(config_file, "r")) == NULL)
return FALSE;
pikrellcam.config_sequence_new = 45;
pikrellcam.config_sequence_new = 47;
while (fgets(linebuf, sizeof(linebuf), f))
{
@ -1317,6 +1350,9 @@ config_load(char *config_file)
)
pikrellcam.motion_record_time_limit = 10;
pikrellcam.zoom_percent = 100;
pikrellcam.zoom_percent_prev = 100;
if (pikrellcam.motion_stills_per_minute > 60)
pikrellcam.motion_stills_per_minute = 60;
else if (pikrellcam.motion_stills_per_minute < 1)

View File

@ -1,6 +1,6 @@
/* PiKrellCam
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
| Copyright (C) 2015-2020 Bill Wilson billw@gkrellm.net
|
| PiKrellCam is free software: you can redistribute it and/or modify it
| under the terms of the GNU General Public License as published by
@ -502,9 +502,10 @@ display_preset_settings(void)
JUSTIFY_LEFT, "Setup->Preset->New");
}
snprintf(info1, sizeof(info1), "Mag %d Cnt %d Burst %d,%d",
snprintf(info1, sizeof(info1), "Mag %d Cnt %d Burst %d,%d Zoom %d%%",
(int) sqrt(mf->mag2_limit), mf->mag2_limit_count,
pikrellcam.motion_burst_count, pikrellcam.motion_burst_frames);
pikrellcam.motion_burst_count, pikrellcam.motion_burst_frames,
pikrellcam.zoom_percent);
i420_print(&bottom_status_area, normal_font, 0xff,
pikrellcam.have_servos ? 1 : 2,
-6 * normal_font->char_width, 0,
@ -608,10 +609,11 @@ motion_draw(uint8_t *i420)
MotionRegion *mreg;
CompositeVector *vec;
SList *mrlist;
char *msg, *fifo_msg, info[100], status[100];
char *msg, *stall_msg, *fifo_msg, buf[32], info[200], status[100];
int16_t color; /* just B&W */
int i, x, y, dx, dy, r, r_unit;
int t_record, t_hold;
static int stall_warning;
if (!glcd)
return;
@ -629,6 +631,17 @@ motion_draw(uint8_t *i420)
}
fifo_msg = "";
if (pikrellcam.mjpeg_stall_count > 0)
stall_warning = 6;
if (stall_warning > 0)
{
--stall_warning;
stall_msg = " Preview stall! See Preview_Stall_Warning in Help";
}
else
stall_msg = "";
if (!inform_shown && (mf->show_preset || pikrellcam.preset_notify))
{
for (mrlist = mf->motion_region_list; mrlist; mrlist = mrlist->next)
@ -714,8 +727,8 @@ motion_draw(uint8_t *i420)
if (mf->frame_window > 0 && mf->motion_status == MOTION_NONE)
{
snprintf(status, sizeof(status), "confirming[%d]", mf->frame_window);
msg = status;
snprintf(buf, sizeof(buf), "confirming[%d]", mf->frame_window);
msg = buf;
}
else if (mf->motion_status & MOTION_DETECTED)
{
@ -732,10 +745,12 @@ motion_draw(uint8_t *i420)
msg = "noise";
else
msg = "quiet";
if (mf->frame_vector.mag2_count > 0)
snprintf(status, sizeof(status), "%s:%-3d", msg, mf->frame_vector.mag2_count);
snprintf(status, sizeof(status), "%s:%-3d%s",
msg, mf->frame_vector.mag2_count, stall_msg);
else
snprintf(status, sizeof(status), "%s", msg);
snprintf(status, sizeof(status), "%s%s", msg, stall_msg);
if (pikrellcam.motion_show_counts)
{
@ -756,7 +771,12 @@ motion_draw(uint8_t *i420)
}
}
else
{
mf->selected_region = -1;
if (pikrellcam.preview_stall_warning)
i420_print(&bottom_status_area, normal_font, 0xff, 0, 0, 0,
JUSTIFY_LEFT, stall_msg);
}
t_record = vcb->record_elapsed_time;
@ -930,7 +950,8 @@ static SList *menu_video_presets_list;
static int menu_video_presets_index;
static SList *menu_still_presets_list;
static int menu_still_presets_index;
static int menu_still_presets_index,
menu_still_presets_list_size;
static SList *menu_picture_list;
static int menu_picture_index;
@ -973,6 +994,7 @@ static char *video_presets_entry[] =
"1640x1232", // V2 4:3
"1640x922", // V2 16:9
"1296x972", // V1 4:3
"1012x760", // HQ 4:3
"1024x768",
"1024x576"
};
@ -984,12 +1006,15 @@ static char *still_presets_entry[] =
{
"1920x1080",
"1280x720",
"3280x2464", // v2
"2592x1944",
"2592x1458",
"1920x1440",
"1640x1232", // V2 4:3
"1640x922", // V2 16:9
"4056x3040", // HQ 4:3
"4056x2280", // HQ 16:9
"3280x2464", // v2 4:3
"3280x1545", // v2 16:9
"2592x1944", // v1 4:3
"2592x1458", // v1 16:9
"1920x1440", // all 4:3
"1640x1232", // all 4:3
"1640x922", // all 16:9
"1296x972",
"1024x768",
"1024x576"
@ -1040,7 +1065,8 @@ static char *white_balance_entry[] =
"flourescent",
"incandescent",
"flash",
"horizon"
"horizon",
"greyworld"
};
#define N_WHITE_BALANCE_ENTRIES \
@ -1104,6 +1130,7 @@ static Adjustment picture_adjustment[] =
{ "iso", 0, 800, 100, 0, 0, 0, 0, "", NULL, NULL },
{ "exposure_compensation", -25, 25, 1, 0, 0, 0, 0, "", NULL, NULL },
{ "video_stabilisation", 0, 1, 1, 0, 0, 0, 0, "", NULL, NULL },
// { "draw_focus_box", 0, 1, 1, 0, 0, 0, 0, "", NULL, NULL },
{ "rotation", 0, 270, 90, 0, 0, 0, 0, "", NULL, NULL },
{ "hflip", 0, 1, 1, 0, 0, 0, 0, "", NULL, NULL },
{ "vflip", 0, 1, 1, 0, 0, 0, 0, "", NULL, NULL },
@ -1137,13 +1164,17 @@ Adjustment motion_limit_adjustment[] =
{ "Vector_Magnitude", 2, 50, 1, 0, 0, 0, 0, "", NULL, &pikrellcam.motion_magnitude_limit },
{ "Vector_Count", 2, 50, 1, 0, 0, 0, 0, "", NULL, &pikrellcam.motion_magnitude_limit_count },
{ "Burst_Count", 50, 2000, 10, 0, 0, 0, 0, "", NULL, &pikrellcam.motion_burst_count },
{ "Burst_Frames", 2, 20, 1, 0, 0, 0, 0, "", NULL, &pikrellcam.motion_burst_frames }
{ "Burst_Frames", 2, 20, 1, 0, 0, 0, 0, "", NULL, &pikrellcam.motion_burst_frames },
{ "Zoom_Percent", 10, 100, 2, 0, 0, 0, 0, "", NULL, &pikrellcam.zoom_percent }
};
#define ZOOM_REGION_INDEX 4
#define N_MOTION_LIMIT_ADJUSTMENTS \
(sizeof(motion_limit_adjustment) / sizeof(Adjustment))
/* Some settings djustment changes are made to a temp struct to avoid thrashing
| camera destroys/creates. Final change is applied if/when SEL is clicked.
*/
@ -1161,6 +1192,7 @@ Adjustment settings_adjustment[] =
{ "Vector_Counts", 0, 1, 1, 0, 0, 0, 0, "", NULL, &pikrellcam.motion_show_counts },
{ "Vector_Dimming", 30, 60, 1, 0, 0, 0, 0, "", NULL, &pikrellcam.motion_vectors_dimming },
{ "Preview_Clean", 0, 1, 1, 0, 0, 0, 0, "", NULL, &pikrellcam.motion_preview_clean },
{ "Preview_Stall_Warning", 0, 1, 1, 0, 0, 0, 0, "", NULL, &pikrellcam.preview_stall_warning },
};
@ -1230,6 +1262,17 @@ adjustment_is_servo_limits(void)
return FALSE;
}
static boolean
adjustment_is_zoom(void)
{
if ( display_state == DISPLAY_ADJUSTMENT
&& adjustments == &motion_limit_adjustment[0]
&& *display_menu_index == ZOOM_REGION_INDEX
)
return TRUE;
return FALSE;
}
static boolean
adjustment_is_servo_pan_limits(void)
{
@ -1315,6 +1358,7 @@ apply_adjustment(void)
settings->mag_limit_count = pikrellcam.motion_magnitude_limit_count;
settings->burst_count = pikrellcam.motion_burst_count;
settings->burst_frames = pikrellcam.motion_burst_frames;
settings->zoom_percent = pikrellcam.zoom_percent;
pikrellcam.preset_modified = TRUE;
}
else
@ -1368,7 +1412,9 @@ revert_adjustment(void)
else
*(cur_adj->config_value) = cur_adj->revert_value;
}
if (adjustment_is_servo_limits())
if (adjustment_is_zoom())
zoom_percent(pikrellcam.zoom_percent);
else if (adjustment_is_servo_limits())
servo_move(pan_save, tilt_save, pikrellcam.servo_move_step_msec);
}
@ -1533,7 +1579,9 @@ display_adjustment(uint8_t *i420)
else
*(cur_adj->config_value) = cur_adj->value;
if (adjustment_is_servo_pan_limits())
if (adjustment_is_zoom())
zoom_percent(pikrellcam.zoom_percent);
else if (adjustment_is_servo_pan_limits())
{
preset_pan_range(&max, &min);
if (cur_adj->value <= min || cur_adj->value >= max)
@ -1625,6 +1673,19 @@ display_adjustment(uint8_t *i420)
i420_print(da, font, 0xff, 2, 0, 0, JUSTIFY_CENTER, cur_adj->name);
}
void
display_motion_limit_adjustment_sync(PresetSettings *settings)
{
if ( display_state != DISPLAY_ADJUSTMENT
|| adjustments != &motion_limit_adjustment[0]
|| !cur_adj
)
return;
cur_adj_start = TRUE;
}
static void
display_draw_menu(uint8_t *i420)
{
@ -1904,8 +1965,13 @@ display_command(char *cmd)
{
if (!strcmp(video_presets_entry[i], "720p"))
{
width = 1296;
height = 730;
width = 1280;
height = 720;
}
else if (!strcmp(video_presets_entry[i], "1080p"))
{
width = 1920;
height = 1080;
}
else
sscanf(video_presets_entry[i], "%dx%d", &width, &height);
@ -1921,15 +1987,19 @@ display_command(char *cmd)
display_menu_index = &menu_still_presets_index;
display_state = DISPLAY_MENU;
display_menu = STILL_PRESET;
for (i = N_STILL_PRESET_ENTRIES - 1; i > 0 ; --i)
for (i = 0, list = display_menu_list; list; ++i, list = list->next)
{
sscanf(still_presets_entry[i], "%dx%d", &width, &height);
entry = (MenuEntry *) list->data;
sscanf(entry->name, "%dx%d", &width, &height);
if ( pikrellcam.camera_config.still_width == width
&& pikrellcam.camera_config.still_height == height
)
break;
}
menu_still_presets_index = i;
if (i < menu_still_presets_list_size)
menu_still_presets_index = i;
else
menu_still_presets_index = 0;
break;
case METERING:
@ -2145,7 +2215,7 @@ display_init(void)
DrawArea da;
MenuEntry *entry;
Adjustment *adj;
int i, position;
int i, position, width, height;
if (!glcd)
glcd = glcd_i420_init();
@ -2278,14 +2348,23 @@ display_init(void)
}
if (!menu_still_presets_list)
{
menu_still_presets_list_size = 0;
for (i = 0, position = 0; i < N_STILL_PRESET_ENTRIES; ++i)
{
entry = calloc(1, sizeof(MenuEntry));
entry->name = still_presets_entry[i];
entry->length = strlen(entry->name);
entry->line_position = position;
position += entry->length + 1;
menu_still_presets_list = slist_append(menu_still_presets_list, entry);
sscanf(still_presets_entry[i], "%dx%d", &width, &height);
if ( pikrellcam.camera_width_max >= width
&& pikrellcam.camera_height_max >= height
)
{
entry = calloc(1, sizeof(MenuEntry));
entry->name = still_presets_entry[i];
entry->length = strlen(entry->name);
entry->line_position = position;
position += entry->length + 1;
++menu_still_presets_list_size;
menu_still_presets_list =
slist_append(menu_still_presets_list, entry);
}
}
}
if (!menu_picture_list)

View File

@ -1,6 +1,6 @@
/* PiKrellCam
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
| Copyright (C) 2015-2020 Bill Wilson billw@gkrellm.net
|
| PiKrellCam is free software: you can redistribute it and/or modify it
| under the terms of the GNU General Public License as published by
@ -490,7 +490,7 @@ static boolean
video_diskfree_percent_delete(char *media_dir, boolean *empty)
{
struct dirent **mp4_list = NULL;
char *s, video_dir[256], thumb_dir[256], fname[256];
char *s, video_dir[256], thumb_dir[256], fname[512];
int i, n, low_space;
boolean done = FALSE;
@ -552,7 +552,7 @@ static boolean
still_diskfree_percent_delete(char *media_dir, char *sub_dir, boolean *empty)
{
struct dirent **jpg_list = NULL;
char still_dir[256], fname[256];
char *s, still_dir[256], fname[600], thumb_base[300];
int i, n, low_space;
boolean done = FALSE;
@ -577,6 +577,15 @@ still_diskfree_percent_delete(char *media_dir, char *sub_dir, boolean *empty)
snprintf(fname, sizeof(fname), "%s/%s",
still_dir, jpg_list[i]->d_name);
unlink(fname);
snprintf(thumb_base, sizeof(thumb_base), "%s", jpg_list[i]->d_name);
if ((s = strstr(thumb_base, ".jpg")) != NULL)
{
*s = '\0';
snprintf(fname, sizeof(fname), "%s/.thumbs/%s.th.jpg",
still_dir, thumb_base);
unlink(fname);
}
log_printf("Low disk space, deleted: %s\n", fname);
if (empty && i == n - 1)
@ -605,7 +614,7 @@ event_archive_diskfree_percent(char *type)
**month_list = NULL,
**day_list = NULL;;
int y, n_yr, m, n_mon, d, n_day;
char year_dir[256], mon_dir[256], day_dir[256], del_dir[256];
char year_dir[300], mon_dir[600], day_dir[800], del_dir[1000];
boolean done = FALSE, dir_empty;
if (!diskfree_is_low(pikrellcam.archive_dir))
@ -645,11 +654,32 @@ event_archive_diskfree_percent(char *type)
rmdir(day_dir);
if (done && d == n_day - 1)
{
/* rmdir() here fails if there are stills */
rmdir(mon_dir);
if (done && m == n_mon - 1)
rmdir(year_dir);
}
}
if (!done)
{
done = still_diskfree_percent_delete(day_dir,
PIKRELLCAM_STILL_SUBDIR, &dir_empty);
if (dir_empty)
{
snprintf(del_dir, sizeof(del_dir),
"%s/stills/.thumbs", day_dir);
rmdir(del_dir);
snprintf(del_dir, sizeof(del_dir),
"%s/stills", day_dir);
rmdir(del_dir);
if (done && d == n_day - 1)
{
rmdir(mon_dir);
if (done && m == n_mon - 1)
rmdir(year_dir);
}
}
}
}
free(day_list[d]);
}
@ -676,7 +706,7 @@ event_loop_diskusage_percent(void)
int i, n, used_percent;
boolean diskfree_low;
char *loop_dir = pikrellcam.loop_dir;
char fname[256], *s;
char fname[500], *s;
uint64_t used_blocks = 0, fs_blocks;
if ( !loop_dir

View File

@ -1,6 +1,6 @@
/* PiKrellCam
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
| Copyright (C) 2015-2020 Bill Wilson billw@gkrellm.net
|
| PiKrellCam is free software: you can redistribute it and/or modify it
| under the terms of the GNU General Public License as published by
@ -34,11 +34,13 @@ extern char* mjpeg_server_queue_get(void);
extern void mjpeg_server_queue_put(char *data, int len);
static boolean motion_frame_event;
static int mjpeg_do_preview_save;
static pthread_mutex_t mjpeg_encoder_count_lock;
static unsigned int mjpeg_encoder_send_count,
mjpeg_encoder_recv_count;
#define N_MJPEG_ENCODER_INPUT_BUFFERS 3
static pthread_mutex_t mjpeg_encoder_frame_count_lock;
static unsigned int mjpeg_encoder_send_frame,
mjpeg_encoder_recv_frame,
mjpeg_preview_save_frame;
static pthread_t video_write_thread_ref;
static int thread_ret = 1;
@ -223,14 +225,14 @@ preview_save(void)
void
mjpeg_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
{
CameraObject *data = (CameraObject *) port->userdata;
static struct timeval timer;
int n, utime;
static FILE *file = NULL;
static char *fname_part;
boolean do_preview_save = FALSE;
static char *tcp_buf;
static int tcp_buf_offset;
CameraObject *data = (CameraObject *) port->userdata;
static struct timeval timer;
int n, utime;
boolean do_preview_save;
static FILE *file = NULL;
static char *fname_part;
static char *tcp_buf;
static int tcp_buf_offset;
if (!fname_part)
@ -264,6 +266,16 @@ mjpeg_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
tcp_buf_offset = 0;
}
pthread_mutex_lock(&mjpeg_encoder_frame_count_lock);
++mjpeg_encoder_recv_frame;
if (mjpeg_encoder_recv_frame > mjpeg_encoder_send_frame)
mjpeg_encoder_recv_frame = mjpeg_encoder_send_frame; /* should not happen */
do_preview_save = (mjpeg_preview_save_frame > 0
&& mjpeg_encoder_recv_frame >= mjpeg_preview_save_frame);
if (do_preview_save)
mjpeg_preview_save_frame = 0;
pthread_mutex_unlock(&mjpeg_encoder_frame_count_lock);
if (pikrellcam.debug_fps && (utime = micro_elapsed_time(&timer)) > 0)
printf("%s fps %d\n", data->name, 1000000 / utime);
if (file)
@ -271,17 +283,6 @@ mjpeg_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
fclose(file);
file = NULL;
pthread_mutex_lock(&mjpeg_encoder_count_lock);
++mjpeg_encoder_recv_count;
if (mjpeg_do_preview_save == 1)
{
mjpeg_do_preview_save = 0;
do_preview_save = TRUE;
}
else if (mjpeg_do_preview_save > 1)
--mjpeg_do_preview_save;
pthread_mutex_unlock(&mjpeg_encoder_count_lock);
rename(fname_part, pikrellcam.mjpeg_filename);
if (do_preview_save)
@ -383,77 +384,67 @@ I420_video_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
MMAL_BUFFER_HEADER_T *buffer_in;
static struct timeval timer;
int utime;
static int encoder_busy_count;
if ( buffer->length > 0
&& motion_frame_event
)
if (buffer->length > 0 && motion_frame_event)
{
motion_frame_event = FALSE;
/* Do not send buffer to encoder if it has not received the previous
| one we sent unless this is the frame we want for a preview save.
| In that case, we may be sending a buffer to preview save before
| the previous buffer is handled. This is accounted for below.
*/
if ( mjpeg_encoder_send_count == mjpeg_encoder_recv_count
|| pikrellcam.do_preview_save
)
if (obj->callback_port_in && obj->callback_pool_in)
{
if (obj->callback_port_in && obj->callback_pool_in)
buffer_in = mmal_queue_get(obj->callback_pool_in->queue);
if ( buffer_in
&& obj->callback_port_in->buffer_size >= buffer->length
)
{
buffer_in = mmal_queue_get(obj->callback_pool_in->queue);
if ( buffer_in
&& obj->callback_port_in->buffer_size >= buffer->length
)
{
mmal_buffer_header_mem_lock(buffer);
memcpy(buffer_in->data, buffer->data, buffer->length);
buffer_in->length = buffer->length;
mmal_buffer_header_mem_unlock(buffer);
display_draw(buffer_in->data);
mmal_buffer_header_mem_lock(buffer);
memcpy(buffer_in->data, buffer->data, buffer->length);
buffer_in->length = buffer->length;
mmal_buffer_header_mem_unlock(buffer);
display_draw(buffer_in->data);
if (pikrellcam.do_preview_save)
{
/* If mjpeg encoder has not received previous buffer,
| then the buffer to save will be the second buffer
| it gets from now. Otherwise it's the next buffer.
*/
pthread_mutex_lock(&mjpeg_encoder_count_lock);
if (mjpeg_encoder_send_count == mjpeg_encoder_recv_count)
mjpeg_do_preview_save = 1;
else
mjpeg_do_preview_save = 2;
pthread_mutex_unlock(&mjpeg_encoder_count_lock);
if (mjpeg_do_preview_save == 2 && pikrellcam.debug)
printf("%s: encoder not clear -> preview save delayed\n",
fname_base(pikrellcam.video_pathname));
}
pikrellcam.do_preview_save = FALSE;
++mjpeg_encoder_send_count;
mmal_port_send_buffer(obj->callback_port_in, buffer_in);
mmal_port_send_buffer(obj->callback_port_in, buffer_in);
pthread_mutex_lock(&mjpeg_encoder_frame_count_lock);
++mjpeg_encoder_send_frame;
if (pikrellcam.do_preview_save)
mjpeg_preview_save_frame = mjpeg_encoder_send_frame;
pthread_mutex_unlock(&mjpeg_encoder_frame_count_lock);
pikrellcam.do_preview_save = FALSE;
if (pikrellcam.mjpeg_stall_count > 0)
--pikrellcam.mjpeg_stall_count;
if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END)
{
if (pikrellcam.debug_fps && (utime = micro_elapsed_time(&timer)) > 0)
printf("%s fps %d\n", obj->name, 1000000 / utime);
}
}
}
else
{
++encoder_busy_count;
if (pikrellcam.debug)
printf("encoder not clear (%d) -> skipping mjpeg frame.\n",
encoder_busy_count);
if (encoder_busy_count > 2) /* Frame maybe dropped ??, move on */
else /* buffer_in NULL means all encoder input buffers are
| still in use, so mjpeg encoder is stalled.
*/
{
++pikrellcam.mjpeg_stall_count;
if (pikrellcam.do_preview_save)
log_printf("%s: encoder is stalled -> preview save delayed\n",
fname_base(pikrellcam.video_pathname));
pthread_mutex_lock(&mjpeg_encoder_frame_count_lock);
if (mjpeg_encoder_send_frame
> mjpeg_encoder_recv_frame + N_MJPEG_ENCODER_INPUT_BUFFERS)
{
/* Means a mjpeg conversion got lost in the encoder.
| Probably should not happen.
*/
mjpeg_encoder_recv_frame = mjpeg_encoder_send_frame
- N_MJPEG_ENCODER_INPUT_BUFFERS;
}
pthread_mutex_unlock(&mjpeg_encoder_frame_count_lock);
if (pikrellcam.debug)
printf(" Syncing recv/send counts.\n");
encoder_busy_count = 0;
mjpeg_encoder_recv_count = mjpeg_encoder_send_count;
printf("mjpeg encoder stalled (%d) -> skipping preview frame.\n",
pikrellcam.mjpeg_stall_count);
}
}
if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END)
{
if (pikrellcam.debug_fps && (utime = micro_elapsed_time(&timer)) > 0)
printf("%s fps %d\n", obj->name, 1000000 / utime);
}
}
return_buffer_to_port(port, buffer);
}
@ -1127,11 +1118,11 @@ splitter_create(char *name, CameraObject *splitter, MMAL_PORT_T *src_port)
boolean
camera_create(void)
{
MMAL_PORT_T *port;
MMAL_STATUS_T status;
char *msg = "mmal_component_create";
MMAL_PORT_T *port;
MMAL_STATUS_T status;
MMAL_COMPONENT_T *camera_info;
char *msg = "mmal_component_create";
camera.name = "RPi camera";
if ((status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA,
&camera.component)) == MMAL_SUCCESS)
{
@ -1148,6 +1139,32 @@ camera_create(void)
mmal_component_destroy(camera.component);
return FALSE;
}
camera.name = strdup("ov5647"); // default to V1
pikrellcam.camera_width_max = 2592;
pikrellcam.camera_height_max = 1944;
if ((status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA_INFO,
&camera_info)) == MMAL_SUCCESS)
{
MMAL_PARAMETER_CAMERA_INFO_T param;
param.hdr.id = MMAL_PARAMETER_CAMERA_INFO;
param.hdr.size = sizeof(param);
status = mmal_port_parameter_get(camera_info->control, &param.hdr);
if (status == MMAL_SUCCESS)
{
free(camera.name);
camera.name = strdup(param.cameras[0].camera_name);
pikrellcam.camera_width_max = (int) param.cameras[0].max_width;
pikrellcam.camera_height_max = (int) param.cameras[0].max_height;
}
mmal_component_destroy(camera_info);
}
log_printf("camera info: %s max width: %d max height: %d\n",
camera.name,
pikrellcam.camera_width_max, pikrellcam.camera_height_max);
video_circular_buffer.h264_header_position = 0;
MMAL_PARAMETER_CAMERA_CONFIG_T camera_config =
@ -1244,6 +1261,8 @@ jpeg_encoder_create(char *name, CameraObject *encoder,
*/
mmal_format_copy(in_port->format, src_port->format);
in_port->buffer_size = src_port->buffer_size;
if (!strcmp(name, "mjpeg_encoder"))
in_port->buffer_num = N_MJPEG_ENCODER_INPUT_BUFFERS;
msg = "mmal_port_format_commit(in_port)";
status = mmal_port_format_commit(in_port);
}

View File

@ -1,6 +1,6 @@
/* PiKrellCam
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
| Copyright (C) 2015-2020 Bill Wilson billw@gkrellm.net
|
| PiKrellCam is free software: you can redistribute it and/or modify it
| under the terms of the GNU General Public License as published by
@ -890,8 +890,11 @@ motion_frame_process(VideoCircularBuffer *vcb, MotionFrame *mf)
|| (mf->fifo_trigger_mode & FIFO_TRIG_MODE_ENABLE)
)
&& !pikrellcam.servo_moving
&& pikrellcam.zoom_motion_holdoff == 0
&& (pikrellcam.on_preset || pikrellcam.motion_off_preset)
);
if (pikrellcam.zoom_motion_holdoff > 0)
--pikrellcam.zoom_motion_holdoff;
if ( ( (mf->motion_status & MOTION_DETECTED)
&& motion_enabled

View File

@ -1,6 +1,6 @@
/* PiKrellCam
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
| Copyright (C) 2015-2020 Bill Wilson billw@gkrellm.net
|
| PiKrellCam is free software: you can redistribute it and/or modify it
| under the terms of the GNU General Public License as published by
@ -129,7 +129,7 @@ multicast_message_id_repeat(char *hostname, int message_id)
static void
multicast_ack(char *to_host, int message_id)
{
char message[64];
char message[200];
snprintf(message, sizeof(message), "%s ack %d", to_host, message_id);
multicast_send("", message);

View File

@ -1,6 +1,6 @@
/* PiKrellCam
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
| Copyright (C) 2015-2020 Bill Wilson billw@gkrellm.net
|
| PiKrellCam is free software: you can redistribute it and/or modify it
| under the terms of the GNU General Public License as published by
@ -1139,6 +1139,7 @@ typedef enum
servo_cmd,
preset_cmd,
multicast,
zoom,
verbose,
verbose_log,
upgrade,
@ -1200,6 +1201,7 @@ static Command commands[] =
{ "preset", preset_cmd, 1, FALSE },
{ "servo", servo_cmd, 1, FALSE },
{ "multicast", multicast, 1, TRUE },
{ "zoom", zoom, 1, TRUE },
{ "verbose", verbose, 1, TRUE },
{ "verbose_log", verbose_log, 1, TRUE },
{ "upgrade", upgrade, 0, TRUE },
@ -1215,7 +1217,7 @@ command_process(char *command_line)
{
VideoCircularBuffer *vcb = &video_circular_buffer;
Command *cmd;
char command[64], args[256], arg1[128], arg2[64], arg3[256], buf[128];
char command[64], args[256], arg1[128], arg2[64], arg3[256], buf[300];
char *fmt, *path;
int i, n;
float f;
@ -1657,6 +1659,14 @@ command_process(char *command_line)
servo_command(args);
break;
case zoom:
sscanf(args, "%d", &n);
if (n >= 10 && n <= 100)
zoom_percent(n);
else
log_printf("Bad percent arg for command: %s\n", command);
break;
case verbose:
config_set_boolean(&pikrellcam.verbose, args);
break;

View File

@ -1,6 +1,6 @@
/* PiKrellCam
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
| Copyright (C) 2015-2020 Bill Wilson billw@gkrellm.net
|
| PiKrellCam is free software: you can redistribute it and/or modify it
| under the terms of the GNU General Public License as published by
@ -57,7 +57,7 @@
#include "utils.h"
#define PIKRELLCAM_VERSION "4.3.1"
#define PIKRELLCAM_VERSION "4.3.2"
//TCP Stream Server
@ -468,6 +468,15 @@ typedef struct
/* -------------- The Global PiKrellCam Environment -----------
*/
typedef struct
{
double x,
y,
width,
height;
}
RoiRect;
typedef struct
{
int event_gap,
@ -520,7 +529,8 @@ typedef struct
int mag_limit,
mag_limit_count,
burst_count,
burst_frames;
burst_frames,
zoom_percent;
SList *region_list; /* string "xf0 yf0 dxf dyf" */
}
PresetSettings;
@ -605,7 +615,10 @@ typedef struct
motion_magnitude_limit_count,
motion_burst_count,
motion_burst_frames,
motion_record_time_limit;
motion_record_time_limit,
zoom_percent,
zoom_percent_prev,
zoom_motion_holdoff;
time_t motion_sync_time;
@ -641,11 +654,16 @@ typedef struct
motion_show_counts;
int motion_area_min_side;
boolean preview_stall_warning;
CameraConfig
camera_config;
CameraAdjust
camera_adjust;
int camera_width_max,
camera_height_max;
char *video_motion_name_format,
*video_manual_name_format,
*video_h264,
@ -686,7 +704,8 @@ typedef struct
int mjpeg_width,
mjpeg_height,
mjpeg_quality,
mjpeg_divider;
mjpeg_divider,
mjpeg_stall_count;
char *still_name_format,
*still_last,
@ -780,6 +799,7 @@ typedef struct
*iso,
*metering_mode,
*video_stabilisation,
// *draw_focus_box,
*exposure_compensation,
*exposure_mode,
*white_balance,
@ -913,6 +933,9 @@ boolean mmalcam_config_parameter_set(char *name, char *value, boolean set_camer
CameraParameter
*mmalcam_config_parameter_get(char *name);
void zoom_percent(int percent);
extern boolean config_load(char *config_file);
extern void config_save(char *config_file);
extern void config_set_defaults(char *homedir);
@ -963,6 +986,7 @@ void display_command(char *cmd_line);
void display_draw(uint8_t *i420);
void display_inform(char *args);
void display_inform_clear(void);
void display_motion_limit_adjustment_sync(PresetSettings *settings);
void display_quit(void);

View File

@ -1,7 +1,7 @@
/* PiKrellCam
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
| Copyright (C) 2015-2020 Bill Wilson billw@gkrellm.net
|
| PiKrellCam is free software: you can redistribute it and/or modify it
| under the terms of the GNU General Public License as published by
@ -258,6 +258,9 @@ preset_load_values(boolean do_pan)
pikrellcam.motion_magnitude_limit_count = settings->mag_limit_count;
pikrellcam.motion_burst_count = settings->burst_count;
pikrellcam.motion_burst_frames = settings->burst_frames;
pikrellcam.zoom_percent = settings->zoom_percent;
zoom_percent(pikrellcam.zoom_percent);
display_motion_limit_adjustment_sync(settings);
}
save_show = mf->show_preset;
motion_command("delete_regions all");
@ -311,6 +314,7 @@ preset_settings_set_modified(void)
settings->mag_limit_count = pikrellcam.motion_magnitude_limit_count;
settings->burst_count = pikrellcam.motion_burst_count;
settings->burst_frames = pikrellcam.motion_burst_frames;
settings->zoom_percent = pikrellcam.zoom_percent;
pikrellcam.preset_modified = TRUE;
}
}
@ -387,6 +391,7 @@ preset_new(PresetPosition *pos_src)
settings->mag_limit_count = settings_src->mag_limit_count;
settings->burst_count = settings_src->burst_count;
settings->burst_frames = settings_src->burst_frames;
settings->zoom_percent = settings_src->zoom_percent;
for (rlist = settings_src->region_list; rlist; rlist = rlist->next)
{
region = strdup((char *) rlist->data);
@ -408,6 +413,7 @@ preset_new(PresetPosition *pos_src)
settings->mag_limit_count = pikrellcam.motion_magnitude_limit_count;
settings->burst_count = pikrellcam.motion_burst_count;
settings->burst_frames = pikrellcam.motion_burst_frames;
settings->zoom_percent = pikrellcam.zoom_percent;
preset_settings_regions_set(settings);
preset_notify(18);
}
@ -539,7 +545,10 @@ preset_command(char *cmd_line)
preset_notify(18);
}
else
{
preset_notify(10);
zoom_percent(pikrellcam.zoom_percent);
}
}
else
preset_load_values(TRUE);
@ -560,7 +569,10 @@ preset_command(char *cmd_line)
preset_notify(18);
}
else
{
preset_notify(10);
zoom_percent(pikrellcam.zoom_percent);
}
}
else
preset_load_values(TRUE);
@ -742,6 +754,7 @@ preset_config_load(void)
settings = calloc(1, sizeof(PresetSettings));
pos->settings_list = slist_append(pos->settings_list, settings);
pos->n_settings += 1;
settings->zoom_percent = 100;
continue;
}
if (!settings)
@ -760,6 +773,8 @@ preset_config_load(void)
sscanf(buf + 12, "%d", &settings->burst_count);
else if (!strncmp(buf, "burst_frames", 12))
sscanf(buf + 13, "%d", &settings->burst_frames);
else if (!strncmp(buf, "zoom_percent", 12))
sscanf(buf + 13, "%d", &settings->zoom_percent);
else if (!strncmp(buf, "add_region", 10))
{
region = strdup(buf); /* string "add_region xf0 yf0 dxf dyf" */
@ -797,6 +812,7 @@ preset_config_save(void)
fprintf(f, "magnitude_count %d\n", settings->mag_limit_count);
fprintf(f, "burst_count %d\n", settings->burst_count);
fprintf(f, "burst_frames %d\n", settings->burst_frames);
fprintf(f, "zoom_percent %d\n", settings->zoom_percent);
for (rlist = settings->region_list; rlist; rlist = rlist->next)
{
region = (char *) rlist->data; /* string "add_region xf0 yf0 dxf dyf" */

View File

@ -1,7 +1,7 @@
/* PiKrellCam
|
| Copyright (C) 2015-2019 Bill Wilson billw@gkrellm.net
| Copyright (C) 2015-2020 Bill Wilson billw@gkrellm.net
|
| PiKrellCam is free software: you can redistribute it and/or modify it
| under the terms of the GNU General Public License as published by

View File

@ -70,6 +70,14 @@ And there is a Raspberry Pi
<span style='font-size: 1.5em; font-weight: 650;'>Recent Release Notes</span><hr>
<div class='indent0'>
Version 4.3.2
<div class='indent1'>
Detect camera to determine resolution options shown in GUI and added
resolutions for HQ camera.<br>
Setup->Preset->Settings-><a href="help.php#ZOOM_PERCENT">Zoom_Percent.</a><br>
Setup->Config->Settings-><a href="help.php#STALL_WARNING">Preview_Stall_Warning.</a>
</div>
<br>
Version 4.3.1 - video_mp4box_fps can be fractional. For audio/video drift
tuning.
<br>
@ -828,6 +836,19 @@ Preset group and there will be no Servo button in the Config group.
field of view. Set the value higher to decrease detection of large objects passing
quickly through the field of view.
</li>
<a name="ZOOM_PERCENT">
<p>
<li><span style='font-weight:700'>Zoom_Percent</span> -
is the percent width and height of the camera sensor used for
imaging. Set the percent lower to digitally zoom in for videos
and stills. Moderate zooming can tune the camera field of view
at the expense of some resolution as fewer pixels may be used to
convert to stills or videos.
While viewing the web page preview, a larger zoom (lower percent
value) magnifies the pixels and is useful for camera focusing.<br>
If a zoom value is selected, it is saved as part of the current
preset along with the motion limit and motion region settings.
</li>
</ul>
</li>
<p>
@ -1064,6 +1085,27 @@ Preset group and there will be no Servo button in the Config group.
is normally not desirable, so the option should be set
<span style='font-weight:700'>ON</span>.
</li>
<a name="STALL_WARNING">
<p>
<li><span style='font-weight:700'>Preview_Stall_Warning</span>
- default is
<span style='font-weight:700'>ON</span>.
Enable showing a warning on the web preview if the preview jpeg
encoder stalls when hitting GPU performance limits which cause
preview frames to be lost.
The solution is to lower video_fps until the stalls stop or at
least become infrequent.
This strangely seems more an issue (at least with current
firmware) with the HQ camera on the Pi 4. With an HQ camera
on a Pi 4 I needed to lower video_fps to 20 to avoid stalls,
but on a P2 the HQ camera ran without stalls at video_fps 24.
I've not seen this issue with V1 or V2 cameras.<br>
If this option is
<span style='font-weight:700'>OFF</span>,
the warning is still enabled when showing preset information
with the
<span style='font-weight:700'>Show: Preset</span> button.
</li>
</ul>
</li>
<p>
@ -1993,6 +2035,8 @@ preset prev_settings
preset next_settings
preset goto position settings
zoom percent - percent is 10-100
display [command] - commands sent by the web page to display OSD menus. Not intended for
script or command line use.