picamera icon indicating copy to clipboard operation
picamera copied to clipboard

Corrupted H264 files when switching between ring buffers

Open rossGardiner opened this issue 2 years ago • 3 comments

Hi,

I'm writing an application which saves h264 and rgb streams when motion is detected. My strategy to get around slow RPi IO is to implement two buffers and switch between them. See my program snippet below:

def write_video(stream,filename, frametype=picamera.PiVideoFrameType.frame):
    # Write the entire content of the circular buffer to disk. No need to
    # lock the stream here as we're definitely not writing to it
    # simultaneously
    with io.open(filename, 'ab') as output:
        for frame in stream.frames:
            if frame.frame_type == frametype:
                stream.seek(frame.position)
                break
        while True:
            buf = stream.read1()
            if not buf:
                break
            output.write(buf)
    # Wipe the circular stream once we're done
    stream.seek(0)
    stream.clear()

#camera set up stuff
iobuf_h264_1 = PiCameraIO(camera, seconds=seconds, splitter_port=1)
iobuf_h264_2 = PiCameraIO(camera, seconds=seconds, splitter_port=1)

iobuf_imgs_1 = PiCameraIO(camera, seconds=(seconds), splitter_port=0)
iobuf_imgs_2 = PiCameraIO(camera, seconds=(seconds), splitter_port=0)

camera.start_recording(iobuf_h264_1, format='h264', splitter_port=1, motion_output=motion_detector)
camera.start_recording(iobuf_imgs_1,  format='rgb', splitter_port=0,  resize=(416, 416))
try:
        while filenum < 10:
            
            if motion_detector.is_motion:
                #this is a motion event
                print('motion detected!')
                start = time.time()
                first_flag = True
                while motion_detector.is_motion:
                    camera.split_recording(iobuf_h264_2, splitter_port=1)
                    camera.split_recording(iobuf_imgs_2, splitter_port=0)
                    write_video(iobuf_h264_1, 'motion'+str(filenum)+'.h264', picamera.PiVideoFrameType.sps_header)
                    write_video(iobuf_imgs_1, 'motion'+str(filenum)+'.dat')
                    camera.wait_recording(3)
                    camera.split_recording(iobuf_h264_1, splitter_port=1)
                    camera.split_recording(iobuf_imgs_1, splitter_port=0)
                    write_video(iobuf_h264_2, 'motion'+str(filenum)+'.h264', picamera.PiVideoFrameType.sps_header)
                    write_video(iobuf_imgs_2, 'motion'+str(filenum)+'.dat')
                    camera.wait_recording(3)
                    first_flag = False
                end = time.time()
                filenum += 1
                print('motion ended! lasted {}s'.format(end-start))

When I view H264 files which I've saved, they are corrupted and only play to the sections where they have been joined together before vlc player gives up and starts again. Is there some problem with the way I'm appending the video to disk? I followed a PiCamera example.

Many thanks for any advice.

rossGardiner avatar Sep 08 '21 18:09 rossGardiner

Update: I suspect the steam corruption is due to large gaps in frames caused by latency of the split_recording function. I measured the split_recording latency for h264 stream. It can grow to be as large as 1.5 seconds. I'm recording at 1080p 25fps 17Mbps.

How is this possible? I'm only changing the location in memory the stream writes to - right? Why does split_recording occasionally take absolutely ages to complete?

rossGardiner avatar Sep 09 '21 12:09 rossGardiner

As far as I know split_recording will ask the encoder to produce a new keyframe. This does not mean the encoder will immediately generate one, although 1.5seconds seems like a lot.

There also was an issue with the ringbuffer not being able to hold an entire frame when it was too big. Supposedly this was fixed but there isn't a new release of it. So maybe try installing directly from the repo

Esser50K avatar Oct 08 '21 10:10 Esser50K

or just try using picameraX -> https://github.com/labthings/picamerax

Esser50K avatar Oct 08 '21 10:10 Esser50K