Converting an HEVC video to H.264 can help when a player supports H.264 but cannot decode HEVC at the needed speed. FFmpeg re-encodes the video stream and can copy selected audio and subtitle streams into a new MKV file.
I’ll show how to check an input video and encode a new MKV with FFmpeg.
TL;DR
Use FFmpeg with libx264 to make a separate H.264 file, then inspect its streams before replacing the HEVC source.
- Check the input video codec with ffprobe.
- Encode the video and copy the selected audio and subtitle streams into an MKV output.
- Keep the source until the new file plays correctly on the target device.
What is HEVC-to-H.264 transcoding?
HEVC-to-H.264 transcoding decodes the source video and encodes those frames again with the H.264 codec. This can help when a player supports H.264 but cannot decode the HEVC source at the needed speed.
A codec describes how a media stream is encoded. A container such as Matroska, usually saved as MKV, holds streams such as video, audio, subtitles, and metadata. Changing a filename extension does not change the video codec inside the file.
| Term | Meaning here |
|---|---|
| HEVC or H.265 | The source video codec in the example. |
| H.264 or AVC | The output video codec selected for broader player support. |
| x264 or libx264 | The software encoder FFmpeg uses to create H.264 video. |
| MKV | The output container, which can hold the copied audio and subtitle streams used here. |
Re-encoding is lossy, so it cannot restore detail already removed from the source. H.264 can also produce a larger file than HEVC at a similar visual quality because the two codecs compress differently.
H.264 is the bitstream standard, while x264 is a software encoder that writes H.264 video. FFmpeg can use other H.264 encoders too, but the example uses libx264 because it is present in the tested build and exposes the CRF and preset controls shown below.
How to convert HEVC to H.264 with FFmpeg
Check the video stream, run an encode that writes to a new file, and verify the output streams before testing playback.
The commands assume Bash and an FFmpeg build with libx264 enabled. The FFmpeg download page links to source releases and compiled packages. Install a package suitable for your distribution before following the shell steps.
Step 1: Check the input video codec
FFmpeg’s companion tool ffprobe reports stream details. This command asks for the codec name of the first video stream in the named MKV file. Routine logs are suppressed, leaving the codec field by itself.
ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1 demo-hevc.mkv
codec_name=hevc

I checked the sample before encoding, and ffprobe returned codec_name=hevc. Replace demo-hevc.mkv with the path to your own file, and keep the input filename in quotes when it contains spaces.
This probe identifies the first video stream only. A source with multiple video tracks may need a different selection, while audio and subtitle streams follow separate mapping rules.
Step 2: Encode to a new MKV file
Save this script as convert_hevc.sh in the directory with your source file. The sample is a single-video-track file, so the first video mapping selects its HEVC stream. The INPUT.mkv label in the usage line is a placeholder, not a required source extension.
The script maps the first video stream and, when present, all audio and subtitle streams. It re-encodes video while copying the selected non-video streams into an MKV container.
The audio and subtitle selectors include every matching stream. If a source has several language tracks, inspect its stream list and select the tracks you intend to keep before encoding.
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -ne 2 ]]; then
printf 'Usage: %s INPUT.mkv OUTPUT.mkv\n' "$0" >&2
exit 2
fi
input=$1
output=$2
ffmpeg -hide_banner -n -loglevel error -i "$input" \
-map 0:v:0 -map '0:a?' -map '0:s?' \
-c:v libx264 -crf 20 -preset medium -pix_fmt yuv420p \
-c:a copy -c:s copy "$output"
ffprobe -v error -show_entries stream=codec_type,codec_name \
-of compact=p=0:nk=1 "$output"
The script refuses to overwrite an existing output, so choose a new filename for each test. CRF 20 is only a starting point. The FFmpeg manual explains stream mapping and encoding or streamcopy options, and a long encode also needs enough free disk space for its output.
The example requests yuv420p output for broad playback support. That pixel format is 8-bit 4:2:0, so footage recorded in 10-bit color or HDR needs a separate color and bit-depth decision before using the same settings. The sample clip uses ordinary 8-bit video and does not test a 10-bit conversion.
FFmpeg’s pixel-format list distinguishes yuv420p’s 8-8-8 samples from yuv420p10le’s 10-10-10 samples. This recipe explicitly requests the 8-bit format. If retaining 10-bit source data matters, choose a compatible 10-bit encoding path and verify that the target device accepts it.
bash convert_hevc.sh demo-hevc.mkv converted-demo.mkv
The input path comes first and the destination path second. Both can be relative to the current directory or full paths. Choose a destination directory with enough free space to hold the converted file beside the original.
h264|video
aac|audio

