Firing up Premiere Pro or DaVinci Resolve to trim a clip is overkill in most situations. If all you need is to cut a section out of a video — no effects, no color correction, just a clip — FFmpeg's stream copy mode completes the job in seconds with zero quality loss.
ffmpeg -y -ss 00:01:30 -to 00:05:30 -i "input.mp4" -c copy "output.mp4"
This single command extracts everything from 1:30 to 5:30, copies the encoded data as-is into a new file, and finishes before a GUI editor would even finish loading.
The Commands
Windows (PowerShell)
# Define variables
$InputVideo = "input.mp4"
$OutputVideo = "output_cut.mp4"
$StartTime = "00:01:30" # HH:MM:SS
$EndTime = "00:01:40"
# -ss : Seek to start time
# -to : Set end time (-t would specify duration instead)
# -c copy : Copy streams without re-encoding
ffmpeg -y -ss $StartTime -to $EndTime -i "$InputVideo" -c copy "$OutputVideo"
macOS / Linux (Bash)
#!/bin/bash
INPUT="input.mp4"
OUTPUT="output_cut.mp4"
START="00:01:30"
END="00:01:40"
# Place -ss before -i for input seeking (fast)
ffmpeg -y -ss "$START" -to "$END" -i "$INPUT" -c copy "$OUTPUT"
How Stream Copy Works
The key option is -c copy (equivalent to -c:v copy -c:a copy). Understanding what it actually does explains both its power and its limitations.
Bypassing the decode/encode cycle
A normal video editing workflow looks like this:
- Decode the compressed video into raw frames (slow, lossy at boundaries)
- Process the frames (crop, color grade, etc.)
- Re-encode the processed frames into compressed video (slow, introduces generation loss)
Stream copy skips steps 1 and 3 entirely. FFmpeg reads the encoded packets from the source container (MP4, MKV, etc.) and writes them directly into the output container without touching the data. The computational load is essentially just disk I/O.
Practical speed comparison:
For a 10 GB 4K video, cutting a 10-second clip:
- With re-encoding (
-c:v libx264): several minutes - With stream copy (
-c copy): 1–3 seconds
Input seeking: why -ss goes before -i
The position of -ss in the command matters significantly.
- Before
-i(input seeking): The demuxer jumps to the specified position in the file before decoding starts. No data before the seek point is processed. This is fast — essentially O(1) for most container formats. - After
-i(output seeking): FFmpeg decodes from the start until it reaches the specified time, then starts copying. Correct but slow, and it produces unstable results with-c copy.
For lossless trimming, always put -ss before -i.
The keyframe constraint
Lossless trimming has one unavoidable technical limitation: the cut point snaps to the nearest keyframe.
Modern codecs (H.264, H.265, AV1) compress video using a structure called GOP (Group of Pictures). A GOP starts with an I-frame (keyframe) that contains complete image data, followed by P-frames and B-frames that store only the difference from surrounding frames.
When you use -c copy, FFmpeg can't start playback mid-GOP because P/B frames need their reference I-frame to decode. So if you specify 00:01:30 as the start time, FFmpeg automatically backs up to the nearest I-frame before that point — which might be 00:01:27, 00:01:25, or further back depending on the GOP structure.
The result: the cut point can be off by a few seconds (up to the GOP length) from what you specified.
Practical implication: Lossless cutting is ideal for "roughly here" trimming — conference recordings, long-form footage, podcast clips. It's not suitable for frame-accurate editorial work. For precision cuts, you need to re-encode.
Troubleshooting
The output video starts with a black or frozen frame
This is usually a player compatibility issue. Some players struggle when the video stream starts with a P-frame rather than an I-frame. Adding -avoid_negative_ts make_zero usually fixes it:
ffmpeg -ss 00:01:30 -to 00:05:30 -i input.mp4 \
-c copy \
-avoid_negative_ts make_zero \
output.mp4
Audio and video are out of sync
Stream copy preserves the original timestamps, which can cause slight sync issues at cut boundaries. Fix with:
ffmpeg -ss 00:01:30 -to 00:05:30 -i input.mp4 \
-c copy \
-avoid_negative_ts make_zero \
output.mp4
The clip needs to start at exactly the right frame
If you need frame-accurate precision, stream copy won't work. Use re-encoding with a fast preset:
# Video re-encode, audio stream copy
ffmpeg -ss 00:01:30 -to 00:05:30 -i input.mp4 \
-c:v libx264 -preset fast -crf 23 \
-c:a copy \
output.mp4
This is slower but starts exactly where you specify.
-t vs -to: what's the difference?
-t 60— cut 60 seconds of duration from the start point-to 00:05:30— cut until timestamp 5:30 in the source file
For "cut from X to Y" use cases, -to is more intuitive. For "cut X seconds starting from here," use -t.
Note: When -ss is placed before -i (input seeking), -to refers to the absolute timestamp of the input file, not a duration from the seek point. For example, -ss 00:01:30 -to 00:05:30 extracts from 1:30 to 5:30 in the original file — not 4 minutes starting from 1:30.
Batch Trimming
Bash: Process a list of clips from a CSV file
Create clips.csv:
input,start,end,output
video1.mp4,00:01:30,00:05:00,clip1.mp4
video2.mp4,00:00:10,00:02:30,clip2.mp4
video3.mp4,00:10:00,00:15:45,clip3.mp4
Then process it:
#!/bin/bash
tail -n +2 clips.csv | while IFS=',' read -r input start end output; do
ffmpeg -y -ss "$start" -to "$end" -i "$input" -c copy "$output"
echo "Done: $output"
done
PowerShell: Batch trim with progress reporting
$clips = Import-Csv -Path "clips.csv"
$total = $clips.Count
$i = 0
foreach ($clip in $clips) {
$i++
Write-Progress -Activity "Trimming clips" `
-Status "$($clip.output) ($i/$total)" `
-PercentComplete (($i / $total) * 100)
ffmpeg -y -ss $clip.start -to $clip.end `
-i $clip.input `
-c copy `
$clip.output 2>$null
if ($LASTEXITCODE -eq 0) {
Write-Host "OK: $($clip.output)"
} else {
Write-Host "FAILED: $($clip.output)" -ForegroundColor Red
}
}
Summary
FFmpeg's lossless trimming is the right tool when:
| Situation | Recommended approach |
|---|---|
| Rough cuts where ±5 seconds is acceptable | -c copy (this article's method) |
| Frame-accurate precision cuts | Re-encode with -c:v libx264 -preset fast |
| Batch trimming many files | Script + -c copy |
| Extracting clips from conference recordings | -c copy |
| Preparing clips for social media | -c copy (platforms re-encode anyway) |
Stream copy treats video as a stream of data packets rather than pixels. That abstraction is what makes it so fast and lossless — and understanding it opens up a whole category of FFmpeg operations that operate at the container level rather than the codec level.