ffmpeg

ffmpeg #

List encoders available in ffmpeg: #

  • ffmpeg -encoders
  • ffmpeg -encoders | grep nvenc
  • ffmpeg -h encoder=hevc_nvenc to know more about the options available for the encoder.

See video metadata #

The ffprobe gathers information from multimedia streams and prints it in human- and machine-readable fashion. ffprobe -i video.mkv

Converting a video to HVEC/H.265 #

It’s done by the -c:v parameter:

ffmpeg -i input.mov -map_metadata 0 -c:v libx265 -x265-params "lossless=1" output.mp4

If you want to use the GPU (Nvidia), do -c:v hevc_nvenc instead. Doing ffmpeg -h encoder=hevc_nvenc you can know all the options available for the encoder.

ffmpeg -h encoder=hevc_nvenc
ffmpeg -i .input.mkv -map_metadata 0 -c:v hevc_nvenc -tune hq output.mp4

Choosing the metadata, subtitles and audio #

It´s done by the -map parameter.

Keeping all the video, audio and subtitle streams from input 1:

ffmpeg.exe -i '.\sample.mkv' -map 0:v -map 0:a -map 0:s -map_metadata 0 -c:v hevc_nvenc -tune hq filme.mkv

Keeping the video, but only audio 2 and subtitle 3 from input 1. Notice that it is indexed by 0:

ffmpeg.exe -i '.\sample.mkv' -map 0:v -map 0:a:1 -map 0:s:2 -map_metadata 0 -c:v hevc_nvenc -tune hq filme.mkv

The 1st video stream, 2nd audio stream, all subtitles:

ffmpeg -i input -map 0:v:0 -map 0:a:1 -map 0:s -c copy output

The 3rd video stream, all audio streams, no subtitles. This example uses negative mapping to exclude the subtitles:

ffmpeg -i input -map 0:v:2 -map 0:a -map -0:s -c copy output

Choosing streams from multiple inputs. All video from input 0, all audio from input 1:

ffmpeg -i input0 -i input1 -map 0:v -map 1:a -c copy output

Trimming a video #

Without re-encoding:

ffmpeg -ss 00:45:00 -i huge_video.mp4 -to 00:05:00 -c copy clipped.mp4

Running ffmpeg using different combinations of parameters #

$filter = "*_video.mp4"
$files = Get-ChildItem -Filter $filter

$nvencPresets = @("p1", "p4", "p7")
$nvecTunes = @("hq", "uhq", "ll", "ull")
$targetQualityLevel = @("0", "10", "15", "20", "25", "30", "35", "40", "45", "50")

$variableBitrate = "-rc vbr -b:v 0"
$pixFormat = "-pix_fmt yuv444p"
$mapVideoAudioSubs = "-map 0:v" #-map 0:a -map 0:s"
$mapFileMetadata = "-map_metadata 0 -movflags use_metadata_tags"
$from = "-ss 7"
$duration = "-t 5"
$scales = @("350", "480", "720", "1080", "1440", "2160", "4320")

