Commit graph

28 commits

Author SHA1 Message Date
235cd00e9a Предпросмотр показывает кадрирование клипа
Клип со своим кадрированием играл в окне во весь кадр: цепочка фильтров
у 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
d0ec869743 Масштаб таймлайна берётся от точки под мышкой
Ctrl с колесом должен оставлять на месте то, на что смотрит мышь, а
оставлял точку левее — ровно на левый край таймлайна. При мыши у левого
края опора и вовсе уходила за пределы окна.

Причина: MousePos у DoMouseWheel по описанию экранный, но под gtk2 в нём
уже клиентские координаты, и ScreenToClient переводил их второй раз.
Берём Mouse.CursorPos — он экранный в любой системе.

Замерено на невидимом экране: до правки мышь в 700, 1000 и 1300 давала
опору в 260, 560 и 860; после — ровно 700, 1000 и 1300. Проверка
оформлена в tests/zoomanchor.py и прогнана на обеих сборках: на прежней
она падает, на новой проходит.
2026-09-30 20:45:32 +03:00
f841ed79ec Честное предупреждение о контейнере и отметка недописанной сборки
У MP4 два неудобства, о которых человек узнавал поздно: прерванную
сборку в нём продолжить нельзя вовсе, а перекодированный стык точного
реза воспроизводится правильно не везде. Теперь об обоих говорится до
начала работы, одним окном с кнопками «Собрать в MKV», «Всё равно mp4»,
«Не собирать».

Признак точного реза заодно исправлен: смотрели на отметку edPrecise,
а резы стали точными всегда — предупреждение молчало. Теперь признак —
клип, начинающийся не с начала файла.

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

Ещё: на каждом стыке кусков приёмник писал «Packet corrupt», по паре
строк на кусок. Данные целы, но журнал забивался, и настоящую ошибку в
нём было не найти. Лечится ключом -mpegts_flags +initial_discontinuity
у отправителя: сверено по кадрам и по md5, результат тот же.
2026-09-30 16:48:31 +03:00
4522f0000a Продолжение прерванной сборки потоком — с недописанного файла
Потоком кэша кусков нет, и продолжать было не с чего. Но недописанный
файл сам по себе — уже собранная часть фильма: в нём видно, сколько
целых кадров успело записаться. Программа отступает до границы
последнего целого куска, переносит эту часть и досылает остаток.

Дописать в конец существующего MKV нельзя, поэтому продолжение пишется
в новый файл. MP4 продолжать нельзя вовсе: оглавление в конце, и
оборванный файл не открывается — об этом говорится прямо.

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

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

В nlvetool у render появились --cancel-after=<сек> и сочетание слов:
cache resume проверяет, что старый путь через кэш не сломался.
2026-09-30 16:37:28 +03:00
38f4b295b9 Сборка потоком: куски идут сразу в готовый файл, без кэша
Раньше каждый кусок монтажа вырезался в отдельный файл, и только потом
список этих файлов шёл на склейку. Кэш весил столько же, сколько готовый
фильм — замерено 110 ГБ на часе материала, — а диск писал всё дважды.

Теперь каждый кусок режется своим ffmpeg прямо в MPEG-TS на стандартный
вывод, все потоки подряд переливаются в один принимающий ffmpeg, а тот
пишет готовый файл. Место куску задаёт -output_ts_offset, считаемый в
кадрах от начала. На диск ложится только результат и звуковая дорожка.

Через кэш по-прежнему собирается то, что потоком не выходит: кодек, не
переносимый в MPEG-TS, и пересборка всего ролика под площадку.

Сверено на четырёх монтажах, включая настоящий материал с дрона
(HEVC 2688x1512, 55 Мбит/с, файлы с шестью потоками): картинка совпала
попиксельно, PSNR бесконечен на каждом кадре, длина и размер те же.
Сверка шла и с прошлым выпуском, а не только нового пути со старым.
На отрывке в 17.5 с: 14.2 с и 421 КБ на диске против 17.5 с и 152 МБ.

По дороге найдены две ловушки, обе записаны в README:
-avoid_negative_ts make_zero отменяет -output_ts_offset, а -fflags
+igndts у приёмника сминает кадры на стыках.
2026-09-30 16:12:00 +03:00
aba9bd57e4 Кнопки внизу: подсказка не перехватывает щелчок, щелчки не теряются
Две беды у всех кнопок нижней полосы.

