Skip to main content

Utility to work with video clips, especially suited for creating timelapses from dashcam footage

Project description

ClipSmith

Utility to work with video clips, especially suited for dashcam footage

Python versions PyPI Tests Coverage Code style: black

Motivation

This project leverages ffmpeg and task orchestration via doit to provide a user-friendly utility to work with video clips. Clips can be readily concatenated, trimmed, and/or rescaled in a single command. This is especially useful for working with dashcam footage wherein there are many short video files to manage.

Getting started

First, ensure you have ffmpeg installed:

# Ubuntu/Debian
sudo apt install ffmpeg

# macOS
brew install ffmpeg

# Windows
# Download from https://ffmpeg.org/download.html

Then install using pip:

pip install clipsmith

CLI

Forging clips

The command clipsmith forge is the entry point for creating new clips.

Usage: clipsmith forge [OPTIONS] INPUTS... OUTPUT                                                                                                            
                                                                                                                                                              
 Create a video from one or more videos with specified operations applied                                                                                     
                                                                                                                                                              
╭─ Arguments ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ *    inputs      INPUTS...  One or more paths to input video(s) or folder(s) of videos [default: None] [required]                                          │
│ *    output      PATH       Path to output video [default: None] [required]                                                                                │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --trim-start                  FLOAT  Start offset (seconds) in input file(s) [default: None]                                                               │
│ --trim-end                    FLOAT  End offset (seconds) in input file(s) [default: None]                                                                 │
│ --dur-scale                   FLOAT  Scale duration by scale factor [default: None]                                                                        │
│ --dur-target                  FLOAT  Scale duration to target (seconds) [default: None]                                                                    │
│ --res-scale                   FLOAT  Scale resolution by scale factor [default: None]                                                                      │
│ --res-target                  TEXT   Scale resolution to target as WIDTH:HEIGHT [default: None]                                                            │
│ --audio         --no-audio           Whether to pass through audio to output (not yet supported with time scaling) [default: audio]                        │
│ --cache         --no-cache           Whether to store a cache of video metadata in input folders [default: no-cache]                                       │
│ --log-level                   TEXT   Log level passed to ffmpeg [default: info]                                                                            │
│ --help                               Show this message and exit.                                                                                           │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

Concatenating

Concatenate multiple clips into a single one:

# Combine specific files
clipsmith forge clip1.mp4 clip2.mp4 combined.mp4

# Combine all clips from a folder
clipsmith forge input_folder/ combined.mp4

Trimming

Trim clips using start and end time offsets:

# Trim to specific time range
clipsmith forge --trim-start 1.0 --trim-end 5.0 input.mp4 output.mp4

# Trim just the start
clipsmith forge --trim-start 1.0 input.mp4 output.mp4

# Trim just the end
clipsmith forge --trim-end 5.0 input.mp4 output.mp4

Rescaling

Rescale video duration and resolution:

# Speed up video by factor (e.g. 2x faster)
clipsmith forge --dur-scale 2.0 --no-audio input.mp4 output.mp4

# Slow down video by factor (e.g. 2x slower)
clipsmith forge --dur-scale 0.5 --no-audio input.mp4 output.mp4

# Set specific target duration in seconds
clipsmith forge --dur-target 60.0 --no-audio input.mp4 output.mp4

# Scale to specific resolution
clipsmith forge --res-target 480:270 input.mp4 output.mp4

# Scale resolution by factor
clipsmith forge --res-scale 0.5 input.mp4 output.mp4

Additional features

Additional features include:

  • Automatic caching of video metadata in folders via --cache
  • Directory recursion (depth-first) for concatenation

API

Context

The Context class provides the main interface for working with clips. It implements a task orchestration pattern using doit:

from pathlib import Path
from clipsmith import Context

# Create a context
context = Context()

# Forge a new clip from input files
context.forge("output.mp4", [Path("input1.mp4"), Path("input2.mp4")])

# Execute all pending operations
context.doit()

Clips

Clips can be manipulated using operation parameters for duration and resolution. A clip can be "reforged" into another clip, with doit managing orchestration of ffmpeg invocations.

from clipsmith import (
    Context, 
    OperationParams,
    DurationParams,
    ResolutionParams
)

context = Context()
inputs = [Path("input1.mp4"), Path("input2.mp4")]

# Trimming
clip1 = context.forge(
    "output1.mp4",
    inputs,
    OperationParams(
        duration_params=DurationParams(
            trim_start=1.0,  # Start at 1 second
            trim_end=5.0,  # End at 5 seconds
        ),
    )
)

# Time scaling
clip2 = context.forge(
    "output2.mp4",
    inputs,
    OperationParams(
        duration_params=DurationParams(
            scale=2.0,  # Speed up by 2x
        ),
        audio=False
    )
)

# Resolution scaling
clip3 = context.forge(
    "output3.mp4", 
    inputs,
    OperationParams(
        resolution_params=ResolutionParams(
            target=(480, 270)  # Scale to specific resolution
        )
    )
)

# Chain operations by reforging trimmed clip
clip4 = clip1.reforge(
    "output4.mp4",
    OperationParams(
        resolution_params=ResolutionParams(
            scale=0.5  # Scale resolution by factor
        )
    )
)

# Execute all operations
context.doit()

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

clipsmith-0.1.1.tar.gz (14.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

clipsmith-0.1.1-py3-none-any.whl (16.6 kB view details)

Uploaded Python 3

File details

Details for the file clipsmith-0.1.1.tar.gz.

File metadata

  • Download URL: clipsmith-0.1.1.tar.gz
  • Upload date:
  • Size: 14.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.3 CPython/3.12.6 Linux/5.15.0-125-generic

File hashes

Hashes for clipsmith-0.1.1.tar.gz
Algorithm Hash digest
SHA256 470af173bee5e2b1105c5d77bfd043c90259ca597ee23363cf3847626b3bbd65
MD5 bcf8b9f8230ab1648b2b668f52243677
BLAKE2b-256 7a2b96c0e313f50e5092a2c80aeed9d3850fe36c2efcaea94af378e8dc17c2b2

See more details on using hashes here.

File details

Details for the file clipsmith-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: clipsmith-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 16.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.3 CPython/3.12.6 Linux/5.15.0-125-generic

File hashes

Hashes for clipsmith-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 1e2626088485e5f01ac1b8572d44b9d22d3a1e1ade350596154528f8f51fadde
MD5 67dfa409e8aeea4ba7a21613d66b0e86
BLAKE2b-256 5c5e50321910e79f32de19fe8c243abcc0eac495fc212b0780e6964f244b6e97

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page