Skip to content

Instantly share code, notes, and snippets.

@visualblind
Created November 2, 2025 09:59
Show Gist options
  • Select an option

  • Save visualblind/70fb354a91b815b9d86becad2bd90a84 to your computer and use it in GitHub Desktop.

Select an option

Save visualblind/70fb354a91b815b9d86becad2bd90a84 to your computer and use it in GitHub Desktop.
Ffmpeg Guide

This guide is primarily targeted at those who need to recursively transcode or remux their media using a shell environment.

Strip all subtitles from input file

# standard
ffmpeg -i inputfile -map 0:v -map 0:a -c:v copy -c:a copy outputfile
# alternatively you can use the '-sn' parameter:
ffmpeg -i inputfile -map 0 -sn -codec copy outputfile
# for loop
for f in *.mkv; do ffmpeg -i "$f" -map 0:v -map 0:a -c:v copy -c:a copy ./working/"${f/.mkv/.x264.mkv}"; done

Remove chapters if they exist

# standard
ffmpeg -i inputfile -map_chapters -1 outputfile
# for loop
for f in *.mkv; do ffmpeg -map 0 -map_chapters -1 -codec copy "${f/.mkv/-modified.mkv}"; done

Convert audio stream to AAC and insert subtitles stream from external srt file

# standard
ffmpeg -i inputfile -f srt -i subtitlefile -map 0:v -map 0:a -map 1:0 -c:v copy -c:a aac -c:s srt outputfile
# for loop
# requires subtitle files in same directory as input file with the same base name and srt file extension
for f in *.mkv; do ffmpeg -i "$f" -f srt -i "${f/.mkv/.srt}" -map 0:v -map 0:a -map 1:0 -c:v copy -c:a aac -c:s srt ./working/"${f/.mkv/.modified.mkv}"; done

Determine if audio stream is not using AAC codec and transcode into AAC, or not

for f in *.mkv; do
audioformat=$(ffprobe -loglevel error -select_streams a:0 -show_entries stream=codec_name -of default=nw=1:nk=1 "$f")
if [ "$audioformat" = "aac" ]; then
  echo -e '\nffprobe detected aac audio streams\nPreparing to copy english audio stream' ; sleep 4
  ffmpeg -i "$f" -map 0:v:0 -map 0:a:m:language:ger -map 0:a:m:language:eng -map 0:s:m:language:eng -movflags faststart -c:v libx264 -crf 23 -c:a copy -c:s copy "${f/x265/x264}"
  else
  echo -e '\nffprobe detectable audio streams not equal to aac\nPreparing to transcode with aac' ; sleep 4
  ffmpeg -i "$f" -map 0:v:0 -map 0:a:m:language:ger -map 0:a:m:language:eng -map 0:s:m:language:eng -movflags faststart -c:v libx264 -crf 23 -c:a aac -c:s copy "${f/x265/x264}"
fi
done

Convert 10/8bit HEVC/H.265 to 8bit AVC/H.264 MKV high profile slow preset, insert external SRT subtitle file and not-DEFAULT with English language

# standard
ffmpeg -y -i inputfile -f srt -i subtitlefile -map 0:v:0 -map 0:a:0 -map 1:0 -movflags faststart -profile:v high -pix_fmt yuv420p -preset slow -disposition:s:0 0 -metadata:s:s:0 language=eng -codec:v libx264 -codec:a copy -codec:s srt outputfile
# for loop
for f in *.mkv; do ffmpeg -y -i "$f" -f srt -i "${f/.mkv/.srt}" -map 0:v:0 -map 0:a:0 -map 1:0 -movflags faststart -profile:v high -pix_fmt yuv420p -preset slow -disposition:s:0 0 -metadata:s:s:0 language=eng -codec:v libx264 -codec:a copy -codec:s srt "${f/.mkv/-modified.mkv}"; done

How to map existing subtitle streams only if they exist

# standard
ffmpeg -y -i inputfile -map "0:s?" -codec:s copy outputfile
# for loop
for f in *.mkv; do ffmpeg -y -i "$f" -map "0:s?" -codec:s copy "${f/.mkv/-modified.mkv}"; done

Increase volume to 150% of original media

for f in *.mkv; do ffmpeg -i "$f" -map 0 -filter:a "volume=1.5" -c:v copy -c:a aac -c:s copy "${f/.mkv/-modified.mkv}"; done

