Add comprehensive video playback optimization for smooth performance
Environment variable optimizations: - KIVY_WINDOW='pygame' - Better window backend performance - KIVY_AUDIO='ffpyplayer' - Optimized audio playback - KIVY_GL_BACKEND='gl' - Use OpenGL for better graphics - FFMPEG_THREADS='4' - Multi-threaded video decoding - LIBPLAYER_BUFFER='2048000' - 2MB buffer for smooth playback - SDL_AUDIODRIVER='alsa' - Better audio on Raspberry Pi Kivy configuration optimizations: - multisampling=0 - Disable for better performance - fast_rgba=1 - Enable fast RGBA mode - Stereo audio (channels=2) - Reduced logging overhead (warning level) Video widget enhancements: - FFmpeg buffer optimization (2MB) - Multi-threaded decoding (4 threads) - Ignore index for better seeking - Allow codec fallback - 60 FPS animation delay New video optimization script (.video-optimization.sh): - GPU memory increased to 256MB - Install video codec libraries - Optimize swappiness to 30 (better memory management) - CPU forced to performance mode - Filesystem cache optimization Installation integration: - Runs video optimization automatically on Raspberry Pi - Configures GPU memory, libraries, and system settings - Improves overall video playback smoothness This addresses video stuttering, frame drops, and playback lag by optimizing at multiple levels: environment, application, and system.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -57,3 +57,5 @@ playlists/server_playlist_*.json
|
|||||||
# OS
|
# OS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|
||||||
|
.player_heartbear
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1768673747.1927276
|
1768675283.8000998
|
||||||
61
.video-optimization.sh
Normal file
61
.video-optimization.sh
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Video playback optimization script for Raspberry Pi
|
||||||
|
# Improves video smoothness and reduces stuttering
|
||||||
|
|
||||||
|
echo "Optimizing system for smooth video playback..."
|
||||||
|
|
||||||
|
# 1. Increase GPU memory split for better video performance
|
||||||
|
if [ -f /boot/config.txt ]; then
|
||||||
|
echo "Checking GPU memory configuration..."
|
||||||
|
if grep -q "gpu_mem=" /boot/config.txt; then
|
||||||
|
# GPU memory already configured, check if it's sufficient
|
||||||
|
CURRENT_GPU_MEM=$(grep "gpu_mem=" /boot/config.txt | head -1 | cut -d'=' -f2)
|
||||||
|
if [ "$CURRENT_GPU_MEM" -lt 256 ]; then
|
||||||
|
sudo sed -i 's/gpu_mem=.*/gpu_mem=256/' /boot/config.txt
|
||||||
|
echo "✓ GPU memory increased to 256MB for video"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Add GPU memory setting
|
||||||
|
echo "gpu_mem=256" | sudo tee -a /boot/config.txt > /dev/null
|
||||||
|
echo "✓ GPU memory set to 256MB for video"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2. Install video codec support
|
||||||
|
echo "Installing video codec libraries..."
|
||||||
|
sudo apt-get install -y \
|
||||||
|
libva-drm2 \
|
||||||
|
libva2 \
|
||||||
|
libavcodec-extra \
|
||||||
|
libavutil-dev \
|
||||||
|
2>/dev/null || true
|
||||||
|
|
||||||
|
# 3. Optimize swappiness for better memory management
|
||||||
|
echo "Optimizing memory management..."
|
||||||
|
if [ -f /proc/sys/vm/swappiness ]; then
|
||||||
|
CURRENT_SWAP=$(cat /proc/sys/vm/swappiness)
|
||||||
|
if [ "$CURRENT_SWAP" -gt 30 ]; then
|
||||||
|
echo 30 | sudo tee /proc/sys/vm/swappiness > /dev/null
|
||||||
|
echo "vm.swappiness=30" | sudo tee -a /etc/sysctl.conf > /dev/null
|
||||||
|
echo "✓ Swappiness optimized"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4. Disable CPU frequency scaling for consistent performance
|
||||||
|
echo "Ensuring CPU performance mode..."
|
||||||
|
for cpu in /sys/devices/system/cpu/cpu[0-9]*; do
|
||||||
|
if [ -f "$cpu/cpufreq/scaling_governor" ]; then
|
||||||
|
echo performance | sudo tee "$cpu/cpufreq/scaling_governor" > /dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "✓ CPU set to performance mode"
|
||||||
|
|
||||||
|
# 5. Optimize file system cache
|
||||||
|
echo "Optimizing filesystem cache..."
|
||||||
|
echo 50 | sudo tee /proc/sys/vm/vfs_cache_pressure > /dev/null
|
||||||
|
echo "vm.vfs_cache_pressure=50" | sudo tee -a /etc/sysctl.conf > /dev/null
|
||||||
|
echo "✓ Filesystem cache optimized"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ Video playback optimization complete!"
|
||||||
|
echo "Note: Some changes require a reboot to take effect."
|
||||||
13
install.sh
13
install.sh
@@ -593,6 +593,19 @@ if detect_raspberry_pi; then
|
|||||||
setup_raspberry_pi_power_management
|
setup_raspberry_pi_power_management
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Optimize video playback for Raspberry Pi
|
||||||
|
if detect_raspberry_pi; then
|
||||||
|
echo ""
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Optimizing for Video Playback"
|
||||||
|
echo "=========================================="
|
||||||
|
|
||||||
|
# Run video optimization script
|
||||||
|
if [ -f "$SCRIPT_DIR/.video-optimization.sh" ]; then
|
||||||
|
bash "$SCRIPT_DIR/.video-optimization.sh"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
echo "To run the signage player:"
|
echo "To run the signage player:"
|
||||||
echo " cd src && python3 main.py"
|
echo " cd src && python3 main.py"
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
35
src/main.py
35
src/main.py
@@ -16,10 +16,27 @@ os.environ['KIVY_VIDEO'] = 'ffpyplayer' # Use ffpyplayer as video provider
|
|||||||
os.environ['FFPYPLAYER_CODECS'] = 'h264,h265,vp9,vp8' # Support common codecs
|
os.environ['FFPYPLAYER_CODECS'] = 'h264,h265,vp9,vp8' # Support common codecs
|
||||||
os.environ['SDL_VIDEO_ALLOW_SCREENSAVER'] = '0' # Prevent screen saver
|
os.environ['SDL_VIDEO_ALLOW_SCREENSAVER'] = '0' # Prevent screen saver
|
||||||
|
|
||||||
|
# Video playback optimizations
|
||||||
|
os.environ['KIVY_WINDOW'] = 'pygame' # Use pygame backend for better performance
|
||||||
|
os.environ['KIVY_AUDIO'] = 'ffpyplayer' # Use ffpyplayer for audio
|
||||||
|
os.environ['KIVY_GL_BACKEND'] = 'gl' # Use OpenGL backend
|
||||||
|
os.environ['FFMPEG_THREADS'] = '4' # Use 4 threads for ffmpeg decoding
|
||||||
|
os.environ['LIBPLAYER_BUFFER'] = '2048000' # 2MB buffer for smooth playback
|
||||||
|
os.environ['SDL_AUDIODRIVER'] = 'alsa' # Use ALSA for better audio on Pi
|
||||||
|
|
||||||
# Configure Kivy BEFORE importing any Kivy modules
|
# Configure Kivy BEFORE importing any Kivy modules
|
||||||
from kivy.config import Config
|
from kivy.config import Config
|
||||||
# Disable default virtual keyboard - we'll use our custom one
|
|
||||||
Config.set('kivy', 'keyboard_mode', '')
|
# Performance optimizations for video playback
|
||||||
|
Config.set('kivy', 'keyboard_mode', '') # Disable default virtual keyboard
|
||||||
|
Config.set('graphics', 'fullscreen', '0') # Will be set to 1 later
|
||||||
|
Config.set('graphics', 'window_state', 'maximized') # Maximize window
|
||||||
|
|
||||||
|
# Video and audio performance settings
|
||||||
|
Config.set('graphics', 'multisampling', '0') # Disable multisampling for better performance
|
||||||
|
Config.set('graphics', 'fast_rgba', '1') # Enable fast RGBA for better performance
|
||||||
|
Config.set('audio', 'channels', '2') # Stereo audio
|
||||||
|
Config.set('kivy', 'log_level', 'warning') # Reduce logging overhead
|
||||||
|
|
||||||
from kivy.app import App
|
from kivy.app import App
|
||||||
from kivy.uix.widget import Widget
|
from kivy.uix.widget import Widget
|
||||||
@@ -1315,7 +1332,7 @@ class SignagePlayer(Widget):
|
|||||||
self.next_media()
|
self.next_media()
|
||||||
|
|
||||||
def play_video(self, video_path, duration):
|
def play_video(self, video_path, duration):
|
||||||
"""Play a video file using Kivy's Video widget"""
|
"""Play a video file using Kivy's Video widget with optimizations"""
|
||||||
try:
|
try:
|
||||||
# Verify file exists
|
# Verify file exists
|
||||||
if not os.path.exists(video_path):
|
if not os.path.exists(video_path):
|
||||||
@@ -1326,15 +1343,23 @@ class SignagePlayer(Widget):
|
|||||||
|
|
||||||
Logger.debug(f"SignagePlayer: Loading video {os.path.basename(video_path)} for {duration}s")
|
Logger.debug(f"SignagePlayer: Loading video {os.path.basename(video_path)} for {duration}s")
|
||||||
|
|
||||||
# Create Video widget with optimized settings
|
# Create Video widget with optimized settings for smooth playback
|
||||||
self.current_widget = Video(
|
self.current_widget = Video(
|
||||||
source=video_path,
|
source=video_path,
|
||||||
state='play', # Start playing immediately
|
state='play', # Start playing immediately
|
||||||
options={
|
options={
|
||||||
'eos': 'stop', # Stop at end of stream
|
'eos': 'stop', # Stop at end of stream
|
||||||
|
'ff_opts': {
|
||||||
|
# FFmpeg options for better playback performance
|
||||||
|
'buffer_size': '2048000', # 2MB buffer
|
||||||
|
'threads': '4', # Multi-threaded decoding
|
||||||
|
'fflags': '+ignidx', # Ignore index for better seeking
|
||||||
|
},
|
||||||
|
'allow_fallback': True, # Allow codec fallback
|
||||||
},
|
},
|
||||||
size_hint=(1, 1),
|
size_hint=(1, 1),
|
||||||
pos_hint={'center_x': 0.5, 'center_y': 0.5}
|
pos_hint={'center_x': 0.5, 'center_y': 0.5},
|
||||||
|
anim_delay=1.0/60.0 # 60 FPS animation
|
||||||
)
|
)
|
||||||
|
|
||||||
# Bind to loaded and error events
|
# Bind to loaded and error events
|
||||||
|
|||||||
Reference in New Issue
Block a user