5

I have a program that will run 24/7 getting frames from a camera, doing processing and sending .jpg images via local network. Generally, I don't want any saving of video to file, however I might want to schedule x minutes of saving on certain occasion (not triggered, scheduled).

I handle video recording by calling VideoWriter as a thread of VideoCamera. I found this to be more accurate to handle writing with correct fps. This process works perfectly when I want to record from the beginning and when I just want to stream. I initiate the camera like this.

import ...
# from custom file import `VideoCamera` which has access to `VideoWriter`
from camera import VideoCamera

video_camera = VideoCamera(
    flip = False, 
    usePiCamera = False, 
    resolution = (640, 480),
    record = False,
    record_duration = None,
    record_timestamp = True
    ) 

The camera can't be initialized twice (can't access same camera twice). So I was thinking about scheduling a stop and restart with new parameters (for example record = True, record_duration = "00:10:00").

I call the script from console (python main.py) which has:

if __name__ == '__main__':
    t = threading.Thread(target=processing_fun, args=())
    t.daemon = True
    t.start()
    print("To see feed connect to " + get_ip_address() + ":5000")
    # to do, read ifconfig and assign IP using raspberry's IP
    app.run(host='0.0.0.0', port = 5000, debug=False)

processing_fun will be dead if I do del(video_camera) because it needs frames from camera. Same for the stream. I'm not sure there's a way to delete the camera without breaking the threads.

Idea to solve the problem

I was thinking about a way to

  1. Do init of video_camera without record
  2. At given moment, cleanly stop main.py (or kill it if not possible)
  3. Restart main.py with new parameters for video_camera
    • This might involve saving a cam_config file, which I'm fine with
  4. repeat 3) and 4) on needed schedule

Places I have looked for help

I have looked here and here but I am not sure how to put things together in a scheduled way.

Matias Andina
  • 4,029
  • 4
  • 26
  • 58
  • Can't you always save the video in a ring buffer and use that if you need it? – hek2mgl Feb 17 '20 at 03:14
  • Interesting, how would you implement scheduled save of the buffer ring in videowriter? – Matias Andina Feb 17 '20 at 03:31
  • Well, you give too less detail to say that. Imo the problem is too broad for Stackoverflow, it can't be answered without providing a whole application. Maybe you can break it down into separate simpler questions. – hek2mgl Feb 17 '20 at 03:50
  • I have an idea, but it depends on one question: Do you have full access to the code in `VideoCamera`? That is, can you modify it to add functionalities? – Nick Lee Feb 17 '20 at 04:33
  • @NickLee Code is available at github.com/matiasandina/python_camera – Matias Andina Feb 17 '20 at 14:10
  • Thanks. My idea is this. Use a cronjob to invoke a script. The script simply creates a file, the content being the number of seconds (of how long you want the saving to be). On the other hand, the `VideoCamera` object or `processing_fun()` would constantly check if that file (created by the above script) exists. If it exists, then read the number of seconds (before removing that file) and start saving for that number of seconds. Next time the cronjob is scheduled, the file will be created again, and saving will happen accordingly. – Nick Lee Feb 18 '20 at 11:32
  • In essence, the above method uses the filesystem to achieve a kind of IPC. More generally, any methods of IPC will do. Named pipe, unix domain socket, even TCP socket, as long as the camera program can be "poked" by another program in some ways. Then, you can leverage cron to do the scheduling. – Nick Lee Feb 18 '20 at 11:37
  • If my suggestion is satisfactory, I'd like to write it up as a formal answer, if you don't mind. I just want to make sure I didn't misunderstand your requirements. – Nick Lee Feb 18 '20 at 11:40
  • By the way, your idea of stopping and starting the camera program will probably work in couple with a cronjob. I just don't find it clean, especially if the functionality can be achieved in other ways without re-starting the program. – Nick Lee Feb 18 '20 at 12:00
  • I agree, Cron is not a clean option. I could have a file or argument with specific dates. If provided camera records and don't need cron. Looks like that will end up being the way, just increase the number of arguments passed to video camera – Matias Andina Feb 18 '20 at 12:14
  • 1
    I actually think cron is a good option. It decouples the scheduling from the camera program. What I think unclean is the stopping/starting of program just to change a simple behavior. I still think cron is a good solution, but it's your choice which direction to pursue. – Nick Lee Feb 18 '20 at 16:03

