Skip to content

Rendering

render_video

render_video(
    project: VideoProject,
    output_dir: str | Path,
    *,
    storage_options: dict[str, Any] | None = None,
    overwrite: bool = False
) -> Path

Renders a video based on a project.

Parameters:

Name Type Description Default
project VideoProject

The project to render.

required
output_dir str | Path

The output directory.

required
storage_options dict[str, Any] | None

Optional storage options to pass to the clip.

None
overwrite bool

Whether to overwrite the output file if it already exists.

False

Returns:

Type Description
Path

The path to the rendered video.

Source code in src/mosaico/video/rendering.py
def render_video(
    project: VideoProject,
    output_dir: str | Path,
    *,
    storage_options: dict[str, Any] | None = None,
    overwrite: bool = False,
) -> Path:
    """
    Renders a video based on a project.

    :param project: The project to render.
    :param output_dir: The output directory.
    :param storage_options: Optional storage options to pass to the clip.
    :param overwrite: Whether to overwrite the output file if it already exists.
    :return: The path to the rendered video.
    """
    output_dir = Path(output_dir).resolve()
    output_path = output_dir / f"{project.config.title}.mp4"

    if not output_dir.exists():
        msg = f"Output directory does not exist: {output_dir}"
        raise FileNotFoundError(msg)

    if output_path.exists() and not overwrite:
        msg = f"Output file already exists: {output_path}"
        raise FileExistsError(msg)

    video_clips = []
    audio_clips = []

    for event in project.timeline:
        event_asset_ref_pairs = _get_event_assets_and_refs(event, project)
        event_video_clips, event_audio_clips = _render_event_clips(
            event_asset_ref_pairs, project.config.resolution, storage_options
        )
        video_clips.extend(event_video_clips or [])
        audio_clips.extend(event_audio_clips or [])

    video: VideoClip = (
        CompositeVideoClip(video_clips, size=project.config.resolution)
        .set_fps(project.config.fps)
        .set_duration(project.duration)
    )

    if audio_clips:
        audio = CompositeAudioClip(audio_clips).set_duration(project.duration)
        video = video.set_audio(audio)

    video.write_videofile(
        output_path.as_posix(),
        codec="libx264",
        audio_codec="aac",
        temp_audiofile_path=output_path.parent.as_posix(),
        threads=multiprocessing.cpu_count(),
    )
    video.close()

    return output_path