Merge branch 'dfries-unstable' into unstable

This commit is contained in:
Mr Dave
2015-08-26 21:01:07 -06:00
13 changed files with 236 additions and 82 deletions

View File

@@ -89,6 +89,9 @@ Features
* Bug fix as part of warnings in webhttpd.c fixed(Mr-Dave)
* Removed compiler warning regarding ffmpeg being newer than 0.4 version(Mr-Dave)
* New configure script and identification of ffmpeg version and additional libs. (Mr-Dave)
* Allow text format specifiers to take a width like printf would. (David Fries)
* Allow text format specifiers to take a width like printf would. (David Fries)
* Add power_line_frequency configuration item to improve image quality. (David Fries)
* Resolve additional compiler warnings in ffmpeg (Mr-Dave)
* Revised INSTALL with samples(Mr-Dave)
* Revisions for RTSP and code standard.(Mr-Dave)
@@ -147,6 +150,7 @@ Bugfixes
* Fixed leak in vloopback.
* Fixed a build of motion for some kernel version with not good videodev.h
* Netcam Modulo 8
* Fix webhttpd race condition crash with SIGHUP, add it to running thread counter (David Fries)
3.2.12 Summary of Changes

View File

@@ -473,6 +473,11 @@ Mark Feenstra
Miguel Freitas
* Came up with the round robing idea.
David Fries
* Fix webhttpd race condition crash with SIGHUP, add it to running thread counter
* Allow text format specifiers to take a width like printf would.
* Add power_line_frequency configuration item to improve image quality.
Aaron Gage
* Pointed me to the vid_mmap/int problem when calling SYNC in
video.c

12
alg.c
View File

@@ -526,6 +526,8 @@ static int alg_labeling(struct context *cnt)
int height = imgs->height;
int labelsize = 0;
int current_label = 2;
/* Keep track of the area just under the threshold. */
int max_under = 0;
cnt->current_image->total_labels = 0;
imgs->labelsize_max = 0;
@@ -561,7 +563,8 @@ static int alg_labeling(struct context *cnt)
labelsize = iflood(ix, iy, width, height, out, labels, current_label + 32768, current_label);
imgs->labelgroup_max += labelsize;
imgs->labels_above++;
}
} else if(max_under < labelsize)
max_under = labelsize;
if (imgs->labelsize_max < labelsize) {
imgs->labelsize_max = labelsize;
@@ -579,8 +582,11 @@ static int alg_labeling(struct context *cnt)
"Largest Label: %i", imgs->largest_label, imgs->labelsize_max,
cnt->current_image->total_labels);
/* Return group of significant labels. */
return imgs->labelgroup_max;
/* Return group of significant labels or if that's none, the next largest
* group (which is under the threshold, but especially for setup gives an
* idea how close it was).
*/
return imgs->labelgroup_max ? imgs->labelgroup_max : max_under;
}
/**

26
conf.c
View File

@@ -71,6 +71,7 @@ struct config conf_template = {
contrast: 0,
saturation: 0,
hue: 0,
power_line_frequency: -1,
roundrobin_frames: 1,
roundrobin_skip: 1,
pre_capture: 0,
@@ -470,6 +471,22 @@ config_param config_params[] = {
print_int
},
{
"power_line_frequency",
"# Set the power line frequency to help cancel flicker by compensating\n"
"# for light intensity ripple. (default: -1).\n"
"# This can help reduce power line light flicker.\n"
"# Valuse :\n"
"# do not modify the device setting : -1\n"
"# V4L2_CID_POWER_LINE_FREQUENCY_DISABLED : 0\n"
"# V4L2_CID_POWER_LINE_FREQUENCY_50HZ : 1\n"
"# V4L2_CID_POWER_LINE_FREQUENCY_60HZ : 2\n"
"# V4L2_CID_POWER_LINE_FREQUENCY_AUTO : 3",
0,
CONF_OFFSET(power_line_frequency),
copy_int,
print_int
},
{
"roundrobin_frames",
"\n############################################################\n"
"# Round Robin (multiple inputs on same video device name)\n"
@@ -661,6 +678,15 @@ config_param config_params[] = {
print_string
},
{
"ffmpeg_duplicate_frames",
"# True to duplicate frames to achieve \"framerate\" fps, but enough\n"
"duplicated frames and the video appears to freeze once a second.",
0,
CONF_OFFSET(ffmpeg_duplicate_frames),
copy_bool,
print_bool
},
{
"output_debug_pictures",
"# Output pictures with only the pixels moving object (ghost images) (default: off)",
0,

2
conf.h
View File

@@ -30,6 +30,7 @@ struct config {
int max_changes;
int threshold_tune;
const char *output_pictures;
int ffmpeg_duplicate_frames;
int motion_img;
int emulate_motion;
int event_gap;
@@ -53,6 +54,7 @@ struct config {
int contrast;
int saturation;
int hue;
int power_line_frequency;
int roundrobin_frames;
int roundrobin_skip;
int pre_capture;

View File

@@ -818,7 +818,7 @@ int decode_jpeg_gray_raw(unsigned char *jpeg_data, int len,
guarantee_huff_tables(&dinfo);
jpeg_start_decompress (&dinfo);
vsf[0]= 1; vsf[1] = 1; vsf[2] = 1;
vsf[0] = 1; vsf[1] = 1; vsf[2] = 1;
/* Height match image height or be exact twice the image height. */