Всплывающая подсказка появлялась прямо поверх кнопки, о которой
рассказывает, и перехватывала щелчок: нажать кнопку было нельзя.
Подсказка переехала в строку состояния — она в той же полосе, ничего не
закрывает и меняется сразу после щелчка, не дожидаясь нового наведения.
Строка состояния теперь занимает всё свободное место справа, пока рядом
не показан ход работы, а самые длинные подсказки укорочены: раньше их
обрезало на полуслове.

Второй щелчок подряд виджетсет отдавал как двойной, и кнопка его не
видела: быстрая очередь щелчков срабатывала через раз. У кнопки убран
csDoubleClicks, а на случай, если двойной всё же дойдёт, он считается
за обычный.

Проверено: tests/lfmcheck, раздел «Кнопки нижней панели», и
tests/buttonclicks.sh мышью на невидимом экране — по всем шести
переключателям очереди из 1-5 щелчков отрабатываются полностью.
2026-09-30 15:44:29 +03:00
6617e29514 Выделение по времени, рез по краям промежутка, курсор идёт за резом
Режимов выделения стало два, переключаются клавишей D и кнопкой внизу,
режим показан её значком.

Рамкой по клипам — как было. По времени — протяжка отмечает промежуток по
всем дорожкам сразу, он остаётся виден пунктиром, и S режет все дорожки по
обоим его краям. Выделенной после этого остаётся ровно середина: следующим
действием её обычно удаляют, а выделение на старых клипах убрало бы не то.

Курсор теперь идёт за резом: после S встаёт на место реза (в режиме по
времени — на начало промежутка), после удаления куска — на место стыка,
после схлопывания дыры — туда же. Раньше в это место приходилось попадать
мышью заново.

Рез кладётся на кадровую сетку: между кадрами времени нет, и рез на доле
кадра оставлял бы в монтаже время, которого не бывает.

Выделение рамкой требует настоящего перекрытия, а не касания краями:
сосед, кончающийся ровно на краю рамки, попадал в выделение из-за разницы
в последнем знаке дробей.

Кнопка журнала и строка состояния сдвинуты вправо: переключатель выделения
встал в один ряд с прилипанием и схлопыванием.

Значки — icons8, набор ios-glyphs, авторство дописано в attribution.txt.
Набора «ios26» на их раздаче нет (404), взят ближайший по виду к нынешним.

Проверки: рез по курсору и по краям промежутка, кадровая сетка, выделение
середины, курсор после удаления и после схлопывания.
2026-09-29 23:58:30 +03:00
37787ce96c Починка проекта: клипы на кадровую сетку, пункт в меню
Меню «Проект» → «Проверить и починить проект...». Показывает найденное и
чинит только по согласию, отменяется через Ctrl+Z.

Ищутся клипы мимо кадровой сетки, клипы на дорожках чужого вида и
повторяющиеся имена дорожек. Первое — наследство: в старых проектах
времена записаны как попало (2.457599 с при 59.94 к/с — это 147.31 кадра),
и пока монтаж просит доли кадра, предпросмотр и сборка округляют их
каждый по-своему. Сдвиг при починке не больше полкадра.

Края отмеченного участка при сборке тоже кладутся на сетку: подрезка
возвращала в крайние куски доли кадра, которые уплощение только что
убрало.

Проверено на копии настоящего проекта: 82 клипа, после починки мимо сетки
ни одного, клипы остались встык, общая длина изменилась на 0.028 с за два
часа; Ctrl+Z возвращает как было. Плюс проверка в lfmcheck, включая клип
короче кадра — он не должен схлопнуться в ничто.
2026-09-16 20:39:33 +03:00
019d016db9 Звук больше не отстаёт от картинки
Рез всегда точный. Раньше начало куска притягивалось к ближайшему
опорному кадру, а звук брался из непритянутой точки: по журналам сборки
средняя притяжка 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 с.
2026-09-16 18:28:29 +03:00
18e55d466e Работа не теряется: автосохранение, видимое сохранение, запасной файл
Сохранение теперь отвечает в строке состояния: «Проект сохранён: имя,
время». Раньше об этом знал только журнал, а он по умолчанию закрыт —
нажал Ctrl+S и не знаешь, дошло ли до файла.

