目前如何在 Pygame 中播放视频? [英] How to play video in Pygame currently?

查看:196
本文介绍了目前如何在 Pygame 中播放视频?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望在我的游戏中添加视频(例如过场动画或动画菜单屏幕).

我环顾四周,似乎 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