Remove all data streams from the container

ffmpeg -i in.mp4 -c copy -dn -map_metadata:c -1 out.mp4
for f in *.mp4; do ffmpeg -i "$f" -c copy -dn -map_metadata:c -1 "$f"; done

Remove closed captions (CC)

ffmpeg -y -i input.mkv -map 0 -c copy -bsf:v "filter_units=remove_types=6" output.mkv
for f in *.mkv; do ffmpeg -y -i "$f" -default_mode infer_no_subs -map 0:v -map 0:a -map 0:s? -c:v copy -c:a copy -c:s copy -bsf:v "filter_units=remove_types=6" "${f/.mkv/-modified.mkv}"; done

Insert srt subtitle to mp4

ffmpeg -i inputfile -i subtitlefile -c:v copy -c:a copy -c:s mov_text outputfile
for f in *.mp4; do ffmpeg -y -i "$f" -i "${f/.mp4/.srt}" -c:v copy -c:a copy -c:s mov_text "${f/.mp4/-modified.mp4}"; done

Export clean Subrip (SRT) subtitle file without annoying font HTML tagging

# the trick is to use '-c:s text' instead of '-c:s srt' or '-c:s mov_text' in MP4's
for f in *.mp4; do ffmpeg -y -i "$f" -map 0:s? -c:s text "${f/.mp4/.srt}"; done

Change Display Aspect Ratio (DAR) in the container

# Sample Aspect Ratio = (SAR) and Display Aspect Ratio (DAR)
ffmpeg -i input.mp4 -map 0 -aspect 1:1 -codec copy output.mp4
ffmpeg -i input.mkv -map 0 -aspect 2.39 -codec copy output.mkv

Change the Sample Aspect Ratio (SAR) in the video stream

ffmpeg -i in.mp4 -c copy -bsf:v "h264_metadata=sample_aspect_ratio=4/3" out.mp4

Increase max muxing queue size

ffmpeg -i 'input.mkv' -max_muxing_queue_size 400 'output.mkv'

Remove subtitle and audio description/title and add english metadata

for f in *.mkv; do ffmpeg -y -i "$f" -codec copy -metadata:s:a:0 language=eng -metadata:s:a:0 title= -metadata:s:s:0 language=eng -metadata:s:s:0 title= ./working/"${f}"; done

Add text metadata to various sections of file

ffmpeg -y -i input.mkv -codec copy -metadata comment="Matroska muxer also accepts free-form key/value metadata pairs" -metadata foo="bar" -metadata description="Matroska muxer description" -metadata:s:v:0 title="Video stream title/description" -metadata:s:a:0 title="Audio stream title/description" -metadata:s:s:0 language=eng -metadata:s:s:0 title="Subtitle stream title/description" output.mkv
for f in *.mkv; do ffmpeg -y -i "$f" -codec copy -metadata comment="Matroska muxer also accepts free-form key/value metadata pairs" -metadata foo="bar" -metadata description="Matroska muxer description" -metadata:s:v:0 title="Video stream title/description" -metadata:s:a:0 title="Audio stream title/description" -metadata:s:s:0 language=eng -metadata:s:s:0 title="Subtitle stream title/description" ./working/"${f}"; done

Add Matroska Title metadata to the container while removing Title metadata from all of its streams (video, audio, subtitle)

ffmpeg -y -i input.mkv -f srt -i input.en.srt -map 0:v -map 0:a:1 -map 1:0 -movflags +faststart -metadata:s:v:0 language= -metadata:s:s:0 language=eng -metadata:s:v:0 Title= -metadata:s:a:0 Title= -metadata:s:s:0 Title= -metadata Title="Who Am I (1998)" -disposition 0 -disposition:s:1 default -c:v copy -c:a copy -c:s srt output.mkv

Change the Constant Rate Factor (CRF) which modifies output video quality and file size

ffmpeg -i inputfile -vcodec libx264 -crf 23 outputfile

Change/scale the video screen-size (for example to 1080p or half its pixel size)

ffmpeg -i inputfile -vf "scale=iw/2:ih/2" outputfile

