This lets the user decide which video problems they would rather see.
In my case a Raspberry Pi 2 with a 640x480 webcam sometimes can keep
up with 10fps so I don't want to set the framerate any lower, but
then sometimes it can't and with duplicate frames it looks like the
video output freezes every second.
The USB webcam I have defaults to the wrong setting causing visible
flickering degrading the image quality. This allows setting the
value to any of the currently available options or -1 to by default
not modify the value.
cnt->current_image because a dangling pointer after image_ring_resize
because it is pointing to cnt->imgs.image_ring which is reallocated in
that routine. motion_loop will then store cnt->current_image in
old_image which it can then read from.
Reallocations are rare, once in init to size 1, then once to the final
size. I apparently have a bad USB link and I was seeing a crash
pointing to bad data, after that camera started, then had an error and
crashed in process_image_ring(cnt, IMAGE_BUFFER_FLUSH);
it hadn't yet resized to the normal ring buffer size. That got me
trying valgrind with a ring buffer size limit of 1 which found this
bug.
As long as errno is EINTR (and that must be the case when the USB
device is still there, but the transfers are failing), the thread
keeps looping running the ioctl when it isn't going to succeed, so
give it access to the finish variable to only loop if the thread isn't
supposed to be going away, and then keep sendig SIGVTALRM to break out
of the ioctl when the thread is supposed to be exiting. With this fix
the webcam was no longer crashing, which let the webcam without a
problem continue to stream.
I apparently have some marginal USB hardware and motion has been
crashing every couple of days in the memcpy at the end of alg.c as
both cnt->imgs.ref and cnt->imgs.image_virgin were NULL pointers.
This was just after the main thread watchdog timer called
pthread_cancel on that thread. The problem is pthread_cancel can't
possibly kill a thread running on another CPU atomically, although in
this case it's a single core processor and I think pthread_cancel was
releasing it from the ioctl and it would then run to completition.
This modifies the code to not cleanup that content's resources until
that thread is no longer running. If it runs to completition a normal
restart will happen, if it doesn't the main thread will check once a
second until it no longer is running, cleanup and restart, but it
can't cleanup with that thread running.
On a SIGHUP restart the main thread waits to restart until all worker
threads are finished executing, except webcontrol wasn't included.
If it was still running (such as reading a web request), it would
have a dangling context pointer after cnt_list was freed leading to a
crash. This counts that thread in the running threads, as a
termination webcontrol_finish variable to terminate it indepdent of
the device thread, and creates a webcontrol_running to identify when
it is running.
I identified this while debugging, the thread was created, but hadn't
yet set its state to running before the main thread checked the running
variable and started another thread for the same device. That
resulted in a crash. Set running in the main thread, to avoid this
race condition.
The function comment says it will send 'I' or 'A', but it was
only sending 'I', even though the function did everything, but
put it in the snprintf (which could be skipped for a fixed string).