Index: conf.c
===================================================================
--- conf.c	(revision 275)
+++ conf.c	(working copy)
@@ -117,6 +117,7 @@
 	on_motion_detected:    NULL,
 	on_movie_start:        NULL,
 	on_movie_end:          NULL,
+	on_camera_lost:        NULL,
 	motionvidpipe:         NULL,
 	netcam_url:            NULL,
 	netcam_userpass:       NULL,
@@ -1115,6 +1116,17 @@
 	copy_string,
 	print_string
 	},
+	{
+	"on_camera_lost",
+	"# Command to be executed when a camera can't be opened or if it is lost\n"
+	"# NOTE: There is situations when motion don't detect a lost camera!\n"
+	"# It depends on the driver, some drivers dosn't detect a lost camera at all\n"
+	"# Some hangs the motion thread. Some even hangs the PC! (default: none)\n",
+	0,
+	CONF_OFFSET(on_camera_lost),
+	copy_string,
+	print_string
+	},
 #ifdef HAVE_FFMPEG
 	{
 	"on_movie_start",
Index: conf.h
===================================================================
--- conf.h	(revision 275)
+++ conf.h	(working copy)
@@ -101,6 +101,7 @@
 	char *on_motion_detected;
 	char *on_movie_start;
 	char *on_movie_end;
+	char *on_camera_lost;
 	const char *motionvidpipe;
 	const char *netcam_url;
 	const char *netcam_userpass;
Index: event.c
===================================================================
--- event.c	(revision 275)
+++ event.c	(working copy)
@@ -329,6 +329,14 @@
 	cnt->snapshot = 0;
 }
 
+static void event_camera_lost(struct context *cnt, int type ATTRIBUTE_UNUSED,
+            unsigned char *img ATTRIBUTE_UNUSED, char *dummy1 ATTRIBUTE_UNUSED,
+            void *dummy2 ATTRIBUTE_UNUSED, struct tm *currenttime_tm)
+{
+	if (cnt->conf.on_camera_lost)
+		exec_command(cnt, cnt->conf.on_camera_lost, NULL, 0);
+}
+
 #ifdef HAVE_FFMPEG
 static void grey2yuv420p(unsigned char *u, unsigned char *v, int width, int height)
 {
@@ -660,6 +668,10 @@
 	},
 #endif /* HAVE_FFMPEG */
 	{
+	EVENT_CAMERA_LOST,
+	event_camera_lost
+	},
+	{
 	EVENT_STOP,
 	event_stop_webcam
 	},
Index: event.h
===================================================================
--- event.h	(revision 275)
+++ event.h	(working copy)
@@ -28,6 +28,7 @@
 #define EVENT_DEBUG             65536
 #define EVENT_CRITICAL          131072
 #define EVENT_AREA_DETECTED     262144
+#define EVENT_CAMERA_LOST       524288
 #
 
 typedef void(* event_handler)(struct context *, int, unsigned char *, char *, void *, struct tm *);
Index: motion.c
===================================================================
--- motion.c	(revision 275)
+++ motion.c	(working copy)
@@ -22,6 +22,11 @@
 #include "picture.h"
 #include "rotate.h"
 
+/* Forward declarations */
+static int motion_init(struct context *cnt);
+static void motion_cleanup(struct context *cnt);
+
+
 /**
  * tls_key_threadnr
  *
@@ -59,6 +64,10 @@
  */
 unsigned short int debug_level;
 