foreach ($preset in $nvencPresets) {
  foreach ($tune in $nvecTunes) {
    foreach ($targetQuality in $targetQualityLevel) {
      foreach ($scale in $scales) {
        $scaleArg = "-vf scale=-1:" + $scale
        foreach ($file in $files) {
            $theCommand = "ffmpeg $from -i $file $duration $mapFileMetadata $mapVideoAudioSubs "
            $newname = $file.Name.Remove($file.Name.Length - $file.Extension.Length)
            $newname += "." + $scale + "p.ffmpeg.nvenc.cq_$targetQuality.tune_$tune.preset_$preset.mkv"
            $theCommand += " -c:v hevc_nvenc $scaleArg -tune $tune -cq $targetQuality $variableBitrate $pixFormat -preset $preset $newname"
            $currentDateTime = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
            $currentDateTime + "; " + $theCommand | Out-File -FilePath "$($file)_ffmpeg_commands_executed.log" -Encoding utf8 -Append
            Invoke-Expression $theCommand

            # comparision video using images: optional
            $outputDirectory = "comparison_images"
            $scaleHeight = 1080
            # Create a directory to store the comparison images
            if (-not (Test-Path $outputDirectory)) {
                New-Item -Path $outputDirectory -ItemType Directory
            }

            $frame1 = "$outputDirectory/frame1.png"
            $frame2 = "$outputDirectory/frame2.png"
            $output = "$outputDirectory/comparison_$newname.jpg"
            $extractFrameCmd = "ffmpeg $from -i $file -vframes 1 -q:v 1 $frame1"
            Invoke-Expression $extractFrameCmd
            $extractFrameCmd = "ffmpeg -i $newname -vframes 1 -q:v 1 $frame2"
            Invoke-Expression $extractFrameCmd

            $label1 = "Original: $file"
            $bitrate = $(ffprobe -v error -show_entries format=bit_rate -of default=noprint_wrappers=1:nokey=1  $newname)
            $label2 = "Compressed. Preset: $preset; Tune: $tune; CQ: $targetQuality; Scale: $scale; Bitrate: $bitrate;"
            magick mogrify -gravity northwest -pointsize 20 -fill black -annotate +18+18 $label1 -fill white -annotate +16+16 $label1 $frame1
            magick mogrify -gravity northwest -pointsize 20 -fill black -annotate +18+18 $label2 -fill white -annotate +16+16 $label2 $frame2

            ffmpeg -i $frame1 -i $frame2 -filter_complex "[0]scale=-1:$scaleHeight[frame1]; [1]scale=-1:$scaleHeight[frame2]; [frame1][frame2]hstack=inputs=2" -q:v 1 $output

            Remove-Item $frame1, $frame2

        }
      }
    }
  }
}

Compare videos side by side #

$video1 = "original.mp4"
$video2 = "otherVideo.mkv"
$output = "comparision_video1_video2.mp4"
$duration = 10

# Create comparision video
ffmpeg -i $video1 -i $video2 -filter_complex "[0:v]scale=-1:2160[vid1]; [1:v]scale=-1:2160[vid2]; [vid1][vid2]hstack=inputs=2" -c:v hevc_nvenc -preset p1 -tune lossless -t $duration $output

Compare videos side by side using images #


$video1 = "video1.mp4"
$video2 = "video2.mp4"

$outputDirectory = "comparison_images"
$interval = 10
$scaleHeight = 1080
$duration = $(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 $video1)

# Create a directory to store the comparison images
if (-not (Test-Path $outputDirectory)) {
    New-Item -Path $outputDirectory -ItemType Directory
}

for ($timestamp = 0; $timestamp -lt $duration; $timestamp += $interval) {
    $frame1 = "$outputDirectory/frame$timestamp-a.png"
    $frame2 = "$outputDirectory/frame$timestamp-b.png"
    $frameCombined = "$outputDirectory/frame$timestamp-combined.png"
    ffmpeg -ss $timestamp  -i $video1 -vframes 1 -q:v 1 $frame1
    ffmpeg -ss $timestamp  -i $video2 -vframes 1 -q:v 1 $frame2
    $label1 = "Original: $video1"
    $label2 = "Compressed: $video2"
    magick mogrify -gravity northwest -pointsize 20 -fill black -annotate +18+18 $label1 -fill white -annotate +16+16 $label1 $frame1
    magick mogrify -gravity northwest -pointsize 20 -fill black -annotate +18+18 $label2 -fill white -annotate +16+16 $label2 $frame2
    ffmpeg -i $frame1 -i $frame2 -filter_complex "[0]scale=-1:$scaleHeight[frame1]; [1]scale=-1:$scaleHeight[frame2]; [frame1][frame2]hstack=inputs=2" -q:v 1 $frameCombined
}