目前如何在 Pygame 中播放视频? [英] How to play video in Pygame currently?
问题描述
我希望在我的游戏中添加视频(例如过场动画或动画菜单屏幕).
我环顾四周,似乎 pygame 不再支持视频播放了,所以我想知道是否有另一种方法可以在很好地集成到我的游戏中的同时播放视频,例如在我的游戏中播放视频背景并在前景中有 pygame 元素(开始按钮等).
某处有一个使用
注意:有时当我运行它时,它会中断 Linux 中的终端回显.我怀疑这与子流程和/或管道有关.运行 reset
修复了这个问题.这似乎是子流程的常见问题.
I am looking to add videos in my game (such as cut scenes or an animated menu screen).
I looked around for a bit and it seems pygame doesn't support video playing anymore, so I was wondering if there was another way to get videos playing while being well integrated in my game, such as having the video playing in the background and having pygame elements (start button etc.) in the foreground.
There's an example somewhere (I was unable to find an original link) of using FFMPEG and another python module to decode the frames via a pipe and read these through into PyGame for displaying. I copied a code snippet (I thought from SO), and forgot about it.
I have now adapted that technique to make a VideoSprite
. It uses FFMPEG to decode (and rescale) the video stream, where it's read during the sprites update()
to get the next frame.
This is a very rough implementation, but I hope it gives you an idea of what's possible. While it would be nice if PyGame would just play the videos on its own, at least this method hands the video decoding and rescaling off to a subprocess where it hopefully runs on another CPU.
(EDIT: added handler for video ending, and proper FPS control)
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()
Obviously, since it's just the video stream, there's no sound. But for all intents and purposes it's just another sprite. When the video runs out we catch the error and go black.
NOTE: Sometimes when I run this, it breaks the terminal echoing in Linux. I suspect it's something to do with the subprocess and/or pipe. Running reset
fixes this. It seems a common problem with subprocesses.
这篇关于目前如何在 Pygame 中播放视频?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!