+/* Set this when we want main to end or restart
+ */
+volatile unsigned short int finish=0;
+
 /**
  * restart
  *
@@ -235,50 +244,6 @@
 {
 	unsigned short int j;
 
-	if (cnt->imgs.out)
-		free(cnt->imgs.out);
-	if (cnt->imgs.ref)
-		free(cnt->imgs.ref);
-	if (cnt->imgs.ref_dyn)
-		free(cnt->imgs.ref_dyn);
-	if (cnt->imgs.image_virgin)
-		free(cnt->imgs.image_virgin);
-	if (cnt->imgs.labels)
-		free(cnt->imgs.labels);
-	if (cnt->imgs.labelsize)
-		free(cnt->imgs.labelsize);
-	if (cnt->imgs.smartmask)
-		free(cnt->imgs.smartmask);
-	if (cnt->imgs.smartmask_final)
-		free(cnt->imgs.smartmask_final);
-	if (cnt->imgs.smartmask_buffer)
-		free(cnt->imgs.smartmask_buffer);
-	if (cnt->imgs.common_buffer)
-		free(cnt->imgs.common_buffer);
-	if (cnt->imgs.preview_image.image)
-		free(cnt->imgs.preview_image.image);
-
-	image_ring_destroy(cnt); /* Cleanup the precapture ring buffer */
-
-	rotate_deinit(cnt); /* cleanup image rotation data */
-
-	if(cnt->pipe != -1)
-		close(cnt->pipe);
-	if(cnt->mpipe != -1)
-		close(cnt->mpipe);
-
-	/* Cleanup the netcam part */
-	if(cnt->netcam)
-		netcam_cleanup(cnt->netcam, 0);
-
-	/* Cleanup the current time structure */
-	if (cnt->currenttime_tm)
-		free(cnt->currenttime_tm);
-
-	/* Cleanup the event time structure */
-	if (cnt->eventtime_tm)
-		free(cnt->eventtime_tm);
-
 	/* Free memory allocated for config parameters */
 	for (j = 0; config_params[j].param_name != NULL; j++) {
 		if (config_params[j].copy == copy_string) {
@@ -342,8 +307,15 @@
 				while (cnt_list[++i]) {
 					cnt_list[i]->makemovie=1;
 					cnt_list[i]->finish=1;
+					/* don't restart thread when it ends, 
+					 * all threads restarts if global restart is set 
+					 */
+					cnt_list[i]->restart=0;
 				}
 			}
+			/* Set flag we want to quit main check threads loop
+			 * if restart is set (above) we start up again */
+			finish = 1;
 			break;
 		case SIGSEGV:
 			exit(0);
@@ -435,8 +407,6 @@
 		/* always save first motion frame as preview-shot, may be changed to an other one later */
 		if (cnt->new_img & (NEWIMG_FIRST | NEWIMG_BEST | NEWIMG_CENTER)) {
 			image_save_as_preview(cnt, img);
-			cnt->preview_time = cnt->currenttime;
-			cnt->preview_shots = cnt->shots;
 
 			/* If we set output_all to yes and during the event
 			 * there is no image with motion, diffs is 0, we are not going to save the preview event */
@@ -460,8 +430,6 @@
 		if (cnt->new_img & NEWIMG_BEST) {
 			if (img->diffs > cnt->imgs.preview_image.diffs) {
 				image_save_as_preview(cnt, img);
-				cnt->preview_time = cnt->currenttime;
-				cnt->preview_shots = cnt->shots;
 
 				/* If we have locate on it is already dine above */
 				if (cnt->locate == LOCATE_PREVIEW) {
@@ -473,8 +441,6 @@
 		if (cnt->new_img & NEWIMG_CENTER) {
 			if(img->cent_dist < cnt->imgs.preview_image.cent_dist) {
 				image_save_as_preview(cnt, img);
-				cnt->preview_time = cnt->currenttime;
-				cnt->preview_shots = cnt->shots;
 
 				/* If we have locate on it is already dine above */
 				if (cnt->locate == LOCATE_PREVIEW) {
@@ -573,9 +539,11 @@
  *
  *      cnt     Pointer to the motion context structure
  *
- * Returns:     nothing
+ * Returns:     0 OK
+ *             -1 Fatal error, open loopback error
+ *             -2 Fatal error, open SQL database error
  */
-static void motion_init(struct context *cnt)
+static int motion_init(struct context *cnt)
 {
 	int i;
 	FILE *picture;
@@ -585,6 +553,10 @@
 
 	cnt->currenttime_tm = mymalloc(sizeof(struct tm));
 	cnt->eventtime_tm = mymalloc(sizeof(struct tm));
+	/* Init frame time */
+	cnt->currenttime = time(NULL);
+	localtime_r(&cnt->currenttime, cnt->currenttime_tm);
+
 	cnt->smartmask_speed = 0;
 
 	/* We initialize cnt->event_nr to 1 and cnt->prev_event to 0 (not really needed) so
@@ -593,6 +565,7 @@
 	cnt->prev_event = 0;
 	cnt->lightswitch_framecounter = 0;
 	cnt->detecting_motion = 0;
+	cnt->makemovie = 0;
 
 	motion_log(LOG_DEBUG, 0, "Thread %d started", (unsigned long)pthread_getspecific(tls_key_threadnr));
 
@@ -602,22 +575,12 @@
 	/* set the device settings */
 	cnt->video_dev = vid_start(cnt);
 
-	/* We still cannot handle a V4L type camera not being available
-	 * during startup. We have no other option than to die
-	 */
-	if (cnt->video_dev == -1 && !cnt->conf.netcam_url) {
-		motion_log(LOG_ERR, 0, "Capture error calling vid_start");
-		motion_log(-1 , 0, "Thread finishing...");
-		motion_remove_pid();
-		exit(1);
-	}
-
-	/* We failed to get an initial image from a network camera
+	/* We failed to get an initial image from a camera
 	 * So we need to guess height and width based on the config
 	 * file options.
 	 */
-	if (cnt->video_dev == -1) {
-		motion_log(LOG_ERR, 0, "Could not fetch initial image from network camera");
+	if (cnt->video_dev < 0) {
+		motion_log(LOG_ERR, 0, "Could not fetch initial image from camera");
 		motion_log(LOG_ERR, 0, "Motion continues using width and height from config file(s)");
 		cnt->imgs.width = cnt->conf.width;
 		cnt->imgs.height = cnt->conf.height;
@@ -632,7 +595,6 @@
 	cnt->imgs.out = mymalloc(cnt->imgs.size);
 	cnt->imgs.ref_dyn = mymalloc(cnt->imgs.motionsize * sizeof(cnt->imgs.ref_dyn));  /* contains the moving objects of ref. frame */
 	cnt->imgs.image_virgin = mymalloc(cnt->imgs.size);
-	memset(cnt->imgs.image_virgin, 0x80, cnt->imgs.size);       /* initialize to grey */
 	cnt->imgs.smartmask = mymalloc(cnt->imgs.motionsize);
 	cnt->imgs.smartmask_final = mymalloc(cnt->imgs.motionsize);
 	cnt->imgs.smartmask_buffer = mymalloc(cnt->imgs.motionsize * sizeof(cnt->imgs.smartmask_buffer));
@@ -656,23 +618,18 @@
 	 */
 	rotate_init(cnt); /* rotate_deinit is called in main */
 
-	/* Allow videodevice to settle in */
-
 	/* Capture first image, or we will get an alarm on start */
 	if (cnt->video_dev > 0) {
-		for (i = 0; i < 10; i++) {
+		for (i = 0; i < 5; i++) {
 			if (vid_next(cnt, cnt->imgs.image_virgin) == 0)
 				break;
 			SLEEP(2,0);
 		}
-		/* We still cannot handle a V4L type camera not being available
-		 * during startup. We have no other option than to die
-		 */
-		if (i >= 10) {
+		if (i >= 5) {
+			memset(cnt->imgs.image_virgin, 0x80, cnt->imgs.size);       /* initialize to grey */
+			draw_text(cnt->imgs.image_virgin, 10, 20, cnt->imgs.width,
+			          "Error capturing first image", cnt->conf.text_double);
 			motion_log(LOG_ERR, 0, "Error capturing first image");
-			motion_log(-1, 0, "Thread finishing...");
-			motion_remove_pid();
-			exit(1);
 		}
 	}
 
@@ -689,9 +646,7 @@
 		cnt->pipe = vid_startpipe(cnt->conf.vidpipe, cnt->imgs.width, cnt->imgs.height, cnt->imgs.type);
 		if (cnt->pipe < 0) {
 			motion_log(LOG_ERR, 0, "Failed to open video loopback");
-			motion_log(-1, 0, "Thread finishing...");
-			motion_remove_pid();
-			exit(1);
+			return -1;
 		}
 	}
 	if (cnt->conf.motionvidpipe) {
@@ -701,9 +656,7 @@
 		cnt->mpipe = vid_startpipe(cnt->conf.motionvidpipe, cnt->imgs.width, cnt->imgs.height, cnt->imgs.type);
 		if (cnt->mpipe < 0) {
 			motion_log(LOG_ERR, 0, "Failed to open video loopback");
-			motion_log(-1, 0, "Thread finishing...");
-			motion_remove_pid();
-			exit(1);
+			return -1;
 		}
 	}
 #endif /* BSD */
@@ -718,9 +671,7 @@
 			motion_log(LOG_ERR, 0, "Cannot connect to MySQL database %s on host %s with user %s",
 			           cnt->conf.mysql_db, cnt->conf.mysql_host, cnt->conf.mysql_user);
 			motion_log(LOG_ERR, 0, "MySQL error was %s", mysql_error(cnt->database));
-			motion_log(-1, 0, "Thread finishing...");
-			motion_remove_pid();
-			exit(1);
+			return -2;
 		}
 		#if (defined(MYSQL_VERSION_ID)) && (MYSQL_VERSION_ID > 50012)
 		my_bool  my_true = TRUE;
@@ -748,9 +699,7 @@
 		if (PQstatus(cnt->database_pg) == CONNECTION_BAD) {
 			motion_log(LOG_ERR, 0, "Connection to PostgreSQL database '%s' failed: %s",
 			           cnt->conf.pgsql_db, PQerrorMessage(cnt->database_pg));
-			motion_log(-1, 0, "Thread finishing...");
-			motion_remove_pid();
-			exit(1);
+			return -2;
 		}
 	}
 #endif /* HAVE_PGSQL */
@@ -805,15 +754,109 @@
 		if ( webcam_init(cnt) == -1 ) {
 			motion_log(LOG_ERR, 1, "Problem enabling stream server in port %d", cnt->conf.webcam_port);
 			cnt->finish = 1;
-			cnt->makemovie = 0;
 		}else 	motion_log(LOG_DEBUG, 0, "Started stream webcam server in port %d", cnt->conf.webcam_port);
 	}
 
 	/* Prevent first few frames from triggering motion... */
 	cnt->moved = 8;
+
+	return 0;
 }
 
 /**
+ * motion_cleanup
+ *
+ * This routine is called from motion_loop when thread ends to
+ * cleanup all memory etc. that motion_init did.
+ *
+ * Parameters:
+ *
+ *      cnt     Pointer to the motion context structure
+ *
+ * Returns:     nothing
+ */
+static void motion_cleanup(struct context *cnt)
+{
+	/* Stop webcam */
+	event(cnt, EVENT_STOP, NULL, NULL, NULL, NULL);
+
+#ifndef WITHOUT_V4L
+	if (cnt->video_dev >= 0)
+		vid_close(cnt);
+#endif
+
+	if (cnt->imgs.out) {
+		free(cnt->imgs.out);
+		cnt->imgs.out = NULL;
+	}
+	if (cnt->imgs.ref) {
+		free(cnt->imgs.ref);
+		cnt->imgs.ref = NULL;
+	}
+	if (cnt->imgs.ref_dyn) {
+		free(cnt->imgs.ref_dyn);
+		cnt->imgs.ref_dyn = NULL;
+	}
+	if (cnt->imgs.image_virgin) {
+		free(cnt->imgs.image_virgin);
+		cnt->imgs.image_virgin = NULL;
+	}
+	if (cnt->imgs.labels) {
+		free(cnt->imgs.labels);
+		cnt->imgs.labels = NULL;
+	}
+	if (cnt->imgs.labelsize) {
+		free(cnt->imgs.labelsize);
+		cnt->imgs.labelsize = NULL;
+	}
+	if (cnt->imgs.smartmask) {
+		free(cnt->imgs.smartmask);
+		cnt->imgs.smartmask = NULL;
+	}
+	if (cnt->imgs.smartmask_final) {
+		free(cnt->imgs.smartmask_final);
+		cnt->imgs.smartmask_final = NULL;
+	}
+	if (cnt->imgs.smartmask_buffer) {
+		free(cnt->imgs.smartmask_buffer);
+		cnt->imgs.smartmask_buffer = NULL;
+	}
+	if (cnt->imgs.common_buffer) {
+		free(cnt->imgs.common_buffer);
+		cnt->imgs.common_buffer = NULL;
+	}
+	if (cnt->imgs.preview_image.image) {
+		free(cnt->imgs.preview_image.image);
+		cnt->imgs.preview_image.image = NULL;
+	}
+
+	image_ring_destroy(cnt); /* Cleanup the precapture ring buffer */
+
+	rotate_deinit(cnt); /* cleanup image rotation data */
+
+	if(cnt->pipe != -1) {
+		close(cnt->pipe);
+		cnt->pipe = -1;
+	}
+	if(cnt->mpipe != -1) {
+		close(cnt->mpipe);
+		cnt->mpipe = -1;
+	}
+
+	/* Cleanup the current time structure */
+	if (cnt->currenttime_tm) {
+		free(cnt->currenttime_tm);
+		cnt->currenttime_tm = NULL;
+	}
+
+	/* Cleanup the event time structure */
+	if (cnt->eventtime_tm) {
+		free(cnt->eventtime_tm);
+		cnt->eventtime_tm = NULL;
+	}
+}
+
+/**
  * motion_loop
  *
  *   Thread function for the motion handling threads.
@@ -834,7 +877,7 @@
 	int previous_diffs = 0, previous_location_x = 0, previous_location_y = 0;
 	int text_size_factor;
 	int passflag = 0;
-	long int *rolling_average_data;
+	long int *rolling_average_data = NULL;
 	long int rolling_average_limit, required_frame_time, frame_delay, delay_time_nsec;
 	int rolling_frame = 0;
 	struct timeval tv1, tv2;
@@ -850,7 +893,11 @@
 	 */
 	unsigned long int time_last_frame=1, time_current_frame;
 
-	motion_init(cnt);
+	cnt->running = 1;
+	
+	if (motion_init(cnt) < 0) {
+		goto err;
+	}
 
 	/* Initialize the double sized characters if needed. */
 	if(cnt->conf.text_double)
@@ -892,6 +939,7 @@
 	while (!cnt->finish || cnt->makemovie) {
 
 	/***** MOTION LOOP - PREPARE FOR NEW FRAME SECTION *****/
+		cnt->watchdog = WATCHDOG_TMO;
 
 		/* Get current time and preserver last time for frame interval calc. */
 		timebefore = timenow;
@@ -918,7 +966,6 @@
 		/* Get time for current frame */
 		cnt->currenttime = time(NULL);
 
-
 		/* localtime returns static data and is not threadsafe
 		 * so we use localtime_r which is reentrant and threadsafe
 		 */
@@ -985,28 +1032,29 @@
 				cnt->current_image->total_labels = 0;
 			}
 
-		/***** MOTION LOOP - RETRY INITIALIZING NETCAM SECTION *****/
-			/* If a network camera is not available we keep on retrying every 10 seconds
+		/***** MOTION LOOP - RETRY INITIALIZING SECTION *****/
+			/* If a camera is not available we keep on retrying every 10 seconds
 			 * until it shows up.
 			 */
-			if (cnt->video_dev == -1 && cnt->conf.netcam_url &&
+			if (cnt->video_dev < 0 &&
 			    cnt->currenttime % 10 == 0 && cnt->shots == 0) {
 				motion_log(LOG_ERR, 0,
-				           "Retrying until successful initial connection with network camera");
-				netcam_cleanup(cnt->netcam, 1);
-				cnt->netcam = NULL;
+				           "Retrying until successful connection with camera");
 				cnt->video_dev = vid_start(cnt);
 
 				/* if the netcam has different dimensions than in the config file
 				 * we need to restart Motion to re-allocate all the buffers
 				 */
-				if (cnt->imgs.width != cnt->imgs.width || cnt->imgs.height != cnt->conf.height) {
-					motion_log(LOG_ERR, 0, "Network camera has finally become available");
-					motion_log(LOG_ERR, 0, "Network camera image has different width and height "
+				if (cnt->imgs.width != cnt->conf.width || cnt->imgs.height != cnt->conf.height) {
+					motion_log(LOG_ERR, 0, "Camera has finally become available");
+					motion_log(LOG_ERR, 0, "Camera image has different width and height "
 					                       "from what is in the config file. You should fix that");
-					motion_log(LOG_ERR, 0, "Restarting Motion to reinitialize all "
+					motion_log(LOG_ERR, 0, "Restarting Motion thread to reinitialize all "
 					                       "image buffers to new picture dimensions");
-					kill(getpid(), 1);
+					cnt->conf.width = cnt->imgs.width;
+					cnt->conf.height = cnt->imgs.height;
+					/* Break out of main loop terminating thread 
+					 * watchdog will start us again */
 					break;
 				}
 			}
@@ -1021,11 +1069,15 @@
 			 * <0 = fatal error - leave the thread by breaking out of the main loop
 			 * >0 = non fatal error - copy last image or show grey image with message
 			 */
-			vid_return_code = vid_next(cnt, cnt->current_image->image);
+			if (cnt->video_dev >= 0)
+				vid_return_code = vid_next(cnt, cnt->current_image->image);
+			else
+				vid_return_code = 1; /* Non fatal error */
 
 			// VALID PICTURE
 			if (vid_return_code == 0) {
 				cnt->lost_connection = 0;
+				cnt->connectionlosttime = 0;
 
 				/* If all is well reset missing_frame_counter */
 				if (cnt->missing_frame_counter >= MISSING_FRAMES_TIMEOUT * cnt->conf.frame_limit) {
@@ -1058,12 +1110,17 @@
 				}
 			// FATAL ERROR - leave the thread by breaking out of the main loop	
 			} else if (vid_return_code < 0) {
-				/* Fatal error - break out of main loop terminating thread */
-				motion_log(LOG_ERR, 0, "Video device fatal error - terminating camera thread");
-				break;
+				/* Fatal error - Close video device */
+				motion_log(LOG_ERR, 0, "Video device fatal error - Closing video device");
+				vid_close(cnt);
+				/* Use virgin image, if we are not able to open it again next loop
+				 * a gray image with message is applied
+				 */
+				memcpy(cnt->current_image->image, cnt->imgs.image_virgin, cnt->imgs.size);
 			// NO FATAL ERROR -  copy last image or show grey image with message			
 			} else { 
 				cnt->lost_connection = 1;
+
 				if (debug_level)
 					motion_log(-1, 0, "vid_return_code %d", vid_return_code);
 
@@ -1073,36 +1130,36 @@
 				 * other way
 				 */
 				if (vid_return_code == NETCAM_RESTART_ERROR) {
-					motion_log(LOG_ERR, 0, "Restarting Motion to reinitialize all "
+					motion_log(LOG_ERR, 0, "Restarting Motion thread to reinitialize all "
 					                       "image buffers");
-					kill(getpid(), 1);
+					/* Break out of main loop terminating thread 
+					 * watchdog will start us again */
 					break;
 				}
 
-				/* First missed frame - store timestamp */
-				if (!cnt->missing_frame_counter)
+				/* First missed frame - store timestamp 
+				 * Don't reset time when thread restarts*/
+				if (cnt->connectionlosttime == 0)
 					cnt->connectionlosttime = cnt->currenttime;
 
-				/* If we are waiting for first image prevent the
-				 * cnt->connectionlosttime from being updated each time we come back
-				 */
-				if (cnt->video_dev == -1)
-					cnt->missing_frame_counter = 1;
-
 				/* Increase missing_frame_counter
 				 * The first MISSING_FRAMES_TIMEOUT seconds we copy previous virgin image
 				 * After 30 seconds we put a grey error image in the buffer
 				 * If we still have not yet received the initial image from a camera
 				 * we go straight for the grey error image.
 				 */
-				if (cnt->video_dev != -1 &&
-				    ++cnt->missing_frame_counter < (MISSING_FRAMES_TIMEOUT * cnt->conf.frame_limit)) {
+				++cnt->missing_frame_counter;
+				if (cnt->video_dev >= 0 &&
+				    cnt->missing_frame_counter < (MISSING_FRAMES_TIMEOUT * cnt->conf.frame_limit)) {
 					memcpy(cnt->current_image->image, cnt->imgs.image_virgin, cnt->imgs.size);
-
 				} else {
+					const char *tmpin;
 					char tmpout[80];
-					char tmpin[] = "CONNECTION TO CAMERA LOST\\nSINCE %Y-%m-%d %T";
 					struct tm tmptime;
+					if (cnt->video_dev >= 0)
+						tmpin = "CONNECTION TO CAMERA LOST\\nSINCE %Y-%m-%d %T";
+					else
+						tmpin = "UNABLE TO OPEN VIDEO DEVICE\\nSINCE %Y-%m-%d %T";
 					localtime_r(&cnt->connectionlosttime, &tmptime);
 					memset(cnt->current_image->image, 0x80, cnt->imgs.size);
 					mystrftime(cnt, tmpout, sizeof(tmpout), tmpin, &tmptime, NULL, 0);
@@ -1113,7 +1170,17 @@
 					if (cnt->missing_frame_counter == MISSING_FRAMES_TIMEOUT * cnt->conf.frame_limit) {
 						motion_log(LOG_ERR, 0, "Video signal lost - Adding grey image");
 						// Event for lost video signal can be called from here
+						event(cnt, EVENT_CAMERA_LOST, NULL, NULL,
+						      NULL, cnt->currenttime_tm);
 					}
+
+					/* If we don't get a valid frame for a long time, try to close/reopen device 
+					 * Only try this when a device is open */
+					if ( (cnt->video_dev > 0) && 
+					     (cnt->missing_frame_counter == (MISSING_FRAMES_TIMEOUT * 4) * cnt->conf.frame_limit) ) {
+						motion_log(LOG_ERR, 0, "Video signal still lost - Trying to close video device");
+						vid_close(cnt);
+					}
 				}
 			}
 
@@ -1143,8 +1210,9 @@
 				 * This can happen due to change of light conditions or due to a sudden change of the camera
 				 * sensitivity. If alg_lightswitch detects lightswitch we suspend motion detection the next
 				 * 5 frames to allow the camera to settle.
+				 * Don't check if we have lost connection, we detect "Lost signal" frame as lightswitch
 				 */
-				if (cnt->conf.lightswitch) {
+				if (cnt->conf.lightswitch && !cnt->lost_connection) {
 					if (alg_lightswitch(cnt, cnt->current_image->diffs)) {
 						if (cnt->conf.setup_mode)
 							motion_log(-1, 0, "Lightswitch detected");
@@ -1742,25 +1810,22 @@
 	/* END OF MOTION MAIN LOOP
 	 * If code continues here it is because the thread is exiting or restarting
 	 */
-
-	if (cnt->netcam) {
-		netcam_cleanup(cnt->netcam, 0);
-		cnt->netcam = NULL;
-	}
+err:
 	if (rolling_average_data)
 		free(rolling_average_data);
 
 	cnt->lost_connection = 1;
 	motion_log(-1, 0, "Thread exiting");
-	if (!cnt->finish)
-		motion_log(LOG_ERR, 1, "Somebody stole the video device, lets hope we got his picture");
 
-	event(cnt, EVENT_STOP, NULL, NULL, NULL, NULL);
+	motion_cleanup(cnt);
 
 	pthread_mutex_lock(&global_lock);
 	threads_running--;
 	pthread_mutex_unlock(&global_lock);
 
+	cnt->running = 0;
+	cnt->finish = 0;
+
 	pthread_exit(NULL);
 }
 
@@ -1923,8 +1988,8 @@
 		context_destroy(cnt_list[i]);
 	}
 	free(cnt_list);
+	cnt_list = NULL;
 #ifndef WITHOUT_V4L
-	vid_close();
 	vid_cleanup();
 #endif
 }
@@ -2011,6 +2076,74 @@
 }
 
 /**
+ * start_motion_thread
+ *
+ *   Called from main when start a motion thread
+ *
+ * Parameters:
+ *
+ *   cnt - Thread context pointer
+ *   thread_attr - pointer to thread attributes
+ *
+ * Returns: nothing
+ */
+static void start_motion_thread(struct context *cnt, pthread_attr_t *thread_attr)
+{
+	int i;
+
+	/* Check the webcam port number for conflicts.
+	 * First we check for conflict with the control port.
+	 * Second we check for that two threads does not use the same port number
+	 * for the webcam. If a duplicate port is found the webcam feature gets disabled (port =0)
+	 * for this thread and a warning is written to console and syslog.
+	 */
+
+	if (cnt->conf.webcam_port != 0) {
+		/* Compare against the control port. */
+		if (cnt_list[0]->conf.control_port == cnt->conf.webcam_port) {
+			motion_log(LOG_ERR, 0,
+			           "Webcam port number %d for thread %d conflicts with the control port",
+			           cnt->conf.webcam_port, cnt->threadnr);
+			motion_log(LOG_ERR, 0, "Webcam feature for thread %d is disabled.", cnt->threadnr);
+			cnt->conf.webcam_port = 0;
+		}
+
+		/* Compare against webcam ports of other threads. */
+		for (i = 1; cnt_list[i]; i++) {
+			if (cnt_list[i] == cnt)
+				continue;
+			if (cnt_list[i]->conf.webcam_port == cnt->conf.webcam_port) {
+				motion_log(LOG_ERR, 0,
+				           "Webcam port number %d for thread %d conflicts with thread %d",
+				           cnt->conf.webcam_port, cnt->threadnr, cnt_list[i]->threadnr);
+				motion_log(LOG_ERR, 0,
+				           "Webcam feature for thread %d is disabled.", cnt->threadnr);
+				cnt->conf.webcam_port = 0;
+			}
+		}
+	}
+
+	/* 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++;
+	pthread_mutex_unlock(&global_lock);
+
+	/* Set a flag that we want this thread running */
+	cnt->restart = 1;
+
+	/* Give the thread 30s to start */
+	cnt->watchdog = 30;
+
+	/* Create the actual thread. Use 'motion_loop' as the thread
+	 * function.
+	 */
+	pthread_create(&cnt->thread_id, thread_attr, &motion_loop, cnt);
+}
+
+/**
  * main
  *
  *   Main entry point of Motion. Launches all the motion threads and contains
@@ -2025,8 +2158,7 @@
  */
 int main (int argc, char **argv)
 {
-	int i, j;
-	int webcam_port;
+	int i;
 	pthread_attr_t thread_attr;
 	pthread_t thread_id;
 
@@ -2080,55 +2212,11 @@
 			motion_startup(0, argc, argv); /* 0 = skip daemon init */
 		}
 
-		/* Check the webcam port number for conflicts.
-		 * First we check for conflict with the control port.
-		 * Second we check for that two threads does not use the same port number
-		 * for the webcam. If a duplicate port is found the webcam feature gets disabled (port =0)
-		 * for this thread and a warning is written to console and syslog.
-		 */
-		for (i = 1; cnt_list[i]; i++) {
-			/* Get the webcam port for thread 'i', may be 0. */
-			webcam_port = cnt_list[i]->conf.webcam_port;
 
-			if (cnt_list[0]->conf.setup_mode)
-				motion_log(LOG_ERR, 0, "Webcam port %d", webcam_port);
-
-			/* Compare against the control port. */
-			if (cnt_list[0]->conf.control_port == webcam_port && webcam_port != 0) {
-				cnt_list[i]->conf.webcam_port = 0;
-				motion_log(LOG_ERR, 0,
-				           "Webcam port number %d for thread %d conflicts with the control port",
-				           webcam_port, i);
-				motion_log(LOG_ERR, 0, "Webcam feature for thread %d is disabled.", i);
-			}
-
-			/* Compare against webcam ports of other threads. */
-			j = i;
-			while (cnt_list[++j]) {
-				if (cnt_list[j]->conf.webcam_port == webcam_port && webcam_port != 0) {
-					cnt_list[j]->conf.webcam_port = 0;
-					motion_log(LOG_ERR, 0,
-					           "Webcam port number %d for thread %d conflicts with thread %d",
-					           webcam_port, j, i);
-					motion_log(LOG_ERR, 0,
-					           "Webcam feature for thread %d is disabled.", j);
-				}
-			}
-		}
-
 		/* Start the motion threads. First 'cnt_list' item is global if 'thread'
 		 * option is used, so start at 1 then and 0 otherwise.
 		 */
 		for (i = cnt_list[1] != NULL ? 1 : 0; cnt_list[i]; i++) {
-
-			/* Assign the thread number for this thread. This is done within a
-			 * mutex lock to prevent multiple simultaneous updates to
-			 * 'threads_running'.
-			 */
-			pthread_mutex_lock(&global_lock);
-			threads_running++;
-			pthread_mutex_unlock(&global_lock);
-			
 			/* If i is 0 it means no thread files and we then set the thread number to 1 */
 			cnt_list[i]->threadnr = i ? i : 1;
 
@@ -2136,16 +2224,16 @@
 				motion_log(LOG_INFO, 0, "Thread %d is from %s", cnt_list[i]->threadnr, cnt_list[i]->conf_filename );
 
 			if (cnt_list[0]->conf.setup_mode) {
-				motion_log(-1, 0, "Thread %d is device: %s input %d", threads_running,
+				motion_log(-1, 0, "Thread %d is device: %s input %d", cnt_list[i]->threadnr,
 				           cnt_list[i]->conf.netcam_url ? cnt_list[i]->conf.netcam_url : cnt_list[i]->conf.video_device,
 				           cnt_list[i]->conf.netcam_url ? -1 : cnt_list[i]->conf.input
 				          );
 			}
 
-			/* Create the actual thread. Use 'motion_loop' as the thread
-			 * function.
-			 */
-			pthread_create(&thread_id, &thread_attr, &motion_loop, cnt_list[i]);
+			if (cnt_list[0]->conf.setup_mode)
+				motion_log(LOG_ERR, 0, "Webcam port %d", cnt_list[i]->conf.webcam_port);
+
+			start_motion_thread(cnt_list[i], &thread_attr);
 		}
 
 		/* Create a thread for the control interface if requested. Create it
@@ -2160,9 +2248,37 @@
 		/* Crude way of waiting for all threads to finish - check the thread
 		 * counter (because we cannot do join on the detached threads).
 		 */
-		while(threads_running > 0) {
+		while( (threads_running > 0) || (!finish) ) {
 			SLEEP(1,0);
+			for (i = (cnt_list[1] != NULL ? 1 : 0); cnt_list[i]; i++) {
+				/* Check if threads wants to be restarted */
+				if ( (!cnt_list[i]->running) && (cnt_list[i]->restart) ) {
+					motion_log(LOG_INFO, 0, "Motion thread %d restart", cnt_list[i]->threadnr);
+					start_motion_thread(cnt_list[i], &thread_attr);
+				}
+				if (cnt_list[i]->watchdog > WATCHDOG_OFF) {
+					cnt_list[i]->watchdog--;
+					if (cnt_list[i]->watchdog == 0) {
+						motion_log(LOG_ERR, 0, "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(LOG_ERR, 0, "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;
+					}
+				}
+			}
 		}
+		/* Reset end main loop flag */
+		finish = 0;
 
 		if (cnt_list[0]->conf.setup_mode)
 			motion_log(LOG_DEBUG, 0, "Threads finished");
Index: motion.h
===================================================================
--- motion.h	(revision 275)
+++ motion.h	(working copy)
@@ -130,6 +130,9 @@
                                      * and then we show a grey image instead
                                      */
 
+#define WATCHDOG_TMO 30  /* 10 sec max motion_loop interval */
+#define WATCHDOG_OFF -127 /* Turn off watchdog, used when we wants to quit a thread */
+
 #define CONNECTION_KO "Lost connection"
 #define CONNECTION_OK "Connection OK"
 
@@ -305,8 +308,6 @@
 	struct netcam_context *netcam;
 	struct image_data *current_image;	/* Pointer to a structure where the image, diffs etc is stored */
 	unsigned short int new_img;
-	time_t preview_time;			/* Timestamp of preview image */
-	unsigned short int preview_shots;	/* Shot of preview buffer image */
 
 	int locate;
 	struct rotdata rotate_data;		/* rotation data is thread-specific */
@@ -316,10 +317,17 @@
 	int diffs_last[THRESHOLD_TUNE_LENGTH];
 	int smartmask_speed;
 
-	unsigned short int snapshot;
-	unsigned short int makemovie;
-	unsigned short int finish;
+	/* Commands to the motion thread */
+	volatile unsigned short int snapshot;    /* Make a snapshot */
+	volatile unsigned short int makemovie;   /* End a movie */
+	volatile unsigned short int finish;      /* End the thread */
+	volatile unsigned short int restart;     /* Restart the thread when it ends */
+	/* Is the motion thread running */
+	volatile unsigned short int running;
+	volatile int watchdog;
 
+	pthread_t thread_id;
+
 	int event_nr;
 	int prev_event;
 	int lightswitch_framecounter;
Index: video.h
===================================================================
--- video.h	(revision 275)
+++ video.h	(working copy)
@@ -35,6 +35,8 @@
 #define VIDEO_DEVICE "/dev/video0"
 
 struct video_dev {
+	struct video_dev *next;
+	int usage_count;
 	int fd;
 	const char *video_device;
 	int input;
@@ -70,7 +72,7 @@
 /* video functions, video_common.c */
 int vid_start(struct context *);
 int vid_next(struct context *, unsigned char *map);
-void vid_close(void);
+void vid_close(struct context *cnt);
 void vid_cleanup(void);
 void vid_init(void);
 void conv_yuv422to420p(unsigned char *map, unsigned char *cap_map, int width, int height);
Index: video_common.c
===================================================================
--- video_common.c	(revision 275)
+++ video_common.c	(working copy)
@@ -514,69 +514,100 @@
 /* Here we setup the viddevs structure which is used globally in the vid_*
  * functions.
  */
-static struct video_dev **viddevs = NULL;
+static struct video_dev *viddevs = NULL;
 
 /**
  * vid_init
  *
  * Called from motion.c at the very beginning before setting up the threads.
- * Function prepares the viddevs struct for the threads and the vid_mutex
+ * Function prepares the vid_mutex
  */
 void vid_init(void)
 {
-	if (!viddevs) {
-		viddevs = mymalloc(sizeof(struct video_dev *));
-		viddevs[0] = NULL;
-	}
-
 	pthread_mutex_init(&vid_mutex, NULL);
 }
 
 /**
- * vid_close
+ * vid_cleanup
  *
- * vid_close is called from motion.c when Motion is stopped or restarted
- * It gets rid of all open video devices. It is called BEFORE vid_cleanup.
+ * vid_cleanup is called from motion.c when Motion is stopped or restarted
  */
-void vid_close(void)
+void vid_cleanup(void)
 {
-	int i = -1;
-
-	if (viddevs) {
-		while (viddevs[++i]) {
-#ifdef MOTION_V4L2
-			if (viddevs[i]->v4l2)
-				v4l2_close(viddevs[i]);
-#else
-			int tmp = viddevs[i]->fd;
-			viddevs[i]->fd = -1;
-			close(tmp);
-#endif
-		}
-	}
+	pthread_mutex_destroy(&vid_mutex);
 }
 
 /**
- * vid_cleanup
+ * vid_close
  *
- * vid_cleanup is called from motion.c when Motion is stopped or restarted
- * It free all the memory held by the viddevs structs.
+ * vid_close is called from motion.c when a Motion thread is stopped or restarted
  */
-void vid_cleanup(void)
+void vid_close(struct context *cnt)
 {
-	int i = -1;
-	if (viddevs) {
-		while (viddevs[++i]) {
+	struct video_dev *dev = viddevs;
+	struct video_dev *prev = NULL;
+
+	/* Cleanup the netcam part */
+	if(cnt->netcam) {
+		netcam_cleanup(cnt->netcam, 0);
+		cnt->netcam = NULL;
+		return;
+	}
+
+	/* Cleanup the v4l part */
+	pthread_mutex_lock(&vid_mutex);
+	while (dev) {
+		if (dev->fd == cnt->video_dev)
+			break;
+		prev = dev;
+		dev = dev->next;
+	}
+	pthread_mutex_unlock(&vid_mutex);
+
+	/* Set it as closed in thread context */
+	cnt->video_dev = -1;
+
+	if (dev == NULL) {
+		motion_log(LOG_ERR, 0, "vid_close: Unable to find video device");
+		return;
+	}
+
+	if( --dev->usage_count == 0) {
+		motion_log(LOG_INFO, 0, "Closing video device %s", dev->video_device);
 #ifdef MOTION_V4L2
-			if (viddevs[i]->v4l2)
-				v4l2_cleanup(viddevs[i]);
-			else
+		if (dev->v4l2) {
+			v4l2_close(dev);
+			v4l2_cleanup(dev);
+		} else {
 #endif
-				munmap(viddevs[i]->v4l_buffers[0], viddevs[i]->size_map);
-			free(viddevs[i]);
+			close(dev->fd);
+			munmap(viddevs->v4l_buffers[0], viddevs->size_map);
+			munmap(viddevs->v4l_buffers[1], viddevs->size_map);
+#ifdef MOTION_V4L2
 		}
-		free(viddevs);
-		viddevs = NULL;
+#endif
+		dev->fd = -1;
+		pthread_mutex_lock(&vid_mutex);
+		/* Remove from list */
+		if (prev == NULL)
+			viddevs = dev->next;
+		else
+			prev->next = dev->next;
+		pthread_mutex_unlock(&vid_mutex);
+
+		pthread_mutexattr_destroy(&dev->attr);
+		pthread_mutex_destroy(&dev->mutex);
+		free(dev);
+	} else {
+		motion_log(LOG_INFO, 0, "Still %d users of video device %s, so we don't close it now", dev->usage_count, dev->video_device);
+		/* There is still at least one thread using this device 
+		 * If we own it, release it
+		 */
+		if (dev->owner == cnt->threadnr) {
+			dev->frames = 0;
+			dev->owner = -1;
+			pthread_mutex_unlock(&dev->mutex);
+		}
 	}
 }
 
@@ -608,180 +639,190 @@
  *     device number
  *     -1 if failed to open device.
  */
-
 static int vid_v4lx_start(struct context *cnt)
 {
 	struct config *conf = &cnt->conf;
-	int dev = -1;
+	int fd = -1;
+	struct video_dev *dev;
 
-	/* Start a new block so we can make declarations without breaking good old
-	 * gcc 2.95 or older.
+	int width, height, input, norm, tuner_number;
+	unsigned long frequency;
+
+	/* We use width and height from conf in this function. They will be assigned
+	 * to width and height in imgs here, and cap_width and cap_height in 
+	 * rotate_data won't be set until in rotate_init.
+	 * Motion requires that width and height is a multiple of 16 so we check
+	 * for this first.
 	 */
-	{
-		int i = -1;
-		int width, height, input, norm, tuner_number;
-		unsigned long frequency;
+	if (conf->width % 16) {
+		motion_log(LOG_ERR, 0, "config image width (%d) is not modulo 16", conf->width);
+		return -1;
+	}
 
-		/* We use width and height from conf in this function. They will be assigned
-		 * to width and height in imgs here, and cap_width and cap_height in 
-		 * rotate_data won't be set until in rotate_init.
-		 * Motion requires that width and height is a multiple of 16 so we check
-		 * for this first.
-		 */
-		if (conf->width % 16) {
-			motion_log(LOG_ERR, 0, "config image width (%d) is not modulo 16", conf->width);
-			return -1;
-		}
+	if (conf->height % 16) {
+		motion_log(LOG_ERR, 0, "config image height (%d) is not modulo 16", conf->height);
+		return -1;
+	}
 
-		if (conf->height % 16) {
-			motion_log(LOG_ERR, 0, "config image height (%d) is not modulo 16", conf->height);
-			return -1;
-		}
+	width = conf->width;
+	height = conf->height;
+	input = conf->input;
+	norm = conf->norm;
+	frequency = conf->frequency;
+	tuner_number = conf->tuner_number;
 
-		width = conf->width;
-		height = conf->height;
-		input = conf->input;
-		norm = conf->norm;
-		frequency = conf->frequency;
-		tuner_number = conf->tuner_number;
+	pthread_mutex_lock(&vid_mutex);
 
-		pthread_mutex_lock(&vid_mutex);
+	/* Transfer width and height from conf to imgs. The imgs values are the ones
+	 * that is used internally in Motion. That way, setting width and height via
+	 * http remote control won't screw things up.
+	 */
+	cnt->imgs.width = width;
+	cnt->imgs.height = height;
 
-		/* Transfer width and height from conf to imgs. The imgs values are the ones
-		 * that is used internally in Motion. That way, setting width and height via
-		 * http remote control won't screw things up.
-		 */
-		cnt->imgs.width = width;
-		cnt->imgs.height = height;
-
-		/* First we walk through the already discovered video devices to see
-		 * if we have already setup the same device before. If this is the case
-		 * the device is a Round Robin device and we set the basic settings
-		 * and return the file descriptor
-		 */
-		while (viddevs[++i]) {
-			if (!strcmp(conf->video_device, viddevs[i]->video_device)) {
-				int fd;
-				cnt->imgs.type = viddevs[i]->v4l_fmt;
-				switch (cnt->imgs.type) {
-				case VIDEO_PALETTE_GREY:
-					cnt->imgs.motionsize = width * height;
-					cnt->imgs.size = width * height;
-					break;
-				case VIDEO_PALETTE_YUYV:
-				case VIDEO_PALETTE_RGB24:
-				case VIDEO_PALETTE_YUV422:
-					cnt->imgs.type = VIDEO_PALETTE_YUV420P;
-				case VIDEO_PALETTE_YUV420P:
-					cnt->imgs.motionsize = width * height;
-					cnt->imgs.size = (width * height * 3) / 2;
-					break;
-				}
-				fd = viddevs[i]->fd;
-				pthread_mutex_unlock(&vid_mutex);
-				return fd;
+	/* First we walk through the already discovered video devices to see
+	 * if we have already setup the same device before. If this is the case
+	 * the device is a Round Robin device and we set the basic settings
+	 * and return the file descriptor
+	 */
+	dev = viddevs;
+	while (dev) {
+		if (!strcmp(conf->video_device, dev->video_device)) {
+			dev->usage_count++;
+			cnt->imgs.type = dev->v4l_fmt;
+			switch (cnt->imgs.type) {
+			case VIDEO_PALETTE_GREY:
+				cnt->imgs.motionsize = width * height;
+				cnt->imgs.size = width * height;
+				break;
+			case VIDEO_PALETTE_YUYV:
+			case VIDEO_PALETTE_RGB24:
+			case VIDEO_PALETTE_YUV422:
+				cnt->imgs.type = VIDEO_PALETTE_YUV420P;
+			case VIDEO_PALETTE_YUV420P:
+				cnt->imgs.motionsize = width * height;
+				cnt->imgs.size = (width * height * 3) / 2;
+				break;
 			}
+			pthread_mutex_unlock(&vid_mutex);
+			return dev->fd;
 		}
+		dev = dev->next;
+	}
 
-		viddevs = myrealloc(viddevs, sizeof(struct video_dev *) * (i + 2), "vid_start");
-		viddevs[i] = mymalloc(sizeof(struct video_dev));
-		memset(viddevs[i], 0, sizeof(struct video_dev));
-		viddevs[i + 1] = NULL;
+	dev = mymalloc(sizeof(struct video_dev));
+	memset(dev, 0, sizeof(struct video_dev));
 
-		pthread_mutexattr_init(&viddevs[i]->attr);
-		pthread_mutex_init(&viddevs[i]->mutex, NULL);
+	dev->video_device = conf->video_device;
 
-		viddevs[i]->video_device = conf->video_device;
+	fd = open(dev->video_device, O_RDWR);
 
-		dev = open(viddevs[i]->video_device, O_RDWR);
+	if (fd < 0) {
+		motion_log(LOG_ERR, 1, "Failed to open video device %s", conf->video_device);
+		free(dev);
+		pthread_mutex_unlock(&vid_mutex);
+		return -1;
+	}
 
-		if (dev < 0) {
-			motion_log(LOG_ERR, 1, "Failed to open video device %s", conf->video_device);
-			return -1;
-		}
+	pthread_mutexattr_init(&dev->attr);
+	pthread_mutex_init(&dev->mutex, &dev->attr);
 
-		viddevs[i]->fd = dev;
-		viddevs[i]->input = input;
-		viddevs[i]->height = height;
-		viddevs[i]->width = width;
-		viddevs[i]->freq = frequency;
-		viddevs[i]->tuner_number = tuner_number;
+	dev->usage_count = 1;
+	dev->fd = fd;
+	dev->input = input;
+	dev->height = height;
+	dev->width = width;
+	dev->freq = frequency;
+	dev->tuner_number = tuner_number;
 
-		/* We set brightness, contrast, saturation and hue = 0 so that they only get
-		 * set if the config is not zero.
-		 */
-		viddevs[i]->brightness = 0;
-		viddevs[i]->contrast = 0;
-		viddevs[i]->saturation = 0;
-		viddevs[i]->hue = 0;
-		viddevs[i]->owner = -1;
-		viddevs[i]->v4l_fmt = VIDEO_PALETTE_YUV420P;
+	/* We set brightness, contrast, saturation and hue = 0 so that they only get
+	 * set if the config is not zero.
+	 */
+	dev->brightness = 0;
+	dev->contrast = 0;
+	dev->saturation = 0;
+	dev->hue = 0;
+	dev->owner = -1;
+	dev->v4l_fmt = VIDEO_PALETTE_YUV420P;
 #ifdef MOTION_V4L2
-		/* First lets try V4L2 and if it's not supported V4L1 */
+	/* First lets try V4L2 and if it's not supported V4L1 */
 
-		viddevs[i]->v4l2 = 1;
+	dev->v4l2 = 1;
 
-		if (!v4l2_start(cnt, viddevs[i], width, height, input, norm, frequency, tuner_number)) {
-			/* restore width & height because could be changed in v4l2_start ()*/
-			viddevs[i]->width = width;
-			viddevs[i]->height = height;
+	if (!v4l2_start(cnt, dev, width, height, input, norm, frequency, tuner_number)) {
+		/* restore width & height before test with v4l
+		 * because could be changed in v4l2_start ()
+		 */
+		dev->width = width;
+		dev->height = height;
 #endif
 
-			if (!v4l_start(cnt, viddevs[i], width, height, input, norm, frequency, tuner_number)) {
-				pthread_mutex_unlock(&vid_mutex);
-				return -1;
-			}
+		if (!v4l_start(cnt, dev, width, height, input, norm, frequency, tuner_number)) {
+			close(dev->fd);
+			pthread_mutexattr_destroy(&dev->attr);
+			pthread_mutex_destroy(&dev->mutex);
+			free(dev);
+
+			pthread_mutex_unlock(&vid_mutex);
+			return -1;
+		}
 #ifdef MOTION_V4L2
-			viddevs[i]->v4l2 = 0;
-		}
+		dev->v4l2 = 0;
+	}
 #endif
-		if (viddevs[i]->v4l2 == 0) {
-			motion_log(-1, 0, "Using V4L1");
-		} else {
-			motion_log(-1, 0, "Using V4L2");
-			/* Update width & height because could be changed in v4l2_start () */
-			width = viddevs[i]->width;
-			height = viddevs[i]->height;
-			cnt->conf.width = width;
-			cnt->conf.height = height;
-			cnt->imgs.width = width;
-			cnt->imgs.height = height;
-		}
+	if (dev->v4l2 == 0) {
+		motion_log(-1, 0, "Using V4L1");
+	} else {
+		motion_log(-1, 0, "Using V4L2");
+		/* Update width & height because could be changed in v4l2_start () */
+		width = dev->width;
+		height = dev->height;
+		cnt->imgs.width = width;
+		cnt->imgs.height = height;
+	}
 
-		cnt->imgs.type = viddevs[i]->v4l_fmt;
+	cnt->imgs.type = dev->v4l_fmt;
 
-		switch (cnt->imgs.type) {
-		case VIDEO_PALETTE_GREY:
-			cnt->imgs.size = width * height;
-			cnt->imgs.motionsize = width * height;
-			break;
-		case VIDEO_PALETTE_YUYV:
-		case VIDEO_PALETTE_RGB24:
-		case VIDEO_PALETTE_YUV422:
-			cnt->imgs.type = VIDEO_PALETTE_YUV420P;
-		case VIDEO_PALETTE_YUV420P:
-			cnt->imgs.size = (width * height * 3) / 2;
-			cnt->imgs.motionsize = width * height;
-			break;
-		}
-
-		pthread_mutex_unlock(&vid_mutex);
+	switch (cnt->imgs.type) {
+	case VIDEO_PALETTE_GREY:
+		cnt->imgs.size = width * height;
+		cnt->imgs.motionsize = width * height;
+		break;
+	case VIDEO_PALETTE_YUYV:
+	case VIDEO_PALETTE_RGB24:
+	case VIDEO_PALETTE_YUV422:
+		cnt->imgs.type = VIDEO_PALETTE_YUV420P;
+	case VIDEO_PALETTE_YUV420P:
+		cnt->imgs.size = (width * height * 3) / 2;
+		cnt->imgs.motionsize = width * height;
+		break;
 	}
 
-	return dev;
+	/* Insert into linked list */
+	dev->next = viddevs;
+	viddevs = dev;
+
+	pthread_mutex_unlock(&vid_mutex);
+
+return fd;
 }
 #endif				/*WITHOUT_V4L */
 
 int vid_start(struct context *cnt)
 {
 	struct config *conf = &cnt->conf;
-	int dev = -1;
+	int dev;
 
 	if (conf->netcam_url) {
-		return netcam_start(cnt);
+		dev = netcam_start(cnt);
+		if (dev < 0) {
+			netcam_cleanup(cnt->netcam, 1);
+			cnt->netcam = NULL;
+		}
 	}
 #ifndef WITHOUT_V4L
-	dev = vid_v4lx_start(cnt);
+	else
+		dev = vid_v4lx_start(cnt);
 #endif				/*WITHOUT_V4L */
 
 	return dev;
@@ -809,60 +850,63 @@
  */
 int vid_next(struct context *cnt, unsigned char *map)
 {
+	int ret;
 	struct config *conf = &cnt->conf;
-	int ret = -1;
 
 	if (conf->netcam_url) {
 		if (cnt->video_dev == -1)
 			return NETCAM_GENERAL_ERROR;
 
-		ret = netcam_next(cnt, map);
-		return ret;
+		return netcam_next(cnt, map);
 	}
 #ifndef WITHOUT_V4L
-
 	/* We start a new block so we can make declarations without breaking
 	 * gcc 2.95 or older
 	 */
 	{
-		int i = -1;
+		struct video_dev *dev;
 		int width, height;
-		int dev = cnt->video_dev;
 
 		/* NOTE: Since this is a capture, we need to use capture dimensions. */
 		width = cnt->rotate_data.cap_width;
 		height = cnt->rotate_data.cap_height;
 
-		while (viddevs[++i])
-			if (viddevs[i]->fd == dev)
+		pthread_mutex_lock(&vid_mutex);
+		dev = viddevs;
+		while (dev) {
+			if (dev->fd == cnt->video_dev)
 				break;
+			dev = dev->next;
+		}
+		pthread_mutex_unlock(&vid_mutex);
 
-		if (!viddevs[i])
+		if (dev == NULL)
 			return V4L_FATAL_ERROR;
 
-		if (viddevs[i]->owner != cnt->threadnr) {
-			pthread_mutex_lock(&viddevs[i]->mutex);
-			viddevs[i]->owner = cnt->threadnr;
-			viddevs[i]->frames = conf->roundrobin_frames;
+		if (dev->owner != cnt->threadnr) {
+			pthread_mutex_lock(&dev->mutex);
+			dev->owner = cnt->threadnr;
+			dev->frames = conf->roundrobin_frames;
 			cnt->switched = 1;
 		}
 #ifdef MOTION_V4L2
-		if (viddevs[i]->v4l2) {
-			v4l2_set_input(cnt, viddevs[i], map, width, height, conf);
+		if (dev->v4l2) {
+			v4l2_set_input(cnt, dev, map, width, height, conf);
 
-			ret = v4l2_next(cnt, viddevs[i], map, width, height);
+			ret = v4l2_next(cnt, dev, map, width, height);
 		} else {
 #endif
-			v4l_set_input(cnt, viddevs[i], map, width, height, conf->input, conf->norm,
+			v4l_set_input(cnt, dev, map, width, height, conf->input, conf->norm,
 				      conf->roundrobin_skip, conf->frequency, conf->tuner_number);
 
-			ret = v4l_next(viddevs[i], map, width, height);
+			ret = v4l_next(dev, map, width, height);
 #ifdef MOTION_V4L2
 		}
 #endif
-		if (--viddevs[i]->frames <= 0) {
-			viddevs[i]->owner = -1;
-			pthread_mutex_unlock(&viddevs[i]->mutex);
+		if (--dev->frames <= 0) {
+			dev->owner = -1;
+			dev->frames = 0;
+			pthread_mutex_unlock(&dev->mutex);
 		}
 
 		if (cnt->rotate_data.degrees > 0) {
Index: webhttpd.c
===================================================================
--- webhttpd.c	(revision 275)
+++ webhttpd.c	(working copy)
@@ -922,22 +922,41 @@
 		pointer = pointer + 7;
 		length_uri = length_uri - 7;
 		if (length_uri == 0) {
-			do {
+			/*call restart*/
+
+			if (thread == 0) {
 				motion_log(LOG_DEBUG, 0, "httpd restart");
-				kill(getpid(),1);
-			} while (cnt[++i]);
-
-			if (cnt[0]->conf.control_html_output) {
-				send_template_ini_client(client_socket, ini_template);
-				sprintf(res,"restart in progress ... bye<br>\n<a href='/'>Home</a>");
-				send_template(client_socket, res);
-				send_template_end_client(client_socket);
+				kill(getpid(),SIGHUP);
+				if (cnt[0]->conf.control_html_output) {
+					send_template_ini_client(client_socket, ini_template);
+					sprintf(res,"restart in progress ... bye<br>\n<a href='/'>Home</a>");
+					send_template(client_socket, res);
+					send_template_end_client(client_socket);
+				} else {
+					send_template_ini_client_raw(client_socket);
+					sprintf(res,"restart in progress ...\nDone\n");
+					send_template_raw(client_socket, res);
+				}
+				return 0; // to restart
 			} else {
-				send_template_ini_client_raw(client_socket);
-				sprintf(res,"restart in progress ...\nDone\n");
-				send_template_raw(client_socket, res);
+				motion_log(LOG_DEBUG, 0, "httpd restart thread %d", thread);
+				if (cnt[thread]->running) {
+					cnt[thread]->makemovie=1;
+					cnt[thread]->finish=1;
+				}
+				cnt[thread]->restart=1;
+				if (cnt[0]->conf.control_html_output) {
+					send_template_ini_client(client_socket, ini_template);
+					sprintf(res,"<a href=/%hu/config><- back</a><br><br>\n"
+						    "restart for thread %hu done<br>\n", thread, thread);
+					send_template(client_socket, res);
+					send_template_end_client(client_socket);
+				} else {
+					send_template_ini_client_raw(client_socket);
+					sprintf(res,"restart for thread %hu\nDone\n", thread);
+					send_template_raw(client_socket, res);
+				}
 			}
-			return 0; // to restart
 		} else {
 			if (cnt[0]->conf.control_html_output)
 				response_client(client_socket,not_found_response_valid_command,NULL);
@@ -949,23 +968,39 @@
 		length_uri = length_uri - 4;
 		if (length_uri == 0) {
 			/*call quit*/
-			do {
-				motion_log(LOG_DEBUG, 0, "httpd quitting");
-				cnt[i]->makemovie = 1;
-				cnt[i]->finish = 1;
-			} while (cnt[++i]);
 
-			if (cnt[0]->conf.control_html_output) {
-				send_template_ini_client(client_socket, ini_template);
-				sprintf(res,"quit in progress ... bye");
-				send_template(client_socket, res);
-				send_template_end_client(client_socket);
+			if (thread == 0) {
+				motion_log(LOG_DEBUG, 0, "httpd quit");
+				kill(getpid(),SIGQUIT);
+				if (cnt[0]->conf.control_html_output) {
+					send_template_ini_client(client_socket, ini_template);
+					sprintf(res,"quit in progress ... bye");
+					send_template(client_socket, res);
+					send_template_end_client(client_socket);
+				} else {
+					send_template_ini_client_raw(client_socket);
+					sprintf(res,"quit in progress ... bye\nDone\n");
+					send_template_raw(client_socket, res);
+				}
+				return 0; // to quit
 			} else {
-				send_template_ini_client_raw(client_socket);
-				sprintf(res,"quit in progress ... bye\nDone\n");
-				send_template_raw(client_socket, res);
+				motion_log(LOG_DEBUG, 0, "httpd quit thread %d", thread);
+				cnt[thread]->restart=0;
+				cnt[thread]->makemovie=1;
+				cnt[thread]->finish=1;
+				cnt[thread]->watchdog=WATCHDOG_OFF;
+				if (cnt[0]->conf.control_html_output) {
+					send_template_ini_client(client_socket, ini_template);
+					sprintf(res,"<a href=/%hu/config><- back</a><br><br>\n"
+						    "quit for thread %hu done<br>\n", thread, thread);
+					send_template(client_socket, res);
+					send_template_end_client(client_socket);
+				} else {
+					send_template_ini_client_raw(client_socket);
+					sprintf(res,"quit for thread %hu\nDone\n", thread);
+					send_template_raw(client_socket, res);
+				}
 			}
-			return 0; // to quit
 		} else {
 			/*error*/
 			if (cnt[0]->conf.control_html_output)
@@ -1006,11 +1041,12 @@
 			if (cnt[0]->conf.control_html_output) {
 				send_template_ini_client(client_socket, ini_template);
 				sprintf(res, "<a href=/%hu/detection><- back</a><br><br><b>Thread %hu</b> Detection status %s\n", 
-					      thread, thread, (cnt[thread]->pause)? "PAUSE":"ACTIVE");
+					      thread, thread, (!cnt[thread]->running)? "NOT RUNNING": (cnt[thread]->pause)? "PAUSE":"ACTIVE");
 				send_template(client_socket, res);
 				send_template_end_client(client_socket);
 			} else {
-				sprintf(res, "Thread %hu Detection status %s\n",thread, (cnt[thread]->pause)? "PAUSE":"ACTIVE");
+				sprintf(res, "Thread %hu Detection status %s\n",thread, 
+				          (!cnt[thread]->running)? "NOT RUNNING" : (cnt[thread]->pause)? "PAUSE":"ACTIVE");
 				send_template_ini_client_raw(client_socket);
 				send_template_raw(client_socket, res);
 			}
@@ -1098,12 +1134,12 @@
 				if (thread == 0){
 					do{
 						sprintf(res,"Thread %hu %s<br>\n",i, 
-								(cnt[i]->lost_connection)?CONNECTION_KO:CONNECTION_OK);
+								(!cnt[i]->running)? "NOT RUNNING" : (cnt[i]->lost_connection)?CONNECTION_KO:CONNECTION_OK);
 						send_template(client_socket,res);
 					}while (cnt[++i]);
 				}else{
-					sprintf(res,"Thread %hu %s\n",
-						     thread, (cnt[thread]->lost_connection)? CONNECTION_KO: CONNECTION_OK);
+					sprintf(res,"Thread %hu %s\n", thread,
+					        (!cnt[thread]->running)? "NOT RUNNING" : (cnt[thread]->lost_connection)? CONNECTION_KO: CONNECTION_OK);
 					send_template(client_socket,res);
 				}	
 				send_template_end_client(client_socket);
@@ -1112,11 +1148,12 @@
 				if (thread == 0){
 					do{
 						sprintf(res,"Thread %hu %s\n", i,
-								(cnt[i]->lost_connection)? CONNECTION_KO: CONNECTION_OK);
+								(!cnt[i]->running)? "NOT RUNNING" : (cnt[i]->lost_connection)? CONNECTION_KO: CONNECTION_OK);
 						send_template_raw(client_socket, res);
 					}while (cnt[++i]);
 				}else{		
-					sprintf(res,"Thread %hu %s\n", thread,(cnt[thread]->lost_connection)? CONNECTION_KO: CONNECTION_OK);
+					sprintf(res,"Thread %hu %s\n", thread,
+					        (!cnt[thread]->running)? "NOT RUNNING" : (cnt[thread]->lost_connection)? CONNECTION_KO: CONNECTION_OK);
 					send_template_raw(client_socket, res);
 				}	
 				