# This method takes care of error: (libx264) "height not divisible by 2"
# https://stackoverflow.com/questions/20847674/ffmpeg-libx264-height-not-divisible-by-2
# https://superuser.com/questions/624563/how-to-resize-a-video-to-make-it-smaller-with-ffmpeg
ffmpeg -y -i "input.mp4" \
-map 0:v -map 0:a -dn -map_chapters -1 -filter:v scale="1920:trunc(ow/a/2)*2" \
-movflags faststart -profile:v high -pix_fmt yuv420p -metadata:s:a:0 language=eng \
-c:v libx264 -c:a copy "output.mp4"

##### Another one but different
ffmpeg -y -i "input.mp4" -map 0:v -map 0:a \
-dn -map_chapters -1 -metadata:s:v:0 handler_name= -metadata:s:a:0 handler_name= \
-vf pad=ceil(iw/2)*2:ceil(ih/2)*2 -movflags faststart -profile:v high -pix_fmt yuv420p \
-metadata:s:a:0 language=eng -c:v libx264 -c:a copy "output.mp4"

Brighten only dark scenes in a media file

# https://ffmpeg.org/ffmpeg-filters.html#eq
# To brighten only the dark scenes in a media file using FFmpeg, you can use the eq filter with a higher brightness value for dark scenes and a lower value for bright scenes. This will make the darker areas appear brighter while maintaining the brightness of the brighter areas.

1. Identify the threshold:
Determine a value for the brightness increase. This value will determine how much brighter the dark scenes will become.
2. Use the eq filter:
FFmpeg\'s eq filter allows you to adjust brightness, contrast, and gamma. Use the following format:

    ffmpeg -i input.mp4 -vf "eq=brightness=brightness_value:contrast=contrast_value:saturation=saturation_value:gamma=gamma_value" output.mp4

* brightness_value: The value to increase brightness by (e.g., 0.1 for a 10% increase).
* contrast_value: The value to adjust the contrast by (e.g., 1.0 for no change, 1.2 for a 20% increase).
* saturation_value: The value to adjust saturation by (e.g., 1.0 for no change, 1.5 for a 50% increase).
* gamma_value: The value to adjust gamma by (e.g., 1.0 for no change, 1.5 for a 50% increase).

## Important Notes

> IMPORTANT TIP: The legacy FFmpeg video filter for color correction, including brightness, contrast, and saturation, was mp=eq2. It has since been deprecated and replaced by the eq filter.
> Attempting to use mp=eq2 in modern FFmpeg versions will result in an error.

The eq filter provides the same functionality with updated syntax. Here is an example of how the syntax changed:

### Legacy mp=eq2 syntax

ffmpeg -i input.mp4 -vf mp=eq2=contrast:brightness:saturation:gamma output.mp4

### Modern eq Filter Syntax

ffmpeg -i input.mp4 -vf eq=contrast=1.5:brightness=-0.1:saturation=1.2 output.mp4

The options can be specified by name, separated by colons (:), for clarity and to avoid the order-dependent issues of the older filter.

### Trial and Error

You might need to experiment with different brightness_value settings to achieve the desired result.

### Over-brightening

Be careful not to over-brighten the video, as it can cause white parts to appear washed out.

### Other Filters

You could also use other filters like gamma=1:1:1 for adjusting gamma.

## Example with Gamma Adjustment

    ffmpeg -i input.mp4 -vf "eq=brightness=0.1:contrast=1.2:saturation=1.5:gamma=1.2" output.mp4

This command will increase the brightness by 10% (brightness=0.1), increase contrast by 20% (contrast=1.2), increase the saturation by 50% (saturation=1.5), and increase gamma by 20% (gamma=1.2).
In summary, by using the eq filter and experimenting with brightness, contrast, saturation, and gamma values, you can effectively brighten only the dark scenes in your media file while preserving the brightness of the already bright scenes.

ffprobe: Output filename, audio codec name, and number of channels

find . -mount -depth -maxdepth 1 -regextype posix-extended -regex '.*\.mkv$|.*\.mp4$' -type f -exec bash -c 'echo "{}" $(ffprobe -loglevel error -select_streams a:0 -show_entries stream=codec_name,channels -of default=nw=1:nk=1 "{}")' \;

ffprobe: Output filename, and video codecs

find . -mount -depth -maxdepth 1 -regextype posix-extended -regex '.*\.mkv$|.*\.mp4$' -type f -exec bash -c 'echo "{}" $(ffprobe -loglevel error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "{}")' \;