Проект пишется во временный файл рядом и подставляется целиком; прежний
остаётся как .bak. Оборванная запись больше не может оставить огрызок
вместо проекта.

Автосохранение: пока есть несохранённое, раз в полминуты рядом с
проектом пишется копия .autosave. При открытии программа сравнивает её
время с временем проекта и, если копия новее, показывает оба времени и
предлагает её открыть. После сохранения проекта копия убирается.

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

Клавиша \ подтягивает окно к курсору и ставит его посередине: её жмут
после реза или выделения. Переключатель «курсор посередине» остался
кнопкой с целью.
2026-09-14 16:06:40 +03:00
86c28a3308 Выделение областью, рез всех дорожек, курсор не улетает
Рамка выделения: протяжка по пустому месту дорожек обтягивает клипы,
Delete убирает всё, что она задела. Щелчок без движения по-прежнему
ставит курсор.

Рез по курсору (S) режет все дорожки, а не ту, что под указателем мыши:
стоило указателю оказаться над пустой дорожкой, и клавиша молча не
делала ничего. Теперь рез отвечает числом разрезанных клипов.

Курсор после правки монтажа улетал в конец: при перезагрузке списка
кусков mpv сбрасывает отсчёт времени, программа ждала перемотки, не
дожидалась и подтягивала курсор к плееру. На паузе курсор теперь
остаётся там, куда его поставил человек. Это и делало Ctrl+Shift+R
неудобным: после каждого схлопывания приходилось целиться заново.

Схлопывание дыры ищет её с допуском и по всем дорожкам, а не только под
мышью, и называет дорожку в строке состояния.

Ответ на команду держится в строке состояния несколько секунд: раньше
его через долю секунды затирало сообщение о пересборке предпросмотра.

Проверки: рамка, рез всех дорожек, допуск при схлопывании (lfmcheck).
2026-09-14 15:27:43 +03:00
ab719dfd1e Копирование клипов: Ctrl+C и Ctrl+V
Отбивку или текстовый блок проще размножить копией, чем заводить заново
через меню и настраивать оформление с нуля.

Копируются выделенные клипы, вставляются по курсору. Связанные берутся
вместе с парой — у картинки со звуком иначе уехала бы половина, — но
связка у копий своя: копия и подлинник не должны ездить вместе. Взаимное
расположение сохраняется, набор сдвигается к курсору.

Дорожка выбирается сама: сначала та, откуда копировали, если это время на
ней свободно; потом любая подходящая по виду; в крайнем случае заводится
новая. Наложить копию на соседа по дорожке нельзя — это означало бы
переход, которого никто не заказывал.

В модели появился TClip.CopyAllFrom: полная копия, кроме места на
монтаже. Проверка в lfmcheck перебирает перенесённые свойства и отдельно
убеждается, что место и связка не переносятся.
2026-09-11 21:14:52 +03:00
407eb02f2d Прокрутка во время воспроизведения больше не отскакивает
При выключенном «курсоре посередине» окно всё равно подтягивалось к
курсору, стоило тому выйти за край видимой части. Со стороны это выглядело
так: Shift с колесом, первый поворот прокручивает, второй возвращает
обратно. Человек отматывает осознанно, и возвращать его силой нельзя.

Теперь выключенный переключатель означает именно неподвижное окно.
Подтягивание при пуске воспроизведения осталось: там курсор надо привести
в поле зрения.

Проверено на невидимом экране при идущем воспроизведении: оба поворота
колеса двигают линейку (1651 и 1581 изменившихся точек), и к исходному
виду она не возвращается.
2026-09-11 20:44:32 +03:00
939184fce7 Чёрные вставки стоят копейки, текст режет кусок
Дыра в сорок минут требовала двухчасового чёрного файла: лестница готовых
длин доходила до восьми часов, и NVENC кодировал такое минутами. Отсюда
«Делаю чёрную вставку 1 из 3», которое не кончается. Теперь длины две, 15
и 60 секунд, длинная дыра набирается повторами минутного файла, а само
чёрное кодируется мегабитом вместо полусотни.

