Source code for toyplot.mp4

# Copyright 2014, Sandia Corporation. Under the terms of Contract
# DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain
# rights in this software.

"""Generate MPEG-4 videos."""


import logging
import os
import subprocess

import toyplot.png

log = logging.getLogger(__name__)

# Verify that ffmpeg is installed, and check the version
_ffmpeg_command = None
_ffmpeg_version = None
for command in ["ffmpeg"]:
    try:
        _ffmpeg_version = subprocess.check_output([command, "-version"]).decode(encoding="utf-8").strip()
        _ffmpeg_command = command
        log.info("Using %s.", _ffmpeg_version)
    except: # pragma: no cover
        pass

[docs]def render( canvas, filename, width=None, height=None, scale=None, progress=None): """Render a canvas as an MPEG-4 video. By default, the canvas dimensions in CSS pixels are mapped directly to pixels in the output MPEG-4 video. Use one of `width`, `height`, or `scale` to override this behavior. Parameters ---------- canvas: :class:`toyplot.canvas.Canvas` Canvas to be rendered. filename: string Output video filename. width: number, optional Specify the width of the output video in pixels. height: number, optional Specify the height of the output video in pixels. scale: number, optional Ratio of output video pixels to `canvas` drawing units. progress: callback function taking a single `frame` argument, optional Callback function that will receive the number of each frame as it's written; useful to provide an indication of progress to end-users. Notes ----- The individual video frames are rendered using PNG representations of the canvas generated with :func:`toyplot.png.render_frames()`. Examples -------- >>> def callback(frame): ... print "Writing frame %s" % frame ... toyplot.mp4.render(canvas, "test.mp4", progress=callback) """ if _ffmpeg_command is None: raise RuntimeError("An ffmpeg executable is required.") # pragma: no cover command = [ _ffmpeg_command, "-f", "image2pipe", "-c", "png", "-i", "-", "-pix_fmt", "yuv420p", "-vcodec", "h264", "-preset", "slow", "-tune", "animation", "-crf", "17", "-y", filename, ] try: log.info("Running command: %s", " ".join(command)) ffmpeg = subprocess.Popen( command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) for frame, png in enumerate( toyplot.png.render_frames( canvas=canvas, width=width, height=height, scale=scale)): if progress is not None: progress(frame) ffmpeg.stdin.write(png) ffmpeg.stdin.close() ffmpeg.wait() except Exception as e: # pragma: no cover log.error(ffmpeg.stdout.read()) log.error(ffmpeg.stderr.read()) raise e