Небольшой ffmpeg скрипт для удобной быстрой конвертации видео

Так как тут один чел запостил гайд на тему пакетной обработки видео ffmpeg'ом, решил тоже всё-таки запостить свой небольшой скрипт и метод для удобной конвертации, который я тоже себе недавно написал.

В живую всё это выглядит как-то так:

UPD 2024.03.29 - Пара мелких доработок. Звук теперь конвертируется в битрейте 256кб чтобы сохранить все детали. При конвертации из HDR и SDR файлу добавится маленькая приписка sdr, чтобы было понятно что его преобразовали в цветах.

UPD 2023.10.29 - Исправлена проблема, из-за которой не удавалось запускать конвертацию файлов, в которых отсутствовали пробелы в названии.

UPD 2023.10.01 - Добавлена возможность рендера только части видео через указание параметра "Cut video from" в формате 00:00:00 и "Cut video to" в таком же формате, например чтобы начать рендер пропустив первые 5 секунд, напишите в первом параметре "00:00:05". И чтобы закончить рендер на 10 секунде, пишите "00:00:10" во втором параметре.

UPD 2023.09.28 - Добавлена возможность настраивать параметры tune и preset, которые точно также имеют значения по-умолчанию, которые не обязательно менять.

UPD 2023.09.26 - Параметр -ac 1 изменен на -ac 2, так как первый вариант переводил аудио дорожку в моно режим :/ Я даже не замечал всё это время.

UPD 2023.09.25 - Добавлено автоматическое определение FPS, ширины и цветового пространства оригинального видео.

У меня карта от Nvidia, поэтому скрипт использует её аппаратные возможности. Я уверен что владельцы карт от AMD смогут сами при необходимости погуглить и заменить пару значений в коде скрипта для того чтобы обрабатывать ролики своими амдшными карточками.

Кодек AV1 поддерживает аппаратную конвертацию только самой последней 4000-й серией видеокарт, у меня такой пока что нет. Для тех кто такую себе уже приобрёл - замените в скрипте строку "libsvtav1" на "av1_nvenc", чтобы конвертировать ролики в AV1 с помощью своей видеокарты.

Прошу любить и жаловать, сохраните этот код в файл с каким-нибудь названием вроде ffmpeg-convert.bat