154
motion.c
View File

@@ -134,6 +134,7 @@ static void image_ring_resize(struct context *cnt, int new_size)
/* Point to the new ring */
cnt->imgs.image_ring = tmp;
cnt->current_image = NULL;
cnt->imgs.image_ring_size = new_size;
}
@@ -168,13 +169,14 @@ static void image_ring_destroy(struct context *cnt)
free(cnt->imgs.image_ring);
cnt->imgs.image_ring = NULL;
cnt->current_image = NULL;
cnt->imgs.image_ring_size = 0;
}
/**
* image_save_as_preview
*
* This routine is called when we detect motion and want to save a image in the preview buffer
* This routine is called when we detect motion and want to save an image in the preview buffer
*
* Parameters:
*
@@ -341,6 +343,7 @@ static void sig_handler(int signo)
while (cnt_list[++i]) {
cnt_list[i]->makemovie = 1;
cnt_list[i]->finish = 1;
cnt_list[i]->webcontrol_finish = 1;
/*
* Don't restart thread when it ends,
* all threads restarts if global restart is set
@@ -356,6 +359,9 @@ static void sig_handler(int signo)
break;
case SIGSEGV:
exit(0);
case SIGVTALRM:
printf("SIGVTALRM went off\n");
break;
}
}
@@ -565,8 +571,13 @@ static void process_image_ring(struct context *cnt, unsigned int max_images)
/*
* Check if we must add any "filler" frames into movie to keep up fps
* Only if we are recording videos ( ffmpeg or extenal pipe )
* While the overall elapsed time might be correct, if there are
* many duplicated frames, say 10 fps, 5 duplicated, the video will
* look like it is frozen every second for half a second.
*/
if ((cnt->imgs.image_ring[cnt->imgs.image_ring_out].shot == 0) &&
if (!cnt->conf.ffmpeg_duplicate_frames) {
/* don't duplicate frames */
} else if ((cnt->imgs.image_ring[cnt->imgs.image_ring_out].shot == 0) &&
#ifdef HAVE_FFMPEG
(cnt->ffmpeg_output || (cnt->conf.useextpipe && cnt->extpipe))) {
#else
@@ -1088,8 +1099,6 @@ static void *motion_loop(void *arg)
*/
unsigned long int time_last_frame = 1, time_current_frame;
cnt->running = 1;
if (motion_init(cnt) < 0)
goto err;
@@ -2526,6 +2535,10 @@ static void setup_signals(struct sigaction *sig_handler_action, struct sigaction
sigaction(SIGQUIT, sig_handler_action, NULL);
sigaction(SIGTERM, sig_handler_action, NULL);
sigaction(SIGUSR1, sig_handler_action, NULL);
/* use SIGVTALRM as a way to break out of the ioctl, don't restart */
sig_handler_action->sa_flags = 0;
sigaction(SIGVTALRM, sig_handler_action, NULL);
}
/**
@@ -2595,11 +2608,22 @@ static void start_motion_thread(struct context *cnt, pthread_attr_t *thread_attr
/* Give the thread WATCHDOG_TMO to start */
cnt->watchdog = WATCHDOG_TMO;
/* Flag it as running outside of the thread, otherwise if the main loop
* checked if it is was running before the thread set it to 1, it would
* start another thread for this device. */
cnt->running = 1;
/*
* Create the actual thread. Use 'motion_loop' as the thread
* function.
*/
pthread_create(&cnt->thread_id, thread_attr, &motion_loop, cnt);
if (pthread_create(&cnt->thread_id, thread_attr, &motion_loop, cnt)) {
/* thread create failed, undo running state */
cnt->running = 0;
pthread_mutex_lock(&global_lock);
threads_running--;
pthread_mutex_unlock(&global_lock);
}
}
/**
@@ -2714,8 +2738,21 @@ int main (int argc, char **argv)
* Create a thread for the control interface if requested. Create it
* detached and with 'motion_web_control' as the thread function.
*/
if (cnt_list[0]->conf.webcontrol_port)
pthread_create(&thread_id, &thread_attr, &motion_web_control, cnt_list);
if (cnt_list[0]->conf.webcontrol_port) {
pthread_mutex_lock(&global_lock);
threads_running++;
/* set outside the loop to avoid thread set vs main thread check */
cnt_list[0]->webcontrol_running = 1;
pthread_mutex_unlock(&global_lock);
if (pthread_create(&thread_id, &thread_attr, &motion_web_control,
cnt_list)) {
/* thread create failed, undo running state */
pthread_mutex_lock(&global_lock);
threads_running--;
cnt_list[0]->webcontrol_running = 0;
pthread_mutex_unlock(&global_lock);
}
}
MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Waiting for threads to finish, pid: %d",
getpid());
@@ -2728,7 +2765,7 @@ int main (int argc, char **argv)
SLEEP(1, 0);
/*
* Calculate how many threads runnig or wants to run
* Calculate how many threads are running or wants to run
* if zero and we want to finish, break out
*/
int motion_threads_running = 0;
@@ -2737,6 +2774,9 @@ int main (int argc, char **argv)
if (cnt_list[i]->running || cnt_list[i]->restart)
motion_threads_running++;
}
if (cnt_list[0]->conf.webcontrol_port &&
cnt_list[0]->webcontrol_running)
motion_threads_running++;
if (((motion_threads_running == 0) && finish) ||
((motion_threads_running == 0) && (threads_running == 0))) {
@@ -2754,24 +2794,42 @@ int main (int argc, char **argv)
}
if (cnt_list[i]->watchdog > WATCHDOG_OFF) {
cnt_list[i]->watchdog--;
if (cnt_list[i]->watchdog == WATCHDOG_KILL) {
/* if 0 then it finally did clean up (and will restart without any further action here)
* kill(, 0) == ESRCH means the thread is no longer running
* if it is no longer running with running set, then cleanup here so it can restart
*/
if(cnt_list[i]->running && pthread_kill(cnt_list[i]->thread_id, 0) == ESRCH) {
MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: cleaning Thread %d", cnt_list[i]->threadnr);
pthread_mutex_lock(&global_lock);
threads_running--;
pthread_mutex_unlock(&global_lock);
motion_cleanup(cnt_list[i]);
cnt_list[i]->running = 0;
cnt_list[i]->finish = 0;
} else {
/* keep sending signals so it doesn't get stuck in a blocking call */
pthread_kill(cnt_list[i]->thread_id, SIGVTALRM);
}
} else {
cnt_list[i]->watchdog--;
if (cnt_list[i]->watchdog == 0) {
MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Thread %d - Watchdog timeout, trying to do "
"a graceful restart", cnt_list[i]->threadnr);
cnt_list[i]->finish = 1;
}
if (cnt_list[i]->watchdog == -60) {
MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Thread %d - Watchdog timeout, did NOT restart graceful,"
"killing it!", cnt_list[i]->threadnr);
pthread_cancel(cnt_list[i]->thread_id);
pthread_mutex_lock(&global_lock);
threads_running--;
pthread_mutex_unlock(&global_lock);
motion_cleanup(cnt_list[i]);
cnt_list[i]->running = 0;
cnt_list[i]->finish = 0;
if (cnt_list[i]->watchdog == 0) {
MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Thread %d - Watchdog timeout, trying to do "
"a graceful restart", cnt_list[i]->threadnr);
cnt_list[i]->finish = 1;
}
if (cnt_list[i]->watchdog == WATCHDOG_KILL) {
MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Thread %d - Watchdog timeout, did NOT restart graceful,"
"killing it!", cnt_list[i]->threadnr);
/* The problem is pthead_cancel might just wake up the thread so it runs to completition
* or it might not. In either case don't rip the carpet out under it by
* doing motion_cleanup until it no longer is running.
*/
pthread_cancel(cnt_list[i]->thread_id);
}
}
}
}
@@ -2796,7 +2854,7 @@ int main (int argc, char **argv)
// Be sure that http control exits fine
cnt_list[0]->finish = 1;
cnt_list[0]->webcontrol_finish = 1;
SLEEP(1, 0);
MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Motion terminating");
@@ -3098,6 +3156,7 @@ size_t mystrftime(const struct context *cnt, char *s, size_t max, const char *us
char tempstring[PATH_MAX] = "";
char *format, *tempstr;
const char *pos_userformat;
int width;
format = formatstring;
@@ -3117,6 +3176,12 @@ size_t mystrftime(const struct context *cnt, char *s, size_t max, const char *us
*/
tempstr = tempstring;
tempstr[0] = '\0';
width = 0;
while ('0' <= pos_userformat[1] && pos_userformat[1] <= '9') {
width *= 10;
width += pos_userformat[1] - '0';
++pos_userformat;
}
switch (*++pos_userformat) {
case '\0': // end of string
@@ -3124,81 +3189,86 @@ size_t mystrftime(const struct context *cnt, char *s, size_t max, const char *us
break;
case 'v': // event
sprintf(tempstr, "%02d", cnt->event_nr);
sprintf(tempstr, "%0*d", width ? width : 2, cnt->event_nr);
break;
case 'q': // shots
sprintf(tempstr, "%02d", cnt->current_image->shot);
sprintf(tempstr, "%0*d", width ? width : 2,
cnt->current_image->shot);
break;
case 'D': // diffs
sprintf(tempstr, "%d", cnt->current_image->diffs);
sprintf(tempstr, "%*d", width, cnt->current_image->diffs);
break;
case 'N': // noise
sprintf(tempstr, "%d", cnt->noise);
sprintf(tempstr, "%*d", width, cnt->noise);
break;
case 'i': // motion width
sprintf(tempstr, "%d", cnt->current_image->location.width);
sprintf(tempstr, "%*d", width,
cnt->current_image->location.width);
break;
case 'J': // motion height
sprintf(tempstr, "%d", cnt->current_image->location.height);
sprintf(tempstr, "%*d", width,
cnt->current_image->location.height);
break;
case 'K': // motion center x
sprintf(tempstr, "%d", cnt->current_image->location.x);
sprintf(tempstr, "%*d", width, cnt->current_image->location.x);
break;
case 'L': // motion center y
sprintf(tempstr, "%d", cnt->current_image->location.y);
sprintf(tempstr, "%*d", width, cnt->current_image->location.y);
break;
case 'o': // threshold
sprintf(tempstr, "%d", cnt->threshold);
sprintf(tempstr, "%*d", width, cnt->threshold);
break;
case 'Q': // number of labels
sprintf(tempstr, "%d", cnt->current_image->total_labels);
sprintf(tempstr, "%*d", width,
cnt->current_image->total_labels);
break;
case 't': // thread number
sprintf(tempstr, "%d",(int)(unsigned long)
sprintf(tempstr, "%*d", width, (int)(unsigned long)
pthread_getspecific(tls_key_threadnr));
break;
case 'C': // text_event
if (cnt->text_event_string && cnt->text_event_string[0])
snprintf(tempstr, PATH_MAX, "%s", cnt->text_event_string);
snprintf(tempstr, PATH_MAX, "%*s", width,
cnt->text_event_string);
else
++pos_userformat;
break;
case 'w': // picture width
sprintf(tempstr, "%d", cnt->imgs.width);
sprintf(tempstr, "%*d", width, cnt->imgs.width);
break;
case 'h': // picture height
sprintf(tempstr, "%d", cnt->imgs.height);
sprintf(tempstr, "%*d", width, cnt->imgs.height);
break;
case 'f': // filename -- or %fps
if ((*(pos_userformat+1) == 'p') && (*(pos_userformat+2) == 's')) {
sprintf(tempstr, "%d", cnt->movie_fps);
sprintf(tempstr, "%*d", width, cnt->movie_fps);
pos_userformat += 2;
break;
}
if (filename)
snprintf(tempstr, PATH_MAX, "%s", filename);
snprintf(tempstr, PATH_MAX, "%*s", width, filename);
else
++pos_userformat;
break;
case 'n': // sqltype
if (sqltype)
sprintf(tempstr, "%d", sqltype);
sprintf(tempstr, "%*d", width, sqltype);
else
++pos_userformat;
break;

View File

@@ -149,6 +149,7 @@
*/
#define WATCHDOG_TMO 30 /* 30 sec max motion_loop interval */
#define WATCHDOG_KILL -60 /* -60 sec grace period before calling thread cancel */
#define WATCHDOG_OFF -127 /* Turn off watchdog, used when we wants to quit a thread */
#define CONNECTION_KO "Lost connection"
@@ -370,6 +371,9 @@ struct context {
volatile unsigned int restart; /* Restart the thread when it ends */
/* Is the motion thread running */
volatile unsigned int running;
/* Is the web control thread running */
volatile unsigned int webcontrol_running;
volatile unsigned int webcontrol_finish; /* End the thread */
volatile int watchdog;
pthread_t thread_id;

View File

@@ -786,12 +786,11 @@ int ftp_get_socket(ftp_context_pointer ctxt)
*/
int ftp_send_type(ftp_context_pointer ctxt, char type)
{
char buf[100];
char buf[100], utype;
int len, res;
toupper(type);
/* Assure transfer will be in "image" mode. */
snprintf(buf, sizeof(buf), "TYPE I\r\n");
utype = toupper(type);
snprintf(buf, sizeof(buf), "TYPE %c\r\n", utype);
len = strlen(buf);
res = send(ctxt->control_file_desc, buf, len, 0);

View File

@@ -65,6 +65,7 @@ struct video_dev {
int contrast;
int saturation;
int hue;
int power_line_frequency;
unsigned long freq;
int tuner_number;
int fps;

View File

@@ -144,6 +144,10 @@ static const u32 queried_ctrls[] = {
V4L2_CID_CONTRAST,
V4L2_CID_SATURATION,
V4L2_CID_HUE,
/* first added in Linux kernel v2.6.26 */
#ifdef V4L2_CID_POWER_LINE_FREQUENCY
V4L2_CID_POWER_LINE_FREQUENCY,
#endif
V4L2_CID_RED_BALANCE,
V4L2_CID_BLUE_BALANCE,
@@ -173,6 +177,7 @@ typedef struct {
u32 ctrl_flags;
struct v4l2_queryctrl *controls;
volatile unsigned int *finish; /* End the thread */
} src_v4l2_t;
@@ -180,16 +185,16 @@ typedef struct {
* xioctl
*/
#ifdef __OpenBSD__
static int xioctl(int fd, unsigned long request, void *arg)
static int xioctl(src_v4l2_t *vid_source, unsigned long request, void *arg)
#else
static int xioctl(int fd, int request, void *arg)
static int xioctl(src_v4l2_t *vid_source, int request, void *arg)
#endif
{
int ret;
do
ret = ioctl(fd, request, arg);
while (-1 == ret && EINTR == errno);
ret = ioctl(vid_source->fd, request, arg);
while (-1 == ret && EINTR == errno && !vid_source->finish);
return ret;
}
@@ -199,7 +204,7 @@ static int xioctl(int fd, int request, void *arg)
*/
static int v4l2_get_capability(src_v4l2_t * vid_source)
{
if (xioctl(vid_source->fd, VIDIOC_QUERYCAP, &vid_source->cap) < 0) {
if (xioctl(vid_source, VIDIOC_QUERYCAP, &vid_source->cap) < 0) {
MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, "%s: Not a V4L2 device?");
return -1;
}
@@ -262,7 +267,7 @@ static int v4l2_select_input(struct config *conf, struct video_dev *viddev,
input.index = IN_TV;
else input.index = in;
if (xioctl(vid_source->fd, VIDIOC_ENUMINPUT, &input) == -1) {
if (xioctl(vid_source, VIDIOC_ENUMINPUT, &input) == -1) {
MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: Unable to query input %d."
" VIDIOC_ENUMINPUT, if you use a WEBCAM change input value in conf by -1",
input.index);
@@ -278,7 +283,7 @@ static int v4l2_select_input(struct config *conf, struct video_dev *viddev,
if (input.type & V4L2_INPUT_TYPE_CAMERA)
MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "%s: - CAMERA");
if (xioctl(vid_source->fd, VIDIOC_S_INPUT, &input.index) == -1) {
if (xioctl(vid_source, VIDIOC_S_INPUT, &input.index) == -1) {
MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: Error selecting input %d"
" VIDIOC_S_INPUT", input.index);
return -1;
@@ -290,7 +295,7 @@ static int v4l2_select_input(struct config *conf, struct video_dev *viddev,
* Set video standard usually webcams doesn't support the ioctl or
* return V4L2_STD_UNKNOWN
*/
if (xioctl(vid_source->fd, VIDIOC_G_STD, &std_id) == -1) {
if (xioctl(vid_source, VIDIOC_G_STD, &std_id) == -1) {
MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO, "%s: Device doesn't support VIDIOC_G_STD");
norm = std_id = 0; // V4L2_STD_UNKNOWN = 0
}
@@ -299,7 +304,7 @@ static int v4l2_select_input(struct config *conf, struct video_dev *viddev,
memset(&standard, 0, sizeof(standard));
standard.index = 0;
while (xioctl(vid_source->fd, VIDIOC_ENUMSTD, &standard) == 0) {
while (xioctl(vid_source, VIDIOC_ENUMSTD, &standard) == 0) {
if (standard.id & std_id)
MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "%s: - video standard %s",
standard.name);
@@ -318,7 +323,7 @@ static int v4l2_select_input(struct config *conf, struct video_dev *viddev,
std_id = V4L2_STD_PAL;
}
if (xioctl(vid_source->fd, VIDIOC_S_STD, &std_id) == -1)
if (xioctl(vid_source, VIDIOC_S_STD, &std_id) == -1)
MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: Error selecting standard"
" method %d VIDIOC_S_STD", (int)std_id);
@@ -338,7 +343,7 @@ static int v4l2_select_input(struct config *conf, struct video_dev *viddev,
memset(&tuner, 0, sizeof(struct v4l2_tuner));
tuner.index = input.tuner;
if (xioctl(vid_source->fd, VIDIOC_G_TUNER, &tuner) == -1) {
if (xioctl(vid_source, VIDIOC_G_TUNER, &tuner) == -1) {
MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: tuner %d VIDIOC_G_TUNER",
tuner.index);
return 0;
@@ -353,7 +358,7 @@ static int v4l2_select_input(struct config *conf, struct video_dev *viddev,
freq.type = V4L2_TUNER_ANALOG_TV;
freq.frequency = (freq_ / 1000) * 16;
if (xioctl(vid_source->fd, VIDIOC_S_FREQUENCY, &freq) == -1) {
if (xioctl(vid_source, VIDIOC_S_FREQUENCY, &freq) == -1) {
MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: freq %ul VIDIOC_S_FREQUENCY",
freq.frequency);
return 0;
@@ -405,7 +410,7 @@ static int v4l2_do_set_pix_format(u32 pixformat, src_v4l2_t * vid_source,
vid_source->dst_fmt.fmt.pix.pixelformat = pixformat;
vid_source->dst_fmt.fmt.pix.field = V4L2_FIELD_ANY;
if (xioctl(vid_source->fd, VIDIOC_TRY_FMT, &vid_source->dst_fmt) != -1 &&
if (xioctl(vid_source, VIDIOC_TRY_FMT, &vid_source->dst_fmt) != -1 &&
vid_source->dst_fmt.fmt.pix.pixelformat == pixformat) {
MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "%s: Testing palette %c%c%c%c (%dx%d)",
pixformat >> 0, pixformat >> 8,
@@ -423,7 +428,7 @@ static int v4l2_do_set_pix_format(u32 pixformat, src_v4l2_t * vid_source,
*height = vid_source->dst_fmt.fmt.pix.height;
}
if (xioctl(vid_source->fd, VIDIOC_S_FMT, &vid_source->dst_fmt) == -1) {
if (xioctl(vid_source, VIDIOC_S_FMT, &vid_source->dst_fmt) == -1) {
MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: Error setting pixel "
"format.\nVIDIOC_S_FMT: ");
return -1;
@@ -502,7 +507,7 @@ static int v4l2_set_pix_format(struct context *cnt, src_v4l2_t * vid_source,
MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "%s: Supported palettes:");
while (xioctl(vid_source->fd, VIDIOC_ENUM_FMT, &fmtd) != -1) {
while (xioctl(vid_source, VIDIOC_ENUM_FMT, &fmtd) != -1) {
int i;
@@ -556,7 +561,7 @@ static void v4l2_set_fps(src_v4l2_t * vid_source) {
setfpvid_source->parm.capture.timeperframe.numerator = 1;
setfpvid_source->parm.capture.timeperframe.denominator = vid_source->fps;
if (xioctl(vid_source->fd, VIDIOC_S_PARM, setfps) == -1)
if (xioctl(vid_source, VIDIOC_S_PARM, setfps) == -1)
MOTION_LOG(ERR, 1, "%s: v4l2_set_fps VIDIOC_S_PARM");
@@ -581,7 +586,7 @@ static int v4l2_set_mmap(src_v4l2_t * vid_source)
vid_source->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vid_source->req.memory = V4L2_MEMORY_MMAP;
if (xioctl(vid_source->fd, VIDIOC_REQBUFS, &vid_source->req) == -1) {
if (xioctl(vid_source, VIDIOC_REQBUFS, &vid_source->req) == -1) {
MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: Error requesting buffers"
" %d for memory map. VIDIOC_REQBUFS",
vid_source->req.count);
@@ -613,7 +618,7 @@ static int v4l2_set_mmap(src_v4l2_t * vid_source)
buf.memory = V4L2_MEMORY_MMAP;
buf.index = buffer_index;
if (xioctl(vid_source->fd, VIDIOC_QUERYBUF, &buf) == -1) {
if (xioctl(vid_source, VIDIOC_QUERYBUF, &buf) == -1) {
MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: Error querying buffer"
" %i\nVIDIOC_QUERYBUF: ", buffer_index);
free(vid_source->buffers);
@@ -642,7 +647,7 @@ static int v4l2_set_mmap(src_v4l2_t * vid_source)
vid_source->buf.memory = V4L2_MEMORY_MMAP;
vid_source->buf.index = buffer_index;
if (xioctl(vid_source->fd, VIDIOC_QBUF, &vid_source->buf) == -1) {
if (xioctl(vid_source, VIDIOC_QBUF, &vid_source->buf) == -1) {
MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: VIDIOC_QBUF");
return -1;
}
@@ -650,7 +655,7 @@ static int v4l2_set_mmap(src_v4l2_t * vid_source)
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (xioctl(vid_source->fd, VIDIOC_STREAMON, &type) == -1) {
if (xioctl(vid_source, VIDIOC_STREAMON, &type) == -1) {
MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: Error starting stream."
" VIDIOC_STREAMON");
return -1;
@@ -671,7 +676,7 @@ static int v4l2_scan_controls(src_v4l2_t * vid_source)
for (i = 0, count = 0; queried_ctrls[i]; i++) {
queryctrl.id = queried_ctrls[i];
if (xioctl(vid_source->fd, VIDIOC_QUERYCTRL, &queryctrl))
if (xioctl(vid_source, VIDIOC_QUERYCTRL, &queryctrl))
continue;
count++;
@@ -692,7 +697,7 @@ static int v4l2_scan_controls(src_v4l2_t * vid_source)
struct v4l2_control control;
queryctrl.id = queried_ctrls[i];
if (xioctl(vid_source->fd, VIDIOC_QUERYCTRL, &queryctrl))
if (xioctl(vid_source, VIDIOC_QUERYCTRL, &queryctrl))
continue;
memcpy(ctrl, &queryctrl, sizeof(struct v4l2_queryctrl));
@@ -704,7 +709,7 @@ static int v4l2_scan_controls(src_v4l2_t * vid_source)
memset(&control, 0, sizeof (control));
control.id = queried_ctrls[i];
xioctl(vid_source->fd, VIDIOC_G_CTRL, &control);
xioctl(vid_source, VIDIOC_G_CTRL, &control);
MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "%s: \t\"%s\", default %d, current %d",
ctrl->name, ctrl->default_value, control.value);
@@ -740,14 +745,21 @@ static int v4l2_set_control(src_v4l2_t * vid_source, u32 cid, int value)
case V4L2_CTRL_TYPE_INTEGER:
value = control.value =
(value * (ctrl->maximum - ctrl->minimum) / 256) + ctrl->minimum;
ret = xioctl(vid_source->fd, VIDIOC_S_CTRL, &control);
ret = xioctl(vid_source, VIDIOC_S_CTRL, &control);
break;
case V4L2_CTRL_TYPE_BOOLEAN:
value = control.value = value ? 1 : 0;
ret = xioctl(vid_source->fd, VIDIOC_S_CTRL, &control);
ret = xioctl(vid_source, VIDIOC_S_CTRL, &control);
break;
case V4L2_CTRL_TYPE_MENU:
/* set as is, no adjustments */
control.value = value;
ret = xioctl(vid_source, VIDIOC_S_CTRL, &control);
break;
default:
MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO, "%s: control type not supported yet");
return -1;
@@ -788,6 +800,14 @@ static void v4l2_picture_controls(struct context *cnt, struct video_dev *viddev)
v4l2_set_control(vid_source, V4L2_CID_HUE, viddev->hue);
}
#ifdef V4L2_CID_POWER_LINE_FREQUENCY
/* -1 is don't modify as 0 is an option to disable the power line filter */
if (cnt->conf.power_line_frequency != -1 && cnt->conf.power_line_frequency != viddev->power_line_frequency) {
viddev->power_line_frequency = cnt->conf.power_line_frequency;
v4l2_set_control(vid_source, V4L2_CID_POWER_LINE_FREQUENCY, viddev->power_line_frequency);
}
#endif
if (cnt->conf.autobright) {
if (vid_do_autobright(cnt, viddev)) {
if (v4l2_set_control(vid_source, V4L2_CID_BRIGHTNESS, viddev->brightness))
@@ -822,6 +842,7 @@ unsigned char *v4l2_start(struct context *cnt, struct video_dev *viddev, int wid
vid_source->fd = viddev->fd;
vid_source->fps = cnt->conf.frame_limit;
vid_source->pframe = -1;
vid_source->finish = &cnt->finish;
struct config *conf = &cnt->conf;
if (v4l2_get_capability(vid_source))
@@ -965,7 +986,7 @@ int v4l2_next(struct context *cnt, struct video_dev *viddev, unsigned char *map,
vid_source->pframe);
if (vid_source->pframe >= 0) {
if (xioctl(vid_source->fd, VIDIOC_QBUF, &vid_source->buf) == -1) {
if (xioctl(vid_source, VIDIOC_QBUF, &vid_source->buf) == -1) {
MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: VIDIOC_QBUF");
pthread_sigmask(SIG_UNBLOCK, &old, NULL);
return -1;
@@ -977,7 +998,7 @@ int v4l2_next(struct context *cnt, struct video_dev *viddev, unsigned char *map,
vid_source->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vid_source->buf.memory = V4L2_MEMORY_MMAP;
if (xioctl(vid_source->fd, VIDIOC_DQBUF, &vid_source->buf) == -1) {
if (xioctl(vid_source, VIDIOC_DQBUF, &vid_source->buf) == -1) {
int ret;
/*
* Some drivers return EIO when there is no signal,
@@ -1082,7 +1103,7 @@ void v4l2_close(struct video_dev *viddev)
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
xioctl(vid_source->fd, VIDIOC_STREAMOFF, &type);
xioctl(vid_source, VIDIOC_STREAMOFF, &type);
close(vid_source->fd);
vid_source->fd = -1;
}

View File

@@ -732,6 +732,8 @@ static int vid_v4lx_start(struct context *cnt)
dev->contrast = 0;
dev->saturation = 0;
dev->hue = 0;
/* -1 is don't modify, (0 is a valid value) */
dev->power_line_frequency = -1;
dev->owner = -1;
dev->v4l_fmt = VIDEO_PALETTE_YUV420P;
dev->fps = 0;

View File

@@ -16,6 +16,9 @@
#include <netdb.h>
#include <stddef.h>
/* Timeout in seconds, used for read and write */
const int NONBLOCK_TIMEOUT = 1;
pthread_mutex_t httpd_mutex;
// This is a dummy variable use to kill warnings when not checking sscanf and similar functions
@@ -197,7 +200,7 @@ static ssize_t write_nonblock(int fd, const void *buf, size_t size)
struct timeval tm;
fd_set fds;
tm.tv_sec = 1; /* Timeout in seconds */
tm.tv_sec = NONBLOCK_TIMEOUT;
tm.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(fd, &fds);
@@ -223,7 +226,7 @@ static ssize_t read_nonblock(int fd ,void *buf, ssize_t size)
struct timeval tm;
fd_set fds;
tm.tv_sec = 1; /* Timeout in seconds */
tm.tv_sec = NONBLOCK_TIMEOUT; /* Timeout in seconds */
tm.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(fd, &fds);
@@ -2509,10 +2512,10 @@ void httpd_run(struct context **cnt)
while ((client_sent_quit_message) && (!closehttpd)) {
client_socket_fd = acceptnonblocking(sd, 1);
client_socket_fd = acceptnonblocking(sd, NONBLOCK_TIMEOUT);
if (client_socket_fd < 0) {
if ((!cnt[0]) || (cnt[0]->finish)) {
if ((!cnt[0]) || (cnt[0]->webcontrol_finish)) {
MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, "%s: motion-httpd - Finishing");
closehttpd = 1;
}
@@ -2542,6 +2545,17 @@ void *motion_web_control(void *arg)
{
struct context **cnt = arg;
httpd_run(cnt);
/*
* Update how many threads we have running. This is done within a
* mutex lock to prevent multiple simultaneous updates to
* 'threads_running'.
*/
pthread_mutex_lock(&global_lock);
threads_running--;
cnt[0]->webcontrol_running = 0;
pthread_mutex_unlock(&global_lock);
MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, "%s: motion-httpd thread exit");
pthread_exit(NULL);
}