waveform80 / picamera

A pure Python interface to the Raspberry Pi camera module
https://picamera.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
1.57k stars 355 forks source link

Empty rgb files written to disk #702

Closed rossGardiner closed 3 years ago

rossGardiner commented 3 years ago

Hello,

I am trying to write a PiCamera application capable of the following after motion is detected:

I have assigned a PiCameraCircularIO buffer for both the rgb and h264 streams. When I copy data from the rgb buffer to file, the before.dat file is always empty, while after.dat, before.h264 and after.h264 always contain data. My suspicion is this is because the data in the ring buffer is too large to copy to disk quickly, so I added a delay between copying and clearing the buffer. No avail.

Can someone help?

Below I show a sketch of my application, based on one of the examples in the docs:

from ctypes import resize
import io
import random
import picamera
from PIL import Image
from time import sleep

def detect_motion(camera):
    result = random.randint(0, 5) == 0
    return result

with picamera.PiCamera() as camera:
    camera.resolution = (1920, 1080)
    camera.framerate = 25
    camera.annotate_frame_num = True
    stream_h264 = picamera.PiCameraCircularIO(camera, seconds=10,splitter_port=1)
    stream_image = picamera.PiCameraCircularIO(camera, seconds=10, splitter_port=0)
    camera.start_recording(stream_h264, format='h264', splitter_port=1)
    camera.start_recording(stream_image, format='rgb', splitter_port=0,  resize=(416, 416))
    try:
        while True:
            camera.wait_recording(1)
            if detect_motion(camera):
                print('Motion detected!')
                # As soon as we detect motion, split the recording to
                # record the frames "after" motion
                camera.split_recording('after.h264', splitter_port=1)
                camera.split_recording('after.dat', splitter_port=0)
                print(list(enumerate(stream_image.frames)))
                # Write the 10 seconds "before" motion to disk as well
                stream_h264.copy_to('before.h264', seconds=10)
                stream_image.copy_to('before.dat', seconds=10)
                sleep(20)
                stream_h264.clear()
                stream_image.clear()
                # Wait until motion is no longer detected, then split
                # recording back to the in-memory circular buffer
                while detect_motion(camera):
                    camera.wait_recording(1)
                print('Motion stopped!')
                camera.split_recording(stream_h264, splitter_port=1)
                camera.split_recording(stream_image, splitter_port=0)
    finally:
        camera.stop_recording()
6by9 commented 3 years ago

https://picamera.readthedocs.io/en/release-1.13/api_streams.html#picamera.PiCameraCircularIO.copy_to

copy_to(output, size=None, seconds=None, first_frame=PiVideoFrameType.sps_header) Warning Note that if a frame of the specified type (e.g. SPS header) cannot be found within the specified number of seconds or bytes then this method will simply copy nothing (but no error will be raised).

An RGB stream will never have any frames of type PiVideoFrameType.sps_header, so it will never copy any data.

stream_image.copy_to('before.dat', seconds=10, first_frame=PiVideoFrameType.frame) is more likely to work.

rossGardiner commented 3 years ago

Thank you