Extract video clips from BORIS behavioural annotation files
Project description
boris-clip
Extract video clips from BORIS behavioural annotation files.
For each annotated bout in a BORIS file, boris-clip cuts the corresponding segment from your video and saves it as an individual clip. Clips are named after the source video, behaviour, subject, and time interval — making them easy to sort and identify without opening them.
recording_REM_ind1_10.033-15.766.mp4
recording_grooming_ind2_42.100-48.500.mp4
Installation
boris-clip requires ffmpeg to be installed and available on your PATH.
Global installation (recommended)
Install boris-clip as a standalone tool, available system-wide without activating any environment.
With uv:
uv tool install boris-clip
With pixi:
pixi global install boris-clip
Both approaches isolate boris-clip in their own environment under the hood, so there are no dependency conflicts with your other projects. Note that with uv tool install, ffmpeg must be installed separately (e.g. via brew install ffmpeg, conda install -c conda-forge ffmpeg, or your system package manager). With pixi global install, ffmpeg is pulled in automatically from conda-forge.
Into an existing environment
With uv:
uv add boris-clip
With pixi:
pixi add boris-clip
With pip:
pip install boris-clip
Quick start
Point boris-clip at your .boris project file. If the file contains the video path (which it does by default when you annotate in BORIS), that's all you need:
boris-clip annotations.boris
If the video has moved since you created the project, or you are working with a CSV export, pass the video path explicitly:
boris-clip annotations.boris recording.mp4
Clips are saved to a clips/ directory in the current folder.
Common usage
Change the output directory:
boris-clip annotations.boris -o /path/to/output/
Add padding around each clip:
boris-clip annotations.boris --padding 2.0
Asymmetric padding — 1 second before, 3 seconds after:
boris-clip annotations.boris --padding-pre 1.0 --padding-post 3.0
Multiple videos (matched to observations by filename):
boris-clip annotations.boris rec1.mp4 rec2.mp4 rec3.mp4
Fast mode — stream-copy instead of re-encoding, much faster but cuts are keyframe-approximate:
boris-clip annotations.boris --fast
BORIS file formats
boris-clip auto-detects whichever format you provide:
| Format | Notes |
|---|---|
.boris project file |
Best option — contains video paths, FPS, and duration for validation |
| Tabular events CSV | Exported from BORIS via Observations → Export events |
| Aggregated events CSV | Exported from BORIS via Observations → Export aggregated events |
Multiple observations in a .boris project file are each processed independently and matched to their respective video by filename. Observations with no annotations are skipped automatically.
Output file naming
Clips are named using the pattern:
{video_stem}_{behaviour}_{subject}_{start}-{stop}.mp4
- Times reflect the original annotation timestamps, not the padded clip boundaries, so names are stable regardless of padding settings.
- Subjects labelled No focal subject in BORIS become
no-focal-subjectin the filename. - Special characters in behaviour or subject names are replaced with underscores.
Reference
Arguments
| Argument | Description |
|---|---|
BORIS_FILE |
Path to a .boris project file or BORIS CSV export |
[VIDEO ...] |
Optional. One or more video files. If omitted, paths embedded in the .boris file are used. Multiple videos are matched to observations by filename. |
Options
| Option | Default | Description |
|---|---|---|
-o, --output-dir |
clips/ |
Directory to write output clips into |
--padding SECONDS |
0 |
Add this many seconds before and after each state event bout |
--padding-pre SECONDS |
0 |
Seconds to add before each bout (overrides --padding for the pre side) |
--padding-post SECONDS |
0 |
Seconds to add after each bout (overrides --padding for the post side) |
--point-padding SECONDS |
5 |
Padding for point events, both sides (defaults to 5s if no general padding is set) |
--point-padding-pre SECONDS |
— | Pre-padding for point events (overrides --point-padding) |
--point-padding-post SECONDS |
— | Post-padding for point events (overrides --point-padding) |
--fast |
off | Use stream-copy instead of re-encoding. Much faster, but cut points snap to the nearest keyframe and may be slightly imprecise |
--force |
off | Downgrade hard errors (mismatched media file, out-of-bounds annotations) to warnings |
--version |
— | Show version and exit |
--help |
— | Show help and exit |
Padding precedence
Padding follows a CSS-like precedence: --padding sets both sides, while --padding-pre and --padding-post override their respective side independently.
# 2s before and after
--padding 2.0
# 2s after only
--padding-post 2.0
# 1s before, 3s after (--padding-pre and --padding-post override --padding)
--padding 3.0 --padding-pre 1.0
Point events have no inherent duration, so padding is always applied. If no point-specific padding is set, the general --padding value is used; if no padding is set at all, a default of 5 seconds each side is applied.
Re-encoding vs. stream-copy
By default, boris-clip re-encodes clips using ffmpeg. This is slower but frame-accurate — cuts land exactly at the annotated timestamp.
With --fast, ffmpeg uses stream-copy, which skips re-encoding and is significantly faster. The trade-off is that cuts snap to the nearest keyframe, which can be a second or two away from the annotation. This is fine for a quick preview but may not be suitable for precise analysis.
Validation
When a .boris project file is provided, boris-clip cross-checks the embedded metadata against the actual video via ffprobe:
- Hard error (use
--forceto override): media filename mismatch, annotation timestamps beyond video duration - Warning: FPS mismatch between BORIS file and video, duration mismatch
Contributing
Bug reports and pull requests are welcome on GitHub.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file boris_clip-0.2.0.tar.gz.
File metadata
- Download URL: boris_clip-0.2.0.tar.gz
- Upload date:
- Size: 82.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0775db115a8a47229439f51af7bb630d0a0f977c146669c2097dfdd167584041
|
|
| MD5 |
1a2d96a708e3e78f410335c4249bcf3b
|
|
| BLAKE2b-256 |
c2c865d16a4c661d48b1977ff9f8216794f5855cf459814f1c1f2aa6cc17f8ae
|
Provenance
The following attestation bundles were made for boris_clip-0.2.0.tar.gz:
Publisher:
publish.yml on roaldarbol/boris-clip
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
boris_clip-0.2.0.tar.gz -
Subject digest:
0775db115a8a47229439f51af7bb630d0a0f977c146669c2097dfdd167584041 - Sigstore transparency entry: 982653034
- Sigstore integration time:
-
Permalink:
roaldarbol/boris-clip@915716dff3dc947cc364e3258f3cd9c23d2a563a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/roaldarbol
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@915716dff3dc947cc364e3258f3cd9c23d2a563a -
Trigger Event:
push
-
Statement type:
File details
Details for the file boris_clip-0.2.0-py3-none-any.whl.
File metadata
- Download URL: boris_clip-0.2.0-py3-none-any.whl
- Upload date:
- Size: 18.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2036aba6a5af1507cea75c3929d5bb050f5b162c0baeba6e56b02aa4cff46062
|
|
| MD5 |
894cc117751a06b199d650474d94bee2
|
|
| BLAKE2b-256 |
89d4632f980942f396bd4ed31427edcc1a3b8e2e1c15f3a00e2cd64894664b56
|
Provenance
The following attestation bundles were made for boris_clip-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on roaldarbol/boris-clip
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
boris_clip-0.2.0-py3-none-any.whl -
Subject digest:
2036aba6a5af1507cea75c3929d5bb050f5b162c0baeba6e56b02aa4cff46062 - Sigstore transparency entry: 982653077
- Sigstore integration time:
-
Permalink:
roaldarbol/boris-clip@915716dff3dc947cc364e3258f3cd9c23d2a563a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/roaldarbol
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@915716dff3dc947cc364e3258f3cd9c23d2a563a -
Trigger Event:
push
-
Statement type: