Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions arcade/experimental/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
"""
Experimental stuff. API may change.
"""
from .video_player import VideoPlayer
from .texture_render_target import RenderTargetTexture
from .shadertoy import Shadertoy, ShadertoyBuffer, ShadertoyBase
from .crt_filter import CRTFilter
from .bloom_filter import BloomFilter


__all__ = [
"VideoPlayer",
"RenderTargetTexture",
"Shadertoy",
"ShadertoyBuffer",
Expand Down
30 changes: 14 additions & 16 deletions arcade/experimental/shadertoy_video_cv2.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@
SCREEN_TITLE = "ShaderToy Video"


class ShadertoyVideo(arcade.Window):
class ShadertoyVideo(arcade.View):
"""
Can be used to add effects like rain to the background of the game.
Make sure to inherit this view and call super for `__init__`, `on_draw`, `on_update` and `on_resize`.
"""

def __init__(self, width, height, title):
super().__init__(width, height, title, resizable=True)
def __init__(self, path: str):
super().__init__()
self.shadertoy = Shadertoy(
self.get_framebuffer_size(),
self.window.get_framebuffer_size(),
"""
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
Expand All @@ -37,18 +41,17 @@ def __init__(self, width, height, title):
}
""",
)
# INSERT YOUR OWN VIDEO HERE
self.video = cv2.VideoCapture("C:/Users/efors/Desktop/BigBuckBunny.mp4")
self.video = cv2.VideoCapture(str(arcade.resources.resolve_resource_path(path)))
width, height = (
int(self.video.get(cv2.CAP_PROP_FRAME_WIDTH)),
int(self.video.get(cv2.CAP_PROP_FRAME_HEIGHT)),
)
self.video_texture = self.ctx.texture((width, height), components=3)
self.video_texture.wrap_x = self.ctx.CLAMP_TO_EDGE
self.video_texture.wrap_y = self.ctx.CLAMP_TO_EDGE
self.video_texture = self.window.ctx.texture((width, height), components=3)
self.video_texture.wrap_x = self.window.ctx.CLAMP_TO_EDGE
self.video_texture.wrap_y = self.window.ctx.CLAMP_TO_EDGE
self.video_texture.swizzle = "BGR1"
self.shadertoy.channel_0 = self.video_texture
self.set_size(width, height)
self.window.set_size(width, height)

def on_draw(self):
self.clear()
Expand All @@ -60,15 +63,10 @@ def on_update(self, delta_time: float):

def on_resize(self, width: int, height: int):
super().on_resize(width, height)
self.shadertoy.resize(self.get_framebuffer_size())
self.shadertoy.resize(self.window.get_framebuffer_size())

def next_frame(self):
exists, frame = self.video.read()
frame = cv2.flip(frame, 0)
if exists:
self.video_texture.write(frame)


if __name__ == "__main__":
ShadertoyVideo(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
arcade.run()
73 changes: 58 additions & 15 deletions arcade/experimental/video_cv2.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,26 @@
pip install opencv-python
"""
from math import floor
from pathlib import Path
from typing import Union

import arcade
from arcade.gl.geometry import quad_2d_fs
import cv2 # type: ignore


class CV2Player(arcade.Window):
class VideoPlayerCV2:
"""
Primitive video player for arcade with cv2.
Renders to the entire screen. Use VideoPlayer to render to specific coordinate.

:param path: Path of the video that is to be played.
"""

def __init__(self, path: Union[str, Path]):

self.ctx = arcade.get_window().ctx

def __init__(self):
super().__init__(800, 600, "OpenCV Video Player", resizable=True)
self.quad_fs = quad_2d_fs()
self.program = self.ctx.program(
vertex_shader="""
Expand All @@ -44,40 +55,51 @@ def __init__(self):
}
""",
)

# Configure videoFrame sampler to read from texture channel 0
self.program["videoFrame"] = 0

# Open the video (can also read from webcam)
self.video = cv2.VideoCapture("C:/Users/efors/Desktop/BigBuckBunny.mp4")
self.video = cv2.VideoCapture(str(arcade.resources.resolve_resource_path(path)))

# Query video size
width, height = (
self._width, self._height = (
int(self.video.get(cv2.CAP_PROP_FRAME_WIDTH)),
int(self.video.get(cv2.CAP_PROP_FRAME_HEIGHT)),
)

# Get the framerate of the video
self.video_frame_rate = self.video.get(cv2.CAP_PROP_FPS)
# Keep track of the current frame and current time
# to estimate a reasonable playback speed
self.current_frame = 0
self.time = 0
self.time: float = 0.0

# Create and configure the OpenGL texture for the video
self.texture = self.ctx.texture((width, height), components=3)
self.texture = self.ctx.texture((self._width, self._height), components=3)
# Swap the components in the texture because cv2 returns BGR data
# Leave the alpha component as always 1
self.texture.swizzle = "BGR1"
# Change the window size to the video size
self.set_size(width, height)

def on_draw(self):
self.clear()
@property
def width(self):
"""Video width."""
return self._width

@property
def height(self):
"""Video height."""
return self._height

def draw(self):
"""Call this in `on_draw`."""

# Bind video texture to texture channel 0
# Bind video texture to texture channel 0
self.texture.use(unit=0)
# Draw a fullscreen quad using our texture program
self.quad_fs.render(self.program)

def on_update(self, delta_time: float):
def update(self, delta_time):
"""Move the frame forward."""
self.time += delta_time

# Do we need to read a new frame?
Expand All @@ -90,4 +112,25 @@ def on_update(self, delta_time: float):
self.texture.write(frame)


CV2Player().run()
class CV2PlayerView(arcade.View):
def __init__(self, path: str):
super().__init__()

self.video_player = VideoPlayerCV2(path)

# Change the window size to the video size
self.window.set_size(self.video_player.width, self.video_player.height)

def on_draw(self):
self.clear()

self.video_player.draw()

def on_update(self, delta_time: float):
self.video_player.update(delta_time)


if __name__ == '__main__':
window = arcade.Window(800, 600, "Video Player")
window.show_view(CV2PlayerView("/home/ibrahim/PycharmProjects/pyweek/35/Tetris-in-Ohio/assets/rain.mp4"))
window.run()
68 changes: 53 additions & 15 deletions arcade/experimental/video_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,63 @@
This requires that you have ffmpeg installed
and you might need to tell pyglet where it's located.
"""
from pathlib import Path
from typing import Optional, Tuple, Union

# import sys
import pyglet
import arcade


class VideoPlayer(arcade.Window):
class VideoPlayer:
"""
Primitive video player for arcade.

def __init__(self) -> None:
super().__init__(800, 600, "Video Player", resizable=True)
:param path: Path of the video that is to be played.
:param loop: Pass `True` to make the video loop.
"""

def __init__(self, path: Union[str, Path], loop=False):
self.player = pyglet.media.Player()
# self.player.queue(pyglet.media.load("C:/Users/efors/Desktop/file_example_MP4_480_1_5MG.mp4"))
self.player.queue(pyglet.media.load("C:/Users/efors/Desktop/BigBuckBunny.mp4"))
self.player.loop = loop
self.player.queue(pyglet.media.load(str(arcade.resources.resolve_resource_path(path))))
self.player.play()

def on_draw(self):
self.clear()
# video_width, video_height = self.get_video_size()
# print((video_width, video_height), self.player.source.duration, self.player.time)
self.ctx = arcade.get_window().ctx

self._width = arcade.get_window().width
self._height = arcade.get_window().height

def draw(self, left: int = 0, bottom: int = 0, size: Optional[Tuple[int, int]] = None):
"""
Call this in `on_draw`.

:param size: Pass None as one of the elements if you want to use the dimension(width, height) attribute.
"""
if size and len(size) == 2:
self._width = size[0] or self.width
self._height = size[1] or self.height

with self.ctx.pyglet_rendering():
self.ctx.disable(self.ctx.BLEND)
video_texture = self.player.texture
if video_texture:
video_texture.blit(
0,
0,
left,
bottom,
width=self.width,
height=self.height,
)

def on_update(self, delta_time: float):
pass
@property
def width(self):
"""Video width."""
return self._width

@property
def height(self):
"""Video height."""
return self._height

def get_video_size(self):
if not self.player.source or not self.player.source.video_format:
Expand All @@ -51,5 +75,19 @@ def get_video_size(self):
return width, height


window = VideoPlayer()
arcade.run()
class VideoPlayerView(arcade.View):
def __init__(self, path) -> None:
super().__init__()

self.video_player = VideoPlayer(path)

def on_draw(self):
self.clear()

self.video_player.draw()


if __name__ == '__main__':
window = arcade.Window(800, 600, "Video Player")
window.show_view(VideoPlayerView("/home/ibrahim/PycharmProjects/pyweek/35/Tetris-in-Ohio/assets/rain.mp4"))
window.run()