Render to video using raw image data. Hide GUI.

Hide GUI since it changes window size, breaking the rendering process.
pull/357/head
nyanpasu64 2018-07-22 03:17:31 -07:00
rodzic 9816001f9d
commit b14d60fd75
3 zmienionych plików z 33 dodań i 27 usunięć

Wyświetl plik

@ -2,16 +2,16 @@
import shlex
import subprocess
from abc import ABC, abstractmethod
from io import BytesIO
from typing import Optional, TYPE_CHECKING, Type, Callable, TypeVar, List
from typing import TYPE_CHECKING, Type, List
from dataclasses import dataclass
if TYPE_CHECKING:
import numpy as np
from ovgenpy.ovgenpy import Config
IMAGE_FORMAT = 'png'
RGB_DEPTH = 3
class OutputConfig:
@ -27,9 +27,8 @@ class Output(ABC):
self.cfg = cfg
@abstractmethod
def output_frame_png(self, frame: bytes) -> None:
""" Output an encoded PNG file. TODO PNG compression overhead is bad """
pass
def write_frame(self, frame: 'np.ndarray') -> None:
""" Output a Numpy ndarray. """
# Glue logic
@ -49,9 +48,15 @@ FFMPEG = 'ffmpeg'
FFPLAY = 'ffplay'
def ffmpeg_input_video(fps: int) -> List[str]:
# Removed: '-c:v {IMAGE_FORMAT}' since it doesn't work
return ['-f image2pipe -framerate', str(fps), '-i -']
assert RGB_DEPTH == 3
def ffmpeg_input_video(cfg: 'Config') -> List[str]:
fps = cfg.fps
width = cfg.render.width
height = cfg.render.height
return [f'-f rawvideo -pixel_format rgb24 -video_size {width}x{height}',
f'-framerate {fps}',
'-i -']
def ffmpeg_input_audio(audio_path: str) -> List[str]:
@ -93,7 +98,7 @@ class FFmpegOutput(Output):
templates: List[str] = [FFMPEG]
# TODO factor out "get_ffmpeg_input"... what if wrong abstraction?
templates += ffmpeg_input_video(fps=ovgen_cfg.fps) # video
templates += ffmpeg_input_video(ovgen_cfg) # video
if ovgen_cfg.audio_path:
templates += ffmpeg_input_audio(audio_path=ovgen_cfg.audio_path) # audio
@ -113,7 +118,7 @@ class FFmpegOutput(Output):
# Python documentation discourages accessing popen.stdin. It's wrong.
# https://stackoverflow.com/a/9886747
def output_frame_png(self, frame: bytes) -> None:
def write_frame(self, frame: bytes) -> None:
self._stream.write(frame)
def close(self):

Wyświetl plik

@ -65,16 +65,13 @@ def main(wave_dir: str, audio_path: Optional[str], fps: int, output: str):
outputs=[
outputs.FFmpegOutputConfig(output)
],
create_window=True
create_window=False
)
ovgen = Ovgen(cfg)
ovgen.write()
COLOR_CHANNELS = 3
class Ovgen:
def __init__(self, cfg: Config):
self.cfg = cfg
@ -148,6 +145,8 @@ class Ovgen:
# Output frame
frame = renderer.get_frame()
for output in self.outputs:
output.write_frame(frame)
# TODO write to file
# how to write ndarray to ffmpeg?

Wyświetl plik

@ -1,13 +1,16 @@
from typing import Optional, List, Tuple, TYPE_CHECKING
import matplotlib
import numpy as np
from dataclasses import dataclass
from ovgenpy.outputs import RGB_DEPTH
from ovgenpy.util import ceildiv
matplotlib.use('agg')
from matplotlib import pyplot as plt
from matplotlib.backends.backend_agg import FigureCanvasAgg
from ovgenpy.outputs import IMAGE_FORMAT
from ovgenpy.util import ceildiv
if TYPE_CHECKING:
from matplotlib.axes import Axes
from matplotlib.figure import Figure
@ -167,10 +170,8 @@ class MatplotlibRenderer:
self.fig.canvas.draw()
self.fig.canvas.flush_events()
assert IMAGE_FORMAT == 'png'
RGB_DEPTH = 3
def get_frame(self):
def get_frame(self) -> np.ndarray:
""" Returns ndarray of shape w,h,3. """
canvas = self.fig.canvas
# Agg is the default noninteractive backend except on OSX.
@ -179,12 +180,13 @@ class MatplotlibRenderer:
raise RuntimeError(
f'oh shit, cannot read data from {type(canvas)} != FigureCanvasAgg')
# buffer_rgba, (w, h) = canvas.print_to_buffer()
w = self.cfg.width
h = self.cfg.height
assert (w, h) == canvas.get_width_height()
w, h = canvas.get_width_height()
buffer_rgb = np.frombuffer(canvas.tostring_rgb(), np.uint8)
print(buffer_rgb.shape)
np.reshape(buffer_rgb, (w, h, self.RGB_DEPTH))
buffer_rgb: np.ndarray = np.frombuffer(canvas.tostring_rgb(), np.uint8) # TODO Pycharm type inference error
np.reshape(buffer_rgb, (w, h, RGB_DEPTH))
assert buffer_rgb.size == w * h * RGB_DEPTH
return buffer_rgb
# # TODO https://matplotlib.org/api/_as_gen/matplotlib.pyplot.imsave.html to