nlve/BACKLOG.md

220 lines
17 KiB
Markdown
Raw Normal View History

# Что отложено
Список того, что известно и сознательно не сделано. Не «когда-нибудь
починим», а «знаем, чего это стоит, и решили пока не платить».
## macOS: собирается, но работает наполовину
Сборка проверена. В тулчейне fpcupdeluxe уже стоит всё нужное:
кросс-компиляторы, Apple SDK (10.13, 11.0, 12.3) и виджетсет cocoa для
обеих архитектур. Обе цели собираются с первого раза:
./build.sh macos → nlve_intel (Mach-O x86_64)
nlve_arm (Mach-O arm64)
Чего не будет, пока не сделано:
**Предпросмотра нет.** Встраивание mpv написано под два случая: X11 (под
gtk2 создаётся своё дочернее окно и его номер отдаётся mpv в `wid`) и
Windows (там у панели есть настоящий HWND). Под cocoa нужен третий путь —
отдать mpv указатель на NSView. Это не правка на десять строк: нужно
разобраться, как LCL под cocoa отдаёт NSView панели, и проверить, что mpv
рисует именно в неё.
**Окно зависимостей врёт.** Списки в `uDeps.pas` разделены на два случая:
Windows и всё остальное. Мак попадает во второй и получает совет
`sudo apt install ffmpeg`. Нужен свой список: `brew install ffmpeg mpv`
или готовые сборки.
**Проверить нечем.** У нас нет мака. Собранный, но ни разу не запущенный
файл — это предположение, а не сборка. Всё, что можно утверждать сейчас:
компилятор и компоновщик отработали без ошибок.
**Двух файлов может оказаться мало.** Intel и Apple Silicon сейчас
раздаются отдельно. Склеить их в один универсальный умеет `lipo`, но в
тулчейне он есть только для powerpc — для x86_64 и arm64 его надо
доставить.
**Обёртка .app не настроена.** lazbuild её создаёт, но внутри лежит
ссылка на файл с именем `nlve`, которого после переименования нет.
Сейчас она просто удаляется. Настоящему приложению нужны свой Info.plist,
значок и, для раздачи, подпись и нотаризация у Apple.
## Лицензия не выбрана
libmpv грузится в наш процесс, а её сборки — GPL (в Ubuntu GPL-3+ из-за
libsmbclient, у shinchiro тоже GPL). По толкованию FSF это делает
совместную работу производной, и при раздаче программа должна быть под
GPL-3+ или совместимой.
Пока ничего не раздаётся — вопрос не стоит. Решать его перед первой
раздачей сборок. Возможный обход: отказаться от libmpv в пользу своего
вывода кадров через ffmpeg, но это большая работа и заметно хуже по
плавности.
ffmpeg проблемой не является: он запускается отдельной программой.
Цветовой ключ и живое наложение в предпросмотре Клипу задаётся цвет, который при сборке становится прозрачным. Окно ключа показывает кадр: цвет берётся щелчком по нему, выбитое показано клеткой, допуск и смягчение края — ползунками. Открывается из окна кадрирования и из меню «Правка», на монтаже клип помечен квадратиком выбиваемого цвета. Предпросмотр перестал сводить такие участки в файлы. Плеер играет две дорожки одна поверх другой: оверлей во весь ролик больше не заставляет пересобирать весь фильм после каждой правки. Замерено: наложение стоит 0.4 с на 10 с материала 2688x1512, вчетверо быстрее реального времени. Починено в сборке: уменьшенный клип обкладывался чёрными полями, и они закрывали собой нижнее видео — оставалась видна только дырка, выбитая ключом. Теперь верхний слой кладётся по координатам, тем же, по которым его показывает предпросмотр. Смещение по горизонтали и вертикали работает и там, где картинка меньше кадра проекта: раньше уменьшенный клип нельзя было сдвинуть в угол. Проверки форм теперь создают каждое окно из файла формы: элемент, забытый в классе, вскрывается на сборке, а не при открытии окна.
2026-08-31 00:10:28 +03:00
## Настоящая прозрачность в исходном файле
Цветовой ключ выбивает цвет, но бывает и прозрачность, записанная в самом
файле: WebM с VP8/VP9, ProRes 4444, QuickTime Animation. ffmpeg их
распаковывает в кадр с альфа-каналом, и ключ таким файлам не нужен —
достаточно не выбрасывать альфу по дороге.
Что для этого потребуется, когда дойдут руки:
- при добавлении файла запоминать, есть ли у него альфа (`pix_fmt` с
буквой «a»: yuva420p, yuva444p10le, argb);
- такой клип считать несплошным так же, как клип с ключом, — то есть
собирать участок слоями;
- в цепочке фильтров следить, чтобы альфа не терялась: `scale` её
сохраняет, а `pad` — только с прозрачным цветом полей;
- аппаратное декодирование к таким файлам не применять: альфа в VP9
лежит отдельным потоком, и видеокарта его не отдаёт.
Чего не будет в любом случае: раздать готовый ролик с прозрачностью в
MP4/H.264 нельзя — контейнер и кодек альфу не хранят. Для этого нужен
отдельный вывод в VP9 или ProRes 4444.
Предпросмотр показывает кадрирование клипа Клип со своим кадрированием играл в окне во весь кадр: цепочка фильтров у mpv одна на весь список кусков, а включить её на одном куске и выключить на следующем нечем — из фильтров ffmpeg по времени переключается только наложение. Обошлось без цепочки вовсе. У вывода mpv своя обрезка, и делает её видеокарта: курсор зашёл в клип с кадрированием — выставили, вышел — сняли. Ни перестройки цепочки, ни копирования кадров из памяти видеокарты в обычную. Рамку источника считает теперь один код на две стороны: по ней окно «Кадрирование и поворот» рисует рамку, и её же плеер отдаёт как обрезку. Проверка в tests/lfmcheck сверяет рамку с фильтром сборки: увеличение 2.77 даёт 970x546 посередине, и это ровно то, что вырезает crop=2688:1512:2379:1338 после scale=7446:4188. Проверено глазами на невидимом экране, на настоящем материале с дрона: картинка в окне совпала с готовым роликом, на границе с обычным клипом обрезка снимается и возвращается. Сверено со сборкой из прошлого коммита — там на том же месте кадр без кадрирования. Не покрыто и записано в BACKLOG: отражение (свойства для него нет), растяжение и участки с наложением — там кадр уже сведён цепочкой.
2026-10-01 00:04:57 +03:00
## Предпросмотр: чего он про кадрирование всё ещё не показывает
Предпросмотр показывает кадрирование клипа Клип со своим кадрированием играл в окне во весь кадр: цепочка фильтров у mpv одна на весь список кусков, а включить её на одном куске и выключить на следующем нечем — из фильтров ffmpeg по времени переключается только наложение. Обошлось без цепочки вовсе. У вывода mpv своя обрезка, и делает её видеокарта: курсор зашёл в клип с кадрированием — выставили, вышел — сняли. Ни перестройки цепочки, ни копирования кадров из памяти видеокарты в обычную. Рамку источника считает теперь один код на две стороны: по ней окно «Кадрирование и поворот» рисует рамку, и её же плеер отдаёт как обрезку. Проверка в tests/lfmcheck сверяет рамку с фильтром сборки: увеличение 2.77 даёт 970x546 посередине, и это ровно то, что вырезает crop=2688:1512:2379:1338 после scale=7446:4188. Проверено глазами на невидимом экране, на настоящем материале с дрона: картинка в окне совпала с готовым роликом, на границе с обычным клипом обрезка снимается и возвращается. Сверено со сборкой из прошлого коммита — там на том же месте кадр без кадрирования. Не покрыто и записано в BACKLOG: отражение (свойства для него нет), растяжение и участки с наложением — там кадр уже сведён цепочкой.
2026-10-01 00:04:57 +03:00
Кадрирование обычного клипа окно теперь показывает — обрезкой на выводе
плеера, её делает видеокарта даром. Остались три случая, где оно
по-прежнему играется как есть, и для них точную картинку даёт окно
«Кадрирование и поворот»:
Предпросмотр показывает кадрирование клипа Клип со своим кадрированием играл в окне во весь кадр: цепочка фильтров у mpv одна на весь список кусков, а включить её на одном куске и выключить на следующем нечем — из фильтров ffmpeg по времени переключается только наложение. Обошлось без цепочки вовсе. У вывода mpv своя обрезка, и делает её видеокарта: курсор зашёл в клип с кадрированием — выставили, вышел — сняли. Ни перестройки цепочки, ни копирования кадров из памяти видеокарты в обычную. Рамку источника считает теперь один код на две стороны: по ней окно «Кадрирование и поворот» рисует рамку, и её же плеер отдаёт как обрезку. Проверка в tests/lfmcheck сверяет рамку с фильтром сборки: увеличение 2.77 даёт 970x546 посередине, и это ровно то, что вырезает crop=2688:1512:2379:1338 после scale=7446:4188. Проверено глазами на невидимом экране, на настоящем материале с дрона: картинка в окне совпала с готовым роликом, на границе с обычным клипом обрезка снимается и возвращается. Сверено со сборкой из прошлого коммита — там на том же месте кадр без кадрирования. Не покрыто и записано в BACKLOG: отражение (свойства для него нет), растяжение и участки с наложением — там кадр уже сведён цепочкой.
2026-10-01 00:04:57 +03:00
**Отражение.** У вывода mpv нет свойства для отражения, только для
поворота. Понадобится — придётся вести такой клип через цепочку.
Предпросмотр показывает кадрирование клипа Клип со своим кадрированием играл в окне во весь кадр: цепочка фильтров у mpv одна на весь список кусков, а включить её на одном куске и выключить на следующем нечем — из фильтров ffmpeg по времени переключается только наложение. Обошлось без цепочки вовсе. У вывода mpv своя обрезка, и делает её видеокарта: курсор зашёл в клип с кадрированием — выставили, вышел — сняли. Ни перестройки цепочки, ни копирования кадров из памяти видеокарты в обычную. Рамку источника считает теперь один код на две стороны: по ней окно «Кадрирование и поворот» рисует рамку, и её же плеер отдаёт как обрезку. Проверка в tests/lfmcheck сверяет рамку с фильтром сборки: увеличение 2.77 даёт 970x546 посередине, и это ровно то, что вырезает crop=2688:1512:2379:1338 после scale=7446:4188. Проверено глазами на невидимом экране, на настоящем материале с дрона: картинка в окне совпала с готовым роликом, на границе с обычным клипом обрезка снимается и возвращается. Сверено со сборкой из прошлого коммита — там на том же месте кадр без кадрирования. Не покрыто и записано в BACKLOG: отражение (свойства для него нет), растяжение и участки с наложением — там кадр уже сведён цепочкой.
2026-10-01 00:04:57 +03:00
**Растяжение.** Кадр жмётся неравномерно, рамкой это не описать.
Предпросмотр показывает кадрирование клипа Клип со своим кадрированием играл в окне во весь кадр: цепочка фильтров у mpv одна на весь список кусков, а включить её на одном куске и выключить на следующем нечем — из фильтров ffmpeg по времени переключается только наложение. Обошлось без цепочки вовсе. У вывода mpv своя обрезка, и делает её видеокарта: курсор зашёл в клип с кадрированием — выставили, вышел — сняли. Ни перестройки цепочки, ни копирования кадров из памяти видеокарты в обычную. Рамку источника считает теперь один код на две стороны: по ней окно «Кадрирование и поворот» рисует рамку, и её же плеер отдаёт как обрезку. Проверка в tests/lfmcheck сверяет рамку с фильтром сборки: увеличение 2.77 даёт 970x546 посередине, и это ровно то, что вырезает crop=2688:1512:2379:1338 после scale=7446:4188. Проверено глазами на невидимом экране, на настоящем материале с дрона: картинка в окне совпала с готовым роликом, на границе с обычным клипом обрезка снимается и возвращается. Сверено со сборкой из прошлого коммита — там на том же месте кадр без кадрирования. Не покрыто и записано в BACKLOG: отражение (свойства для него нет), растяжение и участки с наложением — там кадр уже сведён цепочкой.
2026-10-01 00:04:57 +03:00
**Участок с наложением.** Там кадр уже сведён цепочкой, и обрезка на
выводе резала бы сведённое целиком, вместе с нижним слоем. Такой клип
нужно вести через ту же цепочку, что и само наложение.
Цена пути через цепочку известна, мерили (DJI 2688x1512, HEVC
55 Мбит/с, 600 кадров, `--vo=null`):
| | время | кадров в секунду |
|---|---|---|
| без фильтра | 1.82 с | 330 |
| ветка «обрезать и растянуть» с `enable` | 2.81 с | 214 |
Предпросмотр показывает кадрирование клипа Клип со своим кадрированием играл в окне во весь кадр: цепочка фильтров у mpv одна на весь список кусков, а включить её на одном куске и выключить на следующем нечем — из фильтров ffmpeg по времени переключается только наложение. Обошлось без цепочки вовсе. У вывода mpv своя обрезка, и делает её видеокарта: курсор зашёл в клип с кадрированием — выставили, вышел — сняли. Ни перестройки цепочки, ни копирования кадров из памяти видеокарты в обычную. Рамку источника считает теперь один код на две стороны: по ней окно «Кадрирование и поворот» рисует рамку, и её же плеер отдаёт как обрезку. Проверка в tests/lfmcheck сверяет рамку с фильтром сборки: увеличение 2.77 даёт 970x546 посередине, и это ровно то, что вырезает crop=2688:1512:2379:1338 после scale=7446:4188. Проверено глазами на невидимом экране, на настоящем материале с дрона: картинка в окне совпала с готовым роликом, на границе с обычным клипом обрезка снимается и возвращается. Сверено со сборкой из прошлого коммита — там на том же месте кадр без кадрирования. Не покрыто и записано в BACKLOG: отражение (свойства для него нет), растяжение и участки с наложением — там кадр уже сведён цепочкой.
2026-10-01 00:04:57 +03:00
Нужно 60, то есть запас трёхкратный: по деньгам проходит. Устроена она
так: раздвоить поток, одну ветку обрезать и растянуть, и наложить её на
другую с `enable='between(t,...)'`. Иначе никак — из фильтров ffmpeg по
времени переключается только `overlay`, у `crop` и `scale` поддержки
временной шкалы нет.
## Два видео рядом в одном кадре
Два ролика 16:9, каждый обрезан до половины кадра: один слева до
середины, другой от середины вправо. Никакого смешивания, просто два
куска рядом.
Сборке для этого не нужно ничего нового — только числа. Проверено на
настоящих файлах, кадр получается с первого раза:
[0:v]crop=1344:1512:672:0,pad=2688:1512:0:0,setsar=1[l];
[1:v]crop=1344:1512:672:0,setsar=1[r];
[l][r]overlay=1344:0[out]
То есть каждому источнику своя обрезка, затем оба кладутся на свои места.
Именно такой граф и строит `ArgsRenderLayers`: у слоя уже есть и своя
цепочка фильтров, и координаты, куда его положить.
Не хватает трёх вещей, и первая — главная.
**Клипу негде записать, какое место в кадре он занимает.** Преобразование
сейчас описывает только, как источник ложится в кадр целиком: вписать,
заполнить с обрезкой, увеличение, смещение, поворот. Масштаб при этом
всегда равномерный, поэтому из кадра 2688x1512 никакими настройками не
получить полосу 1344x1512 — для неё нужно сжать вдвое по ширине и не
трогать высоту. Нужен прямоугольник назначения: четыре числа в долях
кадра проекта. Тогда всё остальное — вписывание, увеличение, смещение —
начинает работать внутри него, а `BuildTransform` меняется только в
аргументах: размер прямоугольника вместо размера кадра, а возвращаемые
координаты сдвигаются на его начало.
**Уплощение считает непрозрачный клип закрывающим всё.** Нижний клип
подхватывается, только когда верхний полупрозрачный или с ключом. Значит
половинка на верхней дорожке сегодня закроет собой нижнее видео чёрными
полями. Условие должно смотреть на прямоугольник назначения: не накрывает
кадр — значит под ним видно то, что ниже.
**Предпросмотру нужна вторая дорожка наложения.** Сейчас плеер добавляет
одну: основа — список кусков, поверх неё одна внешняя дорожка. Для двух
половинок обе должны идти через цепочку над чёрной основой, то есть
внешних дорожек нужно две. Механика та же самая — ещё один `video-add` и
ещё один вход `[vidN]` в цепочке.
Переключателей, которые стоят машинного времени, становится больше, а
живут они кто где: прилипание и схлопывание — кнопками внизу, ключ в
предпросмотре — в меню «Вид», выбор кодировщика вообще нигде (берётся
NVENC, если он есть). Это разрозненно и не даёт увидеть общую цену.
Нужно одно окно, где собрано всё, что можно выключить ради скорости:
- ключ и прозрачность в предпросмотре (сейчас в меню «Вид»);
- наложение в предпросмотре вообще — на слабой машине может не хватать и
его, тогда честнее показывать одну основу;
- кодировщик для пересборки: аппаратный или процессорный, и какой
именно;
- где держать кэш и когда его убирать;
- прилипание клипов и курсора (сейчас кнопками, но им место и здесь).
Почему это важно: разработка идёт на машине с быстрой видеокартой, и
всё, что здесь считается «недорогим», на другой может оказаться
неподъёмным. Пока цифры замеряны только на одной машине, у человека
должна быть возможность выключить любую из этих трат.
## Сборка потоком: чего она не даёт
Ролик собирается потоком — куски идут сразу в готовый файл, кэш не
создаётся. За это заплачено тремя вещами, и все три известны заранее.
**Продолжение стоит места.** Дописать в конец существующего MKV нельзя:
Matroska этого не даёт. Продолжение всегда пишется в новый файл, куда
сперва переливается целая часть старого, так что на диске в этот момент
лежат оба — места нужно вдвое больше готового ролика. Обойти это можно
только разбором и правкой самого контейнера, а это уже своя маленькая
библиотека Matroska.
**Отступ назад — до целого куска.** Продолжают не с последнего
записанного кадра, а с границы последнего целого куска: кусок — это
неделимая единица, у него свои метки времени и своё число кадров. На
замерах терялось от нуля до нескольких секунд работы. Мельче отступать
можно было бы, храня рядом с файлом карту стыков, но выигрыш в секундах
не стоит нового файла, который надо держать в согласии с роликом.
**MP4 продолжать нельзя вовсе.** Оглавление пишется в конец, оборванный
файл не открывается — `moov atom not found`. Программа предупреждает об
этом до начала сборки и предлагает MKV. Теоретически недописанный MP4
можно восстановить, собрав оглавление по кускам самому (так делают
untrunc и подобные), но это отдельная задача другого размера.
**Потоком идёт не всё.** MPEG-TS несёт не любой кодек, и пересборка
всего ролика под площадку требует списка кусков. В этих случаях сборка
идёт по-старому, через кэш — со всеми его 110 ГБ на часе материала.
## Мелочи, до которых не дошли руки
Клип не попадает на дорожку чужого вида В живом проекте фотография оказалась на текстовой дорожке, а надпись — на дорожке картинки. Уплощение обходит дорожки по видам, и такой клип не видит ни сборка, ни предпросмотр: на монтаже он нарисован, в готовом ролике его нет, и ни одной жалобы по дороге. Именно это и было причиной пропавших фотографии и текста, а не ошибка со стоп-кадром. Теперь перетаскивание на дорожку чужого вида не проходит, а файл из списка, брошенный на такую дорожку, ложится на подходящую — с записью в журнал, куда именно. Новая дорожка, заведённая перетаскиванием вниз, заводится того вида, какой нужен клипу. При открытии проекта такие клипы пересчитываются, и программа предлагает перенести их на подходящие дорожки, сохранив время. Молча не переносим: клип мог оказаться там осознанно, и внезапный переезд — сюрприз хуже пропажи. Проверка 10 в nlvetool flattest: картинка на текстовой дорожке в уплощение не попадает, после переноса попадает и остаётся на своём месте.
2026-08-31 11:12:05 +03:00
**Вид дорожки не виден в её заголовке.** Дорожки картинки, звука и текста
подписаны V1, A1, Т1, и по букве вид угадывается, но не более того.
Клип, попавший на дорожку чужого вида, теперь не принимается и не
теряется, но само различие стоило бы показать явно — значком или цветом
полосы заголовка.
**Значок файла программы под Windows.** Значок окна задаётся из
`uIconData`, а значок самого `.exe` в проводнике берётся из ресурса при
сборке — там он до сих пор стандартный.
Цветовой ключ и живое наложение в предпросмотре Клипу задаётся цвет, который при сборке становится прозрачным. Окно ключа показывает кадр: цвет берётся щелчком по нему, выбитое показано клеткой, допуск и смягчение края — ползунками. Открывается из окна кадрирования и из меню «Правка», на монтаже клип помечен квадратиком выбиваемого цвета. Предпросмотр перестал сводить такие участки в файлы. Плеер играет две дорожки одна поверх другой: оверлей во весь ролик больше не заставляет пересобирать весь фильм после каждой правки. Замерено: наложение стоит 0.4 с на 10 с материала 2688x1512, вчетверо быстрее реального времени. Починено в сборке: уменьшенный клип обкладывался чёрными полями, и они закрывали собой нижнее видео — оставалась видна только дырка, выбитая ключом. Теперь верхний слой кладётся по координатам, тем же, по которым его показывает предпросмотр. Смещение по горизонтали и вертикали работает и там, где картинка меньше кадра проекта: раньше уменьшенный клип нельзя было сдвинуть в угол. Проверки форм теперь создают каждое окно из файла формы: элемент, забытый в классе, вскрывается на сборке, а не при открытии окна.
2026-08-31 00:10:28 +03:00
**Кэш наложений не убирается.** Каждая правка наплыва создаёт в кэше
проекта новый файл; старые остаются лежать. Клипы с ключом и
прозрачностью сюда больше не попадают — их показывает сам плеер, — так
что расти кэшу теперь почти не с чего.
**Окно кадрирования открывается около четырёх секунд.** Оно синхронно
достаёт два кадра ffmpeg-ом (по 2.2 с каждый на шестигигабайтном файле) и
только потом показывается. Лечится показом окна сразу и дорисовкой кадра
по готовности, либо одним кадром вместо двух.