raspberrypi / picamera2

New libcamera based python library
BSD 2-Clause "Simplified" License
891 stars 188 forks source link

[HOW-TO] change FPS using picamera 2 #1128

Open NadiaColodro opened 1 month ago

NadiaColodro commented 1 month ago

Hi! I’m trying to change the FPS when i record, but the video duration becomes inaccurate when I convert it to MP4 and it lasts much less or accelerates the video. Do you have any suggestions on how to fix this? Here is my code:

#This script records a video for the specified time, converts the video to mp4 format, then uploads the video to a specified cloud location. It also creates a log file documenting each step in the script.
Variables - update as needed

this_pi = 'raspi0'  # Enter identifying info for recording here (e.g. subject ID). Appears in file name and annotation text
brightness = 60  # integer between 1-100. 50 is usually a good place to start
contrast = 700    # integer between 1-100. 50 is usually a good place to start
recording_length = 1200  # number of secs. 1 hour = 3600 secs, 5 minutes = 300 secs
rclone_config = 'lowell_lab:Recordings/'

from picamera2 import Picamera2
from picamera2.encoders import H264Encoder
from picamera2.outputs import FileOutput
from time import sleep
import os
import subprocess
from datetime import datetime
import logging
from libcamera import controls

today = datetime.now()
d1 = today.strftime("%d_%m_%Y")
d2 = today.strftime("%d_%m_%Y__%H_%M_%S")
d3 = today.strftime("%d_%m_%Y__%H_%M")

name = f"{this_pi}_{d3}"
file = f"{name}.h264"
path = f"/home/nadia/Videos/{file}"
file2 = f"{name}.mp4"
path2 = f"/home/nadia/Videos/{file2}"

log_file = f"/home/nadia/Documents/Logs/{name}.txt"
logging.basicConfig(filename=log_file, level=logging.INFO, format='%(asctime)s:%(levelname)s:%(message)s')
logging.info(f"{this_pi} {d1}")

print("Starting recording")
logging.info("Starting recording")

# Initialize Picamera2
camera = Picamera2(0)
video_config = camera.create_video_configuration(main={"size": (1920, 1080), "format": "YUV420"})
camera.video_configuration.controls.FrameRate= 25.0
camera.configure(video_config)

# Set autofocus control
camera.set_controls({"AfMode": controls.AfModeEnum.Continuous})

try:
    camera.start_preview()
    # Start recording
    output = FileOutput(path)
    encoder = H264Encoder(bitrate=2000000)  # Adjust bitrate for quality
    camera.start_recording(encoder, output)
    sleep(recording_length)  # Record for the specified duration
    camera.stop_recording()
    camera.stop_preview()
    print("Finished recording")

except Exception as e:
    logging.exception('Recording error found')
    new_log_file = f"/home/nadia/Documents/Logs/FAILED_recording_{name}.txt"
    os.rename(log_file, new_log_file)
    raise

print("Beginning conversion to MP4")
logging.info("Beginning conversion to MP4")

# Convert file to MP4 format. Requires command line subprocess
from subprocess import CalledProcessError
command = f"ffmpeg -i {path} -c:v copy {path2}"
try:
    output = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=True)
except subprocess.CalledProcessError as e:
    logging.info('MP4 conversion FAIL:\ncmd:{}\noutput:{}'.format(e.cmd, e.output))
    new_log_file = f"/home/nadia/Documents/Logs/FAILED_mp4_conversion_{name}.txt"
    os.rename(log_file, new_log_file)
    raise

print("Conversion finished... Starting MP4 upload")
logging.info("Conversion finished... Starting MP4 upload")

# Upload MP4 to cloud
upload = f"rclone move {path2} {rclone_config} --contimeout=40m"
os.system(upload)

print("Removing H264 file")
logging.info("Removing H264 file")

try:
    os.remove(path)
    print("H264 video moved to trash")
    logging.info("Videos moved to trash")
except Exception as e:
    logging.exception("H264 removal error")
    new_log_file = f"/home/nadia/Documents/Logs/FAILED_delete_{name}.txt"
    os.rename(log_file, new_log_file)
    raise

# Print remaining files in Video directory
vids_list = os.listdir('/home/nadia/Videos/')
vids = '\n'.join(vids_list)
print("Remaining videos:" + vids)
logging.info('Remaining videos:' + vids)
`
NadiaColodro commented 1 month ago

I'm using a raspberry pi 5 and camera module 3!

davidplowman commented 1 month ago

The problem is likely to be that H.264 output files don't contain timestamps, so when you convert it to mp4 it picks some unspecified framerate.

Usually, when you convert to mp4, I would expect the tool to accept some kind of "framerate" parameter, so that you can adjust this to match the real framerate.

Alternatively, when you start recording, there's a pts parameter which you can use to write a file containing timestamps. Some tools (maybe makemkv?) may accept this as input.

Finally, you could use the FfmpegOutput class instead of FileOutput. This should get the timestamps approximately right, though note that Ffmpeg will resample them and so they will exhibit a fair degree of jitter. But it should be "close".

NadiaColodro commented 1 month ago

Thank you so much!