Я добавляю субтитры к видео с помощью ffmpeg двумя разными способами. Первый способ — использовать команду drawtext
, и в этом случае все работает отлично. Вот команда
ffmpeg -i ./input.mp4 -vf "drawtext=text='reise':fontfile=../fonts/Audiowide-Regular.ttf:fontsize=55:fontcolor=white:x=0:y=683" -codec:a copy ./output.mp4
Второй способ — использовать файл субтитров. Таким образом, я получил меньшие буквы и неправильное положение текста. Ниже приведено содержимое файла субтитров задницы.
[Script Info]
Title: Advanced Highlighted Subtitle Example
ScriptType: v4.00+
WrapStyle: 0
PlayResX: 1048
PlayResY: 750
[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default,Audiowide Regular,55,&HFFFFFF,&H00FFFFFF,&H00000000,&H00000000,1,0,0,0,100,100,0,0,0,0,0,2,10,10,10,1
[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Dialogue: 0,00:00:0.00,00:00:2.38,Default,,0,0,0,,{\pos(0,683)\an4}reise
И команда для второго захода
ffmpeg -i ./input.mp4 -vf "ass=../subtitles.ass:fontsdir=../fonts/Audiowide-Regular.ttf" ../output.mp4
Таким образом, они оба получают одно и то же видео, один и тот же шрифт и один и тот же текст. Проблема в том, что в случае использования файла ass текст становится намного меньше и смещается
Цифры на оси обозначают размеры в пикселях. Как вы можете видеть на втором изображении, оно намного меньше и имеет неверную координату y. Кажется, у него неправильные цифры масштабирования. Что не так с моими конфигурациями файлов задницы?
Я попробовал решение от [universalmediaserver] для удаления PlayResX/Y, но оно не работает. (https://www.universalmediaserver.com/forum/viewtopic.php?t=5907). Я также пытался измерить ширину текста многими другими способами (например, в HTML, отображаемом в браузере, на холсте...), поэтому я почти уверен, что drawtext
действительно дает правильно отображаемую ширину. Проблема связана с файлом субтитров. Кроме того, если я использую популярные шрифты, такие как Arial, отклонение будет намного меньше.
Фильтр drawtext
FFmpeg интерпретирует размер шрифта текста иначе, чем средства рендеринга ASS (например, Libass). Фильтр drawtext
использует номинальный размер шрифта (в пикселях), масштабируя его в соответствии с единицами на EM. Напротив, средства визуализации ASS используют реальные размеры шрифта для масштабирования, которые они определяют путем суммирования поля ascender
и минусового значения поля descender
из таблиц шрифта (таких как OS/2 и hhea).
Таким образом, чтобы сопоставить размер между drawtext
и ASS в FFmpeg, нам нужно найти способ вычисления реального размера шрифта (ASS) из номинального размера (drawtext
). Итак, давайте сначала рассчитаем базовый размер шрифта, который затем будет использоваться для его масштабирования.
Для номинального размера нам нужно прочитать unitsPerEm
из Таблицы заголовков шрифтов, в случае шрифта Audiowide это 2048.
Для реального размера измерения нам нужно получить значение полей ascender
и descender
, которые можно найти в таблице hhea, в случае шрифта Audiowide его верхний предел равен 2027, а нижний - -584.
Итак:
Номинальный размер = unitsPerEm
= 2048
Реальный размер измерения = ascender
- descender
= 2027 - (-584) = 2611
Таким образом, реальный размер измерения в некотором масштабе больше.
Масштаб = Реальный размер / Номинальный размер = 2611/2048 ≈ 1,279
Итак, нам нужно умножить исходный размер шрифта (55) на масштабный коэффициент: 55 * 1,279 ≈ 70,345.
Во-вторых, обратите внимание, что фильтр drawtext использует другое выравнивание, чем тег выравнивания \an4 в ASS, который вы использовали, что соответствует выравниванию по левому краю. Чтобы совместить позиции, вы должны использовать \an7 (выравнивание по левому краю) в ASS.
В-третьих, drawtext
выравнивает текст по самому высокому глифу (по историческим причинам), а не по базовой линии плюс восхождение (как это обычно делается), но вы можете изменить это, установив y_align=font
в фильтре drawtext
.
Итак, вот исправленный файл сценария ASSv4+:
[Script Info]
Title: Advanced Highlighted Subtitle Example
ScriptType: v4.00+
WrapStyle: 0
PlayResX: 1048
PlayResY: 750
[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default,Audiowide,70.345,&H00FFFFFF,&H00FFFFFF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,0,0,2,10,10,10,1
[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Dialogue: 0,00:00:0.00,00:00:2.38,Default,,0,0,0,,{\pos(0,683)\an7}reise
И исправлена команда FFmpeg:
ffmpeg -i ./input.mp4 -vf "drawtext=text='reise':fontfile=../fonts/Audiowide-Regular.ttf:fontsize=55:fontcolor=white:x=0:y=683:y_align=font" -codec:a copy ./output.mp4
Ниже приведен пример того, как читать значения метрик из шрифта с помощью Freetype (это то, что drawtext
и средство рендеринга ASS Libass использует под капотом для рендеринга шрифтов) в Python:
import freetype
face = freetype.Face('path/to/your/fontfile.ttf')
units_per_em = face.units_per_EM
ascender = face.ascender
descender = face.descender
print(f"Units per EM: {units_per_em}")
print(f"Ascender: {ascender}")
print(f"Descender: {descender}")
Результат для шрифта Audiowide должен быть:
Units per EM: 2048
Ascender: 2027
Descender: -584
И вы можете установить необходимую библиотеку, используя:
python -m pip install freetype-py