mirror of
https://github.com/Motion-Project/motion.git
synced 2026-06-12 07:44:34 -04:00
Merge branch 'dfries-unstable' into unstable
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
5
CREDITS
5
CREDITS
@@ -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
12
alg.c
@@ -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
26
conf.c
@@ -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
2
conf.h
@@ -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;
|
||||
|
||||
@@ -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
154
motion.c
@@ -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;
|
||||
|
||||
4
motion.h
4
motion.h
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
1
video.h
1
video.h
@@ -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;
|
||||
|
||||
77
video2.c
77
video2.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
22
webhttpd.c
22
webhttpd.c
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user