Нелинейный видеоредактор без перекодирования
Куски видео вырезаются и склеиваются копированием потока: сборка ролика
занимает время копирования файла, а не время рендера. Композитинга нет
принципиально — при перекрытии побеждает клип с верхней дорожки целиком,
и картинкой, и звуком. Именно это ограничение и делает сборку копированием
возможной.
Что внутри:
- монтажный стол со своей отрисовкой: дорожки, масштаб, прилипание,
схлопывание, громкость на клипе;
- предпросмотр прямо с монтажа через libmpv и виртуальный список кусков,
без промежуточных файлов;
- сборка через ffmpeg с точными резами: перекодируется только огрызок от
реза до ближайшего опорного кадра, остальное копируется;
- разбор заголовка MP4 для поиска опорных кадров — в 500 раз быстрее
опроса ffprobe;
- перепаковка контейнеров, кадрирование и поворот, сведения о проекте;
- свои цвета всего окна: системные элементы под Windows цвет не берут,
поэтому кнопки, полоса меню, журнал и полосы прокрутки нарисованы сами;
- окно зависимостей: недостающие ffmpeg, ffprobe и libmpv скачиваются с
официальных источников;
- кросс-сборка под Windows и работа под Wine.
Первый коммит: до этого история не велась.
2026-08-19 18:36:16 +03:00
|
|
|
|
{
|
|
|
|
|
|
uProgressForm — окно хода долгой операции.
|
|
|
|
|
|
|
|
|
|
|
|
Показывается модально, пока работает рабочий поток. Поток шлёт сюда
|
|
|
|
|
|
состояние через Synchronize, поэтому все методы этого окна вызываются
|
|
|
|
|
|
из потока интерфейса и никакой защиты не требуют.
|
|
|
|
|
|
|
|
|
|
|
|
Кнопка одна и меняет назначение: пока идёт работа — «Отмена», после
|
|
|
|
|
|
завершения — «Закрыть». Так окно нельзя закрыть, не остановив работу,
|
|
|
|
|
|
и не приходится гадать, что стало с процессом.
|
|
|
|
|
|
}
|
|
|
|
|
|
unit uProgressForm;
|
|
|
|
|
|
|
|
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
|
|
|
|
uses
|
Затухания видны и настраиваются, сборка с перекодированием, свой журнал в окне сборки
Затухания. Механика была написана давно и работала в сборке, но увидеть
или задать её было нечем. Теперь у клипа два верхних угла — ручки:
левая тянет появление, правая уход. Взятое затухание рисуется срезанным
углом, так это устроено в монтажных программах. Ручки перехватывают
нажатие раньше растягивания за край: они мелкие, промахнуться мимо них
легче, а взяться за край можно ниже.
Перекрытие двух клипов одной дорожки — это переход, и он теперь помечен
косым крестом во всю высоту. Раньше о нём можно было узнать только по
предупреждению перед сборкой.
Сборка с перекодированием. Отдельный пункт меню и отдельное окно:
размер кадра от 720p до 4K, поток в килобитах, кодек HEVC или H.264.
Перекодирование идёт одним проходом на весь ролик — пересобирать куски
по отдельности нельзя, на стыках была бы видна смена качества.
Кодирование на видеокарте, и распаковка тоже: замерено на паре кусков
2688x1512 — 9.18 с на процессоре против 1.77 с с аппаратной распаковкой,
впятеро. Полностью карточный путь через scale_cuda оказался медленнее
(5.74 с) и не взят. Если аппаратная распаковка не пойдёт, сборка
повторяется без неё: медленно лучше, чем никак. Окно честно
предупреждает, когда аппаратного кодировщика в ffmpeg нет вовсе.
Журнал в окне сборки заменён на свой: у системного поля оставались
светлые полосы прокрутки и не работала прокрутка вбок с Shift. Это было
последнее такое место.
2026-08-21 18:11:59 +03:00
|
|
|
|
Classes, SysUtils, Forms, Controls, Graphics, ComCtrls, StdCtrls, ExtCtrls,
|
|
|
|
|
|
uTheme, uLogView;
|
Нелинейный видеоредактор без перекодирования
Куски видео вырезаются и склеиваются копированием потока: сборка ролика
занимает время копирования файла, а не время рендера. Композитинга нет
принципиально — при перекрытии побеждает клип с верхней дорожки целиком,
и картинкой, и звуком. Именно это ограничение и делает сборку копированием
возможной.
Что внутри:
- монтажный стол со своей отрисовкой: дорожки, масштаб, прилипание,
схлопывание, громкость на клипе;
- предпросмотр прямо с монтажа через libmpv и виртуальный список кусков,
без промежуточных файлов;
- сборка через ffmpeg с точными резами: перекодируется только огрызок от
реза до ближайшего опорного кадра, остальное копируется;
- разбор заголовка MP4 для поиска опорных кадров — в 500 раз быстрее
опроса ffprobe;
- перепаковка контейнеров, кадрирование и поворот, сведения о проекте;
- свои цвета всего окна: системные элементы под Windows цвет не берут,
поэтому кнопки, полоса меню, журнал и полосы прокрутки нарисованы сами;
- окно зависимостей: недостающие ffmpeg, ffprobe и libmpv скачиваются с
официальных источников;
- кросс-сборка под Windows и работа под Wine.
Первый коммит: до этого история не велась.
2026-08-19 18:36:16 +03:00
|
|
|
|
|
|
|
|
|
|
type
|
|
|
|
|
|
|
|
|
|
|
|
{ TProgressForm }
|
|
|
|
|
|
|
|
|
|
|
|
TProgressForm = class(TForm)
|
|
|
|
|
|
btnAction: TThemedButton;
|
|
|
|
|
|
lblStage: TLabel;
|
Свойства клипа, порядок дорожек, оценка времени и продолжение сборки
Копирование оформления: Ctrl+Shift+C берёт с выделенного клипа
кадрирование, поворот, увеличение, смещение, прозрачность, ключ,
затухания и громкость, Ctrl+Shift+V применяет их ко всем выделенным. Вид
клипа и текст не переносятся: свойства копируют между разными клипами.
Порядок дорожек: слева в заголовке две стрелки, у крайних дорожек
соответствующая нарисована тускло и не нажимается. Двойной щелчок по
названию переименовывает дорожку — на монтаже из десятка дорожек «карта»
и «титры» читаются лучше, чем V1 и Т1. То же есть и в меню по правому
щелчку. Ввод имени — своим тёмным окном: системный InputQuery выглядел бы
белым пятном.
Окно сборки показывает, сколько прошло и сколько примерно осталось.
Оценка по пройденной доле; скорость на деле меняется, поэтому «примерно»
и пересчёт на каждом шаге.
Прерванная сборка продолжается с готовых кусков. Каждый доведённый до
конца кусок помечается в списке рядом с ними: одного наличия файла мало —
сборку могли прервать посреди записи. Первая строка списка — отпечаток
плана; не совпал, значит монтаж менялся, и всё собирается заново.
Проверено: четыре куска взяты готовыми, два пересобраны, склейка не
потеряла ни одного кадра; при изменённом монтаже готовые куски отвергнуты.
2026-08-31 14:55:19 +03:00
|
|
|
|
lblEta: TLabel;
|
Затухания видны и настраиваются, сборка с перекодированием, свой журнал в окне сборки
Затухания. Механика была написана давно и работала в сборке, но увидеть
или задать её было нечем. Теперь у клипа два верхних угла — ручки:
левая тянет появление, правая уход. Взятое затухание рисуется срезанным
углом, так это устроено в монтажных программах. Ручки перехватывают
нажатие раньше растягивания за край: они мелкие, промахнуться мимо них
легче, а взяться за край можно ниже.
Перекрытие двух клипов одной дорожки — это переход, и он теперь помечен
косым крестом во всю высоту. Раньше о нём можно было узнать только по
предупреждению перед сборкой.
Сборка с перекодированием. Отдельный пункт меню и отдельное окно:
размер кадра от 720p до 4K, поток в килобитах, кодек HEVC или H.264.
Перекодирование идёт одним проходом на весь ролик — пересобирать куски
по отдельности нельзя, на стыках была бы видна смена качества.
Кодирование на видеокарте, и распаковка тоже: замерено на паре кусков
2688x1512 — 9.18 с на процессоре против 1.77 с с аппаратной распаковкой,
впятеро. Полностью карточный путь через scale_cuda оказался медленнее
(5.74 с) и не взят. Если аппаратная распаковка не пойдёт, сборка
повторяется без неё: медленно лучше, чем никак. Окно честно
предупреждает, когда аппаратного кодировщика в ffmpeg нет вовсе.
Журнал в окне сборки заменён на свой: у системного поля оставались
светлые полосы прокрутки и не работала прокрутка вбок с Shift. Это было
последнее такое место.
2026-08-21 18:11:59 +03:00
|
|
|
|
memoLog: TLogView;
|
Показатель работы: число и полоса показывают одно и то же
Полоса ползла по догадке, а подпись показывала замер — и человек видел
полосу, заполненную на девять десятых, рядом с нулём процентов. Что в
этот момент происходит, по такой паре понять нельзя.
Теперь доля одна на обоих. Берётся она у самого ffmpeg: сборка участка с
затуханием идёт минуту и дольше, а «кусок 1 из 1» всё это время не
меняется, поэтому ffmpeg спрашивают ключом -progress, докуда он дошёл.
Пока он не ответил ни разу, полоса трогается с места на пару процентов и
там стоит — пустая полоса и есть правда о только что начатой работе.
Догадка заодно перестала закрывать промежуток до вехи целиком: предел —
девять десятых, остаток виден глазом. Проверка на это добавлена в
tests/progress.
Полоса в окне сборки была системной, и под gtk2 заполнялась ступенями по
восемь кусков на ширину. Теперь там та же своя полоса, что и внизу
главного окна, — заполняется сплошь. Чтобы она читалась из файла формы,
у неё опубликованы Anchors, Align и Visible: читатель формы берёт только
опубликованные свойства, и без этого окно падало при открытии.
Проверено глазами на невидимом экране: «Собираю наложение 1 из 1 — 2%»
при полосе в 2%, через четыре секунды 69% при полосе в 69%.
2026-10-01 15:50:10 +03:00
|
|
|
|
{ Полоса своя, а не системная: TProgressBar под gtk2 рисуется
|
|
|
|
|
|
ступеньками, по восемь кусков на всю ширину, и ход работы в ней
|
|
|
|
|
|
виден рывками. Эта заполняется сплошь, как та, что внизу главного
|
|
|
|
|
|
окна. }
|
|
|
|
|
|
pbBar: TThemedProgress;
|
Нелинейный видеоредактор без перекодирования
Куски видео вырезаются и склеиваются копированием потока: сборка ролика
занимает время копирования файла, а не время рендера. Композитинга нет
принципиально — при перекрытии побеждает клип с верхней дорожки целиком,
и картинкой, и звуком. Именно это ограничение и делает сборку копированием
возможной.
Что внутри:
- монтажный стол со своей отрисовкой: дорожки, масштаб, прилипание,
схлопывание, громкость на клипе;
- предпросмотр прямо с монтажа через libmpv и виртуальный список кусков,
без промежуточных файлов;
- сборка через ffmpeg с точными резами: перекодируется только огрызок от
реза до ближайшего опорного кадра, остальное копируется;
- разбор заголовка MP4 для поиска опорных кадров — в 500 раз быстрее
опроса ffprobe;
- перепаковка контейнеров, кадрирование и поворот, сведения о проекте;
- свои цвета всего окна: системные элементы под Windows цвет не берут,
поэтому кнопки, полоса меню, журнал и полосы прокрутки нарисованы сами;
- окно зависимостей: недостающие ffmpeg, ffprobe и libmpv скачиваются с
официальных источников;
- кросс-сборка под Windows и работа под Wine.
Первый коммит: до этого история не велась.
2026-08-19 18:36:16 +03:00
|
|
|
|
pnlTop: TPanel;
|
|
|
|
|
|
procedure btnActionClick(Sender: TObject);
|
|
|
|
|
|
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
|
|
|
|
|
procedure FormCreate(Sender: TObject);
|
|
|
|
|
|
private
|
|
|
|
|
|
FFinished: Boolean;
|
|
|
|
|
|
FCancelRequested: Boolean;
|
|
|
|
|
|
FOnCancelRequest: TNotifyEvent;
|
Свойства клипа, порядок дорожек, оценка времени и продолжение сборки
Копирование оформления: Ctrl+Shift+C берёт с выделенного клипа
кадрирование, поворот, увеличение, смещение, прозрачность, ключ,
затухания и громкость, Ctrl+Shift+V применяет их ко всем выделенным. Вид
клипа и текст не переносятся: свойства копируют между разными клипами.
Порядок дорожек: слева в заголовке две стрелки, у крайних дорожек
соответствующая нарисована тускло и не нажимается. Двойной щелчок по
названию переименовывает дорожку — на монтаже из десятка дорожек «карта»
и «титры» читаются лучше, чем V1 и Т1. То же есть и в меню по правому
щелчку. Ввод имени — своим тёмным окном: системный InputQuery выглядел бы
белым пятном.
Окно сборки показывает, сколько прошло и сколько примерно осталось.
Оценка по пройденной доле; скорость на деле меняется, поэтому «примерно»
и пересчёт на каждом шаге.
Прерванная сборка продолжается с готовых кусков. Каждый доведённый до
конца кусок помечается в списке рядом с ними: одного наличия файла мало —
сборку могли прервать посреди записи. Первая строка списка — отпечаток
плана; не совпал, значит монтаж менялся, и всё собирается заново.
Проверено: четыре куска взяты готовыми, два пересобраны, склейка не
потеряла ни одного кадра; при изменённом монтаже готовые куски отвергнуты.
2026-08-31 14:55:19 +03:00
|
|
|
|
{ Когда началась работа и какую долю показывали в прошлый раз: по ним
|
|
|
|
|
|
считается, сколько осталось. }
|
|
|
|
|
|
FStartedAt: TDateTime;
|
|
|
|
|
|
FLastFraction: Double;
|
|
|
|
|
|
function FormatSpan(const ASeconds: Double): string;
|
Нелинейный видеоредактор без перекодирования
Куски видео вырезаются и склеиваются копированием потока: сборка ролика
занимает время копирования файла, а не время рендера. Композитинга нет
принципиально — при перекрытии побеждает клип с верхней дорожки целиком,
и картинкой, и звуком. Именно это ограничение и делает сборку копированием
возможной.
Что внутри:
- монтажный стол со своей отрисовкой: дорожки, масштаб, прилипание,
схлопывание, громкость на клипе;
- предпросмотр прямо с монтажа через libmpv и виртуальный список кусков,
без промежуточных файлов;
- сборка через ffmpeg с точными резами: перекодируется только огрызок от
реза до ближайшего опорного кадра, остальное копируется;
- разбор заголовка MP4 для поиска опорных кадров — в 500 раз быстрее
опроса ffprobe;
- перепаковка контейнеров, кадрирование и поворот, сведения о проекте;
- свои цвета всего окна: системные элементы под Windows цвет не берут,
поэтому кнопки, полоса меню, журнал и полосы прокрутки нарисованы сами;
- окно зависимостей: недостающие ffmpeg, ffprobe и libmpv скачиваются с
официальных источников;
- кросс-сборка под Windows и работа под Wine.
Первый коммит: до этого история не велась.
2026-08-19 18:36:16 +03:00
|
|
|
|
public
|
|
|
|
|
|
procedure SetStage(const AText: string);
|
|
|
|
|
|
procedure SetFraction(AValue: Double);
|
|
|
|
|
|
procedure AddLog(const AText: string);
|
|
|
|
|
|
{ Переводит окно в завершённое состояние: прогресс на месте, кнопка
|
|
|
|
|
|
становится «Закрыть». }
|
|
|
|
|
|
procedure Finish(ASuccess: Boolean; const AMessage: string);
|
|
|
|
|
|
|
|
|
|
|
|
property Finished: Boolean read FFinished;
|
|
|
|
|
|
property OnCancelRequest: TNotifyEvent read FOnCancelRequest
|
|
|
|
|
|
write FOnCancelRequest;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
|
|
|
|
|
|
{$R *.lfm}
|
|
|
|
|
|
|
|
|
|
|
|
{ TProgressForm }
|
|
|
|
|
|
|
|
|
|
|
|
procedure TProgressForm.FormCreate(Sender: TObject);
|
|
|
|
|
|
begin
|
|
|
|
|
|
{ Цвета задаём сами: системная тема может быть светлой, и тогда
|
|
|
|
|
|
тёмный таймлайн оказался бы в белой рамке. }
|
|
|
|
|
|
ApplyDarkTheme(Self);
|
Показатель работы: число и полоса показывают одно и то же
Полоса ползла по догадке, а подпись показывала замер — и человек видел
полосу, заполненную на девять десятых, рядом с нулём процентов. Что в
этот момент происходит, по такой паре понять нельзя.
Теперь доля одна на обоих. Берётся она у самого ffmpeg: сборка участка с
затуханием идёт минуту и дольше, а «кусок 1 из 1» всё это время не
меняется, поэтому ffmpeg спрашивают ключом -progress, докуда он дошёл.
Пока он не ответил ни разу, полоса трогается с места на пару процентов и
там стоит — пустая полоса и есть правда о только что начатой работе.
Догадка заодно перестала закрывать промежуток до вехи целиком: предел —
девять десятых, остаток виден глазом. Проверка на это добавлена в
tests/progress.
Полоса в окне сборки была системной, и под gtk2 заполнялась ступенями по
восемь кусков на ширину. Теперь там та же своя полоса, что и внизу
главного окна, — заполняется сплошь. Чтобы она читалась из файла формы,
у неё опубликованы Anchors, Align и Visible: читатель формы берёт только
опубликованные свойства, и без этого окно падало при открытии.
Проверено глазами на невидимом экране: «Собираю наложение 1 из 1 — 2%»
при полосе в 2%, через четыре секунды 69% при полосе в 69%.
2026-10-01 15:50:10 +03:00
|
|
|
|
pbBar.Fraction := 0;
|
Нелинейный видеоредактор без перекодирования
Куски видео вырезаются и склеиваются копированием потока: сборка ролика
занимает время копирования файла, а не время рендера. Композитинга нет
принципиально — при перекрытии побеждает клип с верхней дорожки целиком,
и картинкой, и звуком. Именно это ограничение и делает сборку копированием
возможной.
Что внутри:
- монтажный стол со своей отрисовкой: дорожки, масштаб, прилипание,
схлопывание, громкость на клипе;
- предпросмотр прямо с монтажа через libmpv и виртуальный список кусков,
без промежуточных файлов;
- сборка через ffmpeg с точными резами: перекодируется только огрызок от
реза до ближайшего опорного кадра, остальное копируется;
- разбор заголовка MP4 для поиска опорных кадров — в 500 раз быстрее
опроса ffprobe;
- перепаковка контейнеров, кадрирование и поворот, сведения о проекте;
- свои цвета всего окна: системные элементы под Windows цвет не берут,
поэтому кнопки, полоса меню, журнал и полосы прокрутки нарисованы сами;
- окно зависимостей: недостающие ffmpeg, ffprobe и libmpv скачиваются с
официальных источников;
- кросс-сборка под Windows и работа под Wine.
Первый коммит: до этого история не велась.
2026-08-19 18:36:16 +03:00
|
|
|
|
memoLog.Clear;
|
|
|
|
|
|
btnAction.Caption := 'Отмена';
|
Свойства клипа, порядок дорожек, оценка времени и продолжение сборки
Копирование оформления: Ctrl+Shift+C берёт с выделенного клипа
кадрирование, поворот, увеличение, смещение, прозрачность, ключ,
затухания и громкость, Ctrl+Shift+V применяет их ко всем выделенным. Вид
клипа и текст не переносятся: свойства копируют между разными клипами.
Порядок дорожек: слева в заголовке две стрелки, у крайних дорожек
соответствующая нарисована тускло и не нажимается. Двойной щелчок по
названию переименовывает дорожку — на монтаже из десятка дорожек «карта»
и «титры» читаются лучше, чем V1 и Т1. То же есть и в меню по правому
щелчку. Ввод имени — своим тёмным окном: системный InputQuery выглядел бы
белым пятном.
Окно сборки показывает, сколько прошло и сколько примерно осталось.
Оценка по пройденной доле; скорость на деле меняется, поэтому «примерно»
и пересчёт на каждом шаге.
Прерванная сборка продолжается с готовых кусков. Каждый доведённый до
конца кусок помечается в списке рядом с ними: одного наличия файла мало —
сборку могли прервать посреди записи. Первая строка списка — отпечаток
плана; не совпал, значит монтаж менялся, и всё собирается заново.
Проверено: четыре куска взяты готовыми, два пересобраны, склейка не
потеряла ни одного кадра; при изменённом монтаже готовые куски отвергнуты.
2026-08-31 14:55:19 +03:00
|
|
|
|
FStartedAt := Now;
|
|
|
|
|
|
FLastFraction := 0;
|
|
|
|
|
|
lblEta.Caption := '';
|
Нелинейный видеоредактор без перекодирования
Куски видео вырезаются и склеиваются копированием потока: сборка ролика
занимает время копирования файла, а не время рендера. Композитинга нет
принципиально — при перекрытии побеждает клип с верхней дорожки целиком,
и картинкой, и звуком. Именно это ограничение и делает сборку копированием
возможной.
Что внутри:
- монтажный стол со своей отрисовкой: дорожки, масштаб, прилипание,
схлопывание, громкость на клипе;
- предпросмотр прямо с монтажа через libmpv и виртуальный список кусков,
без промежуточных файлов;
- сборка через ffmpeg с точными резами: перекодируется только огрызок от
реза до ближайшего опорного кадра, остальное копируется;
- разбор заголовка MP4 для поиска опорных кадров — в 500 раз быстрее
опроса ffprobe;
- перепаковка контейнеров, кадрирование и поворот, сведения о проекте;
- свои цвета всего окна: системные элементы под Windows цвет не берут,
поэтому кнопки, полоса меню, журнал и полосы прокрутки нарисованы сами;
- окно зависимостей: недостающие ffmpeg, ffprobe и libmpv скачиваются с
официальных источников;
- кросс-сборка под Windows и работа под Wine.
Первый коммит: до этого история не велась.
2026-08-19 18:36:16 +03:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TProgressForm.SetStage(const AText: string);
|
|
|
|
|
|
begin
|
|
|
|
|
|
lblStage.Caption := AText;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
Свойства клипа, порядок дорожек, оценка времени и продолжение сборки
Копирование оформления: Ctrl+Shift+C берёт с выделенного клипа
кадрирование, поворот, увеличение, смещение, прозрачность, ключ,
затухания и громкость, Ctrl+Shift+V применяет их ко всем выделенным. Вид
клипа и текст не переносятся: свойства копируют между разными клипами.
Порядок дорожек: слева в заголовке две стрелки, у крайних дорожек
соответствующая нарисована тускло и не нажимается. Двойной щелчок по
названию переименовывает дорожку — на монтаже из десятка дорожек «карта»
и «титры» читаются лучше, чем V1 и Т1. То же есть и в меню по правому
щелчку. Ввод имени — своим тёмным окном: системный InputQuery выглядел бы
белым пятном.
Окно сборки показывает, сколько прошло и сколько примерно осталось.
Оценка по пройденной доле; скорость на деле меняется, поэтому «примерно»
и пересчёт на каждом шаге.
Прерванная сборка продолжается с готовых кусков. Каждый доведённый до
конца кусок помечается в списке рядом с ними: одного наличия файла мало —
сборку могли прервать посреди записи. Первая строка списка — отпечаток
плана; не совпал, значит монтаж менялся, и всё собирается заново.
Проверено: четыре куска взяты готовыми, два пересобраны, склейка не
потеряла ни одного кадра; при изменённом монтаже готовые куски отвергнуты.
2026-08-31 14:55:19 +03:00
|
|
|
|
{ Время в виде «3 мин 20 с»: секунды сотнями человек не читает. }
|
|
|
|
|
|
function TProgressForm.FormatSpan(const ASeconds: Double): string;
|
|
|
|
|
|
var
|
|
|
|
|
|
Total, M, S: Integer;
|
|
|
|
|
|
begin
|
|
|
|
|
|
Total := Round(ASeconds);
|
|
|
|
|
|
if Total < 0 then
|
|
|
|
|
|
Total := 0;
|
|
|
|
|
|
M := Total div 60;
|
|
|
|
|
|
S := Total mod 60;
|
|
|
|
|
|
if M >= 60 then
|
|
|
|
|
|
Result := Format('%d ч %d мин', [M div 60, M mod 60])
|
|
|
|
|
|
else if M > 0 then
|
|
|
|
|
|
Result := Format('%d мин %d с', [M, S])
|
|
|
|
|
|
else
|
|
|
|
|
|
Result := Format('%d с', [S]);
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ Сколько прошло и сколько осталось.
|
|
|
|
|
|
|
|
|
|
|
|
Осталось считается по простому правилу: если четверть пути заняла
|
|
|
|
|
|
минуту, весь путь займёт четыре. На деле скорость меняется — куски,
|
|
|
|
|
|
которые копируются, идут мгновенно, а те, что пересобираются,
|
|
|
|
|
|
медленно, — поэтому число называется «примерно» и пересчитывается на
|
|
|
|
|
|
каждом шаге. Даже такая оценка отвечает на главный вопрос: успею ли я
|
|
|
|
|
|
сходить за чаем. }
|
Нелинейный видеоредактор без перекодирования
Куски видео вырезаются и склеиваются копированием потока: сборка ролика
занимает время копирования файла, а не время рендера. Композитинга нет
принципиально — при перекрытии побеждает клип с верхней дорожки целиком,
и картинкой, и звуком. Именно это ограничение и делает сборку копированием
возможной.
Что внутри:
- монтажный стол со своей отрисовкой: дорожки, масштаб, прилипание,
схлопывание, громкость на клипе;
- предпросмотр прямо с монтажа через libmpv и виртуальный список кусков,
без промежуточных файлов;
- сборка через ffmpeg с точными резами: перекодируется только огрызок от
реза до ближайшего опорного кадра, остальное копируется;
- разбор заголовка MP4 для поиска опорных кадров — в 500 раз быстрее
опроса ffprobe;
- перепаковка контейнеров, кадрирование и поворот, сведения о проекте;
- свои цвета всего окна: системные элементы под Windows цвет не берут,
поэтому кнопки, полоса меню, журнал и полосы прокрутки нарисованы сами;
- окно зависимостей: недостающие ffmpeg, ffprobe и libmpv скачиваются с
официальных источников;
- кросс-сборка под Windows и работа под Wine.
Первый коммит: до этого история не велась.
2026-08-19 18:36:16 +03:00
|
|
|
|
procedure TProgressForm.SetFraction(AValue: Double);
|
Свойства клипа, порядок дорожек, оценка времени и продолжение сборки
Копирование оформления: Ctrl+Shift+C берёт с выделенного клипа
кадрирование, поворот, увеличение, смещение, прозрачность, ключ,
затухания и громкость, Ctrl+Shift+V применяет их ко всем выделенным. Вид
клипа и текст не переносятся: свойства копируют между разными клипами.
Порядок дорожек: слева в заголовке две стрелки, у крайних дорожек
соответствующая нарисована тускло и не нажимается. Двойной щелчок по
названию переименовывает дорожку — на монтаже из десятка дорожек «карта»
и «титры» читаются лучше, чем V1 и Т1. То же есть и в меню по правому
щелчку. Ввод имени — своим тёмным окном: системный InputQuery выглядел бы
белым пятном.
Окно сборки показывает, сколько прошло и сколько примерно осталось.
Оценка по пройденной доле; скорость на деле меняется, поэтому «примерно»
и пересчёт на каждом шаге.
Прерванная сборка продолжается с готовых кусков. Каждый доведённый до
конца кусок помечается в списке рядом с ними: одного наличия файла мало —
сборку могли прервать посреди записи. Первая строка списка — отпечаток
плана; не совпал, значит монтаж менялся, и всё собирается заново.
Проверено: четыре куска взяты готовыми, два пересобраны, склейка не
потеряла ни одного кадра; при изменённом монтаже готовые куски отвергнуты.
2026-08-31 14:55:19 +03:00
|
|
|
|
var
|
|
|
|
|
|
{ Не Left: так называется свойство формы. }
|
|
|
|
|
|
Elapsed, Remain: Double;
|
Нелинейный видеоредактор без перекодирования
Куски видео вырезаются и склеиваются копированием потока: сборка ролика
занимает время копирования файла, а не время рендера. Композитинга нет
принципиально — при перекрытии побеждает клип с верхней дорожки целиком,
и картинкой, и звуком. Именно это ограничение и делает сборку копированием
возможной.
Что внутри:
- монтажный стол со своей отрисовкой: дорожки, масштаб, прилипание,
схлопывание, громкость на клипе;
- предпросмотр прямо с монтажа через libmpv и виртуальный список кусков,
без промежуточных файлов;
- сборка через ffmpeg с точными резами: перекодируется только огрызок от
реза до ближайшего опорного кадра, остальное копируется;
- разбор заголовка MP4 для поиска опорных кадров — в 500 раз быстрее
опроса ffprobe;
- перепаковка контейнеров, кадрирование и поворот, сведения о проекте;
- свои цвета всего окна: системные элементы под Windows цвет не берут,
поэтому кнопки, полоса меню, журнал и полосы прокрутки нарисованы сами;
- окно зависимостей: недостающие ffmpeg, ffprobe и libmpv скачиваются с
официальных источников;
- кросс-сборка под Windows и работа под Wine.
Первый коммит: до этого история не велась.
2026-08-19 18:36:16 +03:00
|
|
|
|
begin
|
|
|
|
|
|
if AValue < 0 then
|
|
|
|
|
|
AValue := 0;
|
|
|
|
|
|
if AValue > 1 then
|
|
|
|
|
|
AValue := 1;
|
Показатель работы: число и полоса показывают одно и то же
Полоса ползла по догадке, а подпись показывала замер — и человек видел
полосу, заполненную на девять десятых, рядом с нулём процентов. Что в
этот момент происходит, по такой паре понять нельзя.
Теперь доля одна на обоих. Берётся она у самого ffmpeg: сборка участка с
затуханием идёт минуту и дольше, а «кусок 1 из 1» всё это время не
меняется, поэтому ffmpeg спрашивают ключом -progress, докуда он дошёл.
Пока он не ответил ни разу, полоса трогается с места на пару процентов и
там стоит — пустая полоса и есть правда о только что начатой работе.
Догадка заодно перестала закрывать промежуток до вехи целиком: предел —
девять десятых, остаток виден глазом. Проверка на это добавлена в
tests/progress.
Полоса в окне сборки была системной, и под gtk2 заполнялась ступенями по
восемь кусков на ширину. Теперь там та же своя полоса, что и внизу
главного окна, — заполняется сплошь. Чтобы она читалась из файла формы,
у неё опубликованы Anchors, Align и Visible: читатель формы берёт только
опубликованные свойства, и без этого окно падало при открытии.
Проверено глазами на невидимом экране: «Собираю наложение 1 из 1 — 2%»
при полосе в 2%, через четыре секунды 69% при полосе в 69%.
2026-10-01 15:50:10 +03:00
|
|
|
|
pbBar.Fraction := AValue;
|
Свойства клипа, порядок дорожек, оценка времени и продолжение сборки
Копирование оформления: Ctrl+Shift+C берёт с выделенного клипа
кадрирование, поворот, увеличение, смещение, прозрачность, ключ,
затухания и громкость, Ctrl+Shift+V применяет их ко всем выделенным. Вид
клипа и текст не переносятся: свойства копируют между разными клипами.
Порядок дорожек: слева в заголовке две стрелки, у крайних дорожек
соответствующая нарисована тускло и не нажимается. Двойной щелчок по
названию переименовывает дорожку — на монтаже из десятка дорожек «карта»
и «титры» читаются лучше, чем V1 и Т1. То же есть и в меню по правому
щелчку. Ввод имени — своим тёмным окном: системный InputQuery выглядел бы
белым пятном.
Окно сборки показывает, сколько прошло и сколько примерно осталось.
Оценка по пройденной доле; скорость на деле меняется, поэтому «примерно»
и пересчёт на каждом шаге.
Прерванная сборка продолжается с готовых кусков. Каждый доведённый до
конца кусок помечается в списке рядом с ними: одного наличия файла мало —
сборку могли прервать посреди записи. Первая строка списка — отпечаток
плана; не совпал, значит монтаж менялся, и всё собирается заново.
Проверено: четыре куска взяты готовыми, два пересобраны, склейка не
потеряла ни одного кадра; при изменённом монтаже готовые куски отвергнуты.
2026-08-31 14:55:19 +03:00
|
|
|
|
FLastFraction := AValue;
|
|
|
|
|
|
|
|
|
|
|
|
Elapsed := (Now - FStartedAt) * SecsPerDay;
|
|
|
|
|
|
{ Пока сделано меньше сотой доли, оценка была бы гаданием: первые
|
|
|
|
|
|
секунды уходят на запуск ffmpeg, а не на работу. }
|
|
|
|
|
|
if (AValue > 0.01) and (Elapsed > 1) then
|
|
|
|
|
|
begin
|
|
|
|
|
|
Remain := Elapsed * (1 - AValue) / AValue;
|
|
|
|
|
|
lblEta.Caption := Format('Прошло %s, осталось примерно %s (%d%%)',
|
|
|
|
|
|
[FormatSpan(Elapsed), FormatSpan(Remain), Round(AValue * 100)]);
|
|
|
|
|
|
end
|
|
|
|
|
|
else
|
|
|
|
|
|
lblEta.Caption := 'Прошло ' + FormatSpan(Elapsed);
|
Нелинейный видеоредактор без перекодирования
Куски видео вырезаются и склеиваются копированием потока: сборка ролика
занимает время копирования файла, а не время рендера. Композитинга нет
принципиально — при перекрытии побеждает клип с верхней дорожки целиком,
и картинкой, и звуком. Именно это ограничение и делает сборку копированием
возможной.
Что внутри:
- монтажный стол со своей отрисовкой: дорожки, масштаб, прилипание,
схлопывание, громкость на клипе;
- предпросмотр прямо с монтажа через libmpv и виртуальный список кусков,
без промежуточных файлов;
- сборка через ffmpeg с точными резами: перекодируется только огрызок от
реза до ближайшего опорного кадра, остальное копируется;
- разбор заголовка MP4 для поиска опорных кадров — в 500 раз быстрее
опроса ffprobe;
- перепаковка контейнеров, кадрирование и поворот, сведения о проекте;
- свои цвета всего окна: системные элементы под Windows цвет не берут,
поэтому кнопки, полоса меню, журнал и полосы прокрутки нарисованы сами;
- окно зависимостей: недостающие ffmpeg, ffprobe и libmpv скачиваются с
официальных источников;
- кросс-сборка под Windows и работа под Wine.
Первый коммит: до этого история не велась.
2026-08-19 18:36:16 +03:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TProgressForm.AddLog(const AText: string);
|
|
|
|
|
|
begin
|
Затухания видны и настраиваются, сборка с перекодированием, свой журнал в окне сборки
Затухания. Механика была написана давно и работала в сборке, но увидеть
или задать её было нечем. Теперь у клипа два верхних угла — ручки:
левая тянет появление, правая уход. Взятое затухание рисуется срезанным
углом, так это устроено в монтажных программах. Ручки перехватывают
нажатие раньше растягивания за край: они мелкие, промахнуться мимо них
легче, а взяться за край можно ниже.
Перекрытие двух клипов одной дорожки — это переход, и он теперь помечен
косым крестом во всю высоту. Раньше о нём можно было узнать только по
предупреждению перед сборкой.
Сборка с перекодированием. Отдельный пункт меню и отдельное окно:
размер кадра от 720p до 4K, поток в килобитах, кодек HEVC или H.264.
Перекодирование идёт одним проходом на весь ролик — пересобирать куски
по отдельности нельзя, на стыках была бы видна смена качества.
Кодирование на видеокарте, и распаковка тоже: замерено на паре кусков
2688x1512 — 9.18 с на процессоре против 1.77 с с аппаратной распаковкой,
впятеро. Полностью карточный путь через scale_cuda оказался медленнее
(5.74 с) и не взят. Если аппаратная распаковка не пойдёт, сборка
повторяется без неё: медленно лучше, чем никак. Окно честно
предупреждает, когда аппаратного кодировщика в ffmpeg нет вовсе.
Журнал в окне сборки заменён на свой: у системного поля оставались
светлые полосы прокрутки и не работала прокрутка вбок с Shift. Это было
последнее такое место.
2026-08-21 18:11:59 +03:00
|
|
|
|
{ Свой журнал сам держится конца, пока пользователь не отмотал назад, и
|
|
|
|
|
|
сам обрезает старые строки. }
|
|
|
|
|
|
memoLog.Add(AText);
|
Нелинейный видеоредактор без перекодирования
Куски видео вырезаются и склеиваются копированием потока: сборка ролика
занимает время копирования файла, а не время рендера. Композитинга нет
принципиально — при перекрытии побеждает клип с верхней дорожки целиком,
и картинкой, и звуком. Именно это ограничение и делает сборку копированием
возможной.
Что внутри:
- монтажный стол со своей отрисовкой: дорожки, масштаб, прилипание,
схлопывание, громкость на клипе;
- предпросмотр прямо с монтажа через libmpv и виртуальный список кусков,
без промежуточных файлов;
- сборка через ffmpeg с точными резами: перекодируется только огрызок от
реза до ближайшего опорного кадра, остальное копируется;
- разбор заголовка MP4 для поиска опорных кадров — в 500 раз быстрее
опроса ffprobe;
- перепаковка контейнеров, кадрирование и поворот, сведения о проекте;
- свои цвета всего окна: системные элементы под Windows цвет не берут,
поэтому кнопки, полоса меню, журнал и полосы прокрутки нарисованы сами;
- окно зависимостей: недостающие ffmpeg, ffprobe и libmpv скачиваются с
официальных источников;
- кросс-сборка под Windows и работа под Wine.
Первый коммит: до этого история не велась.
2026-08-19 18:36:16 +03:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TProgressForm.Finish(ASuccess: Boolean; const AMessage: string);
|
|
|
|
|
|
begin
|
|
|
|
|
|
FFinished := True;
|
|
|
|
|
|
btnAction.Caption := 'Закрыть';
|
|
|
|
|
|
lblStage.Caption := AMessage;
|
Свойства клипа, порядок дорожек, оценка времени и продолжение сборки
Копирование оформления: Ctrl+Shift+C берёт с выделенного клипа
кадрирование, поворот, увеличение, смещение, прозрачность, ключ,
затухания и громкость, Ctrl+Shift+V применяет их ко всем выделенным. Вид
клипа и текст не переносятся: свойства копируют между разными клипами.
Порядок дорожек: слева в заголовке две стрелки, у крайних дорожек
соответствующая нарисована тускло и не нажимается. Двойной щелчок по
названию переименовывает дорожку — на монтаже из десятка дорожек «карта»
и «титры» читаются лучше, чем V1 и Т1. То же есть и в меню по правому
щелчку. Ввод имени — своим тёмным окном: системный InputQuery выглядел бы
белым пятном.
Окно сборки показывает, сколько прошло и сколько примерно осталось.
Оценка по пройденной доле; скорость на деле меняется, поэтому «примерно»
и пересчёт на каждом шаге.
Прерванная сборка продолжается с готовых кусков. Каждый доведённый до
конца кусок помечается в списке рядом с ними: одного наличия файла мало —
сборку могли прервать посреди записи. Первая строка списка — отпечаток
плана; не совпал, значит монтаж менялся, и всё собирается заново.
Проверено: четыре куска взяты готовыми, два пересобраны, склейка не
потеряла ни одного кадра; при изменённом монтаже готовые куски отвергнуты.
2026-08-31 14:55:19 +03:00
|
|
|
|
{ На месте оценки — итог: сколько всё это заняло. }
|
|
|
|
|
|
lblEta.Caption := 'Заняло ' + FormatSpan((Now - FStartedAt) * SecsPerDay);
|
Нелинейный видеоредактор без перекодирования
Куски видео вырезаются и склеиваются копированием потока: сборка ролика
занимает время копирования файла, а не время рендера. Композитинга нет
принципиально — при перекрытии побеждает клип с верхней дорожки целиком,
и картинкой, и звуком. Именно это ограничение и делает сборку копированием
возможной.
Что внутри:
- монтажный стол со своей отрисовкой: дорожки, масштаб, прилипание,
схлопывание, громкость на клипе;
- предпросмотр прямо с монтажа через libmpv и виртуальный список кусков,
без промежуточных файлов;
- сборка через ffmpeg с точными резами: перекодируется только огрызок от
реза до ближайшего опорного кадра, остальное копируется;
- разбор заголовка MP4 для поиска опорных кадров — в 500 раз быстрее
опроса ffprobe;
- перепаковка контейнеров, кадрирование и поворот, сведения о проекте;
- свои цвета всего окна: системные элементы под Windows цвет не берут,
поэтому кнопки, полоса меню, журнал и полосы прокрутки нарисованы сами;
- окно зависимостей: недостающие ffmpeg, ffprobe и libmpv скачиваются с
официальных источников;
- кросс-сборка под Windows и работа под Wine.
Первый коммит: до этого история не велась.
2026-08-19 18:36:16 +03:00
|
|
|
|
if ASuccess then
|
|
|
|
|
|
lblStage.Font.Color := clDefault
|
|
|
|
|
|
else
|
|
|
|
|
|
lblStage.Font.Color := clRed;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TProgressForm.btnActionClick(Sender: TObject);
|
|
|
|
|
|
begin
|
|
|
|
|
|
if FFinished then
|
|
|
|
|
|
begin
|
|
|
|
|
|
Close;
|
|
|
|
|
|
Exit;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ Повторное нажатие ничего не даёт: остановка не мгновенна, надо
|
|
|
|
|
|
дождаться, пока ffmpeg завершится. }
|
|
|
|
|
|
if FCancelRequested then
|
|
|
|
|
|
Exit;
|
|
|
|
|
|
|
|
|
|
|
|
FCancelRequested := True;
|
|
|
|
|
|
btnAction.Enabled := False;
|
|
|
|
|
|
lblStage.Caption := 'Останавливаю...';
|
|
|
|
|
|
if Assigned(FOnCancelRequest) then
|
|
|
|
|
|
FOnCancelRequest(Self);
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TProgressForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
|
|
|
|
|
begin
|
|
|
|
|
|
{ Пока работа идёт, закрытие окна означало бы оставить ffmpeg работать
|
|
|
|
|
|
без всякого присмотра. Вместо этого запрашиваем остановку. }
|
|
|
|
|
|
CanClose := FFinished;
|
|
|
|
|
|
if not CanClose then
|
|
|
|
|
|
btnActionClick(nil);
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
end.
|