Browse Source

#34 動画再生可能に

ai-migration
みてるぞ 2 weeks ago
parent
commit
37c9947d4a
1 changed files with 130 additions and 35 deletions
  1. +130
    -35
      test.py

+ 130
- 35
test.py View File

@@ -8,16 +8,19 @@ import wave
from datetime import datetime, timedelta from datetime import datetime, timedelta
from enum import Enum, auto from enum import Enum, auto
from typing import Callable, TypedDict from typing import Callable, TypedDict
from io import BytesIO


import cv2 import cv2
import emoji import emoji
import ephem import ephem
import numpy as np
import pygame import pygame
import pygame.gfxdraw import pygame.gfxdraw
import pytchat import pytchat
import requests import requests
from cv2 import VideoCapture from cv2 import VideoCapture
from ephem import Moon, Observer, Sun from ephem import Moon, Observer, Sun
from pydub import AudioSegment
from pygame import Rect, Surface from pygame import Rect, Surface
from pygame.font import Font from pygame.font import Font
from pygame.mixer import Sound from pygame.mixer import Sound
@@ -50,6 +53,7 @@ def main (
x = CWindow.WIDTH * 3 / 4, x = CWindow.WIDTH * 3 / 4,
y = CWindow.HEIGHT - 120, y = CWindow.HEIGHT - 120,
balloon = balloon) balloon = balloon)
Video (game, 'snack_time.mp4').play ()
CurrentTime (game, SYSTEM_FONT) CurrentTime (game, SYSTEM_FONT)
try: try:
broadcast = Broadcast (os.environ['BROADCAST_CODE']) broadcast = Broadcast (os.environ['BROADCAST_CODE'])
@@ -639,16 +643,6 @@ class Jojoko (GameObject):


def redraw ( def redraw (
self, self,
) -> None:
if self.frame % (FPS * 3600) == 0:
self.surface = self._get_surface ()
surface = pygame.transform.rotate (self.surface, -(90 + math.degrees (self.arg)))
surface.set_colorkey ((0, 255, 0))
self.game.screen.blit (surface, surface.get_rect (center = (self.x, self.y)))
super ().redraw ()

def update (
self,
) -> None: ) -> None:
self.moon.compute (self.game.sky.observer) self.moon.compute (self.game.sky.observer)
self.alt = self.moon.alt self.alt = self.moon.alt
@@ -657,7 +651,12 @@ class Jojoko (GameObject):
self.arg = self.new_arg self.arg = self.new_arg
self.x = self.new_x self.x = self.new_x
self.y = self.new_y self.y = self.new_y
super ().update ()
if self.frame % (FPS * 3600) == 0:
self.surface = self._get_surface ()
surface = pygame.transform.rotate (self.surface, -(90 + math.degrees (self.arg)))
surface.set_colorkey ((0, 255, 0))
self.game.screen.blit (surface, surface.get_rect (center = (self.x, self.y)))
super ().redraw ()


@property @property
def phase ( def phase (
@@ -732,30 +731,6 @@ class CWindow:
HEIGHT = 768 HEIGHT = 768




def get_surfaces_from_video (
video_path: str,
) -> list[Surface]:
cap = VideoCapture (video_path)
if not cap.isOpened ():
return []

fps = cap.get (cv2.CAP_PROP_FPS)

surfaces: list[Surface] = []
while cap.isOpened ():
(ret, frame) = cap.read ()
if not ret:
break
frame = cv2.cvtColor (frame, cv2.COLOR_BGR2RGB)
frame_surface = pygame.surfarray.make_surface (frame)
frame_surface = pygame.transform.rotate (frame_surface, -90)
surfaces.append (pygame.transform.flip (frame_surface, True, False))

cap.release ()

return surfaces


class Broadcast: class Broadcast:
chat: PytchatCore chat: PytchatCore


@@ -777,6 +752,126 @@ class Broadcast:
return random.choice (chats) return random.choice (chats)




class NicoVideo (Video):
...


class Video (GameObject):
fps: int
pausing: bool = False
sound: Sound
surfaces: list[Surface]

def __init__ (
self,
game: Game,
path: str,
):
super ().__init__ (game)
self.pausing = False
(self.surfaces, self.fps) = self._create_surfaces (path)
self.sound = self._create_sound (path)
self.stop ()

def _create_sound (
self,
path: str,
) -> Sound:
bytes_io = BytesIO ()
audio = AudioSegment.from_file (path, format = path.split ('.')[-1])
audio.export (bytes_io, format = 'wav')
bytes_io.seek (0)
return pygame.mixer.Sound (bytes_io)

def _create_surfaces (
self,
path: str,
) -> tuple[list[Surface], int]:
cap = self._load (path)
surfaces: list[Surface] = []
if cap is None:
return ([], FPS)
fps = int (cap.get (cv2.CAP_PROP_FPS))
while cap.isOpened ():
frame = self._read_frame (cap)
if frame is None:
break
surfaces.append (self._convert_to_surface (frame))
new_surfaces: list[Surface] = []
for i in range (len (surfaces) * FPS // fps):
new_surfaces.append (surfaces[i * fps // FPS])
return (new_surfaces, fps)

def _load (
self,
path: str,
) -> VideoCapture | None:
"""
OpenCV で動画を読込む.
"""
cap = VideoCapture (path)
if cap.isOpened ():
return cap
return None

def _read_frame (
self,
cap: VideoCapture,
) -> np.ndarray | None:
"""
動画のフレームを読込む.
"""
ret: bool
frame: np.ndarray
(ret, frame) = cap.read ()
if ret:
return frame
return None

def _convert_to_surface (
self,
frame: np.ndarray,
) -> Surface:
frame = cv2.cvtColor (frame, cv2.COLOR_BGR2RGB)
frame_surface = pygame.surfarray.make_surface (frame)
frame_surface = pygame.transform.rotate (frame_surface, -90)
frame_surface = pygame.transform.flip (frame_surface, True, False)
return frame_surface

def play (
self,
) -> None:
self.enabled = True
self.pausing = False
self.sound.play ()

def stop (
self,
) -> None:
self.enabled = False
self.frame = 0

def pause (
self,
) -> None:
self.pausing = True

def redraw (
self,
) -> None:
self.game.screen.blit (self.surfaces[self.frame], (self.x, self.y))
super ().redraw ()

def update (
self,
) -> None:
if self.frame >= len (self.surfaces) - 1:
self.pause ()
if self.pausing:
self.frame -= 1
super ().update ()


def fetch_bytes_from_url ( def fetch_bytes_from_url (
url: str, url: str,
) -> bytes | None: ) -> bytes | None:


Loading…
Cancel
Save