George David King
George David King

Reputation: 221

How to load and play a video in pygame

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

Answers (5)

nstbayless
nstbayless

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

0asa
0asa

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

Rabbid76
Rabbid76

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

Red
Red

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

Brandon
Brandon

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

Related Questions