1 Answers1

3

You can use the crontab to schedule your scripts, and you mentioned you can also kill your scripts using the crontab. You can create a startup.sh script and some sort of shutdown.sh which will manage your schedule.

Below is an example:

Your python script say your_script.py:

import ...
# from custom file import `VideoCamera` which has access to `VideoWriter`
from camera import VideoCamera

video_camera = VideoCamera(
    flip = False, 
    usePiCamera = False, 
    resolution = (640, 480),
    record = False,
    record_duration = None,
    record_timestamp = True
    ) 


first_arg = sys.argv[1]
second_arg = sys.argv[2]
third_arg = sys.argv[3]

# pass the above arguments here in the function
if __name__ == '__main__':
    t = threading.Thread(target=processing_fun, args=())
    t.daemon = True
    t.start()
    print("To see feed connect to " + get_ip_address() + ":5000")
    # to do, read ifconfig and assign IP using raspberry's IP
    app.run(host='0.0.0.0', port = 5000, debug=False)

cron-python script to schedule your python script:

Name this script as schedule_cron_python.py and call this to manage your schedule. Here you can keep this whole code within a function and also pass arguments to this cron script like the time-date on which you want to schedule and in turn manage this with another cron script. (1st option)


from crontab import CronTab
import os
import sys
cron = CronTab(user='sshuser')

job1 = cron.new(command="python3 your_script.py 'arg1' 'arg2' 'arg3'")
job1.hour.on(5) # Mention your own time here
job1.minute.on(30)

for item in cron:
    print(item)
print(job1.enable())
cron.write()
#print(os.getcwd())

2nd Option:

Create separate startup.sh and shutdown.sh

These files will contain just command like nohup which will just call your script:

nohup python3 your_script.py

Now you can call these .sh files in your cron script to manage your schedule.

from crontab import CronTab
import os
import sys
cron = CronTab(user='sshuser')

job1 = cron.new(command="sh startup.sh")
job1.hour.on(5) # Mention your own time here
job1.minute.on(30)

job2 = cron.new(command="sh shutdown.sh")
job1.hour.on(6) # Mention your own time here
job1.minute.on(30)

for item in cron:
    print(item)
print(job1.enable())
cron.write()

Refer this to get some more context about cron and some more useful functions. https://pypi.org/project/python-crontab/

ashwin agrawal
  • 1,603
  • 8
  • 16
  • Appreciate the answer, I keep my initial thoughts, I would rather add a new argument on the function than using cron. – Matias Andina Feb 23 '20 at 15:30
  • You can do that but adding an argument for just scheduling ie for starting and killing a file is not correct. I guess you should keep the core logic and schedule logic separate, just an suggestion. Because in future if you require to change your logic of scheduling then you will need to add some more arguments which seems wrong. – ashwin agrawal Feb 23 '20 at 15:37
  • And moreover if you plan on using this script for a long time I would suggest using an `Azkaban` or an `Airflow` (for scheduling ) for manageability. – ashwin agrawal Feb 23 '20 at 15:39
  • 1
    With another argument I would not start and kill. I would handle it the same way I handle frame rate. Before putting a frame to the video recorder queue, I check whether the frame rate is correct. In the same manner I can only put frames for recorder to write if they belong within a "recording date + duration" interval. I am already deep in threads and scripts (processing fun also has threading inside). Scheduling through cron and not directly in `main.py` or `camera.py` will add **yet another** level of complexity I'm trying to avoid. – Matias Andina Feb 23 '20 at 16:02
  • I am coming from the point of view, that in some scenario you would want to change the scheduling logic and it becomes more complex and requires some more parameters in that case you will have to change your base python function. – ashwin agrawal Feb 23 '20 at 16:14
  • 1
    Yes, upvoted for modularity and a general way to handle scheduling from a script :) – Matias Andina Feb 23 '20 at 16:32