I ran the script on the checked HEVC sample. ffprobe reported h264 for video and aac for audio. The AAC result confirms the sample’s audio stream copied with the chosen command.
Step 3: Confirm playback on the target device
Before archiving, run these playback checks on the target device:
- Play a moving scene with fine detail.
- Confirm the audio and subtitle tracks you need are present.
- Seek near the end and compare the output duration.
- Keep the source until the checks pass, and test one file of each type before a batch.
Some older players impose H.264 profile or level restrictions. Check the device manual if a verified H.264 file still fails. Frame size or bitrate may be the constraint.
This example writes MKV, which the target TV must also support.
For an MP4 target, give the output path an .mp4 suffix and check that the copied audio and subtitle streams work in that container. Renaming an MKV file does not convert it to MP4.
Edge cases and quality checks
CRF sets the quality target, while the preset changes how much work x264 spends on compression. If you are choosing between speed and compression, compare presets at the same CRF as in the sample below.
Read the final FFmpeg error line to find which stage stopped.
The preset test uses libx264. The installed FFmpeg build listed hardware H.264 encoders, but this task did not test a GPU path. Hardware encoder support depends on the card and driver, so check the available device and encoder-specific options before switching.
Compare presets on a short sample
I held CRF at 20 and compared ultrafast with medium on the same four-second generated HEVC sample. The medium output was smaller in this test, but that size difference is specific to this short sample and does not predict another video’s result.
Save the following as compare_presets.sh to repeat the comparison with a source file. It writes two separate MKV files and measures their byte counts with wc.
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -ne 1 ]]; then
printf 'Usage: %s INPUT.mkv\n' "$0" >&2
exit 2
fi
input=$1
ffmpeg -hide_banner -n -loglevel error -i "$input" \
-map 0:v:0 -map '0:a?' -c:v libx264 -crf 20 -preset ultrafast \
-pix_fmt yuv420p -c:a copy preset-ultrafast.mkv
ffmpeg -hide_banner -n -loglevel error -i "$input" \
-map 0:v:0 -map '0:a?' -c:v libx264 -crf 20 -preset medium \
-pix_fmt yuv420p -c:a copy preset-medium.mkv
wc -c preset-ultrafast.mkv preset-medium.mkv
bash compare_presets.sh demo-hevc.mkv
1203098 preset-ultrafast.mkv
487868 preset-medium.mkv
1690966 total

The final total adds the byte counts for both output files. Compare each individual line with its filename when reading the screenshot.
Watch the preview for banding in gradients and smearing around moving edges. Visible artifacts matter more than a byte count when deciding whether to keep a conversion.
The table below separates common failures by the point where they occur. A path error happens before decoding starts, while a codec or muxer error appears later after FFmpeg has opened the source.
Fix missing files and incompatible streams
I queried an absent filename, and ffprobe returned the exact message below. Check the spelling, directory, and read access before changing encoder settings.
ffprobe -v error -select_streams v:0 -show_entries stream=codec_name missing-demo.mkv
missing-demo.mkv: No such file or directory

| Symptom | What to check |
|---|---|
| No such file or directory | Use the correct path from the current directory and quote names containing spaces. |
| Unknown libx264 encoder | The FFmpeg build may omit that encoder. Check the distribution’s supported FFmpeg package and its encoder list. |
| Audio or subtitles are missing | Confirm the input contains those streams and that the output command maps them. The example writes MKV and copies selected streams. |
| FFmpeg rejects a copied stream | Choose a container that supports the source stream or encode that stream to a compatible codec. |
| Output is larger than the source | Compare a short sample and raise CRF only if the visual result still meets your needs. |
| TV opens H.264 but rejects the file | Check the supported container and audio format in the device manual. The sample output uses MKV, which the target must also support. |
Subtitle streams need similar attention. The example maps and copies them into MKV, but a bitmap subtitle track may not be supported by another output container, and a target device may ignore a subtitle codec even when the file itself is valid.
FFmpeg’s codec and format support depends on the build and container. The stream-selection documentation describes mapping, while the codec manual covers encoder options. For output containers, see the formats manual and its list of supported muxers.
Conclusion
Make a new H.264 file, verify its streams, and keep the HEVC original until the target player handles the result. Choose the next guide by the task you need after the encode.
- For a graphical encoder, use the HandBrake setup guide for Linux.
- For a playback or missing-decoder issue, see multimedia codecs on Linux.
- For a home media server, follow the Jellyfin setup guide for Debian.
- For playback configuration, see how to configure mpv on Linux.
- To separate audio instead of retaining it, use the FFmpeg audio-extraction guide.
For command details, consult the FFmpeg manual and the ffprobe manual.
Keep a short test output around while you compare playback settings, but delete temporary comparison files when finished so they do not become mistaken for your source or final archive copy.
FAQ
These answers cover quality, size, and stream handling after an encode.
Does converting HEVC to H.264 preserve the original quality?
No. Re-encoding is lossy. A CRF setting can trade file size against retained detail, so inspect a sample before converting a full library.
Will the H.264 output always be smaller than the HEVC file?
No. H.264 may need more data than HEVC at a similar visual quality. Compare the output size and image quality rather than expecting a fixed reduction.
Does the example keep audio and subtitles?
The script maps optional audio and subtitle streams and copies them into an MKV output. A copied stream can still fail if its codec or the destination container is incompatible.
Do I need a GPU to encode H.264 with FFmpeg?
No. libx264 is a software encoder and can run on the CPU when the FFmpeg build includes it. Encoding speed depends on the processor and the chosen preset.