Промежуток короче половины кадра дырой больше не считается: между
клипами, сдвинутыми встык мышью, оставались микросекунды. Мышь при этом
кладёт клипы на кадровую сетку — между кадрами времени не существует.

Правка монтажа прекращает генерацию, ставшую ненужной: раньше закрытая
дыра не отменяла уже начатую работу.

Ctrl+Shift+R работает без мыши: дыра ищется на активной дорожке, если
указатель не над дорожками, и команда отвечает в строке состояния, а не
молчит.

Вжигание текста режет кусок на части и пересобирает только середину.
Надпись в тридцать секунд внутри сорокаминутного куска стоила сорока
минут пересборки. Часть после надписи помечается точным резом, иначе
копия пошла бы от опорного кадра и картинка сдвинулась бы.

Проверки: flattest 13 и 14, схлопывание без мыши в lfmcheck, сборка с
надписью внутри длинного куска — 1.000000 с пересборки вместо 6.
2026-09-11 19:35:26 +03:00
45777bbdbb Ролик больше не хранится на диске дважды
Картинка собиралась в промежуточный файл, а потом сшивалась со звуком в
конечный. На часовом ролике это 91 ГБ в кэше плюс 91 ГБ рядом и лишний
полный проход копирования — ради того, чтобы приписать звуковую дорожку.

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

Куски после удачной сборки удаляются, и в журнале сказано, сколько места
освободилось: на часовой съёмке их набирается больше сотни гигабайт, а
нужны они только чтобы продолжить прерванную сборку. После неудачной
сборки они остаются — с них и продолжают. Настройка keep_parts оставляет
их всегда.
2026-08-31 17:39:40 +03:00
a28955fa2e Свойства клипа, порядок дорожек, оценка времени и продолжение сборки
Копирование оформления: Ctrl+Shift+C берёт с выделенного клипа
кадрирование, поворот, увеличение, смещение, прозрачность, ключ,
затухания и громкость, Ctrl+Shift+V применяет их ко всем выделенным. Вид
клипа и текст не переносятся: свойства копируют между разными клипами.

Порядок дорожек: слева в заголовке две стрелки, у крайних дорожек
соответствующая нарисована тускло и не нажимается. Двойной щелчок по
названию переименовывает дорожку — на монтаже из десятка дорожек «карта»
и «титры» читаются лучше, чем V1 и Т1. То же есть и в меню по правому
щелчку. Ввод имени — своим тёмным окном: системный InputQuery выглядел бы
белым пятном.

Окно сборки показывает, сколько прошло и сколько примерно осталось.
Оценка по пройденной доле; скорость на деле меняется, поэтому «примерно»
и пересчёт на каждом шаге.

Прерванная сборка продолжается с готовых кусков. Каждый доведённый до
конца кусок помечается в списке рядом с ними: одного наличия файла мало —
сборку могли прервать посреди записи. Первая строка списка — отпечаток
плана; не совпал, значит монтаж менялся, и всё собирается заново.
Проверено: четыре куска взяты готовыми, два пересобраны, склейка не
потеряла ни одного кадра; при изменённом монтаже готовые куски отвергнуты.
2026-08-31 14:55:19 +03:00
59c778d2f6 Текст вжигается и в фотографию; дорожки и полоса участка
Вжигание не доходило до сгенерированных вставок. Картинки и чёрное
отбирались первой же веткой сборки — до проверки на пересборку — и
копировались целиком вместе с отметкой о разметке. Галка вжигания стояла,
кусок в журнале был помечен «с текстом», а в ролике надписи не было.
Причину показал журнал сборки рядом с файлом: помечено «пересобирается»,
а команда — копирование.

Теперь вставка с разметкой идёт общей веткой пересборки, и время у неё
берётся своё: она начинается с нуля, а не с середины монтажа.

У линейки появился верхний этаж в двенадцать точек — про отметки.
Протяжка по нему отмечает участок, даже если отметок не было; щелчок без
движения их снимает. Уголки по краям тянутся, как и раньше.

