Note
Hello, welcome to the SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts Community on Facebook! Dive deeper into Raspberry Pi, Arduino, and ESP32 with fellow enthusiasts.
Why Join?
Expert Support: Solve post-sale issues and technical challenges with help from our community and team.
Learn & Share: Exchange tips and tutorials to enhance your skills.
Exclusive Previews: Get early access to new product announcements and sneak peeks.
Special Discounts: Enjoy exclusive discounts on our newest products.
Festive Promotions and Giveaways: Take part in giveaways and holiday promotions.
👉 Ready to explore and create with us? Click [here] and join today!
3.2 Video Module
Introduction
Beyond taking photos, the Raspberry Pi Camera Module also allows you to record high-quality videos. This project demonstrates how to set up the camera module to record videos with configurable resolution, frame rate, and bitrate, saving them directly to your Raspberry Pi.
What You’ll Need
Below are the components required for this project:
COMPONENT INTRODUCTION |
PURCHASE LINK |
|---|---|
- |
|
Raspberry Pi |
- |
Experimental Procedures
To use camera module conveniently, Assemble the Pan-tilt (For Camera) is recommended.
Note
Assembling the pan-tilt may obscure some pins, so it is recommended to assemble it only when using the camera, or place it on the outside after assembly.
Access the Raspberry Pi Desktop:
Remote Desktop: Use VNC for a full desktop experience.
Raspberry Pi Connect: Use Raspberry Pi Connect to access your Pi securely from any browser.
Open a Terminal and navigate to the project folder:
cd ~/ai-lab-kit/python
Run the video recording script:
sudo python3 3.2_Video.py
After the script starts, press the Fusion HAT+ USR button to control recording.
First press → Start recording with a live preview.
Second press → Stop recording.
Videos are saved in your
~/Videosdirectory with names like:video_20250101_153045.mp4.Press
Ctrl+Cin the terminal to exit the program.
Note
QT preview requires a desktop environment. If the preview cannot be started (for example, over SSH), the camera can still capture and save photos normally.
Code
Below is the Python code used for this project:
import os
import time
import pwd
from picamera2 import Picamera2, Preview
from picamera2.encoders import H264Encoder
from picamera2.outputs import FfmpegOutput
from fusion_hat.user_button import UserButton
# ----- Paths (works correctly even when using sudo) -----
sudo_user = os.getenv("SUDO_USER")
home = pwd.getpwnam(sudo_user).pw_dir if sudo_user else os.path.expanduser("~")
videos_dir = os.path.join(home, "Videos")
os.makedirs(videos_dir, exist_ok=True)
# ----- Camera / encoder -----
camera = Picamera2()
camera.configure(camera.create_video_configuration(main={"size": (800, 600)}, controls={"FrameRate": 30}))
encoder = H264Encoder(bitrate=10_000_000)
is_recording = False
output = None
preview_started = False
def start_recording():
"""Start recording to a timestamped MP4 file."""
global is_recording, output
ts = time.strftime("%Y%m%d_%H%M%S")
path = os.path.join(videos_dir, f"video_{ts}.mp4")
output = FfmpegOutput(path) # keep a reference while recording
camera.start_recording(encoder, output)
is_recording = True
print(f"\nStart recording: {path}")
def stop_recording():
"""Stop recording safely."""
global is_recording, output
camera.stop_recording()
is_recording = False
output = None
print("\nStop recording.")
def toggle():
"""USR button callback: toggle start/stop."""
if not is_recording:
start_recording()
else:
stop_recording()
# ----- Button -----
UserButton().set_on_click(toggle)
# ----- Preview (only if a GUI display is available) -----
if os.getenv("DISPLAY"):
try:
camera.start_preview(Preview.QT)
preview_started = True
except Exception:
preview_started = False # continue without preview
# ----- Run -----
camera.start()
print("Press USR to START/STOP recording. Ctrl+C to exit.")
try:
while True:
time.sleep(0.1)
except KeyboardInterrupt:
pass
finally:
# Stop recording if still active
if is_recording:
try:
camera.stop_recording()
except Exception:
pass
# Stop preview only if it was started
if preview_started:
try:
camera.stop_preview()
except Exception:
pass
try:
camera.stop()
except Exception:
pass
try:
camera.close()
except Exception:
pass
Understanding the Code
Understanding the Code
Imports and Purpose
import os import time import pwd from picamera2 import Picamera2, Preview from picamera2.encoders import H264Encoder from picamera2.outputs import FfmpegOutput from fusion_hat.user_button import UserButton
These modules are used for:
os: reading environment variables (e.g.,DISPLAY,SUDO_USER) and building file paths.time: generating timestamped filenames and keeping the program running in a loop.pwd: finding the real user’s home directory when the script is run withsudo.Picamera2/Preview: controlling the camera pipeline and preview modes.H264Encoder: encoding video frames into H.264 format.FfmpegOutput: saving the encoded stream into an.mp4file using FFmpeg.UserButton: reading the Fusion HAT+ USR button and binding a click callback.
Selecting the Correct Save Directory (Works with sudo)
sudo_user = os.getenv("SUDO_USER") home = pwd.getpwnam(sudo_user).pw_dir if sudo_user else os.path.expanduser("~") videos_dir = os.path.join(home, "Videos") os.makedirs(videos_dir, exist_ok=True)
This ensures videos are saved in the real user’s
~/Videosfolder:When run with
sudo,SUDO_USERpoints to the original user.pwd.getpwnam(...).pw_dirreturns that user’s home directory.If not using
sudo, it falls back to the current user’s home (~).~/Videosis created if it doesn’t exist.
Camera and Video Encoder Initialization
camera = Picamera2() camera.configure(camera.create_video_configuration(main={"size": (800, 600)}, controls={"FrameRate": 30})) encoder = H264Encoder(bitrate=10_000_000)
create_video_configuration(...)sets up the camera pipeline for recording video.size=(800, 600)chooses the recording resolution.FrameRate=30records at 30 FPS.H264Encodercompresses the stream to H.264 at ~10 Mbps.
Recording State Variables
is_recording = False output = None preview_started = False
is_recordingtracks whether recording is currently active.outputstores theFfmpegOutputobject to keep it alive while recording.preview_startedrecords whether a preview window was successfully started, so we only stop preview if it actually exists.
Starting a Recording
def start_recording(): """Start recording to a timestamped MP4 file.""" global is_recording, output ts = time.strftime("%Y%m%d_%H%M%S") path = os.path.join(videos_dir, f"video_{ts}.mp4") output = FfmpegOutput(path) # keep a reference while recording camera.start_recording(encoder, output) is_recording = True print(f"\nStart recording: {path}")
When recording starts:
A timestamped filename is generated (e.g.,
video_20260203_154500.mp4).A new
FfmpegOutputis created for that file.camera.start_recording(...)begins encoding and writing the video stream.
Stopping a Recording
def stop_recording(): """Stop recording safely.""" global is_recording, output camera.stop_recording() is_recording = False output = None print("\nStop recording.")
When recording stops:
camera.stop_recording()finalizes the output file correctly.The output reference is cleared so the object can be released.
USR Button Toggle Control
def toggle(): if not is_recording: start_recording() else: stop_recording() UserButton().set_on_click(toggle)
Each press of the Fusion HAT+ USR button toggles recording:
First press → start recording.
Second press → stop recording.
Preview Logic (Works With or Without a Screen)
if os.getenv("DISPLAY"): try: camera.start_preview(Preview.QT) preview_started = True except Exception: preview_started = False
If a desktop GUI is available (
DISPLAYis set), the script attempts a QT preview.If no screen/GUI is available (such as SSH without X11), it skips preview safely and recording still works normally.
Main Loop and Clean Exit (Ctrl+C)
camera.start() try: while True: time.sleep(0.1) except KeyboardInterrupt: pass finally: if is_recording: camera.stop_recording() if preview_started: camera.stop_preview() camera.stop() camera.close()
camera.start()starts the camera pipeline.The loop keeps the script running so it can respond to button presses.
When Ctrl+C is pressed, the
finallyblock runs: - Stops recording if it is active (prevents corrupted video files). - Stops preview only if it was started (prevents preview-related errors). - Stops and closes the camera to release hardware resources cleanly.
Troubleshooting
No Preview Window
Cause: Running without a desktop environment or missing Picamera2 GUI support.
Fix: Use Raspberry Pi Desktop/VNC and install Picamera2:
sudo apt install -y python3-picamera2
USR Button Not Working
Cause: Fusion HAT+ not connected or insufficient permissions.
Fix: Reseat the HAT, run the script with
sudo, and print debug logs intoggle_recording()if needed.
Video Not Saved
Cause: Incorrect home directory when using
sudoor missing~/Videosfolder.Fix: Check
REAL_USERandVIDEOS_DIRvalues. Ensure~/Videosexists and is writable.
Recording Starts/Stops Unexpectedly
Cause: Camera in use by another process or system under heavy load.
Fix: Close other camera apps, reboot the Pi, and ensure
ffmpegis installed.
File Not Finalized
Cause: Script terminated abruptly before stopping recording.
Fix: Always exit with
Ctrl+Cso the script can stop recording properly.
Conclusion
This script lets you start and stop video recording using the Fusion HAT+ USR button while viewing a live preview. Videos are saved automatically to ~/Videos with timestamped filenames.
It provides a simple foundation for button-controlled video capture and can be extended for DIY cameras, classroom demos, or sensor-triggered recording projects.