Почему мое приложение VLC Media Player теряет память графического процессора на Raspberry Pi 4B+ и 5?Python

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Почему мое приложение VLC Media Player теряет память графического процессора на Raspberry Pi 4B+ и 5?

Сообщение Anonymous »

У нас есть приложение медиаплеера на основе Python, которое просматривает медиафайлы и отображает их на экране.
После примерно 3–24 часов работы дисплей иногда зависает. во время воспроизведения видео. Когда это происходит, dmesg отображает следующие сообщения (эти конкретные сообщения относятся к тому времени, когда мы еще использовали drm для вывода видео. Сейчас мы используем xcb_xv, но у нас та же проблема):

Код: Выделить всё

...
...
[    3.028998] vc4-drm gpu: [drm] fb0: vc4drmfb frame buffer device
[ 9139.538040] vc4-drm gpu: [drm] *ERROR* Failed to allocate DLIST entry. Requested size=9. ret=-28
[ 9139.545459] vc4-drm gpu: [drm] *ERROR* Failed to allocate DLIST entry. Requested size=9. ret=-28
[ 9139.552522] vc4-drm gpu: [drm] *ERROR* Failed to allocate DLIST entry. Requested size=9. ret=-28
[ 9139.583064] vc4-drm gpu: [drm] *ERROR* Failed to allocate DLIST entry. Requested size=9. ret=-28
[ 9151.090537] vc4-drm gpu: [drm] *ERROR* Failed to allocate DLIST entry. Requested size=9. ret=-28
[ 9151.096344] vc4-drm gpu: [drm] *ERROR* Failed to allocate DLIST entry. Requested size=9. ret=-28
[ 9191.649563] vc4-drm gpu: [drm] *ERROR* Failed to allocate DLIST entry. Requested size=9. ret=-28
[ 9191.675813] vc4-drm gpu: [drm] *ERROR* Failed to allocate DLIST entry. Requested size=9. ret=-28
...
...
Это указывает на утечку памяти графического процессора и ее недостаточно для продолжения воспроизведения видео. В остальном устройство (Raspberry Pi) продолжает функционировать.
Для видеофайлов для воспроизведения используется VLC. В конце каждого видео мы пытаемся очистить все ресурсы, которые VLC использовал для отображения видео. Мы также попытались сохранить счетчик воспроизведения видео, который использовался для полного отключения и восстановления экземпляра проигрывателя VLC после каждых 50 воспроизведений видео. Это не решило проблему.
Вот код:

Код: Выделить всё

import os
import time
import json
import vlc
import subprocess
from pathlib import Path
import pygame
from pygame import display, image, time as pygame_time
from jplayer.utils import scene_update_flag_utils as sufu
from jplayer.utils import logging_utils as lu
from jplayer.utils import system_utils as su
from jplayer.clients.japi_client import JApiClient

logger = lu.get_logger("jplayer_app")

VIDEO_REINIT_THRESHOLD = 50

class MediaPlayer:
def __init__(self, media_directory, scenes_directory):
logger.info("Initializing MediaPlayer ...")
self.media_directory = Path(media_directory)
self.scenes_directory = Path(scenes_directory)
self.default_image_path = Path('/home/static_images/ready_for_content.jpeg')
self.supported_images = {'.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.heic'}
self.supported_videos = {'.mp4', '.avi', '.mov'}
self.current_scenes = []
self.video_count = 0

# Get orientation
self.jclient = JApiClient(logger)
orientation = self.jclient.jplayer_info.get("orientation", "LANDSCAPE")
logger.info(f"     Detected Orientation: {orientation}")
self.screen_config = su.get_screen_config(orientation)

# Initialize Pygame for image display
pygame.init()
display.init()

# Set up fullscreen display with proper orientation
display_dims = self.screen_config.get_display_dimensions()
self.screen = display.set_mode(display_dims, pygame.FULLSCREEN)
self.screen_width, self.screen_height = display_dims

# Initialize VLC
self.initialize_vlc()

logger.info("Done initializing MediaPlayer.")

def initialize_vlc(self):
"""Initialize the VLC instance and player."""
vlc_args = [
'--vout=xcb_xv',
'--no-video-title-show',
'--file-caching=2000'
]
self.vlc_instance = vlc.Instance(vlc_args)
self.vlc_player = self.vlc_instance.media_player_new()

# Tell VLC to render to the pygame window
if os.name == 'nt':  # Windows
self.vlc_player.set_hwnd(pygame.display.get_wm_info()['window'])
else:  # Linux/Raspberry Pi
self.vlc_player.set_xwindow(pygame.display.get_wm_info()['window'])

def reinitialize_vlc(self):
"""Reinitialize VLC after releasing resources to free up GPU memory."""
logger.info("Reinitializing VLC to reclaim GPU resources...")
self.vlc_player.release()
self.vlc_instance.release()
self.initialize_vlc()
self.video_count = 0  # Reset the counter after reinitialization
logger.info("VLC reinitialized successfully.")

def load_scenes(self):
"""Load and parse scene configuration files."""
scenes = []
for file in self.scenes_directory.glob('*.json'):
try:
with open(file, 'r') as f:
scene = json.load(f)
required_fields = {'id', 'media_file', 'order'}
if not all(field in scene for field in required_fields):
logger.info(f"Scene file {file} missing required fields")
continue

media_path = self.media_directory / scene['media_file']
if not media_path.exists():
logger.info(f"Media file not found: {media_path}")
continue

scene['media_path'] = media_path
scenes.append(scene)
except Exception as e:
logger.error(f"Error loading scene file {file}: {e}")
continue

return sorted(scenes, key=lambda x: x['order'])

def display_image(self, scene):
"""Display an image for the specified duration."""
try:
img = image.load(str(scene['media_path']))
img = pygame.transform.scale(img, (self.screen_width, self.screen_height))

if self.screen_config.get_pygame_rotation() != 0:
img = pygame.transform.rotate(img, self.screen_config.get_pygame_rotation())

self.screen.blit(img, (0, 0))
display.flip()

duration = int(scene.get('time_to_display', 7))
pygame_time.wait(duration * 1000)
return True
except Exception as e:
logger.info(f"Error displaying image {scene['media_path']}: {e}")
return False

def display_video(self, scene):
"""Play a video file using VLC."""
media = None
try:
# Stop any existing playback and force cleanup
if self.vlc_player.is_playing():
self.vlc_player.stop()

# Create new media instance
media = self.vlc_instance.media_new(str(scene['media_path']))
media.add_option(":no-audio")  # Disable audio processing if not needed
media.add_option(":no-metadata-network-access")  # Prevent network access
media.add_option(":no-video-title-show")  # Disable title display

# Set media and immediately check if it was successful
self.vlc_player.set_media(media)
if not self.vlc_player.get_media():
logger.info("     Failed to set media")
return False

# Attempt playback
play_result = self.vlc_player.play()
if play_result == -1:
logger.info(f"    Failed to start playback for scene {scene.get('id')}")
return False

time.sleep(1)

while self.vlc_player.is_playing():
logger.info("    video is playing")
pygame.event.pump()
time.sleep(0.25)

for event in pygame.event.get():
if event.type == pygame.QUIT:
self.vlc_player.stop()
if media:
media.release()
return False

# Explicitly stop playback
self.vlc_player.stop()

# Small delay to ensure cleanup
time.sleep(0.1)

# If we got here, the video played successfully
self.video_count += 1
if self.video_count >= VIDEO_REINIT_THRESHOLD:
self.reinitialize_vlc()

return True

except Exception as e:
logger.error(f"Error playing video {scene.get('id')}: {e}")
return False

finally:
# Aggressive cleanup
if self.vlc_player.is_playing():
self.vlc_player.stop()
# Force VLC to release GPU resources
self.vlc_player.set_media(None)
if media:
media.release()
media = None

def display_default_scene(self):
"""Display the default 'ready for content' scene."""
try:
if not self.default_image_path.exists():
logger.error(f"Default image not found at {self.default_image_path}")
return False

img = image.load(str(self.default_image_path))
img = pygame.transform.scale(img, (self.screen_width, self.screen_height))

if self.screen_config.get_pygame_rotation() != 0:
img = pygame.transform.rotate(img, self.screen_config.get_pygame_rotation())

self.screen.blit(img, (0, 0))
display.flip()
pygame_time.wait(7000)
return True
except Exception as e:
logger.error(f"Error displaying default image: {e}")
return False

def run(self):
"""Main loop to display media files."""
try:
while True:
if sufu.should_reload_scenes():
self.current_scenes = self.load_scenes()
logger.info("Reloaded scenes due to update flag")
sufu.reset_update_flag_to_zero()
elif not self.current_scenes:
self.current_scenes = self.load_scenes()
logger.info("Initial scene load")

if not self.current_scenes:
logger.info("No valid scenes found, displaying default scene")
self.display_default_scene()
time.sleep(15)
continue

logger.info("Iterating through scenes ...")
for scene in self.current_scenes:
logger.info(f"     Displaying scene {scene.get('id')} at media path {scene.get('media_path')}")
for event in pygame.event.get():
if event.type == pygame.QUIT:
return

suffix = scene['media_path'].suffix.lower()
if suffix in self.supported_images:
if not self.display_image(scene):
continue
elif suffix in self.supported_videos:
if not self.display_video(scene):
continue

finally:
self.vlc_player.release()
pygame.quit()

if __name__ == "__main__":
import argparse

parser = argparse.ArgumentParser(description='Display images and videos in a loop based on scene configurations')
parser.add_argument('media_directory', help='Directory containing media files (images and videos)')
parser.add_argument('scenes_directory', help='Directory containing scene configuration JSON files')

args = parser.parse_args()

player = MediaPlayer(args.media_directory, args.scenes_directory)
player.run()
Мы постарались очистить ресурсы настолько агрессивно, насколько это возможно. К сожалению, мы все еще наблюдаем утечку. Мы также попытались увеличить память графического процессора, но это не решило проблему.

Подробнее здесь: https://stackoverflow.com/questions/792 ... y-pi-4b-an
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»