Раза два (сперва в ноябре 2024 года, затѣмъ в январе 2026 года) я ужé упоминалъ здѣсь о том, что иногда под Windows приходится пользоваться в командной строке краткими именами файлов при вызове таких утилит, которыя сходят с ума при виде нѣкоторыхъ таких сѵмволовъ, которые допустимы в длинных именах файлов, но недопустимы в кратких — или таких сѵмволовъ, которые допустимы и в кратких именах файлов, однако всё равно нечасто там попадаются, потому что их рѣдко ставят в начале имени файла, так что они оказываются устранены обрѣзаніемъ.
В качестве примѣра этакой утилиты я в январе упоминал cwebp (кодировщик формата WebP), у которого до сих пор не закрыта проблема с обработкою Unicode в именах файлов.
Чтобы этот примѣръ не оставался единственным, в качестве второго примѣра я сегодня назову утилиту NirCmd: по-видимому, исполнение команды «nircmd.exe clonefiletime да.pdf нѣтъ.pdf» не приводит к достижению желаемого результата по той только причине, что в имени у второго из двух указанных файлов есть ять.
Немного другую природу имѣютъ проблемы с передачею имён файлов в FFmpeg, о которых я также упоминал в январе. Ни один сѵмволъ не приводит FFmpeg к окончательной невозможности обработать желаемый файл, однако нѣкоторые сѵмволы воспринимаются в командной строке FFmpeg в качестве специальных, особенно при указании их внутри значения, передаваемого параметру фильтра.
Напримѣръ, так как видеопроигрыватели в Telegram пока ещё не повсемѣстно научили показывать субтитры из видеофайлов (кажется, для этого есть только глубоко сокрытая настройка, по умолчанию выключенная, да и то есть она не в каждом приложении Телеграма), и так как аналогично ведут себя видеопроигрыватели и в других соціальныхъ сѣтяхъ, то обычным этапом при подготовке нѣкоторой видеоцитаты становится впечатывание субтитров в пикселы видеокадров при помощи фильтра subtitles. Это вызывает значительныя проблемы даже при составлении командной строки вручную: скажем, автор вон того вопроса, на сайте SuperUser заданнаго, почувствовал себя принуждённым учетверять каждый сѵмволъ обратной косой черты, а также затрудняться с их количеством при экранировании апострофа в имени файла и двоеточия послѣ буквы диска в пути к файлу.
Если же рѣчь идёт не о простом составлении командной строки, а об автоматическом, то число сѵмволовъ, подлежащих экранированию, переваливает за полдесяток — напримѣръ, автор вон того куска кода, на сайте SuperUser приведённаго (на языке C#, насколько я догадываюсь), заэкранировал в командной строке при вызове FFmpeg и запятые, и точки с запятыми, и квадратныя скобки (и открывающія, и закрывающія), и апострофы, и двоеточия, а уж об экранировании обратных косых черт даже не задумывался (сразу сдался и начал с того, что замѣнилъ всѣ обратныя косыя черты на «простыя», «необратныя» косыя черты).
Послѣдній из этих приёмов (то есть предварительную замѣну обратных косых черт на необратныя вмѣсто экранирования их в пути к файлу) вы могли увидать используемым и в том примѣрѣ, в котором я указывал 2 мая пути ко скачанным файлам моделей внутри параметров фильтра whisper. Можете сравнить съ тѣмъ, как двоеточие, слѣдующее за буквою диска, было экранировано двойною обратною косою чертою.
Причём, если читать документацию по FFmpeg, то такое положеніе дѣлъ может показаться совершенно естественным. Поглядите в ней подраздѣлъ «Notes on filtergraph escaping», и в нём вы увидите примѣръ, в котором число обратных косых черт при экранировании одного-единственнаго апострофа доходит до шести — само собой разумѣется, что это ещё в полтора раза покруче, чѣмъ ихъ четырёхкратность въ примѣрѣ с сайта SuperUser.
В практическом отношении это означает, что моя задумка полностью отказаться от использования формата AVC (он же H.264) в пользу формата FFV1 при таком создании видеоцитат, которое не вносит новых потерь в них, которую я огласил 13 мая, в конечном итоге привела меня к сочинению бáтников (пакетных файлов) наподобие вот такого:
@echo off
ffmpeg -hide_banner -i %1 -vf "subtitles=%~nxs2:si=%3" -map %6 -map %7 -ss %4 -to %5 -sn %8 %9 -c:a libopus -b:a 64k -frame_duration 60 -c:v ffv1 -level 3 -g 300 -coder 1 -context 1 -slicecrc 0 -slices 30 -threads 16 -pix_fmt yuv420p10le -sws_dither ed -map_metadata -1 -map_chapters -1 step1.mkv
Как нетрудно видѣть, в этом бáтнике командную строку пополняют собою «как есть» и первый параметр (путь к видеофайлу), и третий (номер субтитров), и четвёртый да пятый (время начала и конца цитаты), и шестой (номер цитируемой видеодорожки), и седьмой (номер цитируемой аудиодорожки), и восьмой да девятый (содержащие, напримѣръ, параметры «-ac 2» для перевода объёмнаго звука в стереозвук).
А вот для второго параметра (имени файла субтитров) сдѣлано исключение: он не пополняет собою командную строку «как есть», а принуждается содержать только имя файла (с расширением имени файла), да и то в краткой форме (с надеждою на то, что сѵмволы, считающиеся спеціальными в FFmpeg, окажутся запрещёнными к появлению в кратком имени файла или хотя бы срѣзанными раньше, чѣмъ появятся в этом обрубке).
Понятно, что этот подход и неудобен (поскольку принуждает всякий раз наперёд копировать файл с субтитрами в тот «рабочий» подкаталог, в котором будет создаваться видеоцитата «step1.mkv»), и притом не на 100% надёжен по отношению к апострофам, имѣющимъ спеціальный смыслъ въ FFmpeg: насколько я понимаю, появление апострофа в начале краткого имени файла не запрещено операционною системою, а просто маловѣроятно.
(В предыдущем абзаце я выдѣлилъ жирностію словá «всякий раз» оттого, что в частных-то случаях необходимость копирования файла с субтитрами в «рабочий» подкаталог способна возникать, но по другим причинам — и тогда «иногда», а не «всякий раз».)
Недавно я понял, что безальтернативность столь небезупречного подхода — это иллюзия, вызванная двумя негативными факторами, каждый из которых сводится к прискорбной недодокументированности:
➊ Описание команды set на сайте Корпорации Microsoft ни словом не упоминает возможность примѣнить дополнительную операцию поиска и замѣны в момент подстановки значения нѣкоторой перемѣнной. Эта возможность всё ещё упоминается только в той подсказке, которая возникает при вызове команды «set /?» из командной строки, причём подсказку эту переводили на русский язык не слишком ясно (в частности, наивно предполагали возможность читателя фразы «расширит действие переменной среды PATH, заменяя каждое вхождение "str1" в расширенном результате на "str2"» сразу понять, что «дѣйствіемъ перемѣнной» названа подстановка значения перемѣнной, тогда как «расширенным результатом» назван результат поиска и замѣны в таком подставленном значении).
➋ Разсмотренный выше подраздѣлъ «Notes on filtergraph escaping» на сайте FFmpeg приходится признать однобоким и по названию, и по практической полезности: он содержит впечатляющие примѣры экранирования (escaping), но ни одного примѣра обрамления строк (quoting), и даже за описанием принципов их обрамления отсылает к другому подраздѣлу («Quoting and escaping»), который также (но ужé вопреки своему названию) не содержит ни одного практическаго примѣра оформления строк (quoting), а только теоретическое утверждение: строка между апострофами будет воспринятою в FFmpeg буквально.
Одновременно примѣняя то и другое «тайное знание», можно придать вот какой новый вид предыдущему бáтнику:
@echo off
set "SUBTITLEFILE=%~2"
set "SUBTITLEFILE=%SUBTITLEFILE:\=/%"
set "SUBTITLEFILE=%SUBTITLEFILE::=\:%"
set "SUBTITLEFILE=%SUBTITLEFILE:'=\\'%"
ffmpeg -hide_banner -i %1 -vf "subtitles='%SUBTITLEFILE%':si=%3" -map %6 -map %7 -ss %4 -to %5 -sn %8 %9 -c:a libopus -b:a 64k -frame_duration 60 -c:v ffv1 -level 3 -g 300 -coder 1 -context 1 -slicecrc 0 -slices 30 -threads 16 -pix_fmt yuv420p10le -sws_dither ed -map_metadata -1 -map_chapters -1 step1.mkv
Как видите, теперь в пути к файлу субтитров обратныя косыя черты замѣняются необратными, а затѣмъ экранируются только двоеточія да апострофы, а результат этого обрамлён с двух сторон апострофами же — для буквальнаго воспріятія его в FFmpeg.
Я убедился, что такой подход достаточен для того, чтобы не приходилось экранировать ни запятыя, ни точки с запятыми, ни квадратныя скобки (открывающія и закрывающія).
В качестве примѣра этакой утилиты я в январе упоминал cwebp (кодировщик формата WebP), у которого до сих пор не закрыта проблема с обработкою Unicode в именах файлов.
Чтобы этот примѣръ не оставался единственным, в качестве второго примѣра я сегодня назову утилиту NirCmd: по-видимому, исполнение команды «nircmd.exe clonefiletime да.pdf нѣтъ.pdf» не приводит к достижению желаемого результата по той только причине, что в имени у второго из двух указанных файлов есть ять.
Немного другую природу имѣютъ проблемы с передачею имён файлов в FFmpeg, о которых я также упоминал в январе. Ни один сѵмволъ не приводит FFmpeg к окончательной невозможности обработать желаемый файл, однако нѣкоторые сѵмволы воспринимаются в командной строке FFmpeg в качестве специальных, особенно при указании их внутри значения, передаваемого параметру фильтра.
Напримѣръ, так как видеопроигрыватели в Telegram пока ещё не повсемѣстно научили показывать субтитры из видеофайлов (кажется, для этого есть только глубоко сокрытая настройка, по умолчанию выключенная, да и то есть она не в каждом приложении Телеграма), и так как аналогично ведут себя видеопроигрыватели и в других соціальныхъ сѣтяхъ, то обычным этапом при подготовке нѣкоторой видеоцитаты становится впечатывание субтитров в пикселы видеокадров при помощи фильтра subtitles. Это вызывает значительныя проблемы даже при составлении командной строки вручную: скажем, автор вон того вопроса, на сайте SuperUser заданнаго, почувствовал себя принуждённым учетверять каждый сѵмволъ обратной косой черты, а также затрудняться с их количеством при экранировании апострофа в имени файла и двоеточия послѣ буквы диска в пути к файлу.
Если же рѣчь идёт не о простом составлении командной строки, а об автоматическом, то число сѵмволовъ, подлежащих экранированию, переваливает за полдесяток — напримѣръ, автор вон того куска кода, на сайте SuperUser приведённаго (на языке C#, насколько я догадываюсь), заэкранировал в командной строке при вызове FFmpeg и запятые, и точки с запятыми, и квадратныя скобки (и открывающія, и закрывающія), и апострофы, и двоеточия, а уж об экранировании обратных косых черт даже не задумывался (сразу сдался и начал с того, что замѣнилъ всѣ обратныя косыя черты на «простыя», «необратныя» косыя черты).
Послѣдній из этих приёмов (то есть предварительную замѣну обратных косых черт на необратныя вмѣсто экранирования их в пути к файлу) вы могли увидать используемым и в том примѣрѣ, в котором я указывал 2 мая пути ко скачанным файлам моделей внутри параметров фильтра whisper. Можете сравнить съ тѣмъ, как двоеточие, слѣдующее за буквою диска, было экранировано двойною обратною косою чертою.
Причём, если читать документацию по FFmpeg, то такое положеніе дѣлъ может показаться совершенно естественным. Поглядите в ней подраздѣлъ «Notes on filtergraph escaping», и в нём вы увидите примѣръ, в котором число обратных косых черт при экранировании одного-единственнаго апострофа доходит до шести — само собой разумѣется, что это ещё в полтора раза покруче, чѣмъ ихъ четырёхкратность въ примѣрѣ с сайта SuperUser.
В практическом отношении это означает, что моя задумка полностью отказаться от использования формата AVC (он же H.264) в пользу формата FFV1 при таком создании видеоцитат, которое не вносит новых потерь в них, которую я огласил 13 мая, в конечном итоге привела меня к сочинению бáтников (пакетных файлов) наподобие вот такого:
@echo off
ffmpeg -hide_banner -i %1 -vf "subtitles=%~nxs2:si=%3" -map %6 -map %7 -ss %4 -to %5 -sn %8 %9 -c:a libopus -b:a 64k -frame_duration 60 -c:v ffv1 -level 3 -g 300 -coder 1 -context 1 -slicecrc 0 -slices 30 -threads 16 -pix_fmt yuv420p10le -sws_dither ed -map_metadata -1 -map_chapters -1 step1.mkv
Как нетрудно видѣть, в этом бáтнике командную строку пополняют собою «как есть» и первый параметр (путь к видеофайлу), и третий (номер субтитров), и четвёртый да пятый (время начала и конца цитаты), и шестой (номер цитируемой видеодорожки), и седьмой (номер цитируемой аудиодорожки), и восьмой да девятый (содержащие, напримѣръ, параметры «-ac 2» для перевода объёмнаго звука в стереозвук).
А вот для второго параметра (имени файла субтитров) сдѣлано исключение: он не пополняет собою командную строку «как есть», а принуждается содержать только имя файла (с расширением имени файла), да и то в краткой форме (с надеждою на то, что сѵмволы, считающиеся спеціальными в FFmpeg, окажутся запрещёнными к появлению в кратком имени файла или хотя бы срѣзанными раньше, чѣмъ появятся в этом обрубке).
Понятно, что этот подход и неудобен (поскольку принуждает всякий раз наперёд копировать файл с субтитрами в тот «рабочий» подкаталог, в котором будет создаваться видеоцитата «step1.mkv»), и притом не на 100% надёжен по отношению к апострофам, имѣющимъ спеціальный смыслъ въ FFmpeg: насколько я понимаю, появление апострофа в начале краткого имени файла не запрещено операционною системою, а просто маловѣроятно.
(В предыдущем абзаце я выдѣлилъ жирностію словá «всякий раз» оттого, что в частных-то случаях необходимость копирования файла с субтитрами в «рабочий» подкаталог способна возникать, но по другим причинам — и тогда «иногда», а не «всякий раз».)
Недавно я понял, что безальтернативность столь небезупречного подхода — это иллюзия, вызванная двумя негативными факторами, каждый из которых сводится к прискорбной недодокументированности:
➊ Описание команды set на сайте Корпорации Microsoft ни словом не упоминает возможность примѣнить дополнительную операцию поиска и замѣны в момент подстановки значения нѣкоторой перемѣнной. Эта возможность всё ещё упоминается только в той подсказке, которая возникает при вызове команды «set /?» из командной строки, причём подсказку эту переводили на русский язык не слишком ясно (в частности, наивно предполагали возможность читателя фразы «расширит действие переменной среды PATH, заменяя каждое вхождение "str1" в расширенном результате на "str2"» сразу понять, что «дѣйствіемъ перемѣнной» названа подстановка значения перемѣнной, тогда как «расширенным результатом» назван результат поиска и замѣны в таком подставленном значении).
➋ Разсмотренный выше подраздѣлъ «Notes on filtergraph escaping» на сайте FFmpeg приходится признать однобоким и по названию, и по практической полезности: он содержит впечатляющие примѣры экранирования (escaping), но ни одного примѣра обрамления строк (quoting), и даже за описанием принципов их обрамления отсылает к другому подраздѣлу («Quoting and escaping»), который также (но ужé вопреки своему названию) не содержит ни одного практическаго примѣра оформления строк (quoting), а только теоретическое утверждение: строка между апострофами будет воспринятою в FFmpeg буквально.
Одновременно примѣняя то и другое «тайное знание», можно придать вот какой новый вид предыдущему бáтнику:
@echo off
set "SUBTITLEFILE=%~2"
set "SUBTITLEFILE=%SUBTITLEFILE:\=/%"
set "SUBTITLEFILE=%SUBTITLEFILE::=\:%"
set "SUBTITLEFILE=%SUBTITLEFILE:'=\\'%"
ffmpeg -hide_banner -i %1 -vf "subtitles='%SUBTITLEFILE%':si=%3" -map %6 -map %7 -ss %4 -to %5 -sn %8 %9 -c:a libopus -b:a 64k -frame_duration 60 -c:v ffv1 -level 3 -g 300 -coder 1 -context 1 -slicecrc 0 -slices 30 -threads 16 -pix_fmt yuv420p10le -sws_dither ed -map_metadata -1 -map_chapters -1 step1.mkv
Как видите, теперь в пути к файлу субтитров обратныя косыя черты замѣняются необратными, а затѣмъ экранируются только двоеточія да апострофы, а результат этого обрамлён с двух сторон апострофами же — для буквальнаго воспріятія его в FFmpeg.
Я убедился, что такой подход достаточен для того, чтобы не приходилось экранировать ни запятыя, ни точки с запятыми, ни квадратныя скобки (открывающія и закрывающія).