Содержание

Скачивание потокового видео

youtube-dl

Скачать youtube-dl
Справка

# Обновить youtube-dl
youtube-dl.exe -U
# Скачать ролик в наилучшем возможном качестве
youtube-dl.exe https://www.youtube.com/watch?v=iIbYyHHieUQ
# Вывести все доступные форматы
youtube-dl.exe https://www.youtube.com/watch?v=iIbYyHHieUQ -F
# Скачать аудио и видео отдельно и склеить их
youtube-dl.exe https://www.youtube.com/watch?v=iIbYyHHieUQ -f 137+140
# Скачать аудио самого лучшего качества
youtube-dl.exe https://www.youtube.com/watch?v=iIbYyHHieUQ -f bestaudio
# Вытащить аудио и сконвертировать его в mp3 с качеством 8
# Качество с 0 (лучшее) до 9 (худшее), 8 хорошо для речи
youtube-dl.exe https://www.youtube.com/watch?v=iIbYyHHieUQ `
-x --audio-format mp3 --audio-quality 8
# Скачать самое свежее видео на канале,
# выбрать видео меньше 1000 пкс шириной + отдельно аудиодорожка в m4a,
# положить результат в папку, назвать файл по шаблону,
# убрать несовместимые с ASCII символы.
youtube-dl.exe https://www.youtube.com/channel/UCY649zJeJVhhJa-rvWThZ2g `
--playlist-end 1 -f [width<1000],m4a `
-o "%userprofile%\Downloads\AlexeyUtin-%(upload_date)s-%(title)s-%(id)s.%(ext)s" `
--restrict-filenames
# с индексом, перекодировать в mp3
& youtube-dl.exe -o '%(playlist_title)s/%(playlist_index)s %(title)s.%(ext)s' $url -f bestaudio -x --audio-format mp3 --audio-quality 0
# Скачать плейлист (лучшее аудио), переделать контейнер на opus без перекодировки
yt-dlp -o '%(artist)s - %(playlist_title)s/%(playlist_index)s %(title)s.%(ext)s' https://www.youtube.com/playlist?list=PLrxctldPFxGJACwafqa1juKhit2OUDvnQ -f bestaudio --remux-video opus
# получить имена видео на канале
& youtube-dl.exe https://www.youtube.com/user/user --flat-playlist --get-filename --playlist-end 5
# CSV - номер, имя, ссылка + данные в переменную list
[uri]$url = 'https://www.youtube.com/user/user'
& yt-dlp -i -o '%(playlist_index)s; %(title)s; %(id)s' `
$url.AbsoluteUri --get-filename |
ConvertFrom-Csv -Delimiter ';' -Header num,name,url |
select num,name,@{n="url";e={"https://www.youtube.com/watch?v=" + $_.url}} -OutVariable list |
Export-Csv "D:\temp\$($url.Segments[-1]).csv" -Delimiter ';' -NoTypeInformation -Encoding utf8
# Скачать все аудиофайлы роликов, в названии которых есть Вася Пупкин, после 1 января 2019 г, конвертировать в opus.
& yt-dlp "https://www.youtube.com/c/channel/videos" --match-title "Вася Пупкин" --dateafter 20190101 `
-f worstaudio -o "%(upload_date)s-%(title)s-%(id)s.%(ext)s" -x --audio-format opus
# Работа через прокси
& yt-dlp --proxy "http://user:password@proxy:port" url
# Через Tor Browser
& yt-dlp https://www.dailymotion.com/video/x188ngo --proxy socks5://localhost:9150 -f best
# Видео из Вконтакта
& youtube-dl -u LOGIN -p PASS "$url"
# Скачать видео из плейлиста (если не использовать --no-playlist, то скачается весь список)
& yt-dlp 'https://www.youtube.com/watch?v=iQn7ROnRBkg&list=PLd5tvoxcDFoG3_FdEKIINiio8eyOJh326&index=12' --no-playlist
# Vimeo: если ошибка "Cannot download embed-only video without embedding URL", то надо указать страницу, где это видео встроено:
& yt-dlp https://player.vimeo.com/video/123456789 --referer https://new.site.ru/student/lessons/1234567
# Скачать только субтитры (https://github.com/yt-dlp/yt-dlp#subtitle-options)
& yt-dlp.exe https://www.youtube.com/watch?v=link --skip-download --write-subs --sub-langs ru
# Автосубтитры
& yt-dlp.exe https://www.youtube.com/watch?v=link --skip-download --write-auto-subs --sub-langs ru
# Лучшее качество 720p
& yt-dlp https://www.youtube.com/watch?v=111111111 -f "best[height=720]"

Московская филармония

(зал Чайковского):

В Firefox нажать F12 для открытия инструментов разработчика, перейти на вкладку «Сеть» (или сразу нажать Ctrl+Shift+E), нажать F5 для перезапуска страницы. Найти в появившемся списке элементов ссылку на плейлист m3u8 или на сам файл mp4 в нужном качестве.

Выполнить в командной строке:

youtube-dl.exe --add-header "referer:http://meloman.facecast.net/v/facecast_player.swf" http://path/index.m3u8

invidious

Invidious is an alternative front-end to YouTube
https://github.com/iv-org/invidious
https://invidious.io