ffprobe: Output filename and video bit depth

find . -mount -depth -maxdepth 1 -regextype posix-extended -regex '.*\.mkv$|.*\.mp4$' -type f -exec bash -c 'echo "{}" $(ffprobe -loglevel error -select_streams v:0 -show_entries stream=bits_per_raw_sample -of default=nw=1:nk=1 "{}")' \;

Incorporating Bash arithmetic into ffmpeg command

for f in *.mkv; do ffmpeg -y -i "${f}" -i "${f/.mkv/.m4a}" \
-c:v copy -b:a:0 128k -filter_complex "[a:0]aresample=async=1000[a:0]" -movflags faststart -c:a:0 aac -c:a:1 copy -c:s copy \
-map 0:v:0 -map 1:0 -map 0:a:0 $(i=1; while [ $i -lt 28 ]; do echo -n "-map 0:s:$((i++)) "; done) \
-metadata:s:a:0 language=eng -disposition 0 -disposition:a:0 default -disposition:s:0 default -metadata:s:s:0 title= \
-metadata:s:a comment= -shortest "${f/.mkv/-modified.mkv}"; done

Change the H.264 profile to Baseline

ffmpeg -i inputfile -profile:v baseline outputfile

Concatenate multiple media files

# https://trac.ffmpeg.org/wiki/Concatenate
for f in *.mkv; do echo "file '$f'" >> mylist.txt; done
ffmpeg -f concat -safe 0 -i "mylist.txt" "output.mkv"

Map only the languages you want in the audio and subtitle streams

# With this example we will only map the English audio and subtitle streams if they exist:
ffmpeg -y -i "input.mkv" -map 0:v:0 -map 0:a:m:language:eng -map "0:s:m:language:eng?" -c:v copy -codec:a copy -c:s srt "output.mkv"
for f in *.mkv; do ffmpeg -y -i "$f" -map 0:v:0 -map 0:a:m:language:eng -map "0:s:m:language:eng?" -c:v copy -c:a copy -c:s copy "path/$f"; done

Exclude only VobSub subtitles while copying all other subtitle streams using stream-based mapping with a negative filter

ffmpeg -i input.mkv -map 0 -map -0:s:m:handler_name:!dvd_subtitle -c copy output.mkv
for f in *.mkv; do ffmpeg -y -i "$f" -map 0 -map -0:s:m:handler_name:!dvd_subtitle -c copy "path/$f"; done

Insert arbitrary audio stream and alter the starttime offset with '-itsoffset' paramter

ffmpeg -y -i inputfile -itsoffset -500ms -f aac -i 'audio.aac' -map 0:v -map 1:0 -map 0:a:0 \
-disposition:a:0 default -disposition:a:1 0 -metadata:s:a:0 language=eng -metadata:s:a:1 \
language=eng -fflags +bitexact -flags:v +bitexact -flags:a +bitexact -ac 2 -c:v copy \
-c:a:0 aac -c:a:1 copy outputfile

Bitrate Guidelines

# Calculate the bitrate you need by dividing your target size (in bits)
# by the video length (in seconds). For example for a target size of
# 1 GB (one gigabyte, which is 8 gigabits) and 10,000 seconds of video
# (2:h 46 min 40 s), use a bitrate of 800 000 bit/s (800 kbit/s):
ffmpeg -i input.mp4 -b 800k output.mp4

Transcode avi files into standard mp4 containers

