当前如何播放Pygame中的视频?
How to play video in Pygame currently?
我希望在我的游戏中添加视频(例如过场动画或动画菜单屏幕)。
我看了看,好像pygame不支持视频播放了,所以我想知道是否有其他方法可以播放视频,同时很好地集成到我的游戏中,比如在后台播放视频,在前台播放 pygame 个元素(开始按钮等)。
某处有一个示例(我无法找到原始 link)使用 FFMPEG 和另一个 python 模块通过管道解码帧并将它们读入PyGame 用于显示。我复制了一个代码片段(我从 SO 想到的),然后忘了它。
我现在已经采用该技术制作 VideoSprite
。它使用 FFMPEG 解码(并重新缩放)视频流,在精灵 update()
期间读取视频流以获取下一帧。
这是一个非常粗略的实现,但我希望它能让您了解什么是可能的。虽然如果 PyGame 自己播放视频会很好,但至少这种方法将视频解码和重新缩放交给一个子进程,希望 运行 在另一个 CPU 上进行.
(编辑:添加了视频结束处理程序和适当的 FPS 控制)
import pygame
import subprocess
# Window size
WINDOW_WIDTH = 600
WINDOW_HEIGHT = 400
WINDOW_SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
DARK_BLUE = ( 3, 5, 54)
### initialisation
pygame.init()
pygame.mixer.init()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), WINDOW_SURFACE )
pygame.display.set_caption("Video Sprite")
class VideoSprite( pygame.sprite.Sprite ):
FFMPEG_BIN = "/usr/bin/ffmpeg" # Full path to ffmpeg executable
def __init__(self, rect, filename, FPS=25 ):
pygame.sprite.Sprite.__init__(self)
command = [ self.FFMPEG_BIN,
'-loglevel', 'quiet',
'-i', filename,
'-f', 'image2pipe',
'-s', '%dx%d' % (rect.width, rect.height),
'-pix_fmt', 'rgb24',
'-vcodec', 'rawvideo', '-' ]
self.bytes_per_frame = rect.width * rect.height * 3
self.proc = subprocess.Popen( command, stdout=subprocess.PIPE, bufsize=self.bytes_per_frame*3 )
self.image = pygame.Surface( ( rect.width, rect.height ), pygame.HWSURFACE )
self.rect = self.image.get_rect()
self.rect.x = rect.x
self.rect.y = rect.y
# Used to maintain frame-rate
self.last_at = 0 # time frame starts to show
self.frame_delay = 1000 / FPS # milliseconds duration to show frame
self.video_stop = False
def update( self ):
if ( not self.video_stop ):
time_now = pygame.time.get_ticks()
if ( time_now > self.last_at + self.frame_delay ): # has the frame shown for long enough
self.last_at = time_now
try:
raw_image = self.proc.stdout.read( self.bytes_per_frame )
self.image = pygame.image.frombuffer(raw_image, (self.rect.width, self.rect.height), 'RGB')
#self.proc.stdout.flush() - doesn't seem to be necessary
except:
# error getting data, end of file? Black Screen it
self.image = pygame.Surface( ( self.rect.width, self.rect.height ), pygame.HWSURFACE )
self.image.fill( ( 0,0,0 ) )
self.video_stop = True
### Create Video Area
video_sprite1 = VideoSprite( pygame.Rect( 100, 100, 320, 240 ), '1975_test_pattern.mp4' )
video_sprite2 = VideoSprite( pygame.Rect( 100, 100, 160, 90 ), '/home/kingsley/Videos/rocket.avi' ) # 640x360
#sprite_group = pygame.sprite.GroupSingle()
sprite_group = pygame.sprite.Group()
sprite_group.add( video_sprite1 )
sprite_group.add( video_sprite2 )
### Main Loop
clock = pygame.time.Clock()
done = False
while not done:
# Handle user-input
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
elif ( event.type == pygame.MOUSEBUTTONUP ):
# On mouse-click
pass
# Movement keys
keys = pygame.key.get_pressed()
if ( keys[pygame.K_UP] ):
video_sprite2.rect.y -= 10
if ( keys[pygame.K_DOWN] ):
video_sprite2.rect.y += 10
if ( keys[pygame.K_LEFT] ):
video_sprite2.rect.x -= 10
if ( keys[pygame.K_RIGHT] ):
video_sprite2.rect.x += 10
# Update the window, but not more than 60fps
sprite_group.update()
window.fill( DARK_BLUE )
sprite_group.draw( window )
pygame.display.flip()
# Clamp FPS
clock.tick_busy_loop(25) # matching my video file
pygame.quit()
很明显,因为它只是视频流,所以没有声音。但就所有意图和目的而言,它只是另一个精灵。当视频 运行 出来时,我们发现错误并变黑。
注意:有时 当我 运行 这样做时,它会中断 Linux 中的终端回显。我怀疑这与子进程 and/or 管道有关。 运行 reset
解决了这个问题。这似乎是子流程的常见问题。
我写了一段代码,似乎与 moviepy 配合得很好,我的灵感来自 Kingsley。
import moviepy.editor
import moviepy.video.fx.all
import pygame
class VideoSprite(pygame.sprite.Sprite):
def __init__(self, rect, filename):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((rect.width, rect.height), pygame.HWSURFACE)
self.rect = self.image.get_rect()
self.rect.x = rect.x
self.rect.y = rect.y
self.video = moviepy.editor.VideoFileClip(filename).resize((self.rect.width, self.rect.height))
self.video_stop = False
def update(self, time=pygame.time.get_ticks()):
if not self.video_stop:
try:
raw_image = self.video.get_frame(time / 1000) # /1000 for time in s
self.image = pygame.image.frombuffer(raw_image, (self.rect.width, self.rect.height), 'RGB')
except:
self.video_stop = True
这里的优点是视频速度合适
我希望在我的游戏中添加视频(例如过场动画或动画菜单屏幕)。
我看了看,好像pygame不支持视频播放了,所以我想知道是否有其他方法可以播放视频,同时很好地集成到我的游戏中,比如在后台播放视频,在前台播放 pygame 个元素(开始按钮等)。
某处有一个示例(我无法找到原始 link)使用 FFMPEG 和另一个 python 模块通过管道解码帧并将它们读入PyGame 用于显示。我复制了一个代码片段(我从 SO 想到的),然后忘了它。
我现在已经采用该技术制作 VideoSprite
。它使用 FFMPEG 解码(并重新缩放)视频流,在精灵 update()
期间读取视频流以获取下一帧。
这是一个非常粗略的实现,但我希望它能让您了解什么是可能的。虽然如果 PyGame 自己播放视频会很好,但至少这种方法将视频解码和重新缩放交给一个子进程,希望 运行 在另一个 CPU 上进行.
(编辑:添加了视频结束处理程序和适当的 FPS 控制)
import pygame
import subprocess
# Window size
WINDOW_WIDTH = 600
WINDOW_HEIGHT = 400
WINDOW_SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
DARK_BLUE = ( 3, 5, 54)
### initialisation
pygame.init()
pygame.mixer.init()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), WINDOW_SURFACE )
pygame.display.set_caption("Video Sprite")
class VideoSprite( pygame.sprite.Sprite ):
FFMPEG_BIN = "/usr/bin/ffmpeg" # Full path to ffmpeg executable
def __init__(self, rect, filename, FPS=25 ):
pygame.sprite.Sprite.__init__(self)
command = [ self.FFMPEG_BIN,
'-loglevel', 'quiet',
'-i', filename,
'-f', 'image2pipe',
'-s', '%dx%d' % (rect.width, rect.height),
'-pix_fmt', 'rgb24',
'-vcodec', 'rawvideo', '-' ]
self.bytes_per_frame = rect.width * rect.height * 3
self.proc = subprocess.Popen( command, stdout=subprocess.PIPE, bufsize=self.bytes_per_frame*3 )
self.image = pygame.Surface( ( rect.width, rect.height ), pygame.HWSURFACE )
self.rect = self.image.get_rect()
self.rect.x = rect.x
self.rect.y = rect.y
# Used to maintain frame-rate
self.last_at = 0 # time frame starts to show
self.frame_delay = 1000 / FPS # milliseconds duration to show frame
self.video_stop = False
def update( self ):
if ( not self.video_stop ):
time_now = pygame.time.get_ticks()
if ( time_now > self.last_at + self.frame_delay ): # has the frame shown for long enough
self.last_at = time_now
try:
raw_image = self.proc.stdout.read( self.bytes_per_frame )
self.image = pygame.image.frombuffer(raw_image, (self.rect.width, self.rect.height), 'RGB')
#self.proc.stdout.flush() - doesn't seem to be necessary
except:
# error getting data, end of file? Black Screen it
self.image = pygame.Surface( ( self.rect.width, self.rect.height ), pygame.HWSURFACE )
self.image.fill( ( 0,0,0 ) )
self.video_stop = True
### Create Video Area
video_sprite1 = VideoSprite( pygame.Rect( 100, 100, 320, 240 ), '1975_test_pattern.mp4' )
video_sprite2 = VideoSprite( pygame.Rect( 100, 100, 160, 90 ), '/home/kingsley/Videos/rocket.avi' ) # 640x360
#sprite_group = pygame.sprite.GroupSingle()
sprite_group = pygame.sprite.Group()
sprite_group.add( video_sprite1 )
sprite_group.add( video_sprite2 )
### Main Loop
clock = pygame.time.Clock()
done = False
while not done:
# Handle user-input
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
elif ( event.type == pygame.MOUSEBUTTONUP ):
# On mouse-click
pass
# Movement keys
keys = pygame.key.get_pressed()
if ( keys[pygame.K_UP] ):
video_sprite2.rect.y -= 10
if ( keys[pygame.K_DOWN] ):
video_sprite2.rect.y += 10
if ( keys[pygame.K_LEFT] ):
video_sprite2.rect.x -= 10
if ( keys[pygame.K_RIGHT] ):
video_sprite2.rect.x += 10
# Update the window, but not more than 60fps
sprite_group.update()
window.fill( DARK_BLUE )
sprite_group.draw( window )
pygame.display.flip()
# Clamp FPS
clock.tick_busy_loop(25) # matching my video file
pygame.quit()
很明显,因为它只是视频流,所以没有声音。但就所有意图和目的而言,它只是另一个精灵。当视频 运行 出来时,我们发现错误并变黑。
注意:有时 当我 运行 这样做时,它会中断 Linux 中的终端回显。我怀疑这与子进程 and/or 管道有关。 运行 reset
解决了这个问题。这似乎是子流程的常见问题。
我写了一段代码,似乎与 moviepy 配合得很好,我的灵感来自 Kingsley。
import moviepy.editor
import moviepy.video.fx.all
import pygame
class VideoSprite(pygame.sprite.Sprite):
def __init__(self, rect, filename):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((rect.width, rect.height), pygame.HWSURFACE)
self.rect = self.image.get_rect()
self.rect.x = rect.x
self.rect.y = rect.y
self.video = moviepy.editor.VideoFileClip(filename).resize((self.rect.width, self.rect.height))
self.video_stop = False
def update(self, time=pygame.time.get_ticks()):
if not self.video_stop:
try:
raw_image = self.video.get_frame(time / 1000) # /1000 for time in s
self.image = pygame.image.frombuffer(raw_image, (self.rect.width, self.rect.height), 'RGB')
except:
self.video_stop = True
这里的优点是视频速度合适