waveform80/picamera

Empty rgb files written to disk

Closed this issue · 2 comments

Hello,

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

  • Save a stream of before and after video to h264 format
  • Save a stream of uncompressed and down-scaled images from the motion corresponding exactly to those within the motion event.
  • Eventually save the uncompressed stream at a much reduced framerate compared to the video stream, so I do not save too much data.

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

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.

Thank you