for f in **/*.avi; do ffmpeg -i "$f" -map 0:v:0 -map 0:a -dn -map_chapters -1 \
-movflags faststart -profile:v high -pix_fmt yuv420p -metadata:s:a:0 language=eng \
-metadata:s:v:0 title= -metadata:s:a:0 title= -c:v libx264 -c:a aac \
"../.working/${f/.avi/.mp4}"; done

Convert interlaced to progressive (1080i -> 1080p)

ffmpeg -i inputfile -vf yadif -c:v libx264 -preset slow -crf 19 -c:a aac -b:a 192k -c:s srt -max_muxing_queue_size 400 outputfile
ffmpeg -i "interlaced.mkv" -vf yadif=1 -movflags +faststart -y -preset fast -profile:v high -crf 20 -ac 2 -b:a 192k -strict experimental -c:v libx264 -c:a aac "progressive.mkv"
# yadif=0 is normally the preferred option when deinterlacing video as yadif=1 will double the frame-rate of the output video
ffmpeg -i "interlaced.mkv" -vf yadif=0 -y -preset fast -profile:v high -crf 20 -ac 2 -b:a 192k -strict experimental -c:v libx264 -c:a aac "progressive.mkv"

H.264 interlaced BT709 > H.264 progressive BT709

ffmpeg -i inputfile -default_mode infer_no_subs -map 0 -map_chapters -1 -dn -vf "yadif=0, colorspace=all=bt709:iall=bt601-6-625:fast=1" -colorspace 1 -color_primaries 1 -color_trc 1 -b:v 6M -bufsize 6M -minrate 3M -maxrate 10M -profile:v high -pix_fmt yuv420p -preset slow -channel_layout "5.1" -strict experimental -max_muxing_queue_size 400 -c:v libx264 -c:a aac -c:s copy outputfile

Nvidia Hardware Accelerated Latency-Tolerant High-Quality H.264 Transcoding

# standard
ffmpeg -y -vsync 0 -hwaccel cuda -hwaccel_output_format cuda -i inputfile -c:a copy -c:v h264_nvenc -preset p6 -tune hq -b:v 5M -bufsize 5M -maxrate 10M -qmin 0 -g 250 -bf 3 -b_ref_mode middle -temporal-aq 1 -rc-lookahead 20 -i_qfactor 0.75 -b_qfactor 1.1 outputfile

Nvidia HW accelerated H264 10-bit to 8-bit BT709 color

# for loop
for f in *.mkv; do ffmpeg -vsync 0 -hwaccel cuda -y -i "$f" -map 0 -profile:v high -pix_fmt yuv420p -preset slow -vf "colorspace=all=bt709:iall=bt601-6-625:fast=1" -colorspace 1 -color_primaries 1 -color_trc 1 -codec:v h264_nvenc -codec:a copy -codec:s copy "${f/.mkv/-modified.mkv}"; done

Nvidia HW Accelerated H.264 interlaced BT709 > H.264 progressive BT709

# standard
ffmpeg -vsync 0 -hwaccel cuda -y -i inputfile -map 0 -vf "yadif=0, colorspace=all=bt709:iall=bt601-6-625:fast=1" -profile:v high -pix_fmt yuv420p -preset slow -c:v h264_nvenc -c:a copy -c:s copy outputfile
# real-world example
ffmpeg -vsync 0 -hwaccel cuda -y -i inputfile.mkv -default_mode infer_no_subs -map 0 -map_chapters -1 -dn -metadata title="Movie Title" -metadata:s:v:0 title= -metadata:s:a:0 title= -vf "yadif=0, colorspace=all=bt709:iall=bt601-6-625:fast=1" -colorspace 1 -color_primaries 1 -color_trc 1 -b:v 6M -bufsize 6M -minrate 3M -maxrate 10M -profile:v high -pix_fmt yuv420p -preset slow -channel_layout "5.1" -strict experimental -max_muxing_queue_size 400 -c:v h264_nvenc -c:a aac -c:s copy outputfile.mkv

For looped Nvidia HW-accelerated h264_nvenc PAL bt601/bt470bg > NTSC transcoding

# verbose for loop:
for VAR in 01 02 03 04 05 06 07 08 09 10 11 12 13; do ffmpeg -vsync 0 -hwaccel cuda -y -i "VTS_$(echo $VAR)_1.VOB" -movflags faststart -map 0:v:0 -map 0:a:0 -dn -map_chapters -1 -profile:v high -pix_fmt yuv420p -preset slow -x264-params "iall=bt601-6-625:fast=1" -color_range 1 -colorspace bt470bg -color_primaries bt470bg -color_trc gamma28 -metadata title="Title (year) S01E$(echo $VAR)" -metadata:s:a:0 title= -metadata:s:a:0 language=eng -disposition:s 0 -b:v 2500k -minrate 1000k -maxrate 2500k -b:a 128k -codec:v h264_nvenc -channel_layout:a:0 "stereo" -codec:a aac "Title - S01E$VAR.mp4"; done
# less-verbose for loop:
for VAR in {01..13}; do ffmpeg -vsync 0 -hwaccel cuda -y -i "VTS_$(echo $VAR)_1.VOB" -movflags faststart -map 0:v:0 -map 0:a:0 -dn -map_chapters -1 -profile:v high -pix_fmt yuv420p -preset slow -x264-params "iall=bt601-6-625:fast=1" -color_range 1 -colorspace bt470bg -color_primaries bt470bg -color_trc gamma28 -metadata title="Title (year) S01E$(echo $VAR)" -metadata:s:a:0 title= -metadata:s:a:0 language=eng -disposition:s 0 -b:v 2500k -minrate 1000k -maxrate 2500k -b:a 128k -codec:v h264_nvenc -channel_layout:a:0 "stereo" -codec:a aac "Title - S01E$VAR.mp4"; done

H264 10-bit to 8-bit BT709 color

for f in *.mkv; do ffmpeg -y -i "$f" -default_mode infer_no_subs -map 0:v:0 -map 0:a -map "0:s?" -dn -map_chapters -1 -profile:v high -pix_fmt yuv420p -preset slow -vf "colorspace=all=bt709:iall=bt601-6-625:fast=1" -colorspace 1 -color_primaries 1 -color_trc 1 -metadata:s:a:0 title= -codec:v libx264 -codec:a copy -codec:s copy "${f/.mkv/-modified.mkv}"; done

Convert H.265 > H.264 and convert 6CH AC3 audio to AAC and copy only the first subtitle stream

find . -depth -name '*.mkv' -type f -exec bash -c 'ffmpeg -i "$0" -map 0:v:0 -map 0:a:0 -map 0:s:0? -movflags faststart -c:v libx264 -ac 6 -ar 48000 -b:a 768k -channel_layout "5.1" -c:a aac -c:s copy -crf 23 "${0/x265/x264}"' {} \;

Convert H.265 > H.264 and convert 6CH AC3 audio to AAC and copy all subtitle streams

find . -depth -name '*x265*.mkv' -type f -exec bash -c 'ffmpeg -i "$0" -map 0:v:0 -map 0:a:0 -map 0:s? -movflags faststart -c:v libx264 -ac 6 -ar 48000 -b:a 768k -channel_layout "5.1" -c:a aac -c:s copy -crf 23 "${0/x265/x264}"' {} \;; find . -name '*x265*' -type f -delete

Convert H.265 > H.264 and retain original audio and all subtitles

find . -depth -name '*x265*.mkv' -type f -exec bash -c 'ffmpeg -i "$0" -map 0:v:0 -map 0:a:0 -map 0:s? -movflags faststart -c:v libx264 -preset slow -c:a copy -c:s copy -crf 23 "${0/x265/x264}"' {} \;; find . -name '*x265*' -type f -delete

Copy original video stream and convert 6CH AC3 audio to AAC and copy all subtitle streams

find . -depth -name '*x265*.mkv' -type f -exec bash -c 'ffmpeg -i "$0" -map 0:v:0 -map 0:a:0 -map 0:s? -c:v copy -ac 6 -ar 48000 -b:a 384k -channel_layout "5.1" -c:a aac -c:s copy "${0/x265/x264}"' {} \;; find . -name '*x265*' -type f -delete

Constant frame-rate with variable bitrate (VBR) nvidia hw-accel transcoding

# one-liner: Constant frame-rate with variable bitrate (VBR) nvidia hw-accel transcoding
for f in *.mkv; do ffmpeg -vsync 2 -hwaccel cuda -y -i "$f" -default_mode infer_no_subs -map 0 -map_chapters -1 -dn -metadata title="${f/.mkv/}" -metadata:s:v:0 title= -metadata:s:a:0 title= -colorspace 1 -color_primaries 1 -color_trc 1 -r 24 -b:v 5M -minrate 3M -maxrate 8M -bufsize 10M -profile:v high -pix_fmt yuv420p -preset slow -strict experimental -max_muxing_queue_size 400 -c:v h264_nvenc -c:a copy -c:s copy "$f"; done

# multi-lined: Constant frame-rate with variable bitrate (VBR) nvidia hw-accel transcoding
for f in *.mkv; do ffmpeg -vsync 2 -hwaccel cuda -y -i "$f" -default_mode infer_no_subs \
-map 0 -map_chapters -1 -dn -metadata title="${f/.mkv/}" -metadata:s:v:0 title= \
-metadata:s:a:0 title= -colorspace 1 -color_primaries 1 -color_trc 1 -r 24 \
-b:v 5M -minrate 3M -maxrate 8M -bufsize 10M -profile:v high -pix_fmt yuv420p -preset slow \
-strict experimental -max_muxing_queue_size 400 -c:v h264_nvenc -c:a copy -c:s copy \
"$f"; done

Generate thumbnails from video

# adjust the fps interval to change the number of thumbnails generated
ffmpeg -loglevel verbose -i 'input.mkv' -vf fps=1/1000 thumb-%03d.jpg
# add "-discard nokey" in order to generate thumbnails faster since it does not need to scan the file for every keyframe
ffmpeg -discard nokey -i 'input.mkv' -vf fps=1/300 thumb-%03d.png

vsync 1 CFR, cq = 30, avi > mp4

for f in *.avi; do ffmpeg -loglevel verbose -vsync 1 -hwaccel cuda -y -i "$f" -f srt -i "${f/avi/srt}" -map 0:v:0 -map 0:a -map 1:0 -dn -map_chapters -1 -movflags faststart -metadata title= -metadata:s:v:0 title= -metadata:s:a:0 title= -metadata creation_time="$(date --iso-8601=seconds)" -metadata:s:v creation_time="$(date --iso-8601=seconds)" -metadata:s:a creation_time="$(date --iso-8601=seconds)" -metadata:s:a:0 language=eng -metadata:s:s:0 title= -metadata:s:s:0 language=eng -pix_fmt yuv420p -disposition:s:0 0 -c:v h264_nvenc -profile:v high -preset p5 -tune hq -b:v 0 -cq 30 -level:v 4.1 -rc vbr -cbr:v false -channel_layout "stereo" -c:a aac -c:s mov_text "${f/.avi/.mp4}"; done

vsync 2 VFR, cq = 28, avi > mp4

for f in *.avi; do ffmpeg -loglevel verbose -vsync 2 -hwaccel cuda -y -i "$f" -f srt -i "${f/avi/srt}" -map 0:v:0 -map 0:a -map 1:0 -dn -map_chapters -1 -movflags faststart -metadata title= -metadata:s:v:0 title= -metadata:s:a:0 title= -metadata creation_time="$(date --iso-8601=seconds)" -metadata:s:v creation_time="$(date --iso-8601=seconds)" -metadata:s:a creation_time="$(date --iso-8601=seconds)" -metadata:s:a:0 language=eng -metadata:s:s:0 title= -metadata:s:s:0 language=eng -pix_fmt yuv420p -disposition:s:0 0 -r 24 -c:v h264_nvenc -profile:v high -preset p5 -tune hq -b:v 0 -cq 28 -level:v 4.1 -rc vbr -cbr:v false -channel_layout "stereo" -c:a aac -c:s mov_text "${f/.avi/.mp4}"; done

vsync 1 CFR, cq = 30, mp4 > mp4

for f in *.mp4; do ffmpeg -loglevel verbose -vsync 1 -hwaccel cuda -y -i "$f" -f srt -i "${f/avi/srt}" -map 0:v:0 -map 0:a -map 1:0 -dn -map_chapters -1 -movflags faststart -metadata title= -metadata:s:v:0 title= -metadata:s:a:0 title= -metadata creation_time="$(date --iso-8601=seconds)" -metadata:s:v creation_time="$(date --iso-8601=seconds)" -metadata:s:a creation_time="$(date --iso-8601=seconds)" -metadata:s:a:0 language=eng -metadata:s:s:0 title= -metadata:s:s:0 language=eng -pix_fmt yuv420p -disposition:s:0 0 -c:v h264_nvenc -profile:v high -preset p5 -tune hq -b:v 0 -cq 30 -level:v 4.1 -rc vbr -cbr:v false -channel_layout "stereo" -c:a aac -c:s mov_text "${f/.avi/.mp4}"; done

vsync 1 CFR of 24fps (-r 24), cq = 28

for f in *.mkv; do ffmpeg -loglevel verbose -vsync 1 -hwaccel cuda -y -i "$f" -default_mode infer_no_subs -map 0:v:0 -map 0:a -map "0:s?" -dn -map_chapters -1 -r 24 -metadata title= -metadata:s:v:0 title= -metadata:s:a:0 title= -metadata creation_time="$(date --iso-8601=seconds)" -metadata:s:v creation_time="$(date --iso-8601=seconds)" -metadata:s:a creation_time="$(date --iso-8601=seconds)" -pix_fmt yuv420p -disposition:s:0 0 -c:v h264_nvenc -profile:v high -preset p5 -tune hq -b:v 0 -cq 28 -level:v 4.1 -rc vbr -cbr:v false -c:a copy -c:s copy "${f/.mkv/-modified.mkv}"; done

vsync 1 CFR, cq = 28, variable bit rate, keep existing frame rate

for f in *.mkv; do ffmpeg -loglevel info -vsync 1 -hwaccel cuda -y -i "$f" -default_mode infer_no_subs -map 0:v:0 -map 0:a -map "0:s?" -dn -map_chapters -1 -metadata title= -metadata:s:v:0 title= -metadata:s:a:0 title= -metadata creation_time="$(date --iso-8601=seconds)" -metadata:s:v creation_time="$(date --iso-8601=seconds)" -metadata:s:a creation_time="$(date --iso-8601=seconds)" -pix_fmt yuv420p -disposition:s:0 0 -c:v h264_nvenc -profile:v high -preset p5 -tune hq -b:v 0 -cq 28 -level:v 4.1 -rc vbr -cbr:v false -channel_layout "5.1" -c:a aac -c:s copy "${f/.mkv/-modified.mkv}"; done

vsync 1 CFR, cq = 23, variable bit rate, keep existing frame rate

for f in *.mkv; do ffmpeg -loglevel info -vsync 1 -hwaccel cuda -y -i "$f" -default_mode infer_no_subs -map 0:v:0 -map 0:a -map "0:s?" -dn -map_chapters -1 -metadata title= -metadata:s:v:0 title= -metadata:s:a:0 title= -metadata creation_time="$(date --iso-8601=seconds)" -metadata:s:v creation_time="$(date --iso-8601=seconds)" -metadata:s:a creation_time="$(date --iso-8601=seconds)" -pix_fmt yuv420p -disposition:s:0 0 -c:v h264_nvenc -profile:v high -preset p5 -tune hq -b:v 0 -cq 23 -level:v 4.1 -rc vbr -cbr:v false -channel_layout "5.1" -c:a aac -c:s copy "${f/.mkv/-modified.mkv}"; done

stream copy/remux, not changing much except for subtitle deposition and other minor changes

for f in *.mkv; do ffmpeg -y -i "$f" -default_mode infer_no_subs -map 0 -dn -metadata title= -metadata:s:v:0 title= -metadata:s:a:0 title= -metadata creation_time="$(date --iso-8601=seconds)" -metadata:s:v creation_time="$(date --iso-8601=seconds)" -metadata:s:a creation_time="$(date --iso-8601=seconds)" -disposition:v:0 default -disposition:a:0 default -disposition:s 0 -c:v copy -c:a copy -c:s copy "$f"; done

avi > mp4 transcoding, constant frame rate at 24fps, variable bit rate, cq 28

for f in */**.avi; do ffmpeg -loglevel verbose -vsync 1 -hwaccel cuda -y -i "$f" -default_mode infer_no_subs -map 0:v:0 -map 0:a -map "0:s?" -movflags faststart -dn -map_chapters -1 -r 24 -metadata title= -metadata:s:v:0 title= -metadata:s:a:0 title= -metadata:s:a:0 language=eng -metadata creation_time="$(date --iso-8601=seconds)" -metadata:s:v creation_time="$(date --iso-8601=seconds)" -metadata:s:a creation_time="$(date --iso-8601=seconds)" -pix_fmt yuv420p -disposition:s:0 0 -disposition:v:0 default -disposition:a:0 default -c:v h264_nvenc -profile:v high -preset p5 -tune hq -b:v 0 -cq 28 -level:v 4.1 -rc vbr -cbr:v false -channel_layout:a:0 "stereo" -c:a aac -c:s srt "${f/avi/mp4}"; done

INTERNAL MEDIA TERMINOLOGIES

CFR = Constant Frame Rate
VFR = Variable Frame Rate
CBR = Constant Bit Rate
VBR = Variable Bit Rate

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment