Reputation: 221
I'm having a problem. I want to load and play a video in pygame but it doesn't start. The only thing that I am seeing is a black screen. Here is my code:
import pygame
from pygame import display,movie
pygame.init()
screen = pygame.display.set_mode((1024, 768))
background = pygame.Surface((1024, 768))
screen.blit(background, (0, 0))
pygame.display.update()
movie = pygame.movie.Movie('C:\Python27\1.mpg')
mrect = pygame.Rect(0,0,140,113)
movie.set_display(screen, mrect.move(65, 150))
movie.set_volume(0)
movie.play()
Can you help me??
Upvotes: 17
Views: 64640
Reputation: 185
There's actually a way to do this with moviepy
. Here's a demo that displays a video in a pygame surface:
import pygame
from moviepy.editor import VideoFileClip
# Initialize Pygame
pygame.init()
# Load the video clip
clip = VideoFileClip("video.mp4") # (or .webm, .avi, etc.)
def getSurface(t, srf=None):
frame = clip.get_frame(t=t) # t is the time in seconds
if srf is None:
# Transpose the array and create the Pygame surface
return pygame.surfarray.make_surface(frame.swapaxes(0, 1))
else:
pygame.surfarray.blit_array(srf, frame.swapaxes(0, 1))
return srf
surface = getSurface(0)
screen = pygame.display.set_mode(surface.get_size(), 0, 32)
# Run the Pygame loop to keep the window open
running = True
t = 0
while running:
# Draw the surface onto the window
screen.blit(getSurface(t, surface), (0, 0))
pygame.display.flip()
t += 1/60 # use actual fps here
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Quit Pygame
pygame.quit()
You can also extract audio from moviepy and play it separately alongside the video, but I don't have a working demo.
Upvotes: 1
Reputation: 224
Here is another way to do it. Leverage ffmpeg with the convenient ffmpeg-python wrapper.
import ffmpeg
import pygame
import sys
import numpy as np
input_file = "input.mp4"
probe = ffmpeg.probe(input_file)
video_info = next(s for s in probe['streams'] if s['codec_type'] == 'video')
width = int(video_info['width'])
height = int(video_info['height'])
process = (
ffmpeg
.input(input_file)
.output("pipe:", format="rawvideo", pix_fmt="rgb24")
.run_async(pipe_stdout=True)
)
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((width, height))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
in_bytes = process.stdout.read(width * height * 3)
if not in_bytes:
break
in_frame = (
np.frombuffer(in_bytes, dtype="uint8")
.reshape([height, width, 3])
)
out_frame = pygame.surfarray.make_surface(np.transpose(in_frame, (1, 0, 2)))
screen.blit(out_frame, (0, 0))
pygame.display.flip()
clock.tick(60)
process.wait()
pygame.quit()
Upvotes: 1
Reputation: 211220
The pygame.movie
module is deprecated and not longer supported.
If you only want to show the video you can use MoviePy (see also How to be efficient with MoviePy):
import pygame
import moviepy.editor
pygame.init()
video = moviepy.editor.VideoFileClip("video.mp4")
video.preview()
pygame.quit()
An alternative solution is to use the OpenCV VideoCapture
. Install OpenCV for Python (cv2) (see opencv-python). However, it should be mentioned that cv2.VideoCapture
does not provide a way to read the audio from the video file.
This is only a solution to show the video but no audio is played.
Opens a camera for video capturing:
video = cv2.VideoCapture("video.mp4")
Get the frames per second form the VideoCapture
object:
fps = video.get(cv2.CAP_PROP_FPS)
Create a pygame.time.Clock
:
clock = pygame.time.Clock()
Grabs a video frame and limit the frames per second in the application loop:
clock.tick(fps)
success, video_image = video.read()
Convert the camera frame to a pygame.Surface
object using pygame.image.frombuffer
:
video_surf = pygame.image.frombuffer(video_image.tobytes(), video_image.shape[1::-1], "BGR")
See also Video:
Minimal example:
import pygame
import cv2
video = cv2.VideoCapture("video.mp4")
success, video_image = video.read()
fps = video.get(cv2.CAP_PROP_FPS)
window = pygame.display.set_mode(video_image.shape[1::-1])
clock = pygame.time.Clock()
run = success
while run:
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
success, video_image = video.read()
if success:
video_surf = pygame.image.frombuffer(
video_image.tobytes(), video_image.shape[1::-1], "BGR")
else:
run = False
window.blit(video_surf, (0, 0))
pygame.display.flip()
pygame.quit()
exit()
Upvotes: 17
Reputation: 27577
As you probably know, the pygame.movie
module is deprecated and no longer exists in the latest version of pygame.
An alternative would be to read in frames of the video one by one and blit them onto the pygame screen using the the cv2
module (OpenCV), that can be installed with the command prompt command:
pip install opencv-python
Then, you can run the code:
import cv2
import pygame
cap = cv2.VideoCapture('video.mp4')
success, img = cap.read()
shape = img.shape[1::-1]
wn = pygame.display.set_mode(shape)
clock = pygame.time.Clock()
while success:
clock.tick(60)
success, img = cap.read()
for event in pygame.event.get():
if event.type == pygame.QUIT:
success = False
wn.blit(pygame.image.frombuffer(img.tobytes(), shape, "BGR"), (0, 0))
pygame.display.update()
pygame.quit()
Upvotes: 7
Reputation: 106
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.
Upvotes: 9