How to Load and Play a Video in Pygame

How to load and play a video in pygame

You are not actually blitting it to a screen. You are also not utilizing a clock object so it will play as fast as possible. Try this:

# http://www.fileformat.info/format/mpeg/sample/index.dir
import pygame

FPS = 60

pygame.init()
clock = pygame.time.Clock()
movie = pygame.movie.Movie('MELT.MPG')
screen = pygame.display.set_mode(movie.get_size())
movie_screen = pygame.Surface(movie.get_size()).convert()

movie.set_display(movie_screen)
movie.play()

playing = True
while playing:
for event in pygame.event.get():
if event.type == pygame.QUIT:
movie.stop()
playing = False

screen.blit(movie_screen,(0,0))
pygame.display.update()
clock.tick(FPS)

pygame.quit()

I just got that MELT.MPG from the link provided in the comment. You should be able to simply switch out that string for your actual MPG you want to play and it will work... maybe.

How to play video in Pygame currently?

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.

example output

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.

How do you play videos in pygame 1.9.5 on windows 10

PyGame 1.9.5 doesn't have module to dispaly movie (at least not in documentation) maybe because it was incomplet and they try to convert code from library SDL 1.2 to SDL 2.0 which doesn't have module for movie.

You can try to use cv2 with pygame

This code display directly on screen from any stream (built-in camera, local file, remove stream). Window must have the same size as the stream. I don't know why but I had to transpose image before displaying.

import pygame
import cv2

# --- local (built-in) camera ---
#stream = 0

# --- local file ---
#stream = '2019-03-26_08-43-15.mkv'

# --- http stream ---
# doesn't work any more
#stream = 'http://media.dumpert.nl/tablet/9f7c6290_Verstappen_vs._Rosberg_with_Horner_Smile___Streamable.mp4.mp4.mp4'

# --- rtsp stream ---
#stream = 'rtsp://streaming1.osu.edu/media2/ufsap/ufsap.mov'

# --- rtmp stream ---
# Big Buck Bunny
stream = 'rtmp://184.72.239.149/vod/mp4:bigbuckbunny_1500.mp4'

# open stream
cap = cv2.VideoCapture(stream)

# read one frame and check if there was no problem
ret, img = cap.read()
if not ret:
print("Can't read stream")
#exit()

# transpose/rotate frame
#img = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
img = cv2.transpose(img)

# display its width, height, color_depth
print('shape:', img.shape)

pygame.init()

# create window with the same size as frame
screen = pygame.display.set_mode((img.shape[0], img.shape[1]))

running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False

# read one frame and check if there was no problem
ret, img = cap.read()
if not ret:
running = False
break
else:
# transpose/rotate frame
#img = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
#img = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
img = cv2.transpose(img)

# blit directly on screen
pygame.surfarray.blit_array(screen, img)

pygame.display.flip()

pygame.quit()

This code use Surface to get frame from stream so window may have different size.

import pygame
import cv2

# --- local (built-in) camera ---
#stream = 0

# --- local file ---
#stream = '2019-03-26_08-43-15.mkv'

# --- http stream ---
# doesn't work any more
#stream = 'http://media.dumpert.nl/tablet/9f7c6290_Verstappen_vs._Rosberg_with_Horner_Smile___Streamable.mp4.mp4.mp4'

# --- rtsp stream ---
#stream = 'rtsp://streaming1.osu.edu/media2/ufsap/ufsap.mov'

# --- rtmp stream ---
# Big Buck Bunny
stream = 'rtmp://184.72.239.149/vod/mp4:bigbuckbunny_1500.mp4'

cap = cv2.VideoCapture(stream)

ret, img = cap.read()
if not ret:
print("Can't read stream")
#exit()

#img = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
img = cv2.transpose(img)
print('shape:', img.shape)

pygame.init()

screen = pygame.display.set_mode((800, 600))
surface = pygame.surface.Surface((img.shape[0], img.shape[1]))

running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False

ret, img = cap.read()
if not ret:
running = False
break
else:
#img = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
#img = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
img = cv2.transpose(img)

pygame.surfarray.blit_array(surface, img)
screen.blit(surface, (0,0))

pygame.display.flip()

pygame.quit()

Playing Videos in PyGame 2

Edit, 2021-11-09: - My answer below will get the job done, but there is a more idiomatic answer (ie., less of a hack) here


Thanks to the folks over at the pygame discord and this example of using FFMPEG with a subprocess, I have a working solution. Hopefully this will help someone out in the future.

import pygame
from lib.constants import SCREEN_WIDTH, SCREEN_HEIGHT
from viewcontrollers.Base import BaseView
import subprocess as sp

FFMPEG_BIN = "ffmpeg"
BYTES_PER_FRAME = SCREEN_WIDTH * SCREEN_HEIGHT * 3

class AnimationFullScreenView(BaseView):

def __init__(self):
super(AnimationFullScreenView, self).__init__()

command = [
FFMPEG_BIN,
'-loglevel', 'quiet',
'-i', 'animations/__BasicBoot.mp4',
'-f', 'image2pipe',
'-pix_fmt', 'rgb24',
'-vcodec', 'rawvideo', '-'
]
self.proc = sp.Popen(command, stdout = sp.PIPE, bufsize=BYTES_PER_FRAME*2)

# draw() will be run once per frame
def draw(self):
raw_image = self.proc.stdout.read(BYTES_PER_FRAME)
image = pygame.image.frombuffer(raw_image, (SCREEN_WIDTH, SCREEN_HEIGHT), 'RGB')
self.proc.stdout.flush()
self.surf.blit(image, (0, 0))

How to load and play a video in pygame

You are not actually blitting it to a screen. You are also not utilizing a clock object so it will play as fast as possible. Try this:

# http://www.fileformat.info/format/mpeg/sample/index.dir
import pygame

FPS = 60

pygame.init()
clock = pygame.time.Clock()
movie = pygame.movie.Movie('MELT.MPG')
screen = pygame.display.set_mode(movie.get_size())
movie_screen = pygame.Surface(movie.get_size()).convert()

movie.set_display(movie_screen)
movie.play()

playing = True
while playing:
for event in pygame.event.get():
if event.type == pygame.QUIT:
movie.stop()
playing = False

screen.blit(movie_screen,(0,0))
pygame.display.update()
clock.tick(FPS)

pygame.quit()

I just got that MELT.MPG from the link provided in the comment. You should be able to simply switch out that string for your actual MPG you want to play and it will work... maybe.

How can I play a mp4 movie using Moviepy and Pygame

First: you can use

import moviepy

print(moviepy.__file__)

to find source code and see how it works.


After searching in source code you will see that it uses pygame to display it and you can try to use pygame function set_caption() to change title.

from moviepy.editor import *
import pygame

pygame.display.set_caption('Hello World!')

clip = VideoFileClip('video.mp4')
clip.preview()

pygame.quit()


Related Topics



Leave a reply



Submit