setlocal EnableDelayedExpansion @echo off cls set name1=%1 set _extension=%~x1 call set name1=%%name1:"=%% set name1="%name1%" echo File path: %name1% set CommandLine=ffprobe -v error -hide_banner -select_streams v:0 -show_entries stream=r_frame_rate -of default=noprint_wrappers=1 %name1% for /F "delims=" %%I in ('!CommandLine!') do set "original_framerate=%%I" set "original_framerate=%original_framerate:~13,10%" set "original_framerate=%original_framerate:~,-2%" set CommandLine=ffprobe -v error -hide_banner -select_streams v:0 -show_entries stream=width -of default=noprint_wrappers=1 %name1% for /F "delims=" %%I in ('!CommandLine!') do set "original_width=%%I" set "original_width=%original_width:~6,10%" set CommandLine=ffprobe -v error -hide_banner -select_streams v:0 -show_entries stream=height -of default=noprint_wrappers=1 %name1% for /F "delims=" %%I in ('!CommandLine!') do set "original_height=%%I" set "original_height=%original_height:~7,10%" set CommandLine=ffprobe -v error -hide_banner -select_streams v:0 -show_entries stream=color_space -of default=noprint_wrappers=1 %name1% for /F "delims=" %%I in ('!CommandLine!') do set "original_color_space=%%I" set "original_color_space=%original_color_space:~12,50%" echo ORIGINAL FPS - %original_framerate% echo ORIGINAL WIDTH and HEIGHT - %original_width%x%original_height% echo ORIGINAL COLOR SPACE - %original_color_space% set cq=0 set fps=%original_framerate% set width=1440 set encoder=2 set hdr=1 set trimStart=0 set trimEnd=0 if %original_color_space%==bt2020nc set hdr=2 set /p cq=video quality (0 to 51, 0 - auto, 1 - best, 51 - worst) [%cq%]: set /p fps=frames per second (fps) [%fps%]: set /p width=width (original - %original_width%, write "0" to use original) [%width%]: set /p encoder=encoder (1 - h264_nvenc, 2 - hevc_nvenc, 3 - AV1) [%encoder%]: set /p hdr=HDR (1 - do nothing with colors, 2 - convert HDR to SDR) [%hdr%]: if %encoder%==1 set preset=slow if %encoder%==2 set preset=slow if %encoder%==3 set preset=6 if %encoder%==1 set preset_help=slow / medium / fast / p1-p7 if %encoder%==2 set preset_help=slow / medium / fast / p1-p7 if %encoder%==3 set preset_help=from -2 to 12 if %encoder%==1 set tune=hq if %encoder%==2 set tune=hq if %encoder%==3 set tune=0 if %encoder%==1 set tune_help=hq - high quality, ll - low latency, ull - ultra low latency, lossless if %encoder%==2 set tune_help=hq - high quality, ll - low latency, ull - ultra low latency, lossless if %encoder%==3 set tune_help=0 = VQ, 1 = PSNR, 2 = SSIM set /p preset=preset (%preset_help%) [%preset%]: set /p tune=tune (%tune_help%) [%tune%]: set /p trimStart=Cut video from (only if needed, example: 00:05:00): set /p trimEnd=Cut video to (only if needed, example: 00:10:00): if NOT %trimStart%==0 ( set trimStartFinal=-ss %trimStart% set trimStartFinalStr= trimStart=%trimStart% call set trimStartFinalStr=%%trimStartFinalStr::=.%% ) if NOT %trimEnd%==0 ( set trimEndFinal=-to %trimEnd% set trimEndFinalStr= trimEnd=%trimEnd% call set trimEndFinalStr=%%trimEndFinalStr::=.%% ) rem ffmpeg -h encoder=h264_nvenc rem ffmpeg -h encoder=hevc_nvenc rem ffmpeg -h encoder=libsvtav1 if %width%==0 set width=%original_width% if %encoder%==1 set encoder_final=h264_nvenc if %encoder%==2 set encoder_final=hevc_nvenc if %encoder%==3 set encoder_final=libsvtav1 if %encoder%==1 set tune_params=-tune %tune% if %encoder%==2 set tune_params=-tune %tune% if %encoder%==3 set tune_params=-svtav1-params tune=%tune% if %encoder%==1 set quality=-cq %cq% if %encoder%==2 set quality=-cq %cq% if %encoder%==3 set quality=-crf %cq% if %hdr%==1 set hwaccel=opencl if %hdr%==2 set hwaccel=cuda if %hdr%==1 set convert= if %hdr%==2 set convert= sdr if %hdr%==1 set filter= if %hdr%==2 set filter=,zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p call set name2=%%name1:%_extension%= [%encoder_final% w=%width% fps=%fps% quality=%cq% preset=%preset% tune=%tune%%trimStartFinalStr%%trimEndFinalStr%%convert%].mp4%% @echo on ffmpeg -hwaccel %hwaccel% -y -i %name1% ^ -vf fps=%fps%,zscale=width=%width%:height=-2%filter% ^ -c:v %encoder_final% ^ %quality% ^ %tune_params% ^ %trimStartFinal% ^ %trimEndFinal% ^ -preset %preset% ^ -movflags ^ +faststart ^ -c:a aac ^ -ac 2 ^ -b:a 256k ^ -async 1 ^ %name2% pause

Как этим пользоваться? Всё очень просто.

0. Установите ffmpeg. Для этого скачайте его и переместите из архива два исполняемых файла ffmpeg.exe и ffprobe.exe в папку windows/system32.

1. Кидаете батник в ту папку, где у вас лежат записанные вами видео.

2. Тянете нужный видеоролик мышкой и бросаете его на батник.

3. Появляется окно командной строки, отвечаете там на пару вопросов про качество, разрешение, FPS, тип цветового пространства оригинального контента (HDR/SDR). Там есть уже выбранные значения по умолчанию, так что на некоторые вопросы можно не отвечать и просто нажать Enter. Также, значения по умолчанию можете легко отредактировать под свои потребности в скрипте.

4. ..... дожидаетесь завершения конвертации вашего видео.

Рядом с вашим оригинальным файлом появится ещё один, у которого в квадратных скобочках, для вашего удобства, будет написана информация о том, в каком разрешении обработалось видео, какое было выставлено качество, FPS, оригинальное цветовое пространство и т.д.