Заголовок дорожки: правый щелчок открывает меню — поднять, опустить,
удалить (с клипами — с подтверждением). Заголовок можно и потащить:
порядок дорожек есть порядок перекрытия, и менять его перетаскиванием
привычнее, чем через меню.
2026-08-31 12:01:12 +03:00
71381bb774 Участок сборки, качество пересборки и пропавшие куски
Отмеченный участок. Клавиши I и O ставят начало и конец по курсору,
полоса под линейкой показывает отмеченное, сборка собирает только его.
Без этого проверить правку на длинном монтаже нельзя: каждая проверка
стоит столько же, сколько идёт весь ролик. Отметки живут в проекте.
Разметка текста при этом берётся с начала участка, иначе надписи легли бы
со сдвигом.

Фотография пропадала из ролика. Кусок с наложением подаёт слои в ffmpeg
как есть, а одиночная картинка даёт ровно один кадр: кусок в три секунды
получался длиной 0.016667 с. Теперь у слоя есть признак «это картинка», и
она повторяется ключом -loop с частотой кадров проекта.

Текст пропадал там же. Вжигание помечает кусок разметкой, но ветка
наложения про неё не знала. Пока оверлей лежит на всём ролике, этой
веткой идут все куски — и текста не было нигде. Теперь разметка вжигается
последним звеном цепочки, поверх сведённой картинки.

Качество пересобранных кусков. Битрейт не задавался вовсе, и кодировщик
брал своё значение по умолчанию: 5.9 Мбит/с там, где исходник 56. Теперь
пересборка целится в наибольший битрейт среди файлов проекта, с потолком
в полтора раза выше и буфером вдвое. Тем же битрейтом делаются вставки из
фотографий.

Проверки: обрезка списка кусков по участку (nlvetool flattest, 9),
сборка фотографии под наложением и вжигание текста поверх наложения
(nlvetool render ... burn).
2026-08-31 10:37:25 +03:00
d098f1621e Ключ и прозрачность видно прямо в предпросмотре
Оверлей показывался как есть, со своим фоном: чтобы увидеть, что выйдет
после сборки, приходилось собирать. Теперь выбитый цвет и приглушение
считаются в той же цепочке плеера, на лету.

Строки фильтров стали общими со сборкой (ColorKeyFilter, OpacityFilter
в uTransform): окно и готовый ролик больше не могут разойтись по тому,
как записан цвет или порог.

Переключатель в меню «Вид», состояние переживает перезапуск. Замер на
2688x1512, 600 кадров: основа 2.07 с, с наложением 2.43 с, с ключом и
прозрачностью 2.66 с — вчетверо быстрее реального времени, но на слабой
машине это заметнее, поэтому выключить можно.

В бэклог записано окно настроек: переключателей, которые стоят машинного
времени, набралось много, и живут они кто где — кнопками внизу, в меню,
а выбор кодировщика вообще нигде.
2026-08-31 00:46:58 +03:00
4c422ef57d Курсор прилипает к границам клипов
Курсор воспроизведения по щелчку вставал ровно туда, куда попала мышь.
В стык двух кусков так не попасть: на общем плане одна точка экрана —
это секунды материала, а ставят курсор чаще всего именно на стык.

Теперь он притягивается к границам клипов на любой дорожке и к началу
монтажа. Работает и при щелчке по клипу, и по линейке, и по пустому
месту, и при протяжке. Shift меняет решение на противоположное — как у
прилипания клипов.

Переключатель свой, со значком клея, рядом с магнитом: клипы липнут при
перетаскивании, курсор — при щелчке, это разные привычки, и одно бывает
нужно без другого. Состояние переживает перезапуск.

Расчёт открыт наружу и проверяется числами: семь проверок в lfmcheck,
от «стык рядом — притянуло» до «выключено — не притягивает».
2026-08-31 00:32:44 +03:00
fb6b60bc3f Свой тип файла для проектов: *.nlve больше не текст
Внутри проект — обычный JSON, и система считала его просто текстом:
открывала редактором и рисовала значок текстового файла.

Теперь у него свой тип application/x-nlve-project, свой значок (лист с
загнутым углом и знаком программы) и открытие двойным щелчком. Тип
объявлен наследником application/json, но не простого текста — иначе
редактор снова оказался бы программой по умолчанию.

