Предпросмотр показывает кадрирование клипа

Клип со своим кадрированием играл в окне во весь кадр: цепочка фильтров
у mpv одна на весь список кусков, а включить её на одном куске и
выключить на следующем нечем — из фильтров ffmpeg по времени
переключается только наложение.

Обошлось без цепочки вовсе. У вывода mpv своя обрезка, и делает её
видеокарта: курсор зашёл в клип с кадрированием — выставили, вышел —
сняли. Ни перестройки цепочки, ни копирования кадров из памяти
видеокарты в обычную.

Рамку источника считает теперь один код на две стороны: по ней окно
«Кадрирование и поворот» рисует рамку, и её же плеер отдаёт как обрезку.
Проверка в tests/lfmcheck сверяет рамку с фильтром сборки: увеличение
2.77 даёт 970x546 посередине, и это ровно то, что вырезает
crop=2688:1512:2379:1338 после scale=7446:4188.

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

Не покрыто и записано в BACKLOG: отражение (свойства для него нет),
растяжение и участки с наложением — там кадр уже сведён цепочкой.
This commit is contained in:
4aiman 2026-10-01 00:04:57 +03:00
commit 235cd00e9a
8 changed files with 329 additions and 70 deletions

View file

@ -786,6 +786,64 @@ begin
Inc(ClickCount);
end;
{ Рамка источника и фильтр сборки должны говорить об одном.
Одна и та же настройка записана двумя способами: сборка растягивает
кадр и вырезает из него кусок, а окно кадрирования и предпросмотр
говорят, какая часть исходника видна. Разойдутся — окно начнёт обещать
не то, что покажет плеер, а плеер не то, что даст сборка. }
procedure CheckSourceRect;
var
T: TMediaTransform;
R: TRect;
Chain: string;
begin
WriteLn;
WriteLn('Рамка источника и фильтр сборки');
WriteLn;
T := DefaultTransform;
T.Zoom := 2.77;
CheckTrue('увеличение описывается рамкой',
TransformSourceRect(T, 2688, 1512, 2688, 1512, R));
{ Растянули в 2.77 раза — значит видна 1/2.77 часть кадра, посередине. }
CheckTrue('ширина рамки: ' + IntToStr(R.Right - R.Left),
Abs((R.Right - R.Left) - Round(2688 / 2.77)) <= 2);
CheckTrue('высота рамки: ' + IntToStr(R.Bottom - R.Top),
Abs((R.Bottom - R.Top) - Round(1512 / 2.77)) <= 2);
CheckTrue('рамка посередине по горизонтали',
Abs((R.Left + R.Right) - 2688) <= 3);
CheckTrue('рамка посередине по вертикали',
Abs((R.Top + R.Bottom) - 1512) <= 3);
{ Тот же расчёт с другой стороны: сборка растягивает до 7446x4188 и
вырезает 2688x1512 с отступом 2379:1338. Делим отступ на масштаб —
обязано выйти начало рамки. }
Chain := TransformFilter(T, 2688, 1512, 2688, 1512);
CheckTrue('сборка растягивает и вырезает: ' + Chain,
(Pos('scale=7446:4188', Chain) > 0) and
(Pos('crop=2688:1512:2379:1338', Chain) > 0));
CheckTrue('начало рамки совпадает с отступом обрезки',
Abs(R.Left - Round(2379 / 2.77)) <= 2);
{ Растяжение рамкой не описывается: там кадр жмётся неравномерно. }
T := DefaultTransform;
T.Fit := fmStretch;
CheckTrue('растяжение рамкой не описывается',
not TransformSourceRect(T, 2688, 1512, 1920, 1080, R));
{ Отражение обрезкой на выводе не показать — свойства для него нет. }
T := DefaultTransform;
T.FlipH := True;
CheckTrue('отражение обрезкой на выводе не показывается',
not TransformFitsOutputCrop(T));
T := DefaultTransform;
T.Rotation := 90;
CheckTrue('поворот показать можно: у него своё свойство',
TransformFitsOutputCrop(T));
end;
procedure CheckButtonClicks;
var
Btn: TButtonProbe;
@ -845,6 +903,7 @@ begin
CheckSplitAndPlayhead;
CheckSplitAllTracks;
CheckGapTolerance;
CheckSourceRect;
CheckButtonClicks;
WriteLn;