Звук больше не отстаёт от картинки
Рез всегда точный. Раньше начало куска притягивалось к ближайшему опорному кадру, а звук брался из непритянутой точки: по журналам сборки средняя притяжка 0.24 с, худшая 0.99 с, и на длинном куске этот сдвиг держится все его минуты. Плата за точность — доли секунды перекодирования на рез. Второй вид реза (Shift+S) стал тем же самым и убран. Разбор заголовка MP4 не учитывал список правок (elst): метки опорных кадров уезжали на задержку показа, на пробе два кадра. Сверка быстрого пути с ffprobe теперь совпадает точно, в том числе на записи с B-кадрами. Куску заказывается точное число кадров, а не только время: при копировании ffmpeg отмеряет конец по времени декодирования, и у записи с B-кадрами кусок выходил длиннее. Склейке длительность каждого куска задаётся явно. Последний пакет скопированного куска показывается позже прочих, контейнер считал его в длительность, и время картинки растягивалось — 0.05 с на кусок. Звука в кусках картинки больше нет: он не используется, а в MPEG-TS ещё и сбивает выравнивание склейки на 36 мс. Границы кусков ложатся на кадровую сетку: картинка выходит целым числом кадров, звук набирается до отсчёта, и доли кадра разводили их в стороны. Разогрев кодировщика звука компенсируется: сжатый AAC начинается со служебных отсчётов, MP4 помечает их пропускаемыми, Matroska — нет, и звук ехал на 21.3 мс позже. Величина меряется пробным сжатием. Продолжение прерванной сборки чинится заодно: готовность проверяется у каждой части, а не у куска целиком. При точном резе частей две, и вторая при продолжении терялась. В журнал сборки добавлена проверка синхронности: сколько кадров вышло и сколько просил монтаж, с вердиктом и худшей частью. Замер (tests/syncprobe.sh, исходник со вспышкой и щелчком на каждой секунде): было до 0.6 с и росло по ходу ролика, стало 0.02-0.04 с без накопления при точности измерения 0.017 с.
This commit is contained in:
parent
18e55d466e
commit
019d016db9
9 changed files with 849 additions and 158 deletions
77
README.md
77
README.md
|
|
@ -78,7 +78,6 @@ xdg-mime query default application/x-nlve-project
|
|||
| В начало / конец монтажа | Home / End |
|
||||
| Показать, где курсор (окно едет к нему) | \ |
|
||||
| Разрезать по курсору (все дорожки) | S |
|
||||
| Разрезать точно (перекодирует стык) | Shift+S |
|
||||
| Удалить выделенное | Delete |
|
||||
| Выделить всё | Ctrl+A |
|
||||
| Выделить областью | протяжка по пустому месту дорожек |
|
||||
|
|
@ -542,13 +541,26 @@ Linux потом искала по нему `.dll`.
|
|||
кусков нельзя, он на этом зависает. Заготовки делаются готовых длин
|
||||
(15 с, 60 с, 5 мин и так далее), а нужный кусок из них вырезается —
|
||||
тогда любое движение клипа не требует новой генерации.
|
||||
3. Начало каждого куска притягивается к опорному кадру, потому что копировать
|
||||
можно только с него. Конец притягивать не нужно — при копировании он и так
|
||||
получается кадроточным.
|
||||
4. При точном резе огрызок от точки реза до следующего опорного кадра
|
||||
перекодируется, остальное копируется.
|
||||
5. Куски склеиваются concat-демультиплексором, результат сверяется: сумма
|
||||
пакетов кусков обязана совпасть с числом пакетов в готовом файле.
|
||||
3. Границы кусков кладутся на кадровую сетку проекта: между кадрами
|
||||
времени нет, а звук набирается с точностью до отсчёта, и доли кадра
|
||||
разводят их в стороны.
|
||||
4. Рез всегда точный: огрызок от точки реза до ближайшего опорного кадра
|
||||
перекодируется, остальное копируется. Копировать можно только с
|
||||
опорного кадра, поэтому «резать где угодно и ничего не перекодировать»
|
||||
не бывает — но платить приходится долями секунды на рез.
|
||||
5. Каждому куску заказывается точное число кадров (`-frames:v`), а не
|
||||
только время: при копировании ffmpeg отмеряет конец по времени
|
||||
декодирования, и у записи с B-кадрами кусок выходит длиннее
|
||||
запрошенного.
|
||||
6. Куски склеиваются concat-демультиплексором с явно указанной
|
||||
длительностью каждого. Результат сверяется дважды: сумма пакетов кусков
|
||||
обязана совпасть с числом пакетов в готовом файле, а число кадров — с
|
||||
тем, что просил монтаж. Второе и есть проверка синхронности звука с
|
||||
картинкой; вердикт пишется в журнал сборки.
|
||||
|
||||
Звук в кусках картинки не хранится: звуковая дорожка собирается отдельно и
|
||||
точнее, а лишний поток в куске MPEG-TS ещё и сбивает тайминг склейки —
|
||||
замерено 36 мс на стык.
|
||||
|
||||
Напрашивающийся способ — один проход с директивами `inpoint` и `outpoint`,
|
||||
без временных файлов — проверен и отвергнут: он давал 574 кадра вместо 600
|
||||
|
|
@ -579,7 +591,8 @@ Linux потом искала по нему `.dll`.
|
|||
числе кадров. Лечится склейкой через промежуточный MPEG-TS, где параметры
|
||||
повторяются перед каждым опорным кадром — стало 0 ошибок. Способ выбирается
|
||||
автоматически: один источник и никаких точных резов — прямая склейка,
|
||||
иначе MPEG-TS.
|
||||
иначе MPEG-TS. Резы теперь всегда точные, так что на деле это почти всегда
|
||||
MPEG-TS.
|
||||
|
||||
**Лишний кадр на стыке точного реза.** При копировании `-to` работает как
|
||||
«строго меньше», при перекодировании — как «меньше либо равно». Кадр на
|
||||
|
|
@ -591,6 +604,33 @@ Matroska давали метки декодирования, идущие наз
|
|||
меток на шестьсот кадров. Коротким вставкам B-кадры не нужны, поэтому они
|
||||
запрещены (`-bf 0`).
|
||||
|
||||
**Звук отставал от картинки — четыре причины сразу.** Разбор занял день, и
|
||||
каждая находка мерялась, а не угадывалась (`tests/syncprobe.sh`: исходник
|
||||
со вспышкой и щелчком на каждой секунде, монтаж с резами не на опорных
|
||||
кадрах, поиск обоих следов в готовом ролике).
|
||||
|
||||
1. *Притянутый рез.* Начало куска картинки сдвигалось на ближайший опорный
|
||||
кадр, а звук брался из непритянутой точки: в журналах пользователя
|
||||
средняя притяжка 0.24 с, худшая 0.99 с. Лечится точным резом всегда.
|
||||
2. *Список правок MP4.* Разбор заголовка не учитывал блок `elst`, и метки
|
||||
опорных кадров уезжали на задержку показа — на пробе два кадра. Рез
|
||||
просил перекодировать до метки, которая опорным кадром не была.
|
||||
3. *Конец куска при копировании.* `-to` отмеряет по времени декодирования,
|
||||
и у записи с B-кадрами кусок выходил длиннее запрошенного. Лечится
|
||||
явным числом кадров (`-frames:v`).
|
||||
4. *Длительность куска в склейке.* Последний пакет скопированного куска
|
||||
показывается позже всех прочих, контейнер считает его в длительность, и
|
||||
склейка растягивала время — 0.05 с на кусок. Лечится директивой
|
||||
`duration` в списке склейки. Туда же: звук внутри кусков картинки сбивал
|
||||
выравнивание на 36 мс, теперь его там нет.
|
||||
|
||||
Плюс «разогрев» кодировщика звука: сжатый AAC начинается со служебных
|
||||
отсчётов, MP4 помечает их пропускаемыми, Matroska такой пометки не хранит —
|
||||
звук ехал на 21.3 мс позже. Величина меряется пробным сжатием и вычитается.
|
||||
|
||||
Итог замера на образце: было до 0.6 с и росло по ходу ролика, стало 0.02-0.04 с
|
||||
без накопления, при точности самого измерения 0.017 с.
|
||||
|
||||
**Вставка под каждую длину дыры.** Сначала под каждую дыру делался чёрный
|
||||
клип ровно её длины. Любое движение клипа меняло длину дыры, требовало
|
||||
новой генерации, и до её готовности предпросмотр играл прежнюю расстановку.
|
||||
|
|
@ -703,11 +743,30 @@ Wine с новой библиотекой не грузилось ничего.
|
|||
./tests/nlvetool build <проект> <видео> [<картинка>]
|
||||
./tests/nlvetool buildcut <проект> <видео>
|
||||
./tests/nlvetool render <проект> <выход>
|
||||
./tests/nlvetool syncproj <проект> <видео> монтаж для замера синхронности
|
||||
```
|
||||
|
||||
Команды возвращают ненулевой код при расхождении, поэтому годятся для
|
||||
автоматической проверки.
|
||||
|
||||
Отдельно — замер синхронности звука и картинки:
|
||||
|
||||
```
|
||||
./tests/syncprobe.sh весь прогон: образец, сборка, замер
|
||||
./tests/syncprobe.sh measure ФАЙЛ замер готового файла
|
||||
```
|
||||
|
||||
Как он устроен. Делается исходник, где ровно на каждой секунде в кадре
|
||||
белая вспышка, а в звуке щелчок. Из него собирается монтаж, у которого
|
||||
начала кусков заведомо не попадают на опорные кадры. В готовом ролике
|
||||
ищутся времена вспышек и щелчков: если они разошлись — звук уехал от
|
||||
картинки, и видно, на сколько и с какого куска.
|
||||
|
||||
Времена щелчков считаются по самим отсчётам (`tests/clicktimes.py`), а не
|
||||
оконным анализом: окно двигается кратно своему размеру, и его собственный
|
||||
уход выглядит как накапливающийся рассинхрон, которого нет. На это уже
|
||||
попались один раз.
|
||||
|
||||
## Структура
|
||||
|
||||
| Файл | Что это |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue