Source code for manim.utils.commands

from __future__ import annotations

import os
from collections.abc import Generator
from pathlib import Path
from subprocess import run
from typing import TypedDict

import av

from manim.typing import StrOrBytesPath

__all__ = [
    "capture",
    "get_video_metadata",
    "get_dir_layout",
]


[docs] def capture( command: str | list[str], cwd: StrOrBytesPath | None = None, command_input: str | None = None, ) -> tuple[str, str, int]: p = run( command, cwd=cwd, input=command_input, capture_output=True, text=True, encoding="utf-8", ) out, err = p.stdout, p.stderr return out, err, p.returncode
[docs] class VideoMetadata(TypedDict): width: int height: int nb_frames: str duration: str avg_frame_rate: str codec_name: str pix_fmt: str
[docs] def get_video_metadata(path_to_video: str | os.PathLike) -> VideoMetadata: with av.open(str(path_to_video)) as container: stream = container.streams.video[0] ctxt = stream.codec_context rate = stream.average_rate if stream.duration is not None: duration = float(stream.duration * stream.time_base) num_frames = stream.frames else: num_frames = sum(1 for _ in container.decode(video=0)) duration = float(num_frames / stream.base_rate) return { "width": ctxt.width, "height": ctxt.height, "nb_frames": str(num_frames), "duration": f"{duration:.6f}", "avg_frame_rate": f"{rate.numerator}/{rate.denominator}", # Can be a Fraction "codec_name": stream.codec_context.name, "pix_fmt": stream.codec_context.pix_fmt, }
[docs] def get_dir_layout(dirpath: Path) -> Generator[str, None, None]: """Get list of paths relative to dirpath of all files in dir and subdirs recursively.""" for p in dirpath.iterdir(): if p.is_dir(): yield from get_dir_layout(p) continue yield str(p.relative_to(dirpath))