Almost every FFmpeg task starts with one choice: copy the existing audio and video streams as they are, or re-encode them (decode them and compress them again). A copy keeps the quality and can be done in a second. A re-encode loses some quality and can take ten minutes. The part that trips people up most is container compatibility (Section 4).
1. Stream Copy (-c copy)
Stream copy moves the already-compressed audio and video packets from the input straight into a new container. Nothing is decoded or compressed again. The basic command:
ffmpeg -i input.mp4 -c copy output.mp4
-c copy… copy every stream that goes into the output (short for-c:v copy -c:a copy ...). Without-map, FFmpeg picks at most one video and one audio stream. It adds a subtitle stream only when the output format has a default subtitle codec. MP4 has none, so subtitles are left out of an MP4 unless you select them with-map(SRT subtitles also need-c:s mov_text).
Because nothing is decoded:
- Quality does not change. For some containers, such as MPEG-TS, FFmpeg rewrites how the data is packed, but the decoded picture and sound stay exactly the same.
- It usually finishes in seconds. Disk speed is the main limit.
- It uses almost no CPU.
Use it whenever the picture and sound stay as they are: changing the container (remuxing), cutting at keyframes (frames that can be decoded on their own), or merging streams.
2. Re-encoding
Re-encoding decodes every frame back to uncompressed form and then compresses it again with the encoder you choose. The basic command:
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -c:a aac output.mp4
-c:v libx264… re-encode video to H.264.-crf 23… quality target (lower = better quality, larger file).-c:a aac… re-encode audio to AAC.
Compared with a copy:
- Quality drops. A lossy codec throws away some detail when it compresses again. The result is never better than the source.
- It is slow. Every frame is decoded and encoded again, which keeps the CPU busy.
- You can change the codec, resolution, bitrate and frame rate, apply filters, and more.
You need it whenever the picture or sound itself has to change: to compress, resize, convert to another codec, or apply filters.
3. Side by Side
-c copy (stream copy) |
Re-encode | |
|---|---|---|
| Quality | Lossless (identical) | Lossy (some loss) |
| Speed | Seconds | Minutes (CPU-bound) |
| CPU usage | Minimal | High |
| File size | ~Same as source | Controllable |
| Change codec? | No | Yes |
| Resize / filter? | No | Yes |
| Change container? | Yes | Yes |
| Cut anywhere? | Keyframes only | Any frame |
Rule of thumb: copy when you can, and re-encode only when you must.
4. The Container Compatibility Caveat
Each container accepts only certain codecs. If the source codec is not allowed in the target container, stream copy fails. For example:
- MP4 accepts H.264, HEVC and AAC. It does not accept ProRes, or 8-bit or μ-law PCM audio. 16/24-bit PCM goes in, but many players cannot play it.
- WebM accepts VP9 or AV1 video with Opus or Vorbis audio. It does not accept H.264 or AAC.
So a copy can fail even when you do not want to change anything. For example, copying a MOV that contains ProRes video into MP4 fails:
ffmpeg -i input.mov -c copy output.mp4
If FFmpeg prints Could not find tag for codec ... in stream, the codec does not fit the container you chose. Either pick a container that accepts it, or re-encode only that stream to a codec the container accepts (Section 6).
| Source codec | Target container | Copy works? |
|---|---|---|
| H.264 + AAC | MP4 / MKV | Yes |
| HEVC + AAC | MP4 (add -tag:v hvc1) |
Yes |
| VP9 + Opus | WebM / MKV | Yes |
| VP9 + Opus | MP4 | Yes (some players cannot play it) |
| PCM audio | MP4 | 16/24-bit yes, but many players cannot play it (re-encode to AAC) |
| Almost anything | MKV | Usually yes |
MKV accepts the widest range of codecs, so a stream copy into MKV works far more often than one into MP4.
5. When to Copy and When to Re-encode
Use -c copy when:
- Changing only the container (e.g., MKV to MP4, MOV to MP4).
- Trimming at keyframe boundaries.
- Merging or splitting without altering the media.
- The streams already fit the target.
Re-encode when:
- Compressing to reduce file size.
- Changing resolution, frame rate, or pixel format.
- Converting to a codec the container or device requires.
- Applying filters (scale, crop, overlay, subtitles burn-in, color).
- Cutting frame-accurately between keyframes.
6. Per-stream Choices
You can choose copy or re-encode separately for each stream. A common pattern is to copy the video, which is the slow part to encode, and re-encode only the audio to a codec the container accepts:
ffmpeg -i input.mp4 -c:v copy -c:a aac -b:a 192k output.mp4
The video is copied instantly and only the audio is re-encoded. This is far faster than re-encoding everything and still fixes an audio codec the container does not accept. The reverse (re-encode the video, copy the audio) works too:
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -c:a copy output.mp4
7. Troubleshooting
Error 1: Could not find tag for codec ... in stream
Cause: You are copying a codec that the target container does not accept. Fix: Choose a container that accepts it (MKV accepts the most codecs) or re-encode that stream (Section 6).
Error 2: The trimmed copy starts with a frozen frame or black gap
Cause: Stream copy can only start the video at a keyframe. With -ss after -i, the video starts at the next keyframe after the cut point while the audio starts on time, so the picture is missing until that keyframe. With -ss before -i, FFmpeg starts from the previous keyframe and writes an edit list that hides the frames before the cut point; a player that ignores the edit list shows them.
Fix: Re-encode if you need a cut at an exact frame, or accept the keyframe position. See Trim video.
Error 3: Re-encoding made the file bigger, not smaller
Cause: Your -crf (or bitrate) asks for higher quality than the source has.
Fix: Raise the CRF number (for example, from 23 to 26) to compress more. Also check whether you need to re-encode at all.
Error 4: Copy succeeds but the browser takes a long time to start playing
Cause: The moov atom (the index a player needs) is at the end of the MP4, and the browser cannot start playing until it has read it.
Fix: Add -movflags +faststart. See the faststart guide. If the file does not play at all, the browser may not support one of its codecs (see the table in Section 4).
FAQ
Q1. Does -c copy ever change quality?
A. No. It moves the compressed data without decoding it, so the decoded picture and sound are the same as the source. Some containers need the data packed a little differently, but that does not affect quality. Only re-encoding can change quality.
Q2. Why is re-encoding so much slower? A. It decodes every frame to raw pixels and compresses it again. A copy only moves the existing packets, which is far less work.
Q3. Can I re-encode without losing quality?
A. Only with a lossless encoder, such as FFV1 or libx264 with -qp 0, and the files get very large. A normal lossy re-encode always loses some detail.
Q4. How do I know which codecs my file uses?
A. Run ffprobe input.mp4 and read the Stream lines, or use ffprobe -show_streams. Then check the table in Section 4 to see whether a copy will work.
Q5. Should I default to copy or re-encode?
A. Start with -c copy. Re-encode only when you need to change the media (size, resolution, codec, filters) or when the copy fails because the container does not accept a codec.