You can trim any video without re-encoding by using ffmpeg -ss <start> -to <end> -i input.mp4 -c copy output.mp4. The -c copy flag tells FFmpeg to copy the encoded data directly into a new container — no decode, no encode, no quality loss. A 10 GB 4K file trims in under 3 seconds.
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. If all you're doing is pulling clips from conference recordings or raw footage, this one command is all you need.
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. The official FFmpeg Seeking wiki documents this in detail.
- 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 A/V drift at cut boundaries — typically because the nearest audio keyframe and video keyframe don't land on the same timestamp. Two approaches:
- Reset timestamps (usually sufficient):
ffmpeg -ss 00:01:30 -to 00:05:30 -i input.mp4 \
-c copy \
-avoid_negative_ts make_zero \
output.mp4
- Re-encode only the audio (preserves video quality, fixes sync precisely):
ffmpeg -ss 00:01:30 -to 00:05:30 -i input.mp4 \
-c:v copy \
-c:a aac -b:a 192k \
output.mp4
Audio re-encoding is fast (seconds, even for long clips) because audio data is tiny compared to video.
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
}
}
GUI Alternative: LosslessCut
If you prefer a visual interface, LosslessCut is an open-source GUI that does exactly what this article describes — lossless trimming via FFmpeg's stream copy mode. It shows keyframe positions on a timeline so you can see where your cuts will actually land. Check out our FFmpeg GUI Alternatives Comparison for a full breakdown.
Related Articles
- FFmpeg Video Compression Guide — After a lossless cut, choose the right codec and CRF settings for optimal compression
- FFmpeg Usage Tutorial — The foundational FFmpeg commands every developer should know
- H.264 vs H.265 vs AV1 Comparison — Understanding the codecs that determine your GOP structure and keyframe intervals
- FFmpeg Python Batch Automation — Scale up batch trimming with Python for more complex workflows
- GPU Encoding with NVENC and QSV — When you do need to re-encode for frame-accurate cuts, GPU acceleration can speed things up dramatically
- Extract Last Frame from Video — Another container-level operation that benefits from understanding stream copy
FAQ
Does -c copy work with all video formats?
It works with any format that FFmpeg can demux and mux — MP4, MKV, MOV, AVI, WebM, TS, and more. The codec inside doesn't matter since you're not decoding it. The only requirement is that the output container supports the input codec (e.g., VP9 can go into MKV or WebM but not MP4).
How do I find the keyframe positions in a video?
Use ffprobe -select_streams v -show_frames -show_entries frame=pkt_pts_time,key_frame -of csv input.mp4 | grep ",1$" to list all keyframe timestamps. This helps you pick cut points that align with keyframes for predictable results.
Can I trim multiple segments from the same video in one command?
Not directly with -c copy. You need to run separate FFmpeg commands for each segment and then concatenate. Create a file list and use ffmpeg -f concat -safe 0 -i list.txt -c copy merged.mp4. See our batch automation guide for scripting this.
Will -c copy preserve subtitles and metadata?
Yes — -c copy copies all streams by default, including subtitles (if the output container supports them) and metadata. To explicitly include all streams, add -map 0 to the command.
What happens if my video has variable frame rate (VFR)?
Stream copy handles VFR fine because it doesn't touch the timestamps. Problems with VFR typically arise during re-encoding, not stream copy. The keyframe snapping behavior is the same regardless of frame rate variability.
Is there a maximum file size or duration limit?
No practical limit from FFmpeg's side. I've trimmed 50 GB+ ProRes files and multi-hour recordings without issues. The operation is bounded by disk I/O speed, not memory or CPU. A 100 GB file trims just as fast as a 1 GB file.
How accurate is the end point with -c copy?
The end point (-to or -t) also snaps to the nearest keyframe, but it snaps forward — FFmpeg includes the complete GOP that contains the end timestamp. The end point offset is typically smaller than the start point offset because FFmpeg can safely truncate trailing packets.
Can I preview the cut before running it?
Use ffplay -ss 00:01:30 -t 10 input.mp4 to quickly preview 10 seconds from the start point. For GUI-based preview, LosslessCut shows the keyframe boundaries visually.
Wrapping Up
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) |
Cutting conference talks, pulling highlight clips, extracting segments for social media — with -c copy, the entire workflow takes under a minute for what used to require loading up a full NLE. Once you internalize that -c copy treats video as data packets rather than pixels, you start seeing a whole category of FFmpeg operations that work at the container level. That mental shift is what separates "I can use FFmpeg" from "I think in FFmpeg."
For the full FFmpeg documentation on seeking behavior, refer to the official FFmpeg docs and the Seeking wiki page.