Небольшой ffmpeg скрипт для удобной быстрой конвертации видео

Поясню также детальнее пару моментов про логику скрипта.

Скрипт автоматически определяет FPS, ширину и цветовое пространство оригинального видео. Если цветовое пространство равно bt2020nc - то скрипт автоматически выставит обработку HDR. Но вы вольны будете поменять все эти значения на этапе установки параметров.

Насчёт HDR: данный скрипт позволяет преобразовать записанный HDR геймплей в стандартный SDR. Чтобы потом делиться записанным контентом в различных соц-сетях и месенджерах, которые в большинстве своём не поддерживают HDR.

Для обработки используется opencl когда речь идёт про стандартный SDR контент, либо cuda, когда речь идёт про преобразование HDR в SDR. opencl отлично утилизирует все возможности ПК, как процессора, так и видеокарты, давая в результате невероятную скорость конвертации. Но при этом она почему-то очень криво преобразует HDR в SDR, потому для этой ситуации туда подставляется более классический вариант cuda, который работает помедленнее, но конвертирует всё корректно.

Параметр quality, качество - в большинстве случаев проще всего оставлять в значении по умолчанию (0), что подразумевает, что ffmpeg сам постарается определить, в каком качестве лучше отконвертировать видео для достижения наиболее оптимального конечного результата. Всегда можно конечно попробовать поставить ручные значения, где 1 - это самый увесистый файл, и 51 - самый маленький, но растерявший по ходу конвертации все свои детали. Но по моему личному опыту, ffmpeg автоматически определяет это параметр гораздо адекватнее, чем мои ручные попытки угадать, что ему будет лучше.

Параметр width позволяет указать ширину, а высота при этом определится ffmpeg'ом автоматически, сохранив оригинальные пропорции видео.

Собственно, вроде всё. Надеюсь это принесёт кому-нибудь пользу :)

3434
41 комментарий

Комментарий недоступен

7
Ответить

Респект за реализацию на nvenc

3
Ответить

что я делаю не так?

1
Ответить

ещё в пункте FPS введи 29 или 30. по умолчанию парсер иногда парсит какое-то странное значение, на скрине видно. это я тоже победить не смог.

Ответить

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

Ответить

Другим его будет сложновато под себя адаптировать.

Например, -crf 0 в ffmpeg обычно означает lossless-качество, но в SVT-AV1 этот режим (пока) не сделали*, поэтому по счастливой случайности выбирается авто-качество. А вот в libaom-av1 сделали.

-async 1 мог перекочевать из других советов, потому что это неочевидная опция ресемплера**, заданная неочевидным образом***, нужна ли она на самом деле - можно долго думать.

Есть ошибка в zscale=width=%width%:height=-1, из-за 4:2:0 надо сделать высоту гарантированно кратной двум (height=-2).

hwaccel логично сделать целиком отключаемым, а выбор кодека хардкодить под себя.

Комментарии помогают.

* https://gitlab.com/AOMediaCodec/SVT-AV1/-/issues/1636
** https://ffmpeg.org/ffmpeg-resampler.html#:~:text=async
*** https://ffmpeg.org/ffmpeg-resampler.html#:~:text=may%20be%20set%20by%20specifying%20-option

Ответить

Например, -crf 0 в ffmpeg обычно означает lossless-качество, но в SVT-AV1 этот режим (пока) не сделали*, поэтому по счастливой случайности выбирается авто-качество. А вот в libaom-av1 сделали.

Видимо раньше означало. В двух двугих перекодировщиках в cq значение "0" означает автоматическое определение. Выполни ffmpeg -h encoder=h264_nvenc или ffmpeg -h encoder=hevc_nvenc, посмотри что он тебе выдаст. Подскажу: "-cq E..V....... Set target quality level (0 to 51, 0 means automatic) for constant quality mode in VBR rate control (from 0 to 51) (default 0)"

Есть ошибка в zscale=width=%width%:height=-1, из-за 4:2:0 надо сделать высоту гарантированно кратной двум (height=-2).

Не понял проблему, если честно. У меня всё норм.

hwaccel логично сделать целиком отключаемым, а выбор кодека хардкодить под себя.

Без проблем. Сделай себе если тебе это надо.

Ответить