树莓派使用cv2.VideoWriter录制视频异常:时长缩短、播放加速且无声音
Hey there! Let's work through your two video recording issues on Raspberry Pi—shortened/fast-playing footage and missing audio—with practical fixes and code tweaks.
1. Fixing Shortened Video & Speed-Up Playback
The root cause here is almost always a mismatch between the frame rate you set for VideoWriter and the actual frame rate your Raspberry Pi camera is outputting. For example, if you hardcode 30fps but the camera only captures 6fps, 10 seconds of recording would only produce 60 frames—playing back at 30fps makes it feel like 2x speed and only 2 seconds long.
Here's how to fix it:
- First, estimate your camera's real frame rate instead of guessing
- Record based on total frame count (calculated from real fps + desired duration) instead of relying on
time.sleep()
Modified Video-Only Code
import numpy as np import cv2 import time capture_duration = 10 # Desired recording length in seconds # Initialize camera (0 = default Pi camera) cap = cv2.VideoCapture(0) # Estimate actual camera FPS (cap.get(CAP_PROP_FPS) is often inaccurate on Pi) start_time = time.time() frame_count = 0 for _ in range(30): ret, frame = cap.read() if ret: frame_count += 1 actual_fps = frame_count / (time.time() - start_time) print(f"Detected camera FPS: {actual_fps:.2f}") # Configure VideoWriter with matching FPS fourcc = cv2.VideoWriter_fourcc(*'MJPG') # MJPG is more stable on Pi than XVID width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) out = cv2.VideoWriter('fixed_video.avi', fourcc, actual_fps, (width, height)) # Calculate total frames needed for desired duration total_frames = int(actual_fps * capture_duration) captured_frames = 0 # Start recording loop while captured_frames < total_frames: ret, frame = cap.read() if ret: out.write(frame) captured_frames += 1 # Optional preview window cv2.imshow('Recording', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break else: print("Warning: Failed to capture a frame") break # Cleanup cap.release() out.release() cv2.destroyAllWindows() print(f"Recording complete! Captured {captured_frames} frames over {time.time()-start_time:.2f} seconds")
2. Adding Audio to Your Recording
OpenCV's VideoWriter doesn't support audio recording at all—it only handles video frames. To add sound, you'll need to record audio separately with a Python audio library, then merge the video and audio files using ffmpeg.
Step 1: Install Dependencies
First, install required packages on your Pi:
sudo apt install ffmpeg portaudio19-dev pip install sounddevice numpy scipy
Step 2: Combined Video + Audio Recording Code
This uses threads to record video and audio simultaneously, then merges them with ffmpeg:
import numpy as np import cv2 import time import sounddevice as sd from scipy.io.wavfile import write import threading import subprocess import os capture_duration = 10 # --- Video Setup --- cap = cv2.VideoCapture(0) # Estimate real camera FPS start_time = time.time() frame_count = 0 for _ in range(30): ret, frame = cap.read() if ret: frame_count += 1 actual_fps = frame_count / (time.time() - start_time) print(f"Camera FPS: {actual_fps:.2f}") fourcc = cv2.VideoWriter_fourcc(*'MJPG') width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) video_out = cv2.VideoWriter('temp_video.avi', fourcc, actual_fps, (width, height)) total_frames = int(actual_fps * capture_duration) # --- Audio Setup --- audio_sample_rate = 44100 audio_channels = 2 audio_total_frames = int(audio_sample_rate * capture_duration) def record_audio(): """Record audio in a separate thread""" audio_data = sd.rec(audio_total_frames, samplerate=audio_sample_rate, channels=audio_channels, dtype='int16') sd.wait() # Wait for recording to finish write('temp_audio.wav', audio_sample_rate, audio_data) # Start audio recording thread audio_thread = threading.Thread(target=record_audio) audio_thread.start() # --- Record Video --- captured_frames = 0 while captured_frames < total_frames: ret, frame = cap.read() if ret: video_out.write(frame) captured_frames += 1 cv2.imshow('Recording', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break # Cleanup video resources cap.release() video_out.release() cv2.destroyAllWindows() # Wait for audio recording to finish audio_thread.join() # Merge video and audio with ffmpeg subprocess.run([ 'ffmpeg', '-y', # Overwrite output file without prompting '-i', 'temp_video.avi', '-i', 'temp_audio.wav', '-c:v', 'copy', # Reuse existing video codec (no re-encoding) '-c:a', 'aac', # Encode audio to AAC (widely supported) 'final_with_audio.mp4' ]) # Delete temporary files os.remove('temp_video.avi') os.remove('temp_audio.wav') print("Final video with audio saved as final_with_audio.mp4")
Quick Additional Tips
- If you still have issues with camera access, enable the camera in
sudo raspi-config> Interface Options > Camera - Try adjusting the camera resolution manually with
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)andcap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)if the auto-detected resolution is causing problems - For better performance, close any other apps using the camera before running your script
内容的提问来源于stack exchange,提问作者user3470406

