A fast, efficient video trimming and manipulation toolkit built on Python.
- Fast Video I/O: Efficient video reading and writing with
imageioand PyAV backends - Frame-Accurate Trimming: Precise frame-level control with re-encoding support
- Lossless Copy Mode: Ultra-fast trimming using ffmpeg's copy mode (when frame accuracy isn't critical)
- Auto Start Detection: Automatically detect when video content begins using motion-based detection (perfect for removing "hand at start" frames)
- Frame Extraction: Export individual frames as images
- Video Concatenation: Merge multiple videos into one
- Flexible CLI: Powerful command-line interface with timestamp and frame-based operations
- Python API: Full-featured library for programmatic video manipulation
# Install uv if you haven't already
curl -LsSf https://astral.sh/uv/install.sh | sh
# Run videotrim directly
uvx videotrim --help
# Trim a video (frames 100-500)
uvx videotrim trim input.mp4 output.mp4 --start 100 --end 500
# Trim by timestamps
uvx videotrim trim input.mp4 output.mp4 --start-time 00:10 --end-time 00:30# Install videotrim as a tool
uv tool install videotrim
# Run directly
videotrim --help
videotrim info input.mp4
videotrim trim input.mp4 output.mp4 -s 100 -e 500
# Update to latest version
uv tool upgrade videotrim# Using pip
pip install videotrim
# Or using uv
uv pip install videotrim# Clone the repository
git clone https://github.com/talmolab/videotrim.git
cd videotrim
# Install with uv
uv pip install -e .
# Or with dev dependencies
uv pip install -e ".[dev]"videotrim info input.mp4Output:
File: input.mp4
Size: 1,234,567 bytes
Duration: 00:01:23.456
FPS: 30.00
Frames: 2,504
Resolution: 1920x1080
Codec: h264
# Trim by frame range (frame-accurate with re-encoding)
videotrim trim input.mp4 output.mp4 --start 100 --end 500
# Trim by timestamps (skip first 30 seconds, save next 5 seconds)
videotrim trim input.mp4 output.mp4 --start-time 00:30 --end-time 00:35 --mode encode
# Trim by timestamps with shorthand
videotrim trim input.mp4 output.mp4 --start-time 00:10 --end-time 00:30
# Fast copy mode (no re-encoding, may not be frame-accurate)
videotrim trim input.mp4 output.mp4 -s 100 -e 500 --mode copy
# High quality encode
videotrim trim input.mp4 output.mp4 -s 100 -e 500 --mode encode --quality 10
# Auto mode (automatically choose copy or encode)
videotrim trim input.mp4 output.mp4 -s 100 -e 500 --mode auto
# Auto-detect start frame (removes "hand at start" frames)
videotrim trim input.mp4 output.mp4 --auto-detect-start --end 1000
# Auto-detect with verbose output to see detection process
videotrim trim input.mp4 output.mp4 -a -e 1000 -v
# Auto-detect with custom parameters for fine-tuning
videotrim trim input.mp4 output.mp4 -a --detect-coarse-samples 15 --detect-downsample 2# Extract all frames as PNG
videotrim extract input.mp4 frames/
# Extract specific range
videotrim extract input.mp4 frames/ --start 100 --end 500
# Extract every 10th frame
videotrim extract input.mp4 frames/ --step 10
# Extract as JPEG with custom prefix
videotrim extract input.mp4 frames/ --format jpg --prefix frame_# Fast concatenation (copy mode)
videotrim concat output.mp4 part1.mp4 part2.mp4 part3.mp4
# With re-encoding for compatibility
videotrim concat output.mp4 part1.mp4 part2.mp4 --mode encodefrom videotrim import trim_video, TrimMode
# Trim with frame-accurate encoding
trim_video(
"input.mp4",
"output.mp4",
start_frame=100,
end_frame=500,
mode=TrimMode.ENCODE
)
# Fast copy mode
trim_video(
"input.mp4",
"output.mp4",
start_frame=100,
end_frame=500,
mode=TrimMode.COPY
)
# Auto-detect start frame (removes "hand at start" frames)
trim_video(
"input.mp4",
"output.mp4",
auto_detect_start=True,
end_frame=1000
)
# Auto-detect with custom parameters
trim_video(
"input.mp4",
"output.mp4",
auto_detect_start=True,
end_frame=1000,
auto_detect_params={
'coarse_samples': 15,
'downsample_factor': 2,
'verbose': True
}
)from videotrim import detect_start_frame
# Detect where video content actually starts
start_frame = detect_start_frame("input.mp4")
print(f"Content starts at frame {start_frame}")
# With verbose output to see detection process
start_frame = detect_start_frame("input.mp4", verbose=True)
# With custom parameters for fine-tuning
start_frame = detect_start_frame(
"input.mp4",
coarse_samples=15, # More initial samples
downsample_factor=2, # Less aggressive downsampling
binary_search_samples_per_iteration=7, # More samples per iteration
final_window_size=5 # Smaller final window
)from videotrim import VideoReader, VideoWriter
# Read video
with VideoReader("input.mp4") as reader:
print(f"FPS: {reader.fps}")
print(f"Frames: {reader.frame_count}")
print(f"Resolution: {reader.width}x{reader.height}")
# Read specific frame
frame = reader.read_frame(42)
# Read frame range
frames = reader.read_frames(100, 200)
# Iterate through all frames
for frame in reader:
process_frame(frame)
# Write video
with VideoWriter("output.mp4", fps=30.0, quality=8) as writer:
for frame in frames:
writer.write_frame(frame)from videotrim import extract_frames
# Extract all frames
num_frames = extract_frames("input.mp4", "frames/")
# Extract every 10th frame
num_frames = extract_frames(
"input.mp4",
"frames/",
step=10,
format="png"
)from videotrim import concatenate_videos, TrimMode
# Concatenate multiple videos
concatenate_videos(
["part1.mp4", "part2.mp4", "part3.mp4"],
"full.mp4",
mode=TrimMode.COPY
)from videotrim.utils import (
get_video_info,
frame_to_timestamp,
timestamp_to_frame,
parse_time_string,
format_timestamp
)
# Get video metadata
info = get_video_info("input.mp4")
print(info)
# Convert between frames and timestamps
timestamp = frame_to_timestamp(150, fps=30.0) # 5.0 seconds
frame = timestamp_to_frame(5.0, fps=30.0) # 150
# Parse time strings
seconds = parse_time_string("01:23:45.5") # 5025.5
# Format timestamps
time_str = format_timestamp(5025.5) # "01:23:45.500"# Clone and enter directory
git clone https://github.com/talmolab/videotrim.git
cd videotrim
# Install in development mode with dev dependencies
uv pip install -e ".[dev]"
# Run the CLI
python -m videotrim --help
videotrim --help # After installation# Install dev dependencies if not already installed
uv pip install -e ".[dev]"
# Run tests
pytest
# Run with coverage
pytest --cov=videotrim --cov-report=html
# Run specific test file
pytest tests/test_io.py
# Run with verbose output
pytest -v# Format and lint with ruff
ruff check src/ tests/
ruff format src/ tests/
# Auto-fix issues
ruff check --fix src/ tests/- Python ≥ 3.12
- numpy
- imageio
- imageio-ffmpeg
- av (PyAV)
- opencv-python
- click
Optional:
- ffmpeg (for fast copy mode trimming and concatenation)
videotrim is built with a modular architecture:
videotrim.io: Core video I/O withVideoReaderandVideoWriterclassesvideotrim.trim: Trimming operations with multiple modes (copy/encode/auto)videotrim.detection: Motion-based start frame detection using hierarchical searchvideotrim.utils: Utility functions for time/frame conversions and validationvideotrim.cli: Command-line interface built with Click
The library uses imageio with PyAV backend for frame-accurate video operations, and optionally uses ffmpeg directly for ultra-fast copy mode operations.
The motion-based start detection feature uses a hierarchical approach:
- Phase 1 - Coarse Sampling: Sample frames uniformly across the video
- Phase 2 - Region Identification: Find the region with highest motion change
- Phase 3 - Binary Search: Refine detection within that region
This approach samples only ~1-2% of frames, making it very efficient. Based on empirical testing, it achieves approximately 25 frame accuracy (typically <1 second error) for "hand at start" videos.
MIT License - see LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.