# Прямо в папке проекта (подкаталог invidious создастся сам):
git clone https://github.com/iv-org/invidious.git
# Скопировать файлы из подкаталога docker в корень,
# чтобы иметь возможность сборки Dockerfile из стороннего docker-compose
cp invidious/docker/* invidious
# Обновить локальный клон репозитория
cd invidious
git pull origin main

https://docs.invidious.io/Installation.md

Видео для тестов

Тестовые видеоролики: https://media.xiph.org/video/derf/

Мульфильм Big Buck Bunny

NewPipe

Для телефонов на Андроиде. https://newpipe.net/
Последнее время обновляется редко, и не успевает за изменениями самого Ютуба. Вот свежие беты:
https://github.com/TeamNewPipe/NewPipe/pull/9182

ffmpeg

Документация: http://ffmpeg.org/ffmpeg.html

Wiki: https://trac.ffmpeg.org/wiki/TitleIndex

Установка ffmpeg

  1. Use 7-Zip to unpack it in the folder of your choice.
  2. Open a command prompt with administrator's rights.
    NOTE: Use CMD.exe, do not use Powershell! The syntax for accessing environment variables is different from the command shown in Step 4 - running it in Powershell will overwrite your System PATH with a bad value.
  3. Run the command (see note below; in Win7 and Win10, you might want to use the Environmental Variables area of the Windows Control Panel to update PATH):
    setx /M PATH "path\to\ffmpeg\bin;%PATH%"

    Do not run setx if you have more than 1024 characters in your system PATH variable. See this post on SuperUser that discusses alternatives. Be sure to alter the command so that «path\to» reflects the folder path from your root to «ffmpeg\bin».

# Скачать последний билд в зависимости от разрядности ОС,
# распаковать и положить в $env:SystemDrive\scripts\ffmpeg
$url64 = 'https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-latest-win64-static.zip'
$url32 = 'https://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-latest-win32-static.zip'
$dfold = "$env:SystemDrive\scripts\"
$fffold = "$dfold" + 'ffmpeg'
$dfile = "$fffold" + '.zip'
 
if ((gcim win32_operatingsystem).OSArchitecture -match 64) {
Write-Host -fore DarkCyan "Качаю 64-битный ffmpeg"; curl $url64 -OutFile $dfile
}
else {
Write-Host -fore DarkCyan "Качаю 32-битный ffmpeg"; curl $url32 -OutFile $dfile
}
 
Expand-Archive "$dfile" -DestinationPath "$dfold" -Force
$latest = (gci "$dfold" -Directory -Filter ffmpeg-latest-*).FullName
mkdir "$fffold" -ErrorAction SilentlyContinue
Copy-Item "$latest\*" "$fffold" -Recurse -Force
Remove-Item $dfile,$latest -Force -Recurse
# Добавить путь в PATH в Powershell, требуются права админа
 
#Requires -RunAsAdministrator
$folder = Read-Host "Введите путь для добавления в PATH"
$test = Test-Path -Path "$folder"
 
if ($test -eq $true) {write-host -fore Yellow "Добавляем $folder, верно?"
$yes = Read-Host "Нажмите цифру 1, чтобы продолжить"
 
Switch ($yes) {
1 {
$value = $env:path  + ';' + "$folder"
Set-ItemProperty -Path 'Registry::HKLM\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH -Value "$value"
if ($? -eq $True) {write-host -fore Green "$folder успешно добавлен в PATH";sleep 2}
else {write-host -fore Red "Операция завершилась с ошибкой";sleep 2}
}
Default {write-host -fore Yellow "Отмена, выход";sleep 2}
    }
}
else {Write-Host -fore Red "Путь не существует, выход";sleep 2}

Примеры использования

# Сделать .mp4 из .ts без перекодировки
ffmpeg -i "C:\temp\input.ts" -c copy output.mp4
 
# Перекодировать wav в mp3 наилучшего качества
ffmpeg -i input.wav -q:a 0 output.mp3
 
# Склеить видео и аудио
ffmpeg -i input-video.mov -i input-audio.m4a -c copy output.mov
 
# Перекодировка DVD ISO в x265
# выбран 1 и 4 поток (видео и звук), начать со второй секунды
# обрезка - размер X:размер Y:отступ X:отступ Y
# отступы отсчитываются от верхнего левого угла кадра
ffmpeg -i '.\Forrest Gump.ISO' -map 0:1 -map 0:4 -c:v libx265 -vf crop=716:356:4:60 -ss 00:00:02 '.\Forrest Gump-cropped.mp4'
 
# В x265, первые 10 сек, сделать деинтерлейс.
ffmpeg -i '.\video.ts' -c:v libx265 -t 10 -vf yadif '.\video.mov'
 
# Из DVD в x264, взять только видео и одну звуковую дорожку
# Оставить интерлейс (по умолчанию - top field first, проверять порядок полей перед запуском!)
# звук - в кодек opus (160-192 kbps - Transparent with very low chance of artifacts)
ffmpeg -i "concat:VTS_01_1.VOB|VTS_01_2.VOB|VTS_01_3.VOB|VTS_01_4.VOB" -map 0:1 -map 0:2 -flags +ilme+ildct -c:a libopus -b:a 160k ./dvd.mp4
 
# Принудительно указать Bottom field first (для x264)
-flags +ilme+ildct -x264opts bff=1
# Принудительно указать Bottom field first (для x265)
-flags +ilme+ildct -x265-params interlace=bff
# --interlace <false|tff|bff>, --no-interlace
# 0. progressive pictures (default)
# 1. top field first
# 2. bottom field first
 
# Перекодировать в mp3, наихудшее качество, моно, ресэмплинг до 16 kHz (для речи)
# ресэмплинг фактически не оказывает влияния на размер файла, нет особого смысла использовать
& ffmpeg -i '.\input.webm' -ac 1 -ar 16000 -q:a 9 .\output.mp3
# opus для речи
& ffmpeg -i '.\input.webm' -ac 1 -b:a 24k ".\output.opus"
# Пакетная обработка (pwsh 7), https://devblogs.microsoft.com/powershell/powershell-foreach-object-parallel-feature/
#Requires -Version 7.0
$folder = "$env:userprofile\Music\folder"
$files = dir "$folder\*.opus"
cd "$folder"
mkdir .\recoded
 
$files |ForEach-Object -Parallel {
& ffmpeg -i "$($_.fullname)" -ac 1 -b:a 24k ".\recoded\$($_.name)"
} -ThrottleLimit (gcim win32_processor).ThreadCount
 
# Склеить несколько файлов без перекодирования (не MPEG-2, для него - concat:VTS_01_1.VOB|VTS_01_2.VOB)
$path = "D:\temp"
(gci "$path\*.mp4").fullname |% {"file '$_'" |Out-File "$path\list.txt" -Append -Encoding default}
mkdir "$path\output"
& ffmpeg -f concat -safe 0 -i "$path\list.txt" -c copy "$path\output\output-$((get-date).tostring("yy-MM-dd-hh-mm-ss")).mp4"
 
# Статическое изображение + аудио
& ffmpeg -f image2 -loop 1 -framerate 1 -i .\pic.jpg -i .\aud.mp3 -c:a copy -r 1 -shortest .\vid.mp4 -y
 
# Убрать аудиодорожку
& ffmpeg -i '.\videoAndAudio.mp4' -vcodec copy -an '.\videoOnly.mp4'
 
# VP9, CRF 40, первые 30 сек, моно
ffmpeg -i 'C:\temp\VID_20230323_210434.mp4' -c:v libvpx-vp9 -vf scale=1280:-1 -crf 40 -b:v 0 -t 30 -ac 1 'C:\temp\VID_20230323_210434.webm' -y

Аппаратное ускорение

# Поддерживаемые аппаратные методы
ffmpeg -hide_banner -hwaccels
Hardware acceleration methods:
cuda
dxva2
qsv
d3d11va
 
# Поддерживаемые аппаратные кодеки qsv
ffmpeg -encoders |select-string qsv
ffmpeg -decoders |select-string qsv
 
# Вывод опций
ffmpeg -h encoder=h264_qsv
ffmpeg -h encoder=hevc_qsv
 
# Intel Quick Sync (QSV)
# h264_qsv (global_quality (ICQ mode) is similar to crf mode of x264)
& ffmpeg -i .\2020-05-21-all.mov -c:v h264_qsv -profile:v high -global_quality:v 23 -look_ahead 1 -preset slow D:\temp\2020-05-21-all.mp4 -y
# hevc_qsv (main10 profile)
& ffmpeg -i ".\2018-04-25 10-59-32.3gp" -c:v hevc_qsv -profile:v main10 -pix_fmt p010le -global_quality:v 28 -preset slow ".\2018-04-25 10-59-32-hevc-23.mp4" -y
 
# Пакетная обработка
$folder = "$env:userprofile\Videos\archive"
$files = dir "$folder\*.avi"
cd "$folder"
 
foreach ($file in $files) {
# Профиль main10
& ffmpeg -i "$($file.fullname)" -c:v hevc_qsv `
-profile:v main10 -pix_fmt p010le -preset slow -global_quality:v 26 `
".\$($file.basename).mp4" -y
}

https://trac.ffmpeg.org/wiki/Hardware/QuickSync

Видеофильтры

normalize
Normalize RGB video (aka histogram stretching, contrast stretching).

hqdn3d - отличный, быстрый фильтр.
This is a high precision/quality 3d denoise filter. It aims to reduce image noise, producing smooth images and making still images really still. It should enhance compressibility - это правда.

bm3d - неплохо.
Denoise frames using Block-Matching 3D algorithm.

atadenoise - очень хорошо.
Apply an Adaptive Temporal Averaging Denoiser to the video input.

owdenoise - отлично, медленный.
Apply Overcomplete Wavelet denoiser.

removegrain - надо разбираться, сходу не понять.
The removegrain filter is a spatial denoiser for progressive video.

smartblur - очень хорошо.
Blur the input video without impacting the outlines.

vaguedenoiser - очень хорошо.
Apply a wavelet based denoiser.

Поворот видео

Rotate 90 clockwise:

ffmpeg -i in.mov -vf "transpose=1" out.mov

For the transpose parameter you can pass:

Use -vf "transpose=2,transpose=2" for 180 degrees.

Изменение размера (resize)

# Ширина 1280, высоту рассчитать кратно 1:
ffmpeg -i in.mov -vf scale=1280:-1 out.mov
# Кратно 2:
ffmpeg -i in.mov -vf scale=1280:-2 out.mov
# if you want to stretch the image in such a way to only double the width of the input image,
# you can use something like this (iw = input width, ih = input height): 
ffmpeg -i input.jpg -vf scale=iw*2:ih input_double_width.png
# If you want to half the size of the picture, just multiply by .5 or divide by 2: 
ffmpeg -i input.jpg -vf "scale=iw*.5:ih*.5" input_half_size.png
ffmpeg -i input.jpg -vf "scale=iw/2:ih/2" input_half_size.png
# Sometimes you want to scale an image, but avoid upscaling it if its dimensions are too low.
# This can be done using min expressions:
ffmpeg -i input.jpg -vf "scale='min(320,iw)':'min(240,ih)'" input_not_upscaled.png

https://trac.ffmpeg.org/wiki/Scaling

Стабилизация

# в 1 проход - качество не очень
ffmpeg -i '.\shaky video.mp4' -vf deshake '.\stabilized video.mp4'
# 2 прохода - результат гораздо лучше
ffmpeg -i '.\shaky video.mp4' -vf vidstabdetect=stepsize=1:mincontrast=0 -f null -
ffmpeg -i '.\shaky video.mp4' -vf vidstabtransform=input="transforms.trf" '.\stabilized video.mp4'

https://ffmpeg.org/ffmpeg-filters.html#vidstabdetect-1
https://ffmpeg.org/ffmpeg-filters.html#vidstabtransform-1

Пакетный режим:

[CmdletBinding()]
param(
[Parameter(Mandatory=$True, HelpMessage="Каталог, где находятся файлы для стабилизации")]
$folder
)
cd "$folder"
$ext = "mp4"
$files = dir "$folder\*.$ext" -File
 
# vidstabdetect
foreach ($file in $files) {
$fullname = $file.FullName
$trf = $file.Basename + '.trf'
& ffmpeg -i "$fullname" -vf vidstabdetect=result="$trf" -f null -
}
 
# vidstabtransform + loudnorm
foreach ($file in $files) {
$fullname = $file.FullName
$trf = $file.Basename + '.trf'
$result = $file.Basename + '-stab' + ".$ext"
& ffmpeg -i "$fullname" -vf vidstabtransform=interpol=bicubic:optzoom=2:smoothing=30:input="$trf",normalize=smoothing=60 -af loudnorm=tp=-1.0 -ar 44100 "$folder\$result"
}
 
# объединить файлы *-stab.$ext
$mark = Get-Date -UFormat "%Y-%m-%d-%H-%M"
dir "$folder\*-stab.$ext" -File |select -expand name |% {echo file` `'$folder`\$_`' |out-file "$folder\$mark.txt" -Append -encoding ASCII}
& ffmpeg -f concat -safe 0 -i "$folder\$mark.txt" -c copy .\vid-combined-$mark.mp4

Склеить несколько видео плиткой

# вертикально, звук скопировать из второго видео
& ffmpeg -i .\upper.mp4 -i .\lower.mp4 -filter_complex "[0:v][1:v]vstack[v]" -map "[v]" -map 1:1 -c:a copy combined-v.mp4
# чтобы сделать горизонтально - hstack

Размыть часть кадра (blur) на определённое время

Отрезается кусок кадра и размывается на 34 сек, затем он накладывается на оригинальное видео.

ffmpeg -i .\2020-04-26_17-01-41-desktop.mp4 -filter_complex "[0:v]crop=661:395:52:151,boxblur=10:enable='between(t,0,34)'[fg]; [0:v][fg]overlay=52:151[v]" -map "[v]" -map 0:a -c:a copy .\2020-04-26_17-01-41-desktop-blur.mkv

https://superuser.com/questions/901099/ffmpeg-apply-blur-over-face

Распознавание смены сцен

Сохраняется первый кадр из каждой новой сцены

ffmpeg -i video.mp4 -filter:v "select=gt(scene\,0.5)" -vsync vfr output/frame%d.jpg

https://superuser.com/questions/1337709/ffmpeg-scene-detection-and-scenecut

Деинтерлейс

:!: Деинтерлейс лучше вообще не делать, а оставлять чересстрочное видео.
Если такой возможности нет, например, в случае с x265, то всегда делать с удвоением кадров (one frame for each field).

bwdif (https://ffmpeg.org/ffmpeg-filters.html#bwdif) - наверное, лучший вариант. Удваивает кол-во кадров в секунду.
w3fdif (https://ffmpeg.org/ffmpeg-filters.html#w3fdif) - очень хорошо, настройки по умолчанию
yadif (https://ffmpeg.org/ffmpeg-filters.html#yadif-1) - быстрый, но есть огрехи. Использовать yadif=1 для удвоения кадров.
kerndeint (https://ffmpeg.org/ffmpeg-filters.html#kerndeint) - неважно
mcdeint (https://ffmpeg.org/ffmpeg-filters.html#mcdeint) - медленный, не всё обрабатывает
nnedi (https://ffmpeg.org/ffmpeg-filters.html#nnedi) - чересчур навороченный

Качество кодирования

Для x265 и x264: регулируется параметром -crf 0-51 (чем меньше - тем лучше качество), по умолчанию он 28 для x265 и 23 для x264, при хорошем качестве исходного материала этого достаточно. Если исходник шумный, с чересстрочной развёрткой и т. д., то неплохой вариант -crf 22 для x265.
For x264 a subjectively sane range is 17–28. Consider 17 or 18 to be visually lossless or nearly so; it should look the same or nearly the same as the input but it isn't technically lossless.

VP9: 0–63, меньше - лучше. Справка по параметрам.

The range is exponential, so increasing the CRF value +6 results in roughly half the bitrate / file size, while -6 leads to roughly twice the bitrate. CRF Guide (Constant Rate Factor in x264 and x265)

Для MPEG4: параметр -q:v 1-31 (меньше - лучше качество), хороший вариант -q:v 3.

MP3: -q:a 0-9 (меньше - лучше качество), отличный вариант -q:a 0, очень хороший -q:a 1-2 (всё ещё обеспечивающий прозрачность), далее по ситуации.

Opus: указывается целевой битрейт (больше - лучше качество), -b:a 6k-510k. По умолчанию 92k, хватит для фильмов. Если аудиодорожка имеет очень важное значение, то прозрачность OPUS обеспечивает примерно начиная с битрейта 160k.
OPUS music encoding quality

Ogg: -q:a 0-10, выше - лучше. Most users agree -q 5 achieves transparency, if the source is the original or lossless. По умолчанию - 3, для музыкальных видео бескомпромиссный вариант - 6 и выше.

WAV: «нормальный» формат - PCM signed 16-bit little-endian, т. е., -c:a pcm_s16le.

Управление аудиоканалами в ffmpeg

Выбор конкретных VOB-файлов в DVD-Video

Если брать ISO, то кодировщик захватывает также и видеоряд меню. Чтобы этого избежать, нужно выбирать только конкретный ряд файлов VOB.

Если пишет Stream map '0:9' matches no streams. To ignore this, add a trailing '?' to the map. (в данном случае это субтитры), то нужно добавить знак вопроса к этим потокам, например

cd "C:\path to mounted ISO\VIDEO_TS"
ffmpeg -i "concat:VTS_01_1.VOB|VTS_01_2.VOB|VTS_01_3.VOB|VTS_01_4.VOB|VTS_01_5.VOB|VTS_01_6.VOB|VTS_01_7.VOB" -map 0:1 -map -0:3 -map 0:2 -map 0:9? -map 0:6? -c:v libx265 -c:s copy "%userprofile%\Videos\DVD-Video.mkv"

https://www.tech-g.com/2017/01/15/converting-dvd-to-mp4-h264-on-windows/

Слайд-шоу (фото в видео)

Даны 16 файлов .jpg, имена с 001 до 016, надо сделать из них видео.

# Входная частота кадров - 4, выходная - 30
& ffmpeg -framerate 4 -i %03d.jpg -c:v libx264 -r 30 out.mp4
# Пропорции сторон фото сохранены, размер кадра 1080p
& ffmpeg -framerate 4 -i %03d.jpg -c:v libx264 -vf scale=-1:1080 -r 30 out.mp4
# Пропорции сторон фото сохранены, дорисованы поля (letterbox) до 1920x1080
& ffmpeg -framerate 4 -i %03d.jpg -c:v libx264 -vf "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2" -r 30 out.mp4

https://superuser.com/questions/547296/resizing-videos-with-ffmpeg-avconv-to-fit-into-static-sized-player
https://trac.ffmpeg.org/wiki/Slideshow

Вне зависимости от выходной частоты кадров, если входная нестандартная, то склеить такое видео c другими без перекодировки не получится.

Автоматическая резка большой аудиозаписи на сегменты по зонам тишины

# Исходный файл
$file = Get-Item -LiteralPath "D:\Музыка\Yamaha W7 demos.wav"
# Отступ до и после полезного сигнала (чтобы треки не начинались сразу один за другим)
$preSec = 0.25
$postSec = 2
# Формат файлов на выходе
$outputExt = ".wav"
 
$log = (& ffmpeg -i $file.FullName -af silencedetect=n=-50dB -f null - 2>&1) -match '^\[silencedetect'
 
function replaceFfmpegStdout ($in) {$in -replace '.*?: (\d+\.\d+).*','$1'}
$starts,$ends = $log.where({$_ -match 'silence_end'}, 'Split')
$starts = replaceFfmpegStdout $starts |select -SkipLast 1
$ends = replaceFfmpegStdout $ends |select -Skip 1
 
$c = 0
$starts |% {
    & ffmpeg -y `
    -ss ($starts[$c] - $preSec) `
    -t ($ends[$c] - $starts[$c] + $postSec) `
    -i $file.FullName `
    ($file.DirectoryName + "\" + "$($file.BaseName) " + ($c+1).tostring("0000") + $outputExt)
    $c++
}

How to split video or audio by silent parts

Метаинформация, главы, заголовки

Файл с метаинформацией выглядит так:

metadata.txt
;FFMETADATA1
title=Полёт на Луну
artist=Нил Армстронг
 
[CHAPTER]
TIMEBASE=1/1000
START=0
END=498039
title=Туда
 
[CHAPTER]
;00:08:18.040
TIMEBASE=1/1000
START=498040
END=681359
title=Обратно
 
[STREAM]
title=Полёт на Луну

Metadata keys or values containing special characters (‘=’, ‘;’, ‘#’, ‘\’ and a newline) must be escaped with a backslash ‘\’.
Справка по синтаксису: https://ffmpeg.org/ffmpeg-formats.html#Metadata-1

Кодировка файла должна быть 65001 UTF-8 without BOM. Вшивать в Powershell 7, который умеет корректно работать с UTF-8.

& ffmpeg -i 'D:\temp\video.mp4' -i 'D:\temp\metadata.txt' -map_metadata 1 -c copy 'D:\temp\video-metadata.mp4'

:!: Если TIMEBASE=1/1, тогда можно указывать в секундах.
:!: Перенос строк в title не работает, ни с помощью \, ни с помощью `n.

Пересчёт строки времени в секунды

function ConvertTo-Seconds ($str) {
    $i = $str -split ':'
    switch ($i.count) {
        1 {[int]$i[0]} # сек
        2 {[int]$i[0] * 60 + [int]$i[1]} # мин:сек
        3 {[int]$i[0] * 3600 + [int]$i[1] * 60 + [int]$i[2]} # часы:мин:сек
        4 {[int]$i[0] * 86400 + [int]$i[1] * 3600 + [int]$i[2] * 60 + [int]$i[3]} # дни:часы:мин:сек
        default {Write-Error "Time format must be `[days:`]`[hours:`]`[minutes:`]<seconds>"}
    }
}
ConvertTo-Seconds "35:34"
2134
ConvertTo-Seconds "07:54:12"
28452
ConvertTo-Seconds "1:09:44:23"
121463

Из DVD можно вытащить таймкоды глав программой ChapterXtractor. Чтобы программа сама составляла нужный файл метаданных для ffmpeg, нужно в ChapterXtractor.ini добавить следующее:

Preset 7=For ffmpeg metadata
Format 7=\n[CHAPTER]\nTIMEBASE=1/1000\nSTART=%ams\nEND=\ntitle=\n
Header 7=;FFMETADATA1\ntitle=\nartist=\n
Footer 7=\n[STREAM]\ntitle=

Затем, открыв в программе нужный файл .IFO, просто выбрать нужный шаблон на вкладке Format.

ℹ️ Время окончания раздела (END=) добавлять необязательно, достаточно начала (START=).

Субтитры

Добавить субтитры в видеофайл

& ffmpeg -i .\video.mp4 -i .\english.srt -i .\russian.srt `
-map 0 -map 1 -map 2 -c:v copy -c:a copy -c:s mov_text `
-metadata:s:s:0 language=eng `
-metadata:s:s:1 language=rus `
.\output.mp4

Скрипт черновой генерации файла с метадатой

Генерирует в из столбика с временными метками вида 00:16:26.120, выгруженного программой ChapterGrabber, файл с метадатой, автоматически пересчитывая метки в миллисекунды. FIXME

$title="Полёт на Луну"
$artist="Нил Армстронг"
$p=$env:userprofile\Videos\ISO
$ts=gc $p\VTS_01_0.txt
$c=1
 
Start-Transcript -Path $p\metadata.txt
 
echo ";FFMETADATA1"
echo "title=$title"
echo "artist=$artist"
echo "[CHAPTER]"
echo "TIMEBASE=1/1000"
echo "START=0"
 
foreach ($t in $ts) {
$tms=[TimeSpan]::Parse("$t").TotalMilliSeconds
$tmsend=$tms-1
echo "END=$tmsend"
echo "title=Chapter $c"
$c++
echo "[CHAPTER]"
echo "TIMEBASE=1/1000"
echo "START=$tms"
}
 
echo "[STREAM]"
echo "title=$title"
 
Stop-Transcript

Закодировать DVD c добавлением метаинформации:

ffmpeg -i "concat:VTS_01_1.VOB|VTS_01_2.VOB|VTS_01_3.VOB|VTS_01_4.VOB" -i "%userprofile%\Videos\metadata.txt" -map 0:1 -map 0:2 -map_metadata 1 -c:v libx265 -vf yadif "%userprofile%\Videos\DVD.mkv"
Просто добавить информацию в уже готовый файл:
ffmpeg -i DVD.mkv -i "%userprofile%\Videos\metadata.txt" -map_metadata 1 -c copy "%userprofile%\Videos\DVD2.mkv"

Выгрузить метаданные из файла:

ffmpeg -i DVD.mkv -f ffmetadata meta.txt

Полезная информация:
https://multimedia.cx/eggs/supplying-ffmpeg-with-metadata/
https://medium.com/@dathanbennett/adding-chapters-to-an-mp4-file-using-ffmpeg-5e43df269687
https://newspaint.wordpress.com/2016/07/27/ripping-a-video-from-dvd-using-ffmpeg/
https://en.wikibooks.org/wiki/FFMPEG_An_Intermediate_Guide/subtitle_options

Конвертер таймкодов на Youtube в ffmpeg metadata

Было:

00:00 ул. Сталеваров
...
1:53:04 Саянская ул.

Стало:

;FFMETADATA1
title=2020.07.28 Электрозавод - Яуза - Рязанский проспект
artist=

[CHAPTER]
TIMEBASE=1/1
START=0
END=134
title=ул. Сталеваров

...
 
[CHAPTER]
TIMEBASE=1/1
START=6784
END=
title=Саянская ул.

[STREAM]
title=2020.07.28 Электрозавод - Яуза - Рязанский проспект
$srcFile = Get-Item "$env:userprofile\Videos\2020.07.28 Электрозавод - Яуза - Рязанский проспект.txt"
 
$source = (gc "$srcFile") -match "\d:\d"
 
# seconds and custom object
$timeTable = @()
$source |% {
$str = $_ -split '\s+',2
if ($str[0] -notmatch ":\d+:") {$str[0] = '00:' + $str[0]}
    $obj = [PSCustomObject]@{
    start = ([datetime]$str[0]).TimeOfDay.TotalSeconds
    end = ''
    name = $str[1]
    }
$timeTable += $obj
}
 
# + end time
$timeTable |sort start -Descending |% {
if ($startPrev) {$_.end = $startPrev}
$startPrev = $_.start
}
 
# create ffmpeg metadata
$ffmpegMeta = $timetable |% {"
[CHAPTER]
TIMEBASE=1/1
START=$($_.start)
END=$($_.end)
title=$($_.name)
"
}
 
$ffmpegMeta = ";FFMETADATA1
title=$($srcFile.basename)
artist=
" + $ffmpegMeta + "
[STREAM]
title=$($srcFile.basename)"
 
# dump to disk
$ffmpegMeta |Out-File "$($srcFile.DirectoryName + '\' + $srcFile.BaseName + '-ffmpegMetadata' + $srcFile.Extension)" -Encoding default

Вытащить описание с Youtube

$url = curl 'https://www.youtube.com/watch?v=12345' -UseBasicParsing
($url.Content |select-string '(?<="description":\{"simpleText":").*?(?="\},"lengthSeconds)').Matches.Value -split "\\n"

Аудиофильтры

volume

# Определение пиков сигнала (-vn - без видео, это гораздо быстрее)
ffmpeg -i .\file.mkv -vn -af volumedetect -f null -
...
[Parsed_volumedetect_0 @ 000001e2d5e78a00] mean_volume: -27.5 dB
[Parsed_volumedetect_0 @ 000001e2d5e78a00] max_volume: -5.1 dB
...
# Нормализация по max_volume, звук - WAV
ffmpeg -i .\file.mkv -af volume=5.1dB -c:a pcm_s16le -c:v copy .\file-norm.mkv

https://trac.ffmpeg.org/wiki/AudioVolume

loudnorm

Динамическая нормализация аудио.

Первый проход:

ffmpeg -i in.wav -af loudnorm=I=-20:TP=-1:LRA=20:print_format=json -f null -

Второй проход (ввести в значение measured значения input из результатов первого прохода + offset):

ffmpeg -i in.wav -af loudnorm=I=-20:TP=-1:LRA=20:measured_I=-22.27:measured_TP=0.03:measured_LRA=20.10:measured_thresh=-33.99:offset=0.51:print_format=summary -ar 48k out.wav

Более-менее универсальные настройки:

-af loudnorm=I=-16:TP=-1:LRA=18

Справка: http://ffmpeg.org/ffmpeg-filters.html#loudnorm
Статья автора:http://k.ylo.ph/2016/04/04/loudnorm.html
Уровень LRA: https://www.audiokinetic.com/library/edge/?source=Help&id=more_on_loudness_range_lra

alimiter

Лимитер + нормализация. Стандартное значение limit - 1, чем ближе к нулю, тем больше эффект.

ffmpeg -i in.wav -af alimiter=limit=0.1 out.wav

https://ffmpeg.org/ffmpeg-filters.html#alimiter

agate

Гейт. В примере сочетание с лимитером, начало с 6-й секунды, моно, битрейт 64к.

& ffmpeg -i .\record.wav -af agate=threshold=0.025,alimiter=limit=0.2 -ss 6 -ac 1 -ab 64k .\record.opus

https://ffmpeg.org/ffmpeg-filters.html#agate

highpass

От бубнежа в записи, отсечка ниже 250 Гц. Этот фильтр с ffplay не работает.

& ffmpeg -i .\record.wav -af agate=threshold=0.025,alimiter=limit=0.2,highpass=f=250 -ac 1 -ab 64k .\record.opus

https://ffmpeg.org/ffmpeg-filters.html#highpass

amix - смешивание аудиопотоков

# audio.mp3 начинается через 5 сек после начала
& ffmpeg -i "C:\temp\video.mp4" -itsoffset 5s -i "C:\temp\audio.mp3" -map 0 -map 1 -async 1 -filter_complex amix=inputs=2 -c:v copy "C:\temp\output.mp4"

https://ffmpeg.org/ffmpeg-filters.html#amix

rubberband - изменение скорости и высоты

# 40% от оригинального темпа
& ffplay -i '.\audio.mp3' -af rubberband=tempo=0.4:pitchq=quality

https://ffmpeg.org/ffmpeg-filters.html#rubberband

speechnorm - нормализация речи

# Weak and slow amplification:
speechnorm=e=3:r=0.00001:l=1
# Moderate and slow amplification:
speechnorm=e=6.25:r=0.00001:l=1
# Strong and fast amplification:
speechnorm=e=12.5:r=0.0001:l=1
# Very strong and fast amplification:
speechnorm=e=25:r=0.0001:l=1
# Extreme and fast amplification:
speechnorm=e=50:r=0.0001:l=1

https://ffmpeg.org/ffmpeg-filters.html#speechnorm

Пакетная обработка

Всё в x265:

set folder=%userprofile%\Videos
mkdir %folder%\Result
for %%a in ("%folder%\*.*") do ffmpeg -i "%%a" -map 0 -c:v libx265 "%folder%\Result\%%~na.mkv"
# -> MP3 44100 Гц 16 бит:
[CmdletBinding()]
param(
[Parameter(Mandatory=$True, HelpMessage="Каталог, где находятся файлы для перекодирования в mp3")]
$folder = '',
$extin = "flac"
)
$extout = "mp3"
$files = gci -LiteralPath "$folder" -File |? name -match "$extin"
 
foreach ($file in $files) {
$ifile = $file.FullName
$result = $file.BaseName + '.' + "$extout"
& ffmpeg -i "$ifile" -map 0:0 -q:a 0 -ar 44100 -sample_fmt s16p "$folder\$result"
}

Видеозахват

Задача: захватывать видео с веб-камеры, звук брать с микрофонного входа.

Вывести список устройств DirectShow:

ffmpeg -list_devices true -f dshow -i dummy
 
# Примерный результат:
 DirectShow video devices (some may be both video and audio devices)
[dshow @ 0000012cb5b1a140]  "B525 HD Webcam"
[dshow @ 0000012cb5b1a140]     Alternative name "@device_pnp_\\?\usb#vid_046d&pid_0836&mi_02#7&10304ea4&0&0002#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"
[dshow @ 0000012cb5b1a140] DirectShow audio devices
[dshow @ 0000012cb5b1a140]  "╨Ь╨╕╨║╤А╨╛╤Д╨╛╨╜ (B525 HD Webcam)"
[dshow @ 0000012cb5b1a140]     Alternative name "@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{78B33698-9C35-4389-96D6-A4C1FE410B1E}"
[dshow @ 0000012cb5b1a140]  "╨б╤В╨╡╤А╨╡╨╛ ╨╝╨╕╨║╤И╨╡╤А (Realtek High Definition Audio)"
[dshow @ 0000012cb5b1a140]     Alternative name "@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{3054A90F-0C13-4228-B85A-E8D3A525FAA4}"
[dshow @ 0000012cb5b1a140]  "╨Ь╨╕╨║╤А╨╛╤Д╨╛╨╜ (Realtek High Definition Audio)"
[dshow @ 0000012cb5b1a140]     Alternative name "@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{F7E26B25-9DE5-4D59-9F8A-2C56A931A566}"

Т. к. названия некоторых устройств идут крякозябрами, нужно использовать альтернативные имена.

# Вывести список свойств устройства:
ffmpeg -f dshow -list_options true -i video="B525 HD Webcam"
 
# Показать параметры определённого кодировщика или декодера:
ffmpeg -h encoder=mjpeg
ffmpeg -h decoder=flac

Захват:

# Звук с вебкамеры
# $auddev = "@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{E33F0DA4-DD49-40A7-BE50-899260CCB4D5}"
# Звук со стереомикшера
# $auddev = "@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{3054A90F-0C13-4228-B85A-E8D3A525FAA4}"
# Звук с микрофонного входа
$auddev = "@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{F7E26B25-9DE5-4D59-9F8A-2C56A931A566}"
$viddev = "B525 HD Webcam"
$buffer = "150M"
$timestamp = get-date -UFormat "%Y-%m-%d_%H-%M-%S"
 
# Захват в x264 (-movflags +faststart - вроде для Youtube хорошо)
& ffmpeg -f dshow -rtbufsize $buffer -i video="$viddev":audio="$auddev" -preset ultrafast -tune zerolatency -movflags +faststart $env:USERPROFILE\Videos\$timestamp.mp4
 
# Захват как есть, что выдаёт камера (выбран входной поток mjpeg, FHD, 30 fps)
& ffmpeg -f dshow -rtbufsize $buffer -video_size 1920x1080 -framerate 30 -vcodec mjpeg -i video="$viddev":audio="$auddev" -c copy $env:USERPROFILE\Videos\out.mkv
 
# Захват как есть 1280x720
& ffmpeg -f dshow -rtbufsize $buffer -video_size 1280x720 -framerate 30 -vcodec mjpeg -i video="$viddev":audio="$auddev" -c copy $env:USERPROFILE\Videos\$timestamp.mkv
 
# Вариант с AVI (видео FMP4 почти макс. качества (макс. - 2), аудио MP3 - максимального)
& ffmpeg -f dshow -rtbufsize $buffer -i video="$viddev":audio="$auddev" -q:v 3 -q:a 0 $env:USERPROFILE\Videos\$timestamp.avi
 
# AVI, ограничить кол-во кадров до 25, разрешение - до 1024×576.
& ffmpeg -f dshow -rtbufsize $buffer -i video="$viddev":audio="$auddev" -r 25 -s 1024x576 -q:v 3 -q:a 0 $env:USERPROFILE\Videos\$timestamp.avi

https://trac.ffmpeg.org/wiki/DirectShow

Параметры перекодирования после захвата

Исходник шумный, MJPEG 1280×720, WAV 44100.
Обработка: звук - простая нормализация до -1 дБ, видео - два фильтра: hqdn3d для уменьшения шума и normalize для нормализации цветности.

# В x265 + OPUS, архив
ffmpeg -i input.mkv -c:v libx265 -crf 24 -preset slow -vf hqdn3d,normalize -c:a libopus -b:a 256k output.mkv
# В x264 + aac, для браузеров
ffmpeg -i input.mkv -crf 20 -preset slow -vf hqdn3d,normalize -b:a 256k output.mp4
 
# Пример обработки захваченного куска:
cd ~\Videos
$name = '2023-12-12_21-35-35'
# Вырезать нужную часть
ffmpeg -i .\${name}.mkv -ss 5:42 -t 3:12 -c copy .\${name}_edit.mkv
# Измерить пик громкости
Invoke-Expression "
& ffmpeg -i .\${name}_edit.mkv -vn -af volumedetect -f null -
" -ErrorVariable vol
$vol = ($vol -match 'max_volume:') -replace '.*?-?(\S+) dB','$1'
 
# Кодировать + нормализовать аудио на основе измеренного пика громкости
& ffmpeg.exe -i ".\${name}_edit.mkv" -c:v hevc_qsv `
-profile:v main10 -pix_fmt p010le -preset slower `
-global_quality:v 24 -tag:v hvc1 `
-af volume=${vol}dB -c:a libopus -b:a 256k `
".\${name}_norm2.mp4" -y

Захват экрана

В Windows 2 способа - gdigrab (встроенный, звук писать не умеет) и DirectShow (необходимо иметь фильтр, типа UScreenCapture). Можно комбинировать оба способа.

# Посмотреть наличие устройств DirectShow
ffmpeg -list_devices true -f dshow -i dummy
# Захват полного экрана со звуком
ffmpeg -f gdigrab -i desktop -f dshow -i audio="Microphone (High Definition Aud" "c:\temp\$((get-date).tostring("yyyy-MM-dd_HH-mm-ss"))-ScreenCapture.mp4"
# Захват окна, без звука, 6 кадров/с
ffmpeg -f gdigrab -framerate 6 -i title=Calculator out.mpg
# Захват экрана со второго монитора, мышь не показывать, звук моно
& ffmpeg -f gdigrab -rtbufsize 1500M -framerate 30 -offset_x 1920 -offset_y 0 -video_size 1600x1200 -draw_mouse 0 -i desktop `
-f dshow -i audio="Стерео микшер (Realtek High Definition Audio)" `
-c:v h264_qsv -profile:v high -global_quality:v 23 -b:a 64k -ac 1 `
D:\temp\$(get-date -f yyyy-MM-dd-HH-mm-ss).mp4
# Захват экрана со второго монитора, аппаратное ускорение, 15 кадров/с, качество 30
& ffmpeg -f gdigrab -framerate 15 -offset_x 1920 -video_size 1920x1080 -i desktop -c:v h264_qsv -profile:v high -global_quality:v 30 D:\Видео\output.mp4 -y

https://trac.ffmpeg.org/wiki/Capture/Desktop
https://ffmpeg.org/ffmpeg-devices.html#gdigrab
https://www.trishtech.com/2018/02/record-windows-desktop-screen-with-sound-using-ffmpeg/
https://medium.com/@colten_jackson/simple-free-screen-capture-with-ffmpeg-3aeddbeb161b
https://antumdeluge.wordpress.com/2014/02/19/recording-screen-windows-desktop-using-ffmpeg/

Захват экрана + видео с камеры (картинка в картинке, PIP)

Качество надо подбирать по вкусу. Здесь захват в -c:v hevc_qsv -q:v 15, вряд ли это оптимальный вариант.

$t = get-date
$auddev = "Микрофон (B525 HD Webcam)"
$viddev = "B525 HD Webcam"
$screenRes = gwmi Win32_VideoController |select CurrentHorizontalResolution,CurrentVerticalResolution
$camWidth = 320
$camHeight = 240
# Оверлей - вычисляется левый верхний угол. Если написать
# "overlay=main_w-overlay_w-0:main_h-overlay_h-0" - это правый нижний угол.
& ffmpeg `
-f gdigrab -thread_queue_size 1024 -i desktop `
-f dshow -rtbufsize 1500M -video_size "$($camWidth)x$($camHeight)" -thread_queue_size 1024 -i video="$viddev":audio="$auddev" `
-filter_complex "overlay=main_w-overlay_w-$($screenRes.CurrentHorizontalResolution - $camWidth):main_h-overlay_h-$($screenRes.CurrentVerticalResolution - $camHeight)" `
-movflags +faststart -c:v hevc_qsv -q:v 15 `
"$($env:USERPROFILE)\Videos\$($t.ToString("yyyy-MM-dd_HH-mm-ss"))-desktop-overlay.mp4"

https://ffmpeg.org/ffmpeg-filters.html#overlay-1
https://stackoverflow.com/questions/7967699/get-screen-resolution-using-wmi-powershell-in-windows-7

Расчёт битрейта для получения точного размера конечного файла

# Формула расчёта:
# (([желаемый размер в МБ] * 8kb [перевод в килобиты]) / [кол-во секунд в видео] - [аудиобитрейт]
((200 * 8kb) / 635 -as [int]) - 128 = 2452
 
& ffmpeg -i "D:\video.mp4" -maxrate 2452k -bufsize 100M -b:a 128k "D:\video200MB.mp4"

https://askubuntu.com/questions/1027340/convert-a-video-by-setting-the-final-size
https://trac.ffmpeg.org/wiki/Limiting%20the%20output%20bitrate

Поиск ключевых кадров

& ffprobe -i "D:\Видео\2020-05-21.mp4" -select_streams v -show_frames -show_entries frame=pkt_pts_time,key_frame -sexagesimal -of csv=print_section=0 |
ConvertFrom-Csv -Header key,time |? key -eq 1

https://superuser.com/questions/554620/how-to-get-time-stamp-of-closest-keyframe-before-a-given-timestamp-with-ffmpeg
https://superuser.com/questions/885452/extracting-the-index-of-key-frames-from-a-video-using-ffmpeg
https://trac.ffmpeg.org/wiki/FFprobeTips

Отрезать по ключевому кадру

Для этого нужно опцию -ss (начало) указывать до входного видео.

& ffmpeg -ss 5:03 -i .\video.mp4 -c copy .\output.mp4

https://trac.ffmpeg.org/wiki/Seeking
https://stackoverflow.com/questions/14005110/how-to-split-a-video-using-ffmpeg-so-that-each-chunk-starts-with-a-key-frame

Синхронизация аудио- и видеодорожки

Дано: файл, где аудио и видео имеют разную продолжительность, и при пересборке файла начинается рассинхрон.

Input #0, matroska,webm, from '.\2022-04-23_11-39-14_edit.mkv':
  Metadata:
    ENCODER         : Lavf58.20.100
  Duration: 00:00:38.74, start: 0.000000, bitrate: 34875 kb/s
  Stream #0:0: Video: mjpeg (Baseline), yuvj422p(pc, bt470bg/unknown/unknown), 1280x720, SAR 1
:1 DAR 16:9, 29.97 fps, 29.97 tbr, 1k tbn, 1k tbc (default)
    Metadata:
      DURATION        : 00:00:38.290000000
  Stream #0:1: Audio: pcm_s16le, 44100 Hz, 2 channels, s16, 1411 kb/s (default)
    Metadata:
      DURATION        : 00:00:38.743000000

Решение - при пересборке файла учесть разницу:

& ffmpeg -i .\2022-04-23_11-39-14_edit.mkv -ss 00:00:00.453 -i .\2022-04-23_11-39-14_edit1.wav -c copy -shortest '.\2022-04-23_11-39-14_result.mkv'

Если аудио короче видео, то применяется фильтр apad (аудио будет перекодировано):

ffmpeg -i video.mp4 -ss 00:04:00 -i audio.mp3 -c:v copy -af apad -shortest output.mkv

https://stackoverflow.com/questions/13041061/mix-audio-video-of-different-lengths-with-ffmpeg

Если нужно просто сдвинуть одну дорожку относительно другой:

# В этом случае аудио сдвигается вперёд относительно видео.
# Параметр -itsoffset ставится до входного потока, который нужно сдвинуть.
# Входной файл может указываться два раза одинаковый.
ffmpeg -i '.\video.mp4' -itsoffset 00:00:00.600 -i '.\video.mp4' -map 0:v -map 1:a -c copy '.\synced.mp4'

Easily fix async video with ffmpeg

Прочее, решение проблем

Об опции -rtbufsize

Постоянно был пропуск кадров из-за переполнения буфера:

[dshow @ 000001c9a4bca440] real-time buffer [B525 HD Webcam] [video input] too full or near too full (113% of size: 3041280 [rtbufsize parameter])! frame dropped!

Решение:
-rtbufsize 150M (rtbufsize goes before the input name since it applies to inputs)
https://stackoverflow.com/questions/45643572/ffmpeg-problems-with-real-time-buffer

Too many packets buffered for output stream 0:0

Иногда возникает такая ошибка после запуска кодирования. Помогает опция, её нужно ставить перед выходным файлом:

-max_muxing_queue_size 1024

Особенности определения потоков в DVD-Video

Неактуально, т. к. нельзя избавиться от первого VOB, где записано меню. Нужно кодировать, собирая нужные файлы:
ffmpeg -i "concat:VTS_01_1.VOB|VTS_01_2.VOB|VTS_01_3.VOB|и т. д."

DVD subtitles may not appear in the first VOB file in a set; it may be necessary to tell ffmpeg to scan ahead deep into the file so that it can find the subtitles in the second VOB file. The directives to do this are -probesize and -analyzeduration – the first being the number of bytes to read ahead into the file, and the second being the number of microseconds (of which there are 1,000,000 per second). These directives must come before the input file directive.

ffmpeg -probesize 1G -analyzeduration 1G -i DVD-Video.iso

https://newspaint.wordpress.com/2016/07/27/ripping-a-video-from-dvd-using-ffmpeg/

Quality-based encoding not supported, please specify a bitrate and VBR setting

Эта ошибка возникает, когда кодировщик opus принимает на свой счёт опцию -global_quality, предназначенную для видеокодирования через аппаратный QSV. Решение - использовать -global_quality:v.

https://www.reddit.com/r/ffmpeg/comments/12gsvlq/need_help_with_hevc_qsv_and_libopus/

Восстановление видео

Идея в том, чтобы, кроме битого видео, иметь любое рабочее с того же устройства. Несколько проектов - untrunc, его форк mp4fixer.
Реальный рабочий вариант, но платный - Do-It-Yourself Video Repair Tool (VRT), Grau GmbH.

Популярные разрешения

16:9
Ширина Высота Название
426 240 240p (SD)
640 360 360p (SD), nHD
854 480 480p (SD)
960 540 qHD
1024 576
1280 720 720p (HD)
1920 1080 Full HD
2560 1440 1440p (2K)
3840 2160 2160p (4K)
7680 4320 4320p (8K)

https://en.wikipedia.org/wiki/16:9_aspect_ratio
https://ru.wikipedia.org/wiki/4K_(%D1%80%D0%B0%D0%B7%D1%80%D0%B5%D1%88%D0%B5%D0%BD%D0%B8%D0%B5)

Скрипт расчёта разрешений для разных соотношений сторон для Powershell

# Set ratio here
$w,$h = 16,9
 
$wInit,$hInit = $w,$h
$report = @()
do {
    if ($w%8 -eq 0 -and $h%8 -eq 0) {
        $obj = [pscustomobject]@{
        Ширина = $w
        Высота = $h
        }
    $report += $obj
    }
$w = $w + $wInit
$h = $h + $hInit
} until ($w -gt 7680)
 
#$report
 
$report |ConvertTo-Html -Title "$wInit`:$hInit aspect ratio" -PreContent "<h2>Соотношение сторон $wInit`:$hInit</h2>" > $env:temp\$wInit-$hInit-aspect-ratio.html
start $env:temp\$wInit-$hInit-aspect-ratio.html

Примеры

# Взять третью аудиорожку и субтитры из файла в исходной кодировке cp1251,
# отрезать 1:30 в начале файла (заставка), далее оставить 19:35 (до титров),
# закодировать в x264 аппаратно, оставить имя только из цифр.
$files = gci "$env:userprofile\Downloads\Naruto\1 Видео файлы" |? {$_.Extension -eq ".avi" -and $_.basename -ne "Naruto-065 DVDrip"}
$subs = gci "$env:userprofile\Downloads\Naruto\3 Субтитры СРТ" |? Extension -eq ".srt"
 
foreach ($file in $files) {
$sub = $subs -match $file.basename
& ffmpeg -i $file.fullname -sub_charenc cp1251 -i $sub.fullname `
-map 0:0 -map 0:3 -map 1 -c:a copy -metadata:s:s:0 language=rus `
-c:v h264_qsv -profile:v high -global_quality:v 23 -look_ahead 1 -preset slow `
-ss 00:01:30 -t 00:19:35 `
"$env:userprofile\Videos\$($file.name -replace "\D").mkv" -y
}
 
# Вариант с заставкой не с начала.
# Аудио нужно перекодировать, субтитры не использовать (неизвестно, как их резать)
foreach ($file in $files) {
$sub = $subs -match $file.basename
& ffmpeg -i $file.fullname -sub_charenc cp1251 -i $sub.fullname `
-filter_complex `
"[0:0]trim=duration=75,setpts=PTS-STARTPTS[av];
 [0:2]atrim=duration=75,asetpts=PTS-STARTPTS[aa];
 [0:0]trim=start=165:end=1265,setpts=PTS-STARTPTS[bv];
 [0:2]atrim=start=165:end=1265,asetpts=PTS-STARTPTS[ba];
 [av][bv]concat[outv];[aa][ba]concat=v=0:a=1[outa]" `
-map [outv] -map [outa] -c:a aac `
-c:v h264_qsv -profile:v high -global_quality:v 23 -look_ahead 1 -preset slow `
"$env:userprofile\Videos\$($file.name -replace "\D").mkv" -y
}

Заметки

https://jellyfin.org/docs/ - Jellyfin is a Free Software Media System that puts you in control of managing and streaming your media
https://github.com/bluenviron/mediamtx - RTSP server
https://github.com/clsid2/mpc-hc - плеер MPC-HC (форк)
https://www.videolan.org/vlc/index.ru.html - плеер VLC