Всё, что нужно для встраивания в рабочий стол, лежит в packaging и
ставится скриптом tools/install-desktop.sh в домашний каталог, без прав
администратора. Раньше пункт меню и значки существовали только на одной
машине и нигде не были записаны.
2026-08-31 00:13:50 +03:00
chaiman
40a0e2041f Цепочка смешивания снимается до загрузки
Чёрное окно и полная тишина оказались следствием того, что цепочка
смешивания звуковых дорожек оставалась от прошлой загрузки. Она
ссылается на дорожки по номерам, а в новом файле таких номеров нет.

Проверено на живом mpv через канал управления: с оставшейся цепочкой
следующая загрузка даёт ноль дорожек, размер кадра недоступен, не играет
ничего. После снятия — кадр 320, звук выбран.

Снимать после загрузки поздно: ломается сама загрузка. Теперь снимается
перед ней.

Проверена вся последовательность: две звуковые дорожки, затем одна, затем
без внешнего звука. Кадр на месте во всех трёх случаях.
2026-08-20 13:17:27 +03:00
chaiman
3583f74864 Звуковые дорожки смешиваются, а не побеждают друг друга
Правило «верхний побеждает» я перенёс на звук механически, и это была
ошибка: оно придумано для картинки, где и делает возможной сборку
копированием. Для звука оно бессмысленно — под голос нельзя было положить
фоновую музыку. И стоит смешивание ничего: звук всё равно перекодируется.

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

В предпросмотре сложнее: плеер играет одну звуковую дорожку за раз.
Поэтому каждая дорожка монтажа подаётся своим списком кусков, а смесь
собирается цепочкой фильтров плеера. Громкость клипов подставляется в ту
же цепочку — иначе предпросмотр врал бы про баланс.

Проверено: два тона на разных дорожках, второй с громкостью 50%. В
готовом ролике -21.2 и -27.1 dB, в предпросмотре -21.2 и -27.2. Совпало.

Найдена по дороге ошибка в собственном условии: я считал слои без
победителя и потому обнулял список, когда звучали ровно две дорожки.
2026-08-20 12:10:57 +03:00
chaiman
79fe091fbb Звуковая дорожка подключается командой, а не свойством
Найдена настоящая причина обеих жалоб на звук. Свойство audio-files,
заданное перед загрузкой, не подключает внешний список кусков вовсе:
проверено на живом mpv через его канал управления — после установки
свойства дорожек по-прежнему две, обе не внешние. Играл звук, встроенный
в саму картинку.

Отсюда обе стороны: звук был слышен там, где на монтаже его нет (шёл из
видеофайла), и не был слышен там, где есть (в этом месте картинкой была
чёрная вставка, а она молчит).

Правильный способ — команда audio-add с признаком select после загрузки.
Проверено: дорожек становится четыре, внешняя звуковая выбрана,
внутренняя снята с выбора.

Если подключить не удалось, в журнал пишется предупреждение. Глушить звук
на этот случай нельзя — прошлая попытка так сделать оставила без звука
весь монтаж.
2026-08-20 11:58:29 +03:00
chaiman
3acf79d174 Этап 5: прозрачность, переходы и затухания
Ползунок на клипе картинки теперь задаёт непрозрачность, на звуковом —
громкость. Уплощение выдаёт для таких мест не одного победителя, а слои.

Слои появляются в трёх случаях: клип полупрозрачен и сквозь него виден
нижний; два клипа на одной дорожке наползли друг на друга и должны
перетечь один в другой; у клипа задано плавное появление или уход.

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

Картинка собирается фильтрами ffmpeg: постоянная доля через overlay,
переход через xfade, затухание через fade. Звук сводится прямо в
отсчётах — доля каждого слоя считается на каждый отсчёт, и длина
результата получается ровно такой, какая нужна.

Перед сборкой программа сообщает, сколько секунд из скольких придётся
пересобрать, и даёт отказаться.

Проверено замерами:
- красный с непрозрачностью 50% поверх синего дал (127, 0, 126);
- переход на одной дорожке: синий плавно перешёл в красный за секунду;
- звуковой переход: -24 dB, -27.5, -35, -51, тишина;
- появление за 2 секунды: пересобрано 2 секунды из 6, остальное
  скопировано.

