Search code examples
pythonaudiovideopygame

Trouble making a Simple video renderer with the python module Pygame


I need some help creating a video renderer in Pygame. It has a 48x36 display and has 3 colours. Black, white and grey. The data that goes into the project is in the form of a .txt file and each frame of the video in a line(as an example my video uses 6567 frames so there are 6567 lines in the text file). To render the frames I am using the rectangle function.

pygame.draw.rect(canvas, rect_color, pygame.Rect(30,30,60,60))

(By the way in the .txt file 0=black, 1=white and 2=grey)

After finally making a window pop up it stayed a rather boring black color...

After finally making a window pop up it stayed a rather boring black color... If you could give any help it would be greatly needed!

(The code is messy i know)

import time
from datetime import datetime
import pygame
file= open(r"C:\Users\User\Downloads\video Data.txt","r")
lines = file.readlines()
current_l = 1
start_time = time.perf_counter()
pygame.init()
surface = pygame.display.set_mode((480,360))
color = (150,75,75)
def start_vid():
    current_l = 1
    for frame in range(1, 6572):
        xpos = 0
        ypos = 0
        now = datetime.now()
        count = 0
        seconds = now.second
        frame_data = lines[current_l]
        current = frame_data[count]
        for y in range(0, 36):
            for x in range(0, 48):
                if current == '0':
                    pygame.draw.rect(surface, (0,   0, 255),[xpos, xpos+10, ypos, ypos+10], 0)
                elif current == '1':
                    pygame.draw.rect(surface, (255,   255, 255),[xpos, ypos, xpos, ypos], 0)
                else:
                    pygame.draw.rect(surface, (130,   130, 130),[xpos, ypos, xpos, ypos], 0)
                #print(current)
                #pygame.display.update()
                xpos = xpos + 10
                current = frame_data[count]
                count = count + 1
                timer = round(abs((start_time - time.perf_counter())), 1)
                current_l = seconds*30
                current_l = int(timer*30)
            ypos = ypos + -10
        print(current_l)
        
        pygame.display.update()

start_vid()

Solution

  • The reason why you can't see anything is because in Pygame, the origin (0, 0) of the screen is in the top left. The right side of the screen is where the x increases, and the bottom is where the y increases. So, the line:

    ypos = ypos + -10
    

    draws everything "above" the screen, hence invisible. You need to remove the - sign.


    I also saw a couple of things in your code that could be improved, such as:

    • The fact that you never close the data file. To do that automatically, you could use the with statement:
    with open('video.txt') as file:
        lines = file.readlines()
    # the file is closed
    

    This will allow other applications to access the file.

    • You are drawing empty rects

    You are using the pygame.draw.rect method incorrectly. You should use rect objects like such:

    rect = pygame.Rect(x, y, width, height)
    pygame.draw.rect(surface, color, rect)
    
    • You don't need the time and datetime modules, Pygame handles time like this. For example:
    framerate = 30
    start = pygame.time.get_ticks()
    
    ... # main loop
        current_frame = int((pygame.time.get_ticks()-start) / 1000 * framerate)
    

    And, most importantly

    In Pygame, you need a main loop with events handling:

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

    A correct implementation of your code could look like this:

    import pygame
    
    with open('video.txt') as file:
        lines = file.readlines()
    
    pygame.init()
    surface = pygame.display.set_mode((480,360))
    framerate = 30
    start = pygame.time.get_ticks()
    
    run = True
    while run:
        # get pygame events
        for event in pygame.event.get():
            if event.type == pygame.QUIT: # user closes the window
                run = False
    
        current_frame = int((pygame.time.get_ticks()-start) / 1000 * framerate)
        if current_frame < len(lines): # is the video still running?
            count = 0
            for y in range(36):
                for x in range(48):
                    current_pixel = lines[current_frame][count] # current pixel data
                    if current_pixel == '0':
                        color = (0, 0, 0)
                    elif current_pixel == '1':
                        color = (127, 127, 127)
                    else:
                        color = (255, 255, 255)
                    pygame.draw.rect(surface, color, pygame.Rect(x*10, y*10, 10, 10))
                    count += 1 # next pixel
    
        pygame.display.flip()
    
    # user closed the window
    pygame.quit()
    quit()
    

    (In this example, you can reduce the amount of resources used since you know the framerate of the video using pygame.time.Clock)