6

I'm capturing a timelapse with the picamera module for python:

from picamera import PiCamera, Color
class EggAlertCam:

    def __init__(self):
        self.camera = PiCamera()
        self.camera.start_preview()

    def capture_thread_task(self):

        filename = os.path.join(self.SAVEPATH, self.safe_camname + '_{timestamp:%Y%m%d-%H%M%S}-{counter:03d}' + '.jpg' )
        starttime = dt.datetime.now()
        current_time = dt.datetime.now()

        for filename in self.camera.capture_continuous(filename):
            print('Captured {}'.format(filename))
            self.wait(current_time)
            current_time = dt.datetime.now()

    def get_frame(self, size=None):
        if size is None:
            size = (640,480)
        output = io.BytesIO()
        self.camera.capture(output, format='jpeg', resize=size, use_video_port=True)
        output.seek(0)
        return output

This capture_thread_task runs in a thread, and I have a Flask application allowing to capture frames from the camera through a REST call which calls get_frame.

I'm using video_port=True with the hope that I can fetch an (higher noise, but I don't care) image even while capturing the timelapse, but I get an exception:

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/flask/app.py", line 2446, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.7/dist-packages/flask/app.py", line 1951, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.7/dist-packages/flask/app.py", line 1820, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python3.7/dist-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/usr/local/lib/python3.7/dist-packages/flask/app.py", line 1949, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.7/dist-packages/flask/app.py", line 1935, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/local/lib/python3.7/dist-packages/xxx/webapp.py", line 53, in get_frame
    jpg = scheduler.cam.get_frame(size=size)
  File "/usr/local/lib/python3.7/dist-packages/xxx/xxx.py", line 124, in get_frame
    self.camera.capture(output, format='jpeg', resize=size, use_video_port=True)
  File "/usr/local/lib/python3.7/dist-packages/picamera/camera.py", line 1409, in capture
    camera_port, output_port = self._get_ports(use_video_port, splitter_port)
  File "/usr/local/lib/python3.7/dist-packages/picamera/camera.py", line 562, in _get_ports
    'The camera is already using port %d ' % splitter_port)
picamera.exc.PiCameraAlreadyRecording: The camera is already using port 0

I thought I'd be using another port for that capture, but alas it doesn't seem to work.

From the documentation here: https://picamera.readthedocs.io/en/release-1.10/fov.html?highlight=splitter#under-the-hood I figured that the capture_continuous function used port 0, and I should be able to use the port 1 which is the one used when telling use_video_port=True. But the exception message tells me it still wants to use port 0..

EDIT: I tried with splitter port 2, and for some of my Pi's it seems to work, and for others the port 2 seems used. After a few minutes, the port starts to be avaiable and I can fetch a frame from it.

This looks like a capture that takes a too long time, but I don't know how to properly ask the port 2 to free itself for a new capture.

What am I doing wrong ?

Gui13
  • 12,993
  • 17
  • 57
  • 104
  • Not sure if `use_video_port` is related to this. https://www.raspberrypi.org/forums/viewtopic.php?t=172257 – Joe Feb 07 '20 at 11:41
  • It might be Flask spawning a request in a separate thread, creating a second instance of the camera trying to access the `/dev/video...` device. – Joe Feb 07 '20 at 11:42
  • @Joe, I share the same object between the two threads, so it should be [GIL](https://wiki.python.org/moin/GlobalInterpreterLock)d no? So when I capture a frame I use the same object than the one doing the timelapse. I thought it was Ok to do so because I ask data from another port. Maybe I should create a 2nd object dedicated to capturing frames ? – Gui13 Feb 07 '20 at 16:37
  • You can check if it really the same object using `print(id(your_object))`. – Joe Feb 07 '20 at 19:17

1 Answers1

0

Where you declared EggAlertCam object - inside or outside of a view method?

Try outside or use singleton.
Or you can run that in separate thread/process and send commands from Flask to it.

wowkin2
  • 5,895
  • 5
  • 23
  • 66