Найдено по дороге: участок с наложением склеивался с соседним куском и
терял слои — в условии склейки они не учитывались.
2026-08-20 10:11:20 +03:00
chaiman
b7b41f7cf0 Этап 2: кадрирование на клипе с перетаскиваемой рамкой
Настройка кадрирования переехала с файла на клип: два куска одного файла
бывает нужно кадрировать по-разному. У файла осталась такая же, но лишь
как заготовка — её берёт новый клип при добавлении. Проекты, записанные
раньше, читаются: клип без своей настройки берёт её у файла.

Открывается кнопкой в правом нижнем видимом углу клипа. Именно видимом:
у клипа длиной в час настоящий угол почти всегда за краем экрана — та же
задача, что уже решена для ручки громкости.

В окне слева появился кадр источника с рамкой, которую тянут мышью за
середину и за правый нижний угол. Рамка держит пропорции кадра проекта и
пересчитывается в увеличение и смещение; ползунки и рамка следуют друг за
другом.

Кусок пересобирается теперь не только когда файл не совпадает с проектом,
но и когда у клипа своё кадрирование.

Проверено сборкой: первый кусок без кадрирования скопирован, второй с
увеличением вдвое пересобран через scale=1280:720,crop=640:360:384:180.
154 пакета вошло, 154 вышло, декодирование без ошибок.

Заодно: правый щелчок по списку файлов теперь выделяет файл под курсором.
Без этого меню без выделения отключалось целиком и выглядело так, будто
его нет. Цвет формы звука сменён на пастельно-жёлтый.
2026-08-19 23:10:08 +03:00
chaiman
f1ef6e624a Этап 1: форма звука на клипах
Для каждого файла один раз строится список пиков: сто значений в секунду,
каждое есть наибольший модуль отсчёта за свои десять миллисекунд. Рисовать
по настоящим отсчётам нельзя — в секунде их 48 тысяч, а в клипе на экране
сотни пикселей.

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

Shift со стрелками вверх и вниз растягивает форму по высоте. Звук бывает
тихим, и угадывать за человека нужное усиление неправильно. Меняется
только рисунок, значение сохраняется между запусками.

Проверено: файл «4 с тона, 4 с тишины, 4 с тона» даёт форму в первой и
последней трети и пустоту посередине. Полная амплитуда даёт 254 из 255.
Разбор записи на 892 с занимает 12.7 с — это чтение 6.3 ГБ с диска,
быстрее не выйдет. Первоначальный критерий «меньше двух секунд» в плане
был занижен и исправлен по замеру.

Заодно снят риск четвёртого этапа: mpv принимает edl:// как внешнюю
звуковую дорожку и берёт звук именно из неё. Проверено встречными
списками — картинке «тишина, потом тон», звуку «тон, потом тишина».
2026-08-19 21:23:24 +03:00
chaiman
b59cdb1352 Нелинейный видеоредактор без перекодирования
Куски видео вырезаются и склеиваются копированием потока: сборка ролика
занимает время копирования файла, а не время рендера. Композитинга нет
принципиально — при перекрытии побеждает клип с верхней дорожки целиком,
и картинкой, и звуком. Именно это ограничение и делает сборку копированием
возможной.

Что внутри:

- монтажный стол со своей отрисовкой: дорожки, масштаб, прилипание,
  схлопывание, громкость на клипе;
- предпросмотр прямо с монтажа через libmpv и виртуальный список кусков,
  без промежуточных файлов;
- сборка через ffmpeg с точными резами: перекодируется только огрызок от
  реза до ближайшего опорного кадра, остальное копируется;
- разбор заголовка MP4 для поиска опорных кадров — в 500 раз быстрее
  опроса ffprobe;
- перепаковка контейнеров, кадрирование и поворот, сведения о проекте;
- свои цвета всего окна: системные элементы под Windows цвет не берут,
  поэтому кнопки, полоса меню, журнал и полосы прокрутки нарисованы сами;
- окно зависимостей: недостающие ffmpeg, ffprobe и libmpv скачиваются с
  официальных источников;
- кросс-сборка под Windows и работа под Wine.

Первый коммит: до этого история не велась.
2026-08-19 18